File netqmail-1.06-ipv6.patch of Package netqmail
This patch enables (net)qmail to send mail to remote SMTP hosts via IPv6.
It may not apply cleanly to out-of-the-box netqmail.
(C) 2011-2012 Peter Conrad <conrad@quisquis.de>
This file is licensed under the terms of the
GNU General Public License Version 2. A copy of these terms should be
enclosed as "gpl-2.0.txt" in the package containing this file.
diff -rNU3 netqmail-1.06/dns.c netqmail-1.06-ipv6/dns.c
--- netqmail-1.06/dns.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/dns.c 2011-06-01 17:02:23.000000000 +0200
@@ -25,6 +25,7 @@
static unsigned char *responsepos;
static int numanswers;
+static int no_aaaa = 0;
static char name[MAXDNAME];
static struct ip_address ip;
unsigned short pref;
@@ -126,12 +127,12 @@
if (rrtype == wanttype)
{
- if (rrdlen < 4)
+ if (wanttype == T_A && rrdlen < 4 || wanttype == T_AAAA && rrdlen < 16)
return DNS_SOFT;
- ip.d[0] = responsepos[0];
- ip.d[1] = responsepos[1];
- ip.d[2] = responsepos[2];
- ip.d[3] = responsepos[3];
+ ip.type = (wanttype == T_A ? AF_INET : AF_INET6);
+ for (i = 0; i < (wanttype == T_A ? 4 : 16); i++) {
+ ip.addr[i] = responsepos[i];
+ }
responsepos += rrdlen;
return 1;
}
@@ -177,11 +178,11 @@
return 0;
}
-void dns_init(flagsearch)
-int flagsearch;
+void dns_init(int flagsearch, int flagv6)
{
res_init();
if (flagsearch) lookup = res_search;
+ no_aaaa = !flagv6;
}
int dns_cname(sa)
@@ -215,7 +216,7 @@
return DNS_HARD; /* alias loop */
}
-#define FMT_IAA 40
+static const char *HEX_DIGITS = "0123456789abcdef";
static int iaafmt(s,ip)
char *s;
@@ -224,14 +225,28 @@
unsigned int i;
unsigned int len;
len = 0;
- i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i;
+ if (ip->type == AF_INET) {
+ i = fmt_ulong(s,(unsigned long) ip->addr[3]); len += i; if (s) s += i;
i = fmt_str(s,"."); len += i; if (s) s += i;
- i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i;
+ i = fmt_ulong(s,(unsigned long) ip->addr[2]); len += i; if (s) s += i;
i = fmt_str(s,"."); len += i; if (s) s += i;
- i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i;
+ i = fmt_ulong(s,(unsigned long) ip->addr[1]); len += i; if (s) s += i;
i = fmt_str(s,"."); len += i; if (s) s += i;
- i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i;
+ i = fmt_ulong(s,(unsigned long) ip->addr[0]); len += i; if (s) s += i;
i = fmt_str(s,".in-addr.arpa."); len += i; if (s) s += i;
+ } else if (!s) {
+ len = 2*32 + 8; // 32 dot-separated nibbles plus "ip6.arpa"
+ } else {
+ for (i = 16; i != 0; ) {
+ i--;
+ *s++ = HEX_DIGITS[ip->addr[i] & 0xf];
+ *s++ = '.';
+ *s++ = HEX_DIGITS[(ip->addr[i] >> 4) & 0xf];
+ *s++ = '.';
+ len += 4;
+ }
+ i = fmt_str(s, "ip6.arpa"); len += i; s += i;
+ }
return len;
}
@@ -266,7 +281,7 @@
stralloc *sa;
int pref;
{
- int r;
+ int r, i, foundv6 = 0;
struct ip_mx ix = {0};
if (!stralloc_copy(&glue,sa)) return DNS_MEM;
@@ -279,13 +294,16 @@
}
}
- switch(resolve(sa,T_A))
+ for (i = no_aaaa; i < 2; i++) {
+ int type = (i ? T_A : T_AAAA);
+ switch(resolve(sa,type))
{
case DNS_MEM: return DNS_MEM;
case DNS_SOFT: return DNS_SOFT;
- case DNS_HARD: return DNS_HARD;
+ case DNS_HARD: if (type == T_AAAA || foundv6) { continue; }
+ return DNS_HARD;
}
- while ((r = findip(T_A)) != 2)
+ while ((r = findip(type)) != 2)
{
ix.ip = ip;
ix.pref = pref;
@@ -295,8 +313,10 @@
ix.fqdn = glue.s;
#endif
if (!ipalloc_append(ia,&ix)) return DNS_MEM;
+ if (type == T_AAAA) { foundv6 = 1; }
+ }
}
- }
+ }
#ifdef IX_FQDN
glue.s = 0;
#endif
diff -rNU3 netqmail-1.06/dnscname.c netqmail-1.06-ipv6/dnscname.c
--- netqmail-1.06/dnscname.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/dnscname.c 2011-06-01 16:28:34.000000000 +0200
@@ -17,7 +17,7 @@
if (!stralloc_copys(&sa,argv[1]))
{ substdio_putsflush(subfderr,"out of memory\n"); _exit(111); }
- dns_init(0);
+ dns_init(0, 1);
dnsdoe(dns_cname(&sa));
substdio_putflush(subfdout,sa.s,sa.len);
substdio_putsflush(subfdout,"\n");
diff -rNU3 netqmail-1.06/dnsfq.c netqmail-1.06-ipv6/dnsfq.c
--- netqmail-1.06/dnsfq.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/dnsfq.c 2011-06-01 16:28:47.000000000 +0200
@@ -19,7 +19,7 @@
if (!stralloc_copys(&sa,argv[1]))
{ substdio_putsflush(subfderr,"out of memory\n"); _exit(111); }
- dns_init(1);
+ dns_init(1, 1);
dnsdoe(dns_ip(&ia,&sa));
if (ia.len <= 0)
{
diff -rNU3 netqmail-1.06/dnsip.c netqmail-1.06-ipv6/dnsip.c
--- netqmail-1.06/dnsip.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/dnsip.c 2011-06-01 16:28:55.000000000 +0200
@@ -23,7 +23,7 @@
if (!stralloc_copys(&sa,argv[1]))
{ substdio_putsflush(subfderr,"out of memory\n"); _exit(111); }
- dns_init(0);
+ dns_init(0, 1);
dnsdoe(dns_ip(&ia,&sa));
for (j = 0;j < ia.len;++j)
{
diff -rNU3 netqmail-1.06/dnsmxip.c netqmail-1.06-ipv6/dnsmxip.c
--- netqmail-1.06/dnsmxip.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/dnsmxip.c 2011-06-01 16:29:00.000000000 +0200
@@ -27,7 +27,7 @@
{ substdio_putsflush(subfderr,"out of memory\n"); _exit(111); }
r = now() + getpid();
- dns_init(0);
+ dns_init(0, 1);
dnsdoe(dns_mxip(&ia,&sa,r));
for (j = 0;j < ia.len;++j)
{
diff -rNU3 netqmail-1.06/dnsptr.c netqmail-1.06-ipv6/dnsptr.c
--- netqmail-1.06/dnsptr.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/dnsptr.c 2011-06-01 16:29:05.000000000 +0200
@@ -17,9 +17,12 @@
{
if (!argv[1]) _exit(100);
- ip_scan(argv[1],&ip);
+ if (ip_scan(argv[1],&ip) != str_len(argv[1])) {
+ substdio_putsflush(subfdout,"Failed to parse first argument - should be an ip address\n");
+ _exit(1);
+ }
- dns_init(0);
+ dns_init(0, 1);
dnsdoe(dns_ptr(&sa,&ip));
substdio_putflush(subfdout,sa.s,sa.len);
substdio_putsflush(subfdout,"\n");
diff -rNU3 netqmail-1.06/fmt_xlong.c netqmail-1.06-ipv6/fmt_xlong.c
--- netqmail-1.06/fmt_xlong.c 1970-01-01 01:00:00.000000000 +0100
+++ netqmail-1.06-ipv6/fmt_xlong.c 2011-06-01 14:51:26.000000000 +0200
@@ -0,0 +1,14 @@
+#include "fmt.h"
+
+unsigned int fmt_xlong(char *s, unsigned long u)
+{
+ register unsigned int len; register unsigned long q;
+ len = 1; q = u;
+ while (q >= 16) { ++len; q >>= 4; }
+ if (s) {
+ s += len;
+ do { *--s = (u & 0xf) < 10 ? '0' + (u & 0xf) : 'a' + ((u & 0xf) - 10);
+ u >>= 4; } while(u); /* handles u == 0 */
+ }
+ return len;
+}
diff -rNU3 netqmail-1.06/ip.c netqmail-1.06-ipv6/ip.c
--- netqmail-1.06/ip.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/ip.c 2011-06-01 14:52:42.000000000 +0200
@@ -1,3 +1,4 @@
+#include <sys/socket.h>
#include "fmt.h"
#include "scan.h"
#include "ip.h"
@@ -10,16 +11,37 @@
unsigned int i;
len = 0;
- i = fmt_ulong(s,(unsigned long) ip->d[0]); len += i; if (s) s += i;
+ if (ip->type == AF_INET) {
+ i = fmt_ulong(s,(unsigned long) ip->addr[0]); len += i; if (s) s += i;
i = fmt_str(s,"."); len += i; if (s) s += i;
- i = fmt_ulong(s,(unsigned long) ip->d[1]); len += i; if (s) s += i;
+ i = fmt_ulong(s,(unsigned long) ip->addr[1]); len += i; if (s) s += i;
i = fmt_str(s,"."); len += i; if (s) s += i;
- i = fmt_ulong(s,(unsigned long) ip->d[2]); len += i; if (s) s += i;
+ i = fmt_ulong(s,(unsigned long) ip->addr[2]); len += i; if (s) s += i;
i = fmt_str(s,"."); len += i; if (s) s += i;
- i = fmt_ulong(s,(unsigned long) ip->d[3]); len += i; if (s) s += i;
+ i = fmt_ulong(s,(unsigned long) ip->addr[3]); len += i; if (s) s += i;
+ } else {
+ i = fmt_xlong(s,(((unsigned long) ip->addr[0]) << 8) + ip->addr[1]); len += i; if (s) s += i;
+ i = fmt_str(s,":"); len += i; if (s) s += i;
+ i = fmt_xlong(s,(((unsigned long) ip->addr[2]) << 8) + ip->addr[3]); len += i; if (s) s += i;
+ i = fmt_str(s,":"); len += i; if (s) s += i;
+ i = fmt_xlong(s,(((unsigned long) ip->addr[4]) << 8) + ip->addr[5]); len += i; if (s) s += i;
+ i = fmt_str(s,":"); len += i; if (s) s += i;
+ i = fmt_xlong(s,(((unsigned long) ip->addr[6]) << 8) + ip->addr[7]); len += i; if (s) s += i;
+ i = fmt_str(s,":"); len += i; if (s) s += i;
+ i = fmt_xlong(s,(((unsigned long) ip->addr[8]) << 8) + ip->addr[9]); len += i; if (s) s += i;
+ i = fmt_str(s,":"); len += i; if (s) s += i;
+ i = fmt_xlong(s,(((unsigned long) ip->addr[10]) << 8) + ip->addr[11]); len += i; if (s) s += i;
+ i = fmt_str(s,":"); len += i; if (s) s += i;
+ i = fmt_xlong(s,(((unsigned long) ip->addr[12]) << 8) + ip->addr[13]); len += i; if (s) s += i;
+ i = fmt_str(s,":"); len += i; if (s) s += i;
+ i = fmt_xlong(s,(((unsigned long) ip->addr[14]) << 8) + ip->addr[15]); len += i; if (s) s += i;
+ }
return len;
}
+/* Supports dotted-quad for ipv4, "coloned-octet" for ipv6.
+ * ipv6 abbreviations like ::1 are currently *not* supported.
+ */
unsigned int ip_scan(s,ip)
char *s;
struct ip_address *ip;
@@ -29,13 +51,42 @@
unsigned long u;
len = 0;
- i = scan_ulong(s,&u); if (!i) return 0; ip->d[0] = u; s += i; len += i;
+ i = scan_ulong(s,&u);
+ if (i && s[i] == '.') {
+ ip->type = AF_INET;
+ if (!i) return 0; ip->addr[0] = u; s += i; len += i;
if (*s != '.') return 0; ++s; ++len;
- i = scan_ulong(s,&u); if (!i) return 0; ip->d[1] = u; s += i; len += i;
+ i = scan_ulong(s,&u); if (!i) return 0; ip->addr[1] = u; s += i; len += i;
if (*s != '.') return 0; ++s; ++len;
- i = scan_ulong(s,&u); if (!i) return 0; ip->d[2] = u; s += i; len += i;
+ i = scan_ulong(s,&u); if (!i) return 0; ip->addr[2] = u; s += i; len += i;
if (*s != '.') return 0; ++s; ++len;
- i = scan_ulong(s,&u); if (!i) return 0; ip->d[3] = u; s += i; len += i;
+ i = scan_ulong(s,&u); if (!i) return 0; ip->addr[3] = u; s += i; len += i;
+ } else {
+ ip->type = AF_INET6;
+ i = scan_xlong(s,&u); if (!i) return 0;
+ ip->addr[0] = (u >> 8) & 0xff; ip->addr[1] = u & 0xff; s += i; len += i;
+ if (*s != ':') return 0; ++s; ++len;
+ i = scan_xlong(s,&u); if (!i) return 0;
+ ip->addr[2] = (u >> 8) & 0xff; ip->addr[3] = u & 0xff; s += i; len += i;
+ if (*s != ':') return 0; ++s; ++len;
+ i = scan_xlong(s,&u); if (!i) return 0;
+ ip->addr[4] = (u >> 8) & 0xff; ip->addr[5] = u & 0xff; s += i; len += i;
+ if (*s != ':') return 0; ++s; ++len;
+ i = scan_xlong(s,&u); if (!i) return 0;
+ ip->addr[6] = (u >> 8) & 0xff; ip->addr[7] = u & 0xff; s += i; len += i;
+ if (*s != ':') return 0; ++s; ++len;
+ i = scan_xlong(s,&u); if (!i) return 0;
+ ip->addr[8] = (u >> 8) & 0xff; ip->addr[9] = u & 0xff; s += i; len += i;
+ if (*s != ':') return 0; ++s; ++len;
+ i = scan_xlong(s,&u); if (!i) return 0;
+ ip->addr[10] = (u >> 8) & 0xff; ip->addr[11] = u & 0xff; s += i; len += i;
+ if (*s != ':') return 0; ++s; ++len;
+ i = scan_xlong(s,&u); if (!i) return 0;
+ ip->addr[12] = (u >> 8) & 0xff; ip->addr[13] = u & 0xff; s += i; len += i;
+ if (*s != ':') return 0; ++s; ++len;
+ i = scan_xlong(s,&u); if (!i) return 0;
+ ip->addr[14] = (u >> 8) & 0xff; ip->addr[15] = u & 0xff; s += i; len += i;
+ }
return len;
}
diff -rNU3 netqmail-1.06/ip.h netqmail-1.06-ipv6/ip.h
--- netqmail-1.06/ip.h 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/ip.h 2011-06-01 14:52:42.000000000 +0200
@@ -1,10 +1,13 @@
#ifndef IP_H
#define IP_H
-struct ip_address { unsigned char d[4]; } ;
+struct ip_address {
+ unsigned int type;
+ unsigned char addr[16];
+} ;
extern unsigned int ip_fmt();
-#define IPFMT 19
+#define IPFMT 50
extern unsigned int ip_scan();
extern unsigned int ip_scanbracket();
diff -rNU3 netqmail-1.06/ipme.c netqmail-1.06-ipv6/ipme.c
--- netqmail-1.06/ipme.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/ipme.c 2011-06-01 14:52:42.000000000 +0200
@@ -24,7 +24,8 @@
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 (ip->type == ipme.ix[i].ip.type
+ && byte_equal(&ipme.ix[i].ip.addr,ip->type == AF_INET ? 4 : 16,ip->addr))
return 1;
return 0;
}
@@ -37,8 +38,9 @@
char *x;
struct ifreq *ifr;
struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
int len;
- int s;
+ int s, family;
struct ip_mx ix;
if (ipmeok) return 1;
@@ -49,9 +51,17 @@
/* 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");
+ ix.ip.type = AF_INET;
+ byte_zero(&ix.ip.addr,16);
if (!ipalloc_append(&ipme,&ix)) { return 0; }
- if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) return -1;
+ /* same for :: in ipv6 */
+ ix.ip.type = AF_INET6;
+ if (!ipalloc_append(&ipme,&ix)) { return 0; }
+ for (family = 0; family < 2; family++) {
+ if ((s = socket(family ? AF_INET : AF_INET6, SOCK_STREAM,0)) == -1) {
+ if (!family) { continue; }
+ return -1;
+ }
len = 256;
for (;;) {
@@ -76,7 +86,15 @@
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);
+ ix.ip.type = AF_INET;
+ byte_copy(&ix.ip.addr,4,&sin->sin_addr);
+ if (ioctl(s,SIOCGIFFLAGS,x) == 0)
+ if (ifr->ifr_flags & IFF_UP)
+ if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; }
+ } else if (ifr->ifr_addr.sa_family == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
+ ix.ip.type = AF_INET6;
+ byte_copy(&ix.ip.addr,16,&sin6->sin6_addr);
if (ioctl(s,SIOCGIFFLAGS,x) == 0)
if (ifr->ifr_flags & IFF_UP)
if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; }
@@ -88,13 +106,20 @@
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.ip.type = AF_INET;
+ byte_copy(&ix.ip.addr,4,&sin->sin_addr);
+ if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; }
+ } else if (ifr->ifr_addr.sa_family == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
+ ix.ip.type = AF_INET6;
+ byte_copy(&ix.ip.addr,4,&sin6->sin6_addr);
if (!ipalloc_append(&ipme,&ix)) { close(s); return 0; }
}
#endif
x += len;
}
close(s);
+ }
ipmeok = 1;
return 1;
}
diff -rNU3 netqmail-1.06/Makefile netqmail-1.06-ipv6/Makefile
--- netqmail-1.06/Makefile 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/Makefile 2011-06-01 14:51:26.000000000 +0200
@@ -577,6 +577,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
@@ -609,9 +613,10 @@
fs.a: \
makelib fmt_str.o fmt_strn.o fmt_uint.o fmt_uint0.o fmt_ulong.o \
-scan_ulong.o scan_8long.o
+scan_ulong.o scan_8long.o \
+fmt_xlong.o scan_xlong.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 scan_ulong.o scan_8long.o fmt_xlong.o scan_xlong.o
getln.a: \
makelib getln.o getln2.o
@@ -1711,6 +1716,10 @@
compile scan_ulong.c scan.h
./compile scan_ulong.c
+scan_xlong.o: \
+compile scan_xlong.c scan.h
+ ./compile scan_xlong.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 \
diff -rNU3 netqmail-1.06/qmail-remote.8 netqmail-1.06-ipv6/qmail-remote.8
--- netqmail-1.06/qmail-remote.8 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/qmail-remote.8 2011-06-01 16:38:49.000000000 +0200
@@ -238,6 +238,13 @@
.B tlshosts/<FQDN>.pem
exists.
+.TP 5
+.I useipv6
+If this file contains a non-zero integer,
+.B qmail-remote
+will lookup AAAA records (in addition to the standard A records) and
+attempt to connect the resulting IPv6 address, if found.
+
.SH "SEE ALSO"
addresses(5),
envelopes(5),
diff -rNU3 netqmail-1.06/qmail-remote.c netqmail-1.06-ipv6/qmail-remote.c
--- netqmail-1.06/qmail-remote.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/qmail-remote.c 2011-06-01 16:26:06.000000000 +0200
@@ -59,6 +59,8 @@
const char *ssl_err_str = 0;
#endif
+int flagv6;
+
void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); }
void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); }
void zerodie() { zero(); substdio_flush(subfdoutsmall); _exit(0); }
@@ -679,6 +681,9 @@
case 1:
if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break;
}
+ if (control_readint(&flagv6,"control/useipv6") == -1) {
+ flagv6 = 0;
+ }
}
void main(argc,argv)
@@ -699,6 +704,7 @@
if (chdir(auto_qmail) == -1) temp_chdir();
getcontrols();
+ dns_init(0, flagv6);
if (!stralloc_copys(&host,argv[1])) temp_nomem();
@@ -710,8 +716,9 @@
if (relayhost && !*relayhost) relayhost = 0;
if (relayhost) {
+ int r_bracket = str_rchr(relayhost,']');
i = str_chr(relayhost,':');
- if (relayhost[i]) {
+ if (relayhost[i] && (i > r_bracket || !relayhost[r_bracket])) {
scan_ulong(relayhost + i + 1,&port);
relayhost[i] = 0;
}
@@ -766,7 +773,7 @@
for (i = 0;i < ip.len;++i) if (ip.ix[i].pref < prefme) {
if (tcpto(&ip.ix[i].ip)) continue;
- smtpfd = socket(AF_INET,SOCK_STREAM,0);
+ smtpfd = socket(ip.ix[i].ip.type,SOCK_STREAM,0);
if (smtpfd == -1) temp_oserr();
if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) {
@@ -1006,4 +1007,5 @@
}
temp_noconn();
+ _exit(0); // never reached
}
diff -rNU3 netqmail-1.06/qmail-tcpto.c netqmail-1.06-ipv6/qmail-tcpto.c
--- netqmail-1.06/qmail-tcpto.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/qmail-tcpto.c 2011-06-01 14:52:42.000000000 +0200
@@ -28,7 +28,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];
+char tcpto_buf[2048];
char tmp[FMT_ULONG + IPFMT];
@@ -56,26 +56,30 @@
close(fdlock);
if (r == -1) die_read();
- r >>= 4;
+ if (r < sizeof(tcpto_buf)) {
+ substdio_puts(subfderr,"WARNING: tcpto probably has old (IPv4-only) format. Output may be garbled.\n");
+ }
+ r >>= 5;
start = now();
record = tcpto_buf;
for (i = 0;i < r;++i)
{
- if (record[4] >= 1)
+ if (record[17] >= 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];
+ ip.type = record[0];
+ byte_copy(&ip.addr, ip.type == AF_INET ? 4 : 16,record+1);
+ when = (unsigned long) (unsigned char) record[23];
+ when = (when << 8) + (unsigned long) (unsigned char) record[22];
+ when = (when << 8) + (unsigned long) (unsigned char) record[21];
+ when = (when << 8) + (unsigned long) (unsigned char) record[20];
substdio_put(subfdout,tmp,ip_fmt(tmp,&ip));
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,(unsigned long) (unsigned char) record[17]));
substdio_puts(subfdout,"\n");
}
record += 16;
diff -rNU3 netqmail-1.06/remoteinfo.c netqmail-1.06-ipv6/remoteinfo.c
--- netqmail-1.06/remoteinfo.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/remoteinfo.c 2011-06-01 14:52:42.000000000 +0200
@@ -31,8 +31,10 @@
int timeout;
{
char *x;
- int s;
+ int s, sa_len;
+ struct sockaddr *sa;
struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
substdio ss;
char buf[32];
unsigned int len;
@@ -41,14 +43,24 @@
t = timeout;
- s = socket(AF_INET,SOCK_STREAM,0);
+ s = socket(ipl->type,SOCK_STREAM,0);
if (s == -1) return 0;
-
- byte_zero(&sin,sizeof(sin));
+ if (ipl->type == AF_INET) {
+ sa_len = sizeof(sin);
+ byte_zero(&sin,sa_len);
sin.sin_family = AF_INET;
- byte_copy(&sin.sin_addr,4,ipl);
+ byte_copy(&sin.sin_addr,4,ipl->addr);
sin.sin_port = 0;
- if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; }
+ sa = (struct sockaddr *) &sin;
+ } else {
+ sa_len = sizeof(sin6);
+ byte_zero(&sin6,sa_len);
+ sin6.sin6_family = AF_INET6;
+ byte_copy(&sin6.sin6_addr,16,ipl->addr);
+ sin6.sin6_port = 0;
+ sa = (struct sockaddr *) &sin6;
+ }
+ if (bind(s,sa, sa_len) == -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);
diff -rNU3 netqmail-1.06/scan_xlong.c netqmail-1.06-ipv6/scan_xlong.c
--- netqmail-1.06/scan_xlong.c 1970-01-01 01:00:00.000000000 +0100
+++ netqmail-1.06-ipv6/scan_xlong.c 2011-06-01 14:51:26.000000000 +0200
@@ -0,0 +1,13 @@
+#include "scan.h"
+
+unsigned int scan_xlong(const char *s, unsigned long *u)
+{
+ register unsigned int pos; register unsigned long result;
+ register unsigned long c;
+ pos = 0; result = 0;
+ while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10
+ || (c = (unsigned long) (unsigned char) (s[pos] - 'a' + 10)) < 16 && c >= 10
+ || (c = (unsigned long) (unsigned char) (s[pos] - 'A' + 10)) < 16 && c >= 10)
+ { result = result * 16 + c; ++pos; }
+ *u = result; return pos;
+}
diff -rNU3 netqmail-1.06/TARGETS netqmail-1.06-ipv6/TARGETS
--- netqmail-1.06/TARGETS 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/TARGETS 2011-06-01 14:51:26.000000000 +0200
@@ -389,3 +389,5 @@
setup
check
update_tmprsadh
+fmt_xlong.o
+scan_xlong.o
diff -rNU3 netqmail-1.06/tcp-env.c netqmail-1.06-ipv6/tcp-env.c
--- netqmail-1.06/tcp-env.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/tcp-env.c 2011-06-01 14:52:42.000000000 +0200
@@ -18,12 +18,12 @@
void die() { _exit(111); }
-struct sockaddr_in salocal;
+struct sockaddr_in6 sa6local;
unsigned long localport;
struct ip_address iplocal;
stralloc localname = {0};
-struct sockaddr_in saremote;
+struct sockaddr_in6 sa6remote;
unsigned long remoteport;
struct ip_address ipremote;
stralloc remotename = {0};
@@ -39,6 +39,8 @@
int opt;
int flagremoteinfo;
unsigned long timeout;
+ struct sockaddr_in *sal = (struct sockaddr_in *) ((struct sockaddr *) &sa6local);
+ struct sockaddr_in *sar = (struct sockaddr_in *) ((struct sockaddr *) &sa6remote);
sig_pipeignore();
@@ -59,20 +61,32 @@
if (!env_init()) die();
proto = env_get("PROTO");
- if (!proto || str_diff(proto,"TCP"))
+ if (!proto || (str_diff(proto,"TCP") && str_diff(proto,"TCP6")))
{
if (!env_put("PROTO=TCP")) die();
- dummy = sizeof(salocal);
- if (getsockname(0,(struct sockaddr *) &salocal,&dummy) == -1) die();
+ dummy = sizeof(sa6local);
+ if (getsockname(0,(struct sockaddr *) &sa6local,&dummy) == -1) die();
+ if (dummy == sizeof(*sal)) {
+ localport = ntohs(sal->sin_port);
+ temp[fmt_ulong(temp,localport)] = 0;
+ if (!env_put2("TCPLOCALPORT",temp)) die();
- localport = ntohs(salocal.sin_port);
+ iplocal.type = AF_INET;
+ byte_copy(&iplocal.addr,4,&sal->sin_addr);
+ temp[ip_fmt(temp,&iplocal)] = 0;
+ if (!env_put2("TCPLOCALIP",temp)) die();
+ }
+ if (dummy == sizeof(sa6local)) {
+ localport = ntohs(sa6local.sin6_port);
temp[fmt_ulong(temp,localport)] = 0;
if (!env_put2("TCPLOCALPORT",temp)) die();
- byte_copy(&iplocal,4,&salocal.sin_addr);
+ iplocal.type = AF_INET6;
+ byte_copy(&iplocal.addr,16,&sa6local.sin6_addr);
temp[ip_fmt(temp,&iplocal)] = 0;
if (!env_put2("TCPLOCALIP",temp)) die();
+ }
switch(dns_ptr(&localname,&iplocal))
{
@@ -88,16 +102,29 @@
if (!env_unset("TCPLOCALHOST")) die();
}
- dummy = sizeof(saremote);
- if (getpeername(0,(struct sockaddr *) &saremote,&dummy) == -1) die();
+ dummy = sizeof(sa6remote);
+ if (getpeername(0,(struct sockaddr *) &sa6remote,&dummy) == -1) die();
- remoteport = ntohs(saremote.sin_port);
+ if (dummy == sizeof(*sar)) {
+ remoteport = ntohs(sar->sin_port);
+ temp[fmt_ulong(temp,remoteport)] = 0;
+ if (!env_put2("TCPREMOTEPORT",temp)) die();
+
+ ipremote.type = AF_INET;
+ byte_copy(&ipremote.addr,4,&sar->sin_addr);
+ temp[ip_fmt(temp,&ipremote)] = 0;
+ if (!env_put2("TCPREMOTEIP",temp)) die();
+ }
+ if (dummy == sizeof(sa6remote)) {
+ remoteport = ntohs(sa6remote.sin6_port);
temp[fmt_ulong(temp,remoteport)] = 0;
if (!env_put2("TCPREMOTEPORT",temp)) die();
- byte_copy(&ipremote,4,&saremote.sin_addr);
+ ipremote.type = AF_INET6;
+ byte_copy(&ipremote.addr,16,&sa6remote.sin6_addr);
temp[ip_fmt(temp,&ipremote)] = 0;
if (!env_put2("TCPREMOTEIP",temp)) die();
+ }
switch(dns_ptr(&remotename,&ipremote))
{
diff -rNU3 netqmail-1.06/tcpto.c netqmail-1.06-ipv6/tcpto.c
--- netqmail-1.06/tcpto.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/tcpto.c 2011-06-01 14:52:42.000000000 +0200
@@ -8,7 +8,7 @@
#include "datetime.h"
#include "readwrite.h"
-char tcpto_buf[1024];
+char tcpto_buf[2048];
static int flagwasthere;
static int fdlock;
@@ -26,8 +26,11 @@
r = read(fd,tcpto_buf,sizeof(tcpto_buf));
close(fd);
if (r < 0) { close(fdlock); return 0; }
- r >>= 4;
- if (!r) close(fdlock);
+ if (r < sizeof(tcpto_buf)) {
+ byte_zero(tcpto_buf, sizeof(tcpto_buf));
+ r = sizeof(tcpto_buf);
+ }
+ r >>= 5;
return r;
}
@@ -47,22 +50,22 @@
record = tcpto_buf;
for (i = 0;i < n;++i)
{
- if (byte_equal(ip->d,4,record))
+ if (ip->type == record[0] && byte_equal(ip->addr, ip->type == AF_INET ? 4 : 16, record+1))
{
flagwasthere = 1;
- if (record[4] >= 2)
+ if (record[17] >= 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 = (unsigned long) (unsigned char) record[23];
+ when = (when << 8) + (unsigned long) (unsigned char) record[22];
+ when = (when << 8) + (unsigned long) (unsigned char) record[21];
+ when = (when << 8) + (unsigned long) (unsigned char) record[20];
if (now() - when < ((60 + (getpid() & 31)) << 6))
return 1;
}
return 0;
}
- record += 16;
+ record += 32;
}
return 0;
}
@@ -87,33 +90,33 @@
record = tcpto_buf;
for (i = 0;i < n;++i)
{
- if (byte_equal(ip->d,4,record))
+ if (ip->type == record[0] && byte_equal(ip->addr, ip->type == AF_INET ? 4 : 16, record+1))
{
if (!flagerr)
- record[4] = 0;
+ record[17] = 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 = (unsigned long) (unsigned char) record[23];
+ lastwhen = (lastwhen << 8) + (unsigned long) (unsigned char) record[22];
+ lastwhen = (lastwhen << 8) + (unsigned long) (unsigned char) record[21];
+ lastwhen = (lastwhen << 8) + (unsigned long) (unsigned char) record[20];
when = now();
- if (record[4] && (when < 120 + lastwhen)) { close(fdlock); return; }
+ if (record[17] && (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 (++record[17] > 10) record[17] = 10;
+ record[20] = when; when >>= 8;
+ record[21] = when; when >>= 8;
+ record[22] = when; when >>= 8;
+ record[23] = when;
}
- if (seek_set(fdlock,i << 4) == 0)
- if (write(fdlock,record,16) < 16)
+ if (seek_set(fdlock,i << 5) == 0)
+ if (write(fdlock,record,32) < 32)
; /*XXX*/
close(fdlock);
return;
}
- record += 16;
+ record += 32;
}
if (!flagerr) { close(fdlock); return; }
@@ -121,8 +124,8 @@
record = tcpto_buf;
for (i = 0;i < n;++i)
{
- if (!record[4]) break;
- record += 16;
+ if (!record[17]) break;
+ record += 32;
}
if (i >= n)
@@ -131,33 +134,34 @@
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 = (unsigned long) (unsigned char) record[23];
+ when = (when << 8) + (unsigned long) (unsigned char) record[22];
+ when = (when << 8) + (unsigned long) (unsigned char) record[21];
+ when = (when << 8) + (unsigned long) (unsigned char) record[20];
+ when += (record[17] << 10);
if ((firstpos < 0) || (when < firstwhen))
{
firstpos = i;
firstwhen = when;
}
- record += 16;
+ record += 32;
}
i = firstpos;
}
if (i >= 0)
{
- record = tcpto_buf + (i << 4);
- byte_copy(record,4,ip->d);
+ record = tcpto_buf + (i << 5);
+ record[0] = ip->type;
+ byte_copy(record+1,ip->type == AF_INET ? 4 : 16,ip->addr);
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)
+ record[20] = when; when >>= 8;
+ record[21] = when; when >>= 8;
+ record[22] = when; when >>= 8;
+ record[23] = when;
+ record[17] = 1;
+ if (seek_set(fdlock,i << 5) == 0)
+ if (write(fdlock,record,32) < 32)
; /*XXX*/
}
diff -rNU3 netqmail-1.06/timeoutconn.c netqmail-1.06-ipv6/timeoutconn.c
--- netqmail-1.06/timeoutconn.c 2011-06-01 17:02:59.000000000 +0200
+++ netqmail-1.06-ipv6/timeoutconn.c 2011-06-01 14:52:42.000000000 +0200
@@ -18,21 +18,36 @@
{
char ch;
struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr *sa;
+ socklen_t sa_len;
char *x;
fd_set wfds;
struct timeval tv;
-
+
+ if (ip->type == AF_INET) {
byte_zero(&sin,sizeof(sin));
- byte_copy(&sin.sin_addr,4,ip);
+ byte_copy(&sin.sin_addr,4,ip->addr);
x = (char *) &sin.sin_port;
x[1] = port; port >>= 8; x[0] = port;
sin.sin_family = AF_INET;
+ sa = (struct sockaddr *) &sin;
+ sa_len = sizeof(sin);
+ } else {
+ byte_zero(&sin6,sizeof(sin6));
+ byte_copy(&sin6.sin6_addr,16,ip->addr);
+ x = (char *) &sin6.sin6_port;
+ x[1] = port; port >>= 8; x[0] = port;
+ sin6.sin6_family = AF_INET6;
+ sa = (struct sockaddr *) &sin6;
+ sa_len = sizeof(sin6);
+ }
if (ndelay_on(s) == -1) return -1;
/* XXX: could bind s */
- if (connect(s,(struct sockaddr *) &sin,sizeof(sin)) == 0) {
+ if (connect(s, sa, sa_len) == 0) {
ndelay_off(s);
return 0;
}
@@ -44,9 +59,7 @@
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) {
+ if (getpeername(s, sa, &sa_len) == -1) {
read(s,&ch,1);
return -1;
}
diff -rNU3 netqmail-1.06/tcpto_clean.c netqmail-1.06-ipv6/tcpto_clean.c
--- netqmail-1.06/tcpto_clean.c 1998-06-15 12:53:16.000000000 +0200
+++ netqmail-1.06-ipv6/tcpto_clean.c 2011-07-15 15:39:21.000000000 +0200
@@ -3,7 +3,7 @@
#include "substdio.h"
#include "readwrite.h"
-char tcpto_cleanbuf[1024];
+char tcpto_cleanbuf[2048];
void tcpto_clean() /* running from queue/mess */
{
--- netqmail-1.06/tcp-env.c 2012-01-16 23:03:16.000000000 +0100
+++ netqmail.ipv6/tcp-env.c 2012-01-17 11:17:45.000000000 +0100
@@ -16,6 +16,8 @@
#include "exit.h"
#include "case.h"
+static const unsigned char V4_MAPPED_PFX[] = "\0\0\0\0\0\0\0\0\0\0\377\377";
+
void die() { _exit(111); }
struct sockaddr_in6 sa6local;
@@ -67,17 +69,22 @@
dummy = sizeof(sa6local);
if (getsockname(0,(struct sockaddr *) &sa6local,&dummy) == -1) die();
- if (dummy == sizeof(*sal)) {
- localport = ntohs(sal->sin_port);
+ if (dummy == sizeof(*sal)
+ || dummy == sizeof(sa6local) && byte_equal(V4_MAPPED_PFX, 12, &sa6local.sin6_addr)) {
+ if (dummy == sizeof(*sal)) {
+ localport = ntohs(sal->sin_port);
+ byte_copy(&iplocal.addr,4,&sal->sin_addr);
+ } else {
+ localport = ntohs(sa6local.sin6_port);
+ byte_copy(&iplocal.addr,4,&sa6local.sin6_addr.s6_addr[12]);
+ }
temp[fmt_ulong(temp,localport)] = 0;
if (!env_put2("TCPLOCALPORT",temp)) die();
iplocal.type = AF_INET;
- byte_copy(&iplocal.addr,4,&sal->sin_addr);
temp[ip_fmt(temp,&iplocal)] = 0;
if (!env_put2("TCPLOCALIP",temp)) die();
- }
- if (dummy == sizeof(sa6local)) {
+ } else if (dummy == sizeof(sa6local)) {
localport = ntohs(sa6local.sin6_port);
temp[fmt_ulong(temp,localport)] = 0;
if (!env_put2("TCPLOCALPORT",temp)) die();
@@ -105,17 +112,22 @@
dummy = sizeof(sa6remote);
if (getpeername(0,(struct sockaddr *) &sa6remote,&dummy) == -1) die();
- if (dummy == sizeof(*sar)) {
- remoteport = ntohs(sar->sin_port);
+ if (dummy == sizeof(*sar)
+ || dummy == sizeof(sa6remote) && byte_equal(V4_MAPPED_PFX, 12, &sa6remote.sin6_addr)) {
+ if (dummy == sizeof(*sar)) {
+ remoteport = ntohs(sar->sin_port);
+ byte_copy(&ipremote.addr,4,&sar->sin_addr);
+ } else {
+ remoteport = ntohs(sa6remote.sin6_port);
+ byte_copy(&ipremote.addr,4,&sa6remote.sin6_addr.s6_addr[12]);
+ }
temp[fmt_ulong(temp,remoteport)] = 0;
if (!env_put2("TCPREMOTEPORT",temp)) die();
ipremote.type = AF_INET;
- byte_copy(&ipremote.addr,4,&sar->sin_addr);
temp[ip_fmt(temp,&ipremote)] = 0;
if (!env_put2("TCPREMOTEIP",temp)) die();
- }
- if (dummy == sizeof(sa6remote)) {
+ } else if (dummy == sizeof(sa6remote)) {
remoteport = ntohs(sa6remote.sin6_port);
temp[fmt_ulong(temp,remoteport)] = 0;
if (!env_put2("TCPREMOTEPORT",temp)) die();
diff -rU3 netqmail-1.06/qmail-tcpok.c netqmail-1.06.ipv6/qmail-tcpok.c
--- netqmail-1.06/qmail-tcpok.c 1998-06-15 12:53:16.000000000 +0200
+++ netqmail-1.06.ipv6/qmail-tcpok.c 2012-01-24 12:02:34.000000000 +0100
@@ -8,7 +8,7 @@
#define FATAL "qmail-tcpok: fatal: "
-char buf[1024]; /* XXX: must match size in tcpto_clean.c, tcpto.c */
+char buf[2048]; /* XXX: must match size in tcpto_clean.c, tcpto.c */
substdio ss;
void main()
diff -rU3 netqmail-1.06/qmail-tcpto.c netqmail-1.06.ipv6/qmail-tcpto.c
--- netqmail-1.06/qmail-tcpto.c 2012-01-24 12:17:52.000000000 +0100
+++ netqmail-1.06.ipv6/qmail-tcpto.c 2012-01-24 12:17:33.000000000 +0100
@@ -82,7 +82,7 @@
substdio_put(subfdout,tmp,fmt_ulong(tmp,(unsigned long) (unsigned char) record[17]));
substdio_puts(subfdout,"\n");
}
- record += 16;
+ record += 32;
}
die(0);