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);
openSUSE Build Service is sponsored by