diff -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/makedefs postfix-2.0.16/makedefs --- postfix-2.0.16.orig/makedefs 2003-01-23 14:45:02.000000000 +0100 +++ postfix-2.0.16/makedefs 2005-01-07 18:25:30.197331464 +0100 @@ -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;; @@ -318,6 +333,26 @@ : ${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 + 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 sed 's/ / /g' < #include #include +#ifdef INET6 +#include +#include +#include +#endif +#include /* Global library. */ @@ -75,6 +81,9 @@ const char *mynetworks(void) { static VSTRING *result; +#ifdef INET6 + char hbuf[NI_MAXHOST]; +#endif if (result == 0) { char *myname = "mynetworks"; @@ -87,6 +96,13 @@ int junk; int i; int mask_style; +#ifdef INET6 + struct sockaddr *sa; + struct sockaddr_in6 *addr6; + struct sockaddr_in6 *mask6; + struct in6_addr net6; + int j; +#endif mask_style = name_mask("mynetworks mask style", mask_styles, var_mynetworks_style); @@ -96,8 +112,45 @@ 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_INET6) { + addr6 = (struct sockaddr_in6 *)sa; + mask6 = (struct sockaddr_in6 *)&my_mask_list->addrs[i]; + + switch (mask_style) { + case MASK_STYLE_CLASS: + /* treat as subnet for IPv6 */ + case MASK_STYLE_SUBNET: + for (j=0; j<16; j++) + net6.s6_addr[j] = addr6->sin6_addr.s6_addr[j] & mask6->sin6_addr.s6_addr[j]; + for(shift=128; shift>0; shift--) + if ((mask6->sin6_addr.s6_addr[(shift-1) / 8]) & (0x80 >> ((shift-1) % 8))) + break; + break; + case MASK_STYLE_HOST: + memcpy (&net6, &(addr6->sin6_addr), sizeof(net6)); + shift=128; + break; + default: + msg_panic("unknown mynetworks mask style: %s", + var_mynetworks_style); + } + inet_ntop(AF_INET6, &net6, hbuf, sizeof(hbuf)); + if (!shift) + msg_warn("%s: skipped network with zero mask: [%s/0]", myname, hbuf); + else + vstring_sprintf_append(result, "[%s/%d] ", hbuf, shift); + continue; + } else if (sa->sa_family != AF_INET) { + 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 +172,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; @@ -146,6 +206,18 @@ var_mynetworks_style); } net.s_addr = htonl(addr & mask); + if (shift == BITS_PER_ADDR) { +#ifdef INET6 + if (getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST)) + strncpy(hbuf, "???", sizeof(hbuf)); + msg_warn("%s: skipped network with zero mask: %s/0", myname, hbuf); +#else + msg_warn("%s: skipped network with zero mask: %s/0", + myname, inet_ntoa(my_addr_list->addrs[i])); +#endif + continue; + } vstring_sprintf_append(result, "%s/%d ", inet_ntoa(net), BITS_PER_ADDR - shift); } diff -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/global/own_inet_addr.c postfix-2.0.16/src/global/own_inet_addr.c --- postfix-2.0.16.orig/src/global/own_inet_addr.c 2002-10-25 01:19:19.000000000 +0200 +++ postfix-2.0.16/src/global/own_inet_addr.c 2005-01-07 18:25:30.198331312 +0100 @@ -50,6 +50,10 @@ #include #include #include +#ifdef INET6 +#include +#include +#endif #ifdef STRCASECMP_IN_STRINGS_H #include @@ -113,10 +117,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); /* @@ -133,15 +138,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); @@ -151,6 +180,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; @@ -161,8 +226,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 */ @@ -213,6 +278,45 @@ /* proxy_inet_addr - is this my proxy internet address */ +#ifdef INET6 +int proxy_inet_addr(struct sockaddr * addr) +{ + int i; + char *p, *q; + int l; + struct sockaddr *sa; + + if (*var_proxy_interfaces == 0) + return (0); + + if (proxy_list.used == 0) + proxy_inet_addr_init(&proxy_list); + + for (i = 0; i < proxy_list.used; i++) { + sa = (struct sockaddr *)&proxy_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 proxy_inet_addr(struct in_addr * addr) { int i; @@ -228,6 +332,7 @@ return (1); return (0); } +#endif /* proxy_inet_addr_list - return list of addresses */ diff -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/global/own_inet_addr.h postfix-2.0.16/src/global/own_inet_addr.h --- postfix-2.0.16.orig/src/global/own_inet_addr.h 2002-10-25 01:07:05.000000000 +0200 +++ postfix-2.0.16/src/global/own_inet_addr.h 2005-01-07 18:25:30.199331160 +0100 @@ -15,14 +15,25 @@ * 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); +#ifdef INET6 +extern int proxy_inet_addr(struct sockaddr *); +#else extern int proxy_inet_addr(struct in_addr *); +#endif extern struct INET_ADDR_LIST *proxy_inet_addr_list(void); /* LICENSE diff -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/global/peer_name.c postfix-2.0.16/src/global/peer_name.c --- postfix-2.0.16.orig/src/global/peer_name.c 2001-01-28 16:23:02.000000000 +0100 +++ postfix-2.0.16/src/global/peer_name.c 2005-01-07 18:25:30.199331160 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/global/peer_name.h postfix-2.0.16/src/global/peer_name.h --- postfix-2.0.16.orig/src/global/peer_name.h 1998-12-11 19:55:32.000000000 +0100 +++ postfix-2.0.16/src/global/peer_name.h 2005-01-07 18:25:30.199331160 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/global/resolve_local.c postfix-2.0.16/src/global/resolve_local.c --- postfix-2.0.16.orig/src/global/resolve_local.c 2002-10-25 01:21:20.000000000 +0200 +++ postfix-2.0.16/src/global/resolve_local.c 2005-01-07 18:25:30.199331160 +0100 @@ -43,6 +43,7 @@ #include #include #include +#include #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff @@ -80,7 +81,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); } @@ -118,9 +124,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) || proxy_inet_addr(&ipaddr))) RETURN(1); +#endif } /* diff -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/global/wildcard_inet_addr.c postfix-2.0.16/src/global/wildcard_inet_addr.c --- postfix-2.0.16.orig/src/global/wildcard_inet_addr.c 1970-01-01 01:00:00.000000000 +0100 +++ postfix-2.0.16/src/global/wildcard_inet_addr.c 2005-01-07 18:25:30.200331008 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/global/wildcard_inet_addr.h postfix-2.0.16/src/global/wildcard_inet_addr.h --- postfix-2.0.16.orig/src/global/wildcard_inet_addr.h 1970-01-01 01:00:00.000000000 +0100 +++ postfix-2.0.16/src/global/wildcard_inet_addr.h 2005-01-07 18:25:30.200331008 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/master/master_ent.c postfix-2.0.16/src/master/master_ent.c --- postfix-2.0.16.orig/src/master/master_ent.c 2003-06-18 21:19:46.000000000 +0200 +++ postfix-2.0.16/src/master/master_ent.c 2005-01-07 18:35:28.571364784 +0100 @@ -92,6 +92,7 @@ #include #include #include +#include /* Local stuff. */ @@ -307,8 +308,13 @@ inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv)); serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; } else if (strcasecmp(saved_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 */ inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv)); diff -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/master/master_listen.c postfix-2.0.16/src/master/master_listen.c --- postfix-2.0.16.orig/src/master/master_listen.c 2001-05-01 00:47:57.000000000 +0200 +++ postfix-2.0.16/src/master/master_listen.c 2005-01-07 18:25:30.201330856 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/smtp/Makefile.in postfix-2.0.16/src/smtp/Makefile.in --- postfix-2.0.16.orig/src/smtp/Makefile.in 2005-01-07 18:22:25.253447208 +0100 +++ postfix-2.0.16/src/smtp/Makefile.in 2005-01-07 18:25:30.201330856 +0100 @@ -144,6 +144,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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/smtp/smtp_addr.c postfix-2.0.16/src/smtp/smtp_addr.c --- postfix-2.0.16.orig/src/smtp/smtp_addr.c 2002-10-25 01:03:11.000000000 +0200 +++ postfix-2.0.16/src/smtp/smtp_addr.c 2005-01-07 18:25:30.201330856 +0100 @@ -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 + } } /* @@ -273,12 +400,36 @@ */ self = proxy_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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/smtp/smtp_connect.c postfix-2.0.16/src/smtp/smtp_connect.c --- postfix-2.0.16.orig/src/smtp/smtp_connect.c 2005-01-07 18:22:25.254447056 +0100 +++ postfix-2.0.16/src/smtp/smtp_connect.c 2005-01-07 18:25:30.202330704 +0100 @@ -81,6 +81,7 @@ /* System library. */ #include +#include #include #include #include @@ -110,6 +111,7 @@ #include #include #include +#include #include #include #include @@ -135,19 +137,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); @@ -156,17 +184,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", @@ -175,6 +225,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 } /* @@ -182,8 +251,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) @@ -191,30 +269,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 = sane_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); @@ -224,8 +357,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); @@ -237,7 +370,7 @@ stream = vstream_fdopen(sock, O_RDWR); if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) { vstring_sprintf(why, "connect to %s[%s]: server dropped connection without sending the initial greeting", - addr->name, inet_ntoa(sin.sin_addr)); + addr->name, hbuf); smtp_errno = SMTP_RETRY; vstream_fclose(stream); return (0); @@ -249,7 +382,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); @@ -260,12 +393,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 */ diff -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/smtp/smtp_unalias.c postfix-2.0.16/src/smtp/smtp_unalias.c --- postfix-2.0.16.orig/src/smtp/smtp_unalias.c 2000-09-28 19:06:09.000000000 +0200 +++ postfix-2.0.16/src/smtp/smtp_unalias.c 2005-01-07 18:25:30.202330704 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/smtpd/smtpd_check.c postfix-2.0.16/src/smtpd/smtpd_check.c --- postfix-2.0.16.orig/src/smtpd/smtpd_check.c 2005-01-07 18:22:25.302439760 +0100 +++ postfix-2.0.16/src/smtpd/smtpd_check.c 2005-01-07 18:25:30.218328272 +0100 @@ -1393,6 +1393,49 @@ static int has_my_addr(SMTPD_STATE *state, const char *host, const char *reply_name, const char *reply_class) { +#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; @@ -1431,6 +1474,7 @@ msg_info("%s: host %s: no match", myname, host); return (NOPE); +#endif } /* i_am_mx - is this machine listed as MX relay */ @@ -2015,11 +2059,28 @@ #define CHK_ADDR_RETURN(x,y) { *found = y; return(x); } addr = STR(vstring_strcpy(error_text, address)); - +#ifdef INET6 + if (strncmp(addr, "::ffff:", 7) == 0 && msg_verbose) + msg_info("%s: %s v6 addr in v4 compat-mode, " + "converted to v4 for map checking compatibility (%s)", \ + myname, addr, addr+7); +#endif + if ((dict = dict_handle(table)) == 0) msg_panic("%s: dictionary not found: %s", myname, table); do { if (flags == 0 || (flags & dict->flags) != 0) { +#ifdef INET6 + if (strncmp(addr, "::ffff:", 7) == 0) { + /* try if ::ffff: formati is present in map, if not, try + traditional IPv4 format striping :ffff: part */ + if ((value = dict_get(dict, addr)) != 0 || \ + (value = dict_get(dict, addr+7)) != 0) + CHK_ADDR_RETURN(check_table_result(state, table, value, address, + reply_name, reply_class, + def_acl), FOUND); + } else +#endif if ((value = dict_get(dict, addr)) != 0) CHK_ADDR_RETURN(check_table_result(state, table, value, address, reply_name, reply_class, @@ -2579,16 +2640,32 @@ VSTRING *query; int i; SMTPD_RBL_STATE *rbl; +#ifdef INET6 + struct in_addr a; +#else + struct in6_addr a; +#endif if (msg_verbose) msg_info("%s: %s %s", myname, reply_class, addr); - /* - * IPv4 only for now - */ -#ifdef INET6 +#ifndef INET6 + /* IPv4 only for now */ if (inet_pton(AF_INET, 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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/smtpd/smtpd_peer.c postfix-2.0.16/src/smtpd/smtpd_peer.c --- postfix-2.0.16.orig/src/smtpd/smtpd_peer.c 2002-08-22 19:50:51.000000000 +0200 +++ postfix-2.0.16/src/smtpd/smtpd_peer.c 2005-01-07 18:25:30.205330248 +0100 @@ -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,21 +106,28 @@ 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); /* * Avoid suprious complaints from Purify on Solaris. */ - memset((char *) &sin, 0, len); + memset((char *) sa, 0, len); /* * 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; } @@ -132,23 +143,56 @@ /* * 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_hostaddr(hp->h_name, DONT_GRIPE)) { +#endif + } else if (valid_hostaddr(hbuf, DONT_GRIPE)) { msg_warn("numeric result %s in address->name lookup for %s", - hp->h_name, state->addr); + hbuf, state->addr); state->name = mystrdup("unknown"); state->peer_code = 5; - } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) { + } 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; /* @@ -160,16 +204,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", @@ -177,12 +236,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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/smtpstone/smtp-sink.c postfix-2.0.16/src/smtpstone/smtp-sink.c --- postfix-2.0.16.orig/src/smtpstone/smtp-sink.c 2003-09-13 02:46:56.000000000 +0200 +++ postfix-2.0.16/src/smtpstone/smtp-sink.c 2005-01-07 18:25:30.205330248 +0100 @@ -607,7 +607,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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/Makefile.in postfix-2.0.16/src/util/Makefile.in --- postfix-2.0.16.orig/src/util/Makefile.in 2005-01-07 18:22:25.293441128 +0100 +++ postfix-2.0.16/src/util/Makefile.in 2005-01-07 18:25:30.209329640 +0100 @@ -8,7 +8,7 @@ dict_tcp.c dict_unix.c dir_forest.c doze.c duplex_pipe.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 hex_quote.c htable.c inet_addr_host.c \ + get_hostname.c get_port.c hex_quote.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 intv.c line_wrap.c lowercase.c \ lstat_as.c mac_expand.c mac_parse.c make_dirs.c match_list.c \ @@ -37,7 +37,7 @@ dict_tcp.o dict_unix.o dir_forest.o doze.o duplex_pipe.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 hex_quote.o htable.o inet_addr_host.o \ + get_hostname.o get_port.o hex_quote.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 intv.o line_wrap.o lowercase.o \ lstat_as.o mac_expand.o mac_parse.o make_dirs.o match_list.o \ @@ -62,7 +62,7 @@ dict_ht.h dict_ldap.h dict_mysql.h dict_ni.h dict_nis.h \ dict_nisplus.h dict_pcre.h dict_pgsql.h dict_regexp.h dict_static.h dict_tcp.h \ dict_unix.h dir_forest.h events.h exec_command.h find_inet.h \ - fsspace.h fullname.h get_domainname.h get_hostname.h hex_quote.h \ + fsspace.h fullname.h get_domainname.h get_hostname.h get_port.h hex_quote.h \ htable.h inet_addr_host.h inet_addr_list.h inet_addr_local.h \ inet_util.h intv.h iostuff.h line_wrap.h listen.h lstat_as.h \ mac_expand.h mac_parse.h make_dirs.h match_list.h match_ops.h \ @@ -785,6 +785,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 @@ -911,6 +912,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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/get_port.c postfix-2.0.16/src/util/get_port.c --- postfix-2.0.16.orig/src/util/get_port.c 1970-01-01 01:00:00.000000000 +0100 +++ postfix-2.0.16/src/util/get_port.c 2005-01-07 18:25:30.206330096 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/get_port.h postfix-2.0.16/src/util/get_port.h --- postfix-2.0.16.orig/src/util/get_port.h 1970-01-01 01:00:00.000000000 +0100 +++ postfix-2.0.16/src/util/get_port.h 2005-01-07 18:25:30.206330096 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/inet_addr_host.c postfix-2.0.16/src/util/inet_addr_host.c --- postfix-2.0.16.orig/src/util/inet_addr_host.c 1998-12-11 19:55:35.000000000 +0100 +++ postfix-2.0.16/src/util/inet_addr_host.c 2005-01-07 18:28:55.469125408 +0100 @@ -38,7 +38,11 @@ #include #include #include +#include #include +#include +#include +#include #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff @@ -48,15 +52,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 +101,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 +117,8 @@ { INET_ADDR_LIST addr_list; int i; + struct sockaddr *sa; + char hbuf[NI_MAXHOST]; msg_vstream_init(argv[0], VSTREAM_ERR); @@ -89,8 +130,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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/inet_addr_list.c postfix-2.0.16/src/util/inet_addr_list.c --- postfix-2.0.16.orig/src/util/inet_addr_list.c 2001-07-31 20:13:41.000000000 +0200 +++ postfix-2.0.16/src/util/inet_addr_list.c 2005-01-07 18:25:30.207329944 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/inet_addr_list.h postfix-2.0.16/src/util/inet_addr_list.h --- postfix-2.0.16.orig/src/util/inet_addr_list.h 2001-07-31 19:56:47.000000000 +0200 +++ postfix-2.0.16/src/util/inet_addr_list.h 2005-01-07 18:25:30.207329944 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/inet_addr_local.c postfix-2.0.16/src/util/inet_addr_local.c --- postfix-2.0.16.orig/src/util/inet_addr_local.c 2001-02-25 19:20:19.000000000 +0100 +++ postfix-2.0.16/src/util/inet_addr_local.c 2005-01-07 18:25:30.207329944 +0100 @@ -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) || (ifa->ifa_netmask == 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 +219,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 +239,70 @@ } } } +#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); + if (mask_list) { +#error "mask_list for IPv6 without libinet6 not done yet (error to avoid open-relay)" + /* TODO: how to get netmask here? */ + } + } + } +#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); + if (mask_list) { +#error "mask_list for IPv6 without libinet6 not done yet (error to avoid open-relay)" + /* TODO: calculate netmask basing on plen */ + } + } + freeaddrinfo(res0); + } + } + } +#endif /* linux */ +#endif return (addr_list->used - initial_count); +#endif } #ifdef TEST @@ -158,6 +315,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 +331,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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/inet_connect.c postfix-2.0.16/src/util/inet_connect.c --- postfix-2.0.16.orig/src/util/inet_connect.c 2003-09-13 03:04:12.000000000 +0200 +++ postfix-2.0.16/src/util/inet_connect.c 2005-01-07 18:25:30.208329792 +0100 @@ -55,6 +55,9 @@ #include #include #include +#ifdef INET6 +#include +#endif /* Utility library. */ @@ -74,7 +77,12 @@ char *buf; char *host; char *port; +#ifdef INET6 + struct addrinfo hints, *res, *res0; + int error; +#else struct sockaddr_in sin; +#endif int sock; /* @@ -82,14 +90,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. */ @@ -122,4 +174,5 @@ } return (sock); } +#endif } diff -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/inet_listen.c postfix-2.0.16/src/util/inet_listen.c --- postfix-2.0.16.orig/src/util/inet_listen.c 2003-09-13 01:50:50.000000000 +0200 +++ postfix-2.0.16/src/util/inet_listen.c 2005-01-07 18:25:30.208329792 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/listen.h postfix-2.0.16/src/util/listen.h --- postfix-2.0.16.orig/src/util/listen.h 1999-03-22 02:57:11.000000000 +0100 +++ postfix-2.0.16/src/util/listen.h 2005-01-07 18:25:30.208329792 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/match_list.c postfix-2.0.16/src/util/match_list.c --- postfix-2.0.16.orig/src/util/match_list.c 2001-11-20 21:07:15.000000000 +0100 +++ postfix-2.0.16/src/util/match_list.c 2005-01-07 18:25:30.209329640 +0100 @@ -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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/match_ops.c postfix-2.0.16/src/util/match_ops.c --- postfix-2.0.16.orig/src/util/match_ops.c 2003-04-14 16:44:19.000000000 +0200 +++ postfix-2.0.16/src/util/match_ops.c 2005-01-07 18:25:30.210329488 +0100 @@ -81,6 +81,308 @@ #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 +479,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,28 +501,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; struct in_addr net_addr; +#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) @@ -230,6 +560,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); } @@ -238,6 +574,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) @@ -252,5 +602,6 @@ pattern, inet_ntoa(net_addr), mask_shift); } } +#endif return (0); } diff -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/sys_defs.h postfix-2.0.16/src/util/sys_defs.h --- postfix-2.0.16.orig/src/util/sys_defs.h 2005-01-07 18:22:25.289441736 +0100 +++ postfix-2.0.16/src/util/sys_defs.h 2005-01-07 18:25:30.211329336 +0100 @@ -73,6 +73,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 -durN -x '*~' -x '*.orig' postfix-2.0.16.orig/src/util/valid_hostname.c postfix-2.0.16/src/util/valid_hostname.c --- postfix-2.0.16.orig/src/util/valid_hostname.c 2002-12-20 02:33:41.000000000 +0100 +++ postfix-2.0.16/src/util/valid_hostname.c 2005-01-07 18:25:30.211329336 +0100 @@ -53,6 +53,13 @@ #include #include +#ifdef INET6 +#include +#include +#include +#include +#endif + /* Utility library. */ #include "msg.h" @@ -109,7 +116,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); @@ -141,6 +164,9 @@ int byte_count = 0; int byte_val = 0; int ch; +#ifdef INET6 + struct addrinfo hints, *res; +#endif #define BYTES_NEEDED 4 @@ -166,6 +192,17 @@ return (1); } +#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. */