diff --git a/package/Config.in b/package/Config.in
index da5b62b..d4fa62b 100644
--- a/package/Config.in
+++ b/package/Config.in
@@ -373,6 +373,7 @@ source "package/cups/Config.in"
 if BR2_PACKAGE_BUSYBOX_SHOW_OTHERS
 source "package/dhcp/Config.in"
 endif
+source "package/djbdns/Config.in"
 source "package/dnsmasq/Config.in"
 source "package/dropbear/Config.in"
 source "package/ethtool/Config.in"
@@ -433,6 +434,7 @@ source "package/tinyhttpd/Config.in"
 endif
 source "package/tn5250/Config.in"
 source "package/ttcp/Config.in"
+source "package/ucspi-tcp/Config.in"
 source "package/udpcast/Config.in"
 source "package/vpnc/Config.in"
 source "package/vsftpd/Config.in"
@@ -471,6 +473,9 @@ endmenu
 menu "System tools"
 if BR2_PACKAGE_BUSYBOX_SHOW_OTHERS
 source "package/bootutils/Config.in"
+endif
+source "package/daemontools/Config.in"
+if BR2_PACKAGE_BUSYBOX_SHOW_OTHERS
 source "package/module-init-tools/Config.in"
 source "package/procps/Config.in"
 source "package/psmisc/Config.in"
diff --git a/package/daemontools/Config.in b/package/daemontools/Config.in
new file mode 100644
index 0000000..e8fa20a
--- /dev/null
+++ b/package/daemontools/Config.in
@@ -0,0 +1,6 @@
+config BR2_PACKAGE_DAEMONTOOLS
+	bool "daemontools"
+	help
+		Daemontools is a collection of tools for managing UNIX services by DJ Bernstein.
+
+		http://cr.yp.to/daemontools.html
diff --git a/package/daemontools/daemontools-01-cross.patch b/package/daemontools/daemontools-01-cross.patch
new file mode 100644
index 0000000..ec83954
--- /dev/null
+++ b/package/daemontools/daemontools-01-cross.patch
@@ -0,0 +1,137 @@
+diff -ruN daemontools-0.76.orig/src/hasflock.h daemontools-0.76/src/hasflock.h
+--- daemontools-0.76.orig/src/hasflock.h	1970-01-01 01:00:00.000000000 +0100
++++ daemontools-0.76/src/hasflock.h	2011-01-08 12:59:40.000000000 +0100
+@@ -0,0 +1,4 @@
++/* Public domain. */
++
++/* sysdep: +flock */
++#define HASFLOCK 1
+diff -ruN daemontools-0.76.orig/src/hasmkffo.h daemontools-0.76/src/hasmkffo.h
+--- daemontools-0.76.orig/src/hasmkffo.h	1970-01-01 01:00:00.000000000 +0100
++++ daemontools-0.76/src/hasmkffo.h	2011-01-08 12:59:40.000000000 +0100
+@@ -0,0 +1,4 @@
++/* Public domain. */
++
++/* sysdep: +mkfifo */
++#define HASMKFIFO 1
+diff -ruN daemontools-0.76.orig/src/hassgact.h daemontools-0.76/src/hassgact.h
+--- daemontools-0.76.orig/src/hassgact.h	1970-01-01 01:00:00.000000000 +0100
++++ daemontools-0.76/src/hassgact.h	2011-01-08 13:00:04.000000000 +0100
+@@ -0,0 +1,4 @@
++/* Public domain. */
++
++/* sysdep: +sigaction */
++#define HASSIGACTION 1
+diff -ruN daemontools-0.76.orig/src/hassgprm.h daemontools-0.76/src/hassgprm.h
+--- daemontools-0.76.orig/src/hassgprm.h	1970-01-01 01:00:00.000000000 +0100
++++ daemontools-0.76/src/hassgprm.h	2011-01-08 12:59:40.000000000 +0100
+@@ -0,0 +1,4 @@
++/* Public domain. */
++
++/* sysdep: +sigprocmask */
++#define HASSIGPROCMASK 1
+diff -ruN daemontools-0.76.orig/src/hasshsgr.h daemontools-0.76/src/hasshsgr.h
+--- daemontools-0.76.orig/src/hasshsgr.h	1970-01-01 01:00:00.000000000 +0100
++++ daemontools-0.76/src/hasshsgr.h	2011-01-08 12:59:40.000000000 +0100
+@@ -0,0 +1,3 @@
++/* Public domain. */
++
++/* sysdep: -shortsetgroups */
+diff -ruN daemontools-0.76.orig/src/haswaitp.h daemontools-0.76/src/haswaitp.h
+--- daemontools-0.76.orig/src/haswaitp.h	1970-01-01 01:00:00.000000000 +0100
++++ daemontools-0.76/src/haswaitp.h	2011-01-08 12:59:40.000000000 +0100
+@@ -0,0 +1,4 @@
++/* Public domain. */
++
++/* sysdep: +waitpid */
++#define HASWAITPID 1
+diff -ruN daemontools-0.76.orig/src/iopause.h daemontools-0.76/src/iopause.h
+--- daemontools-0.76.orig/src/iopause.h	1970-01-01 01:00:00.000000000 +0100
++++ daemontools-0.76/src/iopause.h	2011-01-08 12:59:40.000000000 +0100
+@@ -0,0 +1,20 @@
++/* Public domain. */
++
++#ifndef IOPAUSE_H
++#define IOPAUSE_H
++
++/* sysdep: +poll */
++#define IOPAUSE_POLL
++
++#include <sys/types.h>
++#include <poll.h>
++
++typedef struct pollfd iopause_fd;
++#define IOPAUSE_READ POLLIN
++#define IOPAUSE_WRITE POLLOUT
++
++#include "taia.h"
++
++extern void iopause(iopause_fd *,unsigned int,struct taia *,struct taia *);
++
++#endif
+diff -ruN daemontools-0.76.orig/src/Makefile daemontools-0.76/src/Makefile
+--- daemontools-0.76.orig/src/Makefile	2011-01-08 12:42:26.000000000 +0100
++++ daemontools-0.76/src/Makefile	2011-01-08 12:59:40.000000000 +0100
+@@ -151,29 +151,6 @@
+ fmt_ulong.o: compile fmt.h fmt_ulong.c
+ 	./compile fmt_ulong.c
+ 
+-hasflock.h: choose compile hasflock.h1 hasflock.h2 load tryflock.c
+-	./choose cl tryflock hasflock.h1 hasflock.h2 > hasflock.h
+-
+-hasmkffo.h: choose compile hasmkffo.h1 hasmkffo.h2 load trymkffo.c
+-	./choose cl trymkffo hasmkffo.h1 hasmkffo.h2 > hasmkffo.h
+-
+-hassgact.h: choose compile hassgact.h1 hassgact.h2 load trysgact.c
+-	./choose cl trysgact hassgact.h1 hassgact.h2 > hassgact.h
+-
+-hassgprm.h: choose compile hassgprm.h1 hassgprm.h2 load trysgprm.c
+-	./choose cl trysgprm hassgprm.h1 hassgprm.h2 > hassgprm.h
+-
+-hasshsgr.h: chkshsgr choose compile hasshsgr.h1 hasshsgr.h2 load \
+-tryshsgr.c warn-shsgr
+-	./chkshsgr || ( cat warn-shsgr; exit 1 )
+-	./choose clr tryshsgr hasshsgr.h1 hasshsgr.h2 > hasshsgr.h
+-
+-haswaitp.h: choose compile haswaitp.h1 haswaitp.h2 load trywaitp.c
+-	./choose cl trywaitp haswaitp.h1 haswaitp.h2 > haswaitp.h
+-
+-iopause.h: choose compile iopause.h1 iopause.h2 load trypoll.c
+-	./choose clr trypoll iopause.h1 iopause.h2 > iopause.h
+-
+ iopause.o: compile iopause.c iopause.h select.h tai.h taia.h uint64.h
+ 	./compile iopause.c
+ 
+@@ -265,7 +242,6 @@
+ rts: envdir envuidgid fghack matchtest multilog pgrphack \
+ readproctitle rts.tests setlock setuidgid softlimit supervise svc \
+ svok svscan svscanboot svstat tai64n tai64nlocal
+-	env - /bin/sh rts.tests 2>&1 | cat -v > rts
+ 
+ scan_ulong.o: compile scan.h scan_ulong.c
+ 	./compile scan_ulong.c
+@@ -478,9 +454,6 @@
+ timestamp.o: compile tai.h taia.h timestamp.c timestamp.h uint64.h
+ 	./compile timestamp.c
+ 
+-uint64.h: choose compile load tryulong64.c uint64.h1 uint64.h2
+-	./choose clr tryulong64 uint64.h1 uint64.h2 > uint64.h
+-
+ unix.a: alloc.o alloc_re.o buffer.o buffer_0.o buffer_1.o buffer_2.o \
+ buffer_get.o buffer_put.o buffer_read.o buffer_write.o coe.o env.o \
+ error.o error_str.o fd_copy.o fd_move.o fifo.o lock_ex.o lock_exnb.o \
+diff -ruN daemontools-0.76.orig/src/uint64.h daemontools-0.76/src/uint64.h
+--- daemontools-0.76.orig/src/uint64.h	1970-01-01 01:00:00.000000000 +0100
++++ daemontools-0.76/src/uint64.h	2011-01-08 12:59:40.000000000 +0100
+@@ -0,0 +1,11 @@
++/* Public domain. */
++
++#ifndef UINT64_H
++#define UINT64_H
++#include <stdint.h>
++
++/* sysdep: -ulong64 */
++
++typedef uint64_t uint64;
++
++#endif
diff --git a/package/daemontools/daemontools.mk b/package/daemontools/daemontools.mk
new file mode 100644
index 0000000..15e7961
--- /dev/null
+++ b/package/daemontools/daemontools.mk
@@ -0,0 +1,38 @@
+#############################################################
+#
+# daemontools
+#
+#############################################################
+
+DAEMONTOOLS_VERSION = 0.76
+DAEMONTOOLS_SOURCE = daemontools-$(DAEMONTOOLS_VERSION).tar.gz
+DAEMONTOOLS_SITE = http://cr.yp.to/daemontools
+
+DAEMONTOOLS_TARGET_BINS= envdir envuidgid fghack multilog pgrphack \
+	readproctitle setlock setuidgid softlimit supervise svc svok \
+	svscan svscanboot svstat tai64n tai64nlocal
+
+define DAEMONTOOLS_POST_EXTRACT_DIR_FIX
+	mv $(@D)/daemontools-$(DAEMONTOOLS_VERSION)/* $(@D)/
+endef
+
+DAEMONTOOLS_POST_EXTRACT_HOOKS+= DAEMONTOOLS_POST_EXTRACT_DIR_FIX
+
+define DAEMONTOOLS_BUILD_CMDS
+	echo '$(TARGET_CC) $(TARGET_CFLAGS)' > $(@D)/src/conf-cc
+	echo '$(TARGET_CC) -s $(TARGET_LDFLAGS)' > $(@D)/src/conf-ld
+	(cd $(@D) && $(@D)/package/compile)
+	$(SED) 's}/command/svc}svc};s}/service}/etc/service}g' \
+		$(@D)/command/svscanboot
+endef
+
+define DAEMONTOOLS_INSTALL_TARGET_CMDS
+	$(INSTALL) -D -m 0755 $(addprefix $(@D)/command/, $(DAEMONTOOLS_TARGET_BINS)) \
+		$(TARGET_DIR)/usr/bin
+endef
+
+define DAEMONTOOLS_UNINSTALL_TARGET_CMDS
+	rm -f $(addprefix $(TARGET_DIR)/usr/bin/, $(DAEMONTOOLS_TARGET_BINS))
+endef
+
+$(eval $(call GENTARGETS,package,daemontools))
diff --git a/package/djbdns/Config.in b/package/djbdns/Config.in
new file mode 100644
index 0000000..71afb46
--- /dev/null
+++ b/package/djbdns/Config.in
@@ -0,0 +1,20 @@
+config BR2_PACKAGE_DJBDNS
+	bool "djbdns"
+	select BR2_PACKAGE_UCSPI_TCP
+	help
+		djbdns is a collection of Domain Name System tools.
+			It includes software for all the fundamental DNS operations: 
+		* DNS server: publishing addresses of Internet hosts.
+		* DNS cache: finding addresses of Internet hosts.
+		* DNS client: talking to a DNS cache.
+				
+		Also included is a DNS client C library, several command-line
+			DNS client utilities, several DNS debugging tools.
+		
+		http://cr.yp.to/djbdns.html
+
+config BR2_PACKAGE_DJBDNS_DAEMONTOOLS
+	bool "manage djbdns services with daemontools"
+	default y
+	select BR2_PACKAGE_DAEMONTOOLS
+	depends on BR2_PACKAGE_DJBDNS
diff --git a/package/djbdns/djbdns-01-fefe-test23-ipv6.patch b/package/djbdns/djbdns-01-fefe-test23-ipv6.patch
new file mode 100644
index 0000000..c9226a1
--- /dev/null
+++ b/package/djbdns/djbdns-01-fefe-test23-ipv6.patch
@@ -0,0 +1,3502 @@
+diff -uNr djbdns-1.05/FILES djbdns-1.05-ipv6/FILES
+--- djbdns-1.05/FILES	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/FILES	2005-09-08 21:58:08.166381250 +0200
+@@ -135,6 +135,7 @@
+ exit.h
+ fmt.h
+ fmt_ulong.c
++fmt_xlong.c
+ gen_alloc.h
+ gen_allocdefs.h
+ getln.c
+@@ -151,6 +152,9 @@
+ ip4.h
+ ip4_fmt.c
+ ip4_scan.c
++ip6.h
++ip6_fmt.c
++ip6_scan.c
+ ndelay.h
+ ndelay_off.c
+ ndelay_on.c
+@@ -164,6 +168,7 @@
+ readclose.c
+ readclose.h
+ scan.h
++scan_0x.c
+ scan_ulong.c
+ seek.h
+ seek_set.c
+@@ -241,3 +246,9 @@
+ warn-shsgr
+ buffer_read.c
+ buffer_write.c
++dns_nd6.c
++socket_udp6.c
++socket_getifidx.c
++tryn2i.c
++haven2i.h1
++haven2i.h2
+diff -uNr djbdns-1.05/Makefile djbdns-1.05-ipv6/Makefile
+--- djbdns-1.05/Makefile	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/Makefile	2005-09-08 21:58:08.166381250 +0200
+@@ -120,12 +120,14 @@
+ case_diffb.o case_diffs.o case_lowerb.o fmt_ulong.o ip4_fmt.o \
+ ip4_scan.o scan_ulong.o str_chr.o str_diff.o str_len.o str_rchr.o \
+ str_start.o uint16_pack.o uint16_unpack.o uint32_pack.o \
+-uint32_unpack.o
++uint32_unpack.o ip6_fmt.o ip6_scan.o fmt_xlong.o \
++scan_xlong.o
+ 	./makelib byte.a byte_chr.o byte_copy.o byte_cr.o \
+ 	byte_diff.o byte_zero.o case_diffb.o case_diffs.o \
+ 	case_lowerb.o fmt_ulong.o ip4_fmt.o ip4_scan.o scan_ulong.o \
+ 	str_chr.o str_diff.o str_len.o str_rchr.o str_start.o \
+-	uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o
++	uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o \
++	ip6_fmt.o ip6_scan.o fmt_xlong.o scan_xlong.o
+ 
+ byte_chr.o: \
+ compile byte_chr.c byte.h
+@@ -228,11 +230,13 @@
+ dns.a: \
+ makelib dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o dns_ipq.o dns_mx.o \
+ dns_name.o dns_nd.o dns_packet.o dns_random.o dns_rcip.o dns_rcrw.o \
+-dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o
++dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o dns_ip6.o \
++dns_sortip6.o dns_nd6.o dns_ipq6.o
+ 	./makelib dns.a dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o \
+ 	dns_ipq.o dns_mx.o dns_name.o dns_nd.o dns_packet.o \
+ 	dns_random.o dns_rcip.o dns_rcrw.o dns_resolve.o \
+-	dns_sortip.o dns_transmit.o dns_txt.o
++	dns_sortip.o dns_transmit.o dns_txt.o dns_ip6.o dns_sortip6.o \
++	dns_nd6.o dns_ipq6.o
+ 
+ dns_dfd.o: \
+ compile dns_dfd.c error.h alloc.h byte.h dns.h stralloc.h gen_alloc.h \
+@@ -254,11 +258,21 @@
+ stralloc.h iopause.h taia.h tai.h uint64.h taia.h
+ 	./compile dns_ip.c
+ 
++dns_ip6.o: \
++compile dns_ip6.c stralloc.h gen_alloc.h uint16.h byte.h dns.h \
++stralloc.h iopause.h taia.h tai.h uint64.h taia.h
++	./compile dns_ip6.c
++
+ dns_ipq.o: \
+ compile dns_ipq.c stralloc.h gen_alloc.h case.h byte.h str.h dns.h \
+ stralloc.h iopause.h taia.h tai.h uint64.h taia.h
+ 	./compile dns_ipq.c
+ 
++dns_ipq6.o: \
++compile dns_ipq6.c stralloc.h gen_alloc.h case.h byte.h str.h dns.h \
++stralloc.h iopause.h taia.h tai.h uint64.h taia.h
++	./compile dns_ipq6.c
++
+ dns_mx.o: \
+ compile dns_mx.c stralloc.h gen_alloc.h byte.h uint16.h dns.h \
+ stralloc.h iopause.h taia.h tai.h uint64.h taia.h
+@@ -274,6 +288,11 @@
+ taia.h tai.h uint64.h taia.h
+ 	./compile dns_nd.c
+ 
++dns_nd6.o: \
++compile dns_nd6.c byte.h fmt.h dns.h stralloc.h gen_alloc.h iopause.h \
++taia.h tai.h uint64.h taia.h
++	./compile dns_nd6.c
++
+ dns_packet.o: \
+ compile dns_packet.c error.h dns.h stralloc.h gen_alloc.h iopause.h \
+ taia.h tai.h uint64.h taia.h
+@@ -306,6 +325,11 @@
+ taia.h tai.h uint64.h taia.h
+ 	./compile dns_sortip.c
+ 
++dns_sortip6.o: \
++compile dns_sortip6.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \
++taia.h tai.h uint64.h taia.h
++	./compile dns_sortip6.c
++
+ dns_transmit.o: \
+ compile dns_transmit.c socket.h uint16.h alloc.h error.h byte.h \
+ uint16.h dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h \
+@@ -369,6 +393,17 @@
+ gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h
+ 	./compile dnsip.c
+ 
++dnsip6: \
++load dnsip6.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \
++byte.a socket.lib
++	./load dnsip6 iopause.o dns.a env.a libtai.a alloc.a \
++	buffer.a unix.a byte.a  `cat socket.lib`
++
++dnsip6.o: \
++compile dnsip6.c buffer.h exit.h strerr.h ip6.h dns.h stralloc.h \
++gen_alloc.h iopause.h taia.h tai.h uint64.h
++	./compile dnsip6.c
++
+ dnsipq: \
+ load dnsipq.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \
+ byte.a socket.lib
+@@ -380,6 +415,17 @@
+ gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h
+ 	./compile dnsipq.c
+ 
++dnsip6q: \
++load dnsip6q.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \
++byte.a socket.lib
++	./load dnsip6q iopause.o dns.a env.a libtai.a alloc.a \
++	buffer.a unix.a byte.a  `cat socket.lib`
++
++dnsip6q.o: \
++compile dnsip6q.c buffer.h exit.h strerr.h ip4.h dns.h stralloc.h \
++gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h
++	./compile dnsip6q.c
++
+ dnsmx: \
+ load dnsmx.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \
+ byte.a socket.lib
+@@ -399,7 +445,7 @@
+ 
+ dnsname.o: \
+ compile dnsname.c buffer.h exit.h strerr.h ip4.h dns.h stralloc.h \
+-gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h
++gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h ip6.h
+ 	./compile dnsname.c
+ 
+ dnsq: \
+@@ -484,6 +530,10 @@
+ compile fmt_ulong.c fmt.h
+ 	./compile fmt_ulong.c
+ 
++fmt_xlong.o: \
++compile fmt_xlong.c scan.h
++	./compile fmt_xlong.c
++
+ generic-conf.o: \
+ compile generic-conf.c strerr.h buffer.h open.h generic-conf.h \
+ buffer.h
+@@ -546,10 +596,18 @@
+ compile ip4_fmt.c fmt.h ip4.h
+ 	./compile ip4_fmt.c
+ 
++ip6_fmt.o: \
++compile ip6_fmt.c fmt.h ip6.h
++	./compile ip6_fmt.c
++
+ ip4_scan.o: \
+ compile ip4_scan.c scan.h ip4.h
+ 	./compile ip4_scan.c
+ 
++ip6_scan.o: \
++compile ip6_scan.c scan.h ip6.h
++	./compile ip6_scan.c
++
+ it: \
+ prog install instcheck
+ 
+@@ -626,9 +684,9 @@
+ 	./compile parsetype.c
+ 
+ pickdns: \
+-load pickdns.o server.o response.o droproot.o qlog.o prot.o dns.a \
++load pickdns.o server.o iopause.o response.o droproot.o qlog.o prot.o dns.a \
+ env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib
+-	./load pickdns server.o response.o droproot.o qlog.o \
++	./load pickdns server.o iopause.o response.o droproot.o qlog.o \
+ 	prot.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \
+ 	byte.a  `cat socket.lib`
+ 
+@@ -677,7 +735,7 @@
+ rbldns-data pickdns-conf pickdns pickdns-data tinydns-conf tinydns \
+ tinydns-data tinydns-get tinydns-edit axfr-get axfrdns-conf axfrdns \
+ dnsip dnsipq dnsname dnstxt dnsmx dnsfilter random-ip dnsqr dnsq \
+-dnstrace dnstracesort cachetest utime rts
++dnstrace dnstracesort cachetest utime rts dnsip6 dnsip6q
+ 
+ prot.o: \
+ compile prot.c hasshsgr.h prot.h
+@@ -704,9 +762,9 @@
+ 	./compile random-ip.c
+ 
+ rbldns: \
+-load rbldns.o server.o response.o dd.o droproot.o qlog.o prot.o dns.a \
++load rbldns.o server.o iopause.o response.o dd.o droproot.o qlog.o prot.o dns.a \
+ env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib
+-	./load rbldns server.o response.o dd.o droproot.o qlog.o \
++	./load rbldns server.o iopause.o response.o dd.o droproot.o qlog.o \
+ 	prot.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \
+ 	byte.a  `cat socket.lib`
+ 
+@@ -762,6 +820,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_set.o: \
+ compile seek_set.c seek.h
+ 	./compile seek_set.c
+@@ -774,7 +836,7 @@
+ compile server.c byte.h case.h env.h buffer.h strerr.h ip4.h uint16.h \
+ ndelay.h socket.h uint16.h droproot.h qlog.h uint16.h response.h \
+ uint32.h dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h \
+-taia.h
++taia.h iopause.h alloc.h str.h
+ 	./compile server.c
+ 
+ setup: \
+@@ -796,14 +858,26 @@
+ compile socket_accept.c byte.h socket.h uint16.h
+ 	./compile socket_accept.c
+ 
++socket_accept6.o: \
++compile socket_accept6.c byte.h socket.h uint16.h
++	./compile socket_accept6.c
++
+ socket_bind.o: \
+ compile socket_bind.c byte.h socket.h uint16.h
+ 	./compile socket_bind.c
+ 
++socket_bind6.o: \
++compile socket_bind6.c sockaddr_in6.h haveip6.h byte.h socket.h uint16.h uint32.h ip6.h error.h
++	./compile socket_bind6.c
++
+ socket_conn.o: \
+ compile socket_conn.c byte.h socket.h uint16.h
+ 	./compile socket_conn.c
+ 
++socket_connect6.o: \
++compile socket_connect6.c byte.h socket.h uint16.h uint32.h
++	./compile socket_connect6.c
++
+ socket_listen.o: \
+ compile socket_listen.c socket.h uint16.h
+ 	./compile socket_listen.c
+@@ -812,18 +886,47 @@
+ compile socket_recv.c byte.h socket.h uint16.h
+ 	./compile socket_recv.c
+ 
++socket_recv6.o: \
++compile socket_recv6.c sockaddr_in6.h haveip6.h byte.h socket.h uint16.h uint32.h ip6.h error.h
++	./compile socket_recv6.c
++
+ socket_send.o: \
+ compile socket_send.c byte.h socket.h uint16.h
+ 	./compile socket_send.c
+ 
++socket_send6.o: \
++compile socket_send6.c byte.h socket.h uint16.h uint32.h ip6.h haveip6.h error.h
++	./compile socket_send6.c
++
+ socket_tcp.o: \
+ compile socket_tcp.c ndelay.h socket.h uint16.h
+ 	./compile socket_tcp.c
+ 
++socket_tcp6.o: \
++compile socket_tcp6.c ndelay.h socket.h uint16.h uint32.h haveip6.h
++	./compile socket_tcp6.c
++
+ socket_udp.o: \
+ compile socket_udp.c ndelay.h socket.h uint16.h
+ 	./compile socket_udp.c
+ 
++socket_udp6.o: \
++compile socket_udp6.c ndelay.h socket.h uint16.h uint32.h haveip6.h
++	./compile socket_udp6.c
++
++socket_noipv6.o: \
++compile socket_noipv6.c haveip6.h
++	./compile socket_noipv6.c
++
++socket_getifidx.o: \
++compile socket_getifidx.c socket.h uint16.h uint32.h haven2i.h
++	./compile socket_getifidx.c
++
++haven2i.h: \
++tryn2i.c choose compile load socket.lib haven2i.h1 haven2i.h2
++	cp /dev/null haven2i.h
++	./choose cL tryn2i haven2i.h1 haven2i.h2 socket > haven2i.h
++
+ str_chr.o: \
+ compile str_chr.c str.h
+ 	./compile str_chr.c
+@@ -965,7 +1068,7 @@
+ tdlookup.o: \
+ compile tdlookup.c uint16.h open.h tai.h uint64.h cdb.h uint32.h \
+ byte.h case.h dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h \
+-taia.h seek.h response.h uint32.h
++taia.h seek.h response.h uint32.h ip6.h
+ 	./compile tdlookup.c
+ 
+ timeoutread.o: \
+@@ -979,10 +1082,10 @@
+ 	./compile timeoutwrite.c
+ 
+ tinydns: \
+-load tinydns.o server.o droproot.o tdlookup.o response.o qlog.o \
++load tinydns.o server.o iopause.o droproot.o tdlookup.o response.o qlog.o \
+ prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a byte.a \
+ socket.lib
+-	./load tinydns server.o droproot.o tdlookup.o response.o \
++	./load tinydns server.o iopause.o droproot.o tdlookup.o response.o \
+ 	qlog.o prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a \
+ 	unix.a byte.a  `cat socket.lib`
+ 
+@@ -1005,7 +1108,7 @@
+ compile tinydns-data.c uint16.h uint32.h str.h byte.h fmt.h ip4.h \
+ exit.h case.h scan.h buffer.h strerr.h getln.h buffer.h stralloc.h \
+ gen_alloc.h cdb_make.h buffer.h uint32.h stralloc.h open.h dns.h \
+-stralloc.h iopause.h taia.h tai.h uint64.h taia.h
++stralloc.h iopause.h taia.h tai.h uint64.h taia.h ip6.h
+ 	./compile tinydns-data.c
+ 
+ tinydns-edit: \
+@@ -1068,12 +1171,18 @@
+ makelib buffer_read.o buffer_write.o error.o error_str.o ndelay_off.o \
+ ndelay_on.o open_read.o open_trunc.o openreadclose.o readclose.o \
+ seek_set.o socket_accept.o socket_bind.o socket_conn.o \
+-socket_listen.o socket_recv.o socket_send.o socket_tcp.o socket_udp.o
++socket_listen.o socket_recv.o socket_send.o socket_tcp.o socket_udp.o \
++socket_udp6.o socket_getifidx.o socket_recv6.o socket_send6.o \
++socket_bind6.o socket_noipv6.o socket_tcp6.o socket_connect6.o \
++socket_accept6.o
+ 	./makelib unix.a buffer_read.o buffer_write.o error.o \
+ 	error_str.o ndelay_off.o ndelay_on.o open_read.o \
+ 	open_trunc.o openreadclose.o readclose.o seek_set.o \
+ 	socket_accept.o socket_bind.o socket_conn.o socket_listen.o \
+-	socket_recv.o socket_send.o socket_tcp.o socket_udp.o
++	socket_recv.o socket_send.o socket_tcp.o socket_udp.o \
++	socket_udp6.o socket_getifidx.o socket_recv6.o socket_send6.o \
++	socket_bind6.o socket_noipv6.o socket_tcp6.o socket_connect6.o \
++	socket_accept6.o
+ 
+ utime: \
+ load utime.o byte.a
+@@ -1084,10 +1193,10 @@
+ 	./compile utime.c
+ 
+ walldns: \
+-load walldns.o server.o response.o droproot.o qlog.o prot.o dd.o \
++load walldns.o server.o iopause.o response.o droproot.o qlog.o prot.o dd.o \
+ dns.a env.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib
+-	./load walldns server.o response.o droproot.o qlog.o \
+-	prot.o dd.o dns.a env.a cdb.a alloc.a buffer.a unix.a \
++	./load walldns server.o iopause.o response.o droproot.o qlog.o \
++	prot.o dd.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a \
+ 	byte.a  `cat socket.lib`
+ 
+ walldns-conf: \
+@@ -1104,3 +1213,14 @@
+ compile walldns.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \
+ taia.h tai.h uint64.h taia.h dd.h response.h uint32.h
+ 	./compile walldns.c
++
++haveip6.h: \
++tryip6.c choose compile haveip6.h1 haveip6.h2
++	./choose c tryip6 haveip6.h1 haveip6.h2 > haveip6.h
++
++sockaddr_in6.h: \
++trysa6.c choose compile sockaddr_in6.h1 sockaddr_in6.h2 haveip6.h
++	./choose c trysa6 sockaddr_in6.h1 sockaddr_in6.h2 > sockaddr_in6.h
++
++clean:
++	rm -f `cat TARGETS`
+diff -uNr djbdns-1.05/TARGETS djbdns-1.05-ipv6/TARGETS
+--- djbdns-1.05/TARGETS	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/TARGETS	2005-09-08 21:58:08.170381500 +0200
+@@ -102,6 +102,7 @@
+ dns_dtda.o
+ dns_ip.o
+ dns_ipq.o
++dns_ipq6.o
+ dns_mx.o
+ dns_name.o
+ dns_nd.o
+@@ -180,6 +181,8 @@
+ dnsip
+ dnsipq.o
+ dnsipq
++dnsip6q.o
++dnsip6q
+ dnsname.o
+ dnsname
+ dnstxt.o
+@@ -214,3 +217,25 @@
+ it
+ setup
+ check
++scan_0x.o
++fmt_xlong.o
++ip6_scan.o
++ip6_fmt.o
++dnsip6.o
++dns_ip6.o
++dns_sortip6.o
++dnsip6
++dns_nd6.o
++socket_udp6.o
++socket_getifidx.o
++socket_bind6.o
++socket_noipv6.o
++socket_recv6.o
++socket_send6.o
++haveip6.h
++haven2i.h
++sockaddr_in6.h
++scan_xlong.o
++socket_accept6.o
++socket_connect6.o
++socket_tcp6.o
+diff -uNr djbdns-1.05/axfr-get.c djbdns-1.05-ipv6/axfr-get.c
+--- djbdns-1.05/axfr-get.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/axfr-get.c	2005-09-08 21:58:08.170381500 +0200
+@@ -13,6 +13,7 @@
+ #include "byte.h"
+ #include "str.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "timeoutread.h"
+ #include "timeoutwrite.h"
+ #include "dns.h"
+@@ -217,6 +218,14 @@
+     x_copy(buf,len,pos,data,4);
+     if (!stralloc_catb(&line,ipstr,ip4_fmt(ipstr,data))) return 0;
+   }
++  else if (byte_equal(data,2,DNS_T_AAAA)) {
++    char ipstr[IP6_FMT];
++    if (!stralloc_copys(&line,"3")) return 0;
++    if (!dns_domain_todot_cat(&line,d1)) return 0;
++    if (!stralloc_cats(&line,":")) return 0;
++    x_copy(buf,len,pos,data,16);
++    if (!stralloc_catb(&line,ipstr,ip6_fmt_flat(ipstr,data))) return 0;
++  }
+   else {
+     unsigned char ch;
+     unsigned char ch2;
+diff -uNr djbdns-1.05/dns.h djbdns-1.05-ipv6/dns.h
+--- djbdns-1.05/dns.h	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/dns.h	2005-09-08 21:58:08.174381750 +0200
+@@ -35,7 +35,8 @@
+   struct taia deadline;
+   unsigned int pos;
+   const char *servers;
+-  char localip[4];
++  char localip[16];
++  unsigned int scope_id;
+   char qtype[2];
+ } ;
+ 
+@@ -43,6 +44,7 @@
+ extern unsigned int dns_random(unsigned int);
+ 
+ extern void dns_sortip(char *,unsigned int);
++extern void dns_sortip6(char *,unsigned int);
+ 
+ extern void dns_domain_free(char **);
+ extern int dns_domain_copy(char **,const char *);
+@@ -68,10 +70,13 @@
+ 
+ extern int dns_ip4_packet(stralloc *,const char *,unsigned int);
+ extern int dns_ip4(stralloc *,const stralloc *);
++extern int dns_ip6_packet(stralloc *,char *,unsigned int);
++extern int dns_ip6(stralloc *,stralloc *);
+ extern int dns_name_packet(stralloc *,const char *,unsigned int);
+ extern void dns_name4_domain(char *,const char *);
+ #define DNS_NAME4_DOMAIN 31
+ extern int dns_name4(stralloc *,const char *);
++extern int dns_name6(stralloc *,const char *);
+ extern int dns_txt_packet(stralloc *,const char *,unsigned int);
+ extern int dns_txt(stralloc *,const stralloc *);
+ extern int dns_mx_packet(stralloc *,const char *,unsigned int);
+@@ -80,5 +85,13 @@
+ extern int dns_resolvconfrewrite(stralloc *);
+ extern int dns_ip4_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *);
+ extern int dns_ip4_qualify(stralloc *,stralloc *,const stralloc *);
++extern int dns_ip6_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *);
++extern int dns_ip6_qualify(stralloc *,stralloc *,const stralloc *);
++
++#define DNS_IP6_INT 0
++#define DNS_IP6_ARPA 1
++
++extern int dns_name6_domain(char *,const char *,int);
++#define DNS_NAME6_DOMAIN (4*16+11)
+ 
+ #endif
+diff -uNr djbdns-1.05/dns_ip6.c djbdns-1.05-ipv6/dns_ip6.c
+--- djbdns-1.05/dns_ip6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/dns_ip6.c	2005-09-08 21:58:08.174381750 +0200
+@@ -0,0 +1,103 @@
++#include "stralloc.h"
++#include "uint16.h"
++#include "byte.h"
++#include "dns.h"
++#include "ip4.h"
++#include "ip6.h"
++
++static int dns_ip6_packet_add(stralloc *out,char *buf,unsigned int len)
++{
++  unsigned int pos;
++  char header[16];
++  uint16 numanswers;
++  uint16 datalen;
++
++  pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1;
++  uint16_unpack_big(header + 6,&numanswers);
++  pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
++  pos += 4;
++
++  while (numanswers--) {
++    pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
++    pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1;
++    uint16_unpack_big(header + 8,&datalen);
++    if (byte_equal(header,2,DNS_T_AAAA)) {
++      if (byte_equal(header + 2,2,DNS_C_IN))
++        if (datalen == 16) {
++	  if (!dns_packet_copy(buf,len,pos,header,16)) return -1;
++	  if (!stralloc_catb(out,header,16)) return -1;
++	}
++    } else if (byte_equal(header,2,DNS_T_A))
++      if (byte_equal(header + 2,2,DNS_C_IN))
++        if (datalen == 4) {
++	  byte_copy(header,12,V4mappedprefix);
++	  if (!dns_packet_copy(buf,len,pos,header+12,4)) return -1;
++	  if (!stralloc_catb(out,header,16)) return -1;
++	}
++    pos += datalen;
++  }
++
++  dns_sortip6(out->s,out->len);
++  return 0;
++}
++
++int dns_ip6_packet(stralloc *out,char *buf,unsigned int len) {
++  if (!stralloc_copys(out,"")) return -1;
++  return dns_ip6_packet_add(out,buf,len);
++}
++
++static char *q = 0;
++
++int dns_ip6(stralloc *out,stralloc *fqdn)
++{
++  unsigned int i;
++  char code;
++  char ch;
++  char ip[16];
++
++  if (!stralloc_copys(out,"")) return -1;
++  if (!stralloc_readyplus(fqdn,1)) return -1;
++  fqdn->s[fqdn->len]=0;
++  if ((i=ip6_scan(fqdn->s,ip))) {
++    if (fqdn->s[i]) return -1;
++    stralloc_copyb(out,ip,16);
++    return 0;
++  }
++  code = 0;
++  for (i = 0;i <= fqdn->len;++i) {
++    if (i < fqdn->len)
++      ch = fqdn->s[i];
++    else
++      ch = '.';
++
++    if ((ch == '[') || (ch == ']')) continue;
++    if (ch == '.') {
++      if (!stralloc_append(out,&code)) return -1;
++      code = 0;
++      continue;
++    }
++    if ((ch >= '0') && (ch <= '9')) {
++      code *= 10;
++      code += ch - '0';
++      continue;
++    }
++
++    if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
++    if (!stralloc_copys(out,"")) return -1;
++    if (dns_resolve(q,DNS_T_AAAA) != -1)
++      if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) {
++	dns_transmit_free(&dns_resolve_tx);
++	dns_domain_free(&q);
++      }
++    if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
++    if (dns_resolve(q,DNS_T_A) != -1)
++      if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) {
++	dns_transmit_free(&dns_resolve_tx);
++	dns_domain_free(&q);
++      }
++    return out->a>0?0:-1;
++  }
++
++  out->len &= ~3;
++  return 0;
++}
+diff -uNr djbdns-1.05/dns_ipq6.c djbdns-1.05-ipv6/dns_ipq6.c
+--- djbdns-1.05/dns_ipq6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/dns_ipq6.c	2005-09-08 21:58:08.178382000 +0200
+@@ -0,0 +1,72 @@
++#include "stralloc.h"
++#include "case.h"
++#include "byte.h"
++#include "str.h"
++#include "dns.h"
++
++static int doit(stralloc *work,const char *rule)
++{
++  char ch;
++  unsigned int colon;
++  unsigned int prefixlen;
++
++  ch = *rule++;
++  if ((ch != '?') && (ch != '=') && (ch != '*') && (ch != '-')) return 1;
++  colon = str_chr(rule,':');
++  if (!rule[colon]) return 1;
++
++  if (work->len < colon) return 1;
++  prefixlen = work->len - colon;
++  if ((ch == '=') && prefixlen) return 1;
++  if (case_diffb(rule,colon,work->s + prefixlen)) return 1;
++  if (ch == '?') {
++    if (byte_chr(work->s,prefixlen,'.') < prefixlen) return 1;
++    if (byte_chr(work->s,prefixlen,':') < prefixlen) return 1;
++    if (byte_chr(work->s,prefixlen,'[') < prefixlen) return 1;
++    if (byte_chr(work->s,prefixlen,']') < prefixlen) return 1;
++  }
++
++  work->len = prefixlen;
++  if (ch == '-') work->len = 0;
++  return stralloc_cats(work,rule + colon + 1);
++}
++
++int dns_ip6_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules)
++{
++  unsigned int i;
++  unsigned int j;
++  unsigned int plus;
++  unsigned int fqdnlen;
++
++  if (!stralloc_copy(fqdn,in)) return -1;
++
++  for (j = i = 0;j < rules->len;++j)
++    if (!rules->s[j]) {
++      if (!doit(fqdn,rules->s + i)) return -1;
++      i = j + 1;
++    }
++
++  fqdnlen = fqdn->len;
++  plus = byte_chr(fqdn->s,fqdnlen,'+');
++  if (plus >= fqdnlen)
++    return dns_ip6(out,fqdn);
++
++  i = plus + 1;
++  for (;;) {
++    j = byte_chr(fqdn->s + i,fqdnlen - i,'+');
++    byte_copy(fqdn->s + plus,j,fqdn->s + i);
++    fqdn->len = plus + j;
++    if (dns_ip6(out,fqdn) == -1) return -1;
++    if (out->len) return 0;
++    i += j;
++    if (i >= fqdnlen) return 0;
++    ++i;
++  }
++}
++
++int dns_ip6_qualify(stralloc *out,stralloc *fqdn,const stralloc *in)
++{
++  static stralloc rules;
++  if (dns_resolvconfrewrite(&rules) == -1) return -1;
++  return dns_ip6_qualify_rules(out,fqdn,in,&rules);
++}
+diff -uNr djbdns-1.05/dns_name.c djbdns-1.05-ipv6/dns_name.c
+--- djbdns-1.05/dns_name.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/dns_name.c	2005-09-08 21:58:08.178382000 +0200
+@@ -2,6 +2,7 @@
+ #include "uint16.h"
+ #include "byte.h"
+ #include "dns.h"
++#include "ip6.h"
+ 
+ static char *q = 0;
+ 
+@@ -46,3 +47,24 @@
+   dns_domain_free(&q);
+   return 0;
+ }
++
++int dns_name6_inner(stralloc *out,const char ip[16],int t)
++{
++  char name[DNS_NAME6_DOMAIN];
++
++  dns_name6_domain(name,ip,t);
++  if (dns_resolve(name,DNS_T_PTR) == -1) return -1;
++  if (dns_name_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1;
++  dns_transmit_free(&dns_resolve_tx);
++  dns_domain_free(&q);
++  return 0;
++}
++
++int dns_name6(stralloc *out,const char ip[16])
++{
++  if (ip6_isv4mapped(ip))
++    return dns_name4(out,ip+12);
++  if (dns_name6_inner(out,ip,DNS_IP6_ARPA)) return -1;
++  if (!out->len) return dns_name6_inner(out,ip,DNS_IP6_INT);
++  return 0;
++}
+diff -uNr djbdns-1.05/dns_nd6.c djbdns-1.05-ipv6/dns_nd6.c
+--- djbdns-1.05/dns_nd6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/dns_nd6.c	2005-09-08 21:58:08.178382000 +0200
+@@ -0,0 +1,35 @@
++#include "byte.h"
++#include "fmt.h"
++#include "dns.h"
++
++/* RFC1886:
++ *   4321:0:1:2:3:4:567:89ab
++ * ->
++ *   b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.INT.
++ *   b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.ARPA.
++ */
++
++extern char tohex(char num);
++
++unsigned int mkint(unsigned char a,unsigned char b) {
++  return ((unsigned int)a << 8) + (unsigned int)b;
++}
++
++int dns_name6_domain(char name[DNS_NAME6_DOMAIN],const char ip[16],int t)
++{
++  unsigned int j;
++
++  for (j=0; j<16; j++) {
++    name[j*4]=1;
++    name[j*4+1]=tohex(ip[15-j] & 15);
++    name[j*4+2]=1;
++    name[j*4+3]=tohex((unsigned char)ip[15-j] >> 4);
++  }
++  if (t==DNS_IP6_INT)
++    byte_copy(name + 4*16,9,"\3ip6\3int\0");
++  else if (t==DNS_IP6_ARPA)
++    byte_copy(name + 4*16,10,"\3ip6\4arpa\0");
++  else return 0;
++  return 4*16+9+t;
++}
++
+diff -uNr djbdns-1.05/dns_rcip.c djbdns-1.05-ipv6/dns_rcip.c
+--- djbdns-1.05/dns_rcip.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/dns_rcip.c	2005-09-08 21:58:08.182382250 +0200
+@@ -2,12 +2,13 @@
+ #include "openreadclose.h"
+ #include "byte.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "env.h"
+ #include "dns.h"
+ 
+ static stralloc data = {0};
+ 
+-static int init(char ip[64])
++static int init(char ip[256])
+ {
+   int i;
+   int j;
+@@ -20,10 +21,10 @@
+       if (*x == '.')
+ 	++x;
+       else {
+-        i = ip4_scan(x,ip + iplen);
++        i = ip6_scan(x,ip + iplen);
+ 	if (!i) break;
+ 	x += i;
+-	iplen += 4;
++	iplen += 16;
+       }
+     }
+ 
+@@ -40,10 +41,8 @@
+             while ((data.s[i] == ' ') || (data.s[i] == '\t'))
+               ++i;
+             if (iplen <= 60)
+-              if (ip4_scan(data.s + i,ip + iplen)) {
+-		if (byte_equal(ip + iplen,4,"\0\0\0\0"))
+-		  byte_copy(ip + iplen,4,"\177\0\0\1");
+-                iplen += 4;
++              if (ip6_scan(data.s + i,ip + iplen)) {
++                iplen += 16;
+ 	      }
+           }
+           i = j + 1;
+@@ -52,19 +51,19 @@
+   }
+ 
+   if (!iplen) {
+-    byte_copy(ip,4,"\177\0\0\1");
+-    iplen = 4;
++    byte_copy(ip,16,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1");
++    iplen = 16;
+   }
+-  byte_zero(ip + iplen,64 - iplen);
++  byte_zero(ip + iplen,256 - iplen);
+   return 0;
+ }
+ 
+ static int ok = 0;
+ static unsigned int uses;
+ static struct taia deadline;
+-static char ip[64]; /* defined if ok */
++static char ip[256]; /* defined if ok */
+ 
+-int dns_resolvconfip(char s[64])
++int dns_resolvconfip(char s[256])
+ {
+   struct taia now;
+ 
+@@ -81,6 +80,6 @@
+   }
+ 
+   --uses;
+-  byte_copy(s,64,ip);
++  byte_copy(s,256,ip);
+   return 0;
+ }
+diff -uNr djbdns-1.05/dns_resolve.c djbdns-1.05-ipv6/dns_resolve.c
+--- djbdns-1.05/dns_resolve.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/dns_resolve.c	2005-09-08 21:58:08.182382250 +0200
+@@ -2,6 +2,7 @@
+ #include "taia.h"
+ #include "byte.h"
+ #include "dns.h"
++#include "ip6.h"
+ 
+ struct dns_transmit dns_resolve_tx = {0};
+ 
+@@ -9,12 +10,12 @@
+ {
+   struct taia stamp;
+   struct taia deadline;
+-  char servers[64];
++  char servers[256];
+   iopause_fd x[1];
+   int r;
+ 
+   if (dns_resolvconfip(servers) == -1) return -1;
+-  if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,"\0\0\0\0") == -1) return -1;
++  if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,V6any) == -1) return -1;
+ 
+   for (;;) {
+     taia_now(&stamp);
+diff -uNr djbdns-1.05/dns_sortip6.c djbdns-1.05-ipv6/dns_sortip6.c
+--- djbdns-1.05/dns_sortip6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/dns_sortip6.c	2005-09-08 21:58:08.186382500 +0200
+@@ -0,0 +1,20 @@
++#include "byte.h"
++#include "dns.h"
++
++/* XXX: sort servers by configurable notion of closeness? */
++/* XXX: pay attention to competence of each server? */
++
++void dns_sortip6(char *s,unsigned int n)
++{
++  unsigned int i;
++  char tmp[16];
++
++  n >>= 4;
++  while (n > 1) {
++    i = dns_random(n);
++    --n;
++    byte_copy(tmp,16,s + (i << 4));
++    byte_copy(s + (i << 4),16,s + (n << 4));
++    byte_copy(s + (n << 4),16,tmp);
++  }
++}
+diff -uNr djbdns-1.05/dns_transmit.c djbdns-1.05-ipv6/dns_transmit.c
+--- djbdns-1.05/dns_transmit.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/dns_transmit.c	2005-09-08 21:58:08.186382500 +0200
+@@ -7,6 +7,7 @@
+ #include "byte.h"
+ #include "uint16.h"
+ #include "dns.h"
++#include "ip6.h"
+ 
+ static int serverwantstcp(const char *buf,unsigned int len)
+ {
+@@ -85,9 +86,9 @@
+   int j;
+ 
+   for (j = 0;j < 10;++j)
+-    if (socket_bind4(d->s1 - 1,d->localip,1025 + dns_random(64510)) == 0)
++    if (socket_bind6(d->s1 - 1,d->localip,1025 + dns_random(64510),d->scope_id) == 0)
+       return 0;
+-  if (socket_bind4(d->s1 - 1,d->localip,0) == 0)
++  if (socket_bind6(d->s1 - 1,d->localip,0,d->scope_id) == 0)
+     return 0;
+   return -1;
+ }
+@@ -102,16 +103,16 @@
+ 
+   while (d->udploop < 4) {
+     for (;d->curserver < 16;++d->curserver) {
+-      ip = d->servers + 4 * d->curserver;
+-      if (byte_diff(ip,4,"\0\0\0\0")) {
++      ip = d->servers + 16 * d->curserver;
++      if (byte_diff(ip,16,V6any)) {
+ 	d->query[2] = dns_random(256);
+ 	d->query[3] = dns_random(256);
+   
+-        d->s1 = 1 + socket_udp();
++        d->s1 = 1 + socket_udp6();
+         if (!d->s1) { dns_transmit_free(d); return -1; }
+ 	if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
+ 
+-        if (socket_connect4(d->s1 - 1,ip,53) == 0)
++        if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0)
+           if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) {
+             struct taia now;
+             taia_now(&now);
+@@ -153,19 +154,19 @@
+   packetfree(d);
+ 
+   for (;d->curserver < 16;++d->curserver) {
+-    ip = d->servers + 4 * d->curserver;
+-    if (byte_diff(ip,4,"\0\0\0\0")) {
++    ip = d->servers + 16 * d->curserver;
++    if (byte_diff(ip,16,V6any)) {
+       d->query[2] = dns_random(256);
+       d->query[3] = dns_random(256);
+ 
+-      d->s1 = 1 + socket_tcp();
++      d->s1 = 1 + socket_tcp6();
+       if (!d->s1) { dns_transmit_free(d); return -1; }
+       if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
+   
+       taia_now(&now);
+       taia_uint(&d->deadline,10);
+       taia_add(&d->deadline,&d->deadline,&now);
+-      if (socket_connect4(d->s1 - 1,ip,53) == 0) {
++      if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0) {
+         d->tcpstate = 2;
+         return 0;
+       }
+@@ -193,7 +194,7 @@
+   return thistcp(d);
+ }
+ 
+-int dns_transmit_start(struct dns_transmit *d,const char servers[64],int flagrecursive,const char *q,const char qtype[2],const char localip[4])
++int dns_transmit_start(struct dns_transmit *d,const char servers[256],int flagrecursive,const char *q,const char qtype[2],const char localip[16])
+ {
+   unsigned int len;
+ 
+@@ -213,7 +214,7 @@
+ 
+   byte_copy(d->qtype,2,qtype);
+   d->servers = servers;
+-  byte_copy(d->localip,4,localip);
++  byte_copy(d->localip,16,localip);
+ 
+   d->udploop = flagrecursive ? 1 : 0;
+ 
+diff -uNr djbdns-1.05/dnscache.c djbdns-1.05-ipv6/dnscache.c
+--- djbdns-1.05/dnscache.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/dnscache.c	2005-09-08 21:58:08.190382750 +0200
+@@ -5,6 +5,7 @@
+ #include "strerr.h"
+ #include "error.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "uint16.h"
+ #include "uint64.h"
+ #include "socket.h"
+@@ -23,6 +24,10 @@
+ #include "okclient.h"
+ #include "droproot.h"
+ 
++long interface;
++
++stralloc ignoreip = {0};
++
+ static int packetquery(char *buf,unsigned int len,char **q,char qtype[2],char qclass[2],char id[2])
+ {
+   unsigned int pos;
+@@ -46,8 +51,8 @@
+ }
+ 
+ 
+-static char myipoutgoing[4];
+-static char myipincoming[4];
++static char myipoutgoing[16];
++static char myipincoming[16];
+ static char buf[1024];
+ uint64 numqueries = 0;
+ 
+@@ -60,9 +65,10 @@
+   struct taia start;
+   uint64 active; /* query number, if active; otherwise 0 */
+   iopause_fd *io;
+-  char ip[4];
++  char ip[16];
+   uint16 port;
+   char id[2];
++  uint32 scope_id;
+ } u[MAXUDP];
+ int uactive = 0;
+ 
+@@ -78,7 +84,7 @@
+   if (!u[j].active) return;
+   response_id(u[j].id);
+   if (response_len > 512) response_tc();
+-  socket_send4(udp53,response,response_len,u[j].ip,u[j].port);
++  socket_send6(udp53,response,response_len,u[j].ip,u[j].port,u[j].scope_id);
+   log_querydone(&u[j].active,response_len);
+   u[j].active = 0; --uactive;
+ }
+@@ -109,7 +115,7 @@
+   x = u + j;
+   taia_now(&x->start);
+ 
+-  len = socket_recv4(udp53,buf,sizeof buf,x->ip,&x->port);
++  len = socket_recv6(udp53,buf,sizeof buf,x->ip,&x->port,&x->scope_id);
+   if (len == -1) return;
+   if (len >= sizeof buf) return;
+   if (x->port < 1024) if (x->port != 53) return;
+@@ -119,7 +125,7 @@
+ 
+   x->active = ++numqueries; ++uactive;
+   log_query(&x->active,x->ip,x->port,x->id,q,qtype);
+-  switch(query_start(&x->q,q,qtype,qclass,myipoutgoing)) {
++  switch(query_start(&x->q,q,qtype,qclass,myipoutgoing,interface)) {
+     case -1:
+       u_drop(j);
+       return;
+@@ -128,7 +134,6 @@
+   }
+ }
+ 
+-
+ static int tcp53;
+ 
+ #define MAXTCP 20
+@@ -138,7 +143,7 @@
+   struct taia timeout;
+   uint64 active; /* query number or 1, if active; otherwise 0 */
+   iopause_fd *io;
+-  char ip[4]; /* send response to this address */
++  char ip[16]; /* send response to this address */
+   uint16 port; /* send response to this port */
+   char id[2];
+   int tcp; /* open TCP socket, if active */
+@@ -146,6 +151,7 @@
+   char *buf; /* 0, or dynamically allocated of length len */
+   unsigned int len;
+   unsigned int pos;
++  uint32 scope_id;
+ } t[MAXTCP];
+ int tactive = 0;
+ 
+@@ -254,7 +260,7 @@
+ 
+   x->active = ++numqueries;
+   log_query(&x->active,x->ip,x->port,x->id,q,qtype);
+-  switch(query_start(&x->q,q,qtype,qclass,myipoutgoing)) {
++  switch(query_start(&x->q,q,qtype,qclass,myipoutgoing,interface)) {
+     case -1:
+       t_drop(j);
+       return;
+@@ -291,7 +297,7 @@
+   x = t + j;
+   taia_now(&x->start);
+ 
+-  x->tcp = socket_accept4(tcp53,x->ip,&x->port);
++  x->tcp = socket_accept6(tcp53,x->ip,&x->port,&x->scope_id);
+   if (x->tcp == -1) return;
+   if (x->port < 1024) if (x->port != 53) { close(x->tcp); return; }
+   if (!okclient(x->ip)) { close(x->tcp); return; }
+@@ -389,24 +395,36 @@
+ int main()
+ {
+   char *x;
++  unsigned int i, j, k;
+   unsigned long cachesize;
++  static stralloc sa = {0};
++
++  x = env_get("INTERFACE");
++  if (x) scan_ulong(x,&interface);
+ 
+   x = env_get("IP");
+   if (!x)
+     strerr_die2x(111,FATAL,"$IP not set");
+-  if (!ip4_scan(x,myipincoming))
++  if (!ip6_scan(x,myipincoming))
+     strerr_die3x(111,FATAL,"unable to parse IP address ",x);
+ 
+-  udp53 = socket_udp();
++#if 0
++  /* if if IP is a mapped-IPv4 address, disable IPv6 functionality */
++  /* this is actually a bad idea */
++  if (ip6_isv4mapped(myipincoming))
++    noipv6 = 1;
++#endif
++
++  udp53 = socket_udp6();
+   if (udp53 == -1)
+     strerr_die2sys(111,FATAL,"unable to create UDP socket: ");
+-  if (socket_bind4_reuse(udp53,myipincoming,53) == -1)
++  if (socket_bind6_reuse(udp53,myipincoming,53,interface) == -1)
+     strerr_die2sys(111,FATAL,"unable to bind UDP socket: ");
+ 
+-  tcp53 = socket_tcp();
++  tcp53 = socket_tcp6();
+   if (tcp53 == -1)
+     strerr_die2sys(111,FATAL,"unable to create TCP socket: ");
+-  if (socket_bind4_reuse(tcp53,myipincoming,53) == -1)
++  if (socket_bind6_reuse(tcp53,myipincoming,53,interface) == -1)
+     strerr_die2sys(111,FATAL,"unable to bind TCP socket: ");
+ 
+   droproot(FATAL);
+@@ -421,7 +439,7 @@
+   x = env_get("IPSEND");
+   if (!x)
+     strerr_die2x(111,FATAL,"$IPSEND not set");
+-  if (!ip4_scan(x,myipoutgoing))
++  if (!ip6_scan(x,myipoutgoing))
+     strerr_die3x(111,FATAL,"unable to parse IP address ",x);
+ 
+   x = env_get("CACHESIZE");
+@@ -431,6 +449,20 @@
+   if (!cache_init(cachesize))
+     strerr_die3x(111,FATAL,"not enough memory for cache of size ",x);
+ 
++  if (openreadclose("ignoreip",&sa,64) < 0) 
++    strerr_die2x(111,FATAL,"trouble reading ignoreip");
++  for(j = k = i = 0; i < sa.len; i++)
++    if (sa.s[i] == '\n')  {
++      sa.s[i] = '\0';
++      if (!stralloc_readyplus(&ignoreip,16))
++	strerr_die2x(111,FATAL,"out of memory parsing ignoreip");
++      if (!ip6_scan(sa.s+k,ignoreip.s+j))
++        strerr_die3x(111,FATAL,"unable to parse address in ignoreip ",ignoreip.s+k);
++      j += 16;
++      k = i + 1;
++    }
++  ignoreip.len = j;
++
+   if (env_get("HIDETTL"))
+     response_hidettl();
+   if (env_get("FORWARDONLY"))
+diff -uNr djbdns-1.05/dnsfilter.c djbdns-1.05-ipv6/dnsfilter.c
+--- djbdns-1.05/dnsfilter.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/dnsfilter.c	2005-09-08 21:58:08.190382750 +0200
+@@ -12,6 +12,7 @@
+ #include "iopause.h"
+ #include "error.h"
+ #include "exit.h"
++#include "ip6.h"
+ 
+ #define FATAL "dnsfilter: fatal: "
+ 
+@@ -44,7 +45,7 @@
+ iopause_fd *io;
+ int iolen;
+ 
+-char servers[64];
++char servers[256];
+ char ip[4];
+ char name[DNS_NAME4_DOMAIN];
+ 
+@@ -191,7 +192,7 @@
+ 	      dns_name4_domain(name,ip);
+ 	      if (dns_resolvconfip(servers) == -1)
+ 	        strerr_die2sys(111,FATAL,"unable to read /etc/resolv.conf: ");
+-	      if (dns_transmit_start(&x[xnum].dt,servers,1,name,DNS_T_PTR,"\0\0\0\0") == -1)
++	      if (dns_transmit_start(&x[xnum].dt,servers,1,name,DNS_T_PTR,V6any) == -1)
+ 	        errout(xnum);
+ 	      else {
+ 	        x[xnum].flagactive = 1;
+diff -uNr djbdns-1.05/dnsip6.c djbdns-1.05-ipv6/dnsip6.c
+--- djbdns-1.05/dnsip6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/dnsip6.c	2005-09-08 21:58:08.190382750 +0200
+@@ -0,0 +1,40 @@
++#include "buffer.h"
++#include "exit.h"
++#include "strerr.h"
++#include "ip6.h"
++#include "dns.h"
++
++#define FATAL "dnsip: fatal: "
++
++static char seed[128];
++
++static stralloc fqdn;
++static stralloc out;
++char str[IP6_FMT];
++
++main(int argc,char **argv)
++{
++  int i;
++
++  dns_random_init(seed);
++
++  if (*argv) ++argv;
++
++  while (*argv) {
++    if (!stralloc_copys(&fqdn,*argv))
++      strerr_die2x(111,FATAL,"out of memory");
++    if (dns_ip6(&out,&fqdn) == -1)
++      strerr_die4sys(111,FATAL,"unable to find IPv6 address for ",*argv,": ");
++
++    for (i = 0;i + 16 <= out.len;i += 16) {
++      buffer_put(buffer_1,str,ip6_fmt(str,out.s + i));
++      buffer_puts(buffer_1," ");
++    }
++    buffer_puts(buffer_1,"\n");
++
++    ++argv;
++  }
++
++  buffer_flush(buffer_1);
++  _exit(0);
++}
+diff -uNr djbdns-1.05/dnsip6q.c djbdns-1.05-ipv6/dnsip6q.c
+--- djbdns-1.05/dnsip6q.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/dnsip6q.c	2005-09-08 21:58:08.194383000 +0200
+@@ -0,0 +1,43 @@
++#include "buffer.h"
++#include "exit.h"
++#include "strerr.h"
++#include "ip6.h"
++#include "dns.h"
++
++#define FATAL "dnsipq: fatal: "
++
++static char seed[128];
++
++static stralloc in;
++static stralloc fqdn;
++static stralloc out;
++char str[IP6_FMT];
++
++int main(int argc,char **argv)
++{
++  int i;
++
++  dns_random_init(seed);
++
++  if (*argv) ++argv;
++
++  while (*argv) {
++    if (!stralloc_copys(&in,*argv))
++      strerr_die2x(111,FATAL,"out of memory");
++    if (dns_ip6_qualify(&out,&fqdn,&in) == -1)
++      strerr_die4sys(111,FATAL,"unable to find IP6 address for ",*argv,": ");
++
++    buffer_put(buffer_1,fqdn.s,fqdn.len);
++    buffer_puts(buffer_1," ");
++    for (i = 0;i + 16 <= out.len;i += 16) {
++      buffer_put(buffer_1,str,ip6_fmt(str,out.s + i));
++      buffer_puts(buffer_1," ");
++    }
++    buffer_puts(buffer_1,"\n");
++
++    ++argv;
++  }
++
++  buffer_flush(buffer_1);
++  _exit(0);
++}
+diff -uNr djbdns-1.05/dnsname.c djbdns-1.05-ipv6/dnsname.c
+--- djbdns-1.05/dnsname.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/dnsname.c	2005-09-08 21:58:08.194383000 +0200
+@@ -2,6 +2,7 @@
+ #include "exit.h"
+ #include "strerr.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "dns.h"
+ 
+ #define FATAL "dnsname: fatal: "
+@@ -9,6 +10,7 @@
+ static char seed[128];
+ 
+ char ip[4];
++char ip6[16];
+ static stralloc out;
+ 
+ int main(int argc,char **argv)
+@@ -18,10 +20,15 @@
+   if (*argv) ++argv;
+ 
+   while (*argv) {
+-    if (!ip4_scan(*argv,ip))
+-      strerr_die3x(111,FATAL,"unable to parse IP address ",*argv);
+-    if (dns_name4(&out,ip) == -1)
+-      strerr_die4sys(111,FATAL,"unable to find host name for ",*argv,": ");
++    if (ip6_scan(*argv,ip6)) {
++      if (dns_name6(&out,ip6) == -1)
++	strerr_die4sys(111,FATAL,"unable to find host name for ",*argv,": ");
++    } else {
++      if (!ip4_scan(*argv,ip))
++	strerr_die3x(111,FATAL,"unable to parse IP address ",*argv);
++      if (dns_name4(&out,ip) == -1)
++	strerr_die4sys(111,FATAL,"unable to find host name for ",*argv,": ");
++    }
+ 
+     buffer_put(buffer_1,out.s,out.len);
+     buffer_puts(buffer_1,"\n");
+diff -uNr djbdns-1.05/dnsq.c djbdns-1.05-ipv6/dnsq.c
+--- djbdns-1.05/dnsq.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/dnsq.c	2005-09-08 21:58:08.198383250 +0200
+@@ -10,6 +10,7 @@
+ #include "printpacket.h"
+ #include "parsetype.h"
+ #include "dns.h"
++#include "ip6.h"
+ 
+ #define FATAL "dnsq: fatal: "
+ 
+@@ -24,14 +25,14 @@
+ 
+ static struct dns_transmit tx;
+ 
+-int resolve(char *q,char qtype[2],char servers[64])
++int resolve(char *q,char qtype[2],char servers[256])
+ {
+   struct taia stamp;
+   struct taia deadline;
+   iopause_fd x[1];
+   int r;
+ 
+-  if (dns_transmit_start(&tx,servers,0,q,qtype,"\0\0\0\0") == -1) return -1;
++  if (dns_transmit_start(&tx,servers,0,q,qtype,V6any) == -1) return -1;
+ 
+   for (;;) {
+     taia_now(&stamp);
+@@ -47,7 +48,7 @@
+   return 0;
+ }
+ 
+-char servers[64];
++char servers[256];
+ static stralloc ip;
+ static stralloc fqdn;
+ 
+@@ -73,9 +74,9 @@
+ 
+   if (!*++argv) usage();
+   if (!stralloc_copys(&out,*argv)) oops();
+-  if (dns_ip4_qualify(&ip,&fqdn,&out) == -1) oops();
+-  if (ip.len >= 64) ip.len = 64;
+-  byte_zero(servers,64);
++  if (dns_ip6_qualify(&ip,&fqdn,&out) == -1) oops();
++  if (ip.len >= 256) ip.len = 256;
++  byte_zero(servers,256);
+   byte_copy(servers,ip.len,ip.s);
+ 
+   if (!stralloc_copys(&out,"")) oops();
+diff -uNr djbdns-1.05/dnstrace.c djbdns-1.05-ipv6/dnstrace.c
+--- djbdns-1.05/dnstrace.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/dnstrace.c	2005-09-08 21:58:08.198383250 +0200
+@@ -4,6 +4,7 @@
+ #include "str.h"
+ #include "byte.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "gen_alloc.h"
+ #include "gen_allocdefs.h"
+ #include "exit.h"
+@@ -30,7 +31,7 @@
+ }
+ 
+ static stralloc querystr;
+-char ipstr[IP4_FMT];
++char ipstr[IP6_FMT];
+ static stralloc tmp;
+ 
+ void printdomain(const char *d)
+@@ -42,19 +43,19 @@
+ 
+ static struct dns_transmit tx;
+ 
+-int resolve(char *q,char qtype[2],char ip[4])
++int resolve(char *q,char qtype[2],char ip[16])
+ {
+   struct taia start;
+   struct taia stamp;
+   struct taia deadline;
+-  char servers[64];
++  char servers[256];
+   iopause_fd x[1];
+   int r;
+ 
+   taia_now(&start);
+ 
+-  byte_zero(servers,64);
+-  byte_copy(servers,4,ip);
++  byte_zero(servers,256);
++  byte_copy(servers,16,ip);
+ 
+   if (dns_transmit_start(&tx,servers,0,q,qtype,"\0\0\0\0") == -1) return -1;
+ 
+@@ -82,7 +83,7 @@
+ 
+ struct address {
+   char *owner;
+-  char ip[4];
++  char ip[16];
+ } ;
+ 
+ GEN_ALLOC_typedef(address_alloc,struct address,s,len,a)
+@@ -117,7 +118,7 @@
+   char *owner;
+   char type[2];
+   char *control;
+-  char ip[4];
++  char ip[16];
+ } ;
+ 
+ GEN_ALLOC_typedef(qt_alloc,struct qt,s,len,a)
+@@ -126,7 +127,7 @@
+ 
+ static qt_alloc qt;
+ 
+-void qt_add(const char *q,const char type[2],const char *control,const char ip[4])
++void qt_add(const char *q,const char type[2],const char *control,const char ip[16])
+ {
+   struct qt x;
+   int i;
+@@ -137,14 +138,14 @@
+     if (dns_domain_equal(qt.s[i].owner,q))
+       if (dns_domain_equal(qt.s[i].control,control))
+         if (byte_equal(qt.s[i].type,2,type))
+-	  if (byte_equal(qt.s[i].ip,4,ip))
++	  if (byte_equal(qt.s[i].ip,16,ip))
+ 	    return;
+ 
+   byte_zero(&x,sizeof x);
+   if (!dns_domain_copy(&x.owner,q)) nomem();
+   if (!dns_domain_copy(&x.control,control)) nomem();
+   byte_copy(x.type,2,type);
+-  byte_copy(x.ip,4,ip);
++  byte_copy(x.ip,16,ip);
+   if (!qt_alloc_append(&qt,&x)) nomem();
+ }
+ 
+@@ -203,7 +204,7 @@
+ 	  qt_add(query.s[i].owner,query.s[i].type,owner,address.s[j].ip);
+ }
+ 
+-void address_add(const char *owner,const char ip[4])
++void address_add(const char *owner,const char ip[16])
+ {
+   struct address x;
+   int i;
+@@ -213,17 +214,20 @@
+   buffer_puts(buffer_1,"A:");
+   printdomain(owner);
+   buffer_puts(buffer_1,":");
+-  buffer_put(buffer_1,ipstr,ip4_fmt(ipstr,ip));
++  if (ip6_isv4mapped(ip))
++    buffer_put(buffer_1,ipstr,ip4_fmt(ipstr,ip+12));
++  else
++    buffer_put(buffer_1,ipstr,ip6_fmt(ipstr,ip));
+   buffer_puts(buffer_1,"\n");
+ 
+   for (i = 0;i < address.len;++i)
+     if (dns_domain_equal(address.s[i].owner,owner))
+-      if (byte_equal(address.s[i].ip,4,ip))
++      if (byte_equal(address.s[i].ip,16,ip))
+ 	return;
+ 
+   byte_zero(&x,sizeof x);
+   if (!dns_domain_copy(&x.owner,owner)) nomem();
+-  byte_copy(x.ip,4,ip);
++  byte_copy(x.ip,16,ip);
+   if (!address_alloc_append(&address,&x)) nomem();
+ 
+   for (i = 0;i < ns.len;++i)
+@@ -331,7 +335,12 @@
+ 	  ns_add(t1,t2);
+         }
+         else if (typematch(header,DNS_T_A) && datalen == 4) {
+-	  if (!dns_packet_copy(buf,len,pos,misc,4)) goto DIE;
++	  if (!dns_packet_copy(buf,len,pos,misc+12,4)) goto DIE;
++	  byte_copy(misc,12,V4mappedprefix);
++	  address_add(t1,misc);
++        }
++        else if (typematch(header,DNS_T_AAAA) && datalen == 16) {
++	  if (!dns_packet_copy(buf,len,pos,misc,16)) goto DIE;
+ 	  address_add(t1,misc);
+         }
+       }
+@@ -419,8 +428,8 @@
+ 
+   while (*++argv) {
+     if (!stralloc_copys(&udn,*argv)) nomem();
+-    if (dns_ip4_qualify(&out,&fqdn,&udn) == -1) nomem(); /* XXX */
+-    for (i = 0;i + 4 <= out.len;i += 4)
++    if (dns_ip6_qualify(&out,&fqdn,&udn) == -1) nomem(); /* XXX */
++    for (i = 0;i + 16 <= out.len;i += 16)
+       address_add("",out.s + i);
+   }
+ 
+@@ -429,7 +438,7 @@
+     control = qt.s[i].control;
+     if (!dns_domain_suffix(q,control)) continue;
+     byte_copy(type,2,qt.s[i].type);
+-    byte_copy(ip,4,qt.s[i].ip);
++    byte_copy(ip,16,qt.s[i].ip);
+ 
+     if (!stralloc_copys(&querystr,"")) nomem();
+     uint16_unpack_big(type,&u16);
+@@ -439,7 +448,10 @@
+     if (!stralloc_cats(&querystr,":")) nomem();
+     if (!dns_domain_todot_cat(&querystr,control)) nomem();
+     if (!stralloc_cats(&querystr,":")) nomem();
+-    if (!stralloc_catb(&querystr,ipstr,ip4_fmt(ipstr,ip))) nomem();
++    if (ip6_isv4mapped(ip)) {
++      if (!stralloc_catb(&querystr,ipstr,ip4_fmt(ipstr,ip+12))) nomem();
++    } else
++      if (!stralloc_catb(&querystr,ipstr,ip6_fmt(ipstr,ip))) nomem();
+     if (!stralloc_cats(&querystr,":")) nomem();
+ 
+     buffer_put(buffer_1,querystr.s,querystr.len);
+diff -uNr djbdns-1.05/error.h djbdns-1.05-ipv6/error.h
+--- djbdns-1.05/error.h	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/error.h	2005-09-08 21:58:08.198383250 +0200
+@@ -1,7 +1,7 @@
+ #ifndef ERROR_H
+ #define ERROR_H
+ 
+-extern int errno;
++#include <errno.h>
+ 
+ extern int error_intr;
+ extern int error_nomem;
+diff -uNr djbdns-1.05/fmt_xlong.c djbdns-1.05-ipv6/fmt_xlong.c
+--- djbdns-1.05/fmt_xlong.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/fmt_xlong.c	2005-09-08 21:58:08.202383500 +0200
+@@ -0,0 +1,22 @@
++#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(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 -uNr djbdns-1.05/haveip6.h1 djbdns-1.05-ipv6/haveip6.h1
+--- djbdns-1.05/haveip6.h1	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/haveip6.h1	2005-09-08 21:58:08.202383500 +0200
+@@ -0,0 +1 @@
++
+diff -uNr djbdns-1.05/haveip6.h2 djbdns-1.05-ipv6/haveip6.h2
+--- djbdns-1.05/haveip6.h2	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/haveip6.h2	2005-09-08 21:58:08.202383500 +0200
+@@ -0,0 +1 @@
++#define LIBC_HAS_IP6 1
+diff -uNr djbdns-1.05/haven2i.h1 djbdns-1.05-ipv6/haven2i.h1
+--- djbdns-1.05/haven2i.h1	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/haven2i.h1	2005-09-08 21:58:08.206383750 +0200
+@@ -0,0 +1 @@
++#undef HAVE_N2I
+diff -uNr djbdns-1.05/haven2i.h2 djbdns-1.05-ipv6/haven2i.h2
+--- djbdns-1.05/haven2i.h2	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/haven2i.h2	2005-09-08 21:58:08.206383750 +0200
+@@ -0,0 +1 @@
++#define HAVE_N2I
+diff -uNr djbdns-1.05/hier.c djbdns-1.05-ipv6/hier.c
+--- djbdns-1.05/hier.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/hier.c	2005-09-08 21:58:08.206383750 +0200
+@@ -29,7 +29,9 @@
+   c(auto_home,"bin","axfr-get",-1,-1,0755);
+ 
+   c(auto_home,"bin","dnsip",-1,-1,0755);
++  c(auto_home,"bin","dnsip6",-1,-1,0755);
+   c(auto_home,"bin","dnsipq",-1,-1,0755);
++  c(auto_home,"bin","dnsip6q",-1,-1,0755);
+   c(auto_home,"bin","dnsname",-1,-1,0755);
+   c(auto_home,"bin","dnstxt",-1,-1,0755);
+   c(auto_home,"bin","dnsmx",-1,-1,0755);
+diff -uNr djbdns-1.05/ip6.h djbdns-1.05-ipv6/ip6.h
+--- djbdns-1.05/ip6.h	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/ip6.h	2005-09-08 21:58:08.210384000 +0200
+@@ -0,0 +1,28 @@
++#ifndef IP6_H
++#define IP6_H
++
++extern unsigned int ip6_scan(const char *,char *);
++extern unsigned int ip6_fmt(char *,const char *);
++
++extern unsigned int ip6_scan_flat(const char *,char *);
++extern unsigned int ip6_fmt_flat(char *,char *);
++
++/*
++ ip6 address syntax: (h = hex digit), no leading '0' required
++   1. hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh
++   2. any number of 0000 may be abbreviated as "::", but only once
++ flat ip6 address syntax:
++   hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
++ */
++
++#define IP6_FMT 40
++
++const static unsigned char V4mappedprefix[12]={0,0,0,0,0,0,0,0,0,0,0xff,0xff};
++const static unsigned char V6loopback[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
++const static unsigned char V6any[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
++
++#define ip6_isv4mapped(ip) (byte_equal(ip,12,V4mappedprefix))
++
++const static char ip4loopback[4] = {127,0,0,1};
++
++#endif
+diff -uNr djbdns-1.05/ip6_fmt.c djbdns-1.05-ipv6/ip6_fmt.c
+--- djbdns-1.05/ip6_fmt.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/ip6_fmt.c	2005-09-08 21:58:08.210384000 +0200
+@@ -0,0 +1,60 @@
++#include "fmt.h"
++#include "byte.h"
++#include "ip4.h"
++#include "ip6.h"
++#include <stdio.h>
++
++extern char tohex(char num);
++
++unsigned int ip6_fmt(char *s,const char ip[16])
++{
++  unsigned int len;
++  unsigned int i;
++  unsigned int temp;
++  unsigned int compressing;
++  unsigned int compressed;
++  int j;
++
++  len = 0; compressing = 0; compressed = 0;
++  for (j=0; j<16; j+=2) {
++    if (j==12 && ip6_isv4mapped(ip)) {
++      temp=ip4_fmt(s,ip+12);
++      len+=temp;
++      break;
++    }
++    temp = ((unsigned long) (unsigned char) ip[j] << 8) +
++            (unsigned long) (unsigned char) ip[j+1];
++    if (temp == 0 && !compressed) {
++      if (!compressing) {
++	compressing=1;
++	if (j==0) {
++	  if (s) *s++=':'; ++len;
++	}
++      }
++    } else {
++      if (compressing) {
++	compressing=0; ++compressed;
++	if (s) *s++=':'; ++len;
++      }
++      i = fmt_xlong(s,temp); len += i; if (s) s += i;
++      if (j<14) {
++	if (s) *s++ = ':';
++	++len;
++      }
++    }
++  }
++  if (compressing) { *s++=':'; ++len; }
++
++/*  if (s) *s=0; */
++  return len;
++}
++
++unsigned int ip6_fmt_flat(char *s,char ip[16])
++{
++  int i;
++  for (i=0; i<16; i++) {
++    *s++=tohex((unsigned char)ip[i] >> 4);
++    *s++=tohex((unsigned char)ip[i] & 15);
++  }
++  return 32;
++}
+diff -uNr djbdns-1.05/ip6_scan.c djbdns-1.05-ipv6/ip6_scan.c
+--- djbdns-1.05/ip6_scan.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/ip6_scan.c	2005-09-08 21:58:08.214384250 +0200
+@@ -0,0 +1,115 @@
++#include "scan.h"
++#include "ip4.h"
++#include "ip6.h"
++#include "byte.h"
++
++/*
++ * 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(const char *s,char ip[16])
++{
++  unsigned int i;
++  unsigned int len=0;
++  unsigned long u;
++
++  char suffix[16];
++  int prefixlen=0;
++  int suffixlen=0;
++
++  if ((i=ip4_scan(s,ip+12))) {
++    const char *c=V4mappedprefix;
++    if (byte_equal(ip+12,4,V6any)) c=V6any;
++    for (len=0; len<12; ++len) ip[len]=c[len];
++    return i;
++  }
++  for (i=0; i<16; i++) ip[i]=0;
++  for (;;) {
++    if (*s == ':') {
++      len++;
++      if (s[1] == ':') {	/* Found "::", skip to part 2 */
++	s+=2;
++	len++;
++	break;
++      }
++      s++;
++    }
++    i = scan_xlong(s,&u);
++    if (!i) return 0;
++    if (prefixlen==12 && s[i]=='.') {
++      /* the last 4 bytes may be written as IPv4 address */
++      i=ip4_scan(s,ip+12);
++      if (i)
++	return i+len;
++      else
++	return 0;
++    }
++    ip[prefixlen++] = (u >> 8);
++    ip[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_xlong(s,&u);
++    if (!i) {
++      len--;
++      break;
++    }
++    if (suffixlen+prefixlen<=12 && s[i]=='.') {
++      int j=ip4_scan(s,suffix+suffixlen);
++      if (j) {
++	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; i<suffixlen; i++)
++    ip[16-suffixlen+i] = suffix[i];
++  return len;
++}
++
++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 ip6_scan_flat(const char *s,char ip[16])
++{
++  int i;
++  for (i=0; i<16; i++) {
++    int tmp;
++    tmp=fromhex(*s++);
++    if (tmp<0) return 0;
++    ip[i]=tmp << 4;
++    tmp=fromhex(*s++);
++    if (tmp<0) return 0;
++    ip[i]+=tmp;
++  }
++  return 32;
++}
+diff -uNr djbdns-1.05/log.c djbdns-1.05-ipv6/log.c
+--- djbdns-1.05/log.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/log.c	2005-09-08 21:58:08.214384250 +0200
+@@ -3,6 +3,7 @@
+ #include "uint16.h"
+ #include "error.h"
+ #include "byte.h"
++#include "ip6.h"
+ #include "log.h"
+ 
+ /* work around gcc 2.95.2 bug */
+@@ -45,12 +46,10 @@
+   string(" ");
+ }
+ 
+-static void ip(const char i[4])
++static void ip(const char i[16])
+ {
+-  hex(i[0]);
+-  hex(i[1]);
+-  hex(i[2]);
+-  hex(i[3]);
++  int j;
++  for (j=0; j<16; ++j) hex(i[j]);
+ }
+ 
+ static void logid(const char id[2])
+@@ -94,7 +93,7 @@
+   line();
+ }
+ 
+-void log_query(uint64 *qnum,const char client[4],unsigned int port,const char id[2],const char *q,const char qtype[2])
++void log_query(uint64 *qnum,const char client[16],unsigned int port,const char id[2],const char *q,const char qtype[2])
+ {
+   string("query "); number(*qnum); space();
+   ip(client); string(":"); hex(port >> 8); hex(port & 255);
+@@ -119,14 +118,14 @@
+   line();
+ }
+ 
+-void log_tcpopen(const char client[4],unsigned int port)
++void log_tcpopen(const char client[16],unsigned int port)
+ {
+   string("tcpopen ");
+   ip(client); string(":"); hex(port >> 8); hex(port & 255);
+   line();
+ }
+ 
+-void log_tcpclose(const char client[4],unsigned int port)
++void log_tcpclose(const char client[16],unsigned int port)
+ {
+   const char *x = error_str(errno);
+   string("tcpclose ");
+@@ -135,15 +134,15 @@
+   line();
+ }
+ 
+-void log_tx(const char *q,const char qtype[2],const char *control,const char servers[64],unsigned int gluelessness)
++void log_tx(const char *q,const char qtype[2],const char *control,const char servers[256],unsigned int gluelessness)
+ {
+   int i;
+ 
+   string("tx "); number(gluelessness); space();
+   logtype(qtype); space(); name(q); space();
+   name(control);
+-  for (i = 0;i < 64;i += 4)
+-    if (byte_diff(servers + i,4,"\0\0\0\0")) {
++  for (i = 0;i < 256;i += 16)
++    if (byte_diff(servers + i,16,V6any)) {
+       space();
+       ip(servers + i);
+     }
+@@ -175,21 +174,21 @@
+   line();
+ }
+ 
+-void log_nxdomain(const char server[4],const char *q,unsigned int ttl)
++void log_nxdomain(const char server[16],const char *q,unsigned int ttl)
+ {
+   string("nxdomain "); ip(server); space(); number(ttl); space();
+   name(q);
+   line();
+ }
+ 
+-void log_nodata(const char server[4],const char *q,const char qtype[2],unsigned int ttl)
++void log_nodata(const char server[16],const char *q,const char qtype[2],unsigned int ttl)
+ {
+   string("nodata "); ip(server); space(); number(ttl); space();
+   logtype(qtype); space(); name(q);
+   line();
+ }
+ 
+-void log_lame(const char server[4],const char *control,const char *referral)
++void log_lame(const char server[16],const char *control,const char *referral)
+ {
+   string("lame "); ip(server); space();
+   name(control); space(); name(referral);
+@@ -205,7 +204,7 @@
+   line();
+ }
+ 
+-void log_rr(const char server[4],const char *q,const char type[2],const char *buf,unsigned int len,unsigned int ttl)
++void log_rr(const char server[16],const char *q,const char type[2],const char *buf,unsigned int len,unsigned int ttl)
+ {
+   int i;
+ 
+@@ -222,7 +221,7 @@
+   line();
+ }
+ 
+-void log_rrns(const char server[4],const char *q,const char *data,unsigned int ttl)
++void log_rrns(const char server[16],const char *q,const char *data,unsigned int ttl)
+ {
+   string("rr "); ip(server); space(); number(ttl);
+   string(" ns "); name(q); space();
+@@ -230,7 +229,7 @@
+   line();
+ }
+ 
+-void log_rrcname(const char server[4],const char *q,const char *data,unsigned int ttl)
++void log_rrcname(const char server[16],const char *q,const char *data,unsigned int ttl)
+ {
+   string("rr "); ip(server); space(); number(ttl);
+   string(" cname "); name(q); space();
+@@ -238,7 +237,7 @@
+   line();
+ }
+ 
+-void log_rrptr(const char server[4],const char *q,const char *data,unsigned int ttl)
++void log_rrptr(const char server[16],const char *q,const char *data,unsigned int ttl)
+ {
+   string("rr "); ip(server); space(); number(ttl);
+   string(" ptr "); name(q); space();
+@@ -246,7 +245,7 @@
+   line();
+ }
+ 
+-void log_rrmx(const char server[4],const char *q,const char *mx,const char pref[2],unsigned int ttl)
++void log_rrmx(const char server[16],const char *q,const char *mx,const char pref[2],unsigned int ttl)
+ {
+   uint16 u;
+ 
+@@ -257,7 +256,7 @@
+   line();
+ }
+ 
+-void log_rrsoa(const char server[4],const char *q,const char *n1,const char *n2,const char misc[20],unsigned int ttl)
++void log_rrsoa(const char server[16],const char *q,const char *n1,const char *n2,const char misc[20],unsigned int ttl)
+ {
+   uint32 u;
+   int i;
+diff -uNr djbdns-1.05/okclient.c djbdns-1.05-ipv6/okclient.c
+--- djbdns-1.05/okclient.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/okclient.c	2005-09-08 21:58:08.214384250 +0200
+@@ -2,24 +2,34 @@
+ #include <sys/stat.h>
+ #include "str.h"
+ #include "ip4.h"
++#include "ip6.h"
++#include "byte.h"
+ #include "okclient.h"
+ 
+-static char fn[3 + IP4_FMT];
++static char fn[3 + IP6_FMT];
+ 
+-int okclient(char ip[4])
++int okclient(char ip[16])
+ {
+   struct stat st;
+   int i;
++  char sep;
+ 
+   fn[0] = 'i';
+   fn[1] = 'p';
+   fn[2] = '/';
+-  fn[3 + ip4_fmt(fn + 3,ip)] = 0;
++  if (byte_equal(ip,12,V4mappedprefix)) {
++    fn[3 + ip4_fmt(fn + 3,ip+12)] = 0;
++    sep='.';
++  } else {
++    fn[3 + ip6_fmt(fn + 3,ip)] = 0;
++    sep=':';
++  }
+ 
+   for (;;) {
++    if (!fn[3]) return 0;
+     if (stat(fn,&st) == 0) return 1;
+     /* treat temporary error as rejection */
+-    i = str_rchr(fn,'.');
++    i = str_rchr(fn,sep);
+     if (!fn[i]) return 0;
+     fn[i] = 0;
+   }
+diff -uNr djbdns-1.05/printrecord.c djbdns-1.05-ipv6/printrecord.c
+--- djbdns-1.05/printrecord.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/printrecord.c	2005-09-08 21:58:08.218384500 +0200
+@@ -4,6 +4,7 @@
+ #include "byte.h"
+ #include "dns.h"
+ #include "printrecord.h"
++#include "ip6.h"
+ 
+ static char *d;
+ 
+@@ -82,6 +83,15 @@
+       if (!stralloc_catulong0(out,ch,0)) return 0;
+     }
+   }
++  else if (byte_equal(misc,2,DNS_T_AAAA)) {
++    char ip6str[IP6_FMT];
++    int stringlen;
++    if (datalen != 16) { errno = error_proto; return 0; }
++    if (!stralloc_cats(out," AAAA ")) return 0;
++    pos = dns_packet_copy(buf,len,pos,misc,16); if (!pos) return 0;
++    stringlen=ip6_fmt(ip6str,misc);
++    if (!stralloc_catb(out,ip6str,stringlen)) return 0;
++  }
+   else {
+     if (!stralloc_cats(out," ")) return 0;
+     uint16_unpack_big(misc,&u16);
+diff -uNr djbdns-1.05/qlog.c djbdns-1.05-ipv6/qlog.c
+--- djbdns-1.05/qlog.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/qlog.c	2005-09-08 21:58:08.218384500 +0200
+@@ -20,15 +20,15 @@
+   put('0' + (c & 7));
+ }
+ 
+-void qlog(const char ip[4],uint16 port,const char id[2],const char *q,const char qtype[2],const char *result)
++void qlog(const char ip[16],uint16 port,const char id[2],const char *q,const char qtype[2],const char *result)
+ {
+   char ch;
+   char ch2;
+ 
+-  hex(ip[0]);
+-  hex(ip[1]);
+-  hex(ip[2]);
+-  hex(ip[3]);
++  {
++    int i;
++    for (i=0; i<16; ++i) hex(ip[i]);
++  }
+   put(':');
+   hex(port >> 8);
+   hex(port & 255);
+diff -uNr djbdns-1.05/query.c djbdns-1.05-ipv6/query.c
+--- djbdns-1.05/query.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/query.c	2005-09-08 21:58:08.218384500 +0200
+@@ -12,6 +12,9 @@
+ #include "alloc.h"
+ #include "response.h"
+ #include "query.h"
++#include "ip6.h"
++
++extern stralloc ignoreip;
+ 
+ static int flagforwardonly = 0;
+ 
+@@ -110,7 +113,7 @@
+   return 1;
+ }
+ 
+-static int globalip(char *d,char ip[4])
++static int globalip(char *d,char ip[16])
+ {
+   if (dns_domain_equal(d,"\011localhost\0")) {
+     byte_copy(ip,4,"\177\0\0\1");
+@@ -165,7 +168,7 @@
+   char *buf;
+   unsigned int len;
+   const char *whichserver;
+-  char header[12];
++  char header[24];
+   char misc[20];
+   unsigned int rcode;
+   unsigned int posanswers;
+@@ -193,6 +196,7 @@
+   int k;
+   int p;
+   int q;
++  unsigned int ii;
+ 
+   errno = error_io;
+   if (state == 1) goto HAVEPACKET;
+@@ -210,9 +214,10 @@
+ 
+   if (globalip(d,misc)) {
+     if (z->level) {
+-      for (k = 0;k < 64;k += 4)
+-        if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) {
+-	  byte_copy(z->servers[z->level - 1] + k,4,misc);
++      for (k = 0;k < 256;k += 16)
++        if (byte_equal(z->servers[z->level - 1] + k,16,V6any)) {
++	  byte_copy(z->servers[z->level - 1] + k,12,V4mappedprefix);
++	  byte_copy(z->servers[z->level - 1] + k + 12,4,misc);
+ 	  break;
+ 	}
+       goto LOWERLEVEL;
+@@ -227,6 +232,158 @@
+     return 1;
+   }
+ 
++  if (dns_domain_equal(d,"\0011\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\003ip6\003int\0")) {
++    if (z->level) goto LOWERLEVEL;
++    if (!rqa(z)) goto DIE;
++    if (typematch(DNS_T_PTR,dtype)) {
++      if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
++      if (!response_addname("\016ipv6-localhost\0")) goto DIE;
++      if (!response_addname("\015ipv6-loopback\0")) goto DIE;
++      response_rfinish(RESPONSE_ANSWER);
++    }
++    cleanup(z);
++    return 1;
++  }
++
++  if (dns_domain_equal(d,"\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\001e\001f\003ip6\003int\0")) {
++    if (z->level) goto LOWERLEVEL;
++    if (!rqa(z)) goto DIE;
++    if (typematch(DNS_T_PTR,dtype)) {
++      if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
++      if (!response_addname("\015ipv6-localnet\0")) goto DIE;
++      response_rfinish(RESPONSE_ANSWER);
++    }
++    cleanup(z);
++    return 1;
++  }
++
++  if (dns_domain_equal(d,"\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\001f\001f\003ip6\003int\0")) {
++    if (z->level) goto LOWERLEVEL;
++    if (!rqa(z)) goto DIE;
++    if (typematch(DNS_T_PTR,dtype)) {
++      if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
++      if (!response_addname("\020ipv6-mcastprefix\0")) goto DIE;
++      response_rfinish(RESPONSE_ANSWER);
++    }
++    cleanup(z);
++    return 1;
++  }
++
++  if (dns_domain_equal(d,"\0011\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0012\0010\001f\001f\003ip6\003int\0")) {
++    if (z->level) goto LOWERLEVEL;
++    if (!rqa(z)) goto DIE;
++    if (typematch(DNS_T_PTR,dtype)) {
++      if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
++      if (!response_addname("\015ipv6-allnodes\0")) goto DIE;
++      response_rfinish(RESPONSE_ANSWER);
++    }
++    cleanup(z);
++    return 1;
++  }
++
++  if (dns_domain_equal(d,"\0012\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0012\0010\001f\001f\003ip6\003int\0")) {
++    if (z->level) goto LOWERLEVEL;
++    if (!rqa(z)) goto DIE;
++    if (typematch(DNS_T_PTR,dtype)) {
++      if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
++      if (!response_addname("\017ipv6-allrouters\0")) goto DIE;
++      response_rfinish(RESPONSE_ANSWER);
++    }
++    cleanup(z);
++    return 1;
++  }
++
++  if (dns_domain_equal(d,"\0011\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0010\0012\0010\001f\001f\003ip6\003int\0")) {
++    if (z->level) goto LOWERLEVEL;
++    if (!rqa(z)) goto DIE;
++    if (typematch(DNS_T_PTR,dtype)) {
++      if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
++      if (!response_addname("\015ipv6-allhosts\0")) goto DIE;
++      response_rfinish(RESPONSE_ANSWER);
++    }
++    cleanup(z);
++    return 1;
++  }
++
++  if (dns_domain_equal(d,"\016ipv6-localhost\0") ||
++      dns_domain_equal(d,"\015ipv6-loopback\0"))
++    {
++      if (z->level) goto LOWERLEVEL;
++      if (!rqa(z)) goto DIE;
++      if (typematch(DNS_T_AAAA,dtype)) {
++	if (!response_rstart(d,DNS_T_AAAA,655360)) goto DIE;
++	if (!response_addbytes("\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001",16)) goto DIE;
++	response_rfinish(RESPONSE_ANSWER);
++      }
++      cleanup(z);
++      return 1;
++    }
++
++  if (dns_domain_equal(d,"\015ipv6-localnet\0"))
++    {
++      if (z->level) goto LOWERLEVEL;
++      if (!rqa(z)) goto DIE;
++      if (typematch(DNS_T_AAAA,dtype)) {
++	if (!response_rstart(d,DNS_T_AAAA,655360)) goto DIE;
++	if (!response_addbytes("\376\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",16)) goto DIE;
++	response_rfinish(RESPONSE_ANSWER);
++      }
++      cleanup(z);
++      return 1;
++    }
++
++  if (dns_domain_equal(d,"\020ipv6-mcastprefix\0"))
++    {
++      if (z->level) goto LOWERLEVEL;
++      if (!rqa(z)) goto DIE;
++      if (typematch(DNS_T_AAAA,dtype)) {
++	if (!response_rstart(d,DNS_T_AAAA,655360)) goto DIE;
++	if (!response_addbytes("\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",16)) goto DIE;
++	response_rfinish(RESPONSE_ANSWER);
++      }
++      cleanup(z);
++      return 1;
++    }
++
++  if (dns_domain_equal(d,"\15ipv6-allnodes\0"))
++    {
++      if (z->level) goto LOWERLEVEL;
++      if (!rqa(z)) goto DIE;
++      if (typematch(DNS_T_AAAA,dtype)) {
++	if (!response_rstart(d,DNS_T_AAAA,655360)) goto DIE;
++	if (!response_addbytes("\377\002\000\000\000\000\000\000\000\000\000\000\000\000\000\001",16)) goto DIE;
++	response_rfinish(RESPONSE_ANSWER);
++      }
++      cleanup(z);
++      return 1;
++    }
++
++  if (dns_domain_equal(d,"\17ipv6-allrouters\0"))
++    {
++      if (z->level) goto LOWERLEVEL;
++      if (!rqa(z)) goto DIE;
++      if (typematch(DNS_T_AAAA,dtype)) {
++	if (!response_rstart(d,DNS_T_AAAA,655360)) goto DIE;
++	if (!response_addbytes("\377\002\000\000\000\000\000\000\000\000\000\000\000\000\000\002",16)) goto DIE;
++	response_rfinish(RESPONSE_ANSWER);
++      }
++      cleanup(z);
++      return 1;
++    }
++
++  if (dns_domain_equal(d,"\15ipv6-allhosts\0"))
++    {
++      if (z->level) goto LOWERLEVEL;
++      if (!rqa(z)) goto DIE;
++      if (typematch(DNS_T_AAAA,dtype)) {
++	if (!response_rstart(d,DNS_T_AAAA,655360)) goto DIE;
++	if (!response_addbytes("\377\002\000\000\000\000\000\000\000\000\000\000\000\000\000\003",16)) goto DIE;
++	response_rfinish(RESPONSE_ANSWER);
++      }
++      cleanup(z);
++      return 1;
++    }
++
+   if (dns_domain_equal(d,"\0011\0010\0010\003127\7in-addr\4arpa\0")) {
+     if (z->level) goto LOWERLEVEL;
+     if (!rqa(z)) goto DIE;
+@@ -326,9 +483,10 @@
+ 	if (z->level) {
+ 	  log_cachedanswer(d,DNS_T_A);
+ 	  while (cachedlen >= 4) {
+-	    for (k = 0;k < 64;k += 4)
+-	      if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) {
+-		byte_copy(z->servers[z->level - 1] + k,4,cached);
++	    for (k = 0;k < 256;k += 16)
++	      if (byte_equal(z->servers[z->level - 1] + k,16,V6any)) {
++		byte_copy(z->servers[z->level - 1] + k,12,V4mappedprefix);
++		byte_copy(z->servers[z->level - 1] + k + 12,4,cached);
+ 		break;
+ 	      }
+ 	    cached += 4;
+@@ -351,7 +509,39 @@
+       }
+     }
+ 
+-    if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_CNAME,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype)) {
++    if (typematch(DNS_T_AAAA,dtype)) {
++      byte_copy(key,2,DNS_T_AAAA);
++      cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
++      if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
++	if (z->level) {
++	  log_cachedanswer(d,DNS_T_AAAA);
++	  while (cachedlen >= 16) {
++	    for (k = 0;k < 256;k += 16)
++	      if (byte_equal(z->servers[z->level - 1] + k,16,V6any)) {
++		byte_copy(z->servers[z->level - 1] + k,16,cached);
++		break;
++	      }
++	    cached += 16;
++	    cachedlen -= 16;
++	  }
++	  goto LOWERLEVEL;
++	}
++
++	log_cachedanswer(d,DNS_T_AAAA);
++	if (!rqa(z)) goto DIE;
++	while (cachedlen >= 16) {
++	  if (!response_rstart(d,DNS_T_AAAA,ttl)) goto DIE;
++	  if (!response_addbytes(cached,16)) goto DIE;
++	  response_rfinish(RESPONSE_ANSWER);
++	  cached += 16;
++	  cachedlen -= 16;
++	}
++	cleanup(z);
++	return 1;
++      }
++    }
++
++    if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_CNAME,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype) && !typematch(DNS_T_AAAA,dtype)) {
+       byte_copy(key,2,dtype);
+       cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
+       if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
+@@ -390,7 +580,7 @@
+         cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
+         if (cached && cachedlen) {
+ 	  z->control[z->level] = d;
+-          byte_zero(z->servers[z->level],64);
++          byte_zero(z->servers[z->level],256);
+           for (j = 0;j < QUERY_MAXNS;++j)
+             dns_domain_free(&z->ns[z->level][j]);
+           pos = 0;
+@@ -423,12 +613,12 @@
+       dns_domain_free(&z->ns[z->level][j]);
+     }
+ 
+-  for (j = 0;j < 64;j += 4)
+-    if (byte_diff(z->servers[z->level] + j,4,"\0\0\0\0"))
++  for (j = 0;j < 256;j += 16)
++    if (byte_diff(z->servers[z->level] + j,16,V6any))
+       break;
+-  if (j == 64) goto SERVFAIL;
++  if (j == 256) goto SERVFAIL;
+ 
+-  dns_sortip(z->servers[z->level],64);
++  dns_sortip6(z->servers[z->level],256);
+   if (z->level) {
+     log_tx(z->name[z->level],DNS_T_A,z->control[z->level],z->servers[z->level],z->level);
+     if (dns_transmit_start(&z->dt,z->servers[z->level],flagforwardonly,z->name[z->level],DNS_T_A,z->localip) == -1) goto DIE;
+@@ -453,7 +643,7 @@
+   buf = z->dt.packet;
+   len = z->dt.packetlen;
+ 
+-  whichserver = z->dt.servers + 4 * z->dt.curserver;
++  whichserver = z->dt.servers + 16 * z->dt.curserver;
+   control = z->control[z->level];
+   d = z->name[z->level];
+   dtype = z->level ? DNS_T_A : z->type;
+@@ -519,7 +709,7 @@
+   if (!flagcname && !rcode && !flagout && flagreferral && !flagsoa)
+     if (dns_domain_equal(referral,control) || !dns_domain_suffix(referral,control)) {
+       log_lame(whichserver,control,referral);
+-      byte_zero(whichserver,4);
++      byte_zero(whichserver,16);
+       goto HAVENS;
+     }
+ 
+@@ -643,6 +833,11 @@
+         pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
+         if (byte_equal(header + 8,2,"\0\4")) {
+           pos = dns_packet_copy(buf,len,pos,header,4); if (!pos) goto DIE;
++          if (ignoreip.len)
++	    for(ii = 0; ii < ignoreip.len; ii+= 16) {
++	      if (byte_equal(ignoreip.s+ii,12,V4mappedprefix) &&
++	          byte_equal(header,4,ignoreip.s+ii+12)) goto NXDOMAIN;
++	    }
+           save_data(header,4);
+           log_rr(whichserver,t1,DNS_T_A,header,4,ttl);
+         }
+@@ -650,6 +845,23 @@
+       }
+       save_finish(DNS_T_A,t1,ttl);
+     }
++    else if (byte_equal(type,2,DNS_T_AAAA)) {
++      save_start();
++      while (i < j) {
++        pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE;
++        pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
++        if (byte_equal(header + 8,2,"\0\20")) {
++          pos = dns_packet_copy(buf,len,pos,header,16); if (!pos) goto DIE;
++          if (ignoreip.len)
++	    for(ii = 0; ii < ignoreip.len; ii+= 16)
++	      if (byte_equal(header,16,ignoreip.s+ii)) goto NXDOMAIN;
++          save_data(header,16);
++          log_rr(whichserver,t1,DNS_T_AAAA,header,16,ttl);
++        }
++        ++i;
++      }
++      save_finish(DNS_T_AAAA,t1,ttl);
++    }
+     else {
+       save_start();
+       while (i < j) {
+@@ -723,9 +935,10 @@
+           if (typematch(header,DNS_T_A))
+             if (byte_equal(header + 2,2,DNS_C_IN)) /* should always be true */
+               if (datalen == 4)
+-                for (k = 0;k < 64;k += 4)
+-                  if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) {
+-                    if (!dns_packet_copy(buf,len,pos,z->servers[z->level - 1] + k,4)) goto DIE;
++                for (k = 0;k < 256;k += 16)
++                  if (byte_equal(z->servers[z->level - 1] + k,16,V6any)) {
++		    byte_copy(z->servers[z->level - 1] + k,12,V4mappedprefix);
++                    if (!dns_packet_copy(buf,len,pos,z->servers[z->level - 1] + k + 12,4)) goto DIE;
+                     break;
+                   }
+         pos += datalen;
+@@ -818,7 +1031,7 @@
+   return -1;
+ }
+ 
+-int query_start(struct query *z,char *dn,char type[2],char class[2],char localip[4])
++int query_start(struct query *z,char *dn,char type[2],char class[2],char localip[16],unsigned int scope_id)
+ {
+   if (byte_equal(type,2,DNS_T_AXFR)) { errno = error_perm; return -1; }
+ 
+@@ -829,7 +1042,8 @@
+   if (!dns_domain_copy(&z->name[0],dn)) return -1;
+   byte_copy(z->type,2,type);
+   byte_copy(z->class,2,class);
+-  byte_copy(z->localip,4,localip);
++  byte_copy(z->localip,16,localip);
++  z->scope_id=scope_id;
+ 
+   return doit(z,0);
+ }
+diff -uNr djbdns-1.05/query.h djbdns-1.05-ipv6/query.h
+--- djbdns-1.05/query.h	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/query.h	2005-09-08 21:58:08.222384750 +0200
+@@ -14,16 +14,17 @@
+   char *name[QUERY_MAXLEVEL];
+   char *control[QUERY_MAXLEVEL]; /* pointing inside name */
+   char *ns[QUERY_MAXLEVEL][QUERY_MAXNS];
+-  char servers[QUERY_MAXLEVEL][64];
++  char servers[QUERY_MAXLEVEL][256];
+   char *alias[QUERY_MAXALIAS];
+   uint32 aliasttl[QUERY_MAXALIAS];
+-  char localip[4];
++  char localip[16];
++  uint32 scope_id;
+   char type[2];
+   char class[2];
+   struct dns_transmit dt;
+ } ;
+ 
+-extern int query_start(struct query *,char *,char *,char *,char *);
++extern int query_start(struct query *,char *,char *,char *,char *,unsigned int);
+ extern void query_io(struct query *,iopause_fd *,struct taia *);
+ extern int query_get(struct query *,iopause_fd *,struct taia *);
+ 
+diff -uNr djbdns-1.05/roots.c djbdns-1.05-ipv6/roots.c
+--- djbdns-1.05/roots.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/roots.c	2005-09-08 21:58:08.222384750 +0200
+@@ -6,6 +6,7 @@
+ #include "error.h"
+ #include "direntry.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "dns.h"
+ #include "openreadclose.h"
+ #include "roots.h"
+@@ -22,7 +23,7 @@
+     j = dns_domain_length(data.s + i);
+     if (dns_domain_equal(data.s + i,q)) return i + j;
+     i += j;
+-    i += 64;
++    i += 256;
+   }
+   return -1;
+ }
+@@ -40,12 +41,12 @@
+   }
+ }
+ 
+-int roots(char servers[64],char *q)
++int roots(char servers[256],char *q)
+ {
+   int r;
+   r = roots_find(q);
+   if (r == -1) return 0;
+-  byte_copy(servers,64,data.s + r);
++  byte_copy(servers,256,data.s + r);
+   return 1;
+ }
+ 
+@@ -60,7 +61,7 @@
+   const char *fqdn;
+   static char *q;
+   static stralloc text;
+-  char servers[64];
++  char servers[256];
+   int serverslen;
+   int i;
+   int j;
+@@ -86,14 +87,14 @@
+       for (i = 0;i < text.len;++i)
+ 	if (text.s[i] == '\n') {
+ 	  if (serverslen <= 60)
+-	    if (ip4_scan(text.s + j,servers + serverslen))
+-	      serverslen += 4;
++	    if (ip6_scan(text.s + j,servers + serverslen))
++	      serverslen += 16;
+ 	  j = i + 1;
+ 	}
+-      byte_zero(servers + serverslen,64 - serverslen);
++      byte_zero(servers + serverslen,256 - serverslen);
+ 
+       if (!stralloc_catb(&data,q,dns_domain_length(q))) return 0;
+-      if (!stralloc_catb(&data,servers,64)) return 0;
++      if (!stralloc_catb(&data,servers,256)) return 0;
+     }
+   }
+ }
+diff -uNr djbdns-1.05/scan_xlong.c djbdns-1.05-ipv6/scan_xlong.c
+--- djbdns-1.05/scan_xlong.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/scan_xlong.c	2005-09-08 21:58:08.222384750 +0200
+@@ -0,0 +1,23 @@
++#include "scan.h"
++
++static inline 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_xlong(const char *src,unsigned long *dest) {
++  register const char *tmp=src;
++  register int l=0;
++  register unsigned char c;
++  while ((c=fromhex(*tmp))<16) {
++    l=(l<<4)+c;
++    ++tmp;
++  }
++  *dest=l;
++  return tmp-src;
++}
+diff -uNr djbdns-1.05/server.c djbdns-1.05-ipv6/server.c
+--- djbdns-1.05/server.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/server.c	2005-09-08 21:58:08.226385000 +0200
+@@ -4,6 +4,7 @@
+ #include "buffer.h"
+ #include "strerr.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "uint16.h"
+ #include "ndelay.h"
+ #include "socket.h"
+@@ -11,13 +12,16 @@
+ #include "qlog.h"
+ #include "response.h"
+ #include "dns.h"
++#include "alloc.h"
++#include "iopause.h"
++#include "str.h"
+ 
+ extern char *fatal;
+ extern char *starting;
+ extern int respond(char *,char *,char *);
+ extern void initialize(void);
+ 
+-static char ip[4];
++static char ip[16];
+ static uint16 port;
+ 
+ static char buf[513];
+@@ -25,6 +29,11 @@
+ 
+ static char *q;
+ 
++void nomem()
++{
++  strerr_die2x(111,fatal,"out of memory");
++}
++
+ static int doit(void)
+ {
+   unsigned int pos;
+@@ -82,35 +91,86 @@
+ int main()
+ {
+   char *x;
+-  int udp53;
++  int *udp53;
++  unsigned int off;
++  unsigned int cnt;
++  iopause_fd *iop;
+ 
+   x = env_get("IP");
+   if (!x)
+     strerr_die2x(111,fatal,"$IP not set");
+-  if (!ip4_scan(x,ip))
+-    strerr_die3x(111,fatal,"unable to parse IP address ",x);
+-
+-  udp53 = socket_udp();
+-  if (udp53 == -1)
+-    strerr_die2sys(111,fatal,"unable to create UDP socket: ");
+-  if (socket_bind4_reuse(udp53,ip,53) == -1)
+-    strerr_die2sys(111,fatal,"unable to bind UDP socket: ");
+-
++  off=cnt=0;
++  while (x[off]) {
++    unsigned int l;
++    char dummy[16];
++    l=ip6_scan(x+off,dummy);
++    if (!l)
++      strerr_die3x(111,fatal,"unable to parse IP address ",x+off);
++    cnt++;
++    if (!x[off+l]) break;
++    if (x[off+l]=='%')
++      while (x[off+l] && x[off+l]!=',') ++l;
++    if (x[off+l]!=',')
++      strerr_die3x(111,fatal,"unable to parse IP address ",x+off);
++    off+=l+1;
++  }
++  udp53=(int *) alloc(sizeof(int) *cnt);
++  if (!udp53) nomem();
++  iop=(iopause_fd *) alloc(sizeof(*iop) * cnt);
++  if (!iop) nomem();
++
++  off=cnt=0;
++  while (x[off]) {
++    unsigned int l;
++    uint32 ifid=0;
++    l=ip6_scan(x+off,ip);
++    udp53[cnt] = socket_udp6();
++    if (udp53[cnt] == -1)
++      strerr_die2sys(111,fatal,"unable to create UDP socket: ");
++    if (x[off+l]=='%') {
++      char* interface=x+off+l+1;
++      int Len=str_chr(interface,',');
++      if (interface[Len]) {
++	interface[Len]=0;
++	ifid=socket_getifidx(interface);
++	interface[Len]=',';
++      } else
++	ifid=socket_getifidx(interface);
++      l+=Len;
++    }
++    if (socket_bind6_reuse(udp53[cnt],ip,53,ifid) == -1)
++      strerr_die2sys(111,fatal,"unable to bind UDP socket: ");
++    ndelay_off(udp53[cnt]);
++    socket_tryreservein(udp53[cnt],65536);
++    iop[cnt].fd=udp53[cnt];
++    iop[cnt].events=IOPAUSE_READ;
++    cnt++;
++    if (!x[off+l]) break;
++    off+=l+1;
++  }
+   droproot(fatal);
+ 
+   initialize();
+-  
+-  ndelay_off(udp53);
+-  socket_tryreservein(udp53,65536);
+ 
+   buffer_putsflush(buffer_2,starting);
+ 
+   for (;;) {
+-    len = socket_recv4(udp53,buf,sizeof buf,ip,&port);
+-    if (len < 0) continue;
+-    if (!doit()) continue;
+-    if (response_len > 512) response_tc();
+-    socket_send4(udp53,response,response_len,ip,port);
+-    /* may block for buffer space; if it fails, too bad */
++    struct taia stamp;
++    struct taia deadline;
++    unsigned int i;
++    uint32 ifid;
++    taia_now(&stamp);
++    taia_uint(&deadline,300);
++    taia_add(&deadline,&deadline,&stamp);
++    iopause(iop,cnt,&deadline,&stamp);
++    for (i=0;i<cnt;i++)
++      if (iop[i].revents) {
++	len = socket_recv6(udp53[i],buf,sizeof buf,ip,&port,&ifid);
++	if (len < 0) continue;
++	if (!doit()) continue;
++	if (response_len > 512) response_tc();
++	socket_send6(udp53[i],response,response_len,ip,port,ifid);
++	/* may block for buffer space; if it fails, too bad */
++      }
+   }
+ }
+diff -uNr djbdns-1.05/sockaddr_in6.h1 djbdns-1.05-ipv6/sockaddr_in6.h1
+--- djbdns-1.05/sockaddr_in6.h1	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/sockaddr_in6.h1	2005-09-08 21:58:08.226385000 +0200
+@@ -0,0 +1,21 @@
++#include "haveip6.h"
++#ifdef LIBC_HAS_IP6
++#include <sys/types.h>
++#include <sys/socket.h>
++#define sockaddr_in6 blub
++#include <netinet/in.h>
++#undef sockaddr_in6
++
++struct sockaddr_in6 {
++  sa_family_t     sin6_family;    /* AF_INET6 */
++  unsigned short  sin6_port;      /* transport layer port # */
++  uint32_t        sin6_flowinfo;  /* IPv6 traffic class & flow info */
++  struct in6_addr sin6_addr;      /* IPv6 address */
++  uint32_t        sin6_scope_id;  /* set of interfaces for a scope */
++};
++
++#else
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#endif
+diff -uNr djbdns-1.05/sockaddr_in6.h2 djbdns-1.05-ipv6/sockaddr_in6.h2
+--- djbdns-1.05/sockaddr_in6.h2	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/sockaddr_in6.h2	2005-09-08 21:58:08.226385000 +0200
+@@ -0,0 +1,4 @@
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++
+diff -uNr djbdns-1.05/socket.h djbdns-1.05-ipv6/socket.h
+--- djbdns-1.05/socket.h	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/socket.h	2005-09-08 21:58:08.230385250 +0200
+@@ -2,21 +2,37 @@
+ #define SOCKET_H
+ 
+ #include "uint16.h"
++#include "uint32.h"
+ 
+ extern int socket_tcp(void);
+ extern int socket_udp(void);
++extern int socket_tcp6(void);
++extern int socket_udp6(void);
+ 
+ extern int socket_connect4(int,const char *,uint16);
++extern int socket_connect6(int s,const char ip[16],uint16 port,uint32 scope_id);
+ extern int socket_connected(int);
+-extern int socket_bind4(int,char *,uint16);
++extern int socket_bind4(int,const char *,uint16);
+ extern int socket_bind4_reuse(int,char *,uint16);
++extern int socket_bind6(int s,const char *ip,uint16 port,uint32 scope_id);
++extern int socket_bind6_reuse(int s,const char *ip,uint16 port,uint32 scope_id);
+ extern int socket_listen(int,int);
+ extern int socket_accept4(int,char *,uint16 *);
++extern int socket_accept6(int s,char *ip,uint16 *port,uint32 *scope_id);
+ extern int socket_recv4(int,char *,int,char *,uint16 *);
+ extern int socket_send4(int,const char *,int,const char *,uint16);
++extern int socket_recv6(int s,char *buf,unsigned int len,char *ip,uint16 *port,uint32 *scope_id);
++extern int socket_send6(int s,const char *buf,unsigned int len,const char *ip,uint16 port,uint32 scope_id);
+ extern int socket_local4(int,char *,uint16 *);
+ extern int socket_remote4(int,char *,uint16 *);
++extern int socket_local6(int s,char *ip,uint16 *port,uint32 *scope_id);
++extern int socket_remote6(int s,char *ip,uint16 *port,uint32 *scope_id);
+ 
+ extern void socket_tryreservein(int,int);
+ 
++extern const char* socket_getifname(uint32 interface);
++extern uint32 socket_getifidx(const char *ifname);
++
++extern int noipv6;
++
+ #endif
+diff -uNr djbdns-1.05/socket_accept6.c djbdns-1.05-ipv6/socket_accept6.c
+--- djbdns-1.05/socket_accept6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/socket_accept6.c	2005-09-08 21:58:08.230385250 +0200
+@@ -0,0 +1,43 @@
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include "byte.h"
++#include "socket.h"
++#include "ip6.h"
++#include "haveip6.h"
++#include "error.h"
++
++int socket_accept6(int s,char ip[16],uint16 *port,uint32 *scope_id)
++{
++#ifdef LIBC_HAS_IP6
++  struct sockaddr_in6 sa;
++#else
++  struct sockaddr_in sa;
++#endif
++  unsigned int dummy = sizeof sa;
++  int fd;
++
++  fd = accept(s,(struct sockaddr *) &sa,&dummy);
++  if (fd == -1) return -1;
++
++#ifdef LIBC_HAS_IP6
++  if (sa.sin6_family==AF_INET) {
++    struct sockaddr_in *sa4=(struct sockaddr_in*)&sa;
++    byte_copy(ip,12,V4mappedprefix);
++    byte_copy(ip+12,4,(char *) &sa4->sin_addr);
++    uint16_unpack_big((char *) &sa4->sin_port,port);
++    return fd;
++  }
++  byte_copy(ip,16,(char *) &sa.sin6_addr);
++  uint16_unpack_big((char *) &sa.sin6_port,port);
++  if (scope_id) *scope_id=sa.sin6_scope_id;
++
++  return fd;
++#else
++  byte_copy(ip,12,V4mappedprefix);
++  byte_copy(ip+12,4,(char *) &sa.sin_addr);
++  uint16_unpack_big((char *) &sa.sin_port,port);
++  if (scope_id) *scope_id=0;
++  return fd;
++#endif
++}
+diff -uNr djbdns-1.05/socket_bind.c djbdns-1.05-ipv6/socket_bind.c
+--- djbdns-1.05/socket_bind.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/socket_bind.c	2005-09-08 21:58:08.230385250 +0200
+@@ -5,7 +5,7 @@
+ #include "byte.h"
+ #include "socket.h"
+ 
+-int socket_bind4(int s,char ip[4],uint16 port)
++int socket_bind4(int s,const char ip[4],uint16 port)
+ {
+   struct sockaddr_in sa;
+ 
+diff -uNr djbdns-1.05/socket_bind6.c djbdns-1.05-ipv6/socket_bind6.c
+--- djbdns-1.05/socket_bind6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/socket_bind6.c	2005-09-08 21:58:08.234385500 +0200
+@@ -0,0 +1,43 @@
++#include <sys/param.h>
++#include "sockaddr_in6.h"
++#include "byte.h"
++#include "socket.h"
++#include "ip6.h"
++#include "haveip6.h"
++#include "error.h"
++
++int socket_bind6(int s,const char ip[16],uint16 port,uint32 scope_id)
++{
++#ifdef LIBC_HAS_IP6
++  struct sockaddr_in6 sa;
++
++  if (noipv6) {
++#endif
++    int i;
++    for (i=0; i<16; i++)
++      if (ip[i]!=0) break;
++    if (i==16 || ip6_isv4mapped(ip))
++      return socket_bind4(s,ip+12,port);
++#ifdef LIBC_HAS_IP6
++  }
++  byte_zero(&sa,sizeof sa);
++  sa.sin6_family = AF_INET6;
++  uint16_pack_big((char *) &sa.sin6_port,port);
++/*  implicit: sa.sin6_flowinfo = 0; */
++  byte_copy((char *) &sa.sin6_addr,16,ip);
++  sa.sin6_scope_id=scope_id;
++
++  return bind(s,(struct sockaddr *) &sa,sizeof sa);
++#else
++  errno=error_proto;
++  return -1;
++#endif
++}
++
++int socket_bind6_reuse(int s,const char ip[16],uint16 port,uint32 scope_id)
++{
++  int opt = 1;
++  setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt);
++  return socket_bind6(s,ip,port,scope_id);
++}
++
+diff -uNr djbdns-1.05/socket_connect6.c djbdns-1.05-ipv6/socket_connect6.c
+--- djbdns-1.05/socket_connect6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/socket_connect6.c	2005-09-08 21:58:32.871925250 +0200
+@@ -0,0 +1,39 @@
++#include <sys/param.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <errno.h>
++#include "byte.h"
++#include "socket.h"
++#include "ip6.h"
++#include "haveip6.h"
++#include "error.h"
++#include "uint32.h"
++#include "ip4.h"
++
++int socket_connect6(int s,const char ip[16],uint16 port,uint32 scope_id)
++{
++#ifdef LIBC_HAS_IP6
++  struct sockaddr_in6 sa;
++
++  if (noipv6) {
++#endif
++    if (ip6_isv4mapped(ip))
++      return socket_connect4(s,ip+12,port);
++    if (byte_equal(ip,16,V6loopback))
++      return socket_connect4(s,ip4loopback,port);
++#ifdef LIBC_HAS_IP6
++  }
++  byte_zero(&sa,sizeof sa);
++  sa.sin6_family = PF_INET6;
++  uint16_pack_big((char *) &sa.sin6_port,port);
++  sa.sin6_flowinfo = 0;
++  sa.sin6_scope_id = scope_id;
++  byte_copy((char *) &sa.sin6_addr,16,ip);
++
++  return connect(s,(struct sockaddr *) &sa,sizeof sa);
++#else
++  errno=error_proto;
++  return -1;
++#endif
++}
+diff -uNr djbdns-1.05/socket_getifidx.c djbdns-1.05-ipv6/socket_getifidx.c
+--- djbdns-1.05/socket_getifidx.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/socket_getifidx.c	2005-09-08 21:58:08.234385500 +0200
+@@ -0,0 +1,13 @@
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <net/if.h>
++#include "socket.h"
++#include "haven2i.h"
++
++uint32 socket_getifidx(const char* ifname) {
++#ifdef HAVE_N2I
++  return if_nametoindex(ifname);
++#else
++  return 0;
++#endif
++}
+diff -uNr djbdns-1.05/socket_noipv6.c djbdns-1.05-ipv6/socket_noipv6.c
+--- djbdns-1.05/socket_noipv6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/socket_noipv6.c	2005-09-08 21:58:08.234385500 +0200
+@@ -0,0 +1,7 @@
++#include "haveip6.h"
++
++#ifdef LIBC_HAS_IP6
++int noipv6=0;
++#else
++int noipv6=1;
++#endif
+diff -uNr djbdns-1.05/socket_recv6.c djbdns-1.05-ipv6/socket_recv6.c
+--- djbdns-1.05/socket_recv6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/socket_recv6.c	2005-09-08 21:58:08.238385750 +0200
+@@ -0,0 +1,42 @@
++#include <sys/param.h>
++#include "sockaddr_in6.h"
++#include "byte.h"
++#include "socket.h"
++#include "ip6.h"
++#include "haveip6.h"
++#include "error.h"
++
++int socket_recv6(int s,char *buf,unsigned int len,char ip[16],uint16 *port,uint32 *scope_id)
++{
++#ifdef LIBC_HAS_IP6
++  struct sockaddr_in6 sa;
++#else
++  struct sockaddr_in sa;
++#endif
++  unsigned int dummy = sizeof sa;
++  int r;
++
++  byte_zero(&sa,dummy);
++  r = recvfrom(s,buf,len,0,(struct sockaddr *) &sa,&dummy);
++  if (r == -1) return -1;
++
++#ifdef LIBC_HAS_IP6
++  if (noipv6) {
++    struct sockaddr_in *sa4=(struct sockaddr_in *)&sa;
++    byte_copy(ip,12,V4mappedprefix);
++    byte_copy(ip+12,4,(char *) &sa4->sin_addr);
++    uint16_unpack_big((char *) &sa4->sin_port,port);
++    return r;
++  }
++  byte_copy(ip,16,(char *) &sa.sin6_addr);
++  uint16_unpack_big((char *) &sa.sin6_port,port);
++  if (scope_id) *scope_id=sa.sin6_scope_id;
++#else
++  byte_copy(ip,12,(char *)V4mappedprefix);
++  byte_copy(ip+12,4,(char *) &sa.sin_addr);
++  uint16_unpack_big((char *) &sa.sin_port,port);
++  if (scope_id) *scope_id=0;
++#endif
++
++  return r;
++}
+diff -uNr djbdns-1.05/socket_send6.c djbdns-1.05-ipv6/socket_send6.c
+--- djbdns-1.05/socket_send6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/socket_send6.c	2005-09-08 21:58:08.238385750 +0200
+@@ -0,0 +1,39 @@
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include "byte.h"
++#include "socket.h"
++#include "ip6.h"
++#include "haveip6.h"
++#include "error.h"
++
++int socket_send6(int s,const char *buf,unsigned int len,const char ip[16],uint16 port,uint32 scope_id)
++{
++#ifdef LIBC_HAS_IP6
++  struct sockaddr_in6 sa;
++#else
++  struct sockaddr_in sa;
++#endif
++
++  byte_zero(&sa,sizeof sa);
++#ifdef LIBC_HAS_IP6
++  if (noipv6) {
++#endif
++    if (ip6_isv4mapped(ip))
++      return socket_send4(s,buf,len,ip+12,port);
++    if (byte_equal(ip,16,V6loopback))
++      return socket_send4(s,buf,len,ip4loopback,port);
++#ifdef LIBC_HAS_IP6
++    errno=error_proto;
++    return -1;
++  }
++  sa.sin6_family = AF_INET6;
++  uint16_pack_big((char *) &sa.sin6_port,port);
++  byte_copy((char *) &sa.sin6_addr,16,ip);
++  return sendto(s,buf,len,0,(struct sockaddr *) &sa,sizeof sa);
++#else
++  errno=error_proto;
++  return -1;
++#endif
++}
+diff -uNr djbdns-1.05/socket_tcp6.c djbdns-1.05-ipv6/socket_tcp6.c
+--- djbdns-1.05/socket_tcp6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/socket_tcp6.c	2005-09-08 22:04:31.194319000 +0200
+@@ -0,0 +1,44 @@
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <errno.h>
++#include <unistd.h>
++#include "ndelay.h"
++#include "socket.h"
++#include "haveip6.h"
++#include "error.h"
++
++#ifndef EAFNOSUPPORT
++#define EAFNOSUPPORT EINVAL
++#endif
++
++int socket_tcp6(void)
++{
++#ifdef LIBC_HAS_IP6
++  int s;
++
++  if (noipv6) goto compat;
++  s = socket(PF_INET6,SOCK_STREAM,0);
++  if (s == -1) {
++    if (errno == EINVAL || errno == EAFNOSUPPORT) {
++compat:
++      s=socket(AF_INET,SOCK_STREAM,0);
++      noipv6=1;
++      if (s==-1) return -1;
++    } else
++    return -1;
++  }
++  if (ndelay_on(s) == -1) { close(s); return -1; }
++#ifdef IPV6_V6ONLY
++  {
++    int zero=0;
++    setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&zero,sizeof(zero));
++  }
++#endif
++  return s;
++#else
++  return socket_tcp();
++#endif
++}
++
+diff -uNr djbdns-1.05/socket_udp6.c djbdns-1.05-ipv6/socket_udp6.c
+--- djbdns-1.05/socket_udp6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/socket_udp6.c	2005-09-08 22:04:23.577843000 +0200
+@@ -0,0 +1,43 @@
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <errno.h>
++#include <unistd.h>
++#include "ndelay.h"
++#include "socket.h"
++#include "haveip6.h"
++#include "error.h"
++
++#ifndef EAFNOSUPPORT
++#define EAFNOSUPPORT EINVAL
++#endif
++
++int socket_udp6(void)
++{
++#ifdef LIBC_HAS_IP6
++  int s;
++
++  if (noipv6) goto compat;
++  s = socket(PF_INET6,SOCK_DGRAM,0);
++  if (s == -1) {
++    if (errno == EINVAL || errno == EAFNOSUPPORT) {
++compat:
++      s=socket(AF_INET,SOCK_DGRAM,0);
++      noipv6=1;
++      if (s==-1) return -1;
++    } else
++    return -1;
++  }
++  if (ndelay_on(s) == -1) { close(s); return -1; }
++#ifdef IPV6_V6ONLY
++  {
++    int zero=0;
++    setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&zero,sizeof(zero));
++  }
++#endif
++  return s;
++#else
++  return socket_udp();
++#endif
++}
+diff -uNr djbdns-1.05/tdlookup.c djbdns-1.05-ipv6/tdlookup.c
+--- djbdns-1.05/tdlookup.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/tdlookup.c	2005-09-08 21:58:08.242386000 +0200
+@@ -8,6 +8,7 @@
+ #include "dns.h"
+ #include "seek.h"
+ #include "response.h"
++#include "ip6.h"
+ 
+ static int want(const char *owner,const char type[2])
+ {
+@@ -119,8 +120,9 @@
+   char x[20];
+   uint16 u16;
+   char addr[8][4];
+-  int addrnum;
+-  uint32 addrttl;
++  char addr6[8][16];
++  int addrnum,addr6num;
++  uint32 addrttl,addr6ttl;
+   int i;
+ 
+   anpos = response_len;
+@@ -152,8 +154,8 @@
+   wild = q;
+ 
+   for (;;) {
+-    addrnum = 0;
+-    addrttl = 0;
++    addrnum = addr6num = 0;
++    addrttl = addr6ttl = 0;
+     cdb_findstart(&c);
+     while (r = find(wild,wild != q)) {
+       if (r == -1) return 0;
+@@ -171,6 +173,17 @@
+ 	if (addrnum < 1000000) ++addrnum;
+ 	continue;
+       }
++      if (byte_equal(type,2,DNS_T_AAAA) && (dlen - dpos == 16)) {
++	addr6ttl = ttl;
++	i = dns_random(addr6num + 1);
++	if (i < 8) {
++	  if ((i < addr6num) && (addr6num < 8))
++	    byte_copy(addr6[addr6num],16,addr6[i]);
++	  byte_copy(addr6[i],16,data + dpos);
++	}
++	if (addr6num < 1000000) ++addr6num;
++	continue;
++      }
+       if (!response_rstart(q,type,ttl)) return 0;
+       if (byte_equal(type,2,DNS_T_NS) || byte_equal(type,2,DNS_T_CNAME) || byte_equal(type,2,DNS_T_PTR)) {
+ 	if (!doname()) return 0;
+@@ -195,6 +208,12 @@
+ 	if (!response_addbytes(addr[i],4)) return 0;
+ 	response_rfinish(RESPONSE_ANSWER);
+       }
++    for (i = 0;i < addr6num;++i)
++      if (i < 8) {
++	if (!response_rstart(q,DNS_T_AAAA,addr6ttl)) return 0;
++	if (!response_addbytes(addr6[i],16)) return 0;
++	response_rfinish(RESPONSE_ANSWER);
++      }
+ 
+     if (flagfound) break;
+     if (wild == control) break;
+@@ -259,6 +278,11 @@
+ 	    if (!dobytes(4)) return 0;
+             response_rfinish(RESPONSE_ADDITIONAL);
+ 	  }
++	  else if (byte_equal(type,2,DNS_T_AAAA)) {
++            if (!response_rstart(d1,DNS_T_AAAA,ttl)) return 0;
++	    if (!dobytes(16)) return 0;
++            response_rfinish(RESPONSE_ADDITIONAL);
++	  }
+         }
+       }
+     }
+@@ -278,7 +302,7 @@
+   return 1;
+ }
+ 
+-int respond(char *q,char qtype[2],char ip[4])
++int respond(char *q,char qtype[2],char ip[16])
+ {
+   int fd;
+   int r;
+@@ -292,15 +316,17 @@
+   byte_zero(clientloc,2);
+   key[0] = 0;
+   key[1] = '%';
+-  byte_copy(key + 2,4,ip);
+-  r = cdb_find(&c,key,6);
+-  if (!r) r = cdb_find(&c,key,5);
+-  if (!r) r = cdb_find(&c,key,4);
+-  if (!r) r = cdb_find(&c,key,3);
+-  if (!r) r = cdb_find(&c,key,2);
+-  if (r == -1) return 0;
+-  if (r && (cdb_datalen(&c) == 2))
+-    if (cdb_read(&c,clientloc,2,cdb_datapos(&c)) == -1) return 0;
++  if (byte_equal(ip,12,V4mappedprefix)) {
++    byte_copy(key + 2,4,ip+12);
++    r = cdb_find(&c,key,6);
++    if (!r) r = cdb_find(&c,key,5);
++    if (!r) r = cdb_find(&c,key,4);
++    if (!r) r = cdb_find(&c,key,3);
++    if (!r) r = cdb_find(&c,key,2);
++    if (r == -1) return 0;
++    if (r && (cdb_datalen(&c) == 2))
++      if (cdb_read(&c,clientloc,2,cdb_datapos(&c)) == -1) return 0;
++  }
+ 
+   r = doit(q,qtype);
+ 
+diff -uNr djbdns-1.05/tinydns-conf.c djbdns-1.05-ipv6/tinydns-conf.c
+--- djbdns-1.05/tinydns-conf.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/tinydns-conf.c	2005-09-08 21:58:08.242386000 +0200
+@@ -82,6 +82,18 @@
+   finish();
+   perm(0755);
+ 
++  start("root/add-host6");
++  outs("#!/bin/sh\nexec ");
++  outs(auto_home); outs("/bin/tinydns-edit data data.new add host6 ${1+\"$@\"}\n");
++  finish();
++  perm(0755);
++
++  start("root/add-alias6");
++  outs("#!/bin/sh\nexec ");
++  outs(auto_home); outs("/bin/tinydns-edit data data.new add alias6 ${1+\"$@\"}\n");
++  finish();
++  perm(0755);
++
+   start("root/add-mx");
+   outs("#!/bin/sh\nexec ");
+   outs(auto_home); outs("/bin/tinydns-edit data data.new add mx ${1+\"$@\"}\n");
+diff -uNr djbdns-1.05/tinydns-data.c djbdns-1.05-ipv6/tinydns-data.c
+--- djbdns-1.05/tinydns-data.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/tinydns-data.c	2005-09-08 21:58:08.246386250 +0200
+@@ -8,6 +8,7 @@
+ #include "byte.h"
+ #include "fmt.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "exit.h"
+ #include "case.h"
+ #include "scan.h"
+@@ -172,6 +173,7 @@
+ static char *d1;
+ static char *d2;
+ char dptr[DNS_NAME4_DOMAIN];
++char d6ptr[DNS_NAME6_DOMAIN];
+ 
+ char strnum[FMT_ULONG];
+ 
+@@ -193,6 +195,7 @@
+   char loc[2];
+   unsigned long u;
+   char ip[4];
++  char ip6[16];
+   char type[2];
+   char soa[20];
+   char buf[4];
+@@ -339,6 +342,33 @@
+ 	}
+ 	break;
+ 
++      case '6': case '3':
++	if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
++	if (!stralloc_0(&f[2])) nomem();
++	if (!scan_ulong(f[2].s,&ttl)) ttl = TTL_POSITIVE;
++	ttdparse(&f[3],ttd);
++	locparse(&f[4],loc);
++
++	if (!stralloc_0(&f[1])) nomem();
++	if (ip6_scan_flat(f[1].s,ip6)) {
++	  rr_start(DNS_T_AAAA,ttl,ttd,loc);
++	  rr_add(ip6,16);
++	  rr_finish(d1);
++
++	  if (line.s[0] == '6') {	/* emit both .ip6.arpa and .ip6.int */
++	    dns_name6_domain(d6ptr,ip6,DNS_IP6_ARPA);
++	    rr_start(DNS_T_PTR,ttl,ttd,loc);
++	    rr_addname(d1);
++	    rr_finish(d6ptr);
++
++	    dns_name6_domain(d6ptr,ip6,DNS_IP6_INT);
++	    rr_start(DNS_T_PTR,ttl,ttd,loc);
++	    rr_addname(d1);
++	    rr_finish(d6ptr);
++	  }
++	}
++	break;
++
+       case '@':
+ 	if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
+ 	if (!stralloc_0(&f[4])) nomem();
+diff -uNr djbdns-1.05/tinydns-edit.c djbdns-1.05-ipv6/tinydns-edit.c
+--- djbdns-1.05/tinydns-edit.c	2001-02-11 22:11:45.000000000 +0100
++++ djbdns-1.05-ipv6/tinydns-edit.c	2005-09-08 21:58:08.246386250 +0200
+@@ -13,6 +13,7 @@
+ #include "str.h"
+ #include "fmt.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "dns.h"
+ 
+ #define FATAL "tinydns-edit: fatal: "
+@@ -25,7 +26,8 @@
+ 
+ void die_usage()
+ {
+-  strerr_die1x(100,"tinydns-edit: usage: tinydns-edit data data.new add [ns|childns|host|alias|mx] domain a.b.c.d");
++  strerr_die1x(100,"tinydns-edit: usage: tinydns-edit data data.new add [ns|childns|host|alias|mx] domain a.b.c.d\n"
++                   "tinydns-edit: usage: tinydns-edit data data.new add [host6|alias6] domain a:b:c:d:e:f:g:h");
+ }
+ void nomem()
+ {
+@@ -43,6 +45,7 @@
+ char mode;
+ static char *target;
+ char targetip[4];
++char targetip6[16];
+ 
+ int fd;
+ buffer b;
+@@ -61,7 +64,9 @@
+ static char *d1;
+ static char *d2;
+ char ip[4];
++char ip6[16];
+ char ipstr[IP4_FMT];
++char ip6str[IP6_FMT];
+ char strnum[FMT_ULONG];
+ 
+ static char *names[26];
+@@ -96,7 +101,9 @@
+   if (str_equal(*argv,"ns")) mode = '.';
+   else if (str_equal(*argv,"childns")) mode = '&';
+   else if (str_equal(*argv,"host")) mode = '=';
++  else if (str_equal(*argv,"host6")) mode = '6';
+   else if (str_equal(*argv,"alias")) mode = '+';
++  else if (str_equal(*argv,"alias6")) mode = '3';
+   else if (str_equal(*argv,"mx")) mode = '@';
+   else die_usage();
+ 
+@@ -104,7 +111,11 @@
+   if (!dns_domain_fromdot(&target,*argv,str_len(*argv))) nomem();
+ 
+   if (!*++argv) die_usage();
+-  if (!ip4_scan(*argv,targetip)) die_usage();
++  if (mode == '6' || mode == '3') {
++    if (!ip6_scan(*argv,targetip6)) die_usage();
++  } else {
++    if (!ip4_scan(*argv,targetip)) die_usage();
++  }
+ 
+   umask(077);
+ 
+@@ -129,7 +140,7 @@
+ 	if (!dns_domain_fromdot(&names[i],f[0].s,f[0].len)) nomem();
+       }
+       break;
+-    case '+': case '=':
++    case '+': case '=': case '6': case '3':
+       ttl = TTL_POSITIVE;
+       break;
+     case '@':
+@@ -203,6 +214,18 @@
+ 	}
+ 	break;
+ 
++      case '6':
++	if (line.s[0] == '6') {
++	  if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
++	  if (dns_domain_equal(d1,target))
++	    strerr_die2x(100,FATAL,"host name already used");
++	  if (!stralloc_0(&f[1])) nomem();
++	  if (ip6_scan(f[1].s,ip6))
++	    if (byte_equal(ip,16,targetip6))
++	      strerr_die2x(100,FATAL,"IPv6 address already used");
++	}
++	break;
++
+       case '@':
+ 	if (line.s[0] == '@') {
+           if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
+@@ -228,7 +251,11 @@
+   if (!stralloc_copyb(&f[0],&mode,1)) nomem();
+   if (!dns_domain_todot_cat(&f[0],target)) nomem();
+   if (!stralloc_cats(&f[0],":")) nomem();
+-  if (!stralloc_catb(&f[0],ipstr,ip4_fmt(ipstr,targetip))) nomem();
++  if (mode == '6' || mode == '3') {
++    if (!stralloc_catb(&f[0],ip6str,ip6_fmt_flat(ip6str,targetip6))) nomem();
++  } else {
++    if (!stralloc_catb(&f[0],ipstr,ip4_fmt(ipstr,targetip))) nomem();
++  }
+   switch(mode) {
+     case '.': case '&': case '@':
+       for (i = 0;i < 26;++i)
+diff -uNr djbdns-1.05/tryip6.c djbdns-1.05-ipv6/tryip6.c
+--- djbdns-1.05/tryip6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/tryip6.c	2005-09-08 21:58:08.246386250 +0200
+@@ -0,0 +1,8 @@
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++
++main() {
++  struct sockaddr_in6 sa;
++  sa.sin6_family = PF_INET6;
++}
+diff -uNr djbdns-1.05/tryn2i.c djbdns-1.05-ipv6/tryn2i.c
+--- djbdns-1.05/tryn2i.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/tryn2i.c	2005-09-08 21:58:08.246386250 +0200
+@@ -0,0 +1,8 @@
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <net/if.h>
++
++int main() {
++  static char ifname[IFNAMSIZ];
++  char *tmp=if_indextoname(0,ifname);
++}
+diff -uNr djbdns-1.05/trysa6.c djbdns-1.05-ipv6/trysa6.c
+--- djbdns-1.05/trysa6.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05-ipv6/trysa6.c	2005-09-08 21:58:08.250386500 +0200
+@@ -0,0 +1,8 @@
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++
++main() {
++  struct sockaddr_in6 sa;
++  sa.sin6_scope_id = 1;
++}
diff --git a/package/djbdns/djbdns-02-cross.patch b/package/djbdns/djbdns-02-cross.patch
new file mode 100644
index 0000000..39ce701
--- /dev/null
+++ b/package/djbdns/djbdns-02-cross.patch
@@ -0,0 +1,198 @@
+diff -ruN djbdns-1.05.orig/auto_home.c djbdns-1.05/auto_home.c
+--- djbdns-1.05.orig/auto_home.c	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05/auto_home.c	2011-01-08 12:30:51.000000000 +0100
+@@ -0,0 +1,3 @@
++const char auto_home[] = "\
++\057\165\163\162\
++";
+diff -ruN djbdns-1.05.orig/direntry.h djbdns-1.05/direntry.h
+--- djbdns-1.05.orig/direntry.h	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05/direntry.h	2011-01-08 12:28:43.000000000 +0100
+@@ -0,0 +1,10 @@
++#ifndef DIRENTRY_H
++#define DIRENTRY_H
++
++/* sysdep: +dirent */
++
++#include <sys/types.h>
++#include <dirent.h>
++#define direntry struct dirent
++
++#endif
+diff -ruN djbdns-1.05.orig/hasdevtcp.h djbdns-1.05/hasdevtcp.h
+--- djbdns-1.05.orig/hasdevtcp.h	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05/hasdevtcp.h	2011-01-08 12:28:43.000000000 +0100
+@@ -0,0 +1 @@
++/* sysdep: -devtcp */
+diff -ruN djbdns-1.05.orig/hasshsgr.h djbdns-1.05/hasshsgr.h
+--- djbdns-1.05.orig/hasshsgr.h	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05/hasshsgr.h	2011-01-08 12:28:43.000000000 +0100
+@@ -0,0 +1 @@
++/* sysdep: -shortsetgroups */
+diff -ruN djbdns-1.05.orig/haven2i.h djbdns-1.05/haven2i.h
+--- djbdns-1.05.orig/haven2i.h	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05/haven2i.h	2011-01-08 12:28:43.000000000 +0100
+@@ -0,0 +1 @@
++#define HAVE_N2I
+diff -ruN djbdns-1.05.orig/iopause.h djbdns-1.05/iopause.h
+--- djbdns-1.05.orig/iopause.h	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05/iopause.h	2011-01-08 12:28:43.000000000 +0100
+@@ -0,0 +1,18 @@
++#ifndef IOPAUSE_H
++#define IOPAUSE_H
++
++/* sysdep: +poll */
++#define IOPAUSE_POLL
++
++#include <sys/types.h>
++#include <poll.h>
++
++typedef struct pollfd iopause_fd;
++#define IOPAUSE_READ POLLIN
++#define IOPAUSE_WRITE POLLOUT
++
++#include "taia.h"
++
++extern void iopause(iopause_fd *,unsigned int,struct taia *,struct taia *);
++
++#endif
+diff -ruN djbdns-1.05.orig/Makefile djbdns-1.05/Makefile
+--- djbdns-1.05.orig/Makefile	2011-01-07 16:30:44.000000000 +0100
++++ djbdns-1.05/Makefile	2011-01-08 12:31:07.000000000 +0100
+@@ -29,10 +29,6 @@
+ compile auto-str.c buffer.h exit.h
+ 	./compile auto-str.c
+ 
+-auto_home.c: \
+-auto-str conf-home
+-	./auto-str auto_home `head -1 conf-home` > auto_home.c
+-
+ auto_home.o: \
+ compile auto_home.c
+ 	./compile auto_home.c
+@@ -223,10 +219,6 @@
+ uint64.h taia.h dd.h
+ 	./compile dd.c
+ 
+-direntry.h: \
+-choose compile trydrent.c direntry.h1 direntry.h2
+-	./choose c trydrent direntry.h1 direntry.h2 > direntry.h
+-
+ dns.a: \
+ makelib dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o dns_ipq.o dns_mx.o \
+ dns_name.o dns_nd.o dns_packet.o dns_random.o dns_rcip.o dns_rcrw.o \
+@@ -551,19 +543,6 @@
+ makelib sgetopt.o subgetopt.o
+ 	./makelib getopt.a sgetopt.o subgetopt.o
+ 
+-hasdevtcp.h: \
+-systype hasdevtcp.h1 hasdevtcp.h2
+-	( case "`cat systype`" in \
+-	  sunos-5.*) cat hasdevtcp.h2 ;; \
+-	  *) cat hasdevtcp.h1 ;; \
+-	esac ) > hasdevtcp.h
+-
+-hasshsgr.h: \
+-choose compile load tryshsgr.c hasshsgr.h1 hasshsgr.h2 chkshsgr \
+-warn-shsgr
+-	./chkshsgr || ( cat warn-shsgr; exit 1 )
+-	./choose clr tryshsgr hasshsgr.h1 hasshsgr.h2 > hasshsgr.h
+-
+ hier.o: \
+ compile hier.c auto_home.h
+ 	./compile hier.c
+@@ -584,10 +563,6 @@
+ compile instcheck.c strerr.h error.h exit.h
+ 	./compile instcheck.c
+ 
+-iopause.h: \
+-choose compile load trypoll.c iopause.h1 iopause.h2
+-	./choose clr trypoll iopause.h1 iopause.h2 > iopause.h
+-
+ iopause.o: \
+ compile iopause.c taia.h tai.h uint64.h select.h iopause.h taia.h
+ 	./compile iopause.c
+@@ -639,7 +614,7 @@
+ 	( cat warn-auto.sh; \
+ 	echo 'main="$$1"; shift'; \
+ 	echo 'rm -f "$$main"'; \
+-	echo 'ar cr "$$main" $${1+"$$@"}'; \
++	echo '$(AR) cr "$$main" $${1+"$$@"}'; \
+ 	case "`cat systype`" in \
+ 	sunos-5.*) ;; \
+ 	unix_sv*) ;; \
+@@ -648,7 +623,7 @@
+ 	dgux-*) ;; \
+ 	hp-ux-*) ;; \
+ 	sco*) ;; \
+-	*) echo 'ranlib "$$main"' ;; \
++	*) echo '$(RANLIB) "$$main"' ;; \
+ 	esac \
+ 	) > makelib
+ 	chmod 755 makelib
+@@ -922,11 +897,6 @@
+ compile socket_getifidx.c socket.h uint16.h uint32.h haven2i.h
+ 	./compile socket_getifidx.c
+ 
+-haven2i.h: \
+-tryn2i.c choose compile load socket.lib haven2i.h1 haven2i.h2
+-	cp /dev/null haven2i.h
+-	./choose cL tryn2i haven2i.h1 haven2i.h2 socket > haven2i.h
+-
+ str_chr.o: \
+ compile str_chr.c str.h
+ 	./compile str_chr.c
+@@ -1148,13 +1118,6 @@
+ compile uint16_unpack.c uint16.h
+ 	./compile uint16_unpack.c
+ 
+-uint32.h: \
+-tryulong32.c compile load uint32.h1 uint32.h2
+-	( ( ./compile tryulong32.c && ./load tryulong32 && \
+-	./tryulong32 ) >/dev/null 2>&1 \
+-	&& cat uint32.h2 || cat uint32.h1 ) > uint32.h
+-	rm -f tryulong32.o tryulong32
+-
+ uint32_pack.o: \
+ compile uint32_pack.c uint32.h
+ 	./compile uint32_pack.c
+@@ -1163,10 +1126,6 @@
+ compile uint32_unpack.c uint32.h
+ 	./compile uint32_unpack.c
+ 
+-uint64.h: \
+-choose compile load tryulong64.c uint64.h1 uint64.h2
+-	./choose clr tryulong64 uint64.h1 uint64.h2 > uint64.h
+-
+ unix.a: \
+ makelib buffer_read.o buffer_write.o error.o error_str.o ndelay_off.o \
+ ndelay_on.o open_read.o open_trunc.o openreadclose.o readclose.o \
+diff -ruN djbdns-1.05.orig/uint32.h djbdns-1.05/uint32.h
+--- djbdns-1.05.orig/uint32.h	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05/uint32.h	2011-01-08 12:29:18.000000000 +0100
+@@ -0,0 +1,12 @@
++#ifndef UINT32_H
++#define UINT32_H
++#include <stdint.h>
++
++typedef uint32_t uint32;
++
++extern void uint32_pack(char *,uint32);
++extern void uint32_pack_big(char *,uint32);
++extern void uint32_unpack(const char *,uint32 *);
++extern void uint32_unpack_big(const char *,uint32 *);
++
++#endif
+diff -ruN djbdns-1.05.orig/uint64.h djbdns-1.05/uint64.h
+--- djbdns-1.05.orig/uint64.h	1970-01-01 01:00:00.000000000 +0100
++++ djbdns-1.05/uint64.h	2011-01-08 12:29:25.000000000 +0100
+@@ -0,0 +1,9 @@
++#ifndef UINT64_H
++#define UINT64_H
++#include <stdint.h>
++
++/* sysdep: +ulong64 */
++
++typedef uint64_t uint64;
++
++#endif
diff --git a/package/djbdns/djbdns-03-dnsroot.patch b/package/djbdns/djbdns-03-dnsroot.patch
new file mode 100644
index 0000000..ce5b863
--- /dev/null
+++ b/package/djbdns/djbdns-03-dnsroot.patch
@@ -0,0 +1,19 @@
+--- a/dnsroots.global
++++ b/dnsroots.global
+@@ -1,5 +1,5 @@
+ 198.41.0.4
+-128.9.0.107
++192.228.79.201
+ 192.33.4.12
+ 128.8.10.90
+ 192.203.230.10
+@@ -7,7 +7,7 @@
+ 192.112.36.4
+ 128.63.2.53
+ 192.36.148.17
+-198.41.0.10
++192.58.128.30
+ 193.0.14.129
+-198.32.64.12
++199.7.83.42
+ 202.12.27.33
diff --git a/package/djbdns/djbdns-04-misformats-some-long-response-packets.patch b/package/djbdns/djbdns-04-misformats-some-long-response-packets.patch
new file mode 100644
index 0000000..28250c8
--- /dev/null
+++ b/package/djbdns/djbdns-04-misformats-some-long-response-packets.patch
@@ -0,0 +1,16 @@
+diff --git a/response.c b/response.c
+index ba90c89..33b2fb1 100644
+--- a/response.c
++++ b/response.c
+@@ -34,7 +34,7 @@ int response_addname(const char *d)
+         uint16_pack_big(buf,49152 + name_ptr[i]);
+         return response_addbytes(buf,2);
+       }
+-    if (dlen <= 128)
++    if ((dlen <= 128) && (response_len < 16384))
+       if (name_num < NAMES) {
+ 	byte_copy(name[name_num],dlen,d);
+ 	name_ptr[name_num] = response_len;
+-- 
+1.6.1.3
+
diff --git a/package/djbdns/djbdns.mk b/package/djbdns/djbdns.mk
new file mode 100644
index 0000000..b7ae99d
--- /dev/null
+++ b/package/djbdns/djbdns.mk
@@ -0,0 +1,40 @@
+#############################################################
+#
+# djbdns
+#
+#############################################################
+
+DJBDNS_VERSION = 1.05
+DJBDNS_SOURCE = djbdns-$(DJBDNS_VERSION).tar.gz
+DJBDNS_SITE = http://cr.yp.to/djbdns
+
+DJBDNS_TARGET_BINS= axfr-get axfrdns axfrdns-conf dnsfilter dnscache \
+	dnscache-conf dnsip dnsipq dnsmx dnsname dnsq dnsqr dnstrace \
+	dnstracesort dnstxt pickdns pickdns-conf pickdns-data random-ip \
+	rbldns rbldns-conf rbldns-data tinydns tinydns-conf tinydns-data \
+	tinydns-edit tinydns-get walldns walldns-conf
+
+define DJBDNS_BUILD_CMDS
+	echo '$(TARGET_CC) $(TARGET_CFLAGS)' > $(@D)/conf-cc
+	echo '$(TARGET_CC) -s $(TARGET_LDFLAGS)' > $(@D)/conf-ld
+	echo /usr > $(@D)/conf-home
+	AR='$(TARGET_AR)' \
+	   RANLIB='$(TARGET_RANLIB)' \
+	   $(MAKE) -C $(@D) haveip6.h
+	AR='$(TARGET_AR)' \
+	   RANLIB='$(TARGET_RANLIB)' \
+	   $(MAKE) -C $(@D)
+endef
+
+define DJBDNS_INSTALL_TARGET_CMDS
+	$(INSTALL) -D -m 0755 $(addprefix $(@D)/, $(DJBDNS_TARGET_BINS)) \
+		$(TARGET_DIR)/usr/bin/
+	$(INSTALL) -D -m 0644 $(@D)/dnsroots.global $(TARGET_DIR)/etc
+endef
+
+define DJBDNS_UNINSTALL_TARGET_CMDS
+	rm -f $(addprefix $(TARGET_DIR)/usr/bin/, $(DJBDNS_TARGET_BINS))
+	rm -f $(TARGET_DIR)/etc/dnsroots.global
+endef
+
+$(eval $(call GENTARGETS,package,djbdns))
diff --git a/package/ucspi-tcp/Config.in b/package/ucspi-tcp/Config.in
new file mode 100644
index 0000000..e936801
--- /dev/null
+++ b/package/ucspi-tcp/Config.in
@@ -0,0 +1,7 @@
+config BR2_PACKAGE_UCSPI_TCP
+	bool "ucspi-tcp"
+	help
+		tcpserver and tcpclient are command-line tools for building
+		TCP client-server applications.
+
+		http://cr.yp.to/ucspi-tcp.html
diff --git a/package/ucspi-tcp/cross.patch b/package/ucspi-tcp/cross.patch
new file mode 100644
index 0000000..4ba7c4f
--- /dev/null
+++ b/package/ucspi-tcp/cross.patch
@@ -0,0 +1,196 @@
+--- a/Makefile
++++ b/Makefile
+@@ -36,10 +36,6 @@ auto-str.o: \
+ compile auto-str.c buffer.h readwrite.h exit.h
+ 	./compile auto-str.c
+ 
+-auto_home.c: \
+-auto-str conf-home
+-	./auto-str auto_home `head -1 conf-home` > auto_home.c
+-
+ auto_home.o: \
+ compile auto_home.c
+ 	./compile auto_home.c
+@@ -305,10 +301,6 @@ fmt_ulong.o: \
+ compile fmt_ulong.c fmt.h
+ 	./compile fmt_ulong.c
+ 
+-fork.h: \
+-choose compile load tryvfork.c fork.h1 fork.h2
+-	./choose cl tryvfork fork.h1 fork.h2 > fork.h
+-
+ getln.o: \
+ compile getln.c byte.h getln.h buffer.h stralloc.h gen_alloc.h
+ 	./compile getln.c
+@@ -317,24 +309,6 @@ getln2.o: \
+ compile getln2.c byte.h getln.h buffer.h stralloc.h gen_alloc.h
+ 	./compile getln2.c
+ 
+-hassgact.h: \
+-choose compile load trysgact.c hassgact.h1 hassgact.h2
+-	./choose cl trysgact hassgact.h1 hassgact.h2 > hassgact.h
+-
+-hassgprm.h: \
+-choose compile load trysgprm.c hassgprm.h1 hassgprm.h2
+-	./choose cl trysgprm hassgprm.h1 hassgprm.h2 > hassgprm.h
+-
+-hasshsgr.h: \
+-choose compile load tryshsgr.c hasshsgr.h1 hasshsgr.h2 chkshsgr \
+-warn-shsgr
+-	./chkshsgr || ( cat warn-shsgr; exit 1 )
+-	./choose clr tryshsgr hasshsgr.h1 hasshsgr.h2 > hasshsgr.h
+-
+-haswaitp.h: \
+-choose compile load trywaitp.c haswaitp.h1 haswaitp.h2
+-	./choose cl trywaitp haswaitp.h1 haswaitp.h2 > haswaitp.h
+-
+ hier.o: \
+ compile hier.c auto_home.h
+ 	./compile hier.c
+@@ -362,10 +336,6 @@ instcheck.o: \
+ compile instcheck.c strerr.h error.h readwrite.h exit.h
+ 	./compile instcheck.c
+ 
+-iopause.h: \
+-choose compile trypoll.c iopause.h1 iopause.h2
+-	./choose clr trypoll iopause.h1 iopause.h2 > iopause.h
+-
+ iopause.o: \
+ compile iopause.c taia.h tai.h uint64.h select.h iopause.h taia.h
+ 	./compile iopause.c
+@@ -404,7 +374,7 @@ warn-auto.sh systype
+ 	dgux-*) ;; \
+ 	hp-ux-*) ;; \
+ 	sco*) ;; \
+-	*) echo 'ranlib "$$main"' ;; \
++	*) echo '$(TARGET_RANLIB) "$$main"' ;; \
+ 	esac \
+ 	) > makelib
+ 	chmod 755 makelib
+@@ -521,10 +491,6 @@ seek_set.o: \
+ compile seek_set.c seek.h
+ 	./compile seek_set.c
+ 
+-select.h: \
+-choose compile trysysel.c select.h1 select.h2
+-	./choose c trysysel select.h1 select.h2 > select.h
+-
+ setup: \
+ it install
+ 	./install
+@@ -791,10 +757,6 @@ uint32_unpack.o: \
+ compile uint32_unpack.c uint32.h
+ 	./compile uint32_unpack.c
+ 
+-uint64.h: \
+-choose compile load tryulong64.c uint64.h1 uint64.h2
+-	./choose clr tryulong64 uint64.h1 uint64.h2 > uint64.h
+-
+ unix.a: \
+ makelib alloc.o alloc_re.o buffer.o buffer_0.o buffer_1.o buffer_2.o \
+ buffer_copy.o buffer_get.o buffer_put.o env.o error.o error_str.o \
+--- /dev/null
++++ b/auto_home.c
+@@ -0,0 +1,3 @@
++const char auto_home[] = "\
++\057\165\163\162\
++";
+--- a/conf-cc
++++ b/conf-cc
+@@ -1,3 +1,3 @@
+-gcc -O2
++$TARGET_CC $TARGET_CFLAGS -include errno.h
+ 
+ This will be used to compile .c files.
+--- a/conf-home
++++ b/conf-home
+@@ -1,4 +1,4 @@
+-/usr/local
++/usr
+ 
+ This is the ucspi-tcp home directory. Programs will be installed in
+ .../bin.
+--- a/conf-ld
++++ b/conf-ld
+@@ -1,3 +1,3 @@
+-gcc -s
++$TARGET_CC -s $TARGET_LDFLAGS
+ 
+ This will be used to link .o files into an executable.
+--- /dev/null
++++ b/fork.h
+@@ -0,0 +1,9 @@
++#ifndef FORK_H
++#define FORK_H
++
++/* sysdep: +vfork */
++
++extern int fork();
++extern int vfork();
++
++#endif
+--- /dev/null
++++ b/hassgact.h
+@@ -0,0 +1,2 @@
++/* sysdep: +sigaction */
++#define HASSIGACTION 1
+--- /dev/null
++++ b/hassgprm.h
+@@ -0,0 +1,2 @@
++/* sysdep: +sigprocmask */
++#define HASSIGPROCMASK 1
+--- /dev/null
++++ b/hasshsgr.h
+@@ -0,0 +1 @@
++/* sysdep: -shortsetgroups */
+--- /dev/null
++++ b/haswaitp.h
+@@ -0,0 +1,2 @@
++/* sysdep: +waitpid */
++#define HASWAITPID 1
+--- /dev/null
++++ b/iopause.h
+@@ -0,0 +1,18 @@
++#ifndef IOPAUSE_H
++#define IOPAUSE_H
++
++/* sysdep: +poll */
++#define IOPAUSE_POLL
++
++#include <sys/types.h>
++#include <poll.h>
++
++typedef struct pollfd iopause_fd;
++#define IOPAUSE_READ POLLIN
++#define IOPAUSE_WRITE POLLOUT
++
++#include "taia.h"
++
++extern void iopause(iopause_fd *,unsigned int,struct taia *,struct taia *);
++
++#endif
+--- /dev/null
++++ b/select.h
+@@ -0,0 +1,11 @@
++#ifndef SELECT_H
++#define SELECT_H
++
++/* sysdep: +sysselect */
++
++#include <sys/types.h>
++#include <sys/time.h>
++#include <sys/select.h>
++extern int select();
++
++#endif
+--- /dev/null
++++ b/uint64.h
+@@ -0,0 +1,8 @@
++#ifndef UINT64_H
++#define UINT64_H
++
++/* sysdep: -ulong64 */
++
++typedef unsigned long long uint64;
++
++#endif
diff --git a/package/ucspi-tcp/ucspi-tcp-01.0.88-ipv6.diff19.patch b/package/ucspi-tcp/ucspi-tcp-01.0.88-ipv6.diff19.patch
new file mode 100644
index 0000000..07d2ea6
--- /dev/null
+++ b/package/ucspi-tcp/ucspi-tcp-01.0.88-ipv6.diff19.patch
@@ -0,0 +1,4899 @@
+diff -uNr ucspi-tcp-0.88.orig/FILES ucspi-tcp-0.88/FILES
+--- ucspi-tcp-0.88.orig/FILES	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/FILES	2009-03-19 12:43:14.894761759 +0100
+@@ -216,3 +216,40 @@
+ warn-auto.sh
+ warn-shsgr
+ x86cpuid.c
++dns_ip6.c
++dns_ipq6.c
++dns_nd6.c
++dns_sortip6.c
++fmt_xlong.c
++ip6_fmt.c
++ip6_scan.c
++scan_0x.c
++socket_accept6.c
++socket_bind6.c
++socket_conn6.c
++socket_local6.c
++socket_recv6.c
++socket_remote6.c
++socket_send6.c
++socket_tcp6.c
++timeoutconn6.c
++tryip6.c
++haveip6.h2
++haveip6.h1
++remoteinfo6.c
++addcr.1
++argv0.1
++date@.1
++delcr.1
++finger@.1
++fixcr.1
++http@.1
++mconnect.1
++recordio.1
++tcp-environ.5
++tcpcat.1
++tcpclient.1
++tcprules.1
++tcprulescheck.1
++tcpserver.1
++who@.1
+diff -uNr ucspi-tcp-0.88.orig/Makefile ucspi-tcp-0.88/Makefile
+--- ucspi-tcp-0.88.orig/Makefile	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/Makefile	2009-03-19 12:43:14.894761759 +0100
+@@ -76,12 +76,14 @@
+ makelib byte_chr.o byte_copy.o byte_cr.o byte_diff.o byte_rchr.o \
+ byte_zero.o case_diffb.o case_diffs.o fmt_ulong.o ip4_fmt.o \
+ ip4_scan.o scan_ulong.o str_chr.o str_diff.o str_len.o str_start.o \
+-uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o
++uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o \
++ip6_fmt.o scan_ip6.o scan_xlong.o fmt_xlong.o
+ 	./makelib byte.a byte_chr.o byte_copy.o byte_cr.o \
+ 	byte_diff.o byte_rchr.o byte_zero.o case_diffb.o \
+ 	case_diffs.o fmt_ulong.o ip4_fmt.o ip4_scan.o scan_ulong.o \
+ 	str_chr.o str_diff.o str_len.o str_start.o uint16_pack.o \
+-	uint16_unpack.o uint32_pack.o uint32_unpack.o
++	uint16_unpack.o uint32_pack.o uint32_unpack.o ip6_fmt.o \
++	scan_ip6.o scan_xlong.o fmt_xlong.o
+ 
+ byte_chr.o: \
+ compile byte_chr.c byte.h
+@@ -181,11 +183,13 @@
+ dns.a: \
+ makelib dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o dns_ipq.o \
+ dns_name.o dns_nd.o dns_packet.o dns_random.o dns_rcip.o dns_rcrw.o \
+-dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o
++dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o dns_ip6.o \
++dns_sortip6.o dns_nd6.o dns_ipq6.o
+ 	./makelib dns.a dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o \
+ 	dns_ipq.o dns_name.o dns_nd.o dns_packet.o dns_random.o \
+ 	dns_rcip.o dns_rcrw.o dns_resolve.o dns_sortip.o \
+-	dns_transmit.o dns_txt.o
++	dns_transmit.o dns_txt.o dns_ip6.o dns_sortip6.o dns_nd6.o \
++	dns_ipq6.o
+ 
+ dns_dfd.o: \
+ compile dns_dfd.c error.h alloc.h byte.h dns.h stralloc.h gen_alloc.h \
+@@ -257,7 +261,7 @@
+ dns_transmit.o: \
+ compile dns_transmit.c socket.h uint16.h alloc.h error.h byte.h \
+ readwrite.h uint16.h dns.h stralloc.h gen_alloc.h iopause.h taia.h \
+-tai.h uint64.h taia.h
++tai.h uint64.h taia.h uint32.h
+ 	./compile dns_transmit.c
+ 
+ dns_txt.o: \
+@@ -498,9 +502,15 @@
+ remoteinfo.o: \
+ compile remoteinfo.c fmt.h buffer.h socket.h uint16.h error.h \
+ iopause.h taia.h tai.h uint64.h timeoutconn.h uint16.h remoteinfo.h \
+-stralloc.h gen_alloc.h uint16.h
++stralloc.h gen_alloc.h uint16.h uint32.h
+ 	./compile remoteinfo.c
+ 
++remoteinfo6.o: \
++compile remoteinfo6.c fmt.h buffer.h socket.h uint16.h error.h \
++iopause.h taia.h tai.h uint64.h timeoutconn.h uint16.h remoteinfo.h \
++stralloc.h gen_alloc.h uint16.h uint32.h
++	./compile remoteinfo6.c
++
+ rts: \
+ warn-auto.sh rts.sh conf-home
+ 	cat warn-auto.sh rts.sh \
+@@ -557,43 +567,43 @@
+ 	rm -f trylsock.o trylsock
+ 
+ socket_accept.o: \
+-compile socket_accept.c byte.h socket.h uint16.h
++compile socket_accept.c byte.h socket.h uint16.h uint32.h
+ 	./compile socket_accept.c
+ 
+ socket_bind.o: \
+-compile socket_bind.c byte.h socket.h uint16.h
++compile socket_bind.c byte.h socket.h uint16.h uint32.h
+ 	./compile socket_bind.c
+ 
+ socket_conn.o: \
+-compile socket_conn.c readwrite.h byte.h socket.h uint16.h
++compile socket_conn.c readwrite.h byte.h socket.h uint16.h uint32.h
+ 	./compile socket_conn.c
+ 
+ socket_delay.o: \
+-compile socket_delay.c socket.h uint16.h
++compile socket_delay.c socket.h uint16.h uint32.h
+ 	./compile socket_delay.c
+ 
+ socket_listen.o: \
+-compile socket_listen.c socket.h uint16.h
++compile socket_listen.c socket.h uint16.h uint32.h
+ 	./compile socket_listen.c
+ 
+ socket_local.o: \
+-compile socket_local.c byte.h socket.h uint16.h
++compile socket_local.c byte.h socket.h uint16.h uint32.h
+ 	./compile socket_local.c
+ 
+ socket_opts.o: \
+-compile socket_opts.c socket.h uint16.h
++compile socket_opts.c socket.h uint16.h uint32.h
+ 	./compile socket_opts.c
+ 
+ socket_remote.o: \
+-compile socket_remote.c byte.h socket.h uint16.h
++compile socket_remote.c byte.h socket.h uint16.h uint32.h
+ 	./compile socket_remote.c
+ 
+ socket_tcp.o: \
+-compile socket_tcp.c ndelay.h socket.h uint16.h
++compile socket_tcp.c ndelay.h socket.h uint16.h uint32.h
+ 	./compile socket_tcp.c
+ 
+ socket_udp.o: \
+-compile socket_udp.c ndelay.h socket.h uint16.h
++compile socket_udp.c ndelay.h socket.h uint16.h uint32.h
+ 	./compile socket_udp.c
+ 
+ str_chr.o: \
+@@ -710,9 +720,9 @@
+ 	chmod 755 tcpcat
+ 
+ tcpclient: \
+-load tcpclient.o remoteinfo.o timeoutconn.o dns.a time.a unix.a \
+-byte.a socket.lib
+-	./load tcpclient remoteinfo.o timeoutconn.o dns.a time.a \
++load tcpclient.o remoteinfo6.o dns.a time.a unix.a \
++byte.a socket.lib byte.h timeoutconn6.o
++	./load tcpclient remoteinfo6.o timeoutconn6.o dns.a time.a \
+ 	unix.a byte.a  `cat socket.lib`
+ 
+ tcpclient.o: \
+@@ -720,7 +730,7 @@
+ scan.h str.h ip4.h uint16.h socket.h uint16.h fd.h stralloc.h \
+ gen_alloc.h buffer.h error.h strerr.h pathexec.h timeoutconn.h \
+ uint16.h remoteinfo.h stralloc.h uint16.h dns.h stralloc.h iopause.h \
+-taia.h tai.h uint64.h taia.h
++taia.h tai.h uint64.h taia.h uint32.h
+ 	./compile tcpclient.c
+ 
+ tcprules: \
+@@ -742,9 +752,9 @@
+ 	./compile tcprulescheck.c
+ 
+ tcpserver: \
+-load tcpserver.o rules.o remoteinfo.o timeoutconn.o cdb.a dns.a \
++load tcpserver.o rules.o remoteinfo6.o timeoutconn6.o cdb.a dns.a \
+ time.a unix.a byte.a socket.lib
+-	./load tcpserver rules.o remoteinfo.o timeoutconn.o cdb.a \
++	./load tcpserver rules.o remoteinfo6.o timeoutconn6.o cdb.a \
+ 	dns.a time.a unix.a byte.a  `cat socket.lib`
+ 
+ tcpserver.o: \
+@@ -753,7 +763,7 @@
+ alloc.h buffer.h error.h strerr.h sgetopt.h subgetopt.h pathexec.h \
+ socket.h uint16.h ndelay.h remoteinfo.h stralloc.h uint16.h rules.h \
+ stralloc.h sig.h dns.h stralloc.h iopause.h taia.h tai.h uint64.h \
+-taia.h
++taia.h uint32.h
+ 	./compile tcpserver.c
+ 
+ time.a: \
+@@ -765,9 +775,14 @@
+ 
+ timeoutconn.o: \
+ compile timeoutconn.c ndelay.h socket.h uint16.h iopause.h taia.h \
+-tai.h uint64.h error.h timeoutconn.h uint16.h
++tai.h uint64.h error.h timeoutconn.h uint16.h uint32.h
+ 	./compile timeoutconn.c
+ 
++timeoutconn6.o: \
++compile timeoutconn6.c ndelay.h socket.h uint16.h iopause.h taia.h \
++tai.h uint64.h error.h timeoutconn.h uint16.h uint32.h
++	./compile timeoutconn6.c
++
+ uint16_pack.o: \
+ compile uint16_pack.c uint16.h
+ 	./compile uint16_pack.c
+@@ -806,7 +821,12 @@
+ socket_opts.o socket_remote.o socket_tcp.o socket_udp.o \
+ stralloc_cat.o stralloc_catb.o stralloc_cats.o stralloc_copy.o \
+ stralloc_eady.o stralloc_opyb.o stralloc_opys.o stralloc_pend.o \
+-strerr_die.o strerr_sys.o subgetopt.o wait_nohang.o wait_pid.o
++strerr_die.o strerr_sys.o subgetopt.o wait_nohang.o wait_pid.o \
++socket_conn6.o socket_bind6.o socket_accept6.o socket_recv6.o \
++socket_send6.o socket_local6.o socket_remote6.o socket_tcp6.o \
++socket_getifname.o socket_getifidx.o socket_v4mappedprefix.o \
++socket_ip4loopback.o socket_v6any.o socket_v6loopback.o \
++socket_udp6.o
+ 	./makelib unix.a alloc.o alloc_re.o buffer.o buffer_0.o \
+ 	buffer_1.o buffer_2.o buffer_copy.o buffer_get.o \
+ 	buffer_put.o env.o error.o error_str.o fd_copy.o fd_move.o \
+@@ -819,7 +839,12 @@
+ 	socket_udp.o stralloc_cat.o stralloc_catb.o stralloc_cats.o \
+ 	stralloc_copy.o stralloc_eady.o stralloc_opyb.o \
+ 	stralloc_opys.o stralloc_pend.o strerr_die.o strerr_sys.o \
+-	subgetopt.o wait_nohang.o wait_pid.o
++	subgetopt.o wait_nohang.o wait_pid.o socket_conn6.o \
++	socket_bind6.o socket_accept6.o socket_recv6.o socket_send6.o \
++	socket_local6.o socket_remote6.o socket_tcp6.o \
++	socket_getifname.o socket_getifidx.o socket_v4mappedprefix.o \
++	socket_ip4loopback.o socket_v6any.o socket_v6loopback.o \
++	socket_udp6.o
+ 
+ wait_nohang.o: \
+ compile wait_nohang.c haswaitp.h
+@@ -835,3 +860,110 @@
+ 	| sed s}HOME}"`head -1 conf-home`"}g \
+ 	> who@
+ 	chmod 755 who@
++
++socket_conn6.o: \
++compile socket_conn6.c socket.h uint16.h haveip6.h error.h ip6.h \
++uint32.h
++	./compile socket_conn6.c
++
++socket_bind6.o: \
++compile socket_bind6.c socket.h uint16.h haveip6.h error.h ip6.h \
++uint32.h
++	./compile socket_bind6.c
++
++socket_accept6.o: \
++compile socket_accept6.c socket.h uint16.h haveip6.h error.h ip6.h \
++uint32.h
++	./compile socket_accept6.c
++
++socket_recv6.o: \
++compile socket_recv6.c socket.h uint16.h haveip6.h error.h ip6.h \
++uint32.h
++	./compile socket_recv6.c
++
++socket_send6.o: \
++compile socket_send6.c socket.h uint16.h haveip6.h error.h uint32.h
++	./compile socket_send6.c
++
++socket_local6.o: \
++compile socket_local6.c socket.h uint16.h haveip6.h error.h uint32.h
++	./compile socket_local6.c
++
++socket_remote6.o: \
++compile socket_remote6.c socket.h uint16.h haveip6.h error.h uint32.h
++	./compile socket_remote6.c
++
++dns_sortip6.o: \
++compile dns_sortip6.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \
++taia.h tai.h uint64.h taia.h
++	./compile dns_sortip6.c
++
++dns_nd6.o: \
++compile dns_nd6.c byte.h fmt.h dns.h stralloc.h gen_alloc.h iopause.h \
++taia.h tai.h uint64.h taia.h
++	./compile dns_nd6.c
++
++dns_ipq6.o: \
++compile dns_ipq6.c stralloc.h gen_alloc.h case.h byte.h str.h dns.h \
++stralloc.h iopause.h taia.h tai.h uint64.h taia.h ip6.h
++	./compile dns_ipq6.c
++
++dns_ip6.o: \
++compile dns_ip6.c stralloc.h gen_alloc.h uint16.h byte.h dns.h \
++stralloc.h iopause.h taia.h tai.h uint64.h taia.h
++	./compile dns_ip6.c
++
++fmt_xlong.o: \
++compile fmt_xlong.c scan.h
++	./compile fmt_xlong.c
++
++scan_xlong.o: \
++compile scan_xlong.c scan.h
++	./compile scan_xlong.c
++
++ip6_fmt.o: \
++compile ip6_fmt.c fmt.h ip6.h
++	./compile ip6_fmt.c
++
++scan_ip6.o: \
++compile scan_ip6.c scan.h ip6.h
++	./compile scan_ip6.c
++
++socket_tcp6.o: \
++compile socket_tcp6.c ndelay.h socket.h uint16.h haveip6.h uint32.h
++	./compile socket_tcp6.c
++
++socket_udp6.o: \
++compile socket_udp6.c ndelay.h socket.h uint16.h haveip6.h uint32.h
++	./compile socket_udp6.c
++
++haveip6.h: \
++tryip6.c choose compile haveip6.h1 haveip6.h2
++	./choose c tryip6 haveip6.h1 haveip6.h2 > haveip6.h
++
++socket_getifname.o: \
++compile socket_getifname.c socket.h uint16.h uint32.h
++	./compile socket_getifname.c
++
++socket_getifidx.o: \
++compile socket_getifidx.c socket.h uint16.h uint32.h
++	./compile socket_getifidx.c
++
++socket_ip4loopback.o: \
++compile socket_ip4loopback.c
++	./compile socket_ip4loopback.c
++
++socket_v4mappedprefix.o: \
++compile socket_v4mappedprefix.c
++	./compile socket_v4mappedprefix.c
++
++socket_v6any.o: \
++compile socket_v6any.c
++	./compile socket_v6any.c
++
++socket_v6loopback.o: \
++compile socket_v6loopback.c
++	./compile socket_v6loopback.c
++
++clean:
++	rm -f `cat TARGETS`
+diff -uNr ucspi-tcp-0.88.orig/TARGETS ucspi-tcp-0.88/TARGETS
+--- ucspi-tcp-0.88.orig/TARGETS	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/TARGETS	2009-03-19 12:43:14.894761759 +0100
+@@ -169,3 +169,31 @@
+ it
+ setup
+ check
++dns_ip6.o
++dns_ipq6.o
++dns_nd6.o
++dns_sortip6.o
++fmt_xlong.o
++ip6_fmt.o
++ip6_scan.o
++scan_0x.o
++socket_accept6.o
++socket_bind6.o
++socket_conn6.o
++socket_local6.o
++socket_recv6.o
++socket_remote6.o
++socket_send6.o
++socket_tcp6.o
++timeoutconn6.o
++haveip6.h
++remoteinfo6.o
++socket_getifidx.o
++socket_getifname.o
++scan_ip6.o
++scan_xlong.o
++socket_ip4loopback.o
++socket_udp6.o
++socket_v4mappedprefix.o
++socket_v6any.o
++socket_v6loopback.o
+diff -uNr ucspi-tcp-0.88.orig/addcr.1 ucspi-tcp-0.88/addcr.1
+--- ucspi-tcp-0.88.orig/addcr.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/addcr.1	2009-03-19 12:43:14.894761759 +0100
+@@ -0,0 +1,22 @@
++.TH addcr 1
++.SH NAME
++addcr \- add a CR before each LF
++.SH SYNOPSIS
++.B addcr
++.SH DESCRIPTION
++.B addcr
++inserts CR at the end of each line of input.
++It does not insert CR at the end of a partial final line.
++.SH COMPATIBILITY
++Some vendors ship
++.B unix2dos
++or
++.B bsd2dos
++tools similar to
++.BR addcr .
++Those tools often blow up on long lines and nulls.
++.B addcr
++has no trouble with long lines and nulls.
++.SH "SEE ALSO"
++delcr(1),
++fixcr(1)
+diff -uNr ucspi-tcp-0.88.orig/argv0.1 ucspi-tcp-0.88/argv0.1
+--- ucspi-tcp-0.88.orig/argv0.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/argv0.1	2009-03-19 12:43:14.894761759 +0100
+@@ -0,0 +1,47 @@
++.TH argv0 1
++.SH NAME
++argv0 \- run a program with a specified 0th argument
++.SH SYNOPSIS
++.B argv0
++.I realname
++.I zero
++[
++.I arg ...
++]
++.SH DESCRIPTION
++.B argv0
++runs
++the program stored as
++.I realname
++on disk,
++with the given
++arguments.
++It sets the 0th argument of
++the program to
++.IR zero .
++
++For example,
++
++.EX
++     argv0 /bin/csh -bin/csh
++.EE
++
++runs
++.B /bin/csh
++with a 0th argument of
++.BR -bin/csh .
++.B csh
++will think it is a login shell
++and behave accordingly.
++
++.B argv0
++can be used to run some
++.B inetd
++wrappers under
++.BR tcpserver .
++.SH "SEE ALSO"
++csh(1),
++tcpserver(1),
++execve(2),
++execvp(3),
++inetd(8)
+diff -uNr ucspi-tcp-0.88.orig/date@.1 ucspi-tcp-0.88/date@.1
+--- ucspi-tcp-0.88.orig/date@.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/date@.1	2009-03-19 12:43:14.894761759 +0100
+@@ -0,0 +1,32 @@
++.TH date@ 1
++.SH NAME
++date@ \- print the date on a host
++.SH SYNTAX
++.B date@
++[
++.I host
++]
++.SH DESCRIPTION
++.B date@
++connects to TCP port 13 (Daytime) on
++.I host
++and prints any data it receives.
++It removes CR and converts unprintable characters to a visible format.
++
++If
++.I host
++is not supplied,
++.B date@
++connects to the local host.
++
++Some computers respond to port 13 with a human-readable date.
++For example, they may be running
++
++.EX
++     tcpserver 0 13 date &
++.EE
++.SH "SEE ALSO"
++cat(1),
++delcr(1),
++tcpclient(1),
++tcpserver(1)
+diff -uNr ucspi-tcp-0.88.orig/delcr.1 ucspi-tcp-0.88/delcr.1
+--- ucspi-tcp-0.88.orig/delcr.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/delcr.1	2009-03-19 12:43:14.894761759 +0100
+@@ -0,0 +1,30 @@
++.TH delcr 1
++.SH NAME
++delcr \- remove a CR before each LF
++.SH SYNOPSIS
++.B delcr
++.SH DESCRIPTION
++.B delcr
++removes a CR at the end of each line of input,
++if a CR is present.
++It also removes a CR at the end of a partial final line.
++
++The pipeline
++
++.EX
++     addcr | delcr
++.EE
++
++prints an exact copy of its input.
++.SH COMPATIBILITY
++Some vendors ship
++.B dos2unix
++or
++.B dos2bsd
++tools similar to
++.BR delcr .
++Those tools often blow up on long lines and nulls.
++.B delcr
++has no trouble with long lines and nulls.
++.SH "SEE ALSO"
++addcr(1)
+diff -uNr ucspi-tcp-0.88.orig/dns.h ucspi-tcp-0.88/dns.h
+--- ucspi-tcp-0.88.orig/dns.h	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns.h	2009-03-19 12:43:14.894761759 +0100
+@@ -34,51 +34,60 @@
+   unsigned int curserver;
+   struct taia deadline;
+   unsigned int pos;
+-  char *servers;
+-  char localip[4];
++  const char *servers;
++  char localip[16];
++  unsigned int scope_id;
+   char qtype[2];
+ } ;
+ 
+-extern void dns_random_init(char *);
++extern void dns_random_init(const char *);
+ extern unsigned int dns_random(unsigned int);
+ 
+ extern void dns_sortip(char *,unsigned int);
++extern void dns_sortip6(char *,unsigned int);
+ 
+ extern void dns_domain_free(char **);
+-extern int dns_domain_copy(char **,char *);
+-extern unsigned int dns_domain_length(char *);
+-extern int dns_domain_equal(char *,char *);
+-extern char *dns_domain_suffix(char *,char *);
+-extern int dns_domain_fromdot(char **,char *,unsigned int);
+-extern int dns_domain_todot_cat(stralloc *,char *);
+-
+-extern unsigned int dns_packet_copy(char *,unsigned int,unsigned int,char *,unsigned int);
+-extern unsigned int dns_packet_getname(char *,unsigned int,unsigned int,char **);
+-extern unsigned int dns_packet_skipname(char *,unsigned int,unsigned int);
+-extern int dns_packet_nameequal(char *,unsigned int,unsigned int,char *,unsigned int,unsigned int);
++extern int dns_domain_copy(char **,const char *);
++extern unsigned int dns_domain_length(const char *);
++extern int dns_domain_equal(const char *,const char *);
++extern int dns_domain_suffix(const char *,const char *);
++extern unsigned int dns_domain_suffixpos(const char *,const char *);
++extern int dns_domain_fromdot(char **,const char *,unsigned int);
++extern int dns_domain_todot_cat(stralloc *,const char *);
++
++extern unsigned int dns_packet_copy(const char *,unsigned int,unsigned int,char *,unsigned int);
++extern unsigned int dns_packet_getname(const char *,unsigned int,unsigned int,char **);
++extern unsigned int dns_packet_skipname(const char *,unsigned int,unsigned int);
+ 
+-extern int dns_transmit_start(struct dns_transmit *,char *,int,char *,char *,char *);
++extern int dns_transmit_start(struct dns_transmit *,const char *,int,const char *,const char *,const char *);
+ extern void dns_transmit_free(struct dns_transmit *);
+ extern void dns_transmit_io(struct dns_transmit *,iopause_fd *,struct taia *);
+-extern int dns_transmit_get(struct dns_transmit *,iopause_fd *,struct taia *);
++extern int dns_transmit_get(struct dns_transmit *,const iopause_fd *,const struct taia *);
+ 
+ extern int dns_resolvconfip(char *);
+-extern int dns_resolve(char *,char *);
++extern int dns_resolve(const char *,const char *);
+ extern struct dns_transmit dns_resolve_tx;
+ 
+-extern int dns_ip4_packet(stralloc *,char *,unsigned int);
+-extern int dns_ip4(stralloc *,stralloc *);
+-extern int dns_name_packet(stralloc *,char *,unsigned int);
+-extern void dns_name4_domain(char *,char *);
++extern int dns_ip4_packet(stralloc *,const char *,unsigned int);
++extern int dns_ip4(stralloc *,const stralloc *);
++extern int dns_ip6_packet(stralloc *,const char *,unsigned int);
++extern int dns_ip6(stralloc *,stralloc *);
++extern int dns_name_packet(stralloc *,const char *,unsigned int);
++extern void dns_name4_domain(char *,const char *);
+ #define DNS_NAME4_DOMAIN 31
+-extern int dns_name4(stralloc *,char *);
+-extern int dns_txt_packet(stralloc *,char *,unsigned int);
+-extern int dns_txt(stralloc *,stralloc *);
+-extern int dns_mx_packet(stralloc *,char *,unsigned int);
+-extern int dns_mx(stralloc *,stralloc *);
++extern int dns_name4(stralloc *,const char *);
++extern int dns_txt_packet(stralloc *,const char *,unsigned int);
++extern int dns_txt(stralloc *,const stralloc *);
++extern int dns_mx_packet(stralloc *,const char *,unsigned int);
++extern int dns_mx(stralloc *,const stralloc *);
+ 
+ extern int dns_resolvconfrewrite(stralloc *);
+-extern int dns_ip4_qualify_rules(stralloc *,stralloc *,stralloc *,stralloc *);
+-extern int dns_ip4_qualify(stralloc *,stralloc *,stralloc *);
++extern int dns_ip4_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *);
++extern int dns_ip4_qualify(stralloc *,stralloc *,const stralloc *);
++extern int dns_ip6_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *);
++extern int dns_ip6_qualify(stralloc *,stralloc *,const stralloc *);
++
++extern int dns_name6_domain(char *,char *);
++#define DNS_NAME6_DOMAIN (4*16+11)
+ 
+ #endif
+diff -uNr ucspi-tcp-0.88.orig/dns_dfd.c ucspi-tcp-0.88/dns_dfd.c
+--- ucspi-tcp-0.88.orig/dns_dfd.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_dfd.c	2009-03-19 12:43:14.894761759 +0100
+@@ -1,9 +1,10 @@
+-#include "error.h"
+-#include "alloc.h"
++#include <stdlib.h>
++#include <errno.h>
+ #include "byte.h"
+ #include "dns.h"
++#include "error.h"
+ 
+-int dns_domain_fromdot(char **out,char *buf,unsigned int n)
++int dns_domain_fromdot(char **out,const char *buf,unsigned int n)
+ {
+   char label[63];
+   unsigned int labellen = 0; /* <= sizeof label */
+@@ -59,11 +60,11 @@
+   if (namelen + 1 > sizeof name) return 0;
+   name[namelen++] = 0;
+ 
+-  x = alloc(namelen);
++  x = malloc(namelen);
+   if (!x) return 0;
+   byte_copy(x,namelen,name);
+ 
+-  if (*out) alloc_free(*out);
++  if (*out) free(*out);
+   *out = x;
+   return 1;
+ }
+diff -uNr ucspi-tcp-0.88.orig/dns_domain.c ucspi-tcp-0.88/dns_domain.c
+--- ucspi-tcp-0.88.orig/dns_domain.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_domain.c	2009-03-19 12:43:14.894761759 +0100
+@@ -1,16 +1,15 @@
+-#include "error.h"
+-#include "alloc.h"
++#include <stdlib.h>
+ #include "case.h"
+ #include "byte.h"
+ #include "dns.h"
+ 
+-unsigned int dns_domain_length(char *dn)
++unsigned int dns_domain_length(const char *dn)
+ {
+-  char *x;
++  const char *x;
+   unsigned char c;
+ 
+   x = dn;
+-  while (c = *x++)
++  while ((c = *x++))
+     x += (unsigned int) c;
+   return x - dn;
+ }
+@@ -18,26 +17,26 @@
+ void dns_domain_free(char **out)
+ {
+   if (*out) {
+-    alloc_free(*out);
++    free(*out);
+     *out = 0;
+   }
+ }
+ 
+-int dns_domain_copy(char **out,char *in)
++int dns_domain_copy(char **out,const char *in)
+ {
+   unsigned int len;
+   char *x;
+ 
+   len = dns_domain_length(in);
+-  x = alloc(len);
++  x = malloc(len);
+   if (!x) return 0;
+   byte_copy(x,len,in);
+-  if (*out) alloc_free(*out);
++  if (*out) free(*out);
+   *out = x;
+   return 1;
+ }
+ 
+-int dns_domain_equal(char *dn1,char *dn2)
++int dns_domain_equal(const char *dn1,const char *dn2)
+ {
+   unsigned int len;
+ 
+@@ -48,12 +47,25 @@
+   return 1;
+ }
+ 
+-char *dns_domain_suffix(char *big,char *little)
++int dns_domain_suffix(const char *big,const char *little)
++{
++  unsigned char c;
++
++  for (;;) {
++    if (dns_domain_equal(big,little)) return 1;
++    c = *big++;
++    if (!c) return 0;
++    big += c;
++  }
++}
++
++unsigned int dns_domain_suffixpos(const char *big,const char *little)
+ {
++  const char *orig = big;
+   unsigned char c;
+ 
+   for (;;) {
+-    if (dns_domain_equal(big,little)) return big;
++    if (dns_domain_equal(big,little)) return big - orig;
+     c = *big++;
+     if (!c) return 0;
+     big += c;
+diff -uNr ucspi-tcp-0.88.orig/dns_dtda.c ucspi-tcp-0.88/dns_dtda.c
+--- ucspi-tcp-0.88.orig/dns_dtda.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_dtda.c	2009-03-19 12:43:14.894761759 +0100
+@@ -1,7 +1,7 @@
+ #include "stralloc.h"
+ #include "dns.h"
+ 
+-int dns_domain_todot_cat(stralloc *out,char *d)
++int dns_domain_todot_cat(stralloc *out,const char *d)
+ {
+   char ch;
+   char ch2;
+diff -uNr ucspi-tcp-0.88.orig/dns_ip.c ucspi-tcp-0.88/dns_ip.c
+--- ucspi-tcp-0.88.orig/dns_ip.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_ip.c	2009-03-19 12:43:14.898761744 +0100
+@@ -3,7 +3,7 @@
+ #include "byte.h"
+ #include "dns.h"
+ 
+-int dns_ip4_packet(stralloc *out,char *buf,unsigned int len)
++int dns_ip4_packet(stralloc *out,const char *buf,unsigned int len)
+ {
+   unsigned int pos;
+   char header[12];
+@@ -36,7 +36,7 @@
+ 
+ static char *q = 0;
+ 
+-int dns_ip4(stralloc *out,stralloc *fqdn)
++int dns_ip4(stralloc *out,const stralloc *fqdn)
+ {
+   unsigned int i;
+   char code;
+diff -uNr ucspi-tcp-0.88.orig/dns_ip6.c ucspi-tcp-0.88/dns_ip6.c
+--- ucspi-tcp-0.88.orig/dns_ip6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/dns_ip6.c	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1,103 @@
++#include "stralloc.h"
++#include "uint16.h"
++#include "byte.h"
++#include "dns.h"
++#include "ip4.h"
++#include "ip6.h"
++
++static int dns_ip6_packet_add(stralloc *out,const char *buf,unsigned int len)
++{
++  unsigned int pos;
++  char header[16];
++  uint16 numanswers;
++  uint16 datalen;
++
++  pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1;
++  uint16_unpack_big(header + 6,&numanswers);
++  pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
++  pos += 4;
++
++  while (numanswers--) {
++    pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
++    pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1;
++    uint16_unpack_big(header + 8,&datalen);
++    if (byte_equal(header,2,DNS_T_AAAA)) {
++      if (byte_equal(header + 2,2,DNS_C_IN))
++        if (datalen == 16) {
++	  if (!dns_packet_copy(buf,len,pos,header,16)) return -1;
++	  if (!stralloc_catb(out,header,16)) return -1;
++	}
++    } else if (byte_equal(header,2,DNS_T_A))
++      if (byte_equal(header + 2,2,DNS_C_IN))
++        if (datalen == 4) {
++	  byte_copy(header,12,V4mappedprefix);
++	  if (!dns_packet_copy(buf,len,pos,header+12,4)) return -1;
++	  if (!stralloc_catb(out,header,16)) return -1;
++	}
++    pos += datalen;
++  }
++
++  dns_sortip6(out->s,out->len);
++  return 0;
++}
++
++int dns_ip6_packet(stralloc *out,const char *buf,unsigned int len) {
++  if (!stralloc_copys(out,"")) return -1;
++  return dns_ip6_packet_add(out,buf,len);
++}
++
++static char *q = 0;
++
++int dns_ip6(stralloc *out,stralloc *fqdn)
++{
++  unsigned int i;
++  char code;
++  char ch;
++  char ip[16];
++
++  if (!stralloc_copys(out,"")) return -1;
++  if (!stralloc_readyplus(fqdn,1)) return -1;
++  fqdn->s[fqdn->len]=0;
++  if ((i=scan_ip6(fqdn->s,ip))) {
++    if (fqdn->s[i]) return -1;
++    stralloc_copyb(out,ip,16);
++    return 0;
++  }
++  code = 0;
++  for (i = 0;i <= fqdn->len;++i) {
++    if (i < fqdn->len)
++      ch = fqdn->s[i];
++    else
++      ch = '.';
++
++    if ((ch == '[') || (ch == ']')) continue;
++    if (ch == '.') {
++      if (!stralloc_append(out,&code)) return -1;
++      code = 0;
++      continue;
++    }
++    if ((ch >= '0') && (ch <= '9')) {
++      code *= 10;
++      code += ch - '0';
++      continue;
++    }
++
++    if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
++    if (!stralloc_copys(out,"")) return -1;
++    if (dns_resolve(q,DNS_T_AAAA) != -1)
++      if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) {
++	dns_transmit_free(&dns_resolve_tx);
++	dns_domain_free(&q);
++      }
++    if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
++    if (dns_resolve(q,DNS_T_A) != -1)
++      if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) {
++	dns_transmit_free(&dns_resolve_tx);
++	dns_domain_free(&q);
++      }
++    return out->a>0?0:-1;
++  }
++
++  out->len &= ~3;
++  return 0;
++}
+diff -uNr ucspi-tcp-0.88.orig/dns_ipq.c ucspi-tcp-0.88/dns_ipq.c
+--- ucspi-tcp-0.88.orig/dns_ipq.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_ipq.c	2009-03-19 12:43:14.898761744 +0100
+@@ -4,7 +4,7 @@
+ #include "str.h"
+ #include "dns.h"
+ 
+-static int doit(stralloc *work,char *rule)
++static int doit(stralloc *work,const char *rule)
+ {
+   char ch;
+   unsigned int colon;
+@@ -30,7 +30,7 @@
+   return stralloc_cats(work,rule + colon + 1);
+ }
+ 
+-int dns_ip4_qualify_rules(stralloc *out,stralloc *fqdn,stralloc *in,stralloc *rules)
++int dns_ip4_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules)
+ {
+   unsigned int i;
+   unsigned int j;
+@@ -63,7 +63,7 @@
+   }
+ }
+ 
+-int dns_ip4_qualify(stralloc *out,stralloc *fqdn,stralloc *in)
++int dns_ip4_qualify(stralloc *out,stralloc *fqdn,const stralloc *in)
+ {
+   static stralloc rules;
+   if (dns_resolvconfrewrite(&rules) == -1) return -1;
+diff -uNr ucspi-tcp-0.88.orig/dns_ipq6.c ucspi-tcp-0.88/dns_ipq6.c
+--- ucspi-tcp-0.88.orig/dns_ipq6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/dns_ipq6.c	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1,72 @@
++#include "stralloc.h"
++#include "case.h"
++#include "byte.h"
++#include "str.h"
++#include "dns.h"
++
++static int doit(stralloc *work,const char *rule)
++{
++  char ch;
++  unsigned int colon;
++  unsigned int prefixlen;
++
++  ch = *rule++;
++  if ((ch != '?') && (ch != '=') && (ch != '*') && (ch != '-')) return 1;
++  colon = str_chr(rule,':');
++  if (!rule[colon]) return 1;
++
++  if (work->len < colon) return 1;
++  prefixlen = work->len - colon;
++  if ((ch == '=') && prefixlen) return 1;
++  if (case_diffb(rule,colon,work->s + prefixlen)) return 1;
++  if (ch == '?') {
++    if (byte_chr(work->s,prefixlen,'.') < prefixlen) return 1;
++    if (byte_chr(work->s,prefixlen,':') < prefixlen) return 1;
++    if (byte_chr(work->s,prefixlen,'[') < prefixlen) return 1;
++    if (byte_chr(work->s,prefixlen,']') < prefixlen) return 1;
++  }
++
++  work->len = prefixlen;
++  if (ch == '-') work->len = 0;
++  return stralloc_cats(work,rule + colon + 1);
++}
++
++int dns_ip6_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules)
++{
++  unsigned int i;
++  unsigned int j;
++  unsigned int plus;
++  unsigned int fqdnlen;
++
++  if (!stralloc_copy(fqdn,in)) return -1;
++
++  for (j = i = 0;j < rules->len;++j)
++    if (!rules->s[j]) {
++      if (!doit(fqdn,rules->s + i)) return -1;
++      i = j + 1;
++    }
++
++  fqdnlen = fqdn->len;
++  plus = byte_chr(fqdn->s,fqdnlen,'+');
++  if (plus >= fqdnlen)
++    return dns_ip6(out,fqdn);
++
++  i = plus + 1;
++  for (;;) {
++    j = byte_chr(fqdn->s + i,fqdnlen - i,'+');
++    byte_copy(fqdn->s + plus,j,fqdn->s + i);
++    fqdn->len = plus + j;
++    if (dns_ip6(out,fqdn) == -1) return -1;
++    if (out->len) return 0;
++    i += j;
++    if (i >= fqdnlen) return 0;
++    ++i;
++  }
++}
++
++int dns_ip6_qualify(stralloc *out,stralloc *fqdn,const stralloc *in)
++{
++  static stralloc rules;
++  if (dns_resolvconfrewrite(&rules) == -1) return -1;
++  return dns_ip6_qualify_rules(out,fqdn,in,&rules);
++}
+diff -uNr ucspi-tcp-0.88.orig/dns_name.c ucspi-tcp-0.88/dns_name.c
+--- ucspi-tcp-0.88.orig/dns_name.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_name.c	2009-03-19 12:43:14.898761744 +0100
+@@ -2,10 +2,11 @@
+ #include "uint16.h"
+ #include "byte.h"
+ #include "dns.h"
++#include "ip6.h"
+ 
+ static char *q = 0;
+ 
+-int dns_name_packet(stralloc *out,char *buf,unsigned int len)
++int dns_name_packet(stralloc *out,const char *buf,unsigned int len)
+ {
+   unsigned int pos;
+   char header[12];
+@@ -35,7 +36,7 @@
+   return 0;
+ }
+ 
+-int dns_name4(stralloc *out,char ip[4])
++int dns_name4(stralloc *out,const char ip[4])
+ {
+   char name[DNS_NAME4_DOMAIN];
+ 
+@@ -46,3 +47,17 @@
+   dns_domain_free(&q);
+   return 0;
+ }
++
++int dns_name6(stralloc *out,char ip[16])
++{
++  char name[DNS_NAME6_DOMAIN];
++
++  if (ip6_isv4mapped(ip))
++    return dns_name4(out,ip+12);
++  dns_name6_domain(name,ip);
++  if (dns_resolve(name,DNS_T_PTR) == -1) return -1;
++  if (dns_name_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1;
++  dns_transmit_free(&dns_resolve_tx);
++  dns_domain_free(&q);
++  return 0;
++}
+diff -uNr ucspi-tcp-0.88.orig/dns_nd.c ucspi-tcp-0.88/dns_nd.c
+--- ucspi-tcp-0.88.orig/dns_nd.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_nd.c	2009-03-19 12:43:14.898761744 +0100
+@@ -2,7 +2,7 @@
+ #include "fmt.h"
+ #include "dns.h"
+ 
+-void dns_name4_domain(char name[DNS_NAME4_DOMAIN],char ip[4])
++void dns_name4_domain(char name[DNS_NAME4_DOMAIN],const char ip[4])
+ {
+   unsigned int namelen;
+   unsigned int i;
+diff -uNr ucspi-tcp-0.88.orig/dns_nd6.c ucspi-tcp-0.88/dns_nd6.c
+--- ucspi-tcp-0.88.orig/dns_nd6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/dns_nd6.c	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1,28 @@
++#include "byte.h"
++#include "fmt.h"
++#include "dns.h"
++
++/* RFC1886:
++ *   4321:0:1:2:3:4:567:89ab
++ * ->
++ *   b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.INT.
++ */
++
++static inline char tohex(char c) {
++  return c>=10?c-10+'a':c+'0';
++}
++
++int dns_name6_domain(char name[DNS_NAME6_DOMAIN],char ip[16])
++{
++  unsigned int j;
++
++  for (j=0; j<16; j++) {
++    name[j*4]=1;
++    name[j*4+1]=tohex(ip[15-j] & 15);
++    name[j*4+2]=1;
++    name[j*4+3]=tohex((unsigned char)ip[15-j] >> 4);
++  }
++  byte_copy(name + 4*16,10,"\3ip6\4arpa\0");
++  return 4*16+10;
++}
++
+diff -uNr ucspi-tcp-0.88.orig/dns_packet.c ucspi-tcp-0.88/dns_packet.c
+--- ucspi-tcp-0.88.orig/dns_packet.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_packet.c	2009-03-19 12:43:14.898761744 +0100
+@@ -2,10 +2,11 @@
+ DNS should have used LZ77 instead of its own sophomoric compression algorithm.
+ */
+ 
+-#include "error.h"
++#include <errno.h>
+ #include "dns.h"
++#include "error.h"
+ 
+-unsigned int dns_packet_copy(char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen)
++unsigned int dns_packet_copy(const char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen)
+ {
+   while (outlen) {
+     if (pos >= len) { errno = error_proto; return 0; }
+@@ -15,7 +16,7 @@
+   return pos;
+ }
+ 
+-unsigned int dns_packet_skipname(char *buf,unsigned int len,unsigned int pos)
++unsigned int dns_packet_skipname(const char *buf,unsigned int len,unsigned int pos)
+ {
+   unsigned char ch;
+ 
+@@ -32,7 +33,7 @@
+   return 0;
+ }
+ 
+-unsigned int dns_packet_getname(char *buf,unsigned int len,unsigned int pos,char **d)
++unsigned int dns_packet_getname(const char *buf,unsigned int len,unsigned int pos,char **d)
+ {
+   unsigned int loop = 0;
+   unsigned int state = 0;
+diff -uNr ucspi-tcp-0.88.orig/dns_random.c ucspi-tcp-0.88/dns_random.c
+--- ucspi-tcp-0.88.orig/dns_random.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_random.c	2009-03-19 12:43:14.898761744 +0100
+@@ -1,3 +1,4 @@
++#include <unistd.h>
+ #include "dns.h"
+ #include "taia.h"
+ #include "uint32.h"
+@@ -29,7 +30,7 @@
+   }
+ }
+ 
+-void dns_random_init(char data[128])
++void dns_random_init(const char data[128])
+ {
+   int i;
+   struct taia t;
+diff -uNr ucspi-tcp-0.88.orig/dns_rcip.c ucspi-tcp-0.88/dns_rcip.c
+--- ucspi-tcp-0.88.orig/dns_rcip.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_rcip.c	2009-03-19 12:43:14.898761744 +0100
+@@ -2,12 +2,13 @@
+ #include "openreadclose.h"
+ #include "byte.h"
+ #include "ip4.h"
+-#include "env.h"
++#include "ip6.h"
+ #include "dns.h"
++#include "env.h"
+ 
+ static stralloc data = {0};
+ 
+-static int init(char ip[64])
++static int init(char ip[256])
+ {
+   int i;
+   int j;
+@@ -16,15 +17,16 @@
+ 
+   x = env_get("DNSCACHEIP");
+   if (x)
+-    while (iplen <= 60)
++    while (iplen <= 60) {
+       if (*x == '.')
+ 	++x;
+       else {
+-        i = ip4_scan(x,ip + iplen);
++        i = scan_ip6(x,ip + iplen);
+ 	if (!i) break;
+ 	x += i;
+-	iplen += 4;
++	iplen += 16;
+       }
++    }
+ 
+   if (!iplen) {
+     i = openreadclose("/etc/resolv.conf",&data,64);
+@@ -39,8 +41,9 @@
+             while ((data.s[i] == ' ') || (data.s[i] == '\t'))
+               ++i;
+             if (iplen <= 60)
+-              if (ip4_scan(data.s + i,ip + iplen))
+-                iplen += 4;
++              if (scan_ip6(data.s + i,ip + iplen)) {
++                iplen += 16;
++	      }
+           }
+           i = j + 1;
+         }
+@@ -48,19 +51,19 @@
+   }
+ 
+   if (!iplen) {
+-    byte_copy(ip,4,"\177\0\0\1");
+-    iplen = 4;
++    byte_copy(ip,16,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1");
++    iplen = 16;
+   }
+-  byte_zero(ip + iplen,64 - iplen);
++  byte_zero(ip + iplen,256 - iplen);
+   return 0;
+ }
+ 
+ static int ok = 0;
+ static unsigned int uses;
+ static struct taia deadline;
+-static char ip[64]; /* defined if ok */
++static char ip[256]; /* defined if ok */
+ 
+-int dns_resolvconfip(char s[64])
++int dns_resolvconfip(char s[256])
+ {
+   struct taia now;
+ 
+@@ -77,6 +80,6 @@
+   }
+ 
+   --uses;
+-  byte_copy(s,64,ip);
++  byte_copy(s,256,ip);
+   return 0;
+ }
+diff -uNr ucspi-tcp-0.88.orig/dns_rcrw.c ucspi-tcp-0.88/dns_rcrw.c
+--- ucspi-tcp-0.88.orig/dns_rcrw.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_rcrw.c	2009-03-19 12:43:14.898761744 +0100
+@@ -1,16 +1,17 @@
++#include <unistd.h>
+ #include "taia.h"
+-#include "env.h"
+ #include "byte.h"
+ #include "str.h"
+ #include "openreadclose.h"
+ #include "dns.h"
++#include "env.h"
+ 
+ static stralloc data = {0};
+ 
+ static int init(stralloc *rules)
+ {
+   char host[256];
+-  char *x;
++  const char *x;
+   int i;
+   int j;
+   int k;
+diff -uNr ucspi-tcp-0.88.orig/dns_resolve.c ucspi-tcp-0.88/dns_resolve.c
+--- ucspi-tcp-0.88.orig/dns_resolve.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_resolve.c	2009-03-19 12:43:14.898761744 +0100
+@@ -2,19 +2,20 @@
+ #include "taia.h"
+ #include "byte.h"
+ #include "dns.h"
++#include "ip6.h"
+ 
+ struct dns_transmit dns_resolve_tx = {0};
+ 
+-int dns_resolve(char *q,char qtype[2])
++int dns_resolve(const char *q,const char qtype[2])
+ {
+   struct taia stamp;
+   struct taia deadline;
+-  char servers[64];
++  char servers[256];
+   iopause_fd x[1];
+   int r;
+ 
+   if (dns_resolvconfip(servers) == -1) return -1;
+-  if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,"\0\0\0\0") == -1) return -1;
++  if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,V6any) == -1) return -1;
+ 
+   for (;;) {
+     taia_now(&stamp);
+diff -uNr ucspi-tcp-0.88.orig/dns_sortip6.c ucspi-tcp-0.88/dns_sortip6.c
+--- ucspi-tcp-0.88.orig/dns_sortip6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/dns_sortip6.c	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1,20 @@
++#include "byte.h"
++#include "dns.h"
++
++/* XXX: sort servers by configurable notion of closeness? */
++/* XXX: pay attention to competence of each server? */
++
++void dns_sortip6(char *s,unsigned int n)
++{
++  unsigned int i;
++  char tmp[16];
++
++  n >>= 4;
++  while (n > 1) {
++    i = dns_random(n);
++    --n;
++    byte_copy(tmp,16,s + (i << 4));
++    byte_copy(s + (i << 4),16,s + (n << 4));
++    byte_copy(s + (n << 4),16,tmp);
++  }
++}
+diff -uNr ucspi-tcp-0.88.orig/dns_transmit.c ucspi-tcp-0.88/dns_transmit.c
+--- ucspi-tcp-0.88.orig/dns_transmit.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_transmit.c	2009-03-19 12:43:14.898761744 +0100
+@@ -1,12 +1,15 @@
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <unistd.h>
++#include <stdlib.h>
+ #include "socket.h"
+-#include "alloc.h"
+-#include "error.h"
++#include <errno.h>
+ #include "byte.h"
+-#include "readwrite.h"
+ #include "uint16.h"
+ #include "dns.h"
++#include "ip6.h"
+ 
+-static int serverwantstcp(char *buf,unsigned int len)
++static int serverwantstcp(const char *buf,unsigned int len)
+ {
+   char out[12];
+ 
+@@ -15,7 +18,7 @@
+   return 0;
+ }
+ 
+-static int serverfailed(char *buf,unsigned int len)
++static int serverfailed(const char *buf,unsigned int len)
+ {
+   char out[12];
+   unsigned int rcode;
+@@ -23,11 +26,11 @@
+   if (!dns_packet_copy(buf,len,0,out,12)) return 1;
+   rcode = out[3];
+   rcode &= 15;
+-  if (rcode && (rcode != 3)) { errno = error_again; return 1; }
++  if (rcode && (rcode != 3)) { errno = EAGAIN; return 1; }
+   return 0;
+ }
+ 
+-static int irrelevant(struct dns_transmit *d,char *buf,unsigned int len)
++static int irrelevant(const struct dns_transmit *d,const char *buf,unsigned int len)
+ {
+   char out[12];
+   char *dn;
+@@ -40,8 +43,8 @@
+ 
+   dn = 0;
+   pos = dns_packet_getname(buf,len,pos,&dn); if (!pos) return 1;
+-  if (!dns_domain_equal(dn,d->query + 14)) { alloc_free(dn); return 1; }
+-  alloc_free(dn);
++  if (!dns_domain_equal(dn,d->query + 14)) { free(dn); return 1; }
++  free(dn);
+ 
+   pos = dns_packet_copy(buf,len,pos,out,4); if (!pos) return 1;
+   if (byte_diff(out,2,d->qtype)) return 1;
+@@ -53,14 +56,14 @@
+ static void packetfree(struct dns_transmit *d)
+ {
+   if (!d->packet) return;
+-  alloc_free(d->packet);
++  free(d->packet);
+   d->packet = 0;
+ }
+ 
+ static void queryfree(struct dns_transmit *d)
+ {
+   if (!d->query) return;
+-  alloc_free(d->query);
++  free(d->query);
+   d->query = 0;
+ }
+ 
+@@ -83,9 +86,9 @@
+   int j;
+ 
+   for (j = 0;j < 10;++j)
+-    if (socket_bind4(d->s1 - 1,d->localip,1025 + dns_random(64510)) == 0)
++    if (socket_bind6(d->s1 - 1,d->localip,1025 + dns_random(64510),d->scope_id) == 0)
+       return 0;
+-  if (socket_bind4(d->s1 - 1,d->localip,0) == 0)
++  if (socket_bind6(d->s1 - 1,d->localip,0,d->scope_id) == 0)
+     return 0;
+   return -1;
+ }
+@@ -94,22 +97,22 @@
+ 
+ static int thisudp(struct dns_transmit *d)
+ {
+-  char *ip;
++  const char *ip;
+ 
+   socketfree(d);
+ 
+   while (d->udploop < 4) {
+     for (;d->curserver < 16;++d->curserver) {
+-      ip = d->servers + 4 * d->curserver;
+-      if (byte_diff(ip,4,"\0\0\0\0")) {
++      ip = d->servers + 16 * d->curserver;
++      if (byte_diff(ip,16,V6any)) {
+ 	d->query[2] = dns_random(256);
+ 	d->query[3] = dns_random(256);
+   
+-        d->s1 = 1 + socket_udp();
++        d->s1 = 1 + socket_udp6();
+         if (!d->s1) { dns_transmit_free(d); return -1; }
+ 	if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
+ 
+-        if (socket_connect4(d->s1 - 1,ip,53) == 0)
++        if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0)
+           if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) {
+             struct taia now;
+             taia_now(&now);
+@@ -145,29 +148,29 @@
+ static int thistcp(struct dns_transmit *d)
+ {
+   struct taia now;
+-  char *ip;
++  const char *ip;
+ 
+   socketfree(d);
+   packetfree(d);
+ 
+   for (;d->curserver < 16;++d->curserver) {
+-    ip = d->servers + 4 * d->curserver;
+-    if (byte_diff(ip,4,"\0\0\0\0")) {
++    ip = d->servers + 16 * d->curserver;
++    if (byte_diff(ip,16,V6any)) {
+       d->query[2] = dns_random(256);
+       d->query[3] = dns_random(256);
+ 
+-      d->s1 = 1 + socket_tcp();
++      d->s1 = 1 + socket_tcp6();
+       if (!d->s1) { dns_transmit_free(d); return -1; }
+       if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
+   
+       taia_now(&now);
+       taia_uint(&d->deadline,10);
+       taia_add(&d->deadline,&d->deadline,&now);
+-      if (socket_connect4(d->s1 - 1,ip,53) == 0) {
++      if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0) {
+         d->tcpstate = 2;
+         return 0;
+       }
+-      if ((errno == error_inprogress) || (errno == error_wouldblock)) {
++      if ((errno == EINPROGRESS) || (errno == EWOULDBLOCK)) {
+         d->tcpstate = 1;
+         return 0;
+       }
+@@ -191,16 +194,16 @@
+   return thistcp(d);
+ }
+ 
+-int dns_transmit_start(struct dns_transmit *d,char servers[64],int flagrecursive,char *q,char qtype[2],char localip[4])
++int dns_transmit_start(struct dns_transmit *d,const char servers[256],int flagrecursive,const char *q,const char qtype[2],const char localip[16])
+ {
+   unsigned int len;
+ 
+   dns_transmit_free(d);
+-  errno = error_io;
++  errno = EIO;
+ 
+   len = dns_domain_length(q);
+   d->querylen = len + 18;
+-  d->query = alloc(d->querylen);
++  d->query = malloc(d->querylen);
+   if (!d->query) return -1;
+ 
+   uint16_pack_big(d->query,len + 16);
+@@ -211,7 +214,7 @@
+ 
+   byte_copy(d->qtype,2,qtype);
+   d->servers = servers;
+-  byte_copy(d->localip,4,localip);
++  byte_copy(d->localip,16,localip);
+ 
+   d->udploop = flagrecursive ? 1 : 0;
+ 
+@@ -236,19 +239,19 @@
+     *deadline = d->deadline;
+ }
+ 
+-int dns_transmit_get(struct dns_transmit *d,iopause_fd *x,struct taia *when)
++int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when)
+ {
+   char udpbuf[513];
+   unsigned char ch;
+   int r;
+   int fd;
+ 
+-  errno = error_io;
++  errno = EIO;
+   fd = d->s1 - 1;
+ 
+   if (!x->revents) {
+     if (taia_less(when,&d->deadline)) return 0;
+-    errno = error_timeout;
++    errno = ETIMEDOUT;
+     if (d->tcpstate == 0) return nextudp(d);
+     return nexttcp(d);
+   }
+@@ -260,7 +263,7 @@
+ */
+     r = recv(fd,udpbuf,sizeof udpbuf,0);
+     if (r <= 0) {
+-      if (d->udploop == 2) return 0;
++      if (errno == ECONNREFUSED) if (d->udploop == 2) return 0;
+       return nextudp(d);
+     }
+     if (r + 1 > sizeof udpbuf) return 0;
+@@ -274,7 +277,7 @@
+     socketfree(d);
+ 
+     d->packetlen = r;
+-    d->packet = alloc(d->packetlen);
++    d->packet = malloc(d->packetlen);
+     if (!d->packet) { dns_transmit_free(d); return -1; }
+     byte_copy(d->packet,d->packetlen,udpbuf);
+     queryfree(d);
+@@ -334,7 +337,7 @@
+     d->packetlen += ch;
+     d->tcpstate = 5;
+     d->pos = 0;
+-    d->packet = alloc(d->packetlen);
++    d->packet = malloc(d->packetlen);
+     if (!d->packet) { dns_transmit_free(d); return -1; }
+     return 0;
+   }
+diff -uNr ucspi-tcp-0.88.orig/dns_txt.c ucspi-tcp-0.88/dns_txt.c
+--- ucspi-tcp-0.88.orig/dns_txt.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/dns_txt.c	2009-03-19 12:43:14.898761744 +0100
+@@ -3,7 +3,7 @@
+ #include "byte.h"
+ #include "dns.h"
+ 
+-int dns_txt_packet(stralloc *out,char *buf,unsigned int len)
++int dns_txt_packet(stralloc *out,const char *buf,unsigned int len)
+ {
+   unsigned int pos;
+   char header[12];
+@@ -48,7 +48,7 @@
+ 
+ static char *q = 0;
+ 
+-int dns_txt(stralloc *out,stralloc *fqdn)
++int dns_txt(stralloc *out,const stralloc *fqdn)
+ {
+   if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
+   if (dns_resolve(q,DNS_T_TXT) == -1) return -1;
+diff -uNr ucspi-tcp-0.88.orig/error.h ucspi-tcp-0.88/error.h
+--- ucspi-tcp-0.88.orig/error.h	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/error.h	2009-03-19 12:43:14.898761744 +0100
+@@ -1,7 +1,7 @@
+ #ifndef ERROR_H
+ #define ERROR_H
+ 
+-extern int errno;
++#include <errno.h>
+ 
+ extern int error_intr;
+ extern int error_nomem;
+diff -uNr ucspi-tcp-0.88.orig/finger@.1 ucspi-tcp-0.88/finger@.1
+--- ucspi-tcp-0.88.orig/finger@.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/finger@.1	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1,45 @@
++.TH finger@ 1
++.SH NAME
++finger@ \- get user information from a host
++.SH SYNTAX
++.B finger@
++[
++.I host
++[
++.I user
++]
++]
++.SH DESCRIPTION
++.B finger@
++connects to TCP port 79 (Finger) on
++.IR host ,
++sends
++.I user
++(with an extra CR)
++to
++.IR host ,
++and prints any data it receives.
++It removes CR and converts unprintable characters to a visible format.
++Some computers respond to port 79 with information about
++.IR user .
++
++If
++.I user
++is not supplied,
++.B finger@
++sends a blank line to
++.IR host .
++Some computers respond with information about
++all the users who are logged in.
++
++If
++.I host
++is not supplied,
++.B finger@
++connects to the local host.
++.SH "SEE ALSO"
++addcr(1),
++cat(1),
++delcr(1),
++finger(1),
++tcpclient(1)
+diff -uNr ucspi-tcp-0.88.orig/fixcr.1 ucspi-tcp-0.88/fixcr.1
+--- ucspi-tcp-0.88.orig/fixcr.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/fixcr.1	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1,11 @@
++.TH fixcr 1
++.SH NAME
++fixcr \- make sure that there is a CR before each LF
++.SH SYNOPSIS
++.B fixcr
++.SH DESCRIPTION
++.B fixcr
++inserts CR at the end of each line of input where a CR is not already present.
++It does not insert CR at the end of a partial final line.
++.SH "SEE ALSO"
++addcr(1)
+diff -uNr ucspi-tcp-0.88.orig/fmt_xlong.c ucspi-tcp-0.88/fmt_xlong.c
+--- ucspi-tcp-0.88.orig/fmt_xlong.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/fmt_xlong.c	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1,22 @@
++#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(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 -uNr ucspi-tcp-0.88.orig/haveip6.h1 ucspi-tcp-0.88/haveip6.h1
+--- ucspi-tcp-0.88.orig/haveip6.h1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/haveip6.h1	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1 @@
++
+diff -uNr ucspi-tcp-0.88.orig/haveip6.h2 ucspi-tcp-0.88/haveip6.h2
+--- ucspi-tcp-0.88.orig/haveip6.h2	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/haveip6.h2	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1 @@
++#define LIBC_HAS_IP6 1
+diff -uNr ucspi-tcp-0.88.orig/hier.c ucspi-tcp-0.88/hier.c
+--- ucspi-tcp-0.88.orig/hier.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/hier.c	2009-03-19 12:43:14.898761744 +0100
+@@ -4,6 +4,9 @@
+ {
+   h(auto_home,-1,-1,02755);
+   d(auto_home,"bin",-1,-1,02755);
++  d(auto_home,"man",-1,-1,02755);
++  d(auto_home,"man/man1",-1,-1,02755);
++  d(auto_home,"man/man5",-1,-1,02755);
+ 
+   c(auto_home,"bin","tcpserver",-1,-1,0755);
+   c(auto_home,"bin","tcprules",-1,-1,0755);
+@@ -22,4 +25,20 @@
+   c(auto_home,"bin","delcr",-1,-1,0755);
+   c(auto_home,"bin","fixcrio",-1,-1,0755);
+   c(auto_home,"bin","rblsmtpd",-1,-1,0755);
++
++  c(auto_home,"man/man1","tcpclient.1",-1,-1,0644);
++  c(auto_home,"man/man1","tcpserver.1",-1,-1,0644);
++  c(auto_home,"man/man1","tcprules.1",-1,-1,0644);
++  c(auto_home,"man/man1","tcprulescheck.1",-1,-1,0644);
++  c(auto_home,"man/man1","fixcr.1",-1,-1,0644);
++  c(auto_home,"man/man1","addcr.1",-1,-1,0644);
++  c(auto_home,"man/man1","delcr.1",-1,-1,0644);
++  c(auto_home,"man/man1","who@.1",-1,-1,0644);
++  c(auto_home,"man/man1","date@.1",-1,-1,0644);
++  c(auto_home,"man/man1","finger@.1",-1,-1,0644);
++  c(auto_home,"man/man1","http@.1",-1,-1,0644);
++  c(auto_home,"man/man1","mconnect.1",-1,-1,0644);
++  c(auto_home,"man/man1","argv0.1",-1,-1,0644);
++  c(auto_home,"man/man1","recordio.1",-1,-1,0644);
++  c(auto_home,"man/man5","tcp-environ.5",-1,-1,0644);
+ }
+diff -uNr ucspi-tcp-0.88.orig/http@.1 ucspi-tcp-0.88/http@.1
+--- ucspi-tcp-0.88.orig/http@.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/http@.1	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1,52 @@
++.TH http@ 1
++.SH NAME
++http@ \- get a web page from a host through HTTP
++.SH SYNTAX
++.B http@
++[
++.I host
++[
++.I page
++[
++.I port
++]
++]
++]
++.SH DESCRIPTION
++.B http@
++connects to
++.I port
++on
++.IR host ,
++sends
++.B GET /\fIpage
++(with an extra CR)
++to
++.IR host ,
++and prints any data it receives,
++removing CR from the end of each line.
++
++If
++.I port
++is not supplied,
++.B http@
++uses port 80 (HTTP).
++
++If
++.I page
++is not supplied,
++.B http@
++sends
++.B GET /
++to
++.IR host .
++
++If
++.I host
++is not supplied,
++.B http@
++connects to the local host.
++.SH "SEE ALSO"
++addcr(1),
++delcr(1),
++tcpclient(1)
+diff -uNr ucspi-tcp-0.88.orig/ip4.h ucspi-tcp-0.88/ip4.h
+--- ucspi-tcp-0.88.orig/ip4.h	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/ip4.h	2009-03-19 12:43:14.898761744 +0100
+@@ -6,4 +6,6 @@
+ 
+ #define IP4_FMT 20
+ 
++extern const char ip4loopback[4]; /* = {127,0,0,1}; */
++
+ #endif
+diff -uNr ucspi-tcp-0.88.orig/ip6.h ucspi-tcp-0.88/ip6.h
+--- ucspi-tcp-0.88.orig/ip6.h	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/ip6.h	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1,28 @@
++#ifndef IP6_H
++#define IP6_H
++
++#include "byte.h"
++
++extern unsigned int scan_ip6(const char *src,char *ip);
++extern unsigned int fmt_ip6(char *dest,const char *ip);
++
++extern unsigned int scan_ip6_flat(const char *src,char *);
++extern unsigned int fmt_ip6_flat(char *dest,const char *);
++
++/*
++ ip6 address syntax: (h = hex digit), no leading '0' required
++   1. hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh
++   2. any number of 0000 may be abbreviated as "::", but only once
++ flat ip6 address syntax:
++   hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
++ */
++
++#define IP6_FMT 40
++
++extern const unsigned char V4mappedprefix[12]; /*={0,0,0,0,0,0,0,0,0,0,0xff,0xff}; */
++extern const unsigned char V6loopback[16]; /*={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; */
++extern const unsigned char V6any[16]; /*={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; */
++
++#define ip6_isv4mapped(ip) (byte_equal(ip,12,V4mappedprefix))
++
++#endif
+diff -uNr ucspi-tcp-0.88.orig/ip6_fmt.c ucspi-tcp-0.88/ip6_fmt.c
+--- ucspi-tcp-0.88.orig/ip6_fmt.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/ip6_fmt.c	2009-03-19 12:45:32.203705811 +0100
+@@ -0,0 +1,64 @@
++#include "fmt.h"
++#include "byte.h"
++#include "ip4.h"
++#include "ip6.h"
++
++unsigned int ip6_fmt(char *s,char ip[16])
++{
++  unsigned long len,temp, k, pos0=0,len0=0, pos1=0, compr=0;
++
++  for (k=0; k<16; k+=2) {
++    if (ip[k]==0 && ip[k+1]==0) {
++      if (!compr) {
++        compr=1;
++        pos1=k;
++      }
++      if (k==14) { k=16; goto last; }
++    } else if (compr) {
++    last:
++      if ((temp=k-pos1) > len0) {
++        len0=temp;
++        pos0=pos1;
++      }
++      compr=0;
++    }
++  }
++
++  for (len=0,k=0; k<16; k+=2) {
++    if (k==12 && ip6_isv4mapped(ip)) {
++      len += ip4_fmt(s,ip+12);
++      break;
++    }
++    if (pos0==k && len0) {
++      if (k==0) { ++len; if (s) *s++ = ':'; }
++      ++len; if (s) *s++ = ':';
++      k += len0-2;
++      continue;
++    }
++    temp = ((unsigned long) (unsigned char) ip[k] << 8) +
++            (unsigned long) (unsigned char) ip[k+1];
++    temp = fmt_xlong(s,temp); len += temp; if (s) s += temp;
++    if (k<14) { ++len; if (s) *s++ = ':'; }
++  }
++
++  return len;
++}
++
++static char tohex(char num) {
++  if (num<10)
++    return num+'0';
++  else if (num<16)
++    return num-10+'a';
++  else
++    return -1;
++}
++
++unsigned int ip6_fmt_flat(char *s,char ip[16])
++{
++  int i;
++  for (i=0; i<16; i++) {
++    *s++=tohex((unsigned char)ip[i] >> 4);
++    *s++=tohex((unsigned char)ip[i] & 15);
++  }
++  return 32;
++}
+diff -uNr ucspi-tcp-0.88.orig/mconnect.1 ucspi-tcp-0.88/mconnect.1
+--- ucspi-tcp-0.88.orig/mconnect.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/mconnect.1	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1,36 @@
++.TH mconnect 1
++.SH NAME
++mconnect \- connect to the SMTP server on a host
++.SH SYNTAX
++.B mconnect
++[
++.I host
++[
++.I port
++]
++]
++.SH DESCRIPTION
++.B mconnect
++connects to
++.I port
++on
++.IR host .
++It sends its input to
++.IR host ,
++adding a CR to each line.
++Meanwhile it prints anything it receives from
++.IR host .
++
++If
++.I port
++is not supplied,
++.B mconnect
++uses port 25 (SMTP).
++
++If
++.I host
++is not supplied,
++.B mconnect
++connects to the local host.
++.SH "SEE ALSO"
++tcpclient(1)
+diff -uNr ucspi-tcp-0.88.orig/old-rules.c ucspi-tcp-0.88/old-rules.c
+--- ucspi-tcp-0.88.orig/old-rules.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/old-rules.c	2009-03-19 12:43:14.898761744 +0100
+@@ -0,0 +1,101 @@
++#include "alloc.h"
++#include "stralloc.h"
++#include "open.h"
++#include "cdb.h"
++#include "rules.h"
++
++stralloc rules_name = {0};
++
++static struct cdb c;
++
++static int dorule(void (*callback)(char *,unsigned int))
++{
++  char *data;
++  unsigned int datalen;
++
++  switch(cdb_find(&c,rules_name.s,rules_name.len)) {
++    case -1: return -1;
++    case 0: return 0;
++  }
++
++  datalen = cdb_datalen(&c);
++  data = alloc(datalen);
++  if (!data) return -1;
++  if (cdb_read(&c,data,datalen,cdb_datapos(&c)) == -1) {
++    alloc_free(data);
++    return -1;
++  }
++
++  callback(data,datalen);
++  alloc_free(data);
++  return 1;
++}
++
++static int doit(void (*callback)(char *,unsigned int),char *ip,char *host,char *info)
++{
++  int r;
++
++  if (info) {
++    if (!stralloc_copys(&rules_name,info)) return -1;
++    if (!stralloc_cats(&rules_name,"@")) return -1;
++    if (!stralloc_cats(&rules_name,ip)) return -1;
++    r = dorule(callback);
++    if (r) return r;
++
++    if (host) {
++      if (!stralloc_copys(&rules_name,info)) return -1;
++      if (!stralloc_cats(&rules_name,"@=")) return -1;
++      if (!stralloc_cats(&rules_name,host)) return -1;
++      r = dorule(callback);
++      if (r) return r;
++    }
++  }
++
++  if (!stralloc_copys(&rules_name,ip)) return -1;
++  r = dorule(callback);
++  if (r) return r;
++
++  if (host) {
++    if (!stralloc_copys(&rules_name,"=")) return -1;
++    if (!stralloc_cats(&rules_name,host)) return -1;
++    r = dorule(callback);
++    if (r) return r;
++  }
++
++  if (!stralloc_copys(&rules_name,ip)) return -1;
++  while (rules_name.len > 0) {
++    if (ip[rules_name.len - 1] == '.' ||
++	(ip[rules_name.len-1]==':' && rules_name.len>1)) {
++      r = dorule(callback);
++      if (r) return r;
++    }
++    --rules_name.len;
++  }
++
++  if (host) {
++    while (*host) {
++      if (*host == '.') {
++        if (!stralloc_copys(&rules_name,"=")) return -1;
++        if (!stralloc_cats(&rules_name,host)) return -1;
++	r = dorule(callback);
++	if (r) return r;
++      }
++      ++host;
++    }
++    if (!stralloc_copys(&rules_name,"=")) return -1;
++    r = dorule(callback);
++    if (r) return r;
++  }
++
++  rules_name.len = 0;
++  return dorule(callback);
++}
++
++int rules(void (*callback)(char *,unsigned int),int fd,char *ip,char *host,char *info)
++{
++  int r;
++  cdb_init(&c,fd);
++  r = doit(callback,ip,host,info);
++  cdb_free(&c);
++  return r;
++}
+diff -uNr ucspi-tcp-0.88.orig/pathexec.h ucspi-tcp-0.88/pathexec.h
+--- ucspi-tcp-0.88.orig/pathexec.h	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/pathexec.h	2009-03-19 12:43:14.902761714 +0100
+@@ -2,7 +2,7 @@
+ #define PATHEXEC_H
+ 
+ extern void pathexec_run(char *,char **,char **);
+-extern int pathexec_env(char *,char *);
++extern int pathexec_env(const char *,const char *);
+ extern void pathexec(char **);
+ 
+ #endif
+diff -uNr ucspi-tcp-0.88.orig/pathexec_env.c ucspi-tcp-0.88/pathexec_env.c
+--- ucspi-tcp-0.88.orig/pathexec_env.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/pathexec_env.c	2009-03-19 12:43:14.902761714 +0100
+@@ -8,7 +8,7 @@
+ static stralloc plus;
+ static stralloc tmp;
+ 
+-int pathexec_env(char *s,char *t)
++int pathexec_env(const char *s,const char *t)
+ {
+   if (!s) return 1;
+   if (!stralloc_copys(&tmp,s)) return 0;
+@@ -22,7 +22,6 @@
+ 
+ void pathexec(char **argv)
+ {
+-  char *path;
+   char **e;
+   unsigned int elen;
+   unsigned int i;
+diff -uNr ucspi-tcp-0.88.orig/recordio.1 ucspi-tcp-0.88/recordio.1
+--- ucspi-tcp-0.88.orig/recordio.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/recordio.1	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,75 @@
++.TH recordio 1
++.SH NAME
++recordio \- record the input and output of a program
++.SH SYNTAX
++.B recordio
++.I program
++[
++.I arg ...
++]
++.SH DESCRIPTION
++.B recordio
++runs
++.I program
++with the given arguments.
++It prints lines to stderr
++showing the input and output of
++.IR program .
++
++At the beginning of each line on stderr,
++.B recordio
++inserts the
++.I program
++process ID,
++along with
++.B <
++for input or
++.B >
++for output.
++At the end of each line it inserts a space, a plus sign, or [EOF];
++a space indicates that there was a newline in the input or output,
++and [EOF] indicates the end of input or output.
++
++.B recordio
++prints every packet of input and output immediately.
++It does not attempt to combine packets into coherent stderr lines.
++For example,
++
++.EX
++     recordio sh -c 'cat /dev/fd/8 2>&1' > /dev/null
++.EE
++
++could produce
++
++.EX
++     5135 > cat: /dev/fd/8: Bad file descriptor 
++.br
++     5135 > [EOF]
++.EE
++
++or
++
++.EX
++     5135 > cat: +
++.br
++     5135 > /dev/fd/8+
++.br
++     5135 > : +
++.br
++     5135 > Bad file descriptor 
++.br
++     5135 > [EOF]
++.EE
++
++.B recordio
++uses several lines for long packets
++to guarantee that each line is printed atomically to stderr.
++
++.B recordio
++runs as a child of
++.IR program .
++It exits when it sees the end of
++.IR program 's
++output.
++.SH "SEE ALSO"
++tcpserver(1)
+diff -uNr ucspi-tcp-0.88.orig/remoteinfo.h ucspi-tcp-0.88/remoteinfo.h
+--- ucspi-tcp-0.88.orig/remoteinfo.h	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/remoteinfo.h	2009-03-19 12:43:14.902761714 +0100
+@@ -5,5 +5,6 @@
+ #include "uint16.h"
+ 
+ extern int remoteinfo(stralloc *,char *,uint16,char *,uint16,unsigned int);
++extern int remoteinfo6(stralloc *,char *,uint16,char *,uint16,unsigned int,uint32);
+ 
+ #endif
+diff -uNr ucspi-tcp-0.88.orig/remoteinfo6.c ucspi-tcp-0.88/remoteinfo6.c
+--- ucspi-tcp-0.88.orig/remoteinfo6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/remoteinfo6.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,98 @@
++#include "fmt.h"
++#include "buffer.h"
++#include "socket.h"
++#include "error.h"
++#include "iopause.h"
++#include "timeoutconn.h"
++#include "remoteinfo.h"
++
++static struct taia now;
++static struct taia deadline;
++
++static int mywrite(int fd,char *buf,int len)
++{
++  iopause_fd x;
++
++  x.fd = fd;
++  x.events = IOPAUSE_WRITE;
++  for (;;) {
++    taia_now(&now);
++    iopause(&x,1,&deadline,&now);
++    if (x.revents) break;
++    if (taia_less(&deadline,&now)) {
++      errno = error_timeout;
++      return -1;
++    }
++  }
++  return write(fd,buf,len);
++}
++
++static int myread(int fd,char *buf,int len)
++{
++  iopause_fd x;
++
++  x.fd = fd;
++  x.events = IOPAUSE_READ;
++  for (;;) {
++    taia_now(&now);
++    iopause(&x,1,&deadline,&now);
++    if (x.revents) break;
++    if (taia_less(&deadline,&now)) {
++      errno = error_timeout;
++      return -1;
++    }
++  }
++  return read(fd,buf,len);
++}
++
++static int doit(stralloc *out,int s,char ipremote[16],uint16 portremote,char iplocal[16],uint16 portlocal,unsigned int timeout,uint32 netif)
++{
++  buffer b;
++  char bspace[128];
++  char strnum[FMT_ULONG];
++  int numcolons;
++  char ch;
++
++  if (socket_bind6(s,iplocal,0,netif) == -1) return -1;
++  if (timeoutconn6(s,ipremote,113,timeout,netif) == -1) return -1;
++
++  buffer_init(&b,mywrite,s,bspace,sizeof bspace);
++  buffer_put(&b,strnum,fmt_ulong(strnum,portremote));
++  buffer_put(&b," , ",3);
++  buffer_put(&b,strnum,fmt_ulong(strnum,portlocal));
++  buffer_put(&b,"\r\n",2);
++  if (buffer_flush(&b) == -1) return -1;
++
++  buffer_init(&b,myread,s,bspace,sizeof bspace);
++  numcolons = 0;
++  for (;;) {
++    if (buffer_get(&b,&ch,1) != 1) return -1;
++    if ((ch == ' ') || (ch == '\t') || (ch == '\r')) continue;
++    if (ch == '\n') return 0;
++    if (numcolons < 3) {
++      if (ch == ':') ++numcolons;
++    }
++    else {
++      if (!stralloc_append(out,&ch)) return -1;
++      if (out->len > 256) return 0;
++    }
++  }
++}
++
++int remoteinfo6(stralloc *out,char ipremote[16],uint16 portremote,char iplocal[16],uint16 portlocal,unsigned int timeout,uint32 netif)
++{
++  int s;
++  int r;
++
++  if (!stralloc_copys(out,"")) return -1;
++
++  taia_now(&now);
++  taia_uint(&deadline,timeout);
++  taia_add(&deadline,&now,&deadline);
++
++  s = socket_tcp6();
++  if (s == -1) return -1;
++  r = doit(out,s,ipremote,portremote,iplocal,portlocal,timeout,netif);
++  close(s);
++  return r;
++}
+diff -uNr ucspi-tcp-0.88.orig/rules.c ucspi-tcp-0.88/rules.c
+--- ucspi-tcp-0.88.orig/rules.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/rules.c	2009-03-19 12:43:14.902761714 +0100
+@@ -64,7 +64,7 @@
+ 
+   if (!stralloc_copys(&rules_name,ip)) return -1;
+   while (rules_name.len > 0) {
+-    if (ip[rules_name.len - 1] == '.') {
++    if (ip[rules_name.len - 1] == '.' || ip[rules_name.len - 1] == ':') {
+       r = dorule(callback);
+       if (r) return r;
+     }
+diff -uNr ucspi-tcp-0.88.orig/scan_ip6.c ucspi-tcp-0.88/scan_ip6.c
+--- ucspi-tcp-0.88.orig/scan_ip6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/scan_ip6.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,87 @@
++#include "scan.h"
++#include "ip4.h"
++#include "ip6.h"
++
++/*
++ * 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 scan_ip6(const char *s,char ip[16])
++{
++  unsigned int i;
++  unsigned int len=0;
++  unsigned long u;
++
++  char suffix[16];
++  int prefixlen=0;
++  int suffixlen=0;
++
++  if ((i=ip4_scan((char*)s,ip+12))) {
++    for (len=0; len<12; ++len) ip[len]=V4mappedprefix[len];
++    return i;
++  }
++  for (i=0; i<16; i++) ip[i]=0;
++  for (;;) {
++    if (*s == ':') {
++      len++;
++      if (s[1] == ':') {	/* Found "::", skip to part 2 */
++	s+=2;
++	len++;
++	break;
++      }
++      s++;
++    }
++    i = scan_xlong((char*)s,&u);
++    if (!i) return 0;
++    if (prefixlen==12 && s[i]=='.') {
++      /* the last 4 bytes may be written as IPv4 address */
++      i=ip4_scan((char*)s,ip+12);
++      if (i)
++	return i+len;
++      else
++	return 0;
++    }
++    ip[prefixlen++] = (u >> 8);
++    ip[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_xlong((char*)s,&u);
++    if (!i) {
++      len--;
++      break;
++    }
++    if (suffixlen+prefixlen<=12 && s[i]=='.') {
++      int j=ip4_scan((char*)s,suffix+suffixlen);
++      if (j) {
++	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; i<suffixlen; i++)
++    ip[16-suffixlen+i] = suffix[i];
++  return len;
++}
+diff -uNr ucspi-tcp-0.88.orig/scan_xlong.c ucspi-tcp-0.88/scan_xlong.c
+--- ucspi-tcp-0.88.orig/scan_xlong.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/scan_xlong.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,23 @@
++#include "scan.h"
++
++static 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_xlong(char *src,unsigned long *dest) {
++  register const char *tmp=src;
++  register int l=0;
++  register unsigned char c;
++  while ((c=fromhex(*tmp))<16) {
++    l=(l<<4)+c;
++    ++tmp;
++  }
++  *dest=l;
++  return tmp-src;
++}
+diff -uNr ucspi-tcp-0.88.orig/socket.h ucspi-tcp-0.88/socket.h
+--- ucspi-tcp-0.88.orig/socket.h	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/socket.h	2009-03-19 12:43:14.902761714 +0100
+@@ -2,21 +2,52 @@
+ #define SOCKET_H
+ 
+ #include "uint16.h"
++#include "uint32.h"
+ 
+ extern int socket_tcp(void);
+ extern int socket_udp(void);
++extern int socket_tcp6(void);
++extern int socket_udp6(void);
+ 
+-extern int socket_connect4(int,char *,uint16);
++extern int socket_connect4(int,const char *,uint16);
++extern int socket_connect6(int s,const char *ip,uint16 port,uint32 scope_id);
+ extern int socket_connected(int);
+-extern int socket_bind4(int,char *,uint16);
+-extern int socket_bind4_reuse(int,char *,uint16);
++extern int socket_bind4(int,const char *,uint16);
++extern int socket_bind4_reuse(int,const char *,uint16);
++extern int socket_bind6(int s,const char *ip,uint16 port,uint32 scope_id);
++extern int socket_bind6_reuse(int s,const char *ip,uint16 port,uint32 scope_id);
+ extern int socket_listen(int,int);
+ extern int socket_accept4(int,char *,uint16 *);
++extern int socket_accept6(int s,char *ip,uint16 *port,uint32 *scope_id);
+ extern int socket_recv4(int,char *,int,char *,uint16 *);
+-extern int socket_send4(int,char *,int,char *,uint16);
++extern int socket_send4(int,const char *,int,const char *,uint16);
++extern int socket_recv6(int s,char *buf,unsigned int len,char *ip,uint16 *port,uint32 *scope_id);
++extern int socket_send6(int s,const char *buf,unsigned int len,const char *ip,uint16 port,uint32 scope_id);
+ extern int socket_local4(int,char *,uint16 *);
+ extern int socket_remote4(int,char *,uint16 *);
++extern int socket_local6(int s,char *ip,uint16 *port,uint32 *scope_id);
++extern int socket_remote6(int s,char *ip,uint16 *port,uint32 *scope_id);
++
++/* enable sending udp packets to the broadcast address */
++extern int socket_broadcast(int);
++/* join a multicast group on the given interface */
++extern int socket_mcjoin4(int,char *,char *);
++extern int socket_mcjoin6(int,char *,int);
++/* leave a multicast group on the given interface */
++extern int socket_mcleave4(int,char *);
++extern int socket_mcleave6(int,char *);
++/* set multicast TTL/hop count for outgoing packets */
++extern int socket_mcttl4(int,char);
++extern int socket_mcttl6(int,char);
++/* enable multicast loopback */
++extern int socket_mcloop4(int,char);
++extern int socket_mcloop6(int,char);
++
++extern const char* socket_getifname(uint32 interface);
++extern uint32 socket_getifidx(const char *ifname);
+ 
+ extern void socket_tryreservein(int,int);
+ 
++extern int noipv6;
++
+ #endif
+diff -uNr ucspi-tcp-0.88.orig/socket_accept6.c ucspi-tcp-0.88/socket_accept6.c
+--- ucspi-tcp-0.88.orig/socket_accept6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_accept6.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,44 @@
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include "byte.h"
++#include "socket.h"
++#include "ip6.h"
++#include "haveip6.h"
++#include "error.h"
++
++int socket_accept6(int s,char ip[16],uint16 *port,uint32 *scope_id)
++{
++#ifdef LIBC_HAS_IP6
++  struct sockaddr_in6 sa;
++#else
++  struct sockaddr_in sa;
++#endif
++  unsigned int dummy = sizeof sa;
++  int fd;
++
++  fd = accept(s,(struct sockaddr *) &sa,&dummy);
++  if (fd == -1) return -1;
++
++#ifdef LIBC_HAS_IP6
++  if (sa.sin6_family==AF_INET) {
++    struct sockaddr_in *sa4=(struct sockaddr_in*)&sa;
++    byte_copy(ip,12,V4mappedprefix);
++    byte_copy(ip+12,4,(char *) &sa4->sin_addr);
++    uint16_unpack_big((char *) &sa4->sin_port,port);
++    return fd;
++  }
++  byte_copy(ip,16,(char *) &sa.sin6_addr);
++  uint16_unpack_big((char *) &sa.sin6_port,port);
++  if (scope_id) *scope_id=sa.sin6_scope_id;
++
++  return fd;
++#else
++  byte_copy(ip,12,V4mappedprefix);
++  byte_copy(ip+12,4,(char *) &sa.sin_addr);
++  uint16_unpack_big((char *) &sa.sin_port,port);
++  if (scope_id) *scope_id=0;
++  return fd;
++#endif
++}
+diff -uNr ucspi-tcp-0.88.orig/socket_bind.c ucspi-tcp-0.88/socket_bind.c
+--- ucspi-tcp-0.88.orig/socket_bind.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/socket_bind.c	2009-03-19 12:43:14.902761714 +0100
+@@ -5,7 +5,7 @@
+ #include "byte.h"
+ #include "socket.h"
+ 
+-int socket_bind4(int s,char ip[4],uint16 port)
++int socket_bind4(int s,const char ip[4],uint16 port)
+ {
+   struct sockaddr_in sa;
+ 
+@@ -17,7 +17,7 @@
+   return bind(s,(struct sockaddr *) &sa,sizeof sa);
+ }
+ 
+-int socket_bind4_reuse(int s,char ip[4],uint16 port)
++int socket_bind4_reuse(int s,const char ip[4],uint16 port)
+ {
+   int opt = 1;
+   setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt);
+diff -uNr ucspi-tcp-0.88.orig/socket_bind6.c ucspi-tcp-0.88/socket_bind6.c
+--- ucspi-tcp-0.88.orig/socket_bind6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_bind6.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,45 @@
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include "byte.h"
++#include "socket.h"
++#include "ip6.h"
++#include "haveip6.h"
++#include "error.h"
++
++int socket_bind6(int s,const char ip[16],uint16 port,uint32 scope_id)
++{
++#ifdef LIBC_HAS_IP6
++  struct sockaddr_in6 sa;
++
++  if (noipv6) {
++#endif
++    int i;
++    for (i=0; i<16; i++)
++      if (ip[i]!=0) break;
++    if (i==16 || ip6_isv4mapped(ip))
++      return socket_bind4(s,ip+12,port);
++#ifdef LIBC_HAS_IP6
++  }
++  byte_zero(&sa,sizeof sa);
++  sa.sin6_family = AF_INET6;
++  uint16_pack_big((char *) &sa.sin6_port,port);
++/*  implicit: sa.sin6_flowinfo = 0; */
++  byte_copy((char *) &sa.sin6_addr,16,ip);
++  sa.sin6_scope_id=scope_id;
++
++  return bind(s,(struct sockaddr *) &sa,sizeof sa);
++#else
++  errno=error_proto;
++  return -1;
++#endif
++}
++
++int socket_bind6_reuse(int s,const char ip[16],uint16 port,uint32 scope_id)
++{
++  int opt = 1;
++  setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt);
++  return socket_bind6(s,ip,port,scope_id);
++}
++
+diff -uNr ucspi-tcp-0.88.orig/socket_conn.c ucspi-tcp-0.88/socket_conn.c
+--- ucspi-tcp-0.88.orig/socket_conn.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/socket_conn.c	2009-03-19 12:43:14.902761714 +0100
+@@ -6,7 +6,7 @@
+ #include "byte.h"
+ #include "socket.h"
+ 
+-int socket_connect4(int s,char ip[4],uint16 port)
++int socket_connect4(int s,const char ip[4],uint16 port)
+ {
+   struct sockaddr_in sa;
+ 
+diff -uNr ucspi-tcp-0.88.orig/socket_conn6.c ucspi-tcp-0.88/socket_conn6.c
+--- ucspi-tcp-0.88.orig/socket_conn6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_conn6.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,38 @@
++#include <sys/param.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <errno.h>
++#include "byte.h"
++#include "socket.h"
++#include "ip6.h"
++#include "haveip6.h"
++#include "uint32.h"
++#include "ip4.h"
++
++int socket_connect6(int s,const char ip[16],uint16 port,uint32 scope_id)
++{
++#ifdef LIBC_HAS_IP6
++  struct sockaddr_in6 sa;
++
++  if (noipv6) {
++#endif
++    if (ip6_isv4mapped(ip))
++      return socket_connect4(s,ip+12,port);
++    if (byte_equal(ip,16,V6loopback))
++      return socket_connect4(s,ip4loopback,port);
++#ifdef LIBC_HAS_IP6
++  }
++  byte_zero(&sa,sizeof sa);
++  sa.sin6_family = PF_INET6;
++  uint16_pack_big((char *) &sa.sin6_port,port);
++  sa.sin6_flowinfo = 0;
++  sa.sin6_scope_id = scope_id;
++  byte_copy((char *) &sa.sin6_addr,16,ip);
++
++  return connect(s,(struct sockaddr *) &sa,sizeof sa);
++#else
++  errno=EPROTONOSUPPORT;
++  return -1;
++#endif
++}
+diff -uNr ucspi-tcp-0.88.orig/socket_getifidx.c ucspi-tcp-0.88/socket_getifidx.c
+--- ucspi-tcp-0.88.orig/socket_getifidx.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_getifidx.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,8 @@
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <net/if.h>
++#include "socket.h"
++
++uint32 socket_getifidx(const char* ifname) {
++  return if_nametoindex(ifname);
++}
+diff -uNr ucspi-tcp-0.88.orig/socket_getifname.c ucspi-tcp-0.88/socket_getifname.c
+--- ucspi-tcp-0.88.orig/socket_getifname.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_getifname.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,14 @@
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <net/if.h>
++#include "socket.h"
++
++static char ifname[IFNAMSIZ];
++
++const char* socket_getifname(uint32 interface) {
++  char *tmp=if_indextoname(interface,ifname);
++  if (tmp)
++    return tmp;
++  else
++    return "[unknown]";
++}
+diff -uNr ucspi-tcp-0.88.orig/socket_ip4loopback.c ucspi-tcp-0.88/socket_ip4loopback.c
+--- ucspi-tcp-0.88.orig/socket_ip4loopback.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_ip4loopback.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,2 @@
++
++const char ip4loopback[4] = {127,0,0,1};
+diff -uNr ucspi-tcp-0.88.orig/socket_local6.c ucspi-tcp-0.88/socket_local6.c
+--- ucspi-tcp-0.88.orig/socket_local6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_local6.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,39 @@
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include "byte.h"
++#include "socket.h"
++#include "ip6.h"
++#include "haveip6.h"
++#include "error.h"
++
++int socket_local6(int s,char ip[16],uint16 *port,uint32 *scope_id)
++{
++#ifdef LIBC_HAS_IP6
++  struct sockaddr_in6 sa;
++#else
++  struct sockaddr_in sa;
++#endif
++  unsigned int dummy = sizeof sa;
++
++  if (getsockname(s,(struct sockaddr *) &sa,&dummy) == -1) return -1;
++#ifdef LIBC_HAS_IP6
++  if (sa.sin6_family==AF_INET) {
++    struct sockaddr_in *sa4=(struct sockaddr_in*)&sa;
++    byte_copy(ip,12,V4mappedprefix);
++    byte_copy(ip+12,4,(char *) &sa4->sin_addr);
++    uint16_unpack_big((char *) &sa4->sin_port,port);
++    return 0;
++  }
++  byte_copy(ip,16,(char *) &sa.sin6_addr);
++  uint16_unpack_big((char *) &sa.sin6_port,port);
++  if (scope_id) *scope_id=sa.sin6_scope_id;
++#else
++  byte_copy(ip,12,V4mappedprefix);
++  byte_copy(ip+12,4,(char *) &sa.sin_addr);
++  uint16_unpack_big((char *) &sa.sin_port,port);
++  if (scope_id) *scope_id=0;
++#endif
++  return 0;
++}
+diff -uNr ucspi-tcp-0.88.orig/socket_recv6.c ucspi-tcp-0.88/socket_recv6.c
+--- ucspi-tcp-0.88.orig/socket_recv6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_recv6.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,44 @@
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include "byte.h"
++#include "socket.h"
++#include "ip6.h"
++#include "haveip6.h"
++#include "error.h"
++
++int socket_recv6(int s,char *buf,unsigned int len,char ip[16],uint16 *port,uint32 *scope_id)
++{
++#ifdef LIBC_HAS_IP6
++  struct sockaddr_in6 sa;
++#else
++  struct sockaddr_in sa;
++#endif
++  unsigned int dummy = sizeof sa;
++  int r;
++
++  byte_zero(&sa,dummy);
++  r = recvfrom(s,buf,len,0,(struct sockaddr *) &sa,&dummy);
++  if (r == -1) return -1;
++
++#ifdef LIBC_HAS_IP6
++  if (noipv6) {
++    struct sockaddr_in *sa4=(struct sockaddr_in *)&sa;
++    byte_copy(ip,12,V4mappedprefix);
++    byte_copy(ip+12,4,(char *) &sa4->sin_addr);
++    uint16_unpack_big((char *) &sa4->sin_port,port);
++    return r;
++  }
++  byte_copy(ip,16,(char *) &sa.sin6_addr);
++  uint16_unpack_big((char *) &sa.sin6_port,port);
++  if (scope_id) *scope_id=sa.sin6_scope_id;
++#else
++  byte_copy(ip,12,(char *)V4mappedprefix);
++  byte_copy(ip+12,4,(char *) &sa.sin_addr);
++  uint16_unpack_big((char *) &sa.sin_port,port);
++  if (scope_id) *scope_id=0;
++#endif
++
++  return r;
++}
+diff -uNr ucspi-tcp-0.88.orig/socket_remote6.c ucspi-tcp-0.88/socket_remote6.c
+--- ucspi-tcp-0.88.orig/socket_remote6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_remote6.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,39 @@
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include "byte.h"
++#include "socket.h"
++#include "ip6.h"
++#include "haveip6.h"
++#include "error.h"
++
++int socket_remote6(int s,char ip[16],uint16 *port,uint32 *scope_id)
++{
++#ifdef LIBC_HAS_IP6
++  struct sockaddr_in6 sa;
++#else
++  struct sockaddr_in sa;
++#endif
++  unsigned int dummy = sizeof sa;
++
++  if (getpeername(s,(struct sockaddr *) &sa,&dummy) == -1) return -1;
++#ifdef LIBC_HAS_IP6
++  if (sa.sin6_family==AF_INET) {
++    struct sockaddr_in *sa4=(struct sockaddr_in*)&sa;
++    byte_copy(ip,12,V4mappedprefix);
++    byte_copy(ip+12,4,(char *) &sa4->sin_addr);
++    uint16_unpack_big((char *) &sa4->sin_port,port);
++    return 0;
++  }
++  byte_copy(ip,16,(char *) &sa.sin6_addr);
++  uint16_unpack_big((char *) &sa.sin6_port,port);
++  if (scope_id) *scope_id=sa.sin6_scope_id;
++#else
++  byte_copy(ip,12,V4mappedprefix);
++  byte_copy(ip+12,4,(char *) &sa.sin_addr);
++  uint16_unpack_big((char *) &sa.sin_port,port);
++  if (scope_id) *scope_id=0;
++#endif
++  return 0;
++}
+diff -uNr ucspi-tcp-0.88.orig/socket_send6.c ucspi-tcp-0.88/socket_send6.c
+--- ucspi-tcp-0.88.orig/socket_send6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_send6.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,40 @@
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include "byte.h"
++#include "socket.h"
++#include "ip4.h"
++#include "ip6.h"
++#include "haveip6.h"
++#include "error.h"
++
++int socket_send6(int s,const char *buf,unsigned int len,const char ip[16],uint16 port,uint32 scope_id)
++{
++#ifdef LIBC_HAS_IP6
++  struct sockaddr_in6 sa;
++#else
++  struct sockaddr_in sa;
++#endif
++
++  byte_zero(&sa,sizeof sa);
++#ifdef LIBC_HAS_IP6
++  if (noipv6) {
++#endif
++    if (ip6_isv4mapped(ip))
++      return socket_send4(s,buf,len,ip+12,port);
++    if (byte_equal(ip,16,V6loopback))
++      return socket_send4(s,buf,len,ip4loopback,port);
++#ifdef LIBC_HAS_IP6
++    errno=error_proto;
++    return -1;
++  }
++  sa.sin6_family = AF_INET6;
++  uint16_pack_big((char *) &sa.sin6_port,port);
++  byte_copy((char *) &sa.sin6_addr,16,ip);
++  return sendto(s,buf,len,0,(struct sockaddr *) &sa,sizeof sa);
++#else
++  errno=error_proto;
++  return -1;
++#endif
++}
+diff -uNr ucspi-tcp-0.88.orig/socket_tcp6.c ucspi-tcp-0.88/socket_tcp6.c
+--- ucspi-tcp-0.88.orig/socket_tcp6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_tcp6.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,44 @@
++#include <sys/types.h>
++#include <sys/param.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <errno.h>
++#include "ndelay.h"
++#include "socket.h"
++#include "haveip6.h"
++#include "error.h"
++
++#ifdef LIBC_HAS_IP6
++int noipv6=0;
++#else
++int noipv6=1;
++#endif
++
++int socket_tcp6(void)
++{
++#ifdef LIBC_HAS_IP6
++  int s;
++
++  if (noipv6) goto compat;
++  s = socket(PF_INET6,SOCK_STREAM,0);
++  if (s == -1) {
++    if (errno == EINVAL || errno == EAFNOSUPPORT) {
++compat:
++      s=socket(AF_INET,SOCK_STREAM,0);
++      noipv6=1;
++      if (s==-1) return -1;
++    } else
++    return -1;
++  }
++  if (ndelay_on(s) == -1) { close(s); return -1; }
++#ifdef IPV6_V6ONLY
++  {
++    int zero=0;
++    setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&zero,sizeof(zero));
++  }
++#endif
++  return s;
++#else
++  return socket_tcp();
++#endif
++}
+diff -uNr ucspi-tcp-0.88.orig/socket_udp6.c ucspi-tcp-0.88/socket_udp6.c
+--- ucspi-tcp-0.88.orig/socket_udp6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_udp6.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,38 @@
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <errno.h>
++#include "haveip6.h"
++#include "socket.h"
++
++#ifndef EAFNOSUPPORT
++#define EAFNOSUPPORT EINVAL
++#endif
++
++int socket_udp6(void)
++{
++#ifdef LIBC_HAS_IP6
++  int s;
++
++  if (noipv6) goto compat;
++  s = socket(PF_INET6,SOCK_DGRAM,0);
++  if (s == -1) {
++    if (errno == EINVAL || errno == EAFNOSUPPORT) {
++compat:
++      s=socket(AF_INET,SOCK_DGRAM,0);
++      noipv6=1;
++      if (s==-1) return -1;
++    } else
++    return -1;
++  }
++#ifdef IPV6_V6ONLY
++  {
++    int zero=0;
++    setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&zero,sizeof(zero));
++  }
++#endif
++  return s;
++#else
++  return socket_udp();
++#endif
++}
+diff -uNr ucspi-tcp-0.88.orig/socket_v4mappedprefix.c ucspi-tcp-0.88/socket_v4mappedprefix.c
+--- ucspi-tcp-0.88.orig/socket_v4mappedprefix.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_v4mappedprefix.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,2 @@
++
++const unsigned char V4mappedprefix[12]={0,0,0,0,0,0,0,0,0,0,0xff,0xff};
+diff -uNr ucspi-tcp-0.88.orig/socket_v6any.c ucspi-tcp-0.88/socket_v6any.c
+--- ucspi-tcp-0.88.orig/socket_v6any.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_v6any.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,2 @@
++
++const unsigned char V6any[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+diff -uNr ucspi-tcp-0.88.orig/socket_v6loopback.c ucspi-tcp-0.88/socket_v6loopback.c
+--- ucspi-tcp-0.88.orig/socket_v6loopback.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/socket_v6loopback.c	2009-03-19 12:43:14.902761714 +0100
+@@ -0,0 +1,2 @@
++
++const unsigned char V6loopback[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
+diff -uNr ucspi-tcp-0.88.orig/str.h ucspi-tcp-0.88/str.h
+--- ucspi-tcp-0.88.orig/str.h	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/str.h	2009-03-19 12:43:14.902761714 +0100
+@@ -1,13 +1,13 @@
+ #ifndef STR_H
+ #define STR_H
+ 
+-extern unsigned int str_copy(char *,char *);
+-extern int str_diff(char *,char *);
+-extern int str_diffn(char *,char *,unsigned int);
+-extern unsigned int str_len(char *);
+-extern unsigned int str_chr(char *,int);
+-extern unsigned int str_rchr(char *,int);
+-extern int str_start(char *,char *);
++extern unsigned int str_copy(char *,const char *);
++extern int str_diff(const char *,const char *);
++extern int str_diffn(const char *,const char *,unsigned int);
++extern unsigned int str_len(const char *);
++extern unsigned int str_chr(const char *,int);
++extern unsigned int str_rchr(const char *,int);
++extern int str_start(const char *,const char *);
+ 
+ #define str_equal(s,t) (!str_diff((s),(t)))
+ 
+diff -uNr ucspi-tcp-0.88.orig/str_chr.c ucspi-tcp-0.88/str_chr.c
+--- ucspi-tcp-0.88.orig/str_chr.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/str_chr.c	2009-03-19 12:43:14.902761714 +0100
+@@ -1,9 +1,9 @@
+ #include "str.h"
+ 
+-unsigned int str_chr(register char *s,int c)
++unsigned int str_chr(register const char *s,int c)
+ {
+   register char ch;
+-  register char *t;
++  register const char *t;
+ 
+   ch = c;
+   t = s;
+diff -uNr ucspi-tcp-0.88.orig/str_diff.c ucspi-tcp-0.88/str_diff.c
+--- ucspi-tcp-0.88.orig/str_diff.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/str_diff.c	2009-03-19 12:43:14.902761714 +0100
+@@ -1,6 +1,6 @@
+ #include "str.h"
+ 
+-int str_diff(register char *s,register char *t)
++int str_diff(register const char *s,register const char *t)
+ {
+   register char x;
+ 
+diff -uNr ucspi-tcp-0.88.orig/str_len.c ucspi-tcp-0.88/str_len.c
+--- ucspi-tcp-0.88.orig/str_len.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/str_len.c	2009-03-19 12:43:14.906762234 +0100
+@@ -1,8 +1,8 @@
+ #include "str.h"
+ 
+-unsigned int str_len(char *s)
++unsigned int str_len(const char *s)
+ {
+-  register char *t;
++  register const char *t;
+ 
+   t = s;
+   for (;;) {
+diff -uNr ucspi-tcp-0.88.orig/str_start.c ucspi-tcp-0.88/str_start.c
+--- ucspi-tcp-0.88.orig/str_start.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/str_start.c	2009-03-19 12:43:14.906762234 +0100
+@@ -1,6 +1,6 @@
+ #include "str.h"
+ 
+-int str_start(register char *s,register char *t)
++int str_start(register const char *s,register const char *t)
+ {
+   register char x;
+ 
+diff -uNr ucspi-tcp-0.88.orig/stralloc.h ucspi-tcp-0.88/stralloc.h
+--- ucspi-tcp-0.88.orig/stralloc.h	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/stralloc.h	2009-03-19 12:43:14.906762234 +0100
+@@ -9,18 +9,20 @@
+ extern int stralloc_readyplus(stralloc *,unsigned int);
+ extern int stralloc_copy(stralloc *,stralloc *);
+ extern int stralloc_cat(stralloc *,stralloc *);
+-extern int stralloc_copys(stralloc *,char *);
+-extern int stralloc_cats(stralloc *,char *);
+-extern int stralloc_copyb(stralloc *,char *,unsigned int);
+-extern int stralloc_catb(stralloc *,char *,unsigned int);
++extern int stralloc_copys(stralloc *,const char *);
++extern int stralloc_cats(stralloc *,const char *);
++extern int stralloc_copyb(stralloc *,const char *,unsigned int);
++extern int stralloc_catb(stralloc *,const char *,unsigned int);
+ extern int stralloc_append(stralloc *,char *); /* beware: this takes a pointer to 1 char */
+-extern int stralloc_starts(stralloc *,char *);
++extern int stralloc_starts(stralloc *,const char *);
+ 
+ #define stralloc_0(sa) stralloc_append(sa,"")
+ 
+ extern int stralloc_catulong0(stralloc *,unsigned long,unsigned int);
+ extern int stralloc_catlong0(stralloc *,long,unsigned int);
+ 
++extern void stralloc_free(stralloc *);
++
+ #define stralloc_catlong(sa,l) (stralloc_catlong0((sa),(l),0))
+ #define stralloc_catuint0(sa,i,n) (stralloc_catulong0((sa),(i),(n)))
+ #define stralloc_catint0(sa,i,n) (stralloc_catlong0((sa),(i),(n)))
+diff -uNr ucspi-tcp-0.88.orig/stralloc_catb.c ucspi-tcp-0.88/stralloc_catb.c
+--- ucspi-tcp-0.88.orig/stralloc_catb.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/stralloc_catb.c	2009-03-19 12:43:14.906762234 +0100
+@@ -1,7 +1,7 @@
+ #include "stralloc.h"
+ #include "byte.h"
+ 
+-int stralloc_catb(stralloc *sa,char *s,unsigned int n)
++int stralloc_catb(stralloc *sa,const char *s,unsigned int n)
+ {
+   if (!sa->s) return stralloc_copyb(sa,s,n);
+   if (!stralloc_readyplus(sa,n + 1)) return 0;
+diff -uNr ucspi-tcp-0.88.orig/stralloc_cats.c ucspi-tcp-0.88/stralloc_cats.c
+--- ucspi-tcp-0.88.orig/stralloc_cats.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/stralloc_cats.c	2009-03-19 12:43:14.906762234 +0100
+@@ -2,7 +2,7 @@
+ #include "str.h"
+ #include "stralloc.h"
+ 
+-int stralloc_cats(stralloc *sa,char *s)
++int stralloc_cats(stralloc *sa,const char *s)
+ {
+   return stralloc_catb(sa,s,str_len(s));
+ }
+diff -uNr ucspi-tcp-0.88.orig/stralloc_opyb.c ucspi-tcp-0.88/stralloc_opyb.c
+--- ucspi-tcp-0.88.orig/stralloc_opyb.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/stralloc_opyb.c	2009-03-19 12:43:14.906762234 +0100
+@@ -1,7 +1,7 @@
+ #include "stralloc.h"
+ #include "byte.h"
+ 
+-int stralloc_copyb(stralloc *sa,char *s,unsigned int n)
++int stralloc_copyb(stralloc *sa,const char *s,unsigned int n)
+ {
+   if (!stralloc_ready(sa,n + 1)) return 0;
+   byte_copy(sa->s,n,s);
+diff -uNr ucspi-tcp-0.88.orig/stralloc_opys.c ucspi-tcp-0.88/stralloc_opys.c
+--- ucspi-tcp-0.88.orig/stralloc_opys.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/stralloc_opys.c	2009-03-19 12:43:14.906762234 +0100
+@@ -2,7 +2,7 @@
+ #include "str.h"
+ #include "stralloc.h"
+ 
+-int stralloc_copys(stralloc *sa,char *s)
++int stralloc_copys(stralloc *sa,const char *s)
+ {
+   return stralloc_copyb(sa,s,str_len(s));
+ }
+diff -uNr ucspi-tcp-0.88.orig/tcp-environ.5 ucspi-tcp-0.88/tcp-environ.5
+--- ucspi-tcp-0.88.orig/tcp-environ.5	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/tcp-environ.5	2009-03-19 12:43:14.906762234 +0100
+@@ -0,0 +1,66 @@
++.TH tcp-environ 5
++.SH NAME
++tcp-environ \- TCP-related environment variables
++.SH DESCRIPTION
++The following environment variables
++describe a TCP connection.
++They are set up by
++.BR tcp-env ,
++.BR tcpclient ,
++and
++.BR tcpserver .
++Note that
++.BR TCPLOCALHOST ,
++.BR TCPREMOTEHOST ,
++and
++.B TCPREMOTEINFO
++can contain arbitrary characters.
++.TP 5
++PROTO
++The string
++.BR TCP .
++.TP 5
++TCPLOCALHOST
++The domain name of the local host,
++with uppercase letters converted to lowercase.
++If there is no currently available domain name
++for the local IP address,
++.B TCPLOCALHOST
++is not set.
++.TP 5
++TCPLOCALIP
++The IP address of the local host, in dotted-decimal form.
++.TP 5
++TCPLOCALPORT
++The local TCP port number, in decimal.
++.TP 5
++TCPREMOTEHOST
++The domain name of the remote host,
++with uppercase letters converted to lowercase.
++If there is no currently available domain name
++for the remote IP address,
++.B TCPREMOTEHOST
++is not set.
++.TP 5
++TCPREMOTEINFO
++A connection-specific string, perhaps a username,
++supplied by the remote host
++via 931/1413/IDENT/TAP.
++If the remote host did not supply connection information,
++.B TCPREMOTEINFO
++is not set.
++.TP 5
++TCPREMOTEIP
++The IP address of the remote host.
++.TP 5
++TCPREMOTEPORT
++The remote TCP port number.
++.TP 5
++TCPINTERFACE
++The interface name ("eth0") for IPv6 connections using link-local
++addresses.
++.SH "SEE ALSO"
++tcpclient(1),
++tcpserver(1),
++tcp-env(1),
++tcp(4)
+diff -uNr ucspi-tcp-0.88.orig/tcpcat.1 ucspi-tcp-0.88/tcpcat.1
+--- ucspi-tcp-0.88.orig/tcpcat.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/tcpcat.1	2009-03-19 12:43:14.906762234 +0100
+@@ -0,0 +1,20 @@
++.TH tcpcat 1
++.SH NAME
++tcpcat \- print data from a TCP port
++.SH SYNTAX
++.B tcpcat
++.I host
++.I port
++.SH DESCRIPTION
++.B tcpcat
++connects to
++.I port
++on
++.I host
++and prints any data it receives.
++
++.B tcpcat
++can be used to transfer binary data.
++It does no conversions.
++.SH "SEE ALSO"
++tcpclient(1)
+diff -uNr ucspi-tcp-0.88.orig/tcpclient.1 ucspi-tcp-0.88/tcpclient.1
+--- ucspi-tcp-0.88.orig/tcpclient.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/tcpclient.1	2009-03-19 12:43:14.906762234 +0100
+@@ -0,0 +1,173 @@
++.TH tcpclient 1
++.SH NAME
++tcpclient \- create an outgoing TCP connection
++.SH SYNOPSIS
++.B tcpclient
++[
++.B \-46hHrRdDqQv
++]
++[
++.B \-i\fIlocalip
++]
++[
++.B \-p\fIlocalport
++]
++[
++.B \-T\fItimeoutconn
++]
++[
++.B \-l\fIlocalname
++]
++[
++.B \-t\fItimeoutinfo
++]
++[
++.B \-I\fIinterface
++]
++.I host
++.I port
++.I program
++[
++.I arg ...
++]
++.SH DESCRIPTION
++.B tcpclient
++attempts to connect to a TCP server.
++If it is successful, it runs
++.I program
++with the given arguments,
++with descriptor 6 reading from the network
++and descriptor 7 writing to the network.
++
++The server's address is given by
++.I host
++and
++.IR port .
++.I host
++may be 0, referring to the local machine,
++or a dotted-decimal IP address,
++or a host name;
++if a host has several IP addresses,
++.B tcpclient
++tries each in turn.
++.I port
++may be a numeric port number
++or a port name.
++
++.B tcpclient
++sets up several environment variables,
++as described in
++.B tcp-environ(5).
++.SH OPTIONS
++.TP
++.B \-i\fIlocalip
++Use
++.I localip
++as the IP address for the local side of the connection;
++quit if
++.I localip
++is not available.
++.TP
++.B \-p\fIlocalport
++Use
++.I localport
++as the port number for the local side of the connection;
++quit if
++.I localport
++is not available.
++.TP
++.B \-I\fIinterface
++Use
++.I interface
++as the local network interface.  This is only defined for IPv6 sockets
++and needed if you use link-local IPv6 addresses.
++.TP
++.B \-T\fItimeoutconn
++Give up on the
++connection attempt
++after
++.I timeoutconn
++seconds. Default: 60.
++This timeout applies to each IP address tried.
++.TP
++.B \-d
++(Default.)
++Delay sending data for a fraction of a second whenever the
++remote host is responding slowly,
++to make better use of the network.
++.TP
++.B \-D
++Never delay sending data;
++enable TCP_NODELAY.
++This is appropriate for interactive connections.
++.TP
++.B \-q
++Quiet.
++Do not print any messages.
++.TP
++.B \-Q
++(Default.)
++Print error messages.
++.TP
++.B \-v
++Verbose.
++Print all available messages.
++.SH "DATA-GATHERING OPTIONS"
++.TP
++.B \-h
++(Default.)
++Look up the remote host name for
++.BR TCPREMOTEHOST .
++.TP
++.B \-H
++Do not look up the remote host name;
++unset
++.BR TCPREMOTEHOST .
++.TP
++.B \-l\fIlocalname
++Do not look up the local host name;
++use
++.I localname
++for
++.BR TCPLOCALHOST .
++.TP
++.B \-r
++(Default.)
++Attempt to obtain
++.B TCPREMOTEINFO
++from the remote host.
++.TP
++.B \-R
++Do not attempt to obtain
++.B TCPREMOTEINFO
++from the remote host.
++.TP
++.B \-t\fItimeoutinfo
++Give up on the 
++.B TCPREMOTEINFO
++connection attempt
++after
++.I timeoutinfo
++seconds. Default: 26.
++.TP
++.B \-4
++Fall back to IPv4 sockets.  This is necessary for terminally broken
++systems like OpenBSD which will not let IPv6 sockets connect to
++V4-mapped IPv6 addresses.  Please note that this also applies to DNS
++lookups, so you will have to use an DNS resolver with an IPv6 address to
++connect to IPv6 systems.  Use \fBDNSCACHEIP\fR to set the DNS resolver
++IP dynamically.
++.TP
++.B \-6
++Force IPv6 mode in UCSPI environment variables, even for
++IPv4 connections.  This will set \fB$PROTO\fR to \fBTCP6\fR and put
++IPv4-mapped IPv6 addresses in \fBTCPLOCALIP\fR and \fBTCPREMOTEIP\fR.
++.SH "SEE ALSO"
++date@(1),
++finger@(1),
++http@(1),
++mconnect(1),
++tcpcat(1),
++tcpserver(1),
++who@(1),
++tcp-environ(5)
+diff -uNr ucspi-tcp-0.88.orig/tcpclient.c ucspi-tcp-0.88/tcpclient.c
+--- ucspi-tcp-0.88.orig/tcpclient.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/tcpclient.c	2009-03-19 12:43:14.906762234 +0100
+@@ -9,6 +9,7 @@
+ #include "scan.h"
+ #include "str.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "uint16.h"
+ #include "socket.h"
+ #include "fd.h"
+@@ -20,6 +21,7 @@
+ #include "timeoutconn.h"
+ #include "remoteinfo.h"
+ #include "dns.h"
++#include "byte.h"
+ 
+ #define FATAL "tcpclient: fatal: "
+ #define CONNECT "tcpclient: unable to connect to "
+@@ -31,27 +33,30 @@
+ void usage(void)
+ {
+   strerr_die1x(100,"tcpclient: usage: tcpclient \
+-[ -hHrRdDqQv ] \
++[ -46hHrRdDqQv ] \
+ [ -i localip ] \
+ [ -p localport ] \
+ [ -T timeoutconn ] \
+ [ -l localname ] \
+ [ -t timeoutinfo ] \
++[ -I interface ] \
+ host port program");
+ }
+ 
++int forcev6 = 0;
+ int verbosity = 1;
+ int flagdelay = 1;
+ int flagremoteinfo = 1;
+ int flagremotehost = 1;
+ unsigned long itimeout = 26;
+ unsigned long ctimeout[2] = { 2, 58 };
++uint32 netif = 0;
+ 
+-char iplocal[4] = { 0,0,0,0 };
++char iplocal[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
+ uint16 portlocal = 0;
+ char *forcelocal = 0;
+ 
+-char ipremote[4];
++char ipremote[16];
+ uint16 portremote;
+ 
+ char *hostname;
+@@ -61,12 +66,13 @@
+ static stralloc tmp;
+ static stralloc fqdn;
+ char strnum[FMT_ULONG];
+-char ipstr[IP4_FMT];
++char ipstr[IP6_FMT];
+ 
+ char seed[128];
+ 
+ main(int argc,char **argv)
+ {
++  int fakev4=0;
+   unsigned long u;
+   int opt;
+   char *x;
+@@ -80,8 +86,10 @@
+   close(7);
+   sig_ignore(sig_pipe);
+  
+-  while ((opt = getopt(argc,argv,"dDvqQhHrRi:p:t:T:l:")) != opteof)
++  while ((opt = getopt(argc,argv,"46dDvqQhHrRi:p:t:T:l:I:")) != opteof)
+     switch(opt) {
++      case '4': noipv6 = 1; break;
++      case '6': forcev6 = 1; break;
+       case 'd': flagdelay = 1; break;
+       case 'D': flagdelay = 0; break;
+       case 'v': verbosity = 2; break;
+@@ -97,7 +105,8 @@
+ 		if (optarg[j] == '+') ++j;
+ 		scan_ulong(optarg + j,&ctimeout[1]);
+ 		break;
+-      case 'i': if (!ip4_scan(optarg,iplocal)) usage(); break;
++      case 'i': if (!scan_ip6(optarg,iplocal)) usage(); break;
++      case 'I': netif=socket_getifidx(optarg); break;
+       case 'p': scan_ulong(optarg,&u); portlocal = u; break;
+       default: usage();
+     }
+@@ -108,8 +117,8 @@
+ 
+   hostname = *argv;
+   if (!hostname) usage();
+-  if (str_equal(hostname,"")) hostname = "127.0.0.1";
+-  if (str_equal(hostname,"0")) hostname = "127.0.0.1";
++  if (!hostname[0] || str_equal(hostname,"0"))
++    hostname = (noipv6?"127.0.0.1":"::1");
+ 
+   x = *++argv;
+   if (!x) usage();
+@@ -127,33 +136,36 @@
+   if (!*++argv) usage();
+ 
+   if (!stralloc_copys(&tmp,hostname)) nomem();
+-  if (dns_ip4_qualify(&addresses,&fqdn,&tmp) == -1)
++  if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1)
+     strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": ");
+-  if (addresses.len < 4)
++  if (addresses.len < 16)
+     strerr_die3x(111,FATAL,"no IP address for ",hostname);
+ 
+-  if (addresses.len == 4) {
++  if (addresses.len == 16) {
+     ctimeout[0] += ctimeout[1];
+     ctimeout[1] = 0;
+   }
+ 
+   for (cloop = 0;cloop < 2;++cloop) {
+     if (!stralloc_copys(&moreaddresses,"")) nomem();
+-    for (j = 0;j + 4 <= addresses.len;j += 4) {
+-      s = socket_tcp();
++    for (j = 0;j + 16 <= addresses.len;j += 4) {
++      s = socket_tcp6();
+       if (s == -1)
+         strerr_die2sys(111,FATAL,"unable to create socket: ");
+-      if (socket_bind4(s,iplocal,portlocal) == -1)
++      if (socket_bind6(s,iplocal,portlocal,netif) == -1)
+         strerr_die2sys(111,FATAL,"unable to bind socket: ");
+-      if (timeoutconn(s,addresses.s + j,portremote,ctimeout[cloop]) == 0)
++      if (timeoutconn6(s,addresses.s + j,portremote,ctimeout[cloop],netif) == 0)
+         goto CONNECTED;
+       close(s);
+       if (!cloop && ctimeout[1] && (errno == error_timeout)) {
+-	if (!stralloc_catb(&moreaddresses,addresses.s + j,4)) nomem();
++	if (!stralloc_catb(&moreaddresses,addresses.s + j,16)) nomem();
+       }
+       else {
+         strnum[fmt_ulong(strnum,portremote)] = 0;
+-        ipstr[ip4_fmt(ipstr,addresses.s + j)] = 0;
++	if (ip6_isv4mapped(addresses.s+j))
++	  ipstr[ip4_fmt(ipstr,addresses.s + j + 12)] = 0;
++	else
++	  ipstr[ip6_fmt(ipstr,addresses.s + j)] = 0;
+         strerr_warn5(CONNECT,ipstr," port ",strnum,": ",&strerr_sys);
+       }
+     }
+@@ -169,37 +181,46 @@
+   if (!flagdelay)
+     socket_tcpnodelay(s); /* if it fails, bummer */
+ 
+-  if (!pathexec_env("PROTO","TCP")) nomem();
+-
+-  if (socket_local4(s,iplocal,&portlocal) == -1)
++  if (socket_local6(s,iplocal,&portlocal,&netif) == -1)
+     strerr_die2sys(111,FATAL,"unable to get local address: ");
+ 
++  if (!forcev6 && (ip6_isv4mapped(iplocal) || byte_equal(iplocal,16,V6any)))
++    fakev4=1;
++
++  if (!pathexec_env("PROTO",fakev4?"TCP":"TCP6")) nomem();
++
+   strnum[fmt_ulong(strnum,portlocal)] = 0;
+   if (!pathexec_env("TCPLOCALPORT",strnum)) nomem();
+-  ipstr[ip4_fmt(ipstr,iplocal)] = 0;
++  if (fakev4)
++    ipstr[ip4_fmt(ipstr,iplocal+12)] = 0;
++  else
++    ipstr[ip6_fmt(ipstr,iplocal)] = 0;
+   if (!pathexec_env("TCPLOCALIP",ipstr)) nomem();
+ 
+   x = forcelocal;
+   if (!x)
+-    if (dns_name4(&tmp,iplocal) == 0) {
++    if (dns_name6(&tmp,iplocal) == 0) {
+       if (!stralloc_0(&tmp)) nomem();
+       x = tmp.s;
+     }
+   if (!pathexec_env("TCPLOCALHOST",x)) nomem();
+ 
+-  if (socket_remote4(s,ipremote,&portremote) == -1)
++  if (socket_remote6(s,ipremote,&portremote,&netif) == -1)
+     strerr_die2sys(111,FATAL,"unable to get remote address: ");
+ 
+   strnum[fmt_ulong(strnum,portremote)] = 0;
+   if (!pathexec_env("TCPREMOTEPORT",strnum)) nomem();
+-  ipstr[ip4_fmt(ipstr,ipremote)] = 0;
++  if (fakev4)
++    ipstr[ip4_fmt(ipstr,ipremote+12)] = 0;
++  else
++    ipstr[ip6_fmt(ipstr,ipremote)] = 0;
+   if (!pathexec_env("TCPREMOTEIP",ipstr)) nomem();
+   if (verbosity >= 2)
+     strerr_warn4("tcpclient: connected to ",ipstr," port ",strnum,0);
+ 
+   x = 0;
+   if (flagremotehost)
+-    if (dns_name4(&tmp,ipremote) == 0) {
++    if (dns_name6(&tmp,ipremote) == 0) {
+       if (!stralloc_0(&tmp)) nomem();
+       x = tmp.s;
+     }
+@@ -207,7 +228,7 @@
+ 
+   x = 0;
+   if (flagremoteinfo)
+-    if (remoteinfo(&tmp,ipremote,portremote,iplocal,portlocal,itimeout) == 0) {
++    if (remoteinfo6(&tmp,ipremote,portremote,iplocal,portlocal,itimeout,netif) == 0) {
+       if (!stralloc_0(&tmp)) nomem();
+       x = tmp.s;
+     }
+diff -uNr ucspi-tcp-0.88.orig/tcprules.1 ucspi-tcp-0.88/tcprules.1
+--- ucspi-tcp-0.88.orig/tcprules.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/tcprules.1	2009-03-19 12:43:14.906762234 +0100
+@@ -0,0 +1,221 @@
++.TH tcprules 1
++.SH NAME
++tcprules \- compile rules for tcpserver
++.SH SYNOPSIS
++.B tcprules
++.I rules.cdb
++.I rules.tmp
++.SH OVERVIEW
++.B tcpserver
++optionally follows rules to decide whether a TCP connection is acceptable.
++For example, a rule of
++
++.EX
++   18.23.0.32:deny
++.EE
++
++prohibits connections from IP address 18.23.0.32.
++
++.B tcprules
++reads rules from its standard input
++and writes them into
++.I rules.cdb
++in a binary format suited
++for quick access by
++.BR tcpserver .
++
++.B tcprules
++can be used while
++.B tcpserver
++is running:
++it ensures that
++.I rules.cdb
++is updated atomically.
++It does this by first writing the rules to
++.I rules.tmp
++and then moving
++.I rules.tmp
++on top of
++.IR rules.cdb .
++If
++.I rules.tmp
++already exists, it is destroyed.
++The directories containing
++.I rules.cdb
++and
++.I rules.tmp
++must be writable to
++.BR tcprules ;
++they must also be on the same filesystem.
++
++If there is a problem with the input,
++.B tcprules
++complains and leaves
++.I rules.cdb
++alone.
++
++The binary
++.I rules.cdb
++format is portable across machines.
++.SH "RULE FORMAT"
++A rule takes up one line.
++A file containing rules
++may also contain comments: lines beginning with # are ignored.
++
++Each rule contains an
++.BR address ,
++a colon,
++and a list of
++.BR instructions ,
++with no extra spaces.
++When
++.B tcpserver
++receives a connection from that address,
++it follows the instructions.
++.SH "ADDRESSES"
++.B tcpserver
++starts by looking for a rule with address
++.IR TCPREMOTEINFO\fB@\fITCPREMOTEIP .
++If it doesn't find one, or if
++.I TCPREMOTEINFO
++is not set, it tries the address
++.IR TCPREMOTEIP .
++If that doesn't work, it tries shorter and shorter prefixes of
++.I TCPREMOTEIP
++ending with a dot.
++If none of them work, it tries the empty string.
++
++For example, here are some rules:
++
++.EX
++   joe@127.0.0.1:first
++.br
++   18.23.0.32:second
++.br
++   127.:third
++.br
++   :fourth
++.br
++   ::1:fifth
++.EE
++
++If
++.I TCPREMOTEIP
++is
++.BR 10.119.75.38 ,
++.B tcpserver
++will follow the
++.B fourth
++instructions.
++
++If
++.I TCPREMOTEIP
++is
++.BR ::1 ,
++.B tcpserver
++will follow the
++.B fifth
++instructions.  Note that you cannot detect IPv4 mapped addresses by
++matching "::ffff", as those addresses will be converted to IPv4 before
++looking at the rules.
++
++If
++.I TCPREMOTEIP
++is
++.BR 18.23.0.32 ,
++.B tcpserver
++will follow the
++.B second
++instructions.
++
++If
++.I TCPREMOTEINFO
++is
++.B bill
++and
++.I TCPREMOTEIP
++is
++.BR 127.0.0.1 ,
++.B tcpserver
++will follow the
++.B third
++instructions.
++
++If
++.I TCPREMOTEINFO
++is
++.B joe
++and
++.I TCPREMOTEIP
++is
++.BR 127.0.0.1 ,
++.B tcpserver
++will follow the
++.B first
++instructions.
++.SH "ADDRESS RANGES"
++.B tcprules
++treats
++.B 1.2.3.37-53:ins
++as an abbreviation
++for the rules
++.BR 1.2.3.37:ins ,
++.BR 1.2.3.38:ins ,
++and so on up through
++.BR 1.2.3.53:ins .
++Similarly,
++.BR 10.2-3.:ins
++is an abbreviation for
++.B 10.2.:ins
++and
++.BR 10.3.:ins .
++.SH "INSTRUCTIONS"
++The instructions in a rule must begin with either
++.B allow
++or
++.BR deny .
++.B deny
++tells
++.B tcpserver
++to drop the connection without running anything.
++For example, the rule
++
++.EX
++   :deny
++.EE
++
++tells
++.B tcpserver
++to drop all connections that aren't handled by more specific rules.
++
++The instructions may continue with some environment variables,
++in the format
++.IR ,VAR="VALUE" .
++.B tcpserver
++adds
++.I VAR=VALUE
++to the current environment.
++For example,
++
++.EX
++   10.0.:allow,RELAYCLIENT="@fix.me"
++.EE
++
++adds
++.B RELAYCLIENT=@fix.me
++to the environment.
++The quotes here may be replaced by any repeated character:
++
++.EX
++   10.0.:allow,RELAYCLIENT=/@fix.me/
++.EE
++
++Any number of variables may be listed:
++
++.EX
++   127.0.0.1:allow,RELAYCLIENT="",TCPLOCALHOST="movie.edu"
++.EE
++.SH "SEE ALSO"
++tcprulescheck(1),
++tcpserver(1),
++tcp-environ(5)
+diff -uNr ucspi-tcp-0.88.orig/tcprules.c ucspi-tcp-0.88/tcprules.c
+--- ucspi-tcp-0.88.orig/tcprules.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/tcprules.c	2009-03-19 12:43:14.906762234 +0100
+@@ -123,8 +123,15 @@
+     }
+     line.len = len; /* for die_bad() */
+ 
+-    colon = byte_chr(x,len,':');
+-    if (colon == len) continue;
++    colon = 0;
++    for (;;) {
++      int tmp;
++      tmp = byte_chr(x + colon,len - colon,':');
++      colon += tmp;
++      if (colon == len) continue;
++      if (byte_equal(x+colon+1,4,"deny") || byte_equal(x+colon+1,5,"allow")) break;
++      ++colon;
++    }
+ 
+     if (!stralloc_copyb(&address,x,colon)) nomem();
+     if (!stralloc_copys(&data,"")) nomem();
+diff -uNr ucspi-tcp-0.88.orig/tcprulescheck.1 ucspi-tcp-0.88/tcprulescheck.1
+--- ucspi-tcp-0.88.orig/tcprulescheck.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/tcprulescheck.1	2009-03-19 12:43:14.906762234 +0100
+@@ -0,0 +1,25 @@
++.TH tcprulescheck 1
++.SH NAME
++tcprulescheck \- try out rules for tcpserver
++.SH SYNTAX
++.B tcprulescheck
++.I rules.cdb
++.I tcpremoteip
++[
++.I tcpremoteinfo
++]
++.SH DESCRIPTION
++.B tcprulescheck
++says what
++.B tcpserver
++will do with a connection from
++IP address
++.IR tcpremoteip ,
++following the rules compiled into
++.I rules.cdb
++by
++.BR tcprules .
++.SH "SEE ALSO"
++tcprules(1),
++tcpserver(1),
++tcp-environ(5)
+diff -uNr ucspi-tcp-0.88.orig/tcpserver.1 ucspi-tcp-0.88/tcpserver.1
+--- ucspi-tcp-0.88.orig/tcpserver.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/tcpserver.1	2009-03-19 12:43:14.906762234 +0100
+@@ -0,0 +1,266 @@
++.TH tcpserver 1
++.SH NAME
++tcpserver \- accept incoming TCP connections
++.SH SYNOPSIS
++.B tcpserver
++[
++.B \-146jpPhHrRoOdDqQv
++]
++[
++.B \-c\fIlimit
++]
++[
++.B \-x\fIrules.cdb
++]
++[
++.B \-B\fIbanner
++]
++[
++.B \-g\fIgid
++]
++[
++.B \-u\fIuid
++]
++[
++.B \-b\fIbacklog
++]
++[
++.B \-l\fIlocalname
++]
++[
++.B \-t\fItimeout
++]
++[
++.B \-I\fIinterface
++]
++.I host
++.I port
++.I program
++[
++.I arg ...
++]
++.SH DESCRIPTION
++.B tcpserver
++waits for connections from TCP clients.
++For each connection, it runs
++.I program
++with the given arguments,
++with descriptor 0 reading from the network
++and descriptor 1 writing to the network.
++
++The server's address is given by
++.I host
++and
++.IR port .
++.I host
++can be 0, allowing connections from any host;
++or a particular IP address,
++allowing connections only to that address;
++or a host name, allowing connections to the first IP address
++for that host.
++.I port
++may be a numeric port number
++or a port name.
++If
++.I port
++is 0,
++.B tcpserver
++will choose a free port.
++
++.B tcpserver
++sets up several environment variables,
++as described in
++.B tcp-environ(5).
++
++.B tcpserver
++exits when it receives SIGTERM.
++.SH "OPTIONS"
++.TP
++.B \-c\fIlimit
++Do not handle more than
++.I limit
++simultaneous connections.
++If there are
++.I limit
++simultaneous copies of
++.I program
++running, defer acceptance of a new connection
++until one copy finishes.
++.I limit
++must be a positive integer.
++Default: 40.
++.TP
++.B \-x\fIrules.cdb
++Follow the rules compiled into
++.I rules.cdb
++by
++.BR tcprules .
++These rules may specify setting environment variables
++or rejecting connections from bad sources.
++
++.B tcpserver
++does not read
++.I rules.cdb
++into memory;
++you can rerun
++.B tcprules
++to change
++.BR tcpserver 's
++behavior on the fly.
++.TP
++.B \-B\fIbanner
++Write
++.I banner
++to the network immediately after each connection is made.
++.B tcpserver
++writes
++.I banner
++before looking up
++.BR TCPREMOTEHOST ,
++before looking up
++.BR TCPREMOTEINFO ,
++and before checking
++.IR rules.cdb .
++
++This feature can be used to reduce latency in protocols
++where the client waits for a greeting from the server.
++.TP
++.B \-g\fIgid
++Switch group ID to
++.I gid
++after preparing to receive connections.
++.I gid
++must be a positive integer.
++.TP
++.B \-u\fIuid
++Switch user ID to 
++.I uid
++after preparing to receive connections.
++.I uid
++must be a positive integer.
++.TP
++.B \-1
++After preparing to receive connections,
++print the local port number to standard output.
++.TP
++.B \-4
++Fall back to IPv4 sockets.  This is necessary for terminally broken
++systems like OpenBSD which will not let IPv6 sockets connect to
++V4-mapped IPv6 addresses.  Please note that this also applies to DNS
++lookups, so you will have to use an DNS resolver with an IPv6 address to
++accept IPv6 connections.  Use \fBDNSCACHEIP\fR to set the DNS resolver
++IP dynamically.
++.TP
++.B \-6
++Force IPv6 mode in UCSPI environment variables, even for
++IPv4 connections.  This will set \fB$PROTO\fR to \fBTCP6\fR and put
++IPv4-mapped IPv6 addresses in \fBTCPLOCALIP\fR and \fBTCPREMOTEIP\fR.
++.TP
++.B \-I\fIinterface
++Bind to the network interface
++.I interface
++("eth0" on Linux, for example).  This is only defined and needed for
++IPv6 link-local addresses.
++.TP
++.B \-b\fIbacklog
++Allow up to
++.I backlog
++simultaneous SYN_RECEIVEDs.
++Default: 20.
++On some systems,
++.I backlog
++is silently limited to 5.
++See
++.BR listen (2)
++for more details.
++.TP
++.B \-o
++Leave IP options alone.
++If the client is sending packets along an IP source route,
++send packets back along the same route.
++.TP
++.B \-O
++(Default.)
++Kill IP options.
++A client can still use source routing to connect and to send data,
++but packets will be sent back along the default route.
++.TP
++.B \-d
++(Default.)
++Delay sending data for a fraction of a second whenever the
++remote host is responding slowly,
++to make better use of the network.
++.TP
++.B \-D
++Never delay sending data;
++enable TCP_NODELAY.
++This is appropriate for interactive connections.
++.TP
++.B \-q
++Quiet.
++Do not print any messages.
++.TP
++.B \-Q
++(Default.)
++Print error messages.
++.TP
++.B \-v
++Verbose.
++Print all available messages.
++.SH "DATA-GATHERING OPTIONS"
++.TP
++.B \-p
++Paranoid.
++After looking up the remote host name,
++look up the IP addresses for that name,
++and make sure one of them matches
++.BR TCPREMOTEIP .
++If none of them do,
++unset
++.BR TCPREMOTEHOST .
++.TP
++.B \-P
++(Default.)
++Not paranoid.
++.TP
++.B \-h
++(Default.)
++Look up the remote host name and set
++.BR TCPREMOTEHOST .
++.TP
++.B \-H
++Do not look up the remote host name.
++.TP
++.B \-l\fIlocalname
++Do not look up the local host name;
++use
++.I localname
++for
++.BR TCPLOCALHOST .
++.TP
++.B \-r
++(Default.)
++Attempt to obtain
++.B TCPREMOTEINFO
++from the remote host.
++.TP
++.B \-R
++Do not attempt to obtain
++.B TCPREMOTEINFO
++from the remote host.
++.TP
++.B \-t\fItimeout
++Give up on the 
++.B TCPREMOTEINFO
++connection attempt
++after
++.I timeout
++seconds. Default: 26.
++.SH "SEE ALSO"
++argv0(1),
++fixcr(1),
++recordio(1),
++tcpclient(1),
++tcprules(1),
++listen(2),
++tcp-environ(5)
+diff -uNr ucspi-tcp-0.88.orig/tcpserver.c ucspi-tcp-0.88/tcpserver.c
+--- ucspi-tcp-0.88.orig/tcpserver.c	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/tcpserver.c	2009-03-19 12:43:14.906762234 +0100
+@@ -7,6 +7,7 @@
+ #include "fmt.h"
+ #include "scan.h"
+ #include "ip4.h"
++#include "ip6.h"
+ #include "fd.h"
+ #include "exit.h"
+ #include "env.h"
+@@ -28,6 +29,7 @@
+ #include "sig.h"
+ #include "dns.h"
+ 
++int forcev6 = 0;
+ int verbosity = 1;
+ int flagkillopts = 1;
+ int flagdelay = 1;
+@@ -36,20 +38,21 @@
+ int flagremotehost = 1;
+ int flagparanoid = 0;
+ unsigned long timeout = 26;
++uint32 netif = 0;
+ 
+ static stralloc tcpremoteinfo;
+ 
+ uint16 localport;
+ char localportstr[FMT_ULONG];
+-char localip[4];
+-char localipstr[IP4_FMT];
++char localip[16];
++char localipstr[IP6_FMT];
+ static stralloc localhostsa;
+ char *localhost = 0;
+ 
+ uint16 remoteport;
+ char remoteportstr[FMT_ULONG];
+-char remoteip[4];
+-char remoteipstr[IP4_FMT];
++char remoteip[16];
++char remoteipstr[IP6_FMT];
+ static stralloc remotehostsa;
+ char *remotehost = 0;
+ 
+@@ -96,12 +99,12 @@
+     if (ch < 33) ch = '?';
+     if (ch > 126) ch = '?';
+     if (ch == '%') ch = '?'; /* logger stupidity */
+-    if (ch == ':') ch = '?';
++/*    if (ch == ':') ch = '?'; */
+     append(&ch);
+   }
+   cats("...");
+ }
+-void env(char *s,char *t)
++void env(const char *s,const char *t)
+ {
+   if (!pathexec_env(s,t)) drop_nomem();
+ }
+@@ -135,9 +138,16 @@
+ 
+ void doit(int t)
+ {
++  int fakev4=0;
+   int j;
++  uint32 scope_id;
+ 
+-  remoteipstr[ip4_fmt(remoteipstr,remoteip)] = 0;
++  if (!forcev6 && ip6_isv4mapped(remoteip))
++    fakev4=1;
++  if (fakev4)
++    remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0;
++  else
++    remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0;
+ 
+   if (verbosity >= 2) {
+     strnum[fmt_ulong(strnum,getpid())] = 0;
+@@ -155,30 +165,40 @@
+       strerr_die2sys(111,DROP,"unable to print banner: ");
+   }
+ 
+-  if (socket_local4(t,localip,&localport) == -1)
++  if (socket_local6(t,localip,&localport,&scope_id) == -1)
+     strerr_die2sys(111,DROP,"unable to get local address: ");
+ 
+-  localipstr[ip4_fmt(localipstr,localip)] = 0;
++  if (fakev4)
++    localipstr[ip4_fmt(localipstr,localip+12)] = 0;
++  else
++    localipstr[ip6_fmt(localipstr,localip)] = 0;
+   remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0;
+ 
+   if (!localhost)
+-    if (dns_name4(&localhostsa,localip) == 0)
++    if (dns_name6(&localhostsa,localip) == 0)
+       if (localhostsa.len) {
+ 	if (!stralloc_0(&localhostsa)) drop_nomem();
+ 	localhost = localhostsa.s;
+       }
+-  env("PROTO","TCP");
++  env("PROTO",fakev4?"TCP":"TCP6");
+   env("TCPLOCALIP",localipstr);
++  localipstr[ip6_fmt(localipstr,localip)]=0;
++  env("TCP6LOCALIP",localipstr);
++
+   env("TCPLOCALPORT",localportstr);
++  env("TCP6LOCALPORT",localportstr);
+   env("TCPLOCALHOST",localhost);
++  env("TCP6LOCALHOST",localhost);
++  if (!fakev4 && scope_id)
++    env("TCP6INTERFACE",socket_getifname(scope_id));
+ 
+   if (flagremotehost)
+-    if (dns_name4(&remotehostsa,remoteip) == 0)
++    if (dns_name6(&remotehostsa,remoteip) == 0)
+       if (remotehostsa.len) {
+ 	if (flagparanoid)
+-	  if (dns_ip4(&tmp,&remotehostsa) == 0)
+-	    for (j = 0;j + 4 <= tmp.len;j += 4)
+-	      if (byte_equal(remoteip,4,tmp.s + j)) {
++	  if (dns_ip6(&tmp,&remotehostsa) == 0)
++	    for (j = 0;j + 16 <= tmp.len;j += 16)
++	      if (byte_equal(remoteip,16,tmp.s + j)) {
+ 		flagparanoid = 0;
+ 		break;
+ 	      }
+@@ -188,15 +208,20 @@
+ 	}
+       }
+   env("TCPREMOTEIP",remoteipstr);
++  remoteipstr[ip6_fmt(remoteipstr,remoteip)]=0;
++  env("TCP6REMOTEIP",remoteipstr);
+   env("TCPREMOTEPORT",remoteportstr);
++  env("TCP6REMOTEPORT",remoteportstr);
+   env("TCPREMOTEHOST",remotehost);
++  env("TCP6REMOTEHOST",remotehost);
+ 
+   if (flagremoteinfo) {
+-    if (remoteinfo(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout) == -1)
++    if (remoteinfo6(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1)
+       flagremoteinfo = 0;
+     if (!stralloc_0(&tcpremoteinfo)) drop_nomem();
+   }
+   env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0);
++  env("TCP6REMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0);
+ 
+   if (fnrules) {
+     int fdrules;
+@@ -206,7 +231,15 @@
+       if (!flagallownorules) drop_rules();
+     }
+     else {
+-      if (rules(found,fdrules,remoteipstr,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules();
++      int fakev4=0;
++      char* temp;
++      if (!forcev6 && ip6_isv4mapped(remoteip))
++	fakev4=1;
++      if (fakev4)
++	temp=remoteipstr+7;
++      else
++	temp=remoteipstr;
++      if (rules(found,fdrules,temp,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules();
+       close(fdrules);
+     }
+   }
+@@ -240,7 +273,7 @@
+ {
+   strerr_warn1("\
+ tcpserver: usage: tcpserver \
+-[ -1UXpPhHrRoOdDqQv ] \
++[ -461UXpPhHrRoOdDqQv ] \
+ [ -c limit ] \
+ [ -x rules.cdb ] \
+ [ -B banner ] \
+@@ -249,6 +282,7 @@
+ [ -b backlog ] \
+ [ -l localname ] \
+ [ -t timeout ] \
++[ -I interface ] \
+ host port program",0);
+   _exit(100);
+ }
+@@ -299,8 +333,8 @@
+   unsigned long u;
+   int s;
+   int t;
+- 
+-  while ((opt = getopt(argc,argv,"dDvqQhHrR1UXx:t:u:g:l:b:B:c:pPoO")) != opteof)
++
++  while ((opt = getopt(argc,argv,"46dDvqQhHrR1UXx:t:u:g:l:b:B:c:I:pPoO")) != opteof)
+     switch(opt) {
+       case 'b': scan_ulong(optarg,&backlog); break;
+       case 'c': scan_ulong(optarg,&limit); break;
+@@ -325,7 +359,10 @@
+ 		x = env_get("GID"); if (x) scan_ulong(x,&gid); break;
+       case 'u': scan_ulong(optarg,&uid); break;
+       case 'g': scan_ulong(optarg,&gid); break;
++      case 'I': netif=socket_getifidx(optarg); break;
+       case '1': flag1 = 1; break;
++      case '4': noipv6 = 1; break;
++      case '6': forcev6 = 1; break;
+       case 'l': localhost = optarg; break;
+       default: usage();
+     }
+@@ -337,8 +374,7 @@
+  
+   hostname = *argv++;
+   if (!hostname) usage();
+-  if (str_equal(hostname,"")) hostname = "0.0.0.0";
+-  if (str_equal(hostname,"0")) hostname = "0.0.0.0";
++  if (str_equal(hostname,"")) hostname = "0";
+ 
+   x = *argv++;
+   if (!x) usage();
+@@ -348,7 +384,7 @@
+     se = getservbyname(x,"tcp");
+     if (!se)
+       strerr_die3x(111,FATAL,"unable to figure out port number for ",x);
+-    localport = ntohs(se->s_port);
++    uint16_unpack_big((char*)&se->s_port,&localport);
+   }
+ 
+   if (!*argv) usage();
+@@ -358,20 +394,26 @@
+   sig_catch(sig_term,sigterm);
+   sig_ignore(sig_pipe);
+  
+-  if (!stralloc_copys(&tmp,hostname))
+-    strerr_die2x(111,FATAL,"out of memory");
+-  if (dns_ip4_qualify(&addresses,&fqdn,&tmp) == -1)
+-    strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": ");
+-  if (addresses.len < 4)
+-    strerr_die3x(111,FATAL,"no IP address for ",hostname);
+-  byte_copy(localip,4,addresses.s);
++  if (str_equal(hostname,"0")) {
++    byte_zero(localip,sizeof localip);
++  } else {
++    if (!stralloc_copys(&tmp,hostname))
++      strerr_die2x(111,FATAL,"out of memory");
++    if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1)
++      strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": ");
++    if (addresses.len < 16)
++      strerr_die3x(111,FATAL,"no IP address for ",hostname);
++    byte_copy(localip,16,addresses.s);
++    if (ip6_isv4mapped(localip))
++      noipv6=1;
++  }
+ 
+-  s = socket_tcp();
++  s = socket_tcp6();
+   if (s == -1)
+     strerr_die2sys(111,FATAL,"unable to create socket: ");
+-  if (socket_bind4_reuse(s,localip,localport) == -1)
++  if (socket_bind6_reuse(s,localip,localport,netif) == -1)
+     strerr_die2sys(111,FATAL,"unable to bind: ");
+-  if (socket_local4(s,localip,&localport) == -1)
++  if (socket_local6(s,localip,&localport,&netif) == -1)
+     strerr_die2sys(111,FATAL,"unable to get local address: ");
+   if (socket_listen(s,backlog) == -1)
+     strerr_die2sys(111,FATAL,"unable to listen: ");
+@@ -399,7 +441,7 @@
+     while (numchildren >= limit) sig_pause();
+ 
+     sig_unblock(sig_child);
+-    t = socket_accept4(s,remoteip,&remoteport);
++    t = socket_accept6(s,remoteip,&remoteport,&netif);
+     sig_block(sig_child);
+ 
+     if (t == -1) continue;
+diff -uNr ucspi-tcp-0.88.orig/timeoutconn.h ucspi-tcp-0.88/timeoutconn.h
+--- ucspi-tcp-0.88.orig/timeoutconn.h	2000-03-18 16:18:42.000000000 +0100
++++ ucspi-tcp-0.88/timeoutconn.h	2009-03-19 12:43:14.906762234 +0100
+@@ -2,7 +2,9 @@
+ #define TIMEOUTCONN_H
+ 
+ #include "uint16.h"
++#include "uint32.h"
+ 
+ extern int timeoutconn(int,char *,uint16,unsigned int);
++extern int timeoutconn6(int,char *,uint16,unsigned int,uint32);
+ 
+ #endif
+diff -uNr ucspi-tcp-0.88.orig/timeoutconn6.c ucspi-tcp-0.88/timeoutconn6.c
+--- ucspi-tcp-0.88.orig/timeoutconn6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/timeoutconn6.c	2009-03-19 12:43:14.906762234 +0100
+@@ -0,0 +1,34 @@
++#include "ndelay.h"
++#include "socket.h"
++#include "iopause.h"
++#include "error.h"
++#include "timeoutconn.h"
++
++int timeoutconn6(int s,char ip[16],uint16 port,unsigned int timeout,uint32 netif)
++{
++  struct taia now;
++  struct taia deadline;
++  iopause_fd x;
++
++  if (socket_connect6(s,ip,port,netif) == -1) {
++    if ((errno != error_wouldblock) && (errno != error_inprogress)) return -1;
++    x.fd = s;
++    x.events = IOPAUSE_WRITE;
++    taia_now(&now);
++    taia_uint(&deadline,timeout);
++    taia_add(&deadline,&now,&deadline);
++    for (;;) {
++      taia_now(&now);
++      iopause(&x,1,&deadline,&now);
++      if (x.revents) break;
++      if (taia_less(&deadline,&now)) {
++	errno = error_timeout; /* note that connect attempt is continuing */
++	return -1;
++      }
++    }
++    if (!socket_connected(s)) return -1;
++  }
++
++  if (ndelay_off(s) == -1) return -1;
++  return 0;
++}
+diff -uNr ucspi-tcp-0.88.orig/tryip6.c ucspi-tcp-0.88/tryip6.c
+--- ucspi-tcp-0.88.orig/tryip6.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/tryip6.c	2009-03-19 12:43:14.906762234 +0100
+@@ -0,0 +1,8 @@
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++
++main() {
++  struct sockaddr_in6 sa;
++  sa.sin6_family = PF_INET6;
++}
+diff -uNr ucspi-tcp-0.88.orig/usr/local/man/man1/tcpclient.1 ucspi-tcp-0.88/usr/local/man/man1/tcpclient.1
+--- ucspi-tcp-0.88.orig/usr/local/man/man1/tcpclient.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/usr/local/man/man1/tcpclient.1	2009-03-19 12:43:14.906762234 +0100
+@@ -0,0 +1,173 @@
++.TH tcpclient 1
++.SH NAME
++tcpclient \- create an outgoing TCP connection
++.SH SYNOPSIS
++.B tcpclient
++[
++.B \-46hHrRdDqQv
++]
++[
++.B \-i\fIlocalip
++]
++[
++.B \-p\fIlocalport
++]
++[
++.B \-T\fItimeoutconn
++]
++[
++.B \-l\fIlocalname
++]
++[
++.B \-t\fItimeoutinfo
++]
++[
++.B \-I\fIinterface
++]
++.I host
++.I port
++.I program
++[
++.I arg ...
++]
++.SH DESCRIPTION
++.B tcpclient
++attempts to connect to a TCP server.
++If it is successful, it runs
++.I program
++with the given arguments,
++with descriptor 6 reading from the network
++and descriptor 7 writing to the network.
++
++The server's address is given by
++.I host
++and
++.IR port .
++.I host
++may be 0, referring to the local machine,
++or a dotted-decimal IP address,
++or a host name;
++if a host has several IP addresses,
++.B tcpclient
++tries each in turn.
++.I port
++may be a numeric port number
++or a port name.
++
++.B tcpclient
++sets up several environment variables,
++as described in
++.B tcp-environ(5).
++.SH OPTIONS
++.TP
++.B \-i\fIlocalip
++Use
++.I localip
++as the IP address for the local side of the connection;
++quit if
++.I localip
++is not available.
++.TP
++.B \-p\fIlocalport
++Use
++.I localport
++as the port number for the local side of the connection;
++quit if
++.I localport
++is not available.
++.TP
++.B \-I\fIinterface
++Use
++.I interface
++as the local network interface.  This is only defined for IPv6 sockets
++and needed if you use link-local IPv6 addresses.
++.TP
++.B \-T\fItimeoutconn
++Give up on the
++connection attempt
++after
++.I timeoutconn
++seconds. Default: 60.
++This timeout applies to each IP address tried.
++.TP
++.B \-d
++(Default.)
++Delay sending data for a fraction of a second whenever the
++remote host is responding slowly,
++to make better use of the network.
++.TP
++.B \-D
++Never delay sending data;
++enable TCP_NODELAY.
++This is appropriate for interactive connections.
++.TP
++.B \-q
++Quiet.
++Do not print any messages.
++.TP
++.B \-Q
++(Default.)
++Print error messages.
++.TP
++.B \-v
++Verbose.
++Print all available messages.
++.SH "DATA-GATHERING OPTIONS"
++.TP
++.B \-h
++(Default.)
++Look up the remote host name for
++.BR TCPREMOTEHOST .
++.TP
++.B \-H
++Do not look up the remote host name;
++unset
++.BR TCPREMOTEHOST .
++.TP
++.B \-l\fIlocalname
++Do not look up the local host name;
++use
++.I localname
++for
++.BR TCPLOCALHOST .
++.TP
++.B \-r
++(Default.)
++Attempt to obtain
++.B TCPREMOTEINFO
++from the remote host.
++.TP
++.B \-R
++Do not attempt to obtain
++.B TCPREMOTEINFO
++from the remote host.
++.TP
++.B \-t\fItimeoutinfo
++Give up on the 
++.B TCPREMOTEINFO
++connection attempt
++after
++.I timeoutinfo
++seconds. Default: 26.
++.TP
++.B \-4
++Fall back to IPv4 sockets.  This is necessary for terminally broken
++systems like OpenBSD which will not let IPv6 sockets connect to
++V4-mapped IPv6 addresses.  Please note that this also applies to DNS
++lookups, so you will have to use an DNS resolver with an IPv6 address to
++connect to IPv6 systems.  Use \fBDNSCACHEIP\fR to set the DNS resolver
++IP dynamically.
++.TP
++.B \-6
++Force IPv6 mode in UCSPI environment variables, even for
++IPv4 connections.  This will set \fB$PROTO\fR to \fBTCP6\fR and put
++IPv4-mapped IPv6 addresses in \fBTCPLOCALIP\fR and \fBTCPREMOTEIP\fR.
++.SH "SEE ALSO"
++date@(1),
++finger@(1),
++http@(1),
++mconnect(1),
++tcpcat(1),
++tcpserver(1),
++who@(1),
++tcp-environ(5)
+diff -uNr ucspi-tcp-0.88.orig/usr/local/man/man1/tcpserver.1 ucspi-tcp-0.88/usr/local/man/man1/tcpserver.1
+--- ucspi-tcp-0.88.orig/usr/local/man/man1/tcpserver.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/usr/local/man/man1/tcpserver.1	2009-03-19 12:43:14.906762234 +0100
+@@ -0,0 +1,266 @@
++.TH tcpserver 1
++.SH NAME
++tcpserver \- accept incoming TCP connections
++.SH SYNOPSIS
++.B tcpserver
++[
++.B \-146jpPhHrRoOdDqQv
++]
++[
++.B \-c\fIlimit
++]
++[
++.B \-x\fIrules.cdb
++]
++[
++.B \-B\fIbanner
++]
++[
++.B \-g\fIgid
++]
++[
++.B \-u\fIuid
++]
++[
++.B \-b\fIbacklog
++]
++[
++.B \-l\fIlocalname
++]
++[
++.B \-t\fItimeout
++]
++[
++.B \-I\fIinterface
++]
++.I host
++.I port
++.I program
++[
++.I arg ...
++]
++.SH DESCRIPTION
++.B tcpserver
++waits for connections from TCP clients.
++For each connection, it runs
++.I program
++with the given arguments,
++with descriptor 0 reading from the network
++and descriptor 1 writing to the network.
++
++The server's address is given by
++.I host
++and
++.IR port .
++.I host
++can be 0, allowing connections from any host;
++or a particular IP address,
++allowing connections only to that address;
++or a host name, allowing connections to the first IP address
++for that host.
++.I port
++may be a numeric port number
++or a port name.
++If
++.I port
++is 0,
++.B tcpserver
++will choose a free port.
++
++.B tcpserver
++sets up several environment variables,
++as described in
++.B tcp-environ(5).
++
++.B tcpserver
++exits when it receives SIGTERM.
++.SH "OPTIONS"
++.TP
++.B \-c\fIlimit
++Do not handle more than
++.I limit
++simultaneous connections.
++If there are
++.I limit
++simultaneous copies of
++.I program
++running, defer acceptance of a new connection
++until one copy finishes.
++.I limit
++must be a positive integer.
++Default: 40.
++.TP
++.B \-x\fIrules.cdb
++Follow the rules compiled into
++.I rules.cdb
++by
++.BR tcprules .
++These rules may specify setting environment variables
++or rejecting connections from bad sources.
++
++.B tcpserver
++does not read
++.I rules.cdb
++into memory;
++you can rerun
++.B tcprules
++to change
++.BR tcpserver 's
++behavior on the fly.
++.TP
++.B \-B\fIbanner
++Write
++.I banner
++to the network immediately after each connection is made.
++.B tcpserver
++writes
++.I banner
++before looking up
++.BR TCPREMOTEHOST ,
++before looking up
++.BR TCPREMOTEINFO ,
++and before checking
++.IR rules.cdb .
++
++This feature can be used to reduce latency in protocols
++where the client waits for a greeting from the server.
++.TP
++.B \-g\fIgid
++Switch group ID to
++.I gid
++after preparing to receive connections.
++.I gid
++must be a positive integer.
++.TP
++.B \-u\fIuid
++Switch user ID to 
++.I uid
++after preparing to receive connections.
++.I uid
++must be a positive integer.
++.TP
++.B \-1
++After preparing to receive connections,
++print the local port number to standard output.
++.TP
++.B \-4
++Fall back to IPv4 sockets.  This is necessary for terminally broken
++systems like OpenBSD which will not let IPv6 sockets connect to
++V4-mapped IPv6 addresses.  Please note that this also applies to DNS
++lookups, so you will have to use an DNS resolver with an IPv6 address to
++accept IPv6 connections.  Use \fBDNSCACHEIP\fR to set the DNS resolver
++IP dynamically.
++.TP
++.B \-6
++Force IPv6 mode in UCSPI environment variables, even for
++IPv4 connections.  This will set \fB$PROTO\fR to \fBTCP6\fR and put
++IPv4-mapped IPv6 addresses in \fBTCPLOCALIP\fR and \fBTCPREMOTEIP\fR.
++.TP
++.B \-I\fIinterface
++Bind to the network interface
++.I interface
++("eth0" on Linux, for example).  This is only defined and needed for
++IPv6 link-local addresses.
++.TP
++.B \-b\fIbacklog
++Allow up to
++.I backlog
++simultaneous SYN_RECEIVEDs.
++Default: 20.
++On some systems,
++.I backlog
++is silently limited to 5.
++See
++.BR listen (2)
++for more details.
++.TP
++.B \-o
++Leave IP options alone.
++If the client is sending packets along an IP source route,
++send packets back along the same route.
++.TP
++.B \-O
++(Default.)
++Kill IP options.
++A client can still use source routing to connect and to send data,
++but packets will be sent back along the default route.
++.TP
++.B \-d
++(Default.)
++Delay sending data for a fraction of a second whenever the
++remote host is responding slowly,
++to make better use of the network.
++.TP
++.B \-D
++Never delay sending data;
++enable TCP_NODELAY.
++This is appropriate for interactive connections.
++.TP
++.B \-q
++Quiet.
++Do not print any messages.
++.TP
++.B \-Q
++(Default.)
++Print error messages.
++.TP
++.B \-v
++Verbose.
++Print all available messages.
++.SH "DATA-GATHERING OPTIONS"
++.TP
++.B \-p
++Paranoid.
++After looking up the remote host name,
++look up the IP addresses for that name,
++and make sure one of them matches
++.BR TCPREMOTEIP .
++If none of them do,
++unset
++.BR TCPREMOTEHOST .
++.TP
++.B \-P
++(Default.)
++Not paranoid.
++.TP
++.B \-h
++(Default.)
++Look up the remote host name and set
++.BR TCPREMOTEHOST .
++.TP
++.B \-H
++Do not look up the remote host name.
++.TP
++.B \-l\fIlocalname
++Do not look up the local host name;
++use
++.I localname
++for
++.BR TCPLOCALHOST .
++.TP
++.B \-r
++(Default.)
++Attempt to obtain
++.B TCPREMOTEINFO
++from the remote host.
++.TP
++.B \-R
++Do not attempt to obtain
++.B TCPREMOTEINFO
++from the remote host.
++.TP
++.B \-t\fItimeout
++Give up on the 
++.B TCPREMOTEINFO
++connection attempt
++after
++.I timeout
++seconds. Default: 26.
++.SH "SEE ALSO"
++argv0(1),
++fixcr(1),
++recordio(1),
++tcpclient(1),
++tcprules(1),
++listen(2),
++tcp-environ(5)
+diff -uNr ucspi-tcp-0.88.orig/who@.1 ucspi-tcp-0.88/who@.1
+--- ucspi-tcp-0.88.orig/who@.1	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/who@.1	2009-03-19 12:43:14.906762234 +0100
+@@ -0,0 +1,32 @@
++.TH who@ 1
++.SH NAME
++who@ \- print list of active users on a host
++.SH SYNTAX
++.B who@
++[
++.I host
++]
++.SH DESCRIPTION
++.B who@
++connects to TCP port 11 (Systat) on
++.I host
++and prints any data it receives.
++It removes CR and converts unprintable characters to a visible format.
++
++If
++.I host
++is not supplied,
++.B who@
++connects to the local host.
++
++Some computers respond to port 11 with a list of active users.
++For example, they may be running
++
++.EX
++     tcpserver 0 11 who &
++.EE
++.SH "SEE ALSO"
++cat(1),
++delcr(1),
++tcpclient(1),
++tcpserver(1)
diff --git a/package/ucspi-tcp/ucspi-tcp-02-cross.patch b/package/ucspi-tcp/ucspi-tcp-02-cross.patch
new file mode 100644
index 0000000..f753243
--- /dev/null
+++ b/package/ucspi-tcp/ucspi-tcp-02-cross.patch
@@ -0,0 +1,196 @@
+diff -ruN ucspi-tcp-0.88.orig/auto_home.c ucspi-tcp-0.88/auto_home.c
+--- ucspi-tcp-0.88.orig/auto_home.c	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/auto_home.c	2011-01-08 16:12:18.000000000 +0100
+@@ -0,0 +1,3 @@
++const char auto_home[] = "\
++\057\165\163\162\
++";
+diff -ruN ucspi-tcp-0.88.orig/fork.h ucspi-tcp-0.88/fork.h
+--- ucspi-tcp-0.88.orig/fork.h	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/fork.h	2011-01-08 15:56:59.000000000 +0100
+@@ -0,0 +1,7 @@
++#ifndef FORK_H
++#define FORK_H
++
++/* sysdep: +vfork */
++#include <unistd.h>
++
++#endif
+diff -ruN ucspi-tcp-0.88.orig/hassgact.h ucspi-tcp-0.88/hassgact.h
+--- ucspi-tcp-0.88.orig/hassgact.h	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/hassgact.h	2011-01-08 15:57:35.000000000 +0100
+@@ -0,0 +1,2 @@
++/* sysdep: +sigaction */
++#define HASSIGACTION 1
+diff -ruN ucspi-tcp-0.88.orig/hassgprm.h ucspi-tcp-0.88/hassgprm.h
+--- ucspi-tcp-0.88.orig/hassgprm.h	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/hassgprm.h	2011-01-08 15:57:57.000000000 +0100
+@@ -0,0 +1,2 @@
++/* sysdep: +sigprocmask */
++#define HASSIGPROCMASK 1
+diff -ruN ucspi-tcp-0.88.orig/hasshsgr.h ucspi-tcp-0.88/hasshsgr.h
+--- ucspi-tcp-0.88.orig/hasshsgr.h	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/hasshsgr.h	2011-01-08 15:58:19.000000000 +0100
+@@ -0,0 +1 @@
++/* sysdep: -shortsetgroups */
+diff -ruN ucspi-tcp-0.88.orig/haswaitp.h ucspi-tcp-0.88/haswaitp.h
+--- ucspi-tcp-0.88.orig/haswaitp.h	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/haswaitp.h	2011-01-08 15:58:43.000000000 +0100
+@@ -0,0 +1,2 @@
++/* sysdep: +waitpid */
++#define HASWAITPID 1
+diff -ruN ucspi-tcp-0.88.orig/iopause.h ucspi-tcp-0.88/iopause.h
+--- ucspi-tcp-0.88.orig/iopause.h	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/iopause.h	2011-01-08 15:59:07.000000000 +0100
+@@ -0,0 +1,18 @@
++#ifndef IOPAUSE_H
++#define IOPAUSE_H
++
++/* sysdep: +poll */
++#define IOPAUSE_POLL
++
++#include <sys/types.h>
++#include <poll.h>
++
++typedef struct pollfd iopause_fd;
++#define IOPAUSE_READ POLLIN
++#define IOPAUSE_WRITE POLLOUT
++
++#include "taia.h"
++
++extern void iopause(iopause_fd *,unsigned int,struct taia *,struct taia *);
++
++#endif
+diff -ruN ucspi-tcp-0.88.orig/Makefile ucspi-tcp-0.88/Makefile
+--- ucspi-tcp-0.88.orig/Makefile	2011-01-08 15:55:48.000000000 +0100
++++ ucspi-tcp-0.88/Makefile	2011-01-08 16:14:48.000000000 +0100
+@@ -36,10 +36,6 @@
+ compile auto-str.c buffer.h readwrite.h exit.h
+ 	./compile auto-str.c
+ 
+-auto_home.c: \
+-auto-str conf-home
+-	./auto-str auto_home `head -1 conf-home` > auto_home.c
+-
+ auto_home.o: \
+ compile auto_home.c
+ 	./compile auto_home.c
+@@ -309,10 +305,6 @@
+ compile fmt_ulong.c fmt.h
+ 	./compile fmt_ulong.c
+ 
+-fork.h: \
+-choose compile load tryvfork.c fork.h1 fork.h2
+-	./choose cl tryvfork fork.h1 fork.h2 > fork.h
+-
+ getln.o: \
+ compile getln.c byte.h getln.h buffer.h stralloc.h gen_alloc.h
+ 	./compile getln.c
+@@ -321,24 +313,6 @@
+ compile getln2.c byte.h getln.h buffer.h stralloc.h gen_alloc.h
+ 	./compile getln2.c
+ 
+-hassgact.h: \
+-choose compile load trysgact.c hassgact.h1 hassgact.h2
+-	./choose cl trysgact hassgact.h1 hassgact.h2 > hassgact.h
+-
+-hassgprm.h: \
+-choose compile load trysgprm.c hassgprm.h1 hassgprm.h2
+-	./choose cl trysgprm hassgprm.h1 hassgprm.h2 > hassgprm.h
+-
+-hasshsgr.h: \
+-choose compile load tryshsgr.c hasshsgr.h1 hasshsgr.h2 chkshsgr \
+-warn-shsgr
+-	./chkshsgr || ( cat warn-shsgr; exit 1 )
+-	./choose clr tryshsgr hasshsgr.h1 hasshsgr.h2 > hasshsgr.h
+-
+-haswaitp.h: \
+-choose compile load trywaitp.c haswaitp.h1 haswaitp.h2
+-	./choose cl trywaitp haswaitp.h1 haswaitp.h2 > haswaitp.h
+-
+ hier.o: \
+ compile hier.c auto_home.h
+ 	./compile hier.c
+@@ -366,10 +340,6 @@
+ compile instcheck.c strerr.h error.h readwrite.h exit.h
+ 	./compile instcheck.c
+ 
+-iopause.h: \
+-choose compile trypoll.c iopause.h1 iopause.h2
+-	./choose clr trypoll iopause.h1 iopause.h2 > iopause.h
+-
+ iopause.o: \
+ compile iopause.c taia.h tai.h uint64.h select.h iopause.h taia.h
+ 	./compile iopause.c
+@@ -399,7 +369,7 @@
+ 	( cat warn-auto.sh; \
+ 	echo 'main="$$1"; shift'; \
+ 	echo 'rm -f "$$main"'; \
+-	echo 'ar cr "$$main" $${1+"$$@"}'; \
++	echo '$(AR) cr "$$main" $${1+"$$@"}'; \
+ 	case "`cat systype`" in \
+ 	sunos-5.*) ;; \
+ 	unix_sv*) ;; \
+@@ -408,7 +378,7 @@
+ 	dgux-*) ;; \
+ 	hp-ux-*) ;; \
+ 	sco*) ;; \
+-	*) echo 'ranlib "$$main"' ;; \
++	*) echo '$(RANLIB) "$$main"' ;; \
+ 	esac \
+ 	) > makelib
+ 	chmod 755 makelib
+@@ -791,13 +761,6 @@
+ compile uint16_unpack.c uint16.h
+ 	./compile uint16_unpack.c
+ 
+-uint32.h: \
+-tryulong32.c compile load uint32.h1 uint32.h2
+-	( ( ./compile tryulong32.c && ./load tryulong32 && \
+-	./tryulong32 ) >/dev/null 2>&1 \
+-	&& cat uint32.h2 || cat uint32.h1 ) > uint32.h
+-	rm -f tryulong32.o tryulong32
+-
+ uint32_pack.o: \
+ compile uint32_pack.c uint32.h
+ 	./compile uint32_pack.c
+@@ -806,10 +769,6 @@
+ compile uint32_unpack.c uint32.h
+ 	./compile uint32_unpack.c
+ 
+-uint64.h: \
+-choose compile load tryulong64.c uint64.h1 uint64.h2
+-	./choose clr tryulong64 uint64.h1 uint64.h2 > uint64.h
+-
+ unix.a: \
+ makelib alloc.o alloc_re.o buffer.o buffer_0.o buffer_1.o buffer_2.o \
+ buffer_copy.o buffer_get.o buffer_put.o env.o error.o error_str.o \
+diff -ruN ucspi-tcp-0.88.orig/uint32.h ucspi-tcp-0.88/uint32.h
+--- ucspi-tcp-0.88.orig/uint32.h	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/uint32.h	2011-01-08 16:01:41.000000000 +0100
+@@ -0,0 +1,12 @@
++#ifndef UINT32_H
++#define UINT32_H
++
++#include <stdint.h>
++typedef uint32_t uint32;
++
++extern void uint32_pack(char *,uint32);
++extern void uint32_pack_big(char *,uint32);
++extern void uint32_unpack(char *,uint32 *);
++extern void uint32_unpack_big(char *,uint32 *);
++
++#endif
+diff -ruN ucspi-tcp-0.88.orig/uint64.h ucspi-tcp-0.88/uint64.h
+--- ucspi-tcp-0.88.orig/uint64.h	1970-01-01 01:00:00.000000000 +0100
++++ ucspi-tcp-0.88/uint64.h	2011-01-08 16:01:12.000000000 +0100
+@@ -0,0 +1,9 @@
++#ifndef UINT64_H
++#define UINT64_H
++
++/* sysdep: +ulong64 */
++#include <stdint.h>
++
++typedef uint64_t uint64;
++
++#endif
diff --git a/package/ucspi-tcp/ucspi-tcp.mk b/package/ucspi-tcp/ucspi-tcp.mk
new file mode 100644
index 0000000..1734b45
--- /dev/null
+++ b/package/ucspi-tcp/ucspi-tcp.mk
@@ -0,0 +1,33 @@
+#############################################################
+#
+# ucspi-tcp
+#
+#############################################################
+
+UCSPI_TCP_VERSION = 0.88
+UCSPI_TCP_SOURCE = ucspi-tcp-$(UCSPI_TCP_VERSION).tar.gz
+UCSPI_TCP_SITE = http://cr.yp.to/ucspi-tcp
+
+UCSPI_TCP_TARGET_BINS= tcpserver tcprules tcprulescheck argv0 \
+   recordio tcpclient who@ date@ finger@ http@ tcpcat mconnect \
+   mconnect-io addcr delcr fixcrio rblsmtpd
+
+define UCSPI_TCP_BUILD_CMDS
+	echo '$(TARGET_CC) $(TARGET_CFLAGS)' > $(@D)/conf-cc
+	echo '$(TARGET_CC) -s $(TARGET_LDFLAGS)' > $(@D)/conf-ld
+	echo /usr > $(@D)/conf-home
+	AR='$(TARGET_AR)' \
+	   RANLIB='$(TARGET_RANLIB)' \
+	   $(MAKE) -C $(@D)
+endef
+
+define UCSPI_TCP_INSTALL_TARGET_CMDS
+	$(INSTALL) -D -m 0755 $(addprefix $(@D)/, $(UCSPI_TCP_TARGET_BINS)) \
+		$(TARGET_DIR)/usr/bin
+endef
+
+define UCSPI_TCP_UNINSTALL_TARGET_CMDS
+	rm -f $(addprefix $(TARGET_DIR)/usr/bin/, $(UCSPI_TCP_TARGET_BINS))
+endef
+
+$(eval $(call GENTARGETS,package,ucspi-tcp))
