--- /dev/null
+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;
+@@ -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;
+@@ -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,8 +1042,9 @@
+ 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/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;
++}