This patch is intended to be applied on top of John Simpson's combined patch, see: http://qmail.jms1.net/patches/combined.shtml This patch modifies fujiwara's original IPv6 patch to add IPv6 support to Qmail patched with John Simpson's combined patch. fujiwara's original patch can be found here: http://member.wide.ad.jp/~fujiwara/qmail-1.03-v6-20021006.diff To enable IPv6, in addition to applying this patch, you must add -DINET6 to the first line of the conf-cc file. This patch does not make this change for you as it makes it much harder to combine patches. Installation instructions: % wget http://cr.yp.to/software/qmail-1.03.tar.gz % wget http://qmail.jms1.net/patches/qmail-1.03-jms1.7.08.patch % wget http://www.bltweb.net/qmail/qmail-1.03-jms1.7.08-ipv6.patch % tar xvzf qmail-1.03.tar.gz % mv qmail-1.03 qmail-1.03-jms1.7.08 % cd qmail-1.03-jms1.7.08 % patch < ../qmail-1.03-jms1.7.08.patch % patch -p1 < ../qmail-1.03-jms1.7.08-ipv6.patch % sed -ie '1s/$/ -DINET6/' conf-cc diff -Naur qmail-1.03.orig/Makefile qmail-1.03/Makefile --- qmail-1.03.orig/Makefile 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/Makefile 2009-03-16 16:46:54.000000000 -0500 @@ -603,6 +603,10 @@ compile fmt_ulong.c fmt.h ./compile fmt_ulong.c +fmt_xlong.o: \ +compile fmt_xlong.c fmt.h + ./compile fmt_xlong.c + fmtqfn.o: \ compile fmtqfn.c fmtqfn.h fmt.h auto_split.h ./compile fmtqfn.c @@ -634,10 +638,10 @@ ./compile forward.c fs.a: \ -makelib fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o fmt_ulong.o \ -scan_ulong.o scan_8long.o +makelib fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o fmt_ulong.o fmt_xlong.o \ +scan_ulong.o scan_8long.o scan_0x.o ./makelib fs.a fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o \ - fmt_ulong.o scan_ulong.o scan_8long.o + fmt_ulong.o fmt_xlong.o scan_ulong.o scan_8long.o scan_0x.o getln.a: \ makelib getln.o getln2.o @@ -1754,6 +1758,10 @@ compile scan_ulong.c scan.h ./compile scan_ulong.c +scan_0x.o: \ +compile scan_0x.c scan.h + ./compile scan_0x.c + seek.a: \ makelib seek_cur.o seek_end.o seek_set.o seek_trunc.o ./makelib seek.a seek_cur.o seek_end.o seek_set.o \ @@ -1870,7 +1878,7 @@ getln.h getln.c getln2.3 getln2.c sgetopt.3 sgetopt.h sgetopt.c \ subgetopt.3 subgetopt.h subgetopt.c error.3 error_str.3 error_temp.3 \ error.h error.c error_str.c error_temp.c fmt.h fmt_str.c fmt_strn.c \ -fmt_uint.c fmt_uint0.c fmt_ulong.c scan.h scan_ulong.c scan_8long.c \ +fmt_uint.c fmt_uint0.c fmt_ulong.c fmt_xlong.c scan.h scan_ulong.c scan_8long.c scan_0x.c \ slurpclose.h slurpclose.c quote.h quote.c hfield.h hfield.c \ headerbody.h headerbody.c token822.h token822.c control.h control.c \ datetime.3 datetime.h datetime.c datetime_un.c prioq.h prioq.c \ diff -Naur qmail-1.03.orig/TARGETS qmail-1.03/TARGETS --- qmail-1.03.orig/TARGETS 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/TARGETS 2009-03-16 16:36:14.000000000 -0500 @@ -118,8 +118,10 @@ fmt_uint.o fmt_uint0.o fmt_ulong.o +fmt_xlong.o scan_ulong.o scan_8long.o +scan_0x.o fs.a datetime.o datetime_un.o diff -Naur qmail-1.03.orig/dns.c qmail-1.03/dns.c --- qmail-1.03.orig/dns.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/dns.c 2009-03-16 16:36:14.000000000 -0500 @@ -3,6 +3,7 @@ #include #include #include +#include #include #include extern int res_query(); @@ -32,6 +33,9 @@ static int numanswers; static char name[MAXDNAME]; static struct ip_address ip; +#ifdef INET6 +static struct ip6_address ip6; +#endif static stralloc txt = {0}; unsigned short pref; @@ -161,6 +165,43 @@ return 0; } +#ifdef INET6 +static int findip6(wanttype) +int wanttype; +{ + unsigned short rrtype; + unsigned short rrdlen; + int i; + + if (numanswers <= 0) return 2; + --numanswers; + if (responsepos == responseend) return DNS_SOFT; + + i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); + if (i < 0) return DNS_SOFT; + responsepos += i; + + i = responseend - responsepos; + if (i < 4 + 3 * 2) return DNS_SOFT; + + rrtype = getshort(responsepos); + rrdlen = getshort(responsepos + 8); + responsepos += 10; + + if (rrtype == wanttype) + { + if (rrdlen < 16) + return DNS_SOFT; + byte_copy(&ip6.d, 16, &responsepos[0]); + responsepos += rrdlen; + return 1; + } + + responsepos += rrdlen; + return 0; +} +#endif + static int findmx(wanttype) int wanttype; { @@ -350,6 +391,57 @@ } +#ifdef INET6 +static int iaafmt6(s,ip) +char *s; +struct ip6_address *ip; +{ + unsigned int i; + int j; + unsigned int len; + static char data[] = "0123456789abcdef"; + len = 0; + + if (s) { + for (j = 15; j >= 0; j--) { + *s++ = data[ip->d[j] & 0x0f]; + *s++ = '.'; + *s++ = data[(ip->d[j] >> 4) & 0x0f]; + *s++ = '.'; + } + str_copy(s, "ip6.int"); + } + return 71; + /* 1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.int */ +} + +int dns_ptr6(sa,ip) +stralloc *sa; +struct ip6_address *ip; +{ + int r; + + if (!stralloc_ready(sa,iaafmt6((char *) 0,ip))) return DNS_MEM; + sa->len = iaafmt6(sa->s,ip); + switch(resolve(sa,T_PTR)) + { + case DNS_MEM: return DNS_MEM; + case DNS_SOFT: return DNS_SOFT; + case DNS_HARD: return DNS_HARD; + } + while ((r = findname(T_PTR)) != 2) + { + if (r == DNS_SOFT) return DNS_SOFT; + if (r == 1) + { + if (!stralloc_copys(sa,name)) return DNS_MEM; + return 0; + } + } + return DNS_HARD; +} +#endif + static int dns_ipplus(ia,sa,pref) ipalloc *ia; stralloc *sa; @@ -357,6 +449,7 @@ { int r; struct ip_mx ix; + int err4 = 0, err6 = 0; #ifdef TLS stralloc fqdn = {0}; @@ -370,28 +463,61 @@ if (!stralloc_0(&glue)) return DNS_MEM; if (glue.s[0]) { ix.pref = 0; - if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) + ix.af = AF_INET; + if (!glue.s[ip_scan(glue.s,&ix.addr.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.addr.ip)]) { + ix.af = AF_INET; if (!ipalloc_append(ia,&ix)) return DNS_MEM; return 0; } } +#ifdef INET6 + switch(resolve(sa,T_AAAA)) + { + case DNS_MEM: err6 = DNS_MEM; break; + case DNS_SOFT: err6 = DNS_SOFT; break; + case DNS_HARD: err6 = DNS_HARD; break; + default: + while ((r = findip6(T_AAAA)) != 2) + { + ix.af = AF_INET6; + ix.addr.ip6 = ip6; + ix.pref = pref; + if (r == DNS_SOFT) { err6 = DNS_SOFT; break; } + if (r == 1) + if (!ipalloc_append(ia,&ix)) { err6 = DNS_MEM; break; } + } + break; + } +#endif + switch(resolve(sa,T_A)) { - case DNS_MEM: return DNS_MEM; - case DNS_SOFT: return DNS_SOFT; - case DNS_HARD: return DNS_HARD; - } - while ((r = findip(T_A)) != 2) + case DNS_MEM: err4 = DNS_MEM; break; + case DNS_SOFT: err4 = DNS_SOFT; break; + case DNS_HARD: err4 = DNS_HARD; break; + default: +while ((r = findip(T_A)) != 2) { - ix.ip = ip; + ix.af = AF_INET; + ix.addr.ip = ip; ix.pref = pref; - if (r == DNS_SOFT) return DNS_SOFT; + if (r == DNS_SOFT) { err4 = DNS_SOFT; break; } if (r == 1) - if (!ipalloc_append(ia,&ix)) return DNS_MEM; + if (!ipalloc_append(ia,&ix)) { err4 = DNS_MEM; break; } + } + break; } + +#ifdef INET6 + if (err4 != 0 && err6 != 0) { + return err4; + } return 0; +#else + return err4; +#endif } int dns_ip(ia,sa) @@ -423,11 +549,12 @@ if (!stralloc_0(&glue)) return DNS_MEM; if (glue.s[0]) { ix.pref = 0; - if (!glue.s[ip_scan(glue.s,&ix.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.ip)]) + if (!glue.s[ip_scan(glue.s,&ix.addr.ip)] || !glue.s[ip_scanbracket(glue.s,&ix.addr.ip)]) { #ifdef TLS ix.fqdn = NULL; #endif + ix.af = AF_INET; if (!ipalloc_append(ia,&ix)) return DNS_MEM; return 0; } diff -Naur qmail-1.03.orig/dnsfq.c qmail-1.03/dnsfq.c --- qmail-1.03.orig/dnsfq.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/dnsfq.c 2009-03-16 16:36:14.000000000 -0500 @@ -1,3 +1,5 @@ +#include +#include #include "substdio.h" #include "subfd.h" #include "stralloc.h" @@ -29,7 +31,12 @@ { substdio_putsflush(subfderr,"no IP addresses\n"); _exit(100); } - dnsdoe(dns_ptr(&ssa,&ia.ix[0].ip)); + if (ia.ix[0].af == AF_INET) + dnsdoe(dns_ptr(&ssa,&ia.ix[0].addr.ip)); +#ifdef INET6 + else + dnsdoe(dns_ptr6(&ssa,&ia.ix[0].addr.ip6)); +#endif for(j = 0;j < ssa.len;++j) { substdio_putflush(subfdout,ssa.sa[j].s,ssa.sa[j].len); diff -Naur qmail-1.03.orig/dnsip.c qmail-1.03/dnsip.c --- qmail-1.03.orig/dnsip.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/dnsip.c 2009-03-16 16:36:14.000000000 -0500 @@ -1,3 +1,5 @@ +#include +#include #include "substdio.h" #include "subfd.h" #include "stralloc.h" @@ -27,7 +29,19 @@ dnsdoe(dns_ip(&ia,&sa)); for (j = 0;j < ia.len;++j) { - substdio_put(subfdout,temp,ip_fmt(temp,&ia.ix[j].ip)); + switch(ia.ix[j].af) { + case AF_INET: + substdio_put(subfdout,temp,ip_fmt(temp,&ia.ix[j].addr.ip)); + break; +#ifdef INET6 + case AF_INET6: + substdio_put(subfdout,temp,ip6_fmt(temp,&ia.ix[j].addr.ip6)); + break; +#endif + default: + substdio_puts(subfdout,"Unknown address family = "); + substdio_put(subfdout,temp,fmt_ulong(temp,ia.ix[j].af)); + } substdio_putsflush(subfdout,"\n"); } _exit(0); diff -Naur qmail-1.03.orig/dnsmxip.c qmail-1.03/dnsmxip.c --- qmail-1.03.orig/dnsmxip.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/dnsmxip.c 2009-03-16 16:36:14.000000000 -0500 @@ -1,3 +1,5 @@ +#include +#include #include "substdio.h" #include "subfd.h" #include "stralloc.h" @@ -31,7 +33,19 @@ dnsdoe(dns_mxip(&ia,&sa,r)); for (j = 0;j < ia.len;++j) { - substdio_put(subfdout,temp,ip_fmt(temp,&ia.ix[j].ip)); + switch(ia.ix[j].af) { + case AF_INET: + substdio_put(subfdout,temp,ip_fmt(temp,&ia.ix[j].addr.ip)); + break; +#ifdef INET6 + case AF_INET6: + substdio_put(subfdout,temp,ip6_fmt(temp,&ia.ix[j].addr.ip6)); + break; +#endif + default: + substdio_puts(subfdout,"Unknown address family = "); + substdio_put(subfdout,temp,fmt_ulong(temp,ia.ix[j].af)); + } substdio_puts(subfdout," "); substdio_put(subfdout,temp,fmt_ulong(temp,(unsigned long) ia.ix[j].pref)); substdio_putsflush(subfdout,"\n"); diff -Naur qmail-1.03.orig/error.c qmail-1.03/error.c --- qmail-1.03.orig/error.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/error.c 2009-03-16 16:36:14.000000000 -0500 @@ -100,3 +100,10 @@ #else -14; #endif + +int error_refused = +#ifdef ECONNREFUSED +ECONNREFUSED; +#else +-15; +#endif diff -Naur qmail-1.03.orig/error.h qmail-1.03/error.h --- qmail-1.03.orig/error.h 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/error.h 2009-03-16 16:36:14.000000000 -0500 @@ -18,6 +18,7 @@ extern int error_perm; extern int error_acces; extern int error_dquot; +extern int error_refused; extern char *error_str(); extern int error_temp(); diff -Naur qmail-1.03.orig/fmt_xlong.c qmail-1.03/fmt_xlong.c --- qmail-1.03.orig/fmt_xlong.c 1969-12-31 18:00:00.000000000 -0600 +++ qmail-1.03/fmt_xlong.c 2009-03-16 16:36:14.000000000 -0500 @@ -0,0 +1,23 @@ +#include "fmt.h" + +char tohex(char num) { + if (num<10) + return num+'0'; + else if (num<16) + return num-10+'a'; + else + return -1; +} + +unsigned int fmt_xlong(s,u) register char *s; register unsigned long u; +{ + register unsigned int len; register unsigned long q; + len = 1; q = u; + while (q > 15) { ++len; q /= 16; } + if (s) { + s += len; + do { *--s = tohex(u % 16); u /= 16; } while(u); /* handles u == 0 */ + } + return len; +} + diff -Naur qmail-1.03.orig/hier.c qmail-1.03/hier.c --- qmail-1.03.orig/hier.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/hier.c 2009-03-16 16:36:14.000000000 -0500 @@ -3,6 +3,8 @@ #include "auto_uids.h" #include "fmt.h" #include "fifo.h" +#include "ipalloc.h" +#include "tcpto.h" char buf[100 + FMT_ULONG]; @@ -60,7 +62,7 @@ dsplit("queue/remote",auto_uids,0700); d(auto_qmail,"queue/lock",auto_uidq,auto_gidq,0750); - z(auto_qmail,"queue/lock/tcpto",1024,auto_uidr,auto_gidq,0644); + z(auto_qmail,"queue/lock/tcpto",sizeof(struct tcpto_buf)*TCPTO_BUFSIZ,auto_uidr,auto_gidq,0644); z(auto_qmail,"queue/lock/sendmutex",0,auto_uids,auto_gidq,0600); p(auto_qmail,"queue/lock/trigger",auto_uids,auto_gidq,0622); diff -Naur qmail-1.03.orig/ip.c qmail-1.03/ip.c --- qmail-1.03.orig/ip.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/ip.c 2009-03-16 16:36:14.000000000 -0500 @@ -1,6 +1,9 @@ #include "fmt.h" #include "scan.h" #include "ip.h" +#include "byte.h" + +const unsigned char V4mappedprefix[12]={0,0,0,0,0,0,0,0,0,0,0xff,0xff}; unsigned int ip_fmt(s,ip) char *s; @@ -51,3 +54,137 @@ if (s[len + 1] != ']') return 0; return len + 2; } + +#ifdef INET6 +unsigned int ip6_fmt(s,ip6) +char *s; +struct ip6_address *ip6; +{ + unsigned int len; + unsigned int i; + unsigned int temp; + unsigned int compressing; + struct ip_address ip4; + int j; + + len = 0; compressing = 0; + for (j=0; j<16; j+=2) { + if (j==12 && byte_equal(ip6->d,12,V4mappedprefix)) { + byte_copy(ip4.d, 4, ip6->d+12); + temp=ip_fmt(s,ip4); + len+=temp; + s+=temp; + break; + } + temp = ((unsigned long) (unsigned char) ip6->d[j] << 8) + + (unsigned long) (unsigned char) ip6->d[j+1]; + if (temp == 0) { + if (!compressing) { + compressing=1; + if (j==0) { + *s=':'; s+=1; ++len; + } + } + } else { + if (compressing) { + compressing=0; + *s=':'; s+=1; ++len; + } + i = fmt_xlong(s,temp); len += i; if (s) s += i; + if (s && j<14) { *s++ = ':'; ++len; } + } + } + + if (s) *s=0; + return len; +} + + +/* + * IPv6 addresses are really ugly to parse. + * Syntax: (h = hex digit) + * 1. hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh + * 2. any number of 0000 may be abbreviated as "::", but only once + * 3. The last two words may be written as IPv4 address + */ +unsigned int ip6_scan(s,ip) +char *s; +struct ip6_address *ip; +{ + unsigned int i; + unsigned int len=0; + unsigned int u; + struct ip_address ip4; + + char suffix[16]; + int prefixlen=0; + int suffixlen=0; + + for (i=0; i<4; i++) ip4.d[i]=0; + for (i=0; i<16; i++) ip->d[i]=0; + + for (;;) { + if (*s == ':') { + len++; + if (s[1] == ':') { /* Found "::", skip to part 2 */ + s+=2; + len++; + break; + } + s++; + } + i = scan_0x(s,&u); + if (!i) return 0; + if (prefixlen==12 && s[i]=='.') { + /* the last 4 bytes may be written as IPv4 address */ + i=ip_scan(s,&ip4); + if(i) { + byte_copy(ip->d+12,4,ip4.d); + return i+len; + } + else + return 0; + } + ip->d[prefixlen++] = (u >> 8); + ip->d[prefixlen++] = (u & 255); + s += i; len += i; + if (prefixlen==16) + return len; + } + +/* part 2, after "::" */ + for (;;) { + if (*s == ':') { + if (suffixlen==0) + break; + s++; + len++; + } else if (suffixlen!=0) + break; + i = scan_0x(s,&u); + if (!i) { + len--; + break; + } + if (suffixlen+prefixlen<=12 && s[i]=='.') { + int j=ip_scan(s,&ip4); + if (j) { + byte_copy(suffix+suffixlen,4,ip4.d); + suffixlen+=4; + len+=j; + break; + } else + prefixlen=12-suffixlen; /* make end-of-loop test true */ + } + suffix[suffixlen++] = (u >> 8); + suffix[suffixlen++] = (u & 255); + s += i; len += i; + if (prefixlen+suffixlen==16) + break; + } + for (i=0; id[16-suffixlen+i] = suffix[i]; + return len; +} + +#endif diff -Naur qmail-1.03.orig/ip.h qmail-1.03/ip.h --- qmail-1.03.orig/ip.h 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/ip.h 2009-03-16 16:36:14.000000000 -0500 @@ -2,10 +2,23 @@ #define IP_H struct ip_address { unsigned char d[4]; } ; +#ifdef INET6 +struct ip6_address { unsigned char d[16]; } ; +#endif extern unsigned int ip_fmt(); +#ifdef INET6 +extern unsigned int ip6_fmt(); +#define IPFMT 72 +#else #define IPFMT 19 +#endif extern unsigned int ip_scan(); extern unsigned int ip_scanbracket(); +#ifdef INET6 +extern unsigned int ip6_scan(); +#endif + +#define HOSTNAMELEN 1025 #endif diff -Naur qmail-1.03.orig/ipalloc.h qmail-1.03/ipalloc.h --- qmail-1.03.orig/ipalloc.h 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/ipalloc.h 2009-03-16 16:36:14.000000000 -0500 @@ -5,9 +5,28 @@ #ifdef TLS #include "stralloc.h" -struct ip_mx { struct ip_address ip; int pref; char *fqdn; } ; +struct ip_mx { + unsigned short af; + union { + struct ip_address ip; +#ifdef INET6 + struct ip6_address ip6; +#endif + } addr; + int pref; + char *fqdn; +}; #else -struct ip_mx { struct ip_address ip; int pref; } ; +struct ip_mx { + unsigned short af; + union { + struct ip_address ip; +#ifdef INET6 + struct ip6_address ip6; +#endif + } addr; + int pref; +}; #endif #include "gen_alloc.h" diff -Naur qmail-1.03.orig/ipme.c qmail-1.03/ipme.c --- qmail-1.03.orig/ipme.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/ipme.c 2009-03-16 16:36:14.000000000 -0500 @@ -24,11 +24,24 @@ int i; if (ipme_init() != 1) return -1; for (i = 0;i < ipme.len;++i) - if (byte_equal(&ipme.ix[i].ip,4,ip)) + if (ipme.ix[i].af == AF_INET && byte_equal(&ipme.ix[i].addr.ip,4,ip)) return 1; return 0; } +#ifdef INET6 +int ipme_is6(ip) +struct ip6_address *ip; +{ + int i; + if (ipme_init() != 1) return -1; + for (i = 0;i < ipme.len;++i) + if (ipme.ix[i].af == AF_INET6 && byte_equal(&ipme.ix[i].addr.ip6,16,ip)) + return 1; + return 0; +} +#endif + static stralloc buf = {0}; int ipme_init() @@ -37,6 +50,9 @@ char *x; struct ifreq *ifr; struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif int len; int s; struct ip_mx ix; @@ -49,7 +65,7 @@ /* 0.0.0.0 is a special address which always refers to * "this host, this network", according to RFC 1122, Sec. 3.2.1.3a. */ - byte_copy(&ix.ip,4,"\0\0\0\0"); + byte_copy(&ix.addr.ip,4,"\0\0\0\0"); if (!ipalloc_append(&ipme,&ix)) { return 0; } if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) return -1; @@ -76,11 +92,22 @@ len = sizeof(*ifr); if (ifr->ifr_addr.sa_family == AF_INET) { sin = (struct sockaddr_in *) &ifr->ifr_addr; - byte_copy(&ix.ip,4,&sin->sin_addr); + byte_copy(&ix.addr.ip,4,&sin->sin_addr); + ix.af = AF_INET; + if (ioctl(s,SIOCGIFFLAGS,x) == 0) + if (ifr->ifr_flags & IFF_UP) + if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; } + } +#ifdef INET6 + else if (ifr->ifr_addr.sa_family == AF_INET6) { + sin6 = (struct sockaddr_in6 *) &ifr->ifr_addr; + byte_copy(&ix.addr.ip6,16,&sin6->sin6_addr); + ix.af = AF_INET6; if (ioctl(s,SIOCGIFFLAGS,x) == 0) if (ifr->ifr_flags & IFF_UP) if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; } } +#endif #else len = sizeof(*ifr); if (ioctl(s,SIOCGIFFLAGS,x) == 0) @@ -88,10 +115,19 @@ if (ioctl(s,SIOCGIFADDR,x) == 0) if (ifr->ifr_addr.sa_family == AF_INET) { sin = (struct sockaddr_in *) &ifr->ifr_addr; - byte_copy(&ix.ip,4,&sin->sin_addr); + ix.af = AF_INET; + byte_copy(&ix.addr.ip,4,&sin->sin_addr); + if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; } + } +#ifdef INET6 + else if (ifr->ifr_addr.sa_family == AF_INET6) { + sin6 = (struct sockaddr_in6 *) &ifr->ifr_addr; + ix.af = AF_INET6; + byte_copy(&ix.addr.ip6,16,&sin6->sin6_addr); if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; } } #endif +#endif x += len; } close(s); diff -Naur qmail-1.03.orig/ipmeprint.c qmail-1.03/ipmeprint.c --- qmail-1.03.orig/ipmeprint.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/ipmeprint.c 2009-03-16 16:36:14.000000000 -0500 @@ -1,3 +1,5 @@ +#include +#include #include "subfd.h" #include "substdio.h" #include "ip.h" @@ -16,7 +18,19 @@ } for (j = 0;j < ipme.len;++j) { - substdio_put(subfdout,temp,ip_fmt(temp,&ipme.ix[j].ip)); + switch(ipme.ix[j].af) { + case AF_INET: + substdio_put(subfdout,temp,ip_fmt(temp,&ipme.ix[j].addr.ip)); + break; +#ifdef INET6 + case AF_INET6: + substdio_put(subfdout,temp,ip6_fmt(temp,&ipme.ix[j].addr.ip6)); + break; +#endif + default: + substdio_puts(subfdout,"Unknown address family = "); + substdio_put(subfdout,temp,fmt_ulong(temp,ipme.ix[j].af)); + } substdio_puts(subfdout,"\n"); } substdio_flush(subfdout); diff -Naur qmail-1.03.orig/qmail-remote.c qmail-1.03/qmail-remote.c --- qmail-1.03.orig/qmail-remote.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/qmail-remote.c 2009-03-16 16:36:14.000000000 -0500 @@ -64,7 +64,7 @@ saa reciplist = {0}; -struct ip_address partner; +struct ip_mx partner; void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); } void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); } @@ -107,7 +107,15 @@ void outhost() { char x[IPFMT]; - if (substdio_put(subfdoutsmall,x,ip_fmt(x,&partner)) == -1) _exit(0); +#ifdef INET6 + if (partner.af == AF_INET) { +#endif + if (substdio_put(subfdoutsmall,x,ip_fmt(x,&partner.addr.ip)) == -1) _exit(0); +#ifdef INET6 + } else { + if (substdio_put(subfdoutsmall,x,ip6_fmt(x,&partner.addr.ip6)) == -1) _exit(0); + } +#endif } int flagcritical = 0; @@ -638,6 +646,33 @@ #endif } +#ifdef INET6 +int ipme_is46(mxip) +struct ip_mx *mxip; +{ + switch(mxip->af) { + case AF_INET: + return ipme_is(&mxip->addr.ip); + case AF_INET6: + return ipme_is6(&mxip->addr.ip6); + } + return 0; +} +#endif + +int timeoutconn46(fd, ix, port, timeout) +int fd; +struct ip_mx *ix; +int port; +int timeout; +{ +#ifdef INET6 + if (ix->af == AF_INET6) + return timeoutconn6(fd, &ix->addr.ip6, port, timeout); +#endif + return timeoutconn(fd, &ix->addr.ip, port, timeout); +} + void main(argc,argv) int argc; char **argv; @@ -735,7 +770,11 @@ prefme = 100000; for (i = 0;i < ip.len;++i) - if (ipme_is(&ip.ix[i].ip)) +#ifdef INET6 + if (ipme_is46(&ip.ix[i])) +#else + if (ipme_is(&ip.ix[i].addr.ip)) +#endif if (ip.ix[i].pref < prefme) prefme = ip.ix[i].pref; @@ -750,24 +789,28 @@ perm_ambigmx(); for (i = 0;i < ip.len;++i) if (ip.ix[i].pref < prefme) { - if (tcpto(&ip.ix[i].ip)) continue; + if (tcpto(&ip.ix[i])) continue; - smtpfd = socket(AF_INET,SOCK_STREAM,0); + smtpfd = socket(ip.ix[i].af,SOCK_STREAM,0); if (smtpfd == -1) temp_oserr(); bind_by_sender ( smtpfd , sender.s , 1 ) ; - bind_by_remoteip ( smtpfd , &ip.ix[i].ip , 0 ) ; + bind_by_remoteip ( smtpfd , &ip.ix[i] , 0 ) ; - if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) { - tcpto_err(&ip.ix[i].ip,0); - partner = ip.ix[i].ip; + if (timeoutconn46(smtpfd,&ip.ix[i],(unsigned int) port,timeoutconnect) == 0) { + tcpto_err(&ip.ix[i],0); + partner = ip.ix[i]; #ifdef TLS smtp(ip.ix[i].fqdn); /* does not return */ #else smtp(); /* only returns when the next MX is to be tried */ #endif } - tcpto_err(&ip.ix[i].ip,errno == error_timeout); + tcpto_err(&ip.ix[i],errno == error_timeout +#ifdef TCPTO_REFUSED + || errno == error_refused +#endif + ); close(smtpfd); } diff -Naur qmail-1.03.orig/qmail-rspawn.c qmail-1.03/qmail-rspawn.c --- qmail-1.03.orig/qmail-rspawn.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/qmail-rspawn.c 2009-03-16 16:36:14.000000000 -0500 @@ -4,6 +4,7 @@ #include "exit.h" #include "fork.h" #include "error.h" +#include "ipalloc.h" #include "tcpto.h" void initialize(argc,argv) diff -Naur qmail-1.03.orig/qmail-tcpok.c qmail-1.03/qmail-tcpok.c --- qmail-1.03.orig/qmail-tcpok.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/qmail-tcpok.c 2009-03-16 16:36:14.000000000 -0500 @@ -5,10 +5,12 @@ #include "readwrite.h" #include "auto_qmail.h" #include "exit.h" +#include "ipalloc.h" +#include "tcpto.h" #define FATAL "qmail-tcpok: fatal: " -char buf[1024]; /* XXX: must match size in tcpto_clean.c, tcpto.c */ +struct tcpto_buf buf[TCPTO_BUFSIZ]; substdio ss; void main() diff -Naur qmail-1.03.orig/qmail-tcpto.c qmail-1.03/qmail-tcpto.c --- qmail-1.03.orig/qmail-tcpto.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/qmail-tcpto.c 2009-03-16 16:36:14.000000000 -0500 @@ -1,5 +1,7 @@ /* XXX: this program knows quite a bit about tcpto's internals */ +#include +#include #include "substdio.h" #include "subfd.h" #include "auto_qmail.h" @@ -10,6 +12,8 @@ #include "exit.h" #include "datetime.h" #include "now.h" +#include "ipalloc.h" +#include "tcpto.h" void die(n) int n; { substdio_flush(subfdout); _exit(n); } @@ -28,7 +32,7 @@ void die_lock() { warn("fatal: unable to lock tcpto"); die(111); } void die_read() { warn("fatal: unable to read tcpto"); die(111); } -char tcpto_buf[1024]; +struct tcpto_buf tcpto_buf[TCPTO_BUFSIZ]; char tmp[FMT_ULONG + IPFMT]; @@ -38,8 +42,7 @@ int fd; int r; int i; - char *record; - struct ip_address ip; + int af; datetime_sec when; datetime_sec start; @@ -56,29 +59,31 @@ close(fdlock); if (r == -1) die_read(); - r >>= 4; + r /= sizeof(tcpto_buf[0]); start = now(); - record = tcpto_buf; for (i = 0;i < r;++i) { - if (record[4] >= 1) + if (tcpto_buf[i].flag >= 1) { - byte_copy(&ip,4,record); - when = (unsigned long) (unsigned char) record[11]; - when = (when << 8) + (unsigned long) (unsigned char) record[10]; - when = (when << 8) + (unsigned long) (unsigned char) record[9]; - when = (when << 8) + (unsigned long) (unsigned char) record[8]; + af = tcpto_buf[i].af; + when = tcpto_buf[i].when; - substdio_put(subfdout,tmp,ip_fmt(tmp,&ip)); +#ifdef INET6 + if (af == AF_INET) + substdio_put(subfdout,tmp,ip_fmt(tmp,&tcpto_buf[i].addr.ip)); + else + substdio_put(subfdout,tmp,ip6_fmt(tmp,&tcpto_buf[i].addr.ip6)); +#else + substdio_put(subfdout,tmp,ip_fmt(tmp,&tcpto_buf[i].addr.ip)); +#endif substdio_puts(subfdout," timed out "); substdio_put(subfdout,tmp,fmt_ulong(tmp,(unsigned long) (start - when))); substdio_puts(subfdout," seconds ago; # recent timeouts: "); - substdio_put(subfdout,tmp,fmt_ulong(tmp,(unsigned long) (unsigned char) record[4])); + substdio_put(subfdout,tmp,fmt_ulong(tmp,tcpto_buf[i].flag)); substdio_puts(subfdout,"\n"); } - record += 16; } die(0); diff -Naur qmail-1.03.orig/remoteinfo.c qmail-1.03/remoteinfo.c --- qmail-1.03.orig/remoteinfo.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/remoteinfo.c 2009-03-16 16:36:14.000000000 -0500 @@ -23,33 +23,62 @@ return timeoutread(t,fd,buf,len); } -char *remoteinfo_get(ipr,rp,ipl,lp,timeout) -struct ip_address *ipr; -unsigned long rp; -struct ip_address *ipl; -unsigned long lp; +union sockunion { + struct sockaddr sa; + struct sockaddr_in sa4; +#ifdef INET6 + struct sockaddr_in6 sa6; +#endif +}; + +char *remoteinfo_get(saremote, salocal, timeout) +union sockunion *saremote, *salocal; int timeout; { char *x; int s; - struct sockaddr_in sin; + union sockunion sa; substdio ss; char buf[32]; - unsigned int len; + unsigned int len, rp, lp; int numcolons; char ch; t = timeout; - s = socket(AF_INET,SOCK_STREAM,0); + s = socket(saremote->sa.sa_family,SOCK_STREAM,0); + if (s == -1) return 0; + + switch(saremote->sa.sa_family) { + case AF_INET: + rp = ntohs(saremote->sa4.sin_port); + lp = ntohs(salocal->sa4.sin_port); + byte_zero(&sa,sizeof(sa)); + sa.sa4.sin_family = AF_INET; + byte_copy(&sa.sa4.sin_addr, 4, &salocal->sa4.sin_addr); + sa.sa4.sin_port = 0; + if (bind(s,(struct sockaddr *) &sa.sa,sizeof(sa.sa4)) == -1) { close(s); return 0; } + if (timeoutconn(s,&saremote->sa4.sin_addr,113,timeout) == -1) { close(s); return 0; } + break; +#ifdef INET6 + case AF_INET6: + rp = ntohs(saremote->sa6.sin6_port); + lp = ntohs(salocal->sa6.sin6_port); + s = socket(PF_INET6, SOCK_STREAM, 0); if (s == -1) return 0; + byte_zero(&sa,sizeof(sa)); + sa.sa6.sin6_family = AF_INET; + byte_copy(&sa.sa6.sin6_addr, 16, &salocal->sa6.sin6_addr); + sa.sa6.sin6_port = 0; + sa.sa6.sin6_flowinfo = 0; + if (bind(s,(struct sockaddr *) &sa.sa,sizeof(sa.sa6)) == -1) { close(s); return 0; } + if (timeoutconn6(s,&saremote->sa6.sin6_addr,113,timeout) == -1) { close(s); return 0; } + break; +#endif + default: + return 0; + } - byte_zero(&sin,sizeof(sin)); - sin.sin_family = AF_INET; - byte_copy(&sin.sin_addr,4,ipl); - sin.sin_port = 0; - if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; } - if (timeoutconn(s,ipr,113,timeout) == -1) { close(s); return 0; } fcntl(s,F_SETFL,fcntl(s,F_GETFL,0) & ~O_NDELAY); len = 0; diff -Naur qmail-1.03.orig/scan_0x.c qmail-1.03/scan_0x.c --- qmail-1.03.orig/scan_0x.c 1969-12-31 18:00:00.000000000 -0600 +++ qmail-1.03/scan_0x.c 2009-03-16 16:36:14.000000000 -0500 @@ -0,0 +1,28 @@ + +#include "scan.h" + + +static long int fromhex(unsigned char c) { + if (c>='0' && c<='9') + return c-'0'; + else if (c>='A' && c<='F') + return c-'A'+10; + else if (c>='a' && c<='f') + return c-'a'+10; + return -1; +} + + +unsigned int scan_0x(s, u) register char *s; register unsigned int *u; +{ + register unsigned int pos = 0; + register unsigned long result = 0; + register long int c; + while ((c = fromhex((unsigned char) (s[pos]))) >= 0) { + result = (result << 4) + c; + ++pos; + } + *u = result; + return pos; +} + diff -Naur qmail-1.03.orig/spf.c qmail-1.03/spf.c --- qmail-1.03.orig/spf.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/spf.c 2009-03-16 16:36:14.000000000 -0500 @@ -1,3 +1,4 @@ +#include #include "stralloc.h" #include "strsalloc.h" #include "alloc.h" @@ -73,7 +74,7 @@ static char *received; static int recursion; -static struct ip_address ip; +static struct ip_mx ipmx; static void hdr_pass() { received = "pass (%{xr}: %{xs} designates %{i} as permitted sender)"; }; static void hdr_softfail() { received = "softfail (%{xr}: transitioning %{xs} does not designate %{i} as permitted sender)"; }; @@ -104,6 +105,23 @@ return 1; } +#ifdef INET6 +static int matchip6(struct ip6_address *net, int mask, struct ip6_address *ip) +{ + int j; + int bytemask; + + for (j = 0; j < 16 && mask > 0; ++j) { + if (mask > 8) bytemask = 8; else bytemask = mask; + mask -= bytemask; + + if ((net->d[j] ^ ip->d[j]) & (0x100 - (1 << (8 - bytemask)))) + return 0; + } + return 1; +} +#endif + static int getipmask(char *mask, int ipv6) { unsigned long r; int pos; @@ -117,6 +135,21 @@ return r; } +#ifdef INET6 +static int getip6mask(char *mask, int ipv6) { + unsigned long r; + int pos; + + if (!mask) return 128; + + pos = scan_ulong(mask, &r); + if (!pos || (mask[pos] && !(mask[pos] == '/' && ipv6))) return -1; + if (r > 128) return -1; + + return r; +} +#endif + int spfget(stralloc *spf, stralloc *domain) { strsalloc ssa = {0}; @@ -220,7 +253,12 @@ break; case 'i': if (!stralloc_ready(&sa, IPFMT)) return 0; - sa.len = ip_fmt(sa.s, &ip); +#ifdef INET6 + if(ipmx.af==AF_INET6) + sa.len = ip6_fmt(sa.s, &ipmx.addr.ip6); + else +#endif + sa.len = ip_fmt(sa.s, &ipmx.addr.ip); break; case 't': if (!stralloc_ready(&sa, FMT_ULONG)) return 0; @@ -372,7 +410,11 @@ { stralloc sa = {0}; ipalloc ia = {0}; +#ifdef INET6 + int ipmask = ipmx.af==AF_INET6 ? getip6mask(mask, 1) : getipmask(mask, 1); +#else int ipmask = getipmask(mask, 1); +#endif int r; int j; @@ -388,7 +430,12 @@ default: r = SPF_NONE; for(j = 0; j < ia.len; ++j) - if (matchip(&ia.ix[j].ip, ipmask, &ip)) { + if((ipmx.af==AF_INET && matchip(&ia.ix[j].addr.ip, ipmask, &ipmx.addr.ip)) +#ifdef INET6 + || + (ipmx.af==AF_INET6 && matchip6(&ia.ix[j].addr.ip6, ipmask, &ipmx.addr.ip6)) +#endif + ) { r = SPF_OK; break; } @@ -420,7 +467,12 @@ default: r = SPF_NONE; for(j = 0; j < ia.len; ++j) - if (matchip(&ia.ix[j].ip, ipmask, &ip)) { + if((ipmx.af==AF_INET && matchip(&ia.ix[j].addr.ip, ipmask, &ipmx.addr.ip)) +#ifdef INET6 + || + (ipmx.af==AF_INET6 && matchip6(&ia.ix[j].addr.ip6, ipmask, &ipmx.addr.ip6)) +#endif + ) { r = SPF_OK; break; } @@ -459,7 +511,7 @@ if (!stralloc_readyplus(&ssa, 0)) return SPF_NOMEM; if (!stralloc_readyplus(&ia, 0)) return SPF_NOMEM; - switch(dns_ptr(&ssa, &ip)) { + switch(dns_ptr(&ssa, &ipmx.addr.ip)) { case DNS_MEM: return SPF_NOMEM; case DNS_SOFT: hdr_dns(); r = SPF_ERROR; break; case DNS_HARD: r = SPF_NONE; break; @@ -472,7 +524,12 @@ case DNS_HARD: break; default: for(k = 0; k < ia.len; ++k) - if (matchip(&ia.ix[k].ip, 32, &ip)) { + if((ipmx.af==AF_INET && matchip(&ia.ix[k].addr.ip, 32, &ipmx.addr.ip)) +#ifdef INET6 + || + (ipmx.af==AF_INET6 && matchip6(&ia.ix[k].addr.ip6, 128, &ipmx.addr.ip6)) +#endif + ) { if (!sender_fqdn.len) if (!stralloc_copy(&sender_fqdn, &ssa.sa[j])) return SPF_NOMEM; @@ -511,10 +568,25 @@ if (ipmask < 0) return SPF_SYNTAX; if (!ip_scan(spec, &net)) return SPF_SYNTAX; - if (matchip(&net, ipmask, &ip)) return SPF_OK; + if (matchip(&net, ipmask, &ipmx.addr.ip)) return SPF_OK; + + return SPF_NONE; +} + +#ifdef INET6 +static int spf_ip6(char *spec, char *mask) +{ + struct ip6_address net; + int ipmask = getip6mask(mask, 0); + + if (ipmask < 0) return SPF_SYNTAX; + if (!ip6_scan(spec, &net)) return SPF_SYNTAX; + + if (matchip6(&net, ipmask, &ipmx.addr.ip6)) return SPF_OK; return SPF_NONE; } +#endif static int spf_exists(char *spec, char *mask) { @@ -552,7 +624,11 @@ , { "mx", spf_mx, 1,1,1,1,0 } , { "ptr", spf_ptr, 1,0,1,1,0 } , { "ip4", spf_ip, 1,1,0,0,0 } +#ifdef INET6 +, { "ip6", spf_ip6, 1,1,0,0,0 } +#else , { "ip6", 0, 1,1,0,0,SPF_NONE } +#endif , { "exists", spf_exists, 1,0,1,0,0 } , { "extension",0, 1,1,0,0,SPF_EXT } , { 0, 0, 1,1,0,0,SPF_EXT } @@ -852,7 +928,18 @@ if (!stralloc_0(&explanation)) return SPF_NOMEM; recursion = 0; - if (!remoteip || !ip_scan(remoteip, &ip)) { + if (remoteip) { + if(ip_scan(remoteip, &ipmx.addr.ip)) + ipmx.af = AF_INET; +#ifdef INET6 + else if(ip6_scan(remoteip, &ipmx.addr.ip6)) + ipmx.af = AF_INET6; +#endif + else + ipmx.af = AF_UNSPEC; + } + + if(!remoteip || ipmx.af == AF_UNSPEC) { hdr_unknown_msg("No IP address in conversation"); return SPF_UNKNOWN; } @@ -864,7 +951,13 @@ sender_fqdn.len = 0; received = (char *) 0; - if ((ip.d[0] == 127 && ip.d[1] == 0 && ip.d[2] == 0 && ip.d[3] == 1) || ipme_is(&ip)) + if ( + (ipmx.af==AF_INET && ((ipmx.addr.ip.d[0] == 127 && ipmx.addr.ip.d[1] == 0 && ipmx.addr.ip.d[2] == 0 && ipmx.addr.ip.d[3] == 1) || ipme_is(&ipmx.addr.ip))) +#ifdef INET6 + || + (ipmx.af==AF_INET6 && ipme_is6(&ipmx.addr.ip6)) +#endif + ) { hdr_pass(); r = SPF_OK; } else r = spflookup(&domain); diff -Naur qmail-1.03.orig/tcp-env.c qmail-1.03/tcp-env.c --- qmail-1.03.orig/tcp-env.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/tcp-env.c 2009-03-16 16:36:14.000000000 -0500 @@ -2,6 +2,7 @@ #include #include #include +#include #include "sig.h" #include "stralloc.h" #include "str.h" @@ -16,20 +17,50 @@ #include "remoteinfo.h" #include "exit.h" #include "case.h" +#include "hassalen.h" void die() { _exit(111); } -struct sockaddr_in salocal; +union sockunion { + struct sockaddr sa; + struct sockaddr_in sa4; +#ifdef INET6 + struct sockaddr_in6 sa6; +#endif +}; + +char temp[HOSTNAMELEN]; + +union sockunion salocal; unsigned long localport; -struct ip_address iplocal; stralloc localname = {0}; -struct sockaddr_in saremote; +union sockunion saremote; unsigned long remoteport; -struct ip_address ipremote; stralloc remotename = {0}; -char temp[IPFMT + FMT_ULONG]; +#if defined(IN6_IS_ADDR_V4MAPPED) && defined(INET6) +void mappedtov4(union sockunion *sa) +{ + struct sockaddr_in sin; + struct sockaddr_in6 *sin6 = &sa->sa6; + + byte_zero(&sin, sizeof(sin)); + if (sin6->sin6_family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ) { + byte_copy(&sin.sin_addr, sizeof(sin.sin_addr), sin6->sin6_addr.s6_addr+12); + sin.sin_port = sin6->sin6_port; + sin.sin_family = AF_INET; +#ifdef HASSALEN + sin.sin_len = sizeof(sin); +#endif + byte_copy(&sa->sa4, sizeof(sin), &sin); + } + +} +#else +#define mappedtov4(A) +#endif void main(argc,argv) int argc; @@ -41,6 +72,7 @@ int opt; int flagremoteinfo; unsigned long timeout; + struct sockaddr_in *v4; sig_pipeignore(); @@ -67,17 +99,18 @@ dummy = sizeof(salocal); if (getsockname(0,(struct sockaddr *) &salocal,&dummy) == -1) die(); + mappedtov4(&salocal); - localport = ntohs(salocal.sin_port); + switch(salocal.sa.sa_family) { + case AF_INET: + localport = ntohs(salocal.sa4.sin_port); temp[fmt_ulong(temp,localport)] = 0; if (!env_put2("TCPLOCALPORT",temp)) die(); - byte_copy(&iplocal,4,&salocal.sin_addr); - temp[ip_fmt(temp,&iplocal)] = 0; + temp[ip_fmt(temp, &salocal.sa4.sin_addr)] = 0; if (!env_put2("TCPLOCALIP",temp)) die(); - switch(dns_ptr(&ssa,&iplocal)) - { + switch(dns_ptr(&localname,&salocal.sa4.sin_addr)) { case DNS_MEM: die(); case DNS_SOFT: if (!stralloc_copys(&localname,"softdnserror")) die(); @@ -90,20 +123,65 @@ default: if (!env_unset("TCPLOCALHOST")) die(); } + break; +#ifdef INET6 + case AF_INET6: + localport = ntohs(salocal.sa6.sin6_port); + temp[fmt_ulong(temp,localport)] = 0; + if (!env_put2("TCPLOCALPORT",temp)) die(); + temp[ip6_fmt(temp, &salocal.sa6.sin6_addr)] = 0; + if (!env_put2("TCPLOCALIP",temp)) die(); + switch(dns_ptr6(&localname,&salocal.sa6.sin6_addr)) { + case DNS_MEM: die(); + case DNS_SOFT: + if (!stralloc_copys(&localname,"softdnserror")) die(); + case 0: + if (!stralloc_0(&localname)) die(); + case_lowers(localname.s); + if (!env_put2("TCPLOCALHOST",localname.s)) die(); + break; + default: + if (!env_unset("TCPLOCALHOST")) die(); + } + break; +#endif + default: + die(); + } + dummy = sizeof(saremote); if (getpeername(0,(struct sockaddr *) &saremote,&dummy) == -1) die(); + mappedtov4(&saremote); - remoteport = ntohs(saremote.sin_port); + switch(saremote.sa.sa_family) { + case AF_INET: + remoteport = ntohs(saremote.sa4.sin_port); temp[fmt_ulong(temp,remoteport)] = 0; if (!env_put2("TCPREMOTEPORT",temp)) die(); - - byte_copy(&ipremote,4,&saremote.sin_addr); - temp[ip_fmt(temp,&ipremote)] = 0; + temp[ip_fmt(temp, &saremote.sa4.sin_addr)] = 0; if (!env_put2("TCPREMOTEIP",temp)) die(); - - switch(dns_ptr(&ssa,&ipremote)) - { + switch(dns_ptr(&remotename,&saremote.sa4.sin_addr)) { + case DNS_MEM: die(); + case DNS_SOFT: + if (!stralloc_copys(&remotename,"softdnserror")) die(); + case 0: + if (!stralloc_0(&remotename)) die(); + case_lowers(remotename.s); + if (!env_put2("TCPREMOTEHOST",remotename.s)) die(); + break; + default: + if (!env_unset("TCPREMOTEHOST")) die(); + } + break; + #ifdef INET6 + case AF_INET6: + remoteport = ntohs(saremote.sa6.sin6_port); + temp[fmt_ulong(temp,remoteport)] = 0; + if (!env_put2("TCPREMOTEPORT",temp)) die(); + temp[ip6_fmt(temp, &saremote.sa6.sin6_addr)] = 0; + if (!env_put2("TCPREMOTEIP",temp)) die(); + switch(dns_ptr6(&remotename,&saremote.sa6.sin6_addr)) { case DNS_MEM: die(); case DNS_SOFT: if (!stralloc_copys(&remotename,"softdnserror")) die(); @@ -116,12 +194,18 @@ default: if (!env_unset("TCPREMOTEHOST")) die(); } + break; +#endif + default: + die(); + } if (!env_unset("TCPREMOTEINFO")) die(); + if (flagremoteinfo) { char *rinfo; - rinfo = remoteinfo_get(&ipremote,remoteport,&iplocal,localport,(int) timeout); + rinfo = remoteinfo_get(&saremote, &salocal,(int) timeout); if (rinfo) if (!env_put2("TCPREMOTEINFO",rinfo)) die(); } diff -Naur qmail-1.03.orig/tcpto.c qmail-1.03/tcpto.c --- qmail-1.03.orig/tcpto.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/tcpto.c 2009-03-16 16:36:14.000000000 -0500 @@ -1,14 +1,19 @@ +#include +#include +#include +#include +#include "ipalloc.h" #include "tcpto.h" #include "open.h" #include "lock.h" #include "seek.h" #include "now.h" #include "ip.h" +#include "ipalloc.h" #include "byte.h" #include "datetime.h" -#include "readwrite.h" -char tcpto_buf[1024]; +struct tcpto_buf tcpto_buf[TCPTO_BUFSIZ]; static int flagwasthere; static int fdlock; @@ -23,19 +28,19 @@ fd = open_read("queue/lock/tcpto"); if (fd == -1) { close(fdlock); return 0; } if (lock_ex(fdlock) == -1) { close(fdlock); close(fd); return 0; } - r = read(fd,tcpto_buf,sizeof(tcpto_buf)); + r = read(fd,&tcpto_buf,sizeof(tcpto_buf)); close(fd); if (r < 0) { close(fdlock); return 0; } - r >>= 4; + r /= sizeof(tcpto_buf[0]); if (!r) close(fdlock); return r; } -int tcpto(ip) struct ip_address *ip; +int tcpto(ix) +struct ip_mx *ix; { int n; int i; - char *record; datetime_sec when; flagwasthere = 0; @@ -44,37 +49,35 @@ if (!n) return 0; close(fdlock); - record = tcpto_buf; for (i = 0;i < n;++i) { - if (byte_equal(ip->d,4,record)) +#ifdef INET6 + if (ix->af == tcpto_buf[i].af && (ix->af == AF_INET ? byte_equal(&ix->addr.ip, sizeof(ix->addr.ip), &tcpto_buf[i].addr.ip) : byte_equal(&ix->addr.ip6, sizeof(ix->addr.ip6), &tcpto_buf[i].addr.ip6))) +#else + if (byte_equal(&ix->addr.ip, sizeof(ix->addr.ip), &tcpto_buf[i].addr.ip)) +#endif { flagwasthere = 1; - if (record[4] >= 2) + if (tcpto_buf[i].flag >= 2) { - when = (unsigned long) (unsigned char) record[11]; - when = (when << 8) + (unsigned long) (unsigned char) record[10]; - when = (when << 8) + (unsigned long) (unsigned char) record[9]; - when = (when << 8) + (unsigned long) (unsigned char) record[8]; - + when = tcpto_buf[i].when; if (now() - when < ((60 + (getpid() & 31)) << 6)) return 1; } return 0; } - record += 16; } return 0; } -void tcpto_err(ip,flagerr) struct ip_address *ip; int flagerr; +void tcpto_err(ix,flagerr) +struct ip_mx *ix; int flagerr; { int n; int i; - char *record; datetime_sec when; - datetime_sec firstwhen; - int firstpos; + datetime_sec firstwhen=0; + int firstpos=-1; datetime_sec lastwhen; if (!flagerr) @@ -84,80 +87,68 @@ n = getbuf(); if (!n) return; - record = tcpto_buf; for (i = 0;i < n;++i) { - if (byte_equal(ip->d,4,record)) +#ifdef INET6 + if (ix->af == tcpto_buf[i].af && (ix->af == AF_INET ? byte_equal(&ix->addr.ip, sizeof(ix->addr.ip), &tcpto_buf[i].addr.ip) : byte_equal(&ix->addr.ip6, sizeof(ix->addr.ip6), &tcpto_buf[i].addr.ip6))) +#else + if (byte_equal(&ix->addr.ip, sizeof(ix->addr.ip), &tcpto_buf[i].addr.ip)) +#endif { if (!flagerr) - record[4] = 0; + tcpto_buf[i].flag = 0; else { - lastwhen = (unsigned long) (unsigned char) record[11]; - lastwhen = (lastwhen << 8) + (unsigned long) (unsigned char) record[10]; - lastwhen = (lastwhen << 8) + (unsigned long) (unsigned char) record[9]; - lastwhen = (lastwhen << 8) + (unsigned long) (unsigned char) record[8]; + lastwhen = tcpto_buf[i].when; when = now(); - if (record[4] && (when < 120 + lastwhen)) { close(fdlock); return; } + if (tcpto_buf[i].flag && (when < 120 + lastwhen)) { close(fdlock); return; } - if (++record[4] > 10) record[4] = 10; - record[8] = when; when >>= 8; - record[9] = when; when >>= 8; - record[10] = when; when >>= 8; - record[11] = when; + if (++tcpto_buf[i].flag > 10) tcpto_buf[i].flag = 10; + tcpto_buf[i].when = when; } - if (seek_set(fdlock,i << 4) == 0) - if (write(fdlock,record,16) < 16) + if (seek_set(fdlock,sizeof(tcpto_buf[0])*i) == 0) + if (write(fdlock,&tcpto_buf[i],sizeof(tcpto_buf[0])) < sizeof(tcpto_buf[0])) ; /*XXX*/ close(fdlock); return; } - record += 16; } if (!flagerr) { close(fdlock); return; } - record = tcpto_buf; for (i = 0;i < n;++i) - { - if (!record[4]) break; - record += 16; - } + if (tcpto_buf[i].flag == 0) break; if (i >= n) { firstpos = -1; - record = tcpto_buf; for (i = 0;i < n;++i) { - when = (unsigned long) (unsigned char) record[11]; - when = (when << 8) + (unsigned long) (unsigned char) record[10]; - when = (when << 8) + (unsigned long) (unsigned char) record[9]; - when = (when << 8) + (unsigned long) (unsigned char) record[8]; - when += (record[4] << 10); + when = tcpto_buf[i].when; + when += (tcpto_buf[i].flag << 10); if ((firstpos < 0) || (when < firstwhen)) { firstpos = i; firstwhen = when; } - record += 16; } i = firstpos; } if (i >= 0) { - record = tcpto_buf + (i << 4); - byte_copy(record,4,ip->d); - when = now(); - record[8] = when; when >>= 8; - record[9] = when; when >>= 8; - record[10] = when; when >>= 8; - record[11] = when; - record[4] = 1; - if (seek_set(fdlock,i << 4) == 0) - if (write(fdlock,record,16) < 16) + tcpto_buf[i].af = ix->af; +#ifdef INET6 + if (ix->af == AF_INET6) + byte_copy(&tcpto_buf[i].addr.ip6, 16, &ix->addr.ip6); + else +#endif + byte_copy(&tcpto_buf[i].addr.ip, 4, &ix->addr.ip); + tcpto_buf[i].when = now(); + tcpto_buf[i].flag = 1; + if (seek_set(fdlock,sizeof(tcpto_buf[0])*i) == 0) + if (write(fdlock,&tcpto_buf[i],sizeof(tcpto_buf[0])) < sizeof(tcpto_buf[0])) ; /*XXX*/ } diff -Naur qmail-1.03.orig/tcpto.h qmail-1.03/tcpto.h --- qmail-1.03.orig/tcpto.h 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/tcpto.h 2009-03-16 16:36:14.000000000 -0500 @@ -1,8 +1,23 @@ #ifndef TCPTO_H #define TCPTO_H -extern int tcpto(); -extern void tcpto_err(); -extern void tcpto_clean(); +#define TCPTO_BUFSIZ 64 + +struct tcpto_buf { + unsigned char af; + unsigned char flag; + unsigned long when; + union { + struct ip_address ip; +#ifdef INET6 + struct ip6_address ip6; +#endif + unsigned char dummy[16]; + } addr; +}; + +extern int tcpto(struct ip_mx *ix); +extern void tcpto_err(struct ip_mx *ix, int flagerr); +extern void tcpto_clean(void); #endif diff -Naur qmail-1.03.orig/tcpto_clean.c qmail-1.03/tcpto_clean.c --- qmail-1.03.orig/tcpto_clean.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/tcpto_clean.c 2009-03-16 16:36:14.000000000 -0500 @@ -1,9 +1,10 @@ +#include "ipalloc.h" #include "tcpto.h" #include "open.h" #include "substdio.h" #include "readwrite.h" -char tcpto_cleanbuf[1024]; +struct tcpto_buf tcpto_cleanbuf[TCPTO_BUFSIZ]; void tcpto_clean() /* running from queue/mess */ { diff -Naur qmail-1.03.orig/timeoutconn.c qmail-1.03/timeoutconn.c --- qmail-1.03.orig/timeoutconn.c 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/timeoutconn.c 2009-03-16 16:36:14.000000000 -0500 @@ -12,6 +12,7 @@ #include "control.h" #include "constmap.h" #include "stralloc.h" +#include "ipalloc.h" /* if 1, bind() failing will be ignored */ #define IGNORE_BIND_ERROR 0 @@ -53,9 +54,9 @@ return 0 ; } -int bind_by_remoteip(s,ip,force) +int bind_by_remoteip(s,ix,force) int s; -struct ip_address *ip; +struct ip_mx *ix; int force; { struct sockaddr_in salocal; @@ -78,7 +79,14 @@ /* search for d.d.d.d, d.d.d., d.d., d., none */ ipstring[0] = '.'; /* "cheating", but makes the loop check easier below! */ ipstr = ipstring+1; - iplen = ip_fmt(ipstr,ip); /* Well, Dan seems to trust its output! */ +#ifdef INET6 + if (ix->af == AF_INET) + iplen = ip_fmt(ipstr,ix->addr.ip); + else + iplen = ip6_fmt(ipstr,ix->addr.ip6); +#else + iplen = ip_fmt(ipstr,ix->addr.ip); /* Well, Dan seems to trust its output! */ +#endif bindroute = constmap(&bindroutes,ipstr,iplen); if (!bindroute) while (iplen--) /* no worries - the lost char must be 0-9 */ @@ -146,3 +154,52 @@ errno = error_timeout; /* note that connect attempt is continuing */ return -1; } + +#ifdef INET6 +int timeoutconn6(s,ip,port,timeout) +int s; +struct ip6_address *ip; +unsigned int port; +int timeout; +{ + char ch; + struct sockaddr_in6 sin; + char *x; + fd_set wfds; + struct timeval tv; + + byte_zero(&sin,sizeof(sin)); + byte_copy(&sin.sin6_addr,16,ip); + sin.sin6_port = htons(port);; + sin.sin6_family = AF_INET6; + + if (ndelay_on(s) == -1) return -1; + + /* XXX: could bind s */ + + if (connect(s,(struct sockaddr *) &sin,sizeof(sin)) == 0) { + ndelay_off(s); + return 0; + } + if ((errno != error_inprogress) && (errno != error_wouldblock)) return -1; + + FD_ZERO(&wfds); + FD_SET(s,&wfds); + tv.tv_sec = timeout; tv.tv_usec = 0; + + if (select(s + 1,(fd_set *) 0,&wfds,(fd_set *) 0,&tv) == -1) return -1; + if (FD_ISSET(s,&wfds)) { + int dummy; + dummy = sizeof(sin); + if (getpeername(s,(struct sockaddr *) &sin,&dummy) == -1) { + read(s,&ch,1); + return -1; + } + ndelay_off(s); + return 0; + } + + errno = error_timeout; /* note that connect attempt is continuing */ + return -1; +} +#endif diff -Naur qmail-1.03.orig/timeoutconn.h qmail-1.03/timeoutconn.h --- qmail-1.03.orig/timeoutconn.h 2009-03-16 16:35:25.000000000 -0500 +++ qmail-1.03/timeoutconn.h 2009-03-16 16:36:14.000000000 -0500 @@ -2,6 +2,7 @@ #define TIMEOUTCONN_H extern int timeoutconn(); +extern int timeoutconn6(); extern int bind_by_sender(); extern int bind_by_remoteip();