diff -Nur snapshot-20011127.orig/makedefs snapshot-20011127/makedefs --- snapshot-20011127.orig/makedefs Wed Nov 21 22:40:39 2001 +++ snapshot-20011127/makedefs Mon Dec 3 14:16:38 2001 @@ -52,6 +52,21 @@ SYSTEM=`(uname -s) 2>/dev/null` RELEASE=`(uname -r) 2>/dev/null` VERSION=`(uname -v) 2>/dev/null` +if test -f /usr/include/netinet6/in6.h; then + grep __KAME__ /usr/include/netinet6/in6.h 2>&1 >/dev/null + if [ $? = 1 ]; then + INET6= + else + if [ -f /usr/local/v6/lib/libinet6.a ]; then + INET6=kame + else + INET6=kame-merged + fi + fi +fi +if [ -z "$INET6" -a -f /usr/include/netinet/ip6.h -a -f /usr/include/linux/icmpv6.h ]; then + INET6=linux +fi case "$VERSION" in dcosx*) SYSTEM=$VERSION;; @@ -289,6 +304,26 @@ esac : ${CC='gcc $(WARN)'} ${OPT='-O'} ${DEBUG='-g'} ${AWK=awk} + +case "$INET6" in +kame) + CCARGS="$CCARGS -DINET6 -D__ss_family=ss_family -D__ss_len=ss_len" + if test -f /usr/local/v6/lib/libinet6.a; then + SYSLIBS="$SYSLIBS -L/usr/local/v6/lib -linet6" + fi + ;; +kame-merged) + CCARGS="$CCARGS -DINET6 -D__ss_family=ss_family -D__ss_len=ss_len" + ;; +linux) + CCARGS="$CCARGS -DINET6 -D__ss_family=ss_family" + if test -f /usr/include/libinet6/netinet/ip6.h -a \ + -f /usr/lib/libinet6.a; then + CCARGS="$CCARGS -I/usr/include/libinet6 -DUSAGI_LIBINET6" + SYSLIBS="$SYSLIBS -linet6" + fi + ;; +esac export SYSTYPE AR ARFL RANLIB SYSLIBS CC OPT DEBUG AWK OPTS diff -Nur snapshot-20011127.orig/src/dns/dns_lookup.c snapshot-20011127/src/dns/dns_lookup.c --- snapshot-20011127.orig/src/dns/dns_lookup.c Sun Feb 4 19:16:20 2001 +++ snapshot-20011127/src/dns/dns_lookup.c Mon Dec 3 14:16:39 2001 @@ -132,6 +132,9 @@ } DNS_REPLY; #define INET_ADDR_LEN 4 /* XXX */ +#ifdef INET6 +#define INET6_ADDR_LEN 16 +#endif /* dns_query - query name server and pre-parse the reply */ @@ -337,6 +340,19 @@ memcpy(temp, pos, fixed->length); data_len = fixed->length; break; +#ifdef INET6 + case T_AAAA: + if (fixed->length != INET6_ADDR_LEN) { + msg_warn("extract_answer: bad IPv6 address length: %d", fixed->length); + return (0); + } + if (fixed->length > sizeof(temp)) + msg_panic("dns_get_rr: length %d > DNS_NAME_LEN", + fixed->length); + memcpy(temp, pos, fixed->length); + data_len = fixed->length; + break; +#endif case T_TXT: data_len = MIN2(pos[0] + 1, MIN2(fixed->length + 1, sizeof(temp))); for (src = pos + 1, dst = (unsigned char *) (temp); diff -Nur snapshot-20011127.orig/src/global/Makefile.in snapshot-20011127/src/global/Makefile.in --- snapshot-20011127.orig/src/global/Makefile.in Mon Dec 3 14:15:12 2001 +++ snapshot-20011127/src/global/Makefile.in Mon Dec 3 14:16:39 2001 @@ -19,7 +19,7 @@ timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \ tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c \ flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c \ - verp_sender.c match_parent_style.c pfixtls.c + verp_sender.c match_parent_style.c pfixtls.c wildcard_inet_addr.c OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \ debug_peer.o debug_process.o defer.o deliver_completed.o \ deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \ @@ -40,7 +40,7 @@ timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \ tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o \ flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o \ - verp_sender.o match_parent_style.o pfixtls.o + verp_sender.o match_parent_style.o pfixtls.o wildcard_inet_addr.o HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \ config.h debug_peer.h debug_process.h defer.h deliver_completed.h \ deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \ @@ -57,7 +57,7 @@ rewrite_clnt.h sent.h smtp_stream.h split_addr.h string_list.h \ sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h \ mbox_conf.h mbox_open.h abounce.h qmqp_proto.h verp_sender.h \ - match_parent_style.h pfixtls.h + match_parent_style.h pfixtls.h wildcard_inet_addr.h TESTSRC = rec2stream.c stream2rec.c recdump.c WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ diff -Nur snapshot-20011127.orig/src/global/mynetworks.c snapshot-20011127/src/global/mynetworks.c --- snapshot-20011127.orig/src/global/mynetworks.c Sun Feb 25 02:46:07 2001 +++ snapshot-20011127/src/global/mynetworks.c Mon Dec 3 14:16:39 2001 @@ -50,6 +50,11 @@ #include #include #include +#ifdef INET6 +#include +#include +#include +#endif /* Global library. */ @@ -75,6 +80,9 @@ const char *mynetworks(void) { static VSTRING *result; +#ifdef INET6 + char hbuf[NI_MAXHOST]; +#endif if (result == 0) { char *myname = "mynetworks"; @@ -87,6 +95,9 @@ int junk; int i; int mask_style; +#ifdef INET6 + struct sockaddr *sa; +#endif mask_style = name_mask("mynetworks mask style", mask_styles, var_mynetworks_style); @@ -96,8 +107,19 @@ my_mask_list = own_inet_mask_list(); for (i = 0; i < my_addr_list->used; i++) { +#ifdef INET6 + sa = (struct sockaddr *)&my_addr_list->addrs[i]; + if (sa->sa_family != AF_INET) { + if (sa->sa_family == AF_INET6) + vstring_sprintf_append(result, "XAATODOmynetworks "); + continue; + } + addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); + mask = ntohl(((struct sockaddr_in *)&my_mask_list->addrs[i])->sin_addr.s_addr); +#else addr = ntohl(my_addr_list->addrs[i].s_addr); mask = ntohl(my_mask_list->addrs[i].s_addr); +#endif switch (mask_style) { @@ -119,8 +140,15 @@ mask = IN_CLASSD_NET; shift = IN_CLASSD_NSHIFT; } else { +#ifdef INET6 + if (getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST)) + strncpy(hbuf, "???", sizeof(hbuf)); + msg_fatal("%s: bad address class: %s", myname, hbuf); +#else msg_fatal("%s: bad address class: %s", myname, inet_ntoa(my_addr_list->addrs[i])); +#endif } break; diff -Nur snapshot-20011127.orig/src/global/own_inet_addr.c snapshot-20011127/src/global/own_inet_addr.c --- snapshot-20011127.orig/src/global/own_inet_addr.c Tue Jul 31 20:38:29 2001 +++ snapshot-20011127/src/global/own_inet_addr.c Mon Dec 3 14:16:39 2001 @@ -39,6 +39,10 @@ #include #include #include +#ifdef INET6 +#include +#include +#endif #ifdef STRCASECMP_IN_STRINGS_H #include @@ -101,10 +105,11 @@ */ else { bufp = hosts = mystrdup(var_inet_interfaces); - while ((host = mystrtok(&bufp, sep)) != 0) + while ((host = mystrtok(&bufp, sep)) != 0) { if (inet_addr_host(addr_list, host) == 0) msg_fatal("config variable %s: host not found: %s", VAR_INET_INTERFACES, host); + } myfree(hosts); /* @@ -121,15 +126,39 @@ msg_fatal("could not find any active network interfaces"); for (nvirtual = 0; nvirtual < addr_list->used; nvirtual++) { for (nlocal = 0; /* see below */ ; nlocal++) { - if (nlocal >= local_addrs.used) + if (nlocal >= local_addrs.used) { +#ifdef INET6 + char hbuf[NI_MAXHOST]; + if (getnameinfo((struct sockaddr *)&addr_list->addrs[nvirtual], + SS_LEN(addr_list->addrs[nvirtual]), hbuf, + sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) + strncpy(hbuf, "???", sizeof(hbuf)); + msg_fatal("parameter %s: no local interface found for %s", + VAR_INET_INTERFACES, hbuf); +#else msg_fatal("parameter %s: no local interface found for %s", VAR_INET_INTERFACES, inet_ntoa(addr_list->addrs[nvirtual])); +#endif + } +#ifdef INET6 + if (addr_list->addrs[nvirtual].ss_family == + local_addrs.addrs[nlocal].ss_family && + SS_LEN(addr_list->addrs[nvirtual]) == + SS_LEN(local_addrs.addrs[nlocal]) && + memcmp(&addr_list->addrs[nvirtual], + &local_addrs.addrs[nlocal], + SS_LEN(local_addrs.addrs[nlocal])) == 0) { + inet_addr_list_append(mask_list, (struct sockaddr *)&local_masks.addrs[nlocal]); + break; + } +#else if (addr_list->addrs[nvirtual].s_addr == local_addrs.addrs[nlocal].s_addr) { inet_addr_list_append(mask_list, &local_masks.addrs[nlocal]); break; } +#endif } } inet_addr_list_free(&local_addrs); @@ -139,6 +168,42 @@ /* own_inet_addr - is this my own internet address */ +#ifdef INET6 +int own_inet_addr(struct sockaddr * addr) +{ + int i; + char *p, *q; + int l; + struct sockaddr *sa; + + if (addr_list.used == 0) + own_inet_addr_init(&addr_list, &mask_list); + + for (i = 0; i < addr_list.used; i++) { + sa = (struct sockaddr *)&addr_list.addrs[i]; + if (addr->sa_family != sa->sa_family) + continue; + switch (addr->sa_family) { + case AF_INET: + p = (char *)&((struct sockaddr_in *)addr)->sin_addr; + q = (char *)&((struct sockaddr_in *)&addr_list.addrs[i])->sin_addr; + l = sizeof(struct in_addr); + break; + case AF_INET6: + /* XXX scope */ + p = (char *)&((struct sockaddr_in6 *)addr)->sin6_addr; + q = (char *)&((struct sockaddr_in6 *)&addr_list.addrs[i])->sin6_addr; + l = sizeof(struct in6_addr); + break; + default: + continue; + } + if (memcmp(p, q, l) == 0) + return (1); + } + return (0); +} +#else int own_inet_addr(struct in_addr * addr) { int i; @@ -149,8 +214,8 @@ for (i = 0; i < addr_list.used; i++) if (addr->s_addr == addr_list.addrs[i].s_addr) return (1); - return (0); } +#endif /* own_inet_addr_list - return list of addresses */ diff -Nur snapshot-20011127.orig/src/global/own_inet_addr.h snapshot-20011127/src/global/own_inet_addr.h --- snapshot-20011127.orig/src/global/own_inet_addr.h Sat Feb 24 02:25:32 2001 +++ snapshot-20011127/src/global/own_inet_addr.h Mon Dec 3 14:16:39 2001 @@ -15,11 +15,18 @@ * System library. */ #include +#ifdef INET6 +#include +#endif /* * External interface. */ +#ifdef INET6 +extern int own_inet_addr(struct sockaddr *); +#else extern int own_inet_addr(struct in_addr *); +#endif extern struct INET_ADDR_LIST *own_inet_addr_list(void); extern struct INET_ADDR_LIST *own_inet_mask_list(void); diff -Nur snapshot-20011127.orig/src/global/peer_name.c snapshot-20011127/src/global/peer_name.c --- snapshot-20011127.orig/src/global/peer_name.c Sun Jan 28 16:23:02 2001 +++ snapshot-20011127/src/global/peer_name.c Mon Dec 3 14:16:39 2001 @@ -69,12 +69,32 @@ PEER_NAME *peer_name(int sock) { static PEER_NAME peer; - struct sockaddr_in sin; - SOCKADDR_SIZE len = sizeof(sin); + union sockunion { + struct { + u_char si_len; + u_char si_family; + u_short si_port; + } su_si; + struct sockaddr peer_un; + struct sockaddr_in peer_un4; +#ifdef INET6 + struct sockaddr_in6 peer_un6; +#endif + } p_un; +#define sun p_un.peer_un +#define sin p_un.peer_un4 +#ifdef INET6 +#define sin6 p_un.peer_un6 + static char hbuf[NI_MAXHOST]; + static char abuf[NI_MAXHOST]; +#else struct hostent *hp; +#endif + SOCKADDR_SIZE len = sizeof(p_un); - if (getpeername(sock, (struct sockaddr *) & sin, &len) == 0) { - switch (sin.sin_family) { + if (getpeername(sock, (struct sockaddr *)&p_un, &len) == 0) { + switch (p_un.peer_un.sa_family) { +#ifndef INET6 case AF_INET: peer.type = PEER_TYPE_INET; hp = gethostbyaddr((char *) &(sin.sin_addr), @@ -83,6 +103,24 @@ hp->h_name : "unknown"); peer.addr = inet_ntoa(sin.sin_addr); return (&peer); +#else + case AF_INET: + peer.type = PEER_TYPE_INET; + if (getnameinfo(&sun, len, hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD) != 0) + peer.name = "unknown"; + else + peer.name = hbuf; + peer.addr = abuf; + return (&peer); + case AF_INET6: + peer.type = PEER_TYPE_INET6; + if (getnameinfo(&sun, len, hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD) != 0) + peer.name = "unknown"; + else + peer.name = hbuf; + peer.addr = abuf; + return (&peer); +#endif case AF_UNSPEC: case AF_UNIX: peer.type = PEER_TYPE_LOCAL; diff -Nur snapshot-20011127.orig/src/global/peer_name.h snapshot-20011127/src/global/peer_name.h --- snapshot-20011127.orig/src/global/peer_name.h Fri Dec 11 19:55:32 1998 +++ snapshot-20011127/src/global/peer_name.h Mon Dec 3 14:16:39 2001 @@ -22,6 +22,9 @@ #define PEER_TYPE_UNKNOWN 0 #define PEER_TYPE_INET 1 #define PEER_TYPE_LOCAL 2 +#ifdef INET6 +#define PEER_TYPE_INET6 3 +#endif extern PEER_NAME *peer_name(int); diff -Nur snapshot-20011127.orig/src/global/resolve_local.c snapshot-20011127/src/global/resolve_local.c --- snapshot-20011127.orig/src/global/resolve_local.c Tue Nov 20 22:41:26 2001 +++ snapshot-20011127/src/global/resolve_local.c Mon Dec 3 14:16:39 2001 @@ -42,6 +42,7 @@ #include #include #include +#include #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff @@ -79,7 +80,12 @@ { char *saved_addr = mystrdup(addr); char *dest; +#ifdef INET6 + struct addrinfo hints, *res, *res0; + int error; +#else struct in_addr ipaddr; +#endif int len; #define RETURN(x) { myfree(saved_addr); return(x); } @@ -109,9 +115,25 @@ if (*dest == '[' && dest[len - 1] == ']') { dest++; dest[len -= 2] = 0; +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + error = getaddrinfo(dest, NULL, &hints, &res0); + if (!error) { + for (res = res0; res; res = res->ai_next) { + if (own_inet_addr(res->ai_addr)) { + freeaddrinfo(res0); + RETURN(1); + } + } + freeaddrinfo(res0); + } +#else if ((ipaddr.s_addr = inet_addr(dest)) != INADDR_NONE && own_inet_addr(&ipaddr)) RETURN(1); +#endif } /* diff -Nur snapshot-20011127.orig/src/global/wildcard_inet_addr.c snapshot-20011127/src/global/wildcard_inet_addr.c --- snapshot-20011127.orig/src/global/wildcard_inet_addr.c Thu Jan 1 01:00:00 1970 +++ snapshot-20011127/src/global/wildcard_inet_addr.c Mon Dec 3 14:16:39 2001 @@ -0,0 +1,82 @@ +/* System library. */ + +#include +#include +#include +#include +#ifdef INET6 +#include +#endif +#include + +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif + +/* Utility library. */ + +#include +#include +#include +#include +#include +#include + +/* Global library. */ + +#include +#include + +/* Application-specific. */ +static INET_ADDR_LIST addr_list; + +/* wildcard_inet_addr_init - initialize my own address list */ + +static void wildcard_inet_addr_init(INET_ADDR_LIST *addr_list) +{ +#ifdef INET6 + struct addrinfo hints, *res, *res0; + char hbuf[NI_MAXHOST]; + int error; +#ifdef NI_WITHSCOPEID + const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflags = NI_NUMERICHOST; +#endif + + inet_addr_list_init(addr_list); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + error = getaddrinfo(NULL, "0", &hints, &res0); + if (error) + msg_fatal("could not get list of wildcard addresses"); + for (res = res0; res; res = res->ai_next) { + if (res->ai_family != AF_INET && res->ai_family != AF_INET6) + continue; + if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), + NULL, 0, niflags) != 0) + continue; + if (inet_addr_host(addr_list, hbuf) == 0) + continue; /* msg_fatal("config variable %s: host not found: %s", + VAR_INET_INTERFACES, hbuf); */ + } + freeaddrinfo(res0); +#else + if (inet_addr_host(addr_list, "0.0.0.0") == 0) + msg_fatal("config variable %s: host not found: %s", + VAR_INET_INTERFACES, "0.0.0.0"); +#endif +} + +/* wildcard_inet_addr_list - return list of addresses */ + +INET_ADDR_LIST *wildcard_inet_addr_list(void) +{ + if (addr_list.used == 0) + wildcard_inet_addr_init(&addr_list); + + return (&addr_list); +} diff -Nur snapshot-20011127.orig/src/global/wildcard_inet_addr.h snapshot-20011127/src/global/wildcard_inet_addr.h --- snapshot-20011127.orig/src/global/wildcard_inet_addr.h Thu Jan 1 01:00:00 1970 +++ snapshot-20011127/src/global/wildcard_inet_addr.h Mon Dec 3 14:16:39 2001 @@ -0,0 +1,36 @@ +#ifndef _WILDCARD_INET_ADDR_H_INCLUDED_ +#define _WILDCARD_INET_ADDR_H_INCLUDED_ + +/*++ +/* NAME +/* wildcard_inet_addr_list 3h +/* SUMMARY +/* grab the list of wildcard IP addresses. +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf +/*--*/ + + /* + * System library. + */ +#include +#ifdef INET6 +#include +#endif + + /* + * External interface. + */ +extern struct INET_ADDR_LIST *wildcard_inet_addr_list(void); + +/* LICENSE +/* .ad +/* .fi +/* foo +/* AUTHOR(S) +/* Jun-ichiro itojun Hagino +/*--*/ + +#endif diff -Nur snapshot-20011127.orig/src/master/master_ent.c snapshot-20011127/src/master/master_ent.c --- snapshot-20011127.orig/src/master/master_ent.c Tue May 1 00:45:54 2001 +++ snapshot-20011127/src/master/master_ent.c Mon Dec 3 14:16:39 2001 @@ -284,8 +284,13 @@ inet_addr_host(MASTER_INET_ADDRLIST(serv), host); serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; } else if (strcasecmp(var_inet_interfaces, DEF_INET_INTERFACES) == 0) { +#ifdef INET6 + MASTER_INET_ADDRLIST(serv) = wildcard_inet_addr_list(); + serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; +#else MASTER_INET_ADDRLIST(serv) = 0; /* wild-card */ serv->listen_fd_count = 1; +#endif } else { MASTER_INET_ADDRLIST(serv) = own_inet_addr_list(); /* virtual */ serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; diff -Nur snapshot-20011127.orig/src/master/master_listen.c snapshot-20011127/src/master/master_listen.c --- snapshot-20011127.orig/src/master/master_listen.c Tue May 1 00:47:57 2001 +++ snapshot-20011127/src/master/master_listen.c Mon Dec 3 14:16:39 2001 @@ -64,13 +64,22 @@ #include "master.h" +#ifdef INET6 +#include +#include +#endif + /* master_listen_init - enable connection requests */ void master_listen_init(MASTER_SERV *serv) { char *myname = "master_listen_init"; char *end_point; - int n; + int n,m,tmpfd; +#ifdef INET6 + char hbuf[NI_MAXHOST]; + SOCKADDR_SIZE salen; +#endif /* * Find out what transport we should use, then create one or more @@ -111,18 +120,31 @@ serv->listen_fd[0] = inet_listen(MASTER_INET_PORT(serv), serv->max_proc > var_proc_limit ? - serv->max_proc : var_proc_limit, NON_BLOCKING); + serv->max_proc : var_proc_limit, NON_BLOCKING, 1); close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC); } else { /* virtual or host:port */ - for (n = 0; n < serv->listen_fd_count; n++) { + for (m = n = 0; n < serv->listen_fd_count; n++) { +#ifdef INET6 + if (getnameinfo((struct sockaddr *)&MASTER_INET_ADDRLIST(serv)->addrs[n], + SA_LEN((struct sockaddr *)&MASTER_INET_ADDRLIST(serv)->addrs[n]), + hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) { + strncpy(hbuf, "?????", sizeof(hbuf)); + } + end_point = concatenate(hbuf, ":", MASTER_INET_PORT(serv), (char *) 0); +#else end_point = concatenate(inet_ntoa(MASTER_INET_ADDRLIST(serv)->addrs[n]), ":", MASTER_INET_PORT(serv), (char *) 0); - serv->listen_fd[n] +#endif + tmpfd = inet_listen(end_point, serv->max_proc > var_proc_limit ? - serv->max_proc : var_proc_limit, NON_BLOCKING); - close_on_exec(serv->listen_fd[n], CLOSE_ON_EXEC); + serv->max_proc : var_proc_limit, NON_BLOCKING, 0); + if (tmpfd >= 0) { + serv->listen_fd[m] = tmpfd; + close_on_exec(serv->listen_fd[m++], CLOSE_ON_EXEC); + } myfree(end_point); } + serv->listen_fd_count=m; } break; default: diff -Nur snapshot-20011127.orig/src/qmgr/qmgr_message.c snapshot-20011127/src/qmgr/qmgr_message.c --- snapshot-20011127.orig/src/qmgr/qmgr_message.c Sat Jul 14 15:08:57 2001 +++ snapshot-20011127/src/qmgr/qmgr_message.c Mon Dec 3 14:16:39 2001 @@ -472,7 +472,11 @@ * every front-ent program. */ if ((at = strrchr(recipient->address, '@')) != 0 +#ifdef INET6 + && (at + 1)[strspn(at + 1, "[]0123456789.:abcdef")] != 0 +#else && (at + 1)[strspn(at + 1, "[]0123456789.")] != 0 +#endif && valid_hostname(at + 1, DONT_GRIPE) == 0) { qmgr_bounce_recipient(message, recipient, "bad host/domain syntax: \"%s\"", at + 1); diff -Nur snapshot-20011127.orig/src/smtp/Makefile.in snapshot-20011127/src/smtp/Makefile.in --- snapshot-20011127.orig/src/smtp/Makefile.in Mon Dec 3 14:15:13 2001 +++ snapshot-20011127/src/smtp/Makefile.in Mon Dec 3 14:16:39 2001 @@ -140,6 +140,7 @@ smtp_connect.o: ../../include/mail_params.h smtp_connect.o: ../../include/own_inet_addr.h smtp_connect.o: ../../include/dns.h +smtp_connect.o: ../../include/get_port.h smtp_connect.o: smtp.h smtp_connect.o: ../../include/argv.h smtp_connect.o: ../../include/deliver_request.h diff -Nur snapshot-20011127.orig/src/smtp/smtp_addr.c snapshot-20011127/src/smtp/smtp_addr.c --- snapshot-20011127.orig/src/smtp/smtp_addr.c Sun Jul 8 17:05:26 2001 +++ snapshot-20011127/src/smtp/smtp_addr.c Mon Dec 3 14:16:39 2001 @@ -134,18 +134,68 @@ static void smtp_print_addr(char *what, DNS_RR *addr_list) { DNS_RR *addr; - struct in_addr in_addr; +#ifdef INET6 + struct sockaddr_storage ss; +#else + struct sockaddr ss; +#endif + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; + char hbuf[NI_MAXHOST]; +#else + char hbuf[sizeof("255.255.255.255") + 1]; +#endif msg_info("begin %s address list", what); for (addr = addr_list; addr; addr = addr->next) { - if (addr->data_len > sizeof(addr)) { - msg_warn("skipping address length %d", addr->data_len); - } else { - memcpy((char *) &in_addr, addr->data, sizeof(in_addr)); - msg_info("pref %4d host %s/%s", - addr->pref, addr->name, - inet_ntoa(in_addr)); + if (addr->class != C_IN) { + msg_warn("skipping unsupported address (class=%u)", addr->class); + continue; } + switch (addr->type) { + case T_A: + if (addr->data_len != sizeof(sin->sin_addr)) { + msg_warn("skipping invalid address (AAAA, len=%u)", + addr->data_len); + continue; + } + sin = (struct sockaddr_in *)&ss; + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; +#ifdef HAS_SA_LEN + sin->sin_len = sizeof(*sin); +#endif + memcpy(&sin->sin_addr, addr->data, sizeof(sin->sin_addr)); + break; +#ifdef INET6 + case T_AAAA: + if (addr->data_len != sizeof(sin6->sin6_addr)) { + msg_warn("skipping invalid address (AAAA, len=%u)", + addr->data_len); + continue; + } + sin6 = (struct sockaddr_in6 *)&ss; + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; +#ifdef HAS_SA_LEN + sin6->sin6_len = sizeof(*sin6); +#endif + memcpy(&sin6->sin6_addr, addr->data, sizeof(sin6->sin6_addr)); + break; +#endif + default: + msg_warn("skipping unsupported address (type=%u)", addr->type); + continue; + } + +#ifdef INET6 + (void)getnameinfo((struct sockaddr *)&ss, SS_LEN(ss), + hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST); +#else + (void)inet_ntop(AF_INET, &sin->sin_addr, hbuf, sizeof(hbuf)); +#endif + msg_info("pref %4d host %s/%s", addr->pref, addr->name, hbuf); } msg_info("end %s address list", what); } @@ -155,15 +205,23 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRING *why) { char *myname = "smtp_addr_one"; +#ifndef INET6 struct in_addr inaddr; - DNS_FIXED fixed; DNS_RR *addr = 0; DNS_RR *rr; struct hostent *hp; +#else + struct addrinfo hints, *res0, *res; + int error = -1; + char *addr; + size_t addrlen; +#endif + DNS_FIXED fixed; if (msg_verbose) msg_info("%s: host %s", myname, host); +#ifndef INET6 /* * Interpret a numerical name as an address. */ @@ -216,6 +274,48 @@ smtp_errno = SMTP_FAIL; break; } +#else + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, NULL, &hints, &res0); + if (error) { + switch (error) { + case EAI_AGAIN: + smtp_errno = SMTP_RETRY; + break; + default: + vstring_sprintf(why, "[%s]: %s",host,gai_strerror(error)); + smtp_errno = SMTP_FAIL; + break; + } + return (addr_list); + } + for (res = res0; res; res = res->ai_next) { + memset((char *) &fixed, 0, sizeof(fixed)); + switch(res->ai_family) { + case AF_INET6: + /* XXX not scope friendly */ + fixed.type = T_AAAA; + addr = (char *)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; + addrlen = sizeof(struct in6_addr); + break; + case AF_INET: + fixed.type = T_A; + addr = (char *)&((struct sockaddr_in *)res->ai_addr)->sin_addr; + addrlen = sizeof(struct in_addr); + break; + default: + msg_warn("%s: unknown address family %d for %s", + myname, res->ai_family, host); + continue; + } + addr_list = dns_rr_append(addr_list, + dns_rr_create(host, &fixed, pref, addr, addrlen)); + } + if (res0) + freeaddrinfo(res0); +#endif return (addr_list); } @@ -251,6 +351,9 @@ INET_ADDR_LIST *self; DNS_RR *addr; int i; +#ifdef INET6 + struct sockaddr *sa; +#endif /* * Find the first address that lists any address that this mail system is @@ -260,12 +363,36 @@ self = own_inet_addr_list(); for (addr = addr_list; addr; addr = addr->next) { - for (i = 0; i < self->used; i++) + for (i = 0; i < self->used; i++) { +#ifdef INET6 + sa = (struct sockaddr *)&self->addrs[i]; + switch(addr->type) { + case T_AAAA: + /* XXX scope */ + if (sa->sa_family != AF_INET6) + break; + if (memcmp(&((struct sockaddr_in6 *)sa)->sin6_addr, + addr->data, sizeof(struct in6_addr)) == 0) { + return(addr); + } + break; + case T_A: + if (sa->sa_family != AF_INET) + break; + if (memcmp(&((struct sockaddr_in *)sa)->sin_addr, + addr->data, sizeof(struct in_addr)) == 0) { + return(addr); + } + break; + } +#else if (INADDRP(addr->data)->s_addr == self->addrs[i].s_addr) { if (msg_verbose) msg_info("%s: found at pref %d", myname, addr->pref); return (addr); } +#endif + } } /* diff -Nur snapshot-20011127.orig/src/smtp/smtp_connect.c snapshot-20011127/src/smtp/smtp_connect.c --- snapshot-20011127.orig/src/smtp/smtp_connect.c Mon Dec 3 14:15:13 2001 +++ snapshot-20011127/src/smtp/smtp_connect.c Mon Dec 3 14:16:39 2001 @@ -81,6 +81,7 @@ /* System library. */ #include +#include #include #include #include @@ -110,6 +111,7 @@ #include #include #include +#include #include /* Global library. */ @@ -133,19 +135,45 @@ VSTRING *why) { char *myname = "smtp_connect_addr"; - struct sockaddr_in sin; - int sock; +#ifdef INET6 + struct sockaddr_storage ss; +#else + struct sockaddr ss; +#endif + struct sockaddr *sa; + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + SOCKADDR_SIZE salen; +#ifdef INET6 + char hbuf[NI_MAXHOST]; +#else + char hbuf[sizeof("255.255.255.255") + 1]; +#endif + int sock = -1; INET_ADDR_LIST *addr_list; int conn_stat; int saved_errno; VSTREAM *stream; int ch; - unsigned long inaddr; + + sa = (struct sockaddr *)&ss; + sin = (struct sockaddr_in *)&ss; +#ifdef INET6 + sin6 = (struct sockaddr_in6 *)&ss; +#endif /* * Sanity checks. */ - if (addr->data_len > sizeof(sin.sin_addr)) { +#ifdef INET6 + if (((addr->type==T_A) && (addr->data_len > sizeof(sin->sin_addr))) || + ((addr->type==T_AAAA) && (addr->data_len > sizeof(sin6->sin6_addr)))) +#else + if (addr->data_len > sizeof(sin->sin_addr)) +#endif + { msg_warn("%s: skip address with length %d", myname, addr->data_len); smtp_errno = SMTP_RETRY; return (0); @@ -154,17 +182,39 @@ /* * Initialize. */ - memset((char *) &sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - - if ((sock = socket(sin.sin_family, SOCK_STREAM, 0)) < 0) - msg_fatal("%s: socket: %m", myname); - + switch (addr->type) { +#ifdef INET6 + case T_AAAA: + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + salen = sizeof(*sin6); + break; +#endif + default: /* T_A: */ + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + salen = sizeof(*sin); + break; + } +#ifdef HAS_SA_LEN + sa->sa_len = salen; +#endif + if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) + msg_warn("%s: socket: %m", myname); + /* * Allow the sysadmin to specify the source address, for example, as "-o * smtp_bind_address=x.x.x.x" in the master.cf file. */ if (*var_smtp_bind_addr) { +#ifndef INET6 + struct sockaddr_in sin; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; +#ifdef HAS_SA_LEN + sin.sin_len = sizeof(sin); +#endif sin.sin_addr.s_addr = inet_addr(var_smtp_bind_addr); if (sin.sin_addr.s_addr == INADDR_NONE) msg_fatal("%s: bad %s parameter: %s", @@ -173,6 +223,25 @@ msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr)); if (msg_verbose) msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr)); +#else + char hbufl[NI_MAXHOST]; + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = sa->sa_family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST; + snprintf(hbufl, sizeof(hbufl)-1, "%s", var_smtp_bind_addr); + if (getaddrinfo(hbufl, NULL, &hints, &res) == 0) { + (void)getnameinfo(res->ai_addr, res->ai_addrlen, hbufl, + sizeof(hbufl), NULL, 0, NI_NUMERICHOST); + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) + msg_warn("%s: bind %s: %m", myname, hbufl); + freeaddrinfo(res); + if (msg_verbose) + msg_info("%s: bind %s", myname, hbufl); + } +#endif } /* @@ -180,8 +249,17 @@ * the mail appears to come from the "right" machine address. */ else if ((addr_list = own_inet_addr_list())->used == 1) { +#ifndef INET6 + struct sockaddr_in sin; + unsigned long inaddr; /*XXX BAD!*/ + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; +#ifdef HAS_SA_LEN + sin.sin_len = sizeof(sin); +#endif memcpy((char *) &sin.sin_addr, addr_list->addrs, sizeof(sin.sin_addr)); - inaddr = ntohl(sin.sin_addr.s_addr); + inaddr = (unsigned long)ntohl(sin.sin_addr.s_addr); if (!IN_CLASSA(inaddr) || !(((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) { if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) @@ -189,30 +267,85 @@ if (msg_verbose) msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr)); } +#else + char hbufl[NI_MAXHOST]; + struct addrinfo hints, *res = NULL, *loopback = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = sa->sa_family; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo(NULL, "0", &hints, &loopback) != 0) + loopback = NULL; + + /* + * getnameinfo -> getaddrinfo loop is here so that we can + * get rid of port. + */ + (void)getnameinfo((struct sockaddr *)addr_list->addrs, SA_LEN((struct sockaddr *)addr_list->addrs), + hbufl, sizeof(hbufl), NULL, 0, NI_NUMERICHOST); + hbufl[sizeof(hbufl)-1] = 0; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = sa->sa_family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST; + if (getaddrinfo(hbufl, NULL, &hints, &res) == 0 && + !(res->ai_addrlen == loopback->ai_addrlen && + memcmp(res->ai_addr, loopback->ai_addr, res->ai_addrlen) == 0)) { + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) + msg_warn("%s: bind %s: %m", myname, hbufl); + if (msg_verbose) + msg_info("%s: bind %s", myname, hbufl); + } + if (res) + freeaddrinfo(res); + if (loopback) + freeaddrinfo(loopback); +#endif } /* * Connect to the SMTP server. */ - sin.sin_port = port; - memcpy((char *) &sin.sin_addr, addr->data, sizeof(sin.sin_addr)); + switch (addr->type) { +#ifdef INET6 + case T_AAAA: + /* XXX scope unfriendly */ + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_port = port; + sin6->sin6_family = AF_INET6; + salen = sizeof(*sin6); + memcpy(&sin6->sin6_addr, addr->data, sizeof(sin6->sin6_addr)); + inet_ntop(AF_INET6, &sin6->sin6_addr, hbuf, sizeof(hbuf)); + break; +#endif + default: /* T_A */ + memset(sin, 0, sizeof(*sin)); + sin->sin_port = port; + sin->sin_family = AF_INET; + salen = sizeof(*sin); + memcpy(&sin->sin_addr, addr->data, sizeof(sin->sin_addr)); + inet_ntop(AF_INET, &sin->sin_addr, hbuf, sizeof(hbuf)); + break; + } +#ifdef HAS_SA_LEN + sa->sa_len = salen; +#endif if (msg_verbose) msg_info("%s: trying: %s[%s] port %d...", - myname, addr->name, inet_ntoa(sin.sin_addr), ntohs(port)); + myname, addr->name, hbuf, ntohs(port)); if (var_smtp_conn_tmout > 0) { non_blocking(sock, NON_BLOCKING); - conn_stat = timed_connect(sock, (struct sockaddr *) & sin, - sizeof(sin), var_smtp_conn_tmout); + conn_stat = timed_connect(sock, sa, salen, var_smtp_conn_tmout); saved_errno = errno; non_blocking(sock, BLOCKING); errno = saved_errno; } else { - conn_stat = connect(sock, (struct sockaddr *) & sin, sizeof(sin)); + conn_stat = connect(sock, sa, salen); } if (conn_stat < 0) { vstring_sprintf(why, "connect to %s[%s]: %m", - addr->name, inet_ntoa(sin.sin_addr)); + addr->name, hbuf); smtp_errno = SMTP_RETRY; close(sock); return (0); @@ -222,8 +355,8 @@ * Skip this host if it takes no action within some time limit. */ if (read_wait(sock, var_smtp_helo_tmout) < 0) { - vstring_sprintf(why, "connect to %s[%s]: read timeout", - addr->name, inet_ntoa(sin.sin_addr)); + vstring_sprintf(why, "connect to %s [%s]: read timeout", + addr->name, hbuf); smtp_errno = SMTP_RETRY; close(sock); return (0); @@ -234,8 +367,8 @@ */ stream = vstream_fdopen(sock, O_RDWR); if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) { - vstring_sprintf(why, "connect to %s[%s]: server dropped connection", - addr->name, inet_ntoa(sin.sin_addr)); + vstring_sprintf(why, "connect to %s [%s]: server dropped connection", + addr->name, hbuf); smtp_errno = SMTP_RETRY; vstream_fclose(stream); return (0); @@ -247,7 +380,7 @@ */ if (ch == '4' && var_smtp_skip_4xx_greeting) { vstring_sprintf(why, "connect to %s[%s]: server refused mail service", - addr->name, inet_ntoa(sin.sin_addr)); + addr->name, hbuf); smtp_errno = SMTP_RETRY; vstream_fclose(stream); return (0); @@ -258,12 +391,12 @@ */ if (ch == '5' && var_smtp_skip_5xx_greeting) { vstring_sprintf(why, "connect to %s[%s]: server refused mail service", - addr->name, inet_ntoa(sin.sin_addr)); + addr->name, hbuf); smtp_errno = SMTP_RETRY; vstream_fclose(stream); return (0); } - return (smtp_session_alloc(dest, stream, addr->name, inet_ntoa(sin.sin_addr))); + return (smtp_session_alloc(dest, stream, addr->name, hbuf)); } /* smtp_connect_host - direct connection to host */ @@ -273,7 +406,7 @@ SMTP_SESSION *session = 0; DNS_RR *addr_list; DNS_RR *addr; - + /* * Try each address in the specified order until we find one that works. * The addresses belong to the same A record, so we have no information @@ -380,6 +513,7 @@ msg_fatal("unknown service: %s/%s", service, protocol); *portp = sp->s_port; } + return (buf); } diff -Nur snapshot-20011127.orig/src/smtp/smtp_unalias.c snapshot-20011127/src/smtp/smtp_unalias.c --- snapshot-20011127.orig/src/smtp/smtp_unalias.c Thu Sep 28 19:06:09 2000 +++ snapshot-20011127/src/smtp/smtp_unalias.c Mon Dec 3 14:16:39 2001 @@ -86,7 +86,11 @@ if ((result = htable_find(cache, name)) == 0) { fqdn = vstring_alloc(10); if (dns_lookup_types(name, smtp_unalias_flags, (DNS_RR **) 0, - fqdn, (VSTRING *) 0, T_MX, T_A, 0) != DNS_OK) + fqdn, (VSTRING *) 0, T_MX, T_A, +#ifdef INET6 + T_AAAA, +#endif + 0) != DNS_OK) vstring_strcpy(fqdn, name); htable_enter(cache, name, result = vstring_export(fqdn)); } diff -Nur snapshot-20011127.orig/src/smtpd/smtpd_check.c snapshot-20011127/src/smtpd/smtpd_check.c --- snapshot-20011127.orig/src/smtpd/smtpd_check.c Mon Dec 3 14:15:13 2001 +++ snapshot-20011127/src/smtpd/smtpd_check.c Mon Dec 3 14:16:39 2001 @@ -916,7 +916,11 @@ msg_info("%s: %s", myname, name); dns_status = dns_lookup_types(name, 0, (DNS_RR **) 0, (VSTRING *) 0, - (VSTRING *) 0, T_A, T_MX, 0); + (VSTRING *) 0, T_A, T_MX, +#ifdef INET6 + T_AAAA, +#endif + 0); if (dns_status != DNS_OK) return (smtpd_check_reject(state, MAIL_ERROR_POLICY, "%d <%s>: %s odrzucony/rejected: Host not found", @@ -938,7 +942,11 @@ msg_info("%s: %s", myname, name); dns_status = dns_lookup_types(name, 0, (DNS_RR **) 0, (VSTRING *) 0, - (VSTRING *) 0, T_A, T_MX, 0); + (VSTRING *) 0, T_A, T_MX, +#ifdef INET6 + T_AAAA, +#endif + 0); if (dns_status != DNS_OK) return (smtpd_check_reject(state, MAIL_ERROR_POLICY, "%d <%s>: %s odrzucony/rejected: Domain not found", @@ -1167,6 +1175,49 @@ static int has_my_addr(const char *host) { +#ifdef INET6 + char *myname = "has_my_addr"; + struct addrinfo hints, *res, *res0; + int error; + char hbuf[NI_MAXHOST]; + + if (msg_verbose) + msg_info("%s: host %s", myname, host); + + /* + * If we can't lookup the host, play safe and assume it is OK. + */ +#define YUP 1 +#define NOPE 0 + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + error = getaddrinfo(host, NULL, &hints, &res0); + if (error) { + if (msg_verbose) + msg_info("%s: host %s: %s", myname, host, gai_strerror(error)); + return (YUP); + } + for (res = res0; res; res = res->ai_next) { + if (msg_verbose) { + if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), + NULL, 0, NI_NUMERICHOST)) { + strncpy(hbuf, "???", sizeof(hbuf)); + } + msg_info("%s: addr %s", myname, hbuf); + } + if (own_inet_addr(res->ai_addr)) { + freeaddrinfo(res0); + return (YUP); + } + } + freeaddrinfo(res0); + if (msg_verbose) + msg_info("%s: host %s: no match", myname, host); + + return (NOPE); +#else char *myname = "has_my_addr"; struct in_addr addr; char **cpp; @@ -1202,6 +1253,7 @@ msg_info("%s: host %s: no match", myname, host); return (NOPE); +#endif } /* i_am_mx - is this machine listed as MX relay */ @@ -1794,7 +1846,7 @@ static int reject_maps_rbl(SMTPD_STATE *state) { char *myname = "reject_maps_rbl"; - ARGV *octets = argv_split(state->addr, "."); + ARGV *octets; VSTRING *query = vstring_alloc(100); char *saved_domains = mystrdup(var_maps_rbl_domains); char *bp = saved_domains; @@ -1806,17 +1858,29 @@ int dns_status = DNS_FAIL; int i; int result; + struct in_addr a; VSTRING *why; if (msg_verbose) msg_info("%s: %s", myname, state->addr); - /* - * IPv4 only for now - */ -#ifdef INET6 +#ifndef INET6 + /* IPv4 only for now */ if (inet_pton(AF_INET, state->addr, &a) != 1) return SMTPD_CHECK_DUNNO; + octets = argv_split(state->addr, "."); +#else + /* IPv4 and IPv6-mapped IPv4 only for now */ + if (inet_pton(AF_INET, state->addr, &a) == 1) + octets = argv_split(state->addr, "."); + else { + struct in6_addr a6; + if (inet_pton(AF_INET6, state->addr, &a6) != 1) + return SMTPD_CHECK_DUNNO; + if (!IN6_IS_ADDR_V4MAPPED(&a6) || (strrchr(state->addr,':') == NULL)) + return SMTPD_CHECK_DUNNO; + octets = argv_split(strrchr(state->addr,':')+1, "."); + } #endif /* diff -Nur snapshot-20011127.orig/src/smtpd/smtpd_peer.c snapshot-20011127/src/smtpd/smtpd_peer.c --- snapshot-20011127.orig/src/smtpd/smtpd_peer.c Thu Jul 5 22:09:47 2001 +++ snapshot-20011127/src/smtpd/smtpd_peer.c Mon Dec 3 14:16:39 2001 @@ -63,6 +63,15 @@ #include #include +/* Utility library. */ + +#include +#include +#include +#include + +/* Global library. */ + /* * Older systems don't have h_errno. Even modern systems don't have * hstrerror(). @@ -84,16 +93,11 @@ ) #endif -/* Utility library. */ - -#include -#include -#include -#include - -/* Global library. */ - - +#ifdef INET6 +#define GAI_STRERROR(error) \ + ((error = EAI_SYSTEM) ? gai_strerror(error) : strerror(errno)) +#endif + /* Application-specific. */ #include "smtpd.h" @@ -102,16 +106,23 @@ void smtpd_peer_init(SMTPD_STATE *state) { - struct sockaddr_in sin; - SOCKADDR_SIZE len = sizeof(sin); +#ifdef INET6 + struct sockaddr_storage ss; +#else + struct sockaddr ss; + struct in_addr *in; struct hostent *hp; - int i; +#endif + struct sockaddr *sa; + SOCKADDR_SIZE len; + + sa = (struct sockaddr *)&ss; + len = sizeof(ss); /* * Look up the peer address information. */ - if (getpeername(vstream_fileno(state->client), - (struct sockaddr *) & sin, &len) >= 0) { + if (getpeername(vstream_fileno(state->client), sa, &len) >= 0) { errno = 0; } @@ -127,18 +138,51 @@ /* * Look up and "verify" the client hostname. */ - else if (errno == 0 && sin.sin_family == AF_INET) { - state->addr = mystrdup(inet_ntoa(sin.sin_addr)); - hp = gethostbyaddr((char *) &(sin.sin_addr), - sizeof(sin.sin_addr), AF_INET); - if (hp == 0) { + else if (errno == 0 && (sa->sa_family == AF_INET +#ifdef INET6 + || sa->sa_family == AF_INET6 +#endif + )) { +#ifdef INET6 + char hbuf[NI_MAXHOST]; + char abuf[NI_MAXHOST]; + struct addrinfo hints, *rnull = NULL; +#else + char abuf[sizeof("255.255.255.255") + 1]; + char *hbuf; +#endif + int error = -1; + +#ifdef INET6 + (void)getnameinfo(sa, len, abuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST); +#else + in = &((struct sockaddr_in *)sa)->sin_addr; + inet_ntop(AF_INET, in, abuf, sizeof(hbuf)); +#endif + state->addr = mystrdup(abuf); +#ifdef INET6 + error = getnameinfo(sa, len, hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD); +#else + hbuf = NULL; + hp = gethostbyaddr((char *)in, sizeof(*in), AF_INET); + if (hp) { + error = 0; + hbuf = mystrdup(hp->h_name); + } else + error = 1; +#endif + if (error) { state->name = mystrdup("unknown"); +#ifdef INET6 + state->peer_code = (error == EAI_AGAIN ? 4 : 5); +#else state->peer_code = (h_errno == TRY_AGAIN ? 4 : 5); - } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) { +#endif + } else if (!valid_hostname(hbuf, DONT_GRIPE)) { state->name = mystrdup("unknown"); state->peer_code = 5; } else { - state->name = mystrdup(hp->h_name); /* hp->name is clobbered!! */ + state->name = mystrdup(hbuf); /* hp->name is clobbered!! */ state->peer_code = 2; /* @@ -150,16 +194,31 @@ state->peer_code = code; \ } +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(state->name, NULL, &hints, &rnull); + if (error) { + msg_warn("%s: hostname %s verification failed: %s", + state->addr, state->name, GAI_STRERROR(error)); + REJECT_PEER_NAME(state, (error == EAI_AGAIN ? 4 : 5)); + } + /* memcmp() isn't needed if we use getaddrinfo */ + if (rnull) + freeaddrinfo(rnull); +#else hp = gethostbyname(state->name); /* clobbers hp->name!! */ if (hp == 0) { msg_warn("%s: hostname %s verification failed: %s", state->addr, state->name, HSTRERROR(h_errno)); REJECT_PEER_NAME(state, (h_errno == TRY_AGAIN ? 4 : 5)); - } else if (hp->h_length != sizeof(sin.sin_addr)) { + } else if (hp->h_length != sizeof(*in)) { msg_warn("%s: hostname %s verification failed: bad address size %d", state->addr, state->name, hp->h_length); REJECT_PEER_NAME(state, 5); } else { + int i; for (i = 0; /* void */ ; i++) { if (hp->h_addr_list[i] == 0) { msg_warn("%s: address not listed for hostname %s", @@ -167,12 +226,11 @@ REJECT_PEER_NAME(state, 5); break; } - if (memcmp(hp->h_addr_list[i], - (char *) &sin.sin_addr, - sizeof(sin.sin_addr)) == 0) + if (memcmp(hp->h_addr_list[i], (char *)in, sizeof(*in)) == 0) break; /* keep peer name */ } } +#endif } } diff -Nur snapshot-20011127.orig/src/smtpstone/smtp-sink.c snapshot-20011127/src/smtpstone/smtp-sink.c --- snapshot-20011127.orig/src/smtpstone/smtp-sink.c Thu Nov 8 21:15:32 2001 +++ snapshot-20011127/src/smtpstone/smtp-sink.c Mon Dec 3 14:16:39 2001 @@ -518,7 +518,7 @@ } else { if (strncmp(argv[optind], "inet:", 5) == 0) argv[optind] += 5; - sock = inet_listen(argv[optind], backlog, BLOCKING); + sock = inet_listen(argv[optind], backlog, BLOCKING, 1); } /* diff -Nur snapshot-20011127.orig/src/util/Makefile.in snapshot-20011127/src/util/Makefile.in --- snapshot-20011127.orig/src/util/Makefile.in Mon Dec 3 14:15:13 2001 +++ snapshot-20011127/src/util/Makefile.in Mon Dec 3 14:16:39 2001 @@ -5,6 +5,7 @@ dict_nisplus.c dict_open.c dir_forest.c doze.c environ.c \ events.c exec_command.c fifo_listen.c fifo_trigger.c file_limit.c \ find_inet.c fsspace.c fullname.c get_domainname.c get_hostname.c \ + get_port.c \ htable.c inet_addr_host.c inet_addr_list.c inet_addr_local.c \ inet_connect.c inet_listen.c inet_trigger.c inet_util.c \ line_wrap.c lowercase.c lstat_as.c mac_parse.c make_dirs.c \ @@ -32,6 +33,7 @@ dict_nisplus.o dict_open.o dir_forest.o doze.o environ.o \ events.o exec_command.o fifo_listen.o fifo_trigger.o file_limit.o \ find_inet.o fsspace.o fullname.o get_domainname.o get_hostname.o \ + get_port.o \ htable.o inet_addr_host.o inet_addr_list.o inet_addr_local.o \ inet_connect.o inet_listen.o inet_trigger.o inet_util.o \ line_wrap.o lowercase.o lstat_as.o mac_parse.o make_dirs.o \ @@ -57,6 +59,7 @@ dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \ dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \ exec_command.h find_inet.h fsspace.h fullname.h get_domainname.h \ + get_port.h \ get_hostname.h htable.h inet_addr_host.h inet_addr_list.h \ inet_addr_local.h inet_util.h iostuff.h line_wrap.h listen.h lstat_as.h \ mac_parse.h make_dirs.h match_list.h match_ops.h msg.h msg_output.h \ @@ -703,6 +706,7 @@ get_domainname.o: mymalloc.h get_domainname.o: get_hostname.h get_domainname.o: get_domainname.h +get_port.o: sys_defs.h get_hostname.o: get_hostname.c get_hostname.o: sys_defs.h get_hostname.o: mymalloc.h @@ -819,6 +823,7 @@ match_list.o: stringops.h match_list.o: argv.h match_list.o: dict.h +match_list.o: inet_util.h match_list.o: match_ops.h match_list.o: match_list.h match_ops.o: match_ops.c diff -Nur snapshot-20011127.orig/src/util/get_port.c snapshot-20011127/src/util/get_port.c --- snapshot-20011127.orig/src/util/get_port.c Thu Jan 1 01:00:00 1970 +++ snapshot-20011127/src/util/get_port.c Mon Dec 3 14:16:39 2001 @@ -0,0 +1,65 @@ +/*++ +/* NAME +/* get_port 3 +/* SUMMARY +/* trivial host and port extracter +/* SYNOPSIS +/* #include +/* +/* char *get_port(data) +/* char *data; +/* +/* DESCRIPTION +/* get_port() extract host name or ip address from +/* strings such as [3ffe:902:12::10]:25, [::1] +/* or 192.168.0.1:25, and null-terminates the +/* \fIdata\fR at the first occurrence of port separator. +/* DIAGNOSTICS +/* If port not found return null pointer. +/* LICENSE +/* .ad +/* .fi +/* BSD Style (or BSD like) license. +/* AUTHOR(S) +/* Arkadiusz Mi¶kiewicz +/* Wroclaw, POLAND +/*--*/ + +/* System libraries */ + +#include +#include + +/* Utility library. */ + +#include "get_port.h" + +/* get_port - extract port number from string */ + +char *get_port(char *data) +{ + const char *escl=strchr(data,'['); + const char *sepl=strchr(data,':'); + char *escr=strrchr(data,']'); + char *sepr=strrchr(data,':'); + + /* extract from "[address]:port" or "[address]"*/ + if (escl && escr) + { + memmove(data, data + 1, strlen(data) - strlen(escr)); + data[strlen(data) - strlen(escr) - 1] = 0; + *escr++ = 0; + if (*escr == ':') + escr++; + return (*escr ? escr : NULL); + } + /* extract from "address:port" or "address" */ + if ((sepl == sepr) && sepr && sepl) + { + *sepr++ = 0; + return sepr; + } + + /* return empty string */ + return NULL; +} diff -Nur snapshot-20011127.orig/src/util/get_port.h snapshot-20011127/src/util/get_port.h --- snapshot-20011127.orig/src/util/get_port.h Thu Jan 1 01:00:00 1970 +++ snapshot-20011127/src/util/get_port.h Mon Dec 3 14:16:39 2001 @@ -0,0 +1,28 @@ +#ifndef _GET_PORT_H_INCLUDED_ +#define _GET_PORT_H_INCLUDED_ + +/*++ +/* NAME +/* get_port 3h +/* SUMMARY +/* trivial host and port extracter +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* External interface. */ + +extern char *get_port(char *); + + +/* LICENSE +/* .ad +/* .fi +/* BSD Style (or BSD like) license. +/* AUTHOR(S) +/* Arkadiusz Mi¶kiewicz +/* Wroclaw, POLAND +/*--*/ + +#endif diff -Nur snapshot-20011127.orig/src/util/inet_addr_host.c snapshot-20011127/src/util/inet_addr_host.c --- snapshot-20011127.orig/src/util/inet_addr_host.c Fri Dec 11 19:55:35 1998 +++ snapshot-20011127/src/util/inet_addr_host.c Mon Dec 3 14:16:39 2001 @@ -38,7 +38,10 @@ #include #include #include +#include #include +#include +#include #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff @@ -48,15 +51,47 @@ #include #include +#ifdef TEST +#include +#endif /* inet_addr_host - look up address list for host */ int inet_addr_host(INET_ADDR_LIST *addr_list, const char *hostname) { +#ifdef INET6 + int s; + struct addrinfo hints, *res0, *res; +#ifdef TEST + char buforhosta[1024]; +#endif + int error; +#else struct hostent *hp; struct in_addr addr; +#endif int initial_count = addr_list->used; +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + error = getaddrinfo(hostname, NULL, &hints, &res0); + if (error == 0) { + for (res = res0; res; res = res->ai_next) { + if(res->ai_family != AF_INET && res->ai_family != AF_INET6) + continue; + /* filter out address families that are not supported */ + s = socket(res->ai_family, SOCK_DGRAM, 0); + if (s < 0) + continue; + close(s); + + inet_addr_list_append(addr_list, res->ai_addr); + } + freeaddrinfo(res0); + } +#else if ((addr.s_addr = inet_addr(hostname)) != INADDR_NONE) { inet_addr_list_append(addr_list, &addr); } else { @@ -65,9 +100,12 @@ inet_addr_list_append(addr_list, (struct in_addr *) * hp->h_addr_list++); } +#endif + return (addr_list->used - initial_count); } + #ifdef TEST #include @@ -78,6 +116,8 @@ { INET_ADDR_LIST addr_list; int i; + struct sockaddr *sa; + char hbuf[NI_MAXHOST]; msg_vstream_init(argv[0], VSTREAM_ERR); @@ -89,8 +129,12 @@ if (inet_addr_host(&addr_list, *argv) == 0) msg_fatal("not found: %s", *argv); - for (i = 0; i < addr_list.used; i++) - vstream_printf("%s\n", inet_ntoa(addr_list.addrs[i])); + for (i = 0; i < addr_list.used; i++) { + sa = (struct sockaddr *)&addr_list.addrs[i]; + getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST); + vstream_printf("%s\n", hbuf); + } vstream_fflush(VSTREAM_OUT); } inet_addr_list_free(&addr_list); diff -Nur snapshot-20011127.orig/src/util/inet_addr_list.c snapshot-20011127/src/util/inet_addr_list.c --- snapshot-20011127.orig/src/util/inet_addr_list.c Tue Jul 31 20:13:41 2001 +++ snapshot-20011127/src/util/inet_addr_list.c Mon Dec 3 14:21:19 2001 @@ -51,6 +51,13 @@ #include #include +#include + +#ifdef INET6 +#include +#include +#endif + /* Utility library. */ #include @@ -63,12 +70,39 @@ { list->used = 0; list->size = 2; +#ifdef INET6 + list->addrs = (struct sockaddr_storage *) +#else list->addrs = (struct in_addr *) +#endif mymalloc(sizeof(*list->addrs) * list->size); } /* inet_addr_list_append - append address to internet address list */ +#ifdef INET6 +void inet_addr_list_append(INET_ADDR_LIST *list, + struct sockaddr * addr) +{ + char *myname = "inet_addr_list_append"; + char hbuf[NI_MAXHOST]; + + if (msg_verbose > 1) { + if (getnameinfo(addr, SA_LEN(addr), hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST)) { + strncpy(hbuf, "??????", sizeof(hbuf)); + } + msg_info("%s: %s", myname, hbuf); + } + + if (list->used >= list->size) + list->size *= 2; + list->addrs = (struct sockaddr_storage *) + myrealloc((char *) list->addrs, + sizeof(*list->addrs) * list->size); + memcpy(&list->addrs[list->used++], addr, SA_LEN(addr)); +} +#else void inet_addr_list_append(INET_ADDR_LIST *list, struct in_addr * addr) { char *myname = "inet_addr_list_append"; @@ -83,15 +117,22 @@ sizeof(*list->addrs) * list->size); list->addrs[list->used++] = *addr; } +#endif /* inet_addr_list_comp - compare addresses */ static int inet_addr_list_comp(const void *a, const void *b) { +#ifdef INET6 + if(((struct sockaddr*)a)->sa_family != ((struct sockaddr*)b)->sa_family) + return ( ((struct sockaddr*)a)->sa_family - ((struct sockaddr*)b)->sa_family ); + return memcmp(a,b,SA_LEN((struct sockaddr*)a)); +#else const struct in_addr *a_addr = (const struct in_addr *) a; const struct in_addr *b_addr = (const struct in_addr *) b; return (a_addr->s_addr - b_addr->s_addr); +#endif } /* inet_addr_list_uniq - weed out duplicates */ diff -Nur snapshot-20011127.orig/src/util/inet_addr_list.h snapshot-20011127/src/util/inet_addr_list.h --- snapshot-20011127.orig/src/util/inet_addr_list.h Tue Jul 31 19:56:47 2001 +++ snapshot-20011127/src/util/inet_addr_list.h Mon Dec 3 14:16:39 2001 @@ -16,19 +16,38 @@ */ #include +#ifndef SA_LEN +#ifndef HAS_SA_LEN +#define SA_LEN(x) (((x)->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) +#define SS_LEN(x) (((x).ss_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) +#else +#define SA_LEN(x) ((x)->sa_len) +#define SS_LEN(x) ((x).ss_len) +#endif +#endif + /* * External interface. */ typedef struct INET_ADDR_LIST { int used; /* nr of elements in use */ int size; /* actual list size */ +#ifdef INET6 + struct sockaddr_storage *addrs; /* payload */ +#else struct in_addr *addrs; /* payload */ +#endif } INET_ADDR_LIST; extern void inet_addr_list_init(INET_ADDR_LIST *); extern void inet_addr_list_free(INET_ADDR_LIST *); extern void inet_addr_list_uniq(INET_ADDR_LIST *); +#ifdef INET6 +struct sockaddr; +extern void inet_addr_list_append(INET_ADDR_LIST *, struct sockaddr *); +#else extern void inet_addr_list_append(INET_ADDR_LIST *, struct in_addr *); +#endif /* LICENSE /* .ad diff -Nur snapshot-20011127.orig/src/util/inet_addr_local.c snapshot-20011127/src/util/inet_addr_local.c --- snapshot-20011127.orig/src/util/inet_addr_local.c Sun Feb 25 19:20:19 2001 +++ snapshot-20011127/src/util/inet_addr_local.c Mon Dec 3 14:16:39 2001 @@ -47,6 +47,13 @@ #endif #include #include +#if defined(INET6) && (defined (LINUX) || defined (LINUX2)) +#include +#include +#endif +#ifdef HAVE_GETIFADDRS +#include +#endif /* Utility library. */ @@ -78,18 +85,104 @@ int inet_addr_local(INET_ADDR_LIST *addr_list, INET_ADDR_LIST *mask_list) { +#ifdef HAVE_GETIFADDRS + char *myname = "inet_addr_local"; + struct ifaddrs *ifap, *ifa; + int initial_count = addr_list->used; + struct sockaddr *sa, *sam; +#ifdef INET6 +#ifdef __KAME__ + struct sockaddr_in6 addr6; +#endif +#else + void *addr, *addrm; +#endif + + if (getifaddrs(&ifap) < 0) + msg_fatal("%s: getifaddrs: %m", myname); + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (! (ifa->ifa_flags & IFF_RUNNING) || ifa->ifa_addr==NULL) + continue; + sa = ifa->ifa_addr; + sam = ifa->ifa_netmask; + switch (ifa->ifa_addr->sa_family) { + case AF_INET: +#ifndef INET6 + addr = (void *)&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; + addrm = (void *)&((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr; +#endif + break; +#ifdef INET6 + case AF_INET6: +#ifdef __KAME__ + memcpy(&addr6, ifa->ifa_addr, ifa->ifa_addr->sa_len); + /* decode scoped address notation */ + if ((IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) || + IN6_IS_ADDR_SITELOCAL(&addr6.sin6_addr)) && + addr6.sin6_scope_id == 0) { + addr6.sin6_scope_id = ntohs(addr6.sin6_addr.s6_addr[3] | + (unsigned int)addr6.sin6_addr.s6_addr[2] << 8); + addr6.sin6_addr.s6_addr[2] = addr6.sin6_addr.s6_addr[3] = 0; + sa = (struct sockaddr *)&addr6; + } +#endif + break; +#endif + default: + continue; + } + +#ifdef INET6 + inet_addr_list_append(addr_list, sa); + if (mask_list != NULL) + inet_addr_list_append(mask_list, sam); +#else + inet_addr_list_append(addr_list, (struct in_addr *)addr); + if (mask_list != NULL) + inet_addr_list_append(mask_list, (struct in_addr *)addrm); +#endif + } + + freeifaddrs(ifap); + return (addr_list->used - initial_count); +#else char *myname = "inet_addr_local"; struct ifconf ifc; struct ifreq *ifr; struct ifreq *the_end; int sock; - VSTRING *buf = vstring_alloc(1024); + VSTRING *buf; int initial_count = addr_list->used; struct in_addr addr; struct ifreq *ifr_mask; + int af = AF_INET; +#ifdef INET6 +#if defined (LINUX) || defined (LINUX2) +#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6" + FILE *f; + char addr6p[8][5], addr6res[40], devname[20]; + int plen, scope, dad_status, if_idx, gaierror; + struct addrinfo hints, *res, *res0; +#endif + struct sockaddr_in6 addr6; - if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) +other_socket_type: +#endif + buf = vstring_alloc(1024); + + if ((sock = socket(af, SOCK_DGRAM, 0)) < 0) { +#ifdef INET6 + if (af == AF_INET6) + { + if (msg_verbose) + msg_warn("%s: socket: %m", myname); + goto end; + } + else +#endif msg_fatal("%s: socket: %m", myname); + } /* * Get the network interface list. XXX The socket API appears to have no @@ -126,10 +213,15 @@ */ the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); for (ifr = ifc.ifc_req; ifr < the_end;) { - if (ifr->ifr_addr.sa_family == AF_INET) { /* IP interface */ + if ((ifr->ifr_addr.sa_family == AF_INET) && + (ifr->ifr_addr.sa_family == af)) { /* IP interface */ addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr; if (addr.s_addr != INADDR_ANY) { /* has IP address */ +#ifdef INET6 + inet_addr_list_append(addr_list, &ifr->ifr_addr); +#else inet_addr_list_append(addr_list, &addr); +#endif if (mask_list) { ifr_mask = (struct ifreq *) mymalloc(IFREQ_SIZE(ifr)); memcpy((char *) ifr_mask, (char *) ifr, IFREQ_SIZE(ifr)); @@ -141,11 +233,61 @@ } } } +#ifdef INET6 + else if ((ifr->ifr_addr.sa_family == AF_INET6) && + (ifr->ifr_addr.sa_family == af)) { /* IPv6 interface */ + addr6 = *((struct sockaddr_in6 *) & ifr->ifr_addr); +#ifdef __KAME__ + /* decode scoped address notation */ + if ((IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) || + IN6_IS_ADDR_SITELOCAL(&addr6.sin6_addr)) && + addr6.sin6_scope_id == 0) { + addr6.sin6_scope_id = ntohs(addr6.sin6_addr.s6_addr[3] | + (unsigned int)addr6.sin6_addr.s6_addr[2] << 8); + addr6.sin6_addr.s6_addr[2] = addr6.sin6_addr.s6_addr[3] = 0; + } +#endif + if (!(IN6_IS_ADDR_UNSPECIFIED(&addr6.sin6_addr))) + inet_addr_list_append(addr_list, (struct sockaddr *)&addr6); + } +#endif ifr = NEXT_INTERFACE(ifr); } vstring_free(buf); (void) close(sock); +#ifdef INET6 +end: + if (af != AF_INET6) { + af = AF_INET6; + goto other_socket_type; + } +#if defined (LINUX) || defined (LINUX2) + if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) { + while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", + addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], + addr6p[5], addr6p[6], addr6p[7], + &if_idx, &plen, &scope, &dad_status, devname) != EOF) { + sprintf(addr6res, "%s:%s:%s:%s:%s:%s:%s:%s", + addr6p[0], addr6p[1], addr6p[2], addr6p[3], + addr6p[4], addr6p[5], addr6p[6], addr6p[7]); + addr6res[sizeof(addr6res) - 1] = 0; + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + gaierror = getaddrinfo(addr6res, NULL, &hints, &res0); + if (!gaierror) { + for (res = res0; res; res = res->ai_next) { + inet_addr_list_append(addr_list, res->ai_addr); + } + freeaddrinfo(res0); + } + } + } +#endif /* linux */ +#endif return (addr_list->used - initial_count); +#endif } #ifdef TEST @@ -158,6 +300,8 @@ INET_ADDR_LIST addr_list; INET_ADDR_LIST mask_list; int i; + char abuf[NI_MAXHOST], mbuf[NI_MAXHOST]; + struct sockaddr *sa; msg_vstream_init(argv[0], VSTREAM_ERR); @@ -172,8 +316,17 @@ msg_warn("found only one active network interface"); for (i = 0; i < addr_list.used; i++) { - vstream_printf("%s/", inet_ntoa(addr_list.addrs[i])); - vstream_printf("%s\n", inet_ntoa(mask_list.addrs[i])); + sa = (struct sockaddr *)&addr_list.addrs[i]; + if (getnameinfo(sa, SA_LEN(sa), abuf, sizeof(abuf), NULL, 0, + NI_NUMERICHOST)) { + strncpy(abuf, "???", sizeof(abuf)); + } + sa = (struct sockaddr *)&mask_list.addrs[i]; + if (getnameinfo(sa, SA_LEN(sa), mbuf, sizeof(mbuf), NULL, 0, + NI_NUMERICHOST)) { + strncpy(mbuf, "???", sizeof(mbuf)); + } + vstream_printf("%s/%s\n", abuf, mbuf); } vstream_fflush(VSTREAM_OUT); inet_addr_list_free(&addr_list); diff -Nur snapshot-20011127.orig/src/util/inet_connect.c snapshot-20011127/src/util/inet_connect.c --- snapshot-20011127.orig/src/util/inet_connect.c Mon Nov 20 19:06:31 2000 +++ snapshot-20011127/src/util/inet_connect.c Mon Dec 3 14:16:39 2001 @@ -55,6 +55,9 @@ #include #include #include +#ifdef INET6 +#include +#endif /* Utility library. */ @@ -73,7 +76,12 @@ char *buf; char *host; char *port; +#ifdef INET6 + struct addrinfo hints, *res, *res0; + int error; +#else struct sockaddr_in sin; +#endif int sock; /* @@ -81,14 +89,58 @@ * the local host. */ buf = inet_parse(addr, &host, &port); +#ifdef INET6 + if (*host == 0) + host = NULL; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; /* find_inet_addr is numeric only */ + if (getaddrinfo(host, port, &hints, &res0)) + msg_fatal("host not found: %s", host); +#else if (*host == 0) host = "localhost"; memset((char *) &sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = find_inet_addr(host); sin.sin_port = find_inet_port(port, "tcp"); +#endif myfree(buf); +#ifdef INET6 + sock = -1; + for (res = res0; res; res = res->ai_next) { + if ((res->ai_family != AF_INET) && (res->ai_family != AF_INET6)) + continue; + + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock < 0) + continue; + if (timeout > 0) { + non_blocking(sock, NON_BLOCKING); + if (timed_connect(sock, res->ai_addr, res->ai_addrlen, timeout) < 0) { + close(sock); + sock = -1; + continue; + } + if (block_mode != NON_BLOCKING) + non_blocking(sock, block_mode); + break; + } else { + non_blocking(sock, block_mode); + if (connect(sock, res->ai_addr, res->ai_addrlen) < 0 + && errno != EINPROGRESS) { + close(sock); + sock = -1; + continue; + } + break; + } + } + freeaddrinfo(res0); + return sock; +#else /* * Create a client socket. */ @@ -121,4 +173,5 @@ } return (sock); } +#endif } diff -Nur snapshot-20011127.orig/src/util/inet_listen.c snapshot-20011127/src/util/inet_listen.c --- snapshot-20011127.orig/src/util/inet_listen.c Mon Nov 20 19:06:32 2000 +++ snapshot-20011127/src/util/inet_listen.c Mon Dec 3 14:16:39 2001 @@ -6,7 +6,7 @@ /* SYNOPSIS /* #include /* -/* int inet_listen(addr, backlog, block_mode) +/* int inet_listen(addr, backlog, block_mode, addinuse_fatal) /* const char *addr; /* int backlog; /* int block_mode; @@ -51,11 +51,17 @@ #include #include #include +#ifdef INET6 +#if (! __GLIBC__ >= 2 && __GLIBC_MINOR__ >=1 ) +#include +#endif +#endif #include #include #ifndef MAXHOSTNAMELEN #include #endif +#include #include #include @@ -77,35 +83,116 @@ /* inet_listen - create inet-domain listener */ -int inet_listen(const char *addr, int backlog, int block_mode) +int inet_listen(const char *addr, int backlog, int block_mode, int addrinuse_fatal) { +#ifdef INET6 + struct addrinfo *res, *res0, hints; + int error; +#else + struct ai { + int ai_family; + int ai_socktype; + int ai_protocol; + struct sockaddr *ai_addr; + SOCKADDR_SIZE ai_addrlen; + struct ai *ai_next; + } *res, *res0, resbody; struct sockaddr_in sin; +#endif int sock; int t = 1; + int addrinuse = 0; char *buf; char *host; char *port; +#ifdef INET6 + char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; +#else + char hbuf[sizeof("255.255.255.255") + 1]; + char pbuf[sizeof("255.255.255.255") + 1]; +#endif + char *cause = "unknown"; /* * Translate address information to internal form. */ buf = inet_parse(addr, &host, &port); - memset((char *) &sin, 0, sizeof(sin)); +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(*host ? host : NULL, *port ? port : "0", &hints, &res0); + if (error) { + msg_fatal("getaddrinfo: %s", gai_strerror(error)); + } + myfree(buf); +#else + memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; +#ifdef HAS_SA_LEN + sin.sin_len = sizeof(sin); +#endif sin.sin_port = find_inet_port(port, "tcp"); sin.sin_addr.s_addr = (*host ? find_inet_addr(host) : INADDR_ANY); - myfree(buf); - /* - * Create a listener socket. - */ - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) - msg_fatal("socket: %m"); - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &t, sizeof(t)) < 0) - msg_fatal("setsockopt: %m"); - if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) - msg_fatal("bind %s port %d: %m", sin.sin_addr.s_addr == INADDR_ANY ? - "INADDR_ANY" : inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); + memset(&resbody, 0, sizeof(resbody)); + resbody.ai_socktype = SOCK_STREAM; + resbody.ai_family = AF_INET; + resbody.ai_addr = (struct sockaddr *)&sin; + resbody.ai_addrlen = sizeof(sin); + + res0 = &resbody; +#endif + + sock = -1; + for (res = res0; res; res = res->ai_next) { + if ((res->ai_family != AF_INET) && (res->ai_family != AF_INET6)) + continue; + + /* + * Create a listener socket. + */ + if ((sock = socket(res->ai_family, res->ai_socktype, 0)) < 0) { + cause = "socket"; + continue; + } +#ifdef IPV6_V6ONLY + if (res->ai_family == AF_INET6 && + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &t, sizeof(t)) < 0) { + /* if kernel/libc don't support this simple ignore it + cause = "setsockopt(IPV6_V6ONLY)"; + close(sock); + sock = -1; + continue; + */ + ; + } +#endif + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &t, sizeof(t)) < 0) { + cause = "setsockopt(SO_REUSEADDR)"; + close(sock); + sock = -1; + continue; + } + + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { + cause = "bind"; + if (errno == EADDRINUSE) + addrinuse = 1; + close(sock); + sock = -1; + continue; + } + break; + } + if (sock < 0 && (addrinuse_fatal || !addrinuse)) + msg_fatal("%s: %m", cause); +#ifdef INET6 + freeaddrinfo(res0); +#endif + if (sock < 0) + return -1; non_blocking(sock, block_mode); if (listen(sock, backlog) < 0) msg_fatal("listen: %m"); diff -Nur snapshot-20011127.orig/src/util/listen.h snapshot-20011127/src/util/listen.h --- snapshot-20011127.orig/src/util/listen.h Mon Mar 22 02:57:11 1999 +++ snapshot-20011127/src/util/listen.h Mon Dec 3 14:16:39 2001 @@ -20,7 +20,7 @@ * Listener external interface. */ extern int unix_listen(const char *, int, int); -extern int inet_listen(const char *, int, int); +extern int inet_listen(const char *, int, int, int); extern int fifo_listen(const char *, int, int); extern int stream_listen(const char *, int, int); diff -Nur snapshot-20011127.orig/src/util/match_list.c snapshot-20011127/src/util/match_list.c --- snapshot-20011127.orig/src/util/match_list.c Tue Nov 20 21:07:15 2001 +++ snapshot-20011127/src/util/match_list.c Mon Dec 3 14:16:39 2001 @@ -118,7 +118,7 @@ list = match_list_parse(list, vstring_str(buf)); if (vstream_fclose(fp)) msg_fatal("%s: read file %s: %m", myname, pattern); - } else if (strchr(pattern, ':') != 0) { /* type:table */ + } else if ((strchr(pattern, ']') == 0) && (strchr(pattern, ':') != 0)) { /* type:table */ for (cp = pattern; *cp == '!'; cp++) /* void */ ; if (dict_handle(pattern) == 0) diff -Nur snapshot-20011127.orig/src/util/match_ops.c snapshot-20011127/src/util/match_ops.c --- snapshot-20011127.orig/src/util/match_ops.c Tue Nov 20 21:16:10 2001 +++ snapshot-20011127/src/util/match_ops.c Mon Dec 3 14:16:39 2001 @@ -81,6 +81,307 @@ #include #include +#ifdef INET6 +/* + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Alexey Kuznetsov, + * + * Modifications: + * Artur Frysiak + * Arkadiusz Mi¶kiewicz + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef AF_DECnet +#define AF_DECnet 12 +#endif + +#ifndef PF_PACKET +#define PF_PACKET 17 +#endif + +typedef struct +{ + unsigned char family; + unsigned char bytelen; + signed short bitlen; + unsigned int data[4]; +} inet_prefix; + +/* prototypes */ +int masked_match(char *, char *, char *); +int get_integer(int *, char *, int); +int get_addr_1(inet_prefix *, char *, int); +int get_prefix_1(inet_prefix *, char *, int); +int get_addr(inet_prefix *, char *, int); +int get_prefix(inet_prefix *, char *, int); +unsigned int get_addr32(char *); +int matches(char *, char *); +int inet_addr_match(inet_prefix *, inet_prefix *, int); +int mask_match(char *, char *, char *); + +int get_integer(int *val, char *arg, int base) +{ + long res; + char *ptr; + + if (!arg || !*arg) + return -1; + res = strtol(arg, &ptr, base); + if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN) + return -1; + *val = res; + return 0; +} + +int get_addr_1(inet_prefix *addr, char *name, int family) +{ + char *cp; + unsigned char *ap = (unsigned char*)addr->data; + int i; + + memset(addr, 0, sizeof(*addr)); + + if (strcmp(name, "default") == 0 || strcmp(name, "any") == 0) { + if (family == AF_DECnet) + return -1; + addr->family = family; + addr->bytelen = (family == AF_INET6 ? 16 : 4); + addr->bitlen = -1; + return 0; + } + + if (strchr(name, ':')) { + addr->family = AF_INET6; + if (family != AF_UNSPEC && family != AF_INET6) + return -1; + if (inet_pton(AF_INET6, name, addr->data) <= 0) + return -1; + addr->bytelen = 16; + addr->bitlen = -1; + return 0; + } + addr->family = AF_INET; + if (family != AF_UNSPEC && family != AF_INET) + return -1; + addr->bytelen = 4; + addr->bitlen = -1; + for (cp = name, i = 0; *cp; cp++) { + if (*cp <= '9' && *cp >= '0') { + ap[i] = 10*ap[i] + (*cp-'0'); + continue; + } + if (*cp == '.' && ++i <= 3) + continue; + return -1; + } + return 0; +} + +int get_prefix_1(inet_prefix *dst, char *arg, int family) +{ + int err; + unsigned plen; + char *slash; + + memset(dst, 0, sizeof(*dst)); + + if (strcmp(arg, "default") == 0 || strcmp(arg, "any") == 0) { + if (family == AF_DECnet) + return -1; + dst->family = family; + dst->bytelen = 0; + dst->bitlen = 0; + return 0; + } + + slash = strchr(arg, '/'); + if (slash) + *slash = 0; + err = get_addr_1(dst, arg, family); + if (err == 0) { + switch(dst->family) { + case AF_INET6: + dst->bitlen = 128; + break; + case AF_DECnet: + dst->bitlen = 16; + break; + default: + case AF_INET: + dst->bitlen = 32; + } + if (slash) { + if (get_integer(&plen, slash+1, 0) || plen > dst->bitlen) { + err = -1; + goto done; + } + dst->bitlen = plen; + } + } +done: + if (slash) + *slash = '/'; + return err; +} + +int get_addr(inet_prefix *dst, char *arg, int family) +{ +#ifdef AF_PACKET + if (family == AF_PACKET) + return -1; +#endif + if (get_addr_1(dst, arg, family)) + return -1; + return 0; +} + +int get_prefix(inet_prefix *dst, char *arg, int family) +{ +#ifdef AF_PACKET + if (family == AF_PACKET) + return -1; +#endif + if (get_prefix_1(dst, arg, family)) + return -1; + return 0; +} + +unsigned int get_addr32(char *name) +{ + inet_prefix addr; + if (get_addr_1(&addr, name, AF_INET)) + return -1; + return addr.data[0]; +} + +int matches(char *cmd, char *pattern) +{ + int len = strlen(cmd); + if (len > strlen(pattern)) + return -1; + return memcmp(pattern, cmd, len); +} + +int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits) +{ + unsigned int *a1 = a->data; + unsigned int *a2 = b->data; + int words = bits >> 0x05; + + bits &= 0x1f; + + if (words) + if (memcmp(a1, a2, words << 2)) + return -1; + + if (bits) { + unsigned int w1, w2; + unsigned int mask; + + w1 = a1[words]; + w2 = a2[words]; + + mask = htonl((0xffffffff) << (0x20 - bits)); + + if ((w1 ^ w2) & mask) + return 1; + } + + return 0; +} + +/* zero if matches */ +int mask_match(char *network, char *cprefix, char *address) +{ + inet_prefix *inetwork; + inet_prefix *iaddress; + int ret, prefix; + + if (!(network && address && cprefix)) + return -1; + prefix = strtol(cprefix, (char **)NULL, 10); + if ((prefix < 0) || (prefix > 128)) + return -1; + if ((strlen(network) == 0) || (strlen(address) == 0)) + return -1; + + inetwork = malloc(sizeof(inet_prefix)); + iaddress = malloc(sizeof(inet_prefix)); + + if ((get_addr(iaddress, address, AF_UNSPEC) >= 0) + && (get_addr(inetwork, network, AF_UNSPEC) >= 0)) + ret = inet_addr_match(inetwork, iaddress, prefix); + else + ret = -1; + free(inetwork); + free(iaddress); + + /* 1 if matches */ + /* return (!ret); */ + /* 0 if matches */ + return ret; +} + +/* + * masked_match() - universal for IPv4 and IPv6 - 1 if matches + */ +int masked_match(net_tok, mask_tok, string) +char *net_tok; +char *mask_tok; +char *string; +{ +#ifdef INET6 + struct in6_addr in6[2]; + char v4addr[2][INET_ADDRSTRLEN]; + char newmask[6]; + int plen; +#endif + + /* Check for NULL */ + if (!(net_tok && mask_tok && string)) + return 0; /* doesn't match!!! */ + + /* If IPv6 mapped convert to native-IPv4 */ +#ifdef INET6 + if (inet_pton(AF_INET6, net_tok, &in6[0]) == 1 && + inet_pton(AF_INET6, string, &in6[1]) == 1 && + IN6_IS_ADDR_V4MAPPED(&in6[0]) && IN6_IS_ADDR_V4MAPPED(&in6[1])) { + plen = atoi(mask_tok); + if (32 < plen && plen < 129) { + sprintf(newmask, "%d", plen - 96); + mask_tok = newmask; + } + + (void)inet_ntop(AF_INET, &in6[0].s6_addr[12], v4addr[0], + sizeof(v4addr[0])); + net_tok = v4addr[0]; + (void)inet_ntop(AF_INET, &in6[1].s6_addr[12], v4addr[1], + sizeof(v4addr[1])); + string = v4addr[1]; + } +#endif + return (!mask_match(net_tok, mask_tok, string)); +} +#endif + /* match_string - match a string literal */ int match_string(int unused_flags, const char *string, const char *pattern) @@ -177,6 +478,7 @@ return (0); } +#ifndef INET6 /* match_parse_mask - parse net/mask pattern */ static int match_parse_mask(const char *pattern, unsigned long *net_bits, @@ -198,27 +500,55 @@ return (mask != 0); } +#endif + /* match_hostaddr - match host by address */ int match_hostaddr(int unused_flags, const char *addr, const char *pattern) { char *myname = "match_hostaddr"; +#ifdef INET6 + char *network, *mask, *escl, *escr, *patternx; + struct in6_addr in6; + char v4addr[INET_ADDRSTRLEN]; +#else int mask_shift; unsigned long mask_bits; unsigned long net_bits; unsigned long addr_bits; +#endif if (msg_verbose) msg_info("%s: %s ~? %s", myname, addr, pattern); +#ifdef INET6 + if (addr[strspn(addr, "01234567890./:abcdef")] != 0) +#else if (addr[strspn(addr, "01234567890./:")] != 0) +#endif return (0); +#ifdef INET6 + patternx = mystrdup(pattern); + escl = strchr(patternx,'['); + escr = strrchr(patternx,']'); + if (escl && escr) { + *escr = 0; + sprintf(patternx, "%s%s", escl + 1, escr + 1); + pattern = patternx; + } +#endif + /* * Try dictionary lookup. This can be case insensitive. XXX Probably * should also try again after stripping least significant octets. */ - if (strchr(pattern, ':') != 0) { +#ifdef INET6 + if (!(escl && escr) && strchr(pattern, ':') != 0) +#else + if (strchr(pattern, ':') != 0) +#endif + { if (dict_lookup(pattern, addr) != 0) return (1); if (dict_errno != 0) @@ -229,6 +559,12 @@ /* * Try an exact match with the host address. */ +#ifdef INET6 + if (inet_pton(AF_INET6, addr, &in6) == 1 && IN6_IS_ADDR_V4MAPPED(&in6)) { + (void)inet_ntop(AF_INET, &in6.s6_addr[12], v4addr, sizeof(v4addr)); + addr = v4addr; + } +#endif if (strcasecmp(addr, pattern) == 0) { return (1); } @@ -237,6 +573,20 @@ * In a net/mask pattern, the mask is specified as the number of bits of * the network part. */ +#ifdef INET6 + network = mystrdup(patternx); + mask = split_at(network, '/'); + + if (masked_match(network, mask, (char *)addr)) { + myfree(network); + myfree(patternx); + return (1); + } else { + myfree(network); + myfree(patternx); + } +#else + if (match_parse_mask(pattern, &net_bits, &mask_shift)) { addr_bits = inet_addr(addr); if (addr_bits == INADDR_NONE) @@ -244,5 +594,6 @@ mask_bits = htonl((0xffffffff) << (BITS_PER_ADDR - mask_shift)); return ((addr_bits & mask_bits) == (net_bits & mask_bits)); } +#endif return (0); } diff -Nur snapshot-20011127.orig/src/util/sys_defs.h snapshot-20011127/src/util/sys_defs.h --- snapshot-20011127.orig/src/util/sys_defs.h Mon Dec 3 14:15:12 2001 +++ snapshot-20011127/src/util/sys_defs.h Mon Dec 3 14:16:39 2001 @@ -68,6 +68,10 @@ #define DEF_MAILBOX_LOCK "flock, dotlock" #endif +#if ((defined(__NetBSD_Version__) && __NetBSD_Version__ >= 105000000) || defined(USAGI_LIBINET6)) +#define HAVE_GETIFADDRS +#endif + /* * UNIX on MAC. */ diff -Nur snapshot-20011127.orig/src/util/valid_hostname.c snapshot-20011127/src/util/valid_hostname.c --- snapshot-20011127.orig/src/util/valid_hostname.c Sun Jan 28 15:10:18 2001 +++ snapshot-20011127/src/util/valid_hostname.c Mon Dec 3 14:16:39 2001 @@ -47,6 +47,13 @@ #include #include +#ifdef INET6 +#include +#include +#include +#include +#endif + /* Utility library. */ #include "msg.h" @@ -103,7 +110,23 @@ msg_warn("%s: misplaced hyphen: %.100s", myname, name); return (0); } - } else { + } +#ifdef INET6 + else if (ch == ':') { + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(name, "0", &hints, &res) == 0) { + freeaddrinfo(res); + return 1; + } else + return 0; + } +#endif + else { if (gripe) msg_warn("%s: invalid character %d(decimal): %.100s", myname, ch, name); @@ -135,6 +158,9 @@ int byte_count = 0; int byte_val = 0; int ch; +#ifdef INET6 + struct addrinfo hints, *res; +#endif #define BYTES_NEEDED 4 @@ -146,6 +172,17 @@ msg_warn("%s: empty address", myname); return (0); } + +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(addr, "0", &hints, &res) == 0) { + freeaddrinfo(res); + return 1; + } +#endif /* * Scary code to avoid sscanf() overflow nasties.