Imported Debian patch 1:1.05-8 debian/1%1.05-8
authorGerrit Pape <pape@smarden.org>
Mon, 29 Mar 2010 23:53:46 +0000 (23:53 +0000)
committerClinton Ebadi <clinton@unknownlamer.org>
Wed, 30 Apr 2014 01:05:09 +0000 (21:05 -0400)
61 files changed:
dbndns/diff/0001-hier.c-don-t-install-etc-dnsroots.global.diff [new file with mode: 0644]
dbndns/diff/0002-Apply-fefe-s-djbdns-1.05-test23-ipv6-patch.diff [new file with mode: 0644]
dbndns/diff/0003-djbdns-misformats-some-long-response-packets-patch-a.diff [new file with mode: 0644]
dbndns/diff/0004-dnscache.c-allow-a-maximum-of-20-concurrent-outgoing.diff [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/dbndns.README.Debian [new file with mode: 0644]
debian/dbndns.conffiles [new file with mode: 0644]
debian/diff/0001-hier.c-don-t-install-etc-dnsroots.global.diff [new file with mode: 0644]
debian/diff/0002-djbdns-misformats-some-long-response-packets-patch-a.diff [new file with mode: 0644]
debian/diff/0003-dnstracesort.sh-don-t-use-deprecated-number-sort.diff [new file with mode: 0644]
debian/djbdns-man/README [new file with mode: 0644]
debian/djbdns-man/axfr-get.8 [new file with mode: 0644]
debian/djbdns-man/axfrdns-conf.8 [new file with mode: 0644]
debian/djbdns-man/axfrdns.8 [new file with mode: 0644]
debian/djbdns-man/dnscache-conf.8 [new file with mode: 0644]
debian/djbdns-man/dnscache.8 [new file with mode: 0644]
debian/djbdns-man/dnsfilter.1 [new file with mode: 0644]
debian/djbdns-man/dnsip.1 [new file with mode: 0644]
debian/djbdns-man/dnsipq.1 [new file with mode: 0644]
debian/djbdns-man/dnsmx.1 [new file with mode: 0644]
debian/djbdns-man/dnsname.1 [new file with mode: 0644]
debian/djbdns-man/dnsq.1 [new file with mode: 0644]
debian/djbdns-man/dnsqr.1 [new file with mode: 0644]
debian/djbdns-man/dnstrace.1 [new file with mode: 0644]
debian/djbdns-man/dnstracesort.1 [new file with mode: 0644]
debian/djbdns-man/dnstxt.1 [new file with mode: 0644]
debian/djbdns-man/qualification.5 [new file with mode: 0644]
debian/djbdns-man/rbldns-conf.8 [new file with mode: 0644]
debian/djbdns-man/rbldns-data.8 [new file with mode: 0644]
debian/djbdns-man/rbldns.8 [new file with mode: 0644]
debian/djbdns-man/tinydns-conf.8 [new file with mode: 0644]
debian/djbdns-man/tinydns-data.8 [new file with mode: 0644]
debian/djbdns-man/tinydns-edit.8 [new file with mode: 0644]
debian/djbdns-man/tinydns-get.1 [new file with mode: 0644]
debian/djbdns-man/tinydns.8 [new file with mode: 0644]
debian/djbdns-man/walldns-conf.8 [new file with mode: 0644]
debian/djbdns-man/walldns.8 [new file with mode: 0644]
debian/djbdns.NEWS.Debian [new file with mode: 0644]
debian/djbdns.README.Debian [new file with mode: 0644]
debian/djbdns.conffiles [new file with mode: 0644]
debian/djbdns.docs [new file with mode: 0644]
debian/dnscache-run.README.Debian [new file with mode: 0644]
debian/dnscache-run.conffiles [new file with mode: 0644]
debian/dnscache-run.postinst [new file with mode: 0644]
debian/dnscache-run.postrm [new file with mode: 0644]
debian/dnscache-run.preinst [new file with mode: 0644]
debian/dnscache-run.prerm [new file with mode: 0644]
debian/dnsroots.global [new file with mode: 0644]
debian/implicit [new file with mode: 0644]
debian/rules [new file with mode: 0755]
dnscache-run/Makefile [new file with mode: 0644]
dnscache-run/env/CACHESIZE [new file with mode: 0644]
dnscache-run/env/DATALIMIT [new file with mode: 0644]
dnscache-run/env/IP [new file with mode: 0644]
dnscache-run/env/IPSEND [new file with mode: 0644]
dnscache-run/env/ROOT [new file with mode: 0644]
dnscache-run/log/run [new file with mode: 0644]
dnscache-run/root/servers/@ [new file with mode: 0644]
dnscache-run/run [new file with mode: 0644]

diff --git a/dbndns/diff/0001-hier.c-don-t-install-etc-dnsroots.global.diff b/dbndns/diff/0001-hier.c-don-t-install-etc-dnsroots.global.diff
new file mode 100644 (file)
index 0000000..71bf6a5
--- /dev/null
@@ -0,0 +1,30 @@
+From 77266cf2ef7d27559339a25c8bf21de4daf7e15b Mon Sep 17 00:00:00 2001
+From: Gerrit Pape <pape@smarden.org>
+Date: Mon, 12 Feb 2001 14:02:49 +0000
+Subject: [PATCH] hier.c: don't install /etc/dnsroots.global
+
+dnsroots.global is installed by debian/rules into debian/djbdns/etc/
+instead while building the Debian package.
+(cherry picked from commit e036abc40f9aefc13f06d944f0ec4b2230e9c28c)
+---
+ hier.c |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/hier.c b/hier.c
+index 4aef75b..b57dba0 100644
+--- a/hier.c
++++ b/hier.c
+@@ -2,7 +2,10 @@
+ void hier()
+ {
++/*
++  This file is installed by debian/rules in debian/tmp/etc
+   c("/","etc","dnsroots.global",-1,-1,0644);
++*/
+   h(auto_home,-1,-1,02755);
+   d(auto_home,"bin",-1,-1,02755);
+-- 
+1.6.2
+
diff --git a/dbndns/diff/0002-Apply-fefe-s-djbdns-1.05-test23-ipv6-patch.diff b/dbndns/diff/0002-Apply-fefe-s-djbdns-1.05-test23-ipv6-patch.diff
new file mode 100644 (file)
index 0000000..e78c904
--- /dev/null
@@ -0,0 +1,3737 @@
+From 816e84a7c1357b9a60cc2102f4641735cae3a34b Mon Sep 17 00:00:00 2001
+From: Gerrit Pape <pape@smarden.org>
+Date: Mon, 12 May 2008 16:51:21 +0000
+Subject: [PATCH] Apply fefe's djbdns-1.05-test23 ipv6 patch.
+
+What is djbdns and why does it need IPv6?
+
+Most people agree that IPv6 will come sooner or later, but obviously you
+need a DNS infrastructure that supports IPv6.  djbdns is a full blown
+DNS server which outperforms BIND in nearly all respects.  However, it
+does not support IPv6 out of the box.
+
+Fortunately, Dan Bernstein (the author of djbdns) has defined a very
+clean API that made the conversion possible in a few days.
+
+What does your diff do?
+
+The current version adds support for AAAA records (those are the DNS
+records that store IPv6 numbers).  tinydns-conf will now create
+/etc/tinydns/add-host6 and /etc/tinydns/add-alias6, and data can now
+contain records of type "6" and "3".  Also, dnsq now understand AAAA
+records and a new program called "dnsip6" is the IPv6 equivalent of the
+old dnsip.  [new] Automatic internal lookup of some reserved IPv6
+addresses (like "::1").  There is also experimental IPv6 transport
+support.
+
+This diff also integrates an ipv6 port of Russ Nelson's anti-Verisign
+patch.  Boycott saboteurs!
+
+What does not work yet?
+
+tinydns-edit won't accept IPv6 addresses for NS or MX records yet.  I
+haven't even started to look at axfr, but it should just work if you use
+my IPv6 patches for ucspi-tcp.
+
+How do reverse lookups work?
+
+The reverse lookup for 2001:658:0:2:2e0:18ff:fe98:b03d looks like this:
+
+d.3.0.b.8.9.e.f.f.f.8.1.0.e.2.0.2.0.0.0.0.0.0.0.8.5.6.0.1.0.0.2.ip6.int
+
+My patch will put a record like this in your data.cdb, but you still
+need to get a delegation for your range.  For a /64, the delegation
+would mean leaving half the digits away, as in
+2.0.0.0.0.0.0.0.8.5.6.0.1.0.0.2.ip6.int.  Talk to your ISP about this!
+
+There also is a supposedly new and better scheme for doing DNS for IPv6,
+and it employs bit strings, DNAME and A6 records, which are really
+broken by design.  Dan has a good write-up about this issue.  Rumour has
+it that the IETF has seen the light and killed this mindblowingly bad
+proposal.  I have not implemented it and probably will not in the
+future.  It involves the domain ip6.arpa, in case you see that
+somewhere.  (News July 2002: The IEFT really has seen the light)
+---
+ FILES             |   11 +++
+ Makefile          |  160 +++++++++++++++++++++++++++++----
+ TARGETS           |   25 +++++
+ axfr-get.c        |    9 ++
+ dns.h             |   15 +++-
+ dns_ip6.c         |  103 +++++++++++++++++++++
+ dns_ipq6.c        |   72 +++++++++++++++
+ dns_name.c        |   22 +++++
+ dns_nd6.c         |   35 +++++++
+ dns_rcip.c        |   25 +++---
+ dns_resolve.c     |    5 +-
+ dns_sortip6.c     |   20 ++++
+ dns_transmit.c    |   25 +++---
+ dnscache.c        |   64 ++++++++++----
+ dnsfilter.c       |    5 +-
+ dnsip6.c          |   40 ++++++++
+ dnsip6q.c         |   43 +++++++++
+ dnsname.c         |   15 +++-
+ dnsq.c            |   13 ++--
+ dnstrace.c        |   50 +++++++----
+ error.h           |    2 +-
+ fmt_xlong.c       |   22 +++++
+ haveip6.h1        |    1 +
+ haveip6.h2        |    1 +
+ haven2i.h1        |    1 +
+ haven2i.h2        |    1 +
+ hier.c            |    2 +
+ ip6.h             |   28 ++++++
+ ip6_fmt.c         |   60 +++++++++++++
+ ip6_scan.c        |  115 ++++++++++++++++++++++++
+ log.c             |   39 ++++----
+ okclient.c        |   18 +++-
+ printrecord.c     |   10 ++
+ qlog.c            |   10 +-
+ query.c           |  256 ++++++++++++++++++++++++++++++++++++++++++++++++-----
+ query.h           |    7 +-
+ roots.c           |   17 ++--
+ scan_xlong.c      |   23 +++++
+ server.c          |  100 +++++++++++++++++----
+ sockaddr_in6.h1   |   21 +++++
+ sockaddr_in6.h2   |    4 +
+ socket.h          |   18 ++++-
+ socket_accept6.c  |   43 +++++++++
+ socket_bind.c     |    2 +-
+ socket_bind6.c    |   43 +++++++++
+ socket_connect6.c |   39 ++++++++
+ socket_getifidx.c |   13 +++
+ socket_noipv6.c   |    7 ++
+ socket_recv6.c    |   42 +++++++++
+ socket_send6.c    |   39 ++++++++
+ socket_tcp6.c     |   44 +++++++++
+ socket_udp6.c     |   43 +++++++++
+ tdlookup.c        |   54 ++++++++---
+ tinydns-conf.c    |   12 +++
+ tinydns-data.c    |   30 ++++++
+ tinydns-edit.c    |   35 +++++++-
+ tryip6.c          |    8 ++
+ tryn2i.c          |    8 ++
+ trysa6.c          |    8 ++
+ 59 files changed, 1786 insertions(+), 197 deletions(-)
+ create mode 100644 dns_ip6.c
+ create mode 100644 dns_ipq6.c
+ create mode 100644 dns_nd6.c
+ create mode 100644 dns_sortip6.c
+ create mode 100644 dnsip6.c
+ create mode 100644 dnsip6q.c
+ create mode 100644 fmt_xlong.c
+ create mode 100644 haveip6.h1
+ create mode 100644 haveip6.h2
+ create mode 100644 haven2i.h1
+ create mode 100644 haven2i.h2
+ create mode 100644 ip6.h
+ create mode 100644 ip6_fmt.c
+ create mode 100644 ip6_scan.c
+ create mode 100644 scan_xlong.c
+ create mode 100644 sockaddr_in6.h1
+ create mode 100644 sockaddr_in6.h2
+ create mode 100644 socket_accept6.c
+ create mode 100644 socket_bind6.c
+ create mode 100644 socket_connect6.c
+ create mode 100644 socket_getifidx.c
+ create mode 100644 socket_noipv6.c
+ create mode 100644 socket_recv6.c
+ create mode 100644 socket_send6.c
+ create mode 100644 socket_tcp6.c
+ create mode 100644 socket_udp6.c
+ create mode 100644 tryip6.c
+ create mode 100644 tryn2i.c
+ create mode 100644 trysa6.c
+
+diff --git a/FILES b/FILES
+index 7adf6d4..27a4e26 100644
+--- a/FILES
++++ b/FILES
+@@ -135,6 +135,7 @@ error_str.c
+ exit.h
+ fmt.h
+ fmt_ulong.c
++fmt_xlong.c
+ gen_alloc.h
+ gen_allocdefs.h
+ getln.c
+@@ -151,6 +152,9 @@ iopause.h2
+ 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 @@ prot.h
+ readclose.c
+ readclose.h
+ scan.h
++scan_0x.c
+ scan_ulong.c
+ seek.h
+ seek_set.c
+@@ -241,3 +246,9 @@ uint64.h2
+ warn-shsgr
+ buffer_read.c
+ buffer_write.c
++dns_nd6.c
++socket_udp6.c
++socket_getifidx.c
++tryn2i.c
++haven2i.h1
++haven2i.h2
+diff --git a/Makefile b/Makefile
+index 1429643..44bd989 100644
+--- a/Makefile
++++ b/Makefile
+@@ -120,12 +120,14 @@ makelib 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
++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 @@ choose compile trydrent.c direntry.h1 direntry.h2
+ 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 @@ compile dns_ip.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_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 @@ compile dns_nd.c byte.h fmt.h dns.h stralloc.h gen_alloc.h iopause.h \
+ 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 @@ compile dns_sortip.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \
+ 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 @@ compile dnsip.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 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 @@ compile dnsipq.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 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 @@ byte.a socket.lib
+ 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 @@ fmt_ulong.o: \
+ 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 @@ ip4_fmt.o: \
+ 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 @@ iopause.h taia.h tai.h uint64.h taia.h uint16.h parsetype.h
+       ./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 @@ dnscache-conf dnscache walldns-conf walldns rbldns-conf rbldns \
+ 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 @@ gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h
+       ./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 @@ scan_ulong.o: \
+ 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 @@ server.o: \
+ 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 @@ socket_accept.o: \
+ 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 @@ socket_recv.o: \
+ 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 @@ compile taia_uint.c taia.h tai.h uint64.h
+ 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 @@ timeoutwrite.h
+       ./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 @@ tinydns-data.o: \
+ 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 @@ unix.a: \
+ makelib buffer_read.o buffer_write.o error.o error_str.o ndelay_off.o \
+ ndelay_on.o open_read.o open_trunc.o openreadclose.o readclose.o \
+ 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 scan.h exit.h
+       ./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 @@ walldns.o: \
+ 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 --git a/TARGETS b/TARGETS
+index 2490b1a..afc4c49 100644
+--- a/TARGETS
++++ b/TARGETS
+@@ -102,6 +102,7 @@ dns_domain.o
+ 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.o
+ dnsip
+ dnsipq.o
+ dnsipq
++dnsip6q.o
++dnsip6q
+ dnsname.o
+ dnsname
+ dnstxt.o
+@@ -214,3 +217,25 @@ instcheck
+ 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 --git a/axfr-get.c b/axfr-get.c
+index 75db627..f6bf5bd 100644
+--- a/axfr-get.c
++++ b/axfr-get.c
+@@ -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 @@ unsigned int doit(char *buf,unsigned int len,unsigned int pos)
+     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 --git a/dns.h b/dns.h
+index 2f899ef..5398e2b 100644
+--- a/dns.h
++++ b/dns.h
+@@ -35,7 +35,8 @@ struct dns_transmit {
+   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 void dns_random_init(const char *);
+ extern unsigned int dns_random(unsigned int);
+ extern void dns_sortip(char *,unsigned int);
++extern void dns_sortip6(char *,unsigned int);
+ extern void dns_domain_free(char **);
+ extern int dns_domain_copy(char **,const char *);
+@@ -68,10 +70,13 @@ extern struct dns_transmit dns_resolve_tx;
+ 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_mx(stralloc *,const stralloc *);
+ 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 --git a/dns_ip6.c b/dns_ip6.c
+new file mode 100644
+index 0000000..30ce699
+--- /dev/null
++++ b/dns_ip6.c
+@@ -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 --git a/dns_ipq6.c b/dns_ipq6.c
+new file mode 100644
+index 0000000..d5cea12
+--- /dev/null
++++ b/dns_ipq6.c
+@@ -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 --git a/dns_name.c b/dns_name.c
+index 6f7cdc3..518a0c0 100644
+--- a/dns_name.c
++++ b/dns_name.c
+@@ -2,6 +2,7 @@
+ #include "uint16.h"
+ #include "byte.h"
+ #include "dns.h"
++#include "ip6.h"
+ static char *q = 0;
+@@ -46,3 +47,24 @@ int dns_name4(stralloc *out,const char ip[4])
+   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 --git a/dns_nd6.c b/dns_nd6.c
+new file mode 100644
+index 0000000..6dbeb89
+--- /dev/null
++++ b/dns_nd6.c
+@@ -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 --git a/dns_rcip.c b/dns_rcip.c
+index 97bd8f5..efd1b21 100644
+--- a/dns_rcip.c
++++ b/dns_rcip.c
+@@ -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 @@ static int init(char ip[64])
+       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 @@ static int init(char ip[64])
+             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 @@ static int init(char ip[64])
+   }
+   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 @@ int dns_resolvconfip(char s[64])
+   }
+   --uses;
+-  byte_copy(s,64,ip);
++  byte_copy(s,256,ip);
+   return 0;
+ }
+diff --git a/dns_resolve.c b/dns_resolve.c
+index 8bdea0d..82b5bbb 100644
+--- a/dns_resolve.c
++++ b/dns_resolve.c
+@@ -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 @@ int dns_resolve(const char *q,const char qtype[2])
+ {
+   struct taia stamp;
+   struct taia deadline;
+-  char servers[64];
++  char servers[256];
+   iopause_fd x[1];
+   int r;
+   if (dns_resolvconfip(servers) == -1) return -1;
+-  if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,"\0\0\0\0") == -1) return -1;
++  if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,V6any) == -1) return -1;
+   for (;;) {
+     taia_now(&stamp);
+diff --git a/dns_sortip6.c b/dns_sortip6.c
+new file mode 100644
+index 0000000..7e752e9
+--- /dev/null
++++ b/dns_sortip6.c
+@@ -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 --git a/dns_transmit.c b/dns_transmit.c
+index 4d6e39f..cba1fd2 100644
+--- a/dns_transmit.c
++++ b/dns_transmit.c
+@@ -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 @@ static int randombind(struct dns_transmit *d)
+   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 @@ static int thisudp(struct dns_transmit *d)
+   while (d->udploop < 4) {
+     for (;d->curserver < 16;++d->curserver) {
+-      ip = d->servers + 4 * d->curserver;
+-      if (byte_diff(ip,4,"\0\0\0\0")) {
++      ip = d->servers + 16 * d->curserver;
++      if (byte_diff(ip,16,V6any)) {
+       d->query[2] = dns_random(256);
+       d->query[3] = dns_random(256);
+   
+-        d->s1 = 1 + socket_udp();
++        d->s1 = 1 + socket_udp6();
+         if (!d->s1) { dns_transmit_free(d); return -1; }
+       if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
+-        if (socket_connect4(d->s1 - 1,ip,53) == 0)
++        if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0)
+           if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) {
+             struct taia now;
+             taia_now(&now);
+@@ -153,19 +154,19 @@ static int thistcp(struct dns_transmit *d)
+   packetfree(d);
+   for (;d->curserver < 16;++d->curserver) {
+-    ip = d->servers + 4 * d->curserver;
+-    if (byte_diff(ip,4,"\0\0\0\0")) {
++    ip = d->servers + 16 * d->curserver;
++    if (byte_diff(ip,16,V6any)) {
+       d->query[2] = dns_random(256);
+       d->query[3] = dns_random(256);
+-      d->s1 = 1 + socket_tcp();
++      d->s1 = 1 + socket_tcp6();
+       if (!d->s1) { dns_transmit_free(d); return -1; }
+       if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
+   
+       taia_now(&now);
+       taia_uint(&d->deadline,10);
+       taia_add(&d->deadline,&d->deadline,&now);
+-      if (socket_connect4(d->s1 - 1,ip,53) == 0) {
++      if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0) {
+         d->tcpstate = 2;
+         return 0;
+       }
+@@ -193,7 +194,7 @@ static int nexttcp(struct dns_transmit *d)
+   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 @@ int dns_transmit_start(struct dns_transmit *d,const char servers[64],int flagrec
+   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 --git a/dnscache.c b/dnscache.c
+index 8c899a3..abcba69 100644
+--- a/dnscache.c
++++ b/dnscache.c
+@@ -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 int packetquery(char *buf,unsigned int len,char **q,char qtype[2],char qc
+ }
+-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 @@ static struct udpclient {
+   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 @@ void u_respond(int j)
+   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 @@ void u_new(void)
+   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 @@ void u_new(void)
+   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 @@ void u_new(void)
+   }
+ }
+-
+ static int tcp53;
+ #define MAXTCP 20
+@@ -138,7 +143,7 @@ struct tcpclient {
+   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 @@ struct tcpclient {
+   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 @@ void t_rw(int j)
+   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 @@ void t_new(void)
+   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 @@ char seed[128];
+ 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 @@ int main()
+   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 @@ int main()
+   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 --git a/dnsfilter.c b/dnsfilter.c
+index 9e6863a..822ff1e 100644
+--- a/dnsfilter.c
++++ b/dnsfilter.c
+@@ -12,6 +12,7 @@
+ #include "iopause.h"
+ #include "error.h"
+ #include "exit.h"
++#include "ip6.h"
+ #define FATAL "dnsfilter: fatal: "
+@@ -44,7 +45,7 @@ int flag0 = 1;
+ iopause_fd *io;
+ int iolen;
+-char servers[64];
++char servers[256];
+ char ip[4];
+ char name[DNS_NAME4_DOMAIN];
+@@ -191,7 +192,7 @@ int main(int argc,char **argv)
+             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 --git a/dnsip6.c b/dnsip6.c
+new file mode 100644
+index 0000000..5b65823
+--- /dev/null
++++ b/dnsip6.c
+@@ -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 --git a/dnsip6q.c b/dnsip6q.c
+new file mode 100644
+index 0000000..82ab04e
+--- /dev/null
++++ b/dnsip6q.c
+@@ -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 --git a/dnsname.c b/dnsname.c
+index 0e5eb26..ff9166d 100644
+--- a/dnsname.c
++++ b/dnsname.c
+@@ -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 @@ int main(int argc,char **argv)
+   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 --git a/dnsq.c b/dnsq.c
+index 533e6af..9e89efe 100644
+--- a/dnsq.c
++++ b/dnsq.c
+@@ -10,6 +10,7 @@
+ #include "printpacket.h"
+ #include "parsetype.h"
+ #include "dns.h"
++#include "ip6.h"
+ #define FATAL "dnsq: fatal: "
+@@ -24,14 +25,14 @@ void oops(void)
+ 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 @@ int resolve(char *q,char qtype[2],char servers[64])
+   return 0;
+ }
+-char servers[64];
++char servers[256];
+ static stralloc ip;
+ static stralloc fqdn;
+@@ -73,9 +74,9 @@ int main(int argc,char **argv)
+   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 --git a/dnstrace.c b/dnstrace.c
+index 3f2159b..1d331bd 100644
+--- a/dnstrace.c
++++ b/dnstrace.c
+@@ -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 @@ void usage(void)
+ }
+ static stralloc querystr;
+-char ipstr[IP4_FMT];
++char ipstr[IP6_FMT];
+ static stralloc tmp;
+ void printdomain(const char *d)
+@@ -42,19 +43,19 @@ void printdomain(const char *d)
+ 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 @@ int resolve(char *q,char qtype[2],char ip[4])
+ struct address {
+   char *owner;
+-  char ip[4];
++  char ip[16];
+ } ;
+ GEN_ALLOC_typedef(address_alloc,struct address,s,len,a)
+@@ -117,7 +118,7 @@ struct qt {
+   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 @@ GEN_ALLOC_append(qt_alloc,struct qt,s,len,a,i,n,x,30,qt_alloc_readyplus,qt_alloc
+ 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 @@ void qt_add(const char *q,const char type[2],const char *control,const char ip[4
+     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 @@ void ns_add(const char *owner,const char *server)
+         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 @@ void address_add(const char *owner,const char ip[4])
+   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 @@ void parsepacket(const char *buf,unsigned int len,const char *d,const char dtype
+         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 @@ int main(int argc,char **argv)
+   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 @@ int main(int argc,char **argv)
+     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 @@ int main(int argc,char **argv)
+     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 --git a/error.h b/error.h
+index 35c976e..9cdd527 100644
+--- a/error.h
++++ b/error.h
+@@ -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 --git a/fmt_xlong.c b/fmt_xlong.c
+new file mode 100644
+index 0000000..332fc9a
+--- /dev/null
++++ b/fmt_xlong.c
+@@ -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 --git a/haveip6.h1 b/haveip6.h1
+new file mode 100644
+index 0000000..8b13789
+--- /dev/null
++++ b/haveip6.h1
+@@ -0,0 +1 @@
++
+diff --git a/haveip6.h2 b/haveip6.h2
+new file mode 100644
+index 0000000..5564de9
+--- /dev/null
++++ b/haveip6.h2
+@@ -0,0 +1 @@
++#define LIBC_HAS_IP6 1
+diff --git a/haven2i.h1 b/haven2i.h1
+new file mode 100644
+index 0000000..732c485
+--- /dev/null
++++ b/haven2i.h1
+@@ -0,0 +1 @@
++#undef HAVE_N2I
+diff --git a/haven2i.h2 b/haven2i.h2
+new file mode 100644
+index 0000000..fd50644
+--- /dev/null
++++ b/haven2i.h2
+@@ -0,0 +1 @@
++#define HAVE_N2I
+diff --git a/hier.c b/hier.c
+index b57dba0..e4b1a7f 100644
+--- a/hier.c
++++ b/hier.c
+@@ -32,7 +32,9 @@ void hier()
+   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 --git a/ip6.h b/ip6.h
+new file mode 100644
+index 0000000..c1135e9
+--- /dev/null
++++ b/ip6.h
+@@ -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 --git a/ip6_fmt.c b/ip6_fmt.c
+new file mode 100644
+index 0000000..b2444bb
+--- /dev/null
++++ b/ip6_fmt.c
+@@ -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 --git a/ip6_scan.c b/ip6_scan.c
+new file mode 100644
+index 0000000..f355d46
+--- /dev/null
++++ b/ip6_scan.c
+@@ -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 --git a/log.c b/log.c
+index c43e8b0..df465e2 100644
+--- a/log.c
++++ b/log.c
+@@ -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 @@ static void space(void)
+   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 @@ void log_startup(void)
+   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 @@ void log_querydrop(uint64 *qnum)
+   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 @@ void log_tcpclose(const char client[4],unsigned int port)
+   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 @@ void log_cachednxdomain(const char *dn)
+   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 @@ void log_servfail(const char *dn)
+   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 @@ void log_rr(const char server[4],const char *q,const char type[2],const char *bu
+   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 @@ void log_rrns(const char server[4],const char *q,const char *data,unsigned int t
+   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 @@ void log_rrcname(const char server[4],const char *q,const char *data,unsigned in
+   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 @@ void log_rrptr(const char server[4],const char *q,const char *data,unsigned int
+   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 @@ void log_rrmx(const char server[4],const char *q,const char *mx,const char pref[
+   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 --git a/okclient.c b/okclient.c
+index a648c02..9a0d3c6 100644
+--- a/okclient.c
++++ b/okclient.c
+@@ -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 --git a/printrecord.c b/printrecord.c
+index ed0b42d..4bc7c3e 100644
+--- a/printrecord.c
++++ b/printrecord.c
+@@ -4,6 +4,7 @@
+ #include "byte.h"
+ #include "dns.h"
+ #include "printrecord.h"
++#include "ip6.h"
+ static char *d;
+@@ -82,6 +83,15 @@ unsigned int printrecord_cat(stralloc *out,const char *buf,unsigned int len,unsi
+       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 --git a/qlog.c b/qlog.c
+index 5c5c7ba..60816df 100644
+--- a/qlog.c
++++ b/qlog.c
+@@ -20,15 +20,15 @@ static void octal(unsigned char c)
+   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 --git a/query.c b/query.c
+index 46cdc00..e0f48b3 100644
+--- a/query.c
++++ b/query.c
+@@ -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 @@ static int rqa(struct query *z)
+   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 @@ static int doit(struct query *z,int state)
+   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 @@ static int doit(struct query *z,int state)
+   int k;
+   int p;
+   int q;
++  unsigned int ii;
+   errno = error_io;
+   if (state == 1) goto HAVEPACKET;
+@@ -210,9 +214,10 @@ static int doit(struct query *z,int state)
+   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 @@ static int doit(struct query *z,int state)
+     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 @@ static int doit(struct query *z,int state)
+       if (z->level) {
+         log_cachedanswer(d,DNS_T_A);
+         while (cachedlen >= 4) {
+-          for (k = 0;k < 64;k += 4)
+-            if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) {
+-              byte_copy(z->servers[z->level - 1] + k,4,cached);
++          for (k = 0;k < 256;k += 16)
++            if (byte_equal(z->servers[z->level - 1] + k,16,V6any)) {
++              byte_copy(z->servers[z->level - 1] + k,12,V4mappedprefix);
++              byte_copy(z->servers[z->level - 1] + k + 12,4,cached);
+               break;
+             }
+           cached += 4;
+@@ -351,7 +509,39 @@ static int doit(struct query *z,int state)
+       }
+     }
+-    if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_CNAME,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype)) {
++    if (typematch(DNS_T_AAAA,dtype)) {
++      byte_copy(key,2,DNS_T_AAAA);
++      cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
++      if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
++      if (z->level) {
++        log_cachedanswer(d,DNS_T_AAAA);
++        while (cachedlen >= 16) {
++          for (k = 0;k < 256;k += 16)
++            if (byte_equal(z->servers[z->level - 1] + k,16,V6any)) {
++              byte_copy(z->servers[z->level - 1] + k,16,cached);
++              break;
++            }
++          cached += 16;
++          cachedlen -= 16;
++        }
++        goto LOWERLEVEL;
++      }
++
++      log_cachedanswer(d,DNS_T_AAAA);
++      if (!rqa(z)) goto DIE;
++      while (cachedlen >= 16) {
++        if (!response_rstart(d,DNS_T_AAAA,ttl)) goto DIE;
++        if (!response_addbytes(cached,16)) goto DIE;
++        response_rfinish(RESPONSE_ANSWER);
++        cached += 16;
++        cachedlen -= 16;
++      }
++      cleanup(z);
++      return 1;
++      }
++    }
++
++    if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_CNAME,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype) && !typematch(DNS_T_AAAA,dtype)) {
+       byte_copy(key,2,dtype);
+       cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
+       if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
+@@ -390,7 +580,7 @@ static int doit(struct query *z,int state)
+         cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
+         if (cached && cachedlen) {
+         z->control[z->level] = d;
+-          byte_zero(z->servers[z->level],64);
++          byte_zero(z->servers[z->level],256);
+           for (j = 0;j < QUERY_MAXNS;++j)
+             dns_domain_free(&z->ns[z->level][j]);
+           pos = 0;
+@@ -423,12 +613,12 @@ static int doit(struct query *z,int state)
+       dns_domain_free(&z->ns[z->level][j]);
+     }
+-  for (j = 0;j < 64;j += 4)
+-    if (byte_diff(z->servers[z->level] + j,4,"\0\0\0\0"))
++  for (j = 0;j < 256;j += 16)
++    if (byte_diff(z->servers[z->level] + j,16,V6any))
+       break;
+-  if (j == 64) goto SERVFAIL;
++  if (j == 256) goto SERVFAIL;
+-  dns_sortip(z->servers[z->level],64);
++  dns_sortip6(z->servers[z->level],256);
+   if (z->level) {
+     log_tx(z->name[z->level],DNS_T_A,z->control[z->level],z->servers[z->level],z->level);
+     if (dns_transmit_start(&z->dt,z->servers[z->level],flagforwardonly,z->name[z->level],DNS_T_A,z->localip) == -1) goto DIE;
+@@ -453,7 +643,7 @@ static int doit(struct query *z,int state)
+   buf = z->dt.packet;
+   len = z->dt.packetlen;
+-  whichserver = z->dt.servers + 4 * z->dt.curserver;
++  whichserver = z->dt.servers + 16 * z->dt.curserver;
+   control = z->control[z->level];
+   d = z->name[z->level];
+   dtype = z->level ? DNS_T_A : z->type;
+@@ -519,7 +709,7 @@ static int doit(struct query *z,int state)
+   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 @@ static int doit(struct query *z,int state)
+         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 @@ static int doit(struct query *z,int state)
+       }
+       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 @@ static int doit(struct query *z,int state)
+           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 @@ static int doit(struct query *z,int state)
+   return -1;
+ }
+-int query_start(struct query *z,char *dn,char type[2],char class[2],char localip[4])
++int query_start(struct query *z,char *dn,char type[2],char class[2],char localip[16],unsigned int scope_id)
+ {
+   if (byte_equal(type,2,DNS_T_AXFR)) { errno = error_perm; return -1; }
+@@ -829,7 +1042,8 @@ int query_start(struct query *z,char *dn,char type[2],char class[2],char localip
+   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 --git a/query.h b/query.h
+index eff68b2..f179c22 100644
+--- a/query.h
++++ b/query.h
+@@ -14,16 +14,17 @@ struct query {
+   char *name[QUERY_MAXLEVEL];
+   char *control[QUERY_MAXLEVEL]; /* pointing inside name */
+   char *ns[QUERY_MAXLEVEL][QUERY_MAXNS];
+-  char servers[QUERY_MAXLEVEL][64];
++  char servers[QUERY_MAXLEVEL][256];
+   char *alias[QUERY_MAXALIAS];
+   uint32 aliasttl[QUERY_MAXALIAS];
+-  char localip[4];
++  char localip[16];
++  uint32 scope_id;
+   char type[2];
+   char class[2];
+   struct dns_transmit dt;
+ } ;
+-extern int query_start(struct query *,char *,char *,char *,char *);
++extern int query_start(struct query *,char *,char *,char *,char *,unsigned int);
+ extern void query_io(struct query *,iopause_fd *,struct taia *);
+ extern int query_get(struct query *,iopause_fd *,struct taia *);
+diff --git a/roots.c b/roots.c
+index 3cfe959..4162ec5 100644
+--- a/roots.c
++++ b/roots.c
+@@ -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 @@ static int roots_find(char *q)
+     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 @@ static int roots_search(char *q)
+   }
+ }
+-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 @@ static int init2(DIR *dir)
+   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 @@ static int init2(DIR *dir)
+       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 --git a/scan_xlong.c b/scan_xlong.c
+new file mode 100644
+index 0000000..1113433
+--- /dev/null
++++ b/scan_xlong.c
+@@ -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 --git a/server.c b/server.c
+index e486fe1..d52ce87 100644
+--- a/server.c
++++ b/server.c
+@@ -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 int len;
+ static char *q;
++void nomem()
++{
++  strerr_die2x(111,fatal,"out of memory");
++}
++
+ static int doit(void)
+ {
+   unsigned int pos;
+@@ -82,35 +91,86 @@ static int doit(void)
+ 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 --git a/sockaddr_in6.h1 b/sockaddr_in6.h1
+new file mode 100644
+index 0000000..b1f8f5e
+--- /dev/null
++++ b/sockaddr_in6.h1
+@@ -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 --git a/sockaddr_in6.h2 b/sockaddr_in6.h2
+new file mode 100644
+index 0000000..d484041
+--- /dev/null
++++ b/sockaddr_in6.h2
+@@ -0,0 +1,4 @@
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <netinet/in.h>
++
+diff --git a/socket.h b/socket.h
+index 95e2a7c..bbb0f82 100644
+--- a/socket.h
++++ b/socket.h
+@@ -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 --git a/socket_accept6.c b/socket_accept6.c
+new file mode 100644
+index 0000000..48a0b6d
+--- /dev/null
++++ b/socket_accept6.c
+@@ -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 --git a/socket_bind.c b/socket_bind.c
+index 20830a4..a33efca 100644
+--- a/socket_bind.c
++++ b/socket_bind.c
+@@ -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 --git a/socket_bind6.c b/socket_bind6.c
+new file mode 100644
+index 0000000..20b22b8
+--- /dev/null
++++ b/socket_bind6.c
+@@ -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 --git a/socket_connect6.c b/socket_connect6.c
+new file mode 100644
+index 0000000..d2df4a2
+--- /dev/null
++++ b/socket_connect6.c
+@@ -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 --git a/socket_getifidx.c b/socket_getifidx.c
+new file mode 100644
+index 0000000..c71fc48
+--- /dev/null
++++ b/socket_getifidx.c
+@@ -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 --git a/socket_noipv6.c b/socket_noipv6.c
+new file mode 100644
+index 0000000..289d699
+--- /dev/null
++++ b/socket_noipv6.c
+@@ -0,0 +1,7 @@
++#include "haveip6.h"
++
++#ifdef LIBC_HAS_IP6
++int noipv6=0;
++#else
++int noipv6=1;
++#endif
+diff --git a/socket_recv6.c b/socket_recv6.c
+new file mode 100644
+index 0000000..1fb9b4d
+--- /dev/null
++++ b/socket_recv6.c
+@@ -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 --git a/socket_send6.c b/socket_send6.c
+new file mode 100644
+index 0000000..ded6793
+--- /dev/null
++++ b/socket_send6.c
+@@ -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 --git a/socket_tcp6.c b/socket_tcp6.c
+new file mode 100644
+index 0000000..77bf7bd
+--- /dev/null
++++ b/socket_tcp6.c
+@@ -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 --git a/socket_udp6.c b/socket_udp6.c
+new file mode 100644
+index 0000000..3a10f49
+--- /dev/null
++++ b/socket_udp6.c
+@@ -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 --git a/tdlookup.c b/tdlookup.c
+index da7420d..d3e473e 100644
+--- a/tdlookup.c
++++ b/tdlookup.c
+@@ -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 @@ static int doit(char *q,char qtype[2])
+   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 @@ static int doit(char *q,char qtype[2])
+   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 @@ static int doit(char *q,char qtype[2])
+       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 @@ static int doit(char *q,char qtype[2])
+       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 @@ static int doit(char *q,char qtype[2])
+           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 @@ static int doit(char *q,char qtype[2])
+   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 @@ int respond(char *q,char qtype[2],char ip[4])
+   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 --git a/tinydns-conf.c b/tinydns-conf.c
+index d3a4ce5..db83f11 100644
+--- a/tinydns-conf.c
++++ b/tinydns-conf.c
+@@ -82,6 +82,18 @@ int main(int argc,char **argv)
+   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 --git a/tinydns-data.c b/tinydns-data.c
+index ba82f84..b42bd62 100644
+--- a/tinydns-data.c
++++ b/tinydns-data.c
+@@ -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 stralloc f[NUMFIELDS];
+ static char *d1;
+ static char *d2;
+ char dptr[DNS_NAME4_DOMAIN];
++char d6ptr[DNS_NAME6_DOMAIN];
+ char strnum[FMT_ULONG];
+@@ -193,6 +195,7 @@ int main()
+   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 @@ int main()
+       }
+       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 --git a/tinydns-edit.c b/tinydns-edit.c
+index 126a7e0..8633220 100644
+--- a/tinydns-edit.c
++++ b/tinydns-edit.c
+@@ -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 @@ char *fnnew;
+ 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 @@ void die_write()
+ char mode;
+ static char *target;
+ char targetip[4];
++char targetip6[16];
+ int fd;
+ buffer b;
+@@ -61,7 +64,9 @@ static stralloc f[NUMFIELDS];
+ 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 @@ int main(int argc,char **argv)
+   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 @@ int main(int argc,char **argv)
+   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 @@ int main(int argc,char **argv)
+       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 @@ int main(int argc,char **argv)
+       }
+       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 @@ int main(int argc,char **argv)
+   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 --git a/tryip6.c b/tryip6.c
+new file mode 100644
+index 0000000..e0d7cfb
+--- /dev/null
++++ b/tryip6.c
+@@ -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 --git a/tryn2i.c b/tryn2i.c
+new file mode 100644
+index 0000000..84c3a08
+--- /dev/null
++++ b/tryn2i.c
+@@ -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 --git a/trysa6.c b/trysa6.c
+new file mode 100644
+index 0000000..0fd180c
+--- /dev/null
++++ b/trysa6.c
+@@ -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;
++}
+-- 
+1.6.2
+
diff --git a/dbndns/diff/0003-djbdns-misformats-some-long-response-packets-patch-a.diff b/dbndns/diff/0003-djbdns-misformats-some-long-response-packets-patch-a.diff
new file mode 100644 (file)
index 0000000..bf63acd
--- /dev/null
@@ -0,0 +1,114 @@
+From b65be17a01f4be5ba90f030dcb7c43704c3c8e7b Mon Sep 17 00:00:00 2001
+From: Matthew Dempsky <matthew@dempsky.org>
+Date: Mon, 2 Mar 2009 04:46:05 +0000
+Subject: [PATCH] djbdns misformats some long response packets; patch and example attack
+
+The DNS protocol restricts name compression to point into the first
+16384 bytes of a packet.  Line 18 of response.c from djbdns 1.05
+directly references this, but response_addname() in the same file does
+not enforce this at all.  The consequence of this is that names in
+very large DNS packets may be mangled, and clients may misparse the
+packet.
+
+Because this email is somewhat long, I'll state up front you can find
+a patch for this issue at the bottom of this email or at:
+    http://shinobi.dempsky.org/~matthew/djbdns-bug/patch
+
+To help demonstrate this bug, I've constructed an example attack.  In
+this scenario, there's a .foo TLD operated using tinydns and axfrdns
+(to support DNS queries over TCP; AXFR support is not required).  The
+attacker has registered x.foo and is allowed to upload NS records for
+x.foo and A records for names within the x.foo domain.  However,
+because of the aforementioned bug, this attacker can construct a
+record set that causes the .foo servers to respond to queries asking
+about names within the x.foo domain with poisonous records for names
+outside of x.foo.
+
+Using tinydns-data and tinydns-get from stock djbdns 1.05, you can
+reproduce this as follows:
+
+    $ curl -O http://shinobi.dempsky.org/~matthew/djbdns-bug/data
+    $ grep -c -v -e '&x\.foo::' -e '^+[^:]*\.x\.foo:' data
+    0
+    $ tinydns-data
+    $ tinydns-get a www.x.foo | grep ': foo '
+    additional: foo 8388608 NS a.ns.bar
+    additional: foo 8388608 NS b.ns.bar
+
+(With the patch I linked above, no records outside of x.foo will be
+served.  It's also worth noting the printpacket_cat() routine
+tinydns-get uses for pretty printing the response packet is much
+stricter about parsing than dnscache's parser is; e.g., it rejects
+packets with extra trailing bytes and records with bad rdlength fields
+on known record types.)
+
+If a victim using dnscache now makes an A query for www.x.foo,
+dnscache will save the poisoned records, and begin contacting the
+attacker's nameservers for all .foo requests.  (The response will be
+over 512 bytes long, so dnscache will have to retry the query over
+TCP, which is why axfrdns is necessary too.)
+
+Now, admittedly if you peek at data, you'll see the supplied records
+exceed what most TLDs probably allow: there are redundant NS records,
+there are very long names (but still within the allowed limits of the
+DNS protocol), names use non-printable characters, there are over 100
+records totalling about 24K of storage.  However, neither the djbdns
+documentation nor standard practice warn potential .foo administrators
+that their domain will be at risk for poisoning if they were to add
+support for glue record sets.  (Standard practice only warns that such
+absurd records can negatively impact x.foo, not .foo as well.)
+
+A perhaps more reasonable scenario is that the .foo servers fetch the
+contents of the x.foo domain over AXFR (removing any records from
+outside of x.foo) and then serve the records themselves.  axfr-get,
+the AXFR client from djbdns, would handle the above data set fine.
+
+In looking for a real life example of this latter scenario, I found
+freedns.afraid.org.  They allowed me to register burlap.afraid.org and
+set it up as an AXFR slave to my personal server.  I have not explored
+what limits they place on imported records, and their website states
+they're using BIND, but assuming they're not too limiting and were to
+instead use tinydns/axfrdns/axfr-get, it would be possible for me to
+trick any dnscache that queries for www.burlap.afraid.org into
+contacting another set of nameservers for all of afraid.org's DNS
+traffic.
+
+There's a similar service everydns.net.  They do claim to use tinydns
+(and so I assume axfrdns and axfr-get) and also provide AXFR slave
+support, but they did not allow me to register burlap.everydns.net.
+If they did, it would probably be possible to similarly poison
+everydns.net.
+
+I've tried to search for previous reports of this issue more
+thoroughly than the last bug I mentioned to the list, and I haven't
+found any mention of it yet.  I emailed Dan earlier today when I first
+began to suspect this bug was 'exploitable' to clarify his definition
+of a 'security hole' in djbdns.  I think the afraid.org example is a
+reasonable use case where this bug would violate afraid.org's security
+constraints if they were to instead use djbdns.
+
+Any thoughts from the list on this bug?  (Except from Dean Anderson;
+I'm sure he'll spend the next 3 weeks now arguing I'm a blackhat
+hacker while refusing to look at the patch or sample data file because
+my web server might hack his computer.)
+(cherry picked from commit 8df61658242b3af187544d6cae0f71e7b9034e68)
+---
+ response.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/response.c b/response.c
+index ba90c89..33b2fb1 100644
+--- a/response.c
++++ b/response.c
+@@ -34,7 +34,7 @@ int response_addname(const char *d)
+         uint16_pack_big(buf,49152 + name_ptr[i]);
+         return response_addbytes(buf,2);
+       }
+-    if (dlen <= 128)
++    if ((dlen <= 128) && (response_len < 16384))
+       if (name_num < NAMES) {
+       byte_copy(name[name_num],dlen,d);
+       name_ptr[name_num] = response_len;
+-- 
+1.6.2
+
diff --git a/dbndns/diff/0004-dnscache.c-allow-a-maximum-of-20-concurrent-outgoing.diff b/dbndns/diff/0004-dnscache.c-allow-a-maximum-of-20-concurrent-outgoing.diff
new file mode 100644 (file)
index 0000000..fde7421
--- /dev/null
@@ -0,0 +1,79 @@
+From a7e94dd5f99a7e63af8fb2ce0406e294703814b7 Mon Sep 17 00:00:00 2001
+From: Gerrit Pape <pape@smarden.org>
+Date: Tue, 10 Mar 2009 13:35:38 +0000
+Subject: [PATCH] dnscache.c: allow a maximum of 20 concurrent outgoing SOA queries
+
+dnscache doesn't cache SOA records, and doesn't merge outgoing queries
+to the same servers.  This commit limits the concurrent outgoing SOA
+queries to 20 to make birthday attacks as described in CVE-2008-4392
+more difficult.
+---
+ dnscache.c |   15 +++++++++++++++
+ log.c      |    6 ++++++
+ 2 files changed, 21 insertions(+), 0 deletions(-)
+
+diff --git a/dnscache.c b/dnscache.c
+index abcba69..2366ecc 100644
+--- a/dnscache.c
++++ b/dnscache.c
+@@ -72,11 +72,15 @@ static struct udpclient {
+ } u[MAXUDP];
+ int uactive = 0;
++#define MAXSOA 20
++int soaactive = 0;
++
+ void u_drop(int j)
+ {
+   if (!u[j].active) return;
+   log_querydrop(&u[j].active);
+   u[j].active = 0; --uactive;
++  if (byte_equal(u[j].q.type,2,DNS_T_SOA)) --soaactive;
+ }
+ void u_respond(int j)
+@@ -87,6 +91,7 @@ void u_respond(int j)
+   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;
++  if (byte_equal(u[j].q.type,2,DNS_T_SOA)) --soaactive;
+ }
+ void u_new(void)
+@@ -125,6 +130,16 @@ void u_new(void)
+   x->active = ++numqueries; ++uactive;
+   log_query(&x->active,x->ip,x->port,x->id,q,qtype);
++
++  if (byte_equal(qtype,2,DNS_T_SOA)) {
++    if (soaactive >= MAXSOA) {
++      log_querydropmaxsoa(&x->active);
++      x->active = 0; --uactive;
++      return;
++    }
++    ++soaactive;
++  }
++
+   switch(query_start(&x->q,q,qtype,qclass,myipoutgoing,interface)) {
+     case -1:
+       u_drop(j);
+diff --git a/log.c b/log.c
+index df465e2..a651607 100644
+--- a/log.c
++++ b/log.c
+@@ -118,6 +118,12 @@ void log_querydrop(uint64 *qnum)
+   line();
+ }
++void log_querydropmaxsoa(uint64 *qnum)
++{
++  string("drop "); number(*qnum); space(); string("maxsoa");
++  line();
++}
++
+ void log_tcpopen(const char client[16],unsigned int port)
+ {
+   string("tcpopen ");
+-- 
+1.6.2
+
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..24404c5
--- /dev/null
@@ -0,0 +1,225 @@
+djbdns (1:1.05-8) unstable; urgency=low
+
+  * debian/dbndns.README.Debian: copy information from
+    debian/djbdns.README.Debian (closes: #575473); clarify purpose of
+    the package.
+  * debian/control: dbndns: adapt long description to clarify the
+    purpose of the package.
+  * debian/dnscache-run.postrm: use -f option to deluser; don't complain
+    if dnscache service already is removed; no longer remove the Gdnslog
+    user on purge.
+
+ -- Gerrit Pape <pape@smarden.org>  Mon, 29 Mar 2010 23:53:46 +0000
+
+djbdns (1:1.05-7) unstable; urgency=low
+
+  * debian/dnscache-run.postinst: use the svc program instead of sv to
+    restart dnscache on upgrade (thx ben; closes: #528973).
+  * debian/diff/0003-dnstracesort.sh-don-t-use-deprecated...diff: new;
+    dnstracesort.sh: don't use deprecated "+number" sort(1) option (thx
+    Shai Rosenfeld; closes: #486935).
+  * debian/djbdns-man/*-conf.8: refer to the update-service(8) program
+    for enabling services, mark creating a symlink manually as example
+    (closes: #542613).
+
+ -- Gerrit Pape <pape@smarden.org>  Wed, 30 Sep 2009 19:49:20 +0000
+
+djbdns (1:1.05-6) unstable; urgency=medium
+
+  * dbndns/diff/0004-dnscache.c-allow-a-maximum-of-20-concurrent...diff:
+    new; dnscache.c: allow a maximum of 20 concurrent outgoing SOA
+    queries (#516394).
+  * debian/djbdns.NEWS.Debian: talk about the patch 0004-dnscache.c...
+    being applied to the dbndns package.
+  * debian/dnscache-run.postinst: restart dnscache on package upgrade.
+  * debian/dbndns.README.Debian: document that patches 0003-...diff,
+    0004-...dif are applied to dbndns.
+
+ -- Gerrit Pape <pape@smarden.org>  Mon, 16 Mar 2009 23:42:32 +0000
+
+djbdns (1:1.05-5) unstable; urgency=high
+
+  * debian/diff/0002-djbdns-misformats-some-long-response...diff: new;
+    djbdns misformats some long response packets; patch and example
+    attack (closes: #518169, #517631).
+  * dbndns/diff/0003-djbdns-misformats-some-long-response...diff: new;
+    djbdns misformats some long response packets; patch and example
+    attack (closes: #518169, #517631).
+
+ -- Gerrit Pape <pape@smarden.org>  Wed, 04 Mar 2009 15:55:50 +0000
+
+djbdns (1:1.05-4) unstable; urgency=medium
+
+  * debian/dnscache-run.postrm: use daemontools' svc program to take
+    down service (thx Javier Fernández-Sanguino Peña for the patch,
+    closes: #491503).
+  * debian/dnscache-run.preinst, debian/dnscache-run.postinst: create
+    seed file through dnscache-conf in postinst instead of preinst
+    (closes: #491343).
+  * debian/control: Standards-Version: 3.8.0.1.
+
+ -- Gerrit Pape <pape@smarden.org>  Wed, 13 Aug 2008 19:30:06 +0000
+
+djbdns (1:1.05-3) unstable; urgency=low
+
+  * debian/rules: build and install new package dbndns (based on patch
+    by Robert Edmonds, thx).
+  * debian/control: new package dbndns: Debian fork of djbdns (closes:
+    #472771).
+  * dbndns/diff/0001-hier.c-don-t-install-etc-dnsroots.global.diff,
+    dbndns/diff/0002-Apply-fefe-s-djbdns-1.05-test23-ipv6-patch.diff:
+    new; hier.c: don't install /etc/dnsroots.global; apply fefe's
+    djbdns-1.05-test23 ipv6 patch.
+  * debian/dbndns.conffiles: new; /etc/dnsroots.global.
+  * debian/djbdns.NEWS.Debian: no longer talk about djbdns-installer
+    still being available, it's been removed from sid.
+  * debian/dbndns.README.Debian: new; document what patches are applied.
+  * dnscache-run/*: new; sources for new dnscache-run package.
+  * debian/dnscache-run.postinst, debian/dnscache-run.postrm,
+    debian/dnscache-run.preinst, debian/dnscache-run.prerm: new; handle
+    dnscache service.
+  * debian/dnscache-run.conffiles: new.
+  * debian/rules: build and install new package dnscache-run.
+  * debian/control: new package dnscache-run: djbdns dnscache service.
+  * debian/dnscache-run.README.Debian: new.
+  * debian/control: packages djbdns, dbndns: Suggests: dnscache-run.
+
+ -- Gerrit Pape <pape@smarden.org>  Tue, 13 May 2008 20:58:56 +0000
+
+djbdns (1:1.05-2) unstable; urgency=low
+
+  * debian/djbdns.NEWS.Debian: add note that ./run scripts in already
+    existing service directories most probably need to be adapted when
+    upgrading from << 1:1.05.
+  * debian/control: Standards-Version: 3.7.3.0.
+
+ -- Gerrit Pape <pape@smarden.org>  Sun, 02 Mar 2008 23:22:04 +0000
+
+djbdns (1:1.05-1) unstable; urgency=low
+
+  * debian/implicit: add proper dependencies to support 'parallel build'
+    through make -j (thx Daniel Schepler for the patch).
+  * debian/changelog: add epoch 1 to supersede unofficial package.
+  * debian/rules: remove target configure:; use glibc by default instead
+    of dietlibc; install programs into /usr/bin/.
+  * debian/gcc/: remove; obsolete.
+  * debian/control: no longer Build-Depends: dietlibc-dev.
+  * debian/rules: run dpkg-shlibdeps; remove debian/substvars in target
+    clean:.
+  * debian/rules: use 'gcc -O2 -g -include /usr/include/errno.h' for
+    conf-cc.
+  * debian/diff/0001-hier.c-don-t-install-etc-dnsroots.global.diff: new;
+    hier.c: don't install /etc/dnsroots.global.
+  * debian/rules: new target patch: apply patches from debian/diff/;
+    reverse apply in target clean:.
+  * debian/rules: target install: force-remove install, instcheck before
+    rebuilding to avoid race.
+  * debian/rules: fix up directory permissions /usr/, /usr/bin/.
+  * debian/control: remove reference to unofficial packages from the
+    description.
+  * debian/control: no longer Recommends: djbdns-doc; no longer Depends:
+    daemontools, ucspi-tcp, make, but Recommends: them; Recommends:
+    daemontools-run | runit; Depends: ${shlibs:Depends}.
+  * debian/djbdns-man/: new; add manpages downloaded from
+    http://smarden.org/pape/djb/manpages/djbdns-1.05-man-20031023.tar.gz.
+  * debian/rules: install manpages from debian/djbdns-man/ into
+    /usr/share/man/man1/ and /usr/share/man/man8/.
+  * debian/copyright: rewrite copyright.
+  * debian/djbdns.README.Debian: redo.
+  * debian/control: Standards-Version: 3.7.2.2.
+  * debian/rules: install updated debian/dnsroots.global, instead of
+    upstream's.
+  * debian/control: update short and long description.
+  * upload to Debian/main (closes: #453680).
+  * debian/djbdns.README.Debian: add note about daemontools' default
+    directory for services is /etc/service/.
+  * debian/djbdns.NEWS.Debian: new; package introduced to Debian/main,
+    mention how to put on hold if upgrade from non-free is not desired.
+  * debian/djbdns-man/dnsipq.1, debian/djbdns-man/dnstxt.1: typo.
+  * debian/control: Replaces: djbdns-doc.
+
+ -- Gerrit Pape <pape@smarden.org>  Tue, 26 Feb 2008 20:54:59 +0000
+
+djbdns (1.05-zarge2) sarge; urgency=low
+
+  * build against sarge's dietlibc-dev (0.28-3).
+
+ -- Gerrit Pape <pape@smarden.org>  Thu, 26 May 2005 19:03:38 +0000
+
+djbdns (1.05-zarge1) sarge; urgency=low
+
+  * debian/rules: minor cleanup.
+  * debian/implicit: update to revision 1.10.
+  * debian/djbdns.conffiles: new; /etc/dnsroots.global.
+  * debian/control: typo in description.
+
+ -- Gerrit Pape <pape@smarden.org>  Wed, 18 Aug 2004 14:35:29 +0000
+
+djbdns (1.05-zarge0.4) sarge; urgency=low
+
+  * debian/control: Depends: make (thx Thomas Mangin); no longer
+    Build-Depends: dephelper; remove Standards-Version.
+  * debian/rules: stop using debhelper, use implicit rules.
+  * debian/implicit: new; implicit Makefile rules.
+  * debian/README.Debian, debian/docs: rename to debian/ucspi-tcp.*.
+  * debian/dirs: remove; obsolete.
+  * debian/copyright: minor.
+
+ -- Gerrit Pape <pape@smarden.org>  Wed, 10 Mar 2004 08:23:22 +0000
+
+djbdns (1.05-zarge0.2) sarge; urgency=low
+
+  * use diet libc.
+  * debian/rules: set up diet program as c compiler wrapper; conditionally
+    overwrite PATH to have diet program used as c compiler wrapper; minor
+    cleanup.
+  * debian/gcc/gcc*: new; diet program as c compiler wrapper.
+  * debian/control: Build-Depends: dietlibc-dev; no longer Depends:
+    ${shlibs:Depends}; minor cleanup.
+
+ -- Gerrit Pape <pape@smarden.org>  Wed, 12 Nov 2003 13:19:10 +0000
+
+djbdns (1.05-woody1) woody; urgency=low
+
+  * bump version for release.
+
+ -- Gerrit Pape <pape@smarden.org>  Tue,  9 Jul 2002 11:05:16 +0200
+
+djbdns (1.05-woody0.1) woody; urgency=low
+
+  * woody package; new Standards-Version: 3.5.2.
+
+ -- Gerrit Pape <pape@smarden.org>  Mon, 15 Oct 2001 11:49:50 +0200
+
+djbdns (1.05-1) stable; urgency=low
+
+  * new upstream version 1.05.
+  * switched to _recommend_ djbdns-doc (not depend on).
+  * dist stable.
+
+ -- Gerrit Pape <pape@innominate.com>  Mon, 12 Feb 2001 14:55:09 +0100
+
+djbdns (1.04-1) unstable; urgency=low
+
+  * new upstream version 1.04.
+
+ -- Gerrit Pape <pape@innominate.com>  Mon, 22 Jan 2001 10:50:51 +0100
+
+djbdns (1.03-1) unstable; urgency=low
+
+  * new upstream version 1.03.
+
+ -- Gerrit Pape <pape@innominate.com>  Mon,  8 Jan 2001 23:29:43 +0100
+
+djbdns (1.02-0.2) unstable; urgency=low
+
+  * dependencies, cleanup.
+
+ -- Gerrit Pape <pape@innominate.com>  Mon, 18 Dec 2000 11:32:59 +0100
+
+djbdns (1.02-0.1) unstable; urgency=low
+
+  * Initial Release.
+
+ -- Gerrit Pape <pape@innominate.de>  Wed,  8 Nov 2000 10:21:36 +0100
+
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..dde0e11
--- /dev/null
@@ -0,0 +1,79 @@
+Source: djbdns
+Section: net
+Priority: optional
+Maintainer: Gerrit Pape <pape@smarden.org>
+Standards-Version: 3.8.0.1
+
+Package: djbdns
+Architecture: any
+Depends: ${shlibs:Depends}
+Replaces: djbdns-doc
+Suggests: dnscache-run
+Recommends: daemontools, ucspi-tcp, daemontools-run | runit, make
+Description: a collection of Domain Name System tools
+ This package includes software for all the fundamental DNS operations:
+ .
+ DNS cache: finding addresses of Internet hosts.  When a browser wants to
+ contact www.hotwired.com, it first asks a DNS cache, such as djbdns's
+ dnscache, to find the IP address of www.hotwired.com.  Internet service
+ providers run dnscache to find IP addresses requested by their customers.
+ If you're running a home computer or a workstation, you can run your own
+ dnscache to speed up your web browsing.
+ .
+ DNS server: publishing addresses of Internet hosts.  The IP address of
+ www.hotwired.com is published by HotWired's DNS servers.  djbdns includes
+ a general-purpose DNS server, tinydns; network administrators run tinydns
+ to publish the IP addresses of their computers.  djbdns also includes
+ special-purpose servers for publishing DNS walls and RBLs.
+ .
+ DNS client: talking to a DNS cache.  djbdns includes a DNS client C
+ library and several command-line DNS client utilities.  Programmers use
+ these tools to send requests to DNS caches.
+ .
+ djbdns also includes several DNS debugging tools, notably dnstrace, which
+ administrators use to diagnose misconfigured remote servers.
+ .
+ See http://cr.yp.to/djbdns.html
+
+Package: dbndns
+Architecture: any
+Depends: ${shlibs:Depends}
+Replaces: djbdns-doc
+Recommends: daemontools, ucspi-tcp, daemontools-run | runit, make
+Conflicts: djbdns
+Provides: djbdns
+Suggests: dnscache-run
+Description: Debian fork of djbdns, a collection of Domain Name System tools
+ dbndns is a fork of the djbdns package, including patches requested by
+ Debian developers and Debian users, e.g. a patch to provide IPv6
+ functionality.
+ .
+ The djbdns package provides software for all the fundamental DNS
+ operations:
+ .
+ DNS cache: finding addresses of Internet hosts.  When a browser wants to
+ contact www.hotwired.com, it first asks a DNS cache, such as djbdns's
+ dnscache, to find the IP address of www.hotwired.com.  Internet service
+ providers run dnscache to find IP addresses requested by their customers.
+ If you're running a home computer or a workstation, you can run your own
+ dnscache to speed up your web browsing.
+ .
+ DNS server: publishing addresses of Internet hosts.  The IP address of
+ www.hotwired.com is published by HotWired's DNS servers.  djbdns includes
+ a general-purpose DNS server, tinydns; network administrators run tinydns
+ to publish the IP addresses of their computers.  djbdns also includes
+ special-purpose servers for publishing DNS walls and RBLs.
+ .
+ DNS client: talking to a DNS cache.  djbdns includes a DNS client C
+ library and several command-line DNS client utilities.  Programmers use
+ these tools to send requests to DNS caches.
+ .
+ djbdns also includes several DNS debugging tools, notably dnstrace, which
+ administrators use to diagnose misconfigured remote servers.
+
+Package: dnscache-run
+Architecture: all
+Depends: djbdns, daemontools, daemontools-run | runit, adduser
+Description: djbdns dnscache service
+ This package automatically sets up the djbdns package to provide a
+ dnscache service, listening on 127.0.0.1 by default.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..d79104e
--- /dev/null
@@ -0,0 +1,20 @@
+This package was debianized by Gerrit Pape <pape@smarden.org> on
+Mon,  8 Jan 2001 23:29:43 +0100.
+
+It was downloaded from
+ http://cr.yp.to/djbdns/djbdns-1.05.tar.gz
+
+The man-pages in debian/djbdns-man/ were downloaded from
+ http://smarden.org/pape/djb/manpages/djbdns-1.05-man-20031023.tar.gz
+
+Upstream Author: D. J. Bernstein <djb@cr.yp.to>
+
+Copyright:
+
+D. J. Bernstein placed the djbdns package into the public domain.
+From http://cr.yp.to/distributors.html
+ 2007.12.28: I hereby place the djbdns package (in particular,
+ djbdns-1.05.tar.gz, with MD5 checksum 3147c5cd56832aa3b41955c7a51cbeb2)
+ into the public domain. The package is no longer copyrighted.
+
+The Debian diff is in the public domain.
diff --git a/debian/dbndns.README.Debian b/debian/dbndns.README.Debian
new file mode 100644 (file)
index 0000000..b0c94a7
--- /dev/null
@@ -0,0 +1,23 @@
+dbndns for Debian
+-----------------
+
+dbndns is a Debian fork of the djbdns package, it includes the following
+patches:
+
+ * IPv6 patch: djbdns-1.05-test23.diff.bz2 from
+     http://www.fefe.de/dns/
+ * long response packets misformat patch from
+     http://shinobi.dempsky.org/~matthew/djbdns-bug/patch
+ * maxsoa patch from
+     http://smarden.org/pape/Debian/dbndns/maxsoa.diff
+
+This package can be used as an alternative to the djbdns package.  It
+provides the same programs as the djbdns package, installed into
+/usr/bin/, and man pages.  When configuring and enabling dns services,
+please note that daemontools' default directory for services on Debian
+is /etc/service/, not /service/.
+
+See http://cr.yp.to/djbdns.html and the URLs above for detailed
+documentation.
+
+ -- Gerrit Pape <pape@smarden.org>  Mon, 16 Mar 2009 23:42:32 +0000
diff --git a/debian/dbndns.conffiles b/debian/dbndns.conffiles
new file mode 100644 (file)
index 0000000..6b0e2f3
--- /dev/null
@@ -0,0 +1 @@
+/etc/dnsroots.global
diff --git a/debian/diff/0001-hier.c-don-t-install-etc-dnsroots.global.diff b/debian/diff/0001-hier.c-don-t-install-etc-dnsroots.global.diff
new file mode 100644 (file)
index 0000000..e1aa4d8
--- /dev/null
@@ -0,0 +1,29 @@
+From e036abc40f9aefc13f06d944f0ec4b2230e9c28c Mon Sep 17 00:00:00 2001
+From: Gerrit Pape <pape@smarden.org>
+Date: Mon, 12 Feb 2001 14:02:49 +0000
+Subject: [PATCH] hier.c: don't install /etc/dnsroots.global
+
+dnsroots.global is installed by debian/rules into debian/djbdns/etc/
+instead while building the Debian package.
+---
+ hier.c |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/hier.c b/hier.c
+index 4aef75b..b57dba0 100644
+--- a/hier.c
++++ b/hier.c
+@@ -2,7 +2,10 @@
+ void hier()
+ {
++/*
++  This file is installed by debian/rules in debian/tmp/etc
+   c("/","etc","dnsroots.global",-1,-1,0644);
++*/
+   h(auto_home,-1,-1,02755);
+   d(auto_home,"bin",-1,-1,02755);
+-- 
+1.6.0.3
+
diff --git a/debian/diff/0002-djbdns-misformats-some-long-response-packets-patch-a.diff b/debian/diff/0002-djbdns-misformats-some-long-response-packets-patch-a.diff
new file mode 100644 (file)
index 0000000..e1b6950
--- /dev/null
@@ -0,0 +1,113 @@
+From 7ab631dd08419f2ce9ea61b941f26db65b622494 Mon Sep 17 00:00:00 2001
+From: Matthew Dempsky <matthew@dempsky.org>
+Date: Mon, 2 Mar 2009 04:46:05 +0000
+Subject: [PATCH] djbdns misformats some long response packets; patch and example attack
+
+The DNS protocol restricts name compression to point into the first
+16384 bytes of a packet.  Line 18 of response.c from djbdns 1.05
+directly references this, but response_addname() in the same file does
+not enforce this at all.  The consequence of this is that names in
+very large DNS packets may be mangled, and clients may misparse the
+packet.
+
+Because this email is somewhat long, I'll state up front you can find
+a patch for this issue at the bottom of this email or at:
+    http://shinobi.dempsky.org/~matthew/djbdns-bug/patch
+
+To help demonstrate this bug, I've constructed an example attack.  In
+this scenario, there's a .foo TLD operated using tinydns and axfrdns
+(to support DNS queries over TCP; AXFR support is not required).  The
+attacker has registered x.foo and is allowed to upload NS records for
+x.foo and A records for names within the x.foo domain.  However,
+because of the aforementioned bug, this attacker can construct a
+record set that causes the .foo servers to respond to queries asking
+about names within the x.foo domain with poisonous records for names
+outside of x.foo.
+
+Using tinydns-data and tinydns-get from stock djbdns 1.05, you can
+reproduce this as follows:
+
+    $ curl -O http://shinobi.dempsky.org/~matthew/djbdns-bug/data
+    $ grep -c -v -e '&x\.foo::' -e '^+[^:]*\.x\.foo:' data
+    0
+    $ tinydns-data
+    $ tinydns-get a www.x.foo | grep ': foo '
+    additional: foo 8388608 NS a.ns.bar
+    additional: foo 8388608 NS b.ns.bar
+
+(With the patch I linked above, no records outside of x.foo will be
+served.  It's also worth noting the printpacket_cat() routine
+tinydns-get uses for pretty printing the response packet is much
+stricter about parsing than dnscache's parser is; e.g., it rejects
+packets with extra trailing bytes and records with bad rdlength fields
+on known record types.)
+
+If a victim using dnscache now makes an A query for www.x.foo,
+dnscache will save the poisoned records, and begin contacting the
+attacker's nameservers for all .foo requests.  (The response will be
+over 512 bytes long, so dnscache will have to retry the query over
+TCP, which is why axfrdns is necessary too.)
+
+Now, admittedly if you peek at data, you'll see the supplied records
+exceed what most TLDs probably allow: there are redundant NS records,
+there are very long names (but still within the allowed limits of the
+DNS protocol), names use non-printable characters, there are over 100
+records totalling about 24K of storage.  However, neither the djbdns
+documentation nor standard practice warn potential .foo administrators
+that their domain will be at risk for poisoning if they were to add
+support for glue record sets.  (Standard practice only warns that such
+absurd records can negatively impact x.foo, not .foo as well.)
+
+A perhaps more reasonable scenario is that the .foo servers fetch the
+contents of the x.foo domain over AXFR (removing any records from
+outside of x.foo) and then serve the records themselves.  axfr-get,
+the AXFR client from djbdns, would handle the above data set fine.
+
+In looking for a real life example of this latter scenario, I found
+freedns.afraid.org.  They allowed me to register burlap.afraid.org and
+set it up as an AXFR slave to my personal server.  I have not explored
+what limits they place on imported records, and their website states
+they're using BIND, but assuming they're not too limiting and were to
+instead use tinydns/axfrdns/axfr-get, it would be possible for me to
+trick any dnscache that queries for www.burlap.afraid.org into
+contacting another set of nameservers for all of afraid.org's DNS
+traffic.
+
+There's a similar service everydns.net.  They do claim to use tinydns
+(and so I assume axfrdns and axfr-get) and also provide AXFR slave
+support, but they did not allow me to register burlap.everydns.net.
+If they did, it would probably be possible to similarly poison
+everydns.net.
+
+I've tried to search for previous reports of this issue more
+thoroughly than the last bug I mentioned to the list, and I haven't
+found any mention of it yet.  I emailed Dan earlier today when I first
+began to suspect this bug was 'exploitable' to clarify his definition
+of a 'security hole' in djbdns.  I think the afraid.org example is a
+reasonable use case where this bug would violate afraid.org's security
+constraints if they were to instead use djbdns.
+
+Any thoughts from the list on this bug?  (Except from Dean Anderson;
+I'm sure he'll spend the next 3 weeks now arguing I'm a blackhat
+hacker while refusing to look at the patch or sample data file because
+my web server might hack his computer.)
+---
+ response.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/response.c b/response.c
+index ba90c89..33b2fb1 100644
+--- a/response.c
++++ b/response.c
+@@ -34,7 +34,7 @@ int response_addname(const char *d)
+         uint16_pack_big(buf,49152 + name_ptr[i]);
+         return response_addbytes(buf,2);
+       }
+-    if (dlen <= 128)
++    if ((dlen <= 128) && (response_len < 16384))
+       if (name_num < NAMES) {
+       byte_copy(name[name_num],dlen,d);
+       name_ptr[name_num] = response_len;
+-- 
+1.6.0.3
+
diff --git a/debian/diff/0003-dnstracesort.sh-don-t-use-deprecated-number-sort.diff b/debian/diff/0003-dnstracesort.sh-don-t-use-deprecated-number-sort.diff
new file mode 100644 (file)
index 0000000..00ebd17
--- /dev/null
@@ -0,0 +1,28 @@
+From ca61a385c7685e0470fb6b140439113fcdc9e74c Mon Sep 17 00:00:00 2001
+From: Shai Rosenfeld <shaiguitar@gmail.com>
+Date: Wed, 30 Sep 2009 18:50:32 +0000
+Subject: [PATCH] dnstracesort.sh: don't use deprecated "+number" sort(1) option
+
+dnstracesort contained the line "sort -t: +0 -2 +4 +3 -4 +2 -3" which
+uses the depracated sort field selection.  This commit changes the
+options to "-k": "sort -t: -k 1,3 -k 5 -k 4,5 -k 3,4".
+---
+ dnstracesort.sh |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/dnstracesort.sh b/dnstracesort.sh
+index e57359c..108ef2f 100644
+--- a/dnstracesort.sh
++++ b/dnstracesort.sh
+@@ -12,7 +12,7 @@ awk -F: '
+     }
+     print
+   }
+-' | sort -t: +0 -2 +4 +3 -4 +2 -3 | uniq | awk -F: '
++' | sort -t: -k 1,3 -k 5 -k 4,5 -k 3,4 | uniq | awk -F: '
+   {
+     type = $1
+     q = $2
+-- 
+1.6.0.3
+
diff --git a/debian/djbdns-man/README b/debian/djbdns-man/README
new file mode 100644 (file)
index 0000000..6755b39
--- /dev/null
@@ -0,0 +1,51 @@
+Thu, 16 Nov 2000 12:20:53 +0100
+
+These man-pages were created from djb's documentation found at
+http://cr.yp.to/djbdns.html .
+
+Gzip the man-pages and copy them to a subdirectory man8/ or man1/ or man5/
+of any directory found in Your $MANPATH:
+
+  # gzip *.8 ; cp *.8.gz /usr/share/man/man8/
+  # gzip *.1 ; cp *.1.gz /usr/share/man/man1/
+  # gzip *.5 ; cp *.5.gz /usr/share/man/man5/
+
+See http://smarden.org/pape/djb/ for recent informations.
+
+G. Pape <pape@smarden.org>
+
+Fri,  1 Dec 2000 10:06:36 +0100
+  * fixed some man-pages to work on solaris, thanks Jonathan de Boyne Pollard.
+
+Tue,  9 Jan 2001 00:27:57 +0100
+  * man-pages adapted to version 1.03: http://cr.yp.to/djbdns/doc.tar.gz
+
+Mon, 22 Jan 2001 12:19:35 +0100
+  * man-pages adapted to version 1.04: http://cr.yp.to/djbdns/doc.tar.gz
+
+Mon, 12 Feb 2001 13:32:11 +0100
+  * man-pages adapted to version 1.05: http://cr.yp.to/djbdns/doc.tar.gz
+
+Wed,  2 May 2001 14:30:38 +0200
+  * merged changes from axfr-get.html into axfr-get.8:
+    http://cr.yp.to/djbdns/doc.tar.gz
+  * added contributed man-page tinydns-edit.8, thanks Jonathan de Boyne
+    Pollard.
+
+Wed, 30 Jan 2002 16:29:54 +0100
+  * merged changes from tinydns-data.html into tinydns-data.8:
+    http://cr.yp.to/djbdns/doc.tar.gz
+
+Wed, 11 Dec 2002 10:23:18 +0100
+  * merge changes from http://cr.yp.to/djbdns/doc.tar.gz into: axfr-get.8,
+    dnscache-conf.8, dnscache.8, dnsfilter.1, dnsip.1, dnsipq.1, dnsmx.1,
+    dnsname.1, dnsq.1, dnsqr.1, dnstrace.1, dnstxt.1, qualification.5,
+    tinydns-conf.8, tinydns-data.8.
+  * tinydns-get.1: new.
+
+Thu, 23 Oct 2003 08:15:45 +0000
+  * merge changes from http://cr.yp.to/djbdns/doc.tar.gz into: axfr-get.8,
+    tinydns-data.8.
+  * pickdns-conf.8, pickdns-data.8, pickdns.8: remove.
+  * dnscache-conf.8, rbldns-conf.8, tinydns-conf.8, walldns-conf.8: adapt.
+  * axfrdns-conf.8: new.
diff --git a/debian/djbdns-man/axfr-get.8 b/debian/djbdns-man/axfr-get.8
new file mode 100644 (file)
index 0000000..a661c05
--- /dev/null
@@ -0,0 +1,130 @@
+.TH axfr-get 8
+
+.SH NAME
+axfr-get \- a DNS zone-transfer client.
+
+It sends a zone-transfer request
+in DNS-over-TCP format to descriptor 7,
+reads the results from descriptor 6,
+and saves the results in a file.
+
+.SH SYNOPSIS
+Normally 
+.B axfr-get
+is run under 
+.BR tcpclient (1),
+which sets up descriptors 6 and 7 as a TCP connection to a remote host.
+
+.B axfr-get 
+.I z
+.I fn
+.I fn.tmp
+
+.SH DESCRIPTION
+.B axfr-get
+performs a zone transfer for domain 
+.IR z .
+It writes the results to 
+.I fn.tmp
+in a format that can be used as input to
+.BR tinydns-data (8).
+If the zone transfer completes successfully,
+.B axfr-get
+atomically renames 
+.I fn.tmp
+as 
+.IR fn .
+
+.I fn.tmp
+and 
+.I fn
+must be on the same filesystem.
+
+.B axfr-get
+writes the zone serial number as a comment at the top of
+.IR fn.tmp .
+It skips the zone transfer,
+leaving 
+.I fn
+alone,
+if
+.I fn
+already exists,
+.I fn
+has a serial number
+matching the zone serial number,
+and both serial numbers are nonzero.
+
+Zone transfers often include duplicate records.
+You should feed the 
+.B axfr-get
+results through
+sort -u.
+
+.B axfr-get
+discards all records outside the domain 
+.IR z .
+It accepts records in child zones,
+but it marks all child zones as non-authoritative, so
+.BR tinydns (8)
+will not report those records except as glue.
+If you plan to merge the 
+.B axfr-get
+results
+for a domain and a child of the same domain,
+creating a file authoritative for both zones,
+make sure to eliminate records in the first output
+that are within the child zone.
+
+.B axfr-get
+will accept arbitrarily large zone transfers.
+To limit the maximum file size to 1 megabyte,
+run 
+.B axfr-get
+under 
+.BR softlimit 
+\-f 1048576.
+
+.SH Compatibility notes
+
+.B axfr-get
+handles
+BIND's RFC-1034-violating multiple-answers zone-transfer format.
+
+.B axfr-get
+does not precisely simulate BIND's handling of 
+.IR *.dom .
+Under BIND, records for
+.I *.dom
+do not apply to
+.I y.dom
+or
+.I anything.y.dom
+if there is a normal record for
+.IR x.y.dom .
+With 
+.B axfr-get
+and 
+.BR tinydns (8),
+the records apply to 
+.I y.dom
+and
+.I anything.y.dom
+except 
+.IR x.y.dom .
+
+.B axfr-get
+does not precisely simulate BIND's handling of multiple IP addresses
+for a single name.
+When there are more than 8 addresses,
+.BR tinydns (8)
+selects a random set of 8 for each query.
+
+.SH SEE ALSO
+axfrdns(8),
+tinydns(8),
+tinydns-data(8),
+tcpclient(1),
+softlimit(8)
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/axfrdns-conf.8 b/debian/djbdns-man/axfrdns-conf.8
new file mode 100644 (file)
index 0000000..16ceaff
--- /dev/null
@@ -0,0 +1,117 @@
+.TH axfrdns-conf 8
+
+.SH NAME
+axfrdns-conf \- sets up a DNS zone-transfer service.
+
+.SH SYNOPSIS
+.B axfrdns-conf 
+.I acct
+.I logacct
+.I D
+.I tiny
+.I ip
+
+.SH DESCRIPTION
+.B axfrdns-conf
+creates a service directory 
+.I D
+that runs
+.BR axfrdns (8)
+under
+.BR tcpserver (1).
+The name 
+.I D
+must start with a slash
+and must not contain any special characters.
+Normally 
+.I D
+is 
+.IR /etc/axfrdns .
+
+You can run the service under
+.BR svscan (8)
+by using the
+.BR update-service (8)
+program on Debian GNU/Linux
+
+update-service --add
+.I D
+
+or by creating a symbolic link in the 
+.BR svscan (8)
+directory (normally /service or /etc/service), e.g.:
+
+ln -s 
+.I D
+/service
+
+The service will start within five seconds,
+and will be restarted upon reboot.
+You can use
+.BR svc (8)
+to control the service.
+
+.B axfrdns-conf
+arranges for
+.BR tcpserver (1)
+to listen for TCP connections on port 53 of
+.IR ip .
+It sets up
+.IR D /tcp
+in
+.BR tcprules (1)
+format
+to control access to
+.BR axfrdns (8);
+initially all access is denied.
+It also sets up
+.IR D /Makefile
+to compile
+.I tcp
+into
+.I tcp.cdb
+for
+.BR tcpserver (1).
+
+.B axfrdns-conf
+arranges for
+.BR axfrdns (8)
+to chroot to
+.IR tiny /root
+and to run under the uid and gid of
+.IR acct .
+The name
+.I tiny
+must start with a slash
+and must not contain any special characters;
+normally it is
+.IR /etc/tinydns .
+The name
+.I acct
+must not contain any special characters.
+
+.B axfrdns-conf
+creates an automatically rotated log directory in
+.IR D /log/main.
+The logs are owned by
+.IR logacct .
+The corresponding
+.BR multilog (8)
+processes run under the uid and gid of
+.IR logacct .
+The name
+.I logacct
+must not contain any special characters.
+
+.SH SEE ALSO
+axfrdns(8),
+svscan(8),
+svc(8),
+multilog(8),
+dnscache-conf(8),
+rbldns-conf(8),
+tinydns-conf(8),
+walldns-conf(8),
+update-service(8)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/axfrdns.8 b/debian/djbdns-man/axfrdns.8
new file mode 100644 (file)
index 0000000..07a5b82
--- /dev/null
@@ -0,0 +1,139 @@
+.TH axfrdns 8
+
+.SH NAME
+axfrdns \- a DNS zone-transfer server.
+
+.SH DESCRIPTION
+.B axfrdns
+reads a zone-transfer request
+in DNS-over-TCP format from its standard input,
+and responds with locally configured information.
+
+.SH Configuration
+Normally 
+.B axfrdns
+is set up by the
+.BR axfrdns-conf (8)
+program.
+
+.B axfrdns
+runs chrooted in the directory
+specified by the 
+.I $ROOT
+environment variable,
+under the uid and gid
+specified by the 
+.I $UID
+and 
+.I $GID
+environment variables.
+
+Normally 
+.B axfrdns
+runs under 
+.BR tcpserver (1)
+to handle TCP connections on port 53 of a local IP address.
+
+.BR tcpserver (1)
+is responsible for
+rejecting connections from hosts not authorized to perform zone transfers.
+
+.B axfrdns
+can also run under secure connection tools
+offering an UCSPI-compliant interface.
+
+.B axfrdns
+looks up zone-transfer results
+in 
+.IR data.cdb ,
+a binary file created by
+.BR tinydns-data (8).
+It also responds to normal client queries,
+such as SOA queries, which usually precede zone-transfer requests.
+
+.B axfrdns
+allows zone transfers
+for any zone listed in the 
+.I $AXFR
+environment variable.
+
+.I $AXFR
+is a slash-separated list of domain names.
+If 
+.I $AXFR
+is not set,
+.B axfrdns
+allows zone transfers for all zones
+available in 
+.IR data.cdb .
+
+.B axfrdns
+aborts
+if it runs out of memory,
+or has trouble reading 
+.IR data.cdb ,
+or receives a request larger than 512 bytes,
+or receives a truncated request,
+or receives a zone-transfer request disallowed by 
+.IR $AXFR ,
+or receives a request not answered by 
+.IR data.cdb ,
+or waits 60 seconds with nothing happening.
+
+.SH Further notes on zone transfers
+
+.B axfrdns
+provides every record it can find inside the target domain.
+This may include records in child zones.
+Some of these records (such as glue inside a child zone) are essential;
+others are not.
+It is up to the client to decide which out-of-zone records to keep.
+
+.B axfrdns
+does not provide glue records outside the target domain.
+
+The zone-transfer protocol does not support timestamps.
+If a record is scheduled to be created in the future,
+.B axfrdns
+does not send it;
+after the starting time,
+the zone-transfer client will continue claiming that the record doesn't exist,
+until it contacts 
+.B axfrdns
+again.
+Similarly, if a record is scheduled to die in the future,
+.B axfrdns
+sends it (with a 2-second TTL);
+after the ending time,
+the zone-transfer client will continue providing the old record,
+until it contacts 
+.B axfrdns
+again.
+
+Zone-transfer clients rely on zone serial numbers
+changing for every zone modification.
+
+.BR tinydns-data (8)
+uses the modification time of the 
+.I data
+file
+as its serial number for all zones.
+Do not make more than one modification per second.
+
+BIND's zone-transfer client, 
+.BR named-xfer ,
+converts zone-transfer data to zone-file format.
+Beware that zone-file format has no generic mechanism
+to express records of arbitrary types;
+
+.B named-xfer
+chokes
+if it does not recognize a record type used in 
+.IR data.cdb .
+
+.SH SEE ALSO
+axfrdns-conf(8),
+tinydns-data(8),
+tcpserver(1)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/dnscache-conf.8 b/debian/djbdns-man/dnscache-conf.8
new file mode 100644 (file)
index 0000000..ac87da9
--- /dev/null
@@ -0,0 +1,140 @@
+.TH dnscache-conf 8
+
+.SH NAME
+dnscache-conf \- sets up a DNS cache service.
+
+.SH SYNOPSIS
+.B dnscache-conf 
+.I acct
+.I logacct
+.I D
+[
+.I ip
+]
+
+.SH DESCRIPTION
+This is a reference page.
+For tutorial information, see the instructions for
+.br
+.B workstations
+(http://cr.yp.to/djbdns/run-cache.html),
+.br
+.B home computers
+(http://cr.yp.to/djbdns/run-cache-home.html),
+.br
+.B external caches
+(http://cr.yp.to/djbdns/run-cache-x.html),
+or
+.br
+.B upgrading from BIND
+(http://cr.yp.to/djbdns/run-cache-bind-1.html).
+
+.B dnscache-conf
+creates a service directory 
+.I D
+that runs
+.BR dnscache (8).
+The name 
+.I D
+must start with a slash
+and must not contain any special characters.
+Normally 
+.I D
+is 
+.IR /etc/dnscache .
+
+You can run the service under
+.BR svscan (8)
+by using the
+.BR update-service (8)
+program on Debian GNU/Linux
+
+update-service --add
+.I D
+
+or by creating a symbolic link in the
+.BR svscan (8)
+directory (normally /service or /etc/service), e.g.:
+
+ln -s 
+.I D
+/service
+
+The service will start within five seconds,
+and will be restarted upon reboot.
+You can use
+.BR svc (8)
+to control the service.
+
+.B dnscache-conf
+arranges for 
+.BR dnscache (8)
+to chroot to 
+.IR D /root
+and to run under the uid and gid of 
+.IR acct .
+The name
+.I acct
+must not contain any special characters.
+
+.B dnscache-conf
+arranges for 
+.BR dnscache (8)
+to listen for UDP packets and TCP connections on port 53 of 
+.IR ip .
+
+.I ip
+is optional;
+if it is not supplied,
+.B dnscache-conf
+arranges for 
+.BR dnscache (8)
+to listen on 127.0.0.1.
+
+.B dnscache-conf
+creates 
+.IR D /root/ip/127.0.0.1
+so that 
+.BR dnscache (8)
+will accept queries from 127.0.0.1.
+
+.B dnscache-conf
+puts 128 bytes of not-particularly-secret data
+into 
+.IR D /seed
+and arranges for 
+.BR dnscache (8)
+to pass 
+.IR D /seed
+to 
+.BR dns_random_init (3).
+If your system has a good source of random data,
+you can replace 
+.IR D /seed
+with 128 bytes of data from that source.
+
+.B dnscache-conf
+creates an automatically rotated log directory in
+.IR D /log/main.
+The logs are owned by 
+.IR logacct .
+The corresponding 
+.BR multilog (8)
+processes run under the uid and gid of 
+.IR logacct .
+The name 
+.I logacct
+must not contain any special characters.
+
+.SH SEE ALSO
+dnscache(8),
+svscan(8),
+svc(8),
+multilog(8),
+axfrdns-conf(8),
+rbldns-conf(8),
+tinydns-conf(8),
+walldns-conf(8),
+update-service(8)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/dnscache.8 b/debian/djbdns-man/dnscache.8
new file mode 100644 (file)
index 0000000..54fd357
--- /dev/null
@@ -0,0 +1,320 @@
+.TH dnscache 8
+
+.SH NAME
+dnscache \- a DNS cache.
+
+.SH DESCRIPTION
+This is a reference page.
+For tutorial information, see the instructions for
+.br
+.B workstations
+(http://cr.yp.to/djbdns/run-cache.html),
+.br
+.B home computers
+(http://cr.yp.to/djbdns/run-cache-home.html),
+.br
+.B external caches
+(http://cr.yp.to/djbdns/run-cache-x.html),
+or
+.br
+.B upgrading from BIND
+(http://cr.yp.to/djbdns/run-cache-bind-1.html).
+
+.B dnscache
+accepts recursive DNS queries
+from local clients such as web browsers and mail transfer agents.
+It collects responses from remote DNS servers.
+It caches the responses to save time later.
+
+.SH Configuration
+Normally 
+.B dnscache
+is set up by the
+.BR dnscache-conf (8)
+program.
+
+.B dnscache
+runs chrooted in the directory
+specified by the 
+.I $ROOT
+environment variable,
+under the uid and gid
+specified by the 
+.I $UID
+and 
+.I $GID
+environment variables.
+
+.B dnscache
+listens for incoming UDP packets and TCP connections
+addressed to port 53 of 
+.IR $IP .
+Typically 
+.I $IP
+is 
+.IR 127.0.0.1 ,
+but it can also be an externally accessible IP address.
+
+.B dnscache
+accepts a packet or connection
+from IP address 
+.I 1.2.3.4
+if it sees a file named 
+.I ip/1.2.3.4
+or 
+.I ip/1.2.3
+or 
+.I ip/1.2
+or 
+.IR ip/1 .
+
+.B dnscache
+sends outgoing packets from high ports of 
+.IR $IPSEND .
+Typically 
+.I $IPSEND
+is 
+.IR 0.0.0.0 ,
+meaning the machine's primary IP address.
+
+.B dnscache
+reads a seed, up to 128 bytes,
+from standard input,
+and passes the seed to
+dns_random_init.
+
+.B dnscache
+reads a list of dotted-decimal root server IP addresses,
+one address per line,
+from 
+.IR servers/@ .
+It also scans the 
+.I servers
+directory
+for server IP addresses for other domains.
+If there are addresses listed in 
+.IR servers/moon.af.mil ,
+for example,
+then 
+.B dnscache
+will send queries for 
+.I anything.moon.af.mil
+to those addresses,
+and will not cache records for 
+.I anything.moon.af.mil
+from outside servers such as the root servers.
+
+Versions 1.03 and above:
+If
+.I $FORWARDONLY
+is set,
+.B dnscache
+treats
+.I servers/@
+as a list of IP addresses
+for other caches, not root servers.
+It forwards queries to those caches the same way that a client does,
+rather than contacting a chain of servers according to NS records.
+
+.SH Memory use
+
+.B dnscache
+uses a fixed-size table, under 256K,
+to keep track of as many as 200 simultaneous UDP queries
+and 20 simultaneous TCP connections.
+It also dynamically allocates memory,
+usually just a few bytes but occasionally much more,
+for each active query.
+If it runs out of memory handling a query, it discards that query.
+
+.B dnscache
+asks the operating system to reserve a 128K buffer
+for bursts of incoming UDP queries.
+In versions 1.03 and above,
+if a new UDP query arrives
+when
+.B dnscache
+is already handling 200 simultaneous UDP queries,
+.B dnscache
+drops the oldest query.
+If a new TCP connection arrives
+when
+.B dnscache
+is already handling 20 simultaneous TCP connections,
+.B dnscache
+drops the oldest connection.
+
+.B dnscache
+uses a fixed-size cache,
+as controlled by the 
+.I $CACHESIZE
+environment variable.
+Roughly 5% of the cache is used for a hash table.
+The rest is used for cache entries
+(including 8-byte Y2038-compliant expiration times):
+
+.TP
+o
+A sets.
+22 bytes plus 4 bytes per address plus the length of the owner name.
+.TP
+o
+NS sets or PTR sets or CNAME sets.
+22 bytes plus the length of the owner name and all the data names.
+.TP
+o
+MX sets.
+22 bytes plus 2 bytes per MX plus the length of all the names.
+.TP
+o
+Other record sets.
+22 bytes plus 2 bytes per record
+plus the length of all the data strings
+plus the length of the owner name.
+.TP
+o
+Nonexistent domain or server failure.
+22 bytes plus the length of the owner name.
+
+.P
+Sets larger than 8192 bytes are not cached.
+
+.B dnscache
+does not exit when it runs out of space in its cache;
+it simply removes the oldest entries to make more space.
+
+.SH Resolution and caching policies
+
+.B dnscache
+relies on a configured list of root name servers.
+In contrast, BIND starts from a ``hint file'' listing name servers,
+and asks those name servers where the root name servers are.
+
+.B dnscache
+does not cache (or pass along) records outside the server's bailiwick;
+those records could be poisoned.
+Records for 
+.IR foo.dom ,
+for example,
+are accepted only from the root servers,
+the 
+.I dom
+servers, and the 
+.I foo.dom
+servers.
+
+.B dnscache
+does not bypass its cache
+to obtain glue from the additional section of a response.
+In particular, it will not use glue outside the server's bailiwick,
+or glue with TTL 0,
+or glue that violates other caching policies.
+
+.B dnscache
+caches records for at most a week.
+It interprets TTLs above 2147483647 as 0.
+
+.B dnscache
+does not cache SOA records.
+However, it does use SOA TTLs to determine cache times (up to an hour)
+for zero-record responses and nonexistent domains.
+
+.SH Responses to DNS clients
+
+.BR dnscache 's
+responses are generally much smaller than BIND's responses.
+They do not include
+authority records
+(NS records of the source name servers
+and SOA records for negative answers)
+or additional records
+(A records relevant to NS or MX records).
+When the answer section is truncated by UDP length limits,
+it is eliminated entirely.
+
+.B dnscache
+tries to prevent local users from snooping on other local users.
+It discards non-recursive queries;
+it discards inverse queries;
+and it discards zone-transfer requests.
+If
+.I $HIDETTL
+is set,
+.B dnscache
+always uses a TTL of 0 in its responses.
+In versions before 1.03,
+.B dnscache
+always uses a TTL of 0 in its responses.
+
+According to RFC 1035,
+the AA bit ``specifies that the responding name server 
+is an authority for the domain name in question section.''
+
+.B dnscache
+is not an authority for any domain names.
+
+.B dnscache
+never sets the AA bit
+(except in NXDOMAIN responses, as required by RFC 2308,
+to work around a common client bug).
+In contrast, BIND often sets AA for positive responses
+even when it is not an authority for the domain name.
+(This appears to have been fixed in BIND 9.)
+
+.SH Repeated IP addresses
+If a server
+sends
+.B dnscache
+a repeated IP address,
+.B dnscache
+passes the repeated IP address along to the client.
+The server's behavior violates RFC 2181, section 5.5,
+but there are reasonable uses of repeated IP addresses for load balancing,
+so
+.B dnscache
+does not go out of its way to remove repetitions when they occur.
+
+A widespread BIND server bug (apparently fixed in BIND 9.1)
+can unintentionally produce repeated IP addresses.
+Here is an example from one of the BIND company's servers (now fixed):
+
+  % dnsq a ns-ext.vix.com ns-ext.vix.com
+  1 ns-ext.vix.com:
+  117 bytes, 1+1+2+2 records, response, authoritative, noerror
+  query: 1 ns-ext.vix.com
+  answer: ns-ext.vix.com 3600 A 204.152.184.64
+  authority: vix.com 3600 NS ns-ext.vix.com
+  authority: vix.com 3600 NS ns1.gnac.com
+  additional: ns-ext.vix.com 3600 A 204.152.184.64
+  additional: ns1.gnac.com 130768 A 209.182.195.77
+
+This BIND bug is the most common reason
+for users to see repeated IP addresses from
+.BR dnscache .
+
+.SH Special names
+
+.B dnscache
+handles 
+.I localhost
+internally,
+giving it an A record of 127.0.0.1.
+
+.B dnscache
+handles 
+.I 1.0.0.127.in-addr.arpa
+internally,
+giving it a PTR record of
+.IR localhost .
+
+.B dnscache
+handles dotted-decimal domain names internally,
+giving (e.g.) the domain name 
+.I 192.48.96.2
+an A record of 
+.IR 192.48.96.2 .
+
+.SH SEE ALSO
+dnscache-conf(8)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/dnsfilter.1 b/debian/djbdns-man/dnsfilter.1
new file mode 100644 (file)
index 0000000..f3783f5
--- /dev/null
@@ -0,0 +1,67 @@
+.TH dnsfilter 1
+
+.SH NAME
+dnsfilter \- reverse-resolves IP addresses, converting them to host names.
+
+.SH SYNOPSIS
+.B dnsfilter 
+[
+.I opts
+]
+
+.SH DESCRIPTION
+.B dnsfilter
+reads a series of lines from stdin,
+converts an IP address to a host name at the beginning of each line,
+and prints the results to stdout.
+
+If a line does not begin with an IP address,
+.B dnsfilter
+leaves the line alone.
+If an IP address does not have a host name listed in DNS,
+.B dnsfilter
+leaves the line alone.
+If an IP address has a host name listed in DNS,
+.B dnsfilter
+inserts an equals sign and the host name
+before the first space or tab in the line.
+If a DNS lookup fails temporarily,
+.B dnsfilter
+inserts a colon and a dash-separated error message
+before the first space or tab in the line.
+
+While 
+.B dnsfilter
+is looking up an address in DNS,
+it reads ahead in the input and looks for more addresses to look up in parallel.
+
+.SH OPTIONS
+.I opts
+is a series of getopt-style options:
+
+.TP
+.B \-c \fIn
+Do at most 
+.I n
+DNS queries in parallel.
+Default: 10.
+
+.TP
+.B -l \fIn
+Read ahead at most 
+.I n
+lines.
+Default: 1000.
+
+.SH SEE ALSO
+dnsip(1),
+dnsipq(1),
+dnsname(1),
+dnsmx(1),
+dnstxt(1),
+dnsqr(1),
+dnsq(1),
+dnstrace(1)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/dnsip.1 b/debian/djbdns-man/dnsip.1
new file mode 100644 (file)
index 0000000..bc91e8d
--- /dev/null
@@ -0,0 +1,48 @@
+.TH dnsip 1
+
+.SH NAME
+dnsip \- lookup IP addresses
+
+.SH SYNOPSIS
+dnsip 
+[
+.I fqdn
+]
+
+.SH DESCRIPTION
+.B dnsip
+resolves
+.I fqdn
+and prints the IP addresses of
+.I fqdn
+on a single line.
+If 
+.I fqdn
+does not exist, 
+.B dnsip
+prints a blank line.
+You can list several  
+.IR fqdn s;
+.B dnsip
+prints each result on a separate line.
+
+Normally 
+.B dnsip
+exits 0.
+If 
+.B dnsip
+encounters a temporary problem
+that prevents it from determining the list of IP addresses,
+it prints an error message and exits 111.
+The same comments apply to the other programs described here.
+
+.SH SEE ALSO
+dnsipq(1),
+dnsname(1),
+dnsmx(1),
+dnstxt(1),
+dnsqr(1),
+dnsq(1),
+dnstrace(1)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/dnsipq.1 b/debian/djbdns-man/dnsipq.1
new file mode 100644 (file)
index 0000000..be7d320
--- /dev/null
@@ -0,0 +1,47 @@
+.TH dnsipq 1
+
+.SH NAME
+dnsipq \- dns lookup tool
+
+.SH SYNOPSIS
+.B dnsipq 
+[
+.I udn
+]
+
+.SH DESCRIPTION
+.B dnsipq
+feeds the name  
+.I udn
+through
+.BR qualification (5).
+It prints the fully qualified domain name and IP addresses
+on a single line.
+If the fully qualified domain name does not exist,
+.B dnsipq
+prints no addresses.
+You can list several  
+.IR udn s;
+.B dnsipq
+prints each result on a separate line.
+
+Normally 
+.B dnsipq
+exits 0.
+If 
+.B dnsipq
+encounters a temporary problem
+that prevents it from determining the list of IP addresses,
+it prints an error message and exits 111.
+
+.SH SEE ALSO
+qualification(5),
+dnsip(1),
+dnsname(1),
+dnsmx(1),
+dnstxt(1),
+dnsqr(1),
+dnsq(1),
+dnstrace(1)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/dnsmx.1 b/debian/djbdns-man/dnsmx.1
new file mode 100644 (file)
index 0000000..a9197dd
--- /dev/null
@@ -0,0 +1,38 @@
+.TH dnsmx 1
+
+.SH NAME
+dnsmx \- prints the MX records of fqdn
+
+.SH SYNOPSIS
+.B dnsmx
+.I fqdn
+
+.SH DESCRIPTION
+
+.B dnsmx
+prints the MX records of
+.IR fqdn .
+If there are no MX records,
+.B dnsmx
+prints an artificial MX record,
+simulating the behavior of MTAs.
+
+Normally 
+.B dnsmx
+exits 0.
+If 
+.B dnsmx
+encounters a temporary problem
+that prevents it from determining the list of MX records,
+it prints an error message and exits 111.
+
+.SH SEE ALSO
+dnsip(1),
+dnsname(1),
+dnsipq(1),
+dnstxt(1),
+dnsqr(1),
+dnsq(1),
+dnstrace(1)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/dnsname.1 b/debian/djbdns-man/dnsname.1
new file mode 100644 (file)
index 0000000..06a1ff1
--- /dev/null
@@ -0,0 +1,46 @@
+.TH dnsname 1
+
+.SH NAME
+dnsname \- does a reverse lookup for the IP address
+
+.SH SYNOPSIS
+.B dnsname 
+.I a.b.c.d
+
+.SH DESCRIPTION
+.B dnsname
+does a reverse lookup for the IP address
+.IR a.b.c.d .
+It prints the first domain name for that address.
+If no domain names are listed in DNS,
+.B dnsname
+prints a blank line.
+You can list several IP addresses;
+.B dnsname
+prints each result on a separate line.
+
+There is also a
+.BR dnsfilter (1)
+program
+that reads IP addresses from its input
+and performs many reverse lookups in parallel.
+
+Normally 
+.B dnsname
+exits 0.
+If 
+.B dnsname
+encounters a temporary problem
+that prevents it from determining the domain name,
+it prints an error message and exits 111.
+
+.SH SEE ALSO
+dnsip(1),
+dnsipq(1),
+dnsmx(1),
+dnstxt(1),
+dnsqr(1),
+dnsq(1),
+dnstrace(1)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/dnsq.1 b/debian/djbdns-man/dnsq.1
new file mode 100644 (file)
index 0000000..6f65fe6
--- /dev/null
@@ -0,0 +1,33 @@
+.TH dnsq 1
+
+.SH NAME
+dnsq \- sends a non-recursive DNS query to DNS server
+
+.SH SYNOPSIS
+.B dnsq 
+.I t
+.I fqdn
+.I s
+
+.SH DESCRIPTION
+.B dnsq
+sends a non-recursive DNS query
+to DNS server 
+.I s
+for records of type 
+.I t
+under the domain name 
+.IR fqdn .
+It prints the results in a human-readable format.
+
+.SH SEE ALSO
+dnsip(1),
+dnsipq(1),
+dnsmx(1),
+dnstxt(1),
+dnsqr(1),
+dnsname(1),
+dnstrace(1),
+tinydns-get(1)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/dnsqr.1 b/debian/djbdns-man/dnsqr.1
new file mode 100644 (file)
index 0000000..7a61185
--- /dev/null
@@ -0,0 +1,61 @@
+.TH dnsqr 1
+
+.SH NAME
+dnsqr \- asks for records of type 
+.I t
+under the domain name 
+.I fqdn
+
+.SH SYNOPSIS
+.B dnsqr 
+.I t
+.I fqdn
+
+.SH DESCRIPTION
+.B dnsqr
+asks for records of type 
+.I t
+under the domain name 
+.IR fqdn .
+It prints the results in a human-readable format,
+more compact than the 
+.I dig
+output format.
+
+.I t
+may be a name or number.
+Currently recognized names:
+.IR any ,
+.IR a ,
+.IR ns ,
+.IR mx ,
+.IR ptr ,
+.IR txt ,
+.IR cname ,
+.IR soa ,
+.IR hinfo ,
+.IR rp ,
+.IR sig ,
+.IR key ,
+.IR aaaa ,
+.IR axfr .
+Note that, if you want to
+perform a zone transfer, you should use
+.BR axfr-get (8),
+not
+.B dnsqr axfr\fR.
+
+.B dnsqr
+is available in djbdns 1.01 and above.
+
+.SH SEE ALSO
+dnsip(1),
+dnsipq(1),
+dnsmx(1),
+dnstxt(1),
+dnsname(1),
+dnsq(1),
+dnstrace(1),
+tinydns-get(1)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/dnstrace.1 b/debian/djbdns-man/dnstrace.1
new file mode 100644 (file)
index 0000000..fb3c1e4
--- /dev/null
@@ -0,0 +1,78 @@
+.TH dnstrace 1
+
+.SH NAME
+dnstrace \- dns lookup tool
+
+.SH SYNOPSIS
+.B dnstrace 
+.I t
+.I fqdn
+.I r
+
+.SH DESCRIPTION
+.B dnstrace
+searches for all DNS servers
+that can affect the resolution of records of type  
+.I t
+under the domain name 
+.IR fqdn ,
+starting from the root server
+.IR r .
+You can list more than one root server.
+
+.B dnstrace
+uses the standard DNS resolution algorithm,
+but follows all possible paths in the algorithm.
+It prints all responses it receives from DNS servers;
+it also prints warnings about slow servers, dead servers,
+misdelegated (``lame'') servers, and misformatted packets.
+.B dnstrace
+is similar in spirit to DOC and dnswalk
+but is much more effective than those tools at debugging resolution problems.
+
+In versions 1.03 and above:
+You can pipe
+.B dnstrace
+through
+.BR dnstracesort (1)
+for human-friendly output.
+.B dnstrace
+can take a long time to run,
+so standard procedure is to save its output in a file:
+
+  dnstrace any www.aol.com a.root-servers.net > AOL &
+
+Then you can run
+.BR dnstracesort (1)
+to see the results so far:
+
+  dnstracesort < AOL | less
+
+The
+.BR dnstracesort (1)
+output uses
+.I ul
+codes
+for boldface and underline;
+these codes are displayed properly by
+.BR less (1).
+
+Beware that, as of January 2001,
+.B dnstrace
+produces more than 5 megabytes of output
+for the complete trace of cr.yp.to
+starting from all the root servers.
+It ends up sending more than 6000 queries to more than 200 different servers.
+
+.SH SEE ALSO
+dnsip(1),
+dnsipq(1),
+dnsmx(1),
+dnstxt(1),
+dnsqr(1),
+dnsq(1),
+dnsname(1),
+less(1),
+tinydns-get(1)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/dnstracesort.1 b/debian/djbdns-man/dnstracesort.1
new file mode 100644 (file)
index 0000000..38a97b2
--- /dev/null
@@ -0,0 +1 @@
+.so man1/dnstrace.1
diff --git a/debian/djbdns-man/dnstxt.1 b/debian/djbdns-man/dnstxt.1
new file mode 100644 (file)
index 0000000..d70865b
--- /dev/null
@@ -0,0 +1,37 @@
+.TH dnstxt 1
+
+.SH NAME
+dnstxt \- prints the TXT record of fqdn
+
+.SH SYNOPSIS
+.B dnstxt
+.I fqdn
+
+.SH DESCRIPTION
+.B dnstxt
+prints the TXT record of  
+.I fqdn
+on a single line.
+If there is no TXT record,
+.B dnstxt
+prints a blank line.
+
+Normally 
+.B dnstxt
+exits 0.
+If 
+.B dnstxt
+encounters a temporary problem
+that prevents it from determining the TXT record,
+it prints an error message and exits 111.
+
+.SH SEE ALSO
+dnsip(1),
+dnsname(1),
+dnsmx(1),
+dnsipq(1),
+dnsqr(1),
+dnsq(1),
+dnstrace(1)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/qualification.5 b/debian/djbdns-man/qualification.5
new file mode 100644 (file)
index 0000000..fea174b
--- /dev/null
@@ -0,0 +1,228 @@
+.TH qualification 5
+
+.SH NAME
+qualification \- User's guide to name qualification
+
+.SH OVERVIEW
+.B Qualification
+means conversion
+of a short host name that you type, such as 
+.IR cheetah ,
+into a complete (``fully qualified'') domain name,
+such as 
+.IR cheetah.heaven.af.mil .
+
+This page explains the djbdns qualification procedure.
+These rules are followed by the
+.I dns_ip4_qualify
+library routine in djbdns,
+and by programs that use the
+.BR dns_ip4_qualify (3)
+routine.
+
+.SH Rewriting instructions
+Normally the djbdns  qualification procedure
+follows instructions listed in 
+.IR /etc/dnsrewrite ,
+a file created by your system administrator.
+You can override
+.I /etc/dnsrewrite
+by creating your own file
+and setting the
+.I $DNSREWRITEFILE
+environment variable
+to the name of that file.
+
+Sample instructions:
+
+  # anything.local -> me
+  -.local:me
+  # me -> 127.0.0.1
+  =me:127.0.0.1
+  # any.name.a -> any.name.af.mil
+  *.a:.af.mil
+  # any-name-without-dots -> any-name-without-dots.heaven.af.mil
+  ?:.heaven.af.mil
+  # remove trailing dot
+  *.:
+
+Instructions are followed in order, each at most once.
+There are four types of instructions:
+.TP
+.RI = post\fR:\fInew\fR
+means that the host name 
+.I post
+is replaced by 
+.IR new .
+.TP
+.RI * post\fR:\fInew\fR
+means that any name of the form 
+.I prepost
+is replaced by 
+.IR prenew .
+.TP
+.RI ? post\fR:\fInew\fR
+means that any name of the form 
+.IR prepost ,
+where 
+.I pre
+does not contain dots or brackets,
+is replaced by 
+.IR prenew .
+.TP
+.RI - post\fR:\fInew\fR
+means that any name of the form 
+.I prepost
+is replaced by 
+.IR new .
+
+.SH Searching
+
+The djbdns qualification procedure
+can search through DNS for several possible qualifications of a name.
+For example, the name
+
+cheetah+.heaven.af.mil+.af.mil
+
+is qualified as 
+.I cheetah.heaven.af.mil
+if that name has IP addresses listed in DNS,
+or 
+.I cheetah.af.mil
+otherwise.
+
+In general,
+.IR x +\fIy1\fR+\fIy2\fR+\fIy3\fR
+is qualified as 
+.I xy1
+if 
+.I xy1
+has IP addresses listed in DNS;
+otherwise, as 
+.I xy2
+if 
+.I xy2
+has IP addresses listed in DNS;
+otherwise, as 
+.IR xy3 .
+You can list any number of +'s.
+
+Searching is applied after rewriting,
+so you can use a rewriting instruction such as
+
+?:+.heaven.af.mil+.af.mil
+
+to have
+.I lion
+qualified as 
+.I lion.heaven.af.mil
+or 
+.IR lion.af.mil ,
+and
+.I tiger
+qualified as 
+.I tiger.heaven.af.mil
+or 
+.IR tiger.af.mil ,
+and so on.
+
+Searching is generally not a recommended feature.
+If you rely on 
+.I gw
+being qualified as 
+.IR gw.af.mil ,
+and someone suddenly adds a new 
+.IR gw.heaven.af.mil ,
+you'll end up talking to the wrong host.
+It's better to rely on syntactic rules that you control.
+
+.SH Compatibility mechanisms
+If the rewriting-instructions file does not exist,
+the djbdns qualification procedure looks for a local domain name in three
+places:
+.TP
+1.
+the 
+.I $LOCALDOMAIN
+environment variable, if it is set; or
+.TP
+2.
+the first 
+.I domain
+or 
+.I search
+line
+in 
+.IR /etc/resolv.conf ,
+if 
+.I /etc/resolv.conf
+exists and has such a line; or
+.TP
+3.
+everything after the first dot in the system's hostname.
+.P
+It then creates rewriting instructions of the form
+
+  ?:.\fIdomain\fR
+  *.:
+
+so that 
+.RI . domain
+is added to any name without dots or brackets.
+
+You can specify searching in 
+.I $LOCALDOMAIN
+by using several domain names separated by spaces.
+Your system administrator can specify searching in 
+.I /etc/resolv.conf
+by putting several domains on a 
+.I search
+line.
+
+.SH Compatibility notes
+Different DNS client programs use different qualification procedures.
+Two major differences between the djbdns qualification procedure
+and other qualification procedures:
+.IP
+Most programs use only
+.IR /etc/resolv.conf .
+They don't know anything about
+.I /etc/dnsrewrite
+and
+.IR $DNSREWRITEFILE .
+.IP
+Most long-running programs
+don't notice changes in
+.IR /etc/resolv.conf ;
+they read
+.I /etc/resolv.conf
+when they start,
+and they don't reread it until they are restarted.
+In contrast, the djbdns qualification procedure
+checks for changes every 10 minutes or 10000 uses.
+.P
+Two minor differences:
+.IP
+Some programs interpret a
+.I domain
+line in
+.I /etc/resolv.conf
+as specifying a search list consisting of various suffixes of the domain.
+.IP
+Many programs will search the local domain
+for names 
+.I with
+dots.
+.P
+If you want the local domain searched for names with dots,
+you can set it up with rewriting:
+
+  # aol.com -> aol.com or aol.com.heaven.af.mil
+  *:++.heaven.af.mil
+  # but skip directly to heaven.af.mil if no dots
+  ?++.heaven.af.mil:.heaven.af.mil
+
+.SH SEE ALSO
+dnsipq(1)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/rbldns-conf.8 b/debian/djbdns-man/rbldns-conf.8
new file mode 100644 (file)
index 0000000..aef227b
--- /dev/null
@@ -0,0 +1,113 @@
+.TH rbldns-conf 8
+
+.SH NAME
+rbldns-conf \- sets up an IP-address-listing DNS service.
+
+.SH SYNOPSIS
+.B rbldns-conf 
+.I acct
+.I logacct
+.I D
+.I ip
+.I base
+
+.SH DESCRIPTION
+.B rbldns-conf
+creates a service directory 
+.I D
+that runs
+.BR rbldns (8).
+The name
+.I D
+must start with a slash
+and must not contain any special characters.
+Normally 
+.I D
+is 
+.IR /etc/rbldns .
+
+You can run the service under
+.BR svscan (8)
+by using the
+.BR update-service (8)
+program on Debian GNU/Linux
+
+update-service --add
+.I D
+
+or by creating a symbolic link in the
+.BR svscan (8)
+directory (normally /service or /etc/service), e.g.:
+
+ln -s 
+.I D
+/service
+
+The service will start within five seconds,
+and will be restarted upon reboot.
+You can use
+.BR svc (8)
+to control the service.
+
+.B rbldns-conf
+arranges for 
+.BR rbldns (8)
+to chroot to 
+.IR D /root
+and to run under the uid and gid of
+.IR acct .
+The name 
+.I acct
+must not contain any special characters.
+
+.B rbldns-conf
+creates 
+.IR D /root/Makefile
+to run 
+.BR rbldns-data (8)
+upon request.
+
+.B rbldns-conf
+arranges for 
+.BR rbldns (8)
+to listen for UDP packets on port 53 of 
+.IR ip ,
+and to send outgoing packets from 
+.IR ip .
+
+.B rbldns-conf
+arranges for 
+.BR rbldns (8)
+to answer queries under the 
+.I base
+domain.
+The name
+.I base
+must not contain any special characters.
+
+.B rbldns-conf
+creates an automatically rotated log directory in
+.IR D /log/main.
+The logs are owned by 
+.IR logacct .
+The corresponding 
+.BR multilog (8)
+processes run under the uid and gid of 
+.IR logacct .
+The name
+.I logacct
+must not contain any special characters.
+
+.SH SEE ALSO
+rbldns(8),
+rbldns-data(8)
+svscan(8),
+svc(8),
+multilog(8),
+axfrdns-conf(8),
+dnscache-conf(8),
+tinydns-conf(8),
+walldns-conf(8),
+update-service(8)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/rbldns-data.8 b/debian/djbdns-man/rbldns-data.8
new file mode 100644 (file)
index 0000000..336cf2e
--- /dev/null
@@ -0,0 +1,95 @@
+.TH rbldns-data 8
+
+.SH NAME
+rbldns-data \- data tool for rbldns
+
+.SH DESCRIPTION
+.B rbldns-data
+reads an IP address list
+from a file named 
+.I data
+in the current directory.
+It creates 
+.I data.cdb
+in a binary format designed for
+fast access by 
+.BR rbldns (8).
+It may also create some other files
+with names beginning with 
+.IR data .
+
+.B rbldns-data
+updates 
+.I data.cdb
+atomically,
+so you can use it safely while 
+.BR rbldns (8)
+is running.
+If anything goes wrong with the creation of 
+.IR data.cdb ,
+.B rbldns-data
+stops and leaves the old 
+.I data.cdb
+in place.
+
+.SH Data format
+
+.I ip
+
+The IP address 
+.I ip
+is on the list.
+
+.I ip\fR/\fIn
+
+All IP addresses that share the first 
+.I n
+bits
+of the IP address 
+.I ip
+are on the list.
+For example, 
+.I 1.2.3.0/24
+means all 
+.I 1.2.3.*
+addresses.
+.I n
+must be at least 8,
+and all bits past the 
+.IR n th
+in 
+.I ip
+must be 0.
+
+.RI : a\fR:\fItxt\fR
+
+DNS queries for addresses on the list
+will receive an A record of 
+.I a
+and a TXT record of 
+.IR txt .
+Typically 
+.I a
+is 
+.I 127.0.0.2
+and 
+.I txt
+is a pointer to a web page about the list.
+
+If 
+.I txt
+ends with 
+.IR $ ,
+.BR rbldns (8)
+replaces the 
+.I $
+with the IP address.
+
+.RI # comment
+
+Comment line. The line is ignored.
+
+.SH SEE ALSO
+rbldns(8)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/rbldns.8 b/debian/djbdns-man/rbldns.8
new file mode 100644 (file)
index 0000000..081028a
--- /dev/null
@@ -0,0 +1,68 @@
+.TH rbldns 8
+
+.SH NAME
+rbldns \- an IP-address-listing DNS server
+
+.SH DESCRIPTION
+.B rbldns
+is an IP-address-listing DNS server.
+It accepts iterative DNS queries
+from hosts around the Internet asking about various IP addresses.
+It provides responses showing whether the addresses
+are on a locally configured list,
+such as RBL or DUL.
+
+.SH Configuration
+Normally 
+.B rbldns
+is set up by the
+.BR rbldns-conf (8)
+program.
+
+.B rbldns
+runs chrooted in the directory
+specified by the 
+.I $ROOT
+environment variable,
+under the uid and gid
+specified by the 
+.I $UID
+and 
+.I $GID
+environment variables.
+
+.B rbldns
+listens for incoming UDP packets
+addressed to port 53 of 
+.IR $IP .
+It does not listen for TCP queries.
+
+.B rbldns
+handles domains of the form
+.IR d.c.b.a\fR.\fIbase
+where 
+.I a.b.c.d
+is the IP address in question
+and 
+.I base
+is given by the 
+.I $BASE
+environment variable.
+
+.B rbldns
+rejects
+inverse queries, non-Internet-class queries, truncated packets,
+packets that contain anything other than a single query,
+query types other than A, TXT, or *,
+and queries for domains outside 
+.IR $BASE .
+It looks up other queries inside 
+.IR data.cdb ,
+a binary file created by
+.BR rbldns-data (8).
+
+.SH SEE ALSO
+rbldns-conf(8),
+rbldns-data(8)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/tinydns-conf.8 b/debian/djbdns-man/tinydns-conf.8
new file mode 100644 (file)
index 0000000..9feebee
--- /dev/null
@@ -0,0 +1,107 @@
+.TH tinydns-conf 8
+
+.SH NAME
+tinydns-conf \- sets up a DNS publication service.
+
+.SH SYNOPSIS
+.B tinydns-conf
+.I acct
+.I logacct
+.I D
+.I ip
+
+.SH DESCRIPTION
+This is a reference page.
+For tutorial information, see the instructions for
+.br
+.B running a DNS server
+(http://cr.yp.to/djbdns/run-server.html).
+
+.B tinydns-conf
+creates a service directory 
+.I D
+that runs
+.BR tinydns (8).
+The name 
+.I D
+must start with a slash
+and must not contain any special characters.
+Normally 
+.I D
+is 
+.IR /etc/tinydns .
+
+You can run the service under
+.BR svscan (8)
+by using the
+.BR update-service (8)
+program on Debian GNU/Linux
+
+update-service --add
+.I D
+
+or by creating a symbolic link in the
+.BR svscan (8)
+directory (normally /service or /etc/service), e.g.:
+
+ln -s 
+.I D
+/service
+
+The service will start within five seconds,
+and will be restarted upon reboot.
+You can use
+.BR svc (8)
+to control the service.
+
+.B tinydns-conf
+arranges for 
+.BR tinydns (8)
+to chroot to
+.IR D /root
+and to run under the uid and gid of
+.IR acct .
+The name
+.I acct
+must not contain any special characters.
+
+.B tinydns-conf
+creates
+.IR D /root/Makefile
+to run 
+.BR tinydns-data (8)
+upon request.
+
+.B tinydns-conf
+arranges for 
+.BR tinydns (8)
+to listen for UDP packets on port 53 of 
+.IR ip ,
+and to send outgoing packets from
+.IR ip .
+
+.B tinydns-conf
+creates an automatically rotated log directory in
+.IR D /log/main.
+The logs are owned by 
+.IR logacct .
+The corresponding 
+.IR multilog (8)
+processes run under the uid and gid of 
+.IR logacct .
+The name
+.I logacct
+must not contain any special characters.
+
+.SH SEE ALSO
+tinydns(8),
+svscan(8),
+svc(8),
+multilog(8),
+axfrdns-conf(8),
+rbldns-conf(8),
+dnscache-conf(8),
+walldns-conf(8),
+update-service(8)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/tinydns-data.8 b/debian/djbdns-man/tinydns-data.8
new file mode 100644 (file)
index 0000000..38416e0
--- /dev/null
@@ -0,0 +1,706 @@
+.TH tinydns-data 8
+
+.SH NAME
+tinydns-data \- data tool for tinydns
+
+.SH DESCRIPTION
+This is a reference page.
+For tutorial information, see the instructions for
+.br
+.B running a DNS server
+(http://cr.yp.to/djbdns/run-server.html).
+
+.B tinydns-data
+reads local DNS information
+from a file named 
+.I data
+in the current directory.
+It creates 
+.I data.cdb
+in a binary format designed for
+fast access by 
+.BR tinydns (8).
+It may also create some other files
+with names beginning with 
+.IR data .
+
+.B tinydns-data
+updates 
+.I data.cdb
+atomically,
+so you can use it safely while 
+.BR tinydns (8)
+is running.
+If anything goes wrong with the creation of 
+.IR data.cdb ,
+.B tinydns-data
+stops and leaves the old 
+.I data.cdb
+in place.
+
+.SH Data format
+The DNS information in 
+.I data
+is a series of lines.
+There are several types of lines, as shown below.
+
+Each line starts with a special character
+and continues with a series of colon-separated fields.
+In some cases the fields may be omitted;
+however, all colons must be included except at the end of the line.
+Spaces and tabs at the end of a line are ignored.
+Blank lines are ignored.
+
+Each line contains a
+.I ttl
+(``time to live'')
+specifying the number of seconds that the line's DNS records may be cached.
+Beware that cache times below 300 seconds
+will be treated as 300 by some clients,
+and NS cache times below 2 seconds can cause lookup failures.
+You may omit
+.IR ttl ;
+.B tinydns-data
+will use default cache times,
+carefully selected to work well in normal situations.
+
+You may include a timestamp on each line.
+If
+.I ttl
+is nonzero (or omitted),
+the timestamp is a starting time
+for the information in the line;
+the line will be ignored before that time.
+If 
+.I ttl
+is zero,
+the timestamp is an ending time (``time to die'')
+for the information in the line;
+.BR tinydns (8)
+dynamically adjusts 
+.I ttl
+so that the line's DNS records are not cached for more than a few seconds
+past the ending time.
+A timestamp is an
+external TAI64 timestamp,
+printed as 16 lowercase hexadecimal characters.
+For example, the lines
+
++www.heaven.af.mil:1.2.3.4:0:4000000038af1379
++www.heaven.af.mil:1.2.3.7::4000000038af1379
+
+specify that 
+.I www.heaven.af.mil
+will have address 
+.I 1.2.3.4
+until time 
+.I 4000000038af1379
+(2000-02-19 22:04:31 UTC)
+and will then switch to IP address 
+.IR 1.2.3.7 .
+
+For versions 1.04 and above:
+You may include a client location on each line.
+The line is ignored for clients outside that location.
+Client locations are specified by
+.B %
+lines:
+
+%\fIlo\fR:\fIipprefix\fR
+
+means that IP addresses starting with
+.I ipprefix
+are in location
+.IR lo .
+.I lo
+is a sequence of one or two ASCII letters.
+A client is in only one location;
+longer prefixes override shorter prefixes.
+For example,
+
+  %in:192.168
+  %ex
+  +jupiter.heaven.af.mil:192.168.1.2:::in
+  +jupiter.heaven.af.mil:1.2.3.4:::ex
+
+specifies that
+.I jupiter.heaven.af.mil
+has address
+.I 192.168.1.2
+for clients in the
+.I 192.168.*
+network
+and address
+.I 1.2.3.4
+for everyone else.
+
+.SH Common data lines
+
+.RI \. fqdn\fR:\fIip\fR:\fIx\fR:\fIttl\fR:\fItimestamp\fR:\fIlo\fR
+
+Name server for our domain 
+.IR fqdn .
+
+.B tinydns-data
+creates
+.IP
+an NS (``name server'') record
+showing 
+.IR x .ns.\fIfqdn\fR
+as a name server for
+.IR fqdn ;
+.P
+.IP
+an A (``address'') record showing
+.I ip
+as the IP address
+of
+.IR x\fR.ns.\fIfqdn ;
+and
+.P
+.IP
+an SOA (``start of authority'') record for 
+.I fqdn
+listing 
+.IR x\fR.ns.\fIfqdn
+as the primary name server
+and hostmaster@\fIfqdn\fR
+as the contact address.
+.P
+
+You may have several name servers for one domain,
+with a different 
+.I x
+for each server.
+
+.BR tinydns (8)
+will return only one SOA record per domain.
+
+If
+.I x
+contains a dot
+then 
+.B tinydns-data
+will use 
+.I x
+as the server name
+rather than 
+.IR x\fR.ns.\fIfqdn .
+This feature is provided only for compatibility reasons;
+names not ending with
+.I fqdn
+will force clients to contact parent servers
+much more often than they otherwise would,
+and will reduce the overall reliability of DNS.
+You should omit 
+.I ip
+if 
+.I x
+has IP addresses assigned elsewhere in 
+.IR data ;
+in this case,
+.B tinydns-data
+will omit the A record.
+.P
+Examples:
+
+  .panic.mil:1.8.7.55:a
+
+creates an NS record showing
+.I a.ns.panic.mil
+as a name server for
+.IR panic.mil ,
+an A record showing
+.I 1.8.7.55
+as the IP address of
+.IR a.ns.panic.mil ,
+and an SOA record for
+.IR panic.mil .
+
+  .panic.mil:1.8.7.56:dns2.panic.mil
+
+creates an NS record showing
+.I dns2.panic.mil
+as a name server for
+.IR panic.mil ,
+an A record showing
+.I 1.8.7.56
+as the IP address of
+.IR dns2.panic.mil ,
+and an SOA record for
+.IR panic.mil .
+
+  .panic.mil::a.ns.heaven.af.mil
+
+creates an NS record showing
+.I a.ns.heaven.af.mil
+as a name server for
+.IR panic.mil ,
+and an SOA record for
+.IR panic.mil .
+
+.RI & fqdn\fR:\fIip\fR:\fIx\fR:\fIttl\fR:\fItimestamp\fR:\fIlo\fR
+
+Name server for domain
+.IR fqdn .
+
+.B tinydns-data
+creates
+.IP
+an NS record
+showing 
+.IR x\fR.ns.\fIfqdn
+as a name server for 
+.IR fqdn
+and
+.P
+.IP
+an A record showing
+.I ip
+as the IP address
+of
+.IR x\fR.ns.\fIfqdn .
+.P
+
+If
+.I x
+contains a dot
+then it is treated specially; see above.
+
+You may have several name servers for one domain,
+with a different
+.I x
+for each server.
+
+Normally
+.I &
+is used
+for domains delegated by this server to child servers,
+while
+.I .
+is used for domains delegated to this server.
+.P
+Examples:
+
+  &serious.panic.mil:1.8.248.6:a
+
+creates an NS record showing
+.I a.ns.serious.panic.mil
+as a name server for
+.IR serious.panic.mil ,
+and an A record showing
+.I 1.8.248.6
+as the IP address of
+.IR a.ns.serious.panic.mil .
+
+  &serious.panic.mil:1.8.248.7:ns7.panic.mil
+
+creates an NS record showing
+.I ns7.panic.mil
+as a name server for
+.IR serious.panic.mil ,
+and an A record showing
+.I 1.8.248.7
+as the IP address of
+.IR ns7.panic.mil .
+
+.RI = fqdn\fR:\fIip\fR:\fIttl\fR:\fItimestamp\fR:\fIlo\fR
+
+Host
+.I fqdn
+with IP address 
+.IR ip .
+
+.B tinydns-data
+creates
+.IP
+an A record showing 
+.I ip
+as
+the IP address of 
+.IR fqdn
+and
+.P
+.IP
+a PTR (``pointer'') record showing 
+.I fqdn
+as
+the name of 
+.IR d.c.b.a .in-addr.arpa
+if 
+.I ip
+is 
+.IR a.b.c.d .
+.P
+
+Remember to specify name servers for some suffix of
+.IR fqdn ;
+otherwise 
+.BR tinydns (8)
+will not respond
+to queries about
+.IR fqdn .
+The same comment applies to other records described below.
+Similarly, remember to specify name servers for some suffix of
+.IR d.c.b.a .in-addr.arpa,
+if that domain has been delegated to you.
+.P
+Example:
+
+  =button.panic.mil:1.8.7.108
+
+creates an A record showing
+.I 1.8.7.108
+as the IP address of
+.IR button.panic.mil ,
+and a PTR record showing
+.I button.panic.mil
+as the name of
+.IR 108.7.8.1.in-addr.arpa .
+
+.RI + fqdn\fR:\fIip\fR:\fIttl\fR:\fItimestamp\fR:\fIlo\fR
+
+Alias
+.I fqdn
+with IP address 
+.IR ip .
+This is just like 
+.RI = fqdn\fR:\fIip\fR:\fIttl\fR
+except that 
+.B tinydns-data
+does not create the PTR record.
+
+For versions 1.04 and above:
+.BR tinydns (8)
+returns addresses
+(from
+.I +
+or
+.I =
+or
+.I @
+or
+.I .
+or
+.I &
+lines)
+in a random order in the answer section.
+If there are more than 8 records,
+it returns a random set of 8.
+.P
+Example:
+
+  +button.panic.mil:1.8.7.109
+
+creates an A record showing
+.I 1.8.7.109
+as another IP address for
+.IR button.panic.mil .
+
+.RI @ fqdn\fR:\fIip\fR:\fIx\fR:\fIdist\fR:\fIttl\fR:\fItimestamp\fR:\fIlo\fR
+
+Mail exchanger for 
+.IR fqdn .
+
+.B tinydns-data
+creates
+.IP
+an MX (``mail exchanger'') record
+showing 
+.IR x\fR.mx.\fIfqdn
+as a mail exchanger for 
+.I fqdn
+at distance 
+.I dist
+and
+.P
+.IP
+an A record showing 
+.I ip
+as the IP address
+of 
+.IR x\fR.mx.\fIfqdn .
+.P
+You may omit 
+.IR dist ;
+the default distance is 0.
+
+If 
+.I x
+contains a dot
+then it is treated specially; see above.
+
+You may create several MX records for 
+.IR fqdn ,
+with a different 
+.I x
+for each server.
+Make sure to arrange for the SMTP server on each IP address
+to accept mail for 
+.IR fqdn .
+.P
+Example:
+
+  @panic.mil:1.8.7.88:mail.panic.mil
+
+creates an MX record showing
+.I mail.panic.mil
+as a mail exchanger for
+.I panic.mil
+at distance 0, and an A record showing
+.I 1.8.7.88
+as the IP address of
+.IR mail.panic.mil .
+
+.RI # comment
+
+Comment line. The line is ignored.
+
+.SH Uncommon data lines
+
+.RI - fqdn\fR:\fIs\fR:\fIttl\fR:\fItimestamp\fR:\fIlo\fR
+
+For versions 1.04 and above:
+This type of line is used by
+programs that automatically edit
+.B +
+lines in
+.I data
+to temporarily exclude addresses of overloaded or dead machines.
+The line is ignored.
+
+.RI ' fqdn\fR:\fIs\fR:\fIttl\fR:\fItimestamp\fR:\fIlo\fR
+
+TXT (``text'') record for 
+.IR fqdn .
+.B tinydns-data
+creates a TXT record for 
+.I fqdn
+containing the string 
+.IR s .
+You may use octal 
+.RI \ nnn
+codes
+to include arbitrary bytes inside 
+.IR s ;
+for example, 
+.RI \ 072
+is a colon.
+
+.RI ^ fqdn\fR:\fIp\fR:\fIttl\fR:\fItimestamp\fR:\fIlo\fR
+
+PTR record for 
+.IR fqdn .
+.B tinydns-data
+creates a PTR record for
+.I fqdn
+pointing to the domain name 
+.IR p .
+
+.RI C fqdn\fR:\fIp\fR:\fIttl\fR:\fItimestamp\fR:\fIlo\fR
+
+CNAME (``canonical name'') record for 
+.IR fqdn .
+.B tinydns-data
+creates a CNAME record for 
+.I fqdn
+pointing to the domain name 
+.IR p .
+
+Don't use
+.RI C fqdn
+if there are any other records for
+.I fqdn
+Don't use
+.RI C fqdn
+for common aliases;
+use
+.RI + fqdn
+instead.
+Remember the wise words of Inigo Montoya:
+``You keep using CNAME records.
+I do not think they mean what you think they mean.''
+
+.RI Z fqdn\fR:\fImname\fR:\fIrname\fR:\fIser\fR:\fIref\fR:\fIret\fR:\fIexp\fR:\fImin\fR:\fIttl\fR:\fItimestamp\fR:\fIlo\fR
+
+SOA record for 
+.I fqdn
+showing 
+.I mname
+as the primary name server,
+.I rname
+(with the first 
+.I .
+converted to 
+.IR @ )
+as the contact address,
+.I ser
+as the serial number,
+.I ref
+as the refresh time,
+.I ret
+as the retry time,
+.I exp
+as the expire time, and
+.I min
+as the minimum time.
+.IR ser ,
+.IR ref ,
+.IR ret ,
+.IR exp ,
+and
+.I min
+may be omitted;
+they default to, respectively,
+the modification time of the 
+.I data
+file,
+16384 seconds,
+2048 seconds,
+1048576 seconds, and
+2560 seconds.
+
+.RI : fqdn\fR:\fIn\fR:\fIrdata\fR:\fIttl\fR:\fItimestamp\fR:\fIlo\fR
+
+Generic record for
+.IR fqdn .
+.B tinydns-data
+creates a record of type 
+.I n
+for 
+.I fqdn
+showing 
+.IR rdata .
+.I n
+must be an integer between 1 and 65535;
+it must not be 2 (NS), 5 (CNAME), 6 (SOA), 12 (PTR), 15 (MX), or 252 (AXFR).
+The proper format of
+.I rdata
+depends on 
+.IR n .
+You may use octal 
+.RI \ nnn
+codes
+to include arbitrary bytes inside 
+.IR rdata .
+
+.SH Wildcards
+
+.I tinydns
+supports wildcards of the form 
+.IR *.fqdn .
+Information for 
+.I *.fqdn
+is provided for every name ending with 
+.IR .fqdn ,
+.I except
+names that have their own records
+and names that are covered by more specific wildcards.
+
+For example, the lines
+
+  +pink.floyd.u.heaven.af.mil:1.2.3.4
+  +*.u.heaven.af.mil:1.2.3.200
+
+have the same effect as
+
+  +pink.floyd.u.heaven.af.mil:1.2.3.4
+  +joe.u.heaven.af.mil:1.2.3.200
+  +bill.u.heaven.af.mil:1.2.3.200
+  +floyd.u.heaven.af.mil:1.2.3.200
+  +ishtar.u.heaven.af.mil:1.2.3.200
+  +joe.bob.u.heaven.af.mil:1.2.3.200
+  +sally.floyd.u.heaven.af.mil:1.2.3.200
+  +post.pink.floyd.u.heaven.af.mil:1.2.3.200
+
+and so on.
+
+As another example, the lines
+
+  +pink.floyd.u.heaven.af.mil:1.2.3.4
+  @*.u.heaven.af.mil::mail.heaven.af.mil
+
+have the same effect as
+
+  +pink.floyd.u.heaven.af.mil:1.2.3.4
+  @joe.u.heaven.af.mil::mail.heaven.af.mil
+  @bill.u.heaven.af.mil::mail.heaven.af.mil
+  @floyd.u.heaven.af.mil::mail.heaven.af.mil
+  @ishtar.u.heaven.af.mil::mail.heaven.af.mil
+  @joe.bob.u.heaven.af.mil::mail.heaven.af.mil
+  @sally.floyd.u.heaven.af.mil::mail.heaven.af.mil
+  @post.pink.floyd.u.heaven.af.mil::mail.heaven.af.mil
+
+and so on.
+Notice that the wildcard does not apply to
+.IR pink.floyd.u.heaven.af.mil ,
+because that name has its own records.
+
+.SH A typical data file:
+
+  =lion.heaven.af.mil:1.2.3.4
+  @heaven.af.mil:1.2.3.4
+  @3.2.1.in-addr.arpa:1.2.3.4
+
+  =tiger.heaven.af.mil:1.2.3.5
+  \.heaven.af.mil:1.2.3.5:a
+  \.3.2.1.in-addr.arpa:1.2.3.5:a
+
+  =bear.heaven.af.mil:1.2.3.6
+  \.heaven.af.mil:1.2.3.6:b
+  \.3.2.1.in-addr.arpa:1.2.3.6:b
+
+  =cheetah.heaven.af.mil:1.2.3.248
+  =panther.heaven.af.mil:1.2.3.249
+
+Here is the same information in BIND zone-file format
+with the two zones merged:
+
+  heaven.af.mil. 2560 IN SOA a.ns.heaven.af.mil. hostmaster.heaven.af.mil. ...
+  heaven.af.mil. 259200 IN NS a.ns.heaven.af.mil.
+  heaven.af.mil. 259200 IN NS b.ns.heaven.af.mil.
+  heaven.af.mil. 86400 IN MX mx.heaven.af.mil.
+
+  3.2.1.in-addr.arpa. 2560 IN SOA a.ns.3.2.1.in-addr.arpa. hostmaster.3.2.1.in-addr.arpa. ...
+  3.2.1.in-addr.arpa. 259200 IN NS a.ns.3.2.1.in-addr.arpa.
+  3.2.1.in-addr.arpa. 259200 IN NS b.ns.3.2.1.in-addr.arpa.
+  3.2.1.in-addr.arpa. 86400 IN MX mx.3.2.1.in-addr.arpa.
+
+  4.3.2.1.in-addr.arpa. 86400 IN PTR lion.heaven.af.mil.
+  lion.heaven.af.mil. 86400 IN A 1.2.3.4
+  mx.heaven.af.mil. 86400 IN A 1.2.3.4
+  mx.3.2.1.in-addr.arpa. 86400 IN A 1.2.3.4
+
+  5.3.2.1.in-addr.arpa. 86400 IN PTR tiger.heaven.af.mil.
+  tiger.heaven.af.mil. 86400 IN A 1.2.3.5
+  a.ns.heaven.af.mil. 259200 IN A 1.2.3.5
+  a.ns.3.2.1.in-addr.arpa. 259200 IN A 1.2.3.5
+
+  6.3.2.1.in-addr.arpa. 86400 IN PTR bear.heaven.af.mil.
+  bear.heaven.af.mil. 86400 IN A 1.2.3.6
+  b.ns.heaven.af.mil. 259200 IN A 1.2.3.6
+  b.ns.3.2.1.in-addr.arpa. 259200 IN A 1.2.3.6
+
+  248.3.2.1.in-addr.arpa. 86400 IN PTR cheetah.heaven.af.mil.
+  cheetah.heaven.af.mil. 86400 IN A 1.2.3.248
+
+  249.3.2.1.in-addr.arpa. 86400 IN PTR panther.heaven.af.mil.
+  panther.heaven.af.mil. 86400 IN A 1.2.3.249
+
+.SH Design notes
+The 
+.I data
+format is very easy for programs to edit,
+and reasonably easy for humans to edit,
+unlike the traditional zone-file format.
+
+.B tinydns-data
+could support a name wherever an IP address is required;
+it would look up the name in DNS and use the resulting address.
+This would reliably track changes in offsite IP addresses
+if the database were rebuilt periodically.
+
+.SH SEE ALSO
+tinydns(8)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/tinydns-edit.8 b/debian/djbdns-man/tinydns-edit.8
new file mode 100644 (file)
index 0000000..697b879
--- /dev/null
@@ -0,0 +1,149 @@
+.TH tinydns-edit 8
+
+.SH NAME
+tinydns-edit \- edit the (source form of the) database served by tinydns/axfrdns
+
+.SH SYNOPSIS
+.B tinydns-edit
+.I data
+.I data.tmp
+add
+.I type
+.I name
+.I address
+
+.SH DESCRIPTION
+.B tinydns-edit
+edits the
+.I data
+file, which is the source form of the database that is compiled by
+.BR tinydns-data (8)
+and that is served by
+.BR tinydns (8)
+and
+.BR axfrdns (8).
+The update to
+.I data
+is performed atomically, by first writing the updated database content to the file
+.I data.tmp
+and then renaming
+.I data.tmp
+to
+.I data .
+The two files must, of course, reside on the same volume in order that this can be achieved.
+.PP
+On success,
+.I tinydns-edit
+returns zero.  If, for any reason, an error occurs it will exit with a non-zero code and
+.I data
+will not be changed.
+.PP
+With the "add" verb, 
+.I tinydns-edit
+appends to the database a record whose type is determined by
+.I type ,
+with the fully-qualified name
+.I name
+and the IP address
+.I address .
+.I type
+can be one of:
+.IP ns
+A '.' record is created.  This record specifies that the domain
+.I name
+is published by a DNS content server that is listening on the IP address
+.I address .
+.IP
+The name of the DNS content server is not directly specifiable.  Names are automatically assigned by
+.I tinydns-edit
+itself, following the pattern
+.I [a-z].ns.name .
+.I tinydns-edit
+will assign the first letter of the alphabet that is not already used in another '.' or '&' record as the name of a DNS content server.
+If no letters of the alphabet remain unused,
+.I tinydns-edit
+will fail.
+.IP
+If a '.' or '&' record for the domain already exists, proxy DNS servers are allowed to cache the new record for the same length of time as they are allowed to cache the existing records.
+Otherwise, proxy DNS servers are allowed to cache the record for up to 3 days.
+.IP childns
+A '&' record is created.  This record specifies that queries for names in the domain
+.I name
+should be referred to a ("child") DNS content server that is listening on the IP address
+.I address .
+.IP
+The name of the DNS content server is not directly specifiable.  Names are automatically assigned by
+.I tinydns-edit
+itself, following the pattern
+.I [a-z].ns.name .
+.I tinydns-edit
+will assign the first letter of the alphabet that is not already used in another '.' or '&' record as the name of a DNS content server.
+If no letters of the alphabet remain unused,
+.I tinydns-edit
+will fail.
+.IP
+If a '.' or '&' record for the domain already exists, proxy DNS servers are allowed to cache the new record for the same length of time as they are allowed to cache the existing records.
+Otherwise, proxy DNS servers are allowed to cache the record for up to 3 days.
+.IP mx
+A '@' record is created.  This record specifies that mail to names in the domain
+.I name
+should be sent to an SMTP server that is listening on the IP address
+.I address .
+.IP
+The name of the SMTP server is not directly specifiable.  Names are automatically assigned by
+.I tinydns-edit
+itself, following the pattern
+.I [a-z].mx.name .
+.I tinydns-edit
+will assign the first letter of the alphabet that is not already used in another '@' record as the name of an SMTP server.
+If no letters of the alphabet remain unused,
+.I tinydns-edit
+will fail.
+.IP
+It is not possible to specify the 
+.I distance 
+value for the SMTP server.  
+.I tinydns-edit
+will leave that field blank, meaning that 
+.I tinydns-data (8)
+will use whatever the default value is.
+.IP
+If a '@' record for the domain already exists, proxy DNS servers are allowed to cache the new record for the same length of time as they are allowed to cache the existing records.
+Otherwise, proxy DNS servers are allowed to cache the record for up to 1 day.
+.IP host
+A '=' record is created, that proxy DNS servers are allowed to cache for up to 1 day.  This record specifies that the name
+.I name
+maps to the IP address
+.I address 
+and vice versa.
+.IP
+.I tinydns-edit
+will fail if a '=' record already exists that uses either
+.I name
+or
+.I address .
+.IP alias
+A '+' record is created, that proxy DNS servers are allowed to cache for up to 1 day.  This record specifies that the name
+.I name
+maps to the IP address
+.I address 
+but that there is no reverse mapping.
+.IP
+Because this is an alias record,
+.I tinydns-edit
+will not fail if there happen to already be existing records that use
+.I address .
+
+.SH SEE ALSO
+tinydns-data(8),
+
+http://cr.yp.to/djbdns.html
+
+.SH AUTHOR AND MODIFICATIONS
+This manual page was created by Jonathan de Boyne Pollard on 2001-04-06.
+.PP
+2001-04-26: A new AUTHOR AND MODIFICATIONS section was added.
+.BR axfrdns (8)
+is now mentioned.
+The description of how server names were auto-generated was clarified.
+A cut-and-paste error in the description of the "mx" type was corrected.
diff --git a/debian/djbdns-man/tinydns-get.1 b/debian/djbdns-man/tinydns-get.1
new file mode 100644 (file)
index 0000000..313b5c8
--- /dev/null
@@ -0,0 +1,44 @@
+.TH tinydns-get 1
+
+.SH NAME
+tinydns-get \- is like dnsq(1), but obtains its results from data.cdb in the current directory
+
+.SH SYNOPSIS
+.B tinydns-get 
+.I t
+.I fqdn
+[
+.I ip
+]
+
+.SH DESCRIPTION
+.B tinydns-get
+is like
+.BR dnsq (1),
+but obtains its results from
+.I data.cdb
+in the current directory, in exactly the same way that
+.BR tinydns (8)
+and
+.BR axfrdns (8)
+obtain results from
+.I data.cdb
+in their root directories. If
+.I ip
+is provided, it simulates the results of a query from IP address
+.IR ip ;
+this matters if
+.I data.cdb
+differentiates among clients in different locations.
+
+.SH SEE ALSO
+dnsq(1),
+dnsip(1),
+dnsipq(1),
+dnsmx(1),
+dnstxt(1),
+dnsqr(1),
+dnsname(1),
+dnstrace(1)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/tinydns.8 b/debian/djbdns-man/tinydns.8
new file mode 100644 (file)
index 0000000..ff92edd
--- /dev/null
@@ -0,0 +1,75 @@
+.TH tinydns 8
+
+.SH NAME
+tinydns \- a DNS server.
+
+.SH DESCRIPTION
+.B tinydns
+accepts iterative DNS queries
+from hosts around the Internet,
+and responds with locally configured information.
+
+.SH Configuration
+This is a reference page.
+For tutorial information, see the instructions for
+.br
+.B running a DNS server
+(http://cr.yp.to/djbdns/run-server.html).
+
+Normally 
+.B tinydns
+is set up by the
+.BR tinydns-conf (8)
+program.
+
+.B tinydns
+runs chrooted in the directory
+specified by the 
+.I $ROOT
+environment variable,
+under the uid and gid
+specified by the 
+.I $UID
+and 
+.I $GID
+environment variables.
+
+.B tinydns
+listens for incoming UDP packets
+addressed to port 53 of 
+.IR $IP .
+It does not listen for TCP queries.
+
+.B tinydns
+answers queries
+as specified by 
+.IR data.cdb ,
+a binary file created by
+.BR tinydns-data (8).
+
+.SH Further details
+
+.B tinydns
+rejects
+zone-transfer requests,
+inverse queries, non-Internet-class queries, truncated packets, and
+packets that contain anything other than a single query.
+
+.BR tinydns ,
+like BIND,
+includes NS records with answers to most queries.
+This increases DNS packet sizes,
+but it draws queries away from parent servers,
+and reduces the frequency of long DNS delays.
+With the default 
+.BR tinydns-data (8)
+cache times,
+a client that uses a normal record at least once every day
+will always have the corresponding NS records cached
+and will never have to talk to parent servers.
+
+.SH SEE ALSO
+tinydns-conf(8),
+tinydns-data(8)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/walldns-conf.8 b/debian/djbdns-man/walldns-conf.8
new file mode 100644 (file)
index 0000000..331a215
--- /dev/null
@@ -0,0 +1,94 @@
+.TH walldns-conf 8
+
+.SH NAME
+walldns-conf \- sets up a DNS wall service.
+
+.SH SYNOPSIS
+walldns-conf 
+.I acct
+.I logacct
+.I D
+.I ip
+
+.SH DESCRIPTION
+.B walldns-conf
+creates a service directory 
+.I D
+that runs
+.BR walldns (8).
+The name 
+.I D
+must start with a slash
+and must not contain any special characters.
+Normally 
+.I D
+is 
+.IR /etc/walldns .
+
+You can run the service under
+.BR svscan (8)
+by using the
+.BR update-service (8)
+program on Debian GNU/Linux
+
+update-service --add
+.I D
+
+or by creating a symbolic link in the
+.BR svscan (8)
+directory (normally /service or /etc/service), e.g.:
+
+ln -s 
+.I D
+/service
+
+The service will start within five seconds,
+and will be restarted upon reboot.
+You can use
+.BR svc (8)
+to control the service.
+
+.B walldns-conf
+arranges for 
+.I walldns
+to chroot to 
+.IR D /root
+and to run under the uid and gid of
+.IR acct .
+The name
+.I acct
+must not contain any special characters.
+
+.B walldns-conf
+arranges for 
+.BR walldns (8)
+to listen for UDP packets on port 53 of 
+.IR ip ,
+and to send outgoing packets from
+.IR ip .
+
+.B walldns-conf
+creates an automatically rotated log directory in
+.IR D /log/main.
+The logs are owned by 
+.IR logacct .
+The corresponding 
+.BR multilog (8)
+processes run under the uid and gid of 
+.IR logacct .
+The name
+.I logacct
+must not contain any special characters.
+
+.SH SEE ALSO
+walldns(8),
+svscan(8),
+svc(8),
+multilog(8),
+axfrdns-conf(8),
+rbldns-conf(8),
+tinydns-conf(8),
+dnscache-conf(8),
+update-service(8)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns-man/walldns.8 b/debian/djbdns-man/walldns.8
new file mode 100644 (file)
index 0000000..db2538b
--- /dev/null
@@ -0,0 +1,72 @@
+.TH walldns 8
+
+.SH NAME
+walldns \- a reverse DNS wall
+
+.SH DESCRIPTION
+.B walldns
+is a reverse DNS wall.
+It accepts iterative DNS queries for 
+.I in-addr.arpa
+domains
+from hosts around the Internet,
+and supplies generic responses that avoid revealing local host information.
+
+For example, 
+.B walldns
+provides a PTR record for 
+.I 4.3.2.1.in-addr.arpa
+showing 
+.I 4.3.2.1.in-addr.arpa
+as the name of IP address 
+.IR 1.2.3.4 ,
+and a matching A record showing 
+.I 1.2.3.4
+as the IP address of 
+.IR 4.3.2.1.in-addr.arpa .
+
+.SH Configuration
+Normally 
+.B walldns
+is set up by the
+.BR walldns-conf (8)
+program.
+
+.B walldns
+runs chrooted in the directory
+specified by the 
+.I $ROOT
+environment variable,
+under the uid and gid
+specified by the 
+.I $UID
+and 
+.I $GID
+environment variables.
+
+.B walldns
+listens for incoming UDP packets
+addressed to port 53 of 
+.IR $IP .
+It does not listen for TCP queries.
+
+.SH Further details
+
+.B walldns
+rejects
+inverse queries, non-Internet-class queries, truncated packets,
+packets that contain anything other than a single question,
+queries for domains outside 
+.IR in-addr.arpa ,
+and request types other than A, PTR, and *.
+
+.B walldns
+does not include NS or SOA records with its responses.
+
+.B walldns
+uses TTLs slightly over one week.
+
+.SH SEE ALSO
+walldns-conf(8)
+
+http://cr.yp.to/djbdns.html
diff --git a/debian/djbdns.NEWS.Debian b/debian/djbdns.NEWS.Debian
new file mode 100644 (file)
index 0000000..4a6e286
--- /dev/null
@@ -0,0 +1,33 @@
+djbdns (1:1.05-6) unstable; urgency=medium
+
+  CVE-2008-4392 reports 'Rapid DNS Poisoning in dnscache', the dnscache
+  program included in djbdns-1.05.  Upstream's comments on this can be
+  read in http://cr.yp.to/djbdns/forgery.html
+
+  The dbndns package, the Debian fork of djbdns, includes a patch that
+  limits concurrent outgoing SOA queries to 20 instead 200 (MAXUDP) to
+  make birthday attacks more difficult.
+
+ -- Gerrit Pape <pape@smarden.org>  Mon, 16 Mar 2009 23:00:06 +0000
+
+djbdns (1:1.05-1) unstable; urgency=low
+
+  With the djbdns package being put into the public domain by the
+  upstream author, djbdns is now available as binary package in
+  Debian/main.
+
+  Please note that this new binary package differs from the package
+  created through the djbdns-installer package available in
+  Debian/non-free; most notably this package depends on a different
+  version of the daemontools package, and installs the programs into
+  a different path (now /usr/bin/).  The latter change most probably
+  requires adapting the paths in the ./run scripts in already existing
+  service directories.
+  
+  If you don't want to upgrade to the new binary package, you should
+  stop the installation, and put djbdns on hold, as described in
+
+   http://www.debian.org/doc/FAQ/ch-pkg_basics.en.html#s-puttingonhold
+  
+ -- Gerrit Pape <pape@smarden.org>  Mon, 25 Feb 2008 21:44:02 +0000
+
diff --git a/debian/djbdns.README.Debian b/debian/djbdns.README.Debian
new file mode 100644 (file)
index 0000000..205419e
--- /dev/null
@@ -0,0 +1,11 @@
+djbdns for Debian
+-----------------
+
+This package provides the djbdns programs, installed into /usr/bin/, and
+man pages.  When configuring and enabling djbdns services, please note
+that daemontools' default directory for services on Debian is
+/etc/service/, not /service/.
+
+See http://cr.yp.to/djbdns.html for detailed documentation.
+
+ -- Gerrit Pape <pape@smarden.org>, Wed, 09 Jan 2008 21:14:00 +0000
diff --git a/debian/djbdns.conffiles b/debian/djbdns.conffiles
new file mode 100644 (file)
index 0000000..6b0e2f3
--- /dev/null
@@ -0,0 +1 @@
+/etc/dnsroots.global
diff --git a/debian/djbdns.docs b/debian/djbdns.docs
new file mode 100644 (file)
index 0000000..47125a2
--- /dev/null
@@ -0,0 +1,5 @@
+README
+TODO
+VERSION
+SYSDEPS
+TINYDNS
diff --git a/debian/dnscache-run.README.Debian b/debian/dnscache-run.README.Debian
new file mode 100644 (file)
index 0000000..a238ee2
--- /dev/null
@@ -0,0 +1,20 @@
+dnscache-run for Debian
+-----------------------
+
+This package automatically sets up the djbdns package to provide a
+dnscache service.  By default the dnscache service listens on
+127.0.0.1:53, and /etc/resolv.conf is adjusted accordingly.
+
+To make the dnscache service available to other machines, you can
+change the IP dnscache should listen on by changing the configuration
+in /etc/dnscache/, e.g.
+
+ # echo 192.168.0.1 >/etc/dnscache/env/IP
+ # touch /etc/dnscache/root/ip/192.168.0
+ # svc -t /etc/service/dnscache
+ # perl -p -i -e 's/nameserver 127.0.0.1/nameserver 192.168.0.1/' \
+   /etc/resolv.conf
+
+See http://cr.yp.to/djbdns.html for detailed documentation.
+
+ -- Gerrit Pape <pape@smarden.org>, Tue, 13 May 2008 18:56:32 +0000
diff --git a/debian/dnscache-run.conffiles b/debian/dnscache-run.conffiles
new file mode 100644 (file)
index 0000000..66887d4
--- /dev/null
@@ -0,0 +1,10 @@
+/etc/sv/dnscache/env/CACHESIZE
+/etc/sv/dnscache/env/DATALIMIT
+/etc/sv/dnscache/env/IP
+/etc/sv/dnscache/env/IPSEND
+/etc/sv/dnscache/env/ROOT
+/etc/sv/dnscache/log/run
+/etc/sv/dnscache/log/status
+/etc/sv/dnscache/root/ip/127.0.0.1
+/etc/sv/dnscache/root/servers/@
+/etc/sv/dnscache/run
diff --git a/debian/dnscache-run.postinst b/debian/dnscache-run.postinst
new file mode 100644 (file)
index 0000000..7843269
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+set -e
+
+test "$1" = 'configure' || exit 0
+
+if test ! -r /etc/sv/dnscache/seed; then
+  rm -rf /etc/sv/dnscache/.'{tmp}'.$$
+  dnscache-conf Gdnscache Gdnslog /etc/sv/dnscache/.'{tmp}'.$$
+  mv /etc/sv/dnscache/.'{tmp}'.$$/seed /etc/sv/dnscache/seed
+  rm -rf /etc/sv/dnscache/.'{tmp}'.$$
+fi
+
+if test -e /etc/service/dnscache; then
+  echo 'Restarting dnscache service...'
+  svc -t /etc/service/dnscache || :
+else
+  update-service --add /etc/sv/dnscache
+fi
+
+test -z "$2" || exit 0
+
+chown Gdnslog:adm /var/log/dnscache
+# adapt resolv.conf
+! grep 'nameserver 127.0.0.1' /etc/resolv.conf >/dev/null || exit 0
+test -e /etc/resolv.conf || exec echo 'nameserver 127.0.0.1' >/etc/resolv.conf
+sed -e 's/nameserver /# nameserver /g' /etc/resolv.conf >/etc/resolv.conf'{new}'
+echo 'nameserver 127.0.0.1' >>/etc/resolv.conf'{new}'
+mv -f /etc/resolv.conf'{new}' /etc/resolv.conf
diff --git a/debian/dnscache-run.postrm b/debian/dnscache-run.postrm
new file mode 100644 (file)
index 0000000..e912a93
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+set -e
+
+test "$1" = 'purge' || exit 0
+
+svc -x /etc/sv/dnscache 2>/dev/null || :
+rm -rf /etc/sv/dnscache
+rm -rf /var/lib/supervise/dnscache /var/lib/supervise/dnscache.log
+for i in '@*' current config lock state; do
+  rm -f /var/log/dnscache/$i
+done
+rmdir /var/log/dnscache || :
+! getent passwd Gdnscache >/dev/null || userdel -f Gdnscache || :
diff --git a/debian/dnscache-run.preinst b/debian/dnscache-run.preinst
new file mode 100644 (file)
index 0000000..2485baf
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/sh
+set -e
+
+test "$1" = 'install' || exit 0
+test -z "$2" || exit 0
+
+# not upgrading
+for i in Gdnscache Gdnslog; do
+  getent passwd $i >/dev/null ||
+    adduser --quiet --system --force-badname --shell /bin/false --group \
+      --home /nonexistent --no-create-home $i || exit 1;
+done
diff --git a/debian/dnscache-run.prerm b/debian/dnscache-run.prerm
new file mode 100644 (file)
index 0000000..43baa98
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+set -e
+
+test "$1" = 'remove' || test "$1" = 'deconfigure' ||
+  test "$1" = 'failed-upgrade' || exit 0
+
+update-service --remove /etc/sv/dnscache || :
diff --git a/debian/dnsroots.global b/debian/dnsroots.global
new file mode 100644 (file)
index 0000000..ca40b38
--- /dev/null
@@ -0,0 +1,13 @@
+198.41.0.4
+192.228.79.201
+192.33.4.12
+128.8.10.90
+192.203.230.10
+192.5.5.241
+192.112.36.4
+128.63.2.53
+192.36.148.17
+192.58.128.30
+193.0.14.129
+199.7.83.42
+202.12.27.33
diff --git a/debian/implicit b/debian/implicit
new file mode 100644 (file)
index 0000000..2b074cd
--- /dev/null
@@ -0,0 +1,93 @@
+# $Id: 60d9070435b8d5608f20f60bc44e081960b6e39d $
+
+.PHONY: deb-checkdir deb-checkuid
+
+deb-checkdir:
+       @test -e debian/control || sh -cx '! : wrong directory'
+deb-checkuid:
+       @test "`id -u`" -eq 0 || sh -cx '! : need root privileges'
+
+%.deb: %.deb-docs %.deb-DEBIAN
+       @rm -f $*.deb $*.deb-checkdir $*.deb-docs $*.deb-docs-base \
+         $*.deb-docs-docs $*.deb-docs-examples $*.deb-DEBIAN \
+         $*.deb-DEBIAN-dir $*.deb-DEBIAN-scripts $*.deb-DEBIAN-md5sums
+
+%.udeb: %.deb-DEBIAN
+       @rm -f $*.deb $*.deb-checkdir $*.deb-DEBIAN $*.deb-DEBIAN-dir \
+         $*.deb-DEBIAN-scripts $*.deb-DEBIAN-md5sums
+
+%.deb-checkdir: install
+       @test -d debian/$* || sh -cx '! : directory debian/$* missing'
+       @test "`id -u`" -eq 0 || sh -cx '! : need root privileges'
+
+%.deb-docs-base: install
+       : implicit
+       @rm -f debian/$*/usr/share/doc/$*/* || :
+       @install -d -m0755 debian/$*/usr/share/doc/$*
+       : debian/$*/usr/share/doc/$*/
+       @sh -cx 'install -m0644 debian/copyright debian/$*/usr/share/doc/$*/'
+       @sh -cx 'install -m0644 debian/changelog \
+         debian/$*/usr/share/doc/$*/changelog.Debian'
+       @test ! -r changelog || \
+         sh -cx 'install -m0644 changelog debian/$*/usr/share/doc/$*/'
+       @test -r debian/$*/usr/share/doc/$*/changelog || \
+         sh -cx 'mv debian/$*/usr/share/doc/$*/changelog.Debian \
+           debian/$*/usr/share/doc/$*/changelog'
+       @test -s debian/$*/usr/share/doc/$*/changelog || \
+         sh -cx 'rm -f debian/$*/usr/share/doc/$*/changelog'
+       @gzip -9 debian/$*/usr/share/doc/$*/changelog*
+%.deb-docs-docs: %.deb-docs-base
+       @for i in `cat debian/$*.docs 2>/dev/null || :`; do \
+         if test -d $$i; then \
+           sh -cx "install -d -m0755 debian/$*/usr/share/doc/$*/$${i##*/}" && \
+           for j in $$i/*; do \
+             sh -cx "install -m0644 $$j \
+               debian/$*/usr/share/doc/$*/$${i##*/}/" || exit 1; \
+           done || exit 1; \
+           continue; \
+         fi; \
+         sh -cx "install -m0644 $$i debian/$*/usr/share/doc/$*/" || exit 1; \
+       done
+       @test ! -r debian/$*.README.Debian || \
+         sh -cx 'install -m0644 debian/$*.README.Debian \
+           debian/$*/usr/share/doc/$*/README.Debian'
+       @if test -r debian/$*.NEWS.Debian; then \
+         sh -cx 'install -m0644 debian/$*.NEWS.Debian \
+           debian/$*/usr/share/doc/$*/NEWS.Debian && \
+             gzip -9 debian/$*/usr/share/doc/$*/NEWS.Debian'; \
+       fi
+%.deb-docs-examples: %.deb-docs-docs
+       @rm -rf debian/$*/usr/share/doc/$*/examples
+       : debian/$*/usr/share/doc/$*/examples/
+       @test ! -r debian/$*.examples || \
+         install -d -m0755 debian/$*/usr/share/doc/$*/examples
+       @for i in `cat debian/$*.examples 2>/dev/null || :`; do \
+         sh -cx "install -m0644 $$i debian/$*/usr/share/doc/$*/examples/" \
+           || exit 1; \
+       done
+%.deb-docs: %.deb-checkdir %.deb-docs-base %.deb-docs-docs %.deb-docs-examples
+       : debian/$*/usr/share/doc/$*/ ok
+
+%.deb-DEBIAN-base: install
+       @rm -rf debian/$*/DEBIAN
+       : debian/$*/DEBIAN/
+       @install -d -m0755 debian/$*/DEBIAN
+       @for i in conffiles shlibs templates; do \
+         test ! -r debian/$*.$$i || \
+           sh -cx "install -m0644 debian/$*.$$i debian/$*/DEBIAN/$$i" \
+             || exit 1; \
+       done
+%.deb-DEBIAN-scripts: %.deb-DEBIAN-base
+       @for i in preinst prerm postinst postrm config; do \
+         test ! -r debian/$*.$$i || \
+           sh -cx "install -m0755 debian/$*.$$i debian/$*/DEBIAN/$$i" \
+             || exit 1; \
+       done
+%.deb-DEBIAN-md5sums: %.deb-DEBIAN-base %.deb-docs
+       : debian/$*/DEBIAN/md5sums
+       @rm -f debian/$*/DEBIAN/md5sums
+       @cd debian/$* && find * -path 'DEBIAN' -prune -o \
+         -type f -exec md5sum {} >>DEBIAN/md5sums \;
+%.deb-DEBIAN: %.deb-checkdir %.deb-DEBIAN-base %.deb-DEBIAN-scripts \
+         %.deb-DEBIAN-md5sums
+       : debian/$*/DEBIAN/ ok
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..ce81891
--- /dev/null
@@ -0,0 +1,135 @@
+#!/usr/bin/make -f
+
+STRIP =strip
+ifneq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+  STRIP =: nostrip
+endif
+
+DIR =$(shell pwd)/debian/djbdns
+DIRDBN =$(shell pwd)/debian/dbndns
+DIRCACHERUN =$(shell pwd)/debian/dnscache-run
+
+configure: deb-checkdir configure-stamp
+configure-stamp:
+       for i in `cat FILES`; do \
+         test -r dbndns/$$i || cp -p $$i dbndns/$$i || exit 1; \
+       done
+       touch configure-stamp
+
+patch: deb-checkdir patch-stamp dbndns/patch-stamp
+patch-stamp: configure-stamp
+       for i in `ls -1 debian/diff/*.diff || :`; do \
+         patch -p1 <$$i || exit 1; \
+       done
+       touch patch-stamp
+dbndns/patch-stamp: configure-stamp
+       for i in `ls -1 dbndns/diff/*.diff || :`; do \
+         (cd dbndns/ && patch -p1) <$$i || exit 1; \
+       done
+       touch dbndns/patch-stamp
+
+build: deb-checkdir build-stamp dbndns/build-stamp
+build-stamp: patch-stamp
+       test -r conf-home'{orig}' || cp -f conf-home conf-home'{orig}'
+       echo /usr >conf-home
+       test -r conf-cc'{orig}' || cp conf-cc conf-cc'{orig}'
+       echo 'gcc -O2 -g -include /usr/include/errno.h' >conf-cc
+       $(MAKE)
+       touch build-stamp
+dbndns/build-stamp: dbndns/patch-stamp
+       test -r dbndns/conf-home'{orig}' || \
+         cp -f dbndns/conf-home dbndns/conf-home'{orig}'
+       echo /usr >dbndns/conf-home
+       test -r dbndns/conf-cc'{orig}' || \
+         cp dbndns/conf-cc dbndns/conf-cc'{orig}'
+       echo 'gcc -O2 -g -include /usr/include/errno.h' >dbndns/conf-cc
+       $(MAKE) -Cdbndns/
+       touch dbndns/build-stamp
+
+clean: deb-checkdir deb-checkuid
+       rm -f `cat TARGETS`
+       for i in dbndns/*; do test -d $$i || rm -f $$i; done
+       test ! -e patch-stamp || \
+         for i in `ls -1r debian/diff/*.diff || :`; do patch -p1 -R <$$i; done
+       rm -f configure-stamp patch-stamp build-stamp \
+         dbndns/patch-stamp dbndns/build-stamp
+       rm -rf '$(DIR)' '$(DIRDBN)' '$(DIRCACHERUN)'
+       rm -f debian/files debian/substvars changelog
+       test ! -r conf-home'{orig}' || mv -f conf-home'{orig}' conf-home
+       test ! -r conf-cc'{orig}' || mv conf-cc'{orig}' conf-cc
+
+install: install-arch install-indep
+install-arch: deb-checkdir deb-checkuid build-stamp dbndns/build-stamp
+       rm -rf '$(DIR)' '$(DIRDBN)'
+       # djbdns programs
+       install -d -m0755 '$(DIR)'/usr
+       test -r conf-home'{orig}' || cp conf-home conf-home'{orig}'
+       echo '$(DIR)'/usr >conf-home
+       rm -f install instcheck install.o instcheck.o hier.o auto_home.o
+       $(MAKE) install instcheck
+       mv -f conf-home'{orig}' conf-home
+       ./install
+       ./instcheck
+       for i in '$(DIR)'/usr/bin/*; do \
+         test "`head -c2 $$i`" = '#!' || \
+           $(STRIP) -R .comment -R .note $$i || exit 1; \
+       done
+       # dbndns programs
+       install -d -m0755 '$(DIRDBN)'/usr
+       test -r dbndns/conf-home'{orig}' || \
+         cp dbndns/conf-home dbndns/conf-home'{orig}'
+       echo '$(DIRDBN)'/usr >dbndns/conf-home
+       (cd dbndns/ && \
+         rm -f install instcheck install.o instcheck.o hier.o auto_home.o)
+       $(MAKE) -Cdbndns/ install instcheck
+       mv -f dbndns/conf-home'{orig}' dbndns/conf-home
+       (cd dbndns/ && ./install)
+       (cd dbndns/ && ./instcheck)
+       for i in '$(DIRDBN)'/usr/bin/*; do \
+         test "`head -c2 $$i`" = '#!' || \
+           $(STRIP) -R .comment -R .note $$i || exit 1; \
+       done
+       # etc
+       install -d -m0755 '$(DIR)'/etc
+       install -m0644 debian/dnsroots.global '$(DIR)'/etc/dnsroots.global
+       cp -a '$(DIR)'/etc '$(DIRDBN)'/etc
+       # manpages
+       for i in 1 8; do \
+         install -d -m0755 '$(DIR)'/usr/share/man/man$$i; \
+         for j in debian/djbdns-man/*.$$i; do \
+           install -m0644 $$j '$(DIR)'/usr/share/man/man$$i/ && \
+           gzip -9 '$(DIR)'/usr/share/man/man$$i/$${j##*/} || exit 1; \
+         done; \
+       done
+       install -d -m0755 '$(DIRDBN)'/usr/share
+       cp -a '$(DIR)'/usr/share/man '$(DIRDBN)'/usr/share/man
+       # fix up directory permissions
+       chmod g-s '$(DIR)'/usr '$(DIR)'/usr/bin
+       chmod g-s '$(DIRDBN)'/usr '$(DIRDBN)'/usr/bin
+       # changelog
+       rm -f changelog && ln -s CHANGES changelog
+install-indep: deb-checkdir deb-checkuid
+       rm -rf '$(DIRCACHERUN)'
+       $(MAKE) -Cdnscache-run install DESTDIR='$(DIRCACHERUN)'
+       ln -s sv/dnscache '$(DIRCACHERUN)'/etc/dnscache
+       install -d -m0755 '$(DIRCACHERUN)'/var/log/dnscache
+       ln -s /var/log/dnscache '$(DIRCACHERUN)'/etc/sv/dnscache/log/main
+
+binary: binary-indep binary-arch
+binary-arch: install-arch djbdns.deb dbndns.deb
+       rm -f debian/substvars
+       dpkg-shlibdeps '$(DIR)'/usr/bin/*
+       dpkg-gencontrol -isp -pdjbdns -P'$(DIR)'
+       dpkg -b '$(DIR)' ..
+       rm -f debian/substvars
+       dpkg-shlibdeps '$(DIRDBN)'/usr/bin/*
+       dpkg-gencontrol -isp -pdbndns -P'$(DIRDBN)'
+       dpkg -b '$(DIRDBN)' ..
+binary-indep: install-indep dnscache-run.deb
+       dpkg-gencontrol -isp -pdnscache-run -P'$(DIRCACHERUN)'
+       dpkg -b '$(DIRCACHERUN)' ..
+
+.PHONY: configure patch dbndns/patch build dbndns/build clean install \
+  binary-indep binary-arch binary
+
+include debian/implicit
diff --git a/dnscache-run/Makefile b/dnscache-run/Makefile
new file mode 100644 (file)
index 0000000..87e10ce
--- /dev/null
@@ -0,0 +1,15 @@
+install:
+       install -d -m3755 '$(DESTDIR)'/etc/sv/dnscache
+       install -d -m2755 '$(DESTDIR)'/etc/sv/dnscache/env
+       install -d -m2755 '$(DESTDIR)'/etc/sv/dnscache/log
+       install -d -m2755 '$(DESTDIR)'/etc/sv/dnscache/root
+       install -m0755 run '$(DESTDIR)'/etc/sv/dnscache/
+       install -m0644 env/* '$(DESTDIR)'/etc/sv/dnscache/env/
+       install -m0755 log/run '$(DESTDIR)'/etc/sv/dnscache/log/
+       touch '$(DESTDIR)'/etc/sv/dnscache/log/status
+       chmod 0644 '$(DESTDIR)'/etc/sv/dnscache/log/status
+       install -d -m2755 '$(DESTDIR)'/etc/sv/dnscache/root/ip
+       install -d -m2755 '$(DESTDIR)'/etc/sv/dnscache/root/servers
+       touch '$(DESTDIR)'/etc/sv/dnscache/root/ip/127.0.0.1
+       chmod 0600 '$(DESTDIR)'/etc/sv/dnscache/root/ip/127.0.0.1
+       install -m0644 root/servers/@ '$(DESTDIR)'/etc/sv/dnscache/root/servers/
diff --git a/dnscache-run/env/CACHESIZE b/dnscache-run/env/CACHESIZE
new file mode 100644 (file)
index 0000000..749fce6
--- /dev/null
@@ -0,0 +1 @@
+1000000
diff --git a/dnscache-run/env/DATALIMIT b/dnscache-run/env/DATALIMIT
new file mode 100644 (file)
index 0000000..d4f015c
--- /dev/null
@@ -0,0 +1 @@
+3000000
diff --git a/dnscache-run/env/IP b/dnscache-run/env/IP
new file mode 100644 (file)
index 0000000..7b9ad53
--- /dev/null
@@ -0,0 +1 @@
+127.0.0.1
diff --git a/dnscache-run/env/IPSEND b/dnscache-run/env/IPSEND
new file mode 100644 (file)
index 0000000..d690dc0
--- /dev/null
@@ -0,0 +1 @@
+0.0.0.0
diff --git a/dnscache-run/env/ROOT b/dnscache-run/env/ROOT
new file mode 100644 (file)
index 0000000..c608f6b
--- /dev/null
@@ -0,0 +1 @@
+/etc/sv/dnscache/root
diff --git a/dnscache-run/log/run b/dnscache-run/log/run
new file mode 100644 (file)
index 0000000..c16f110
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec setuidgid Gdnslog multilog t ./main
diff --git a/dnscache-run/root/servers/@ b/dnscache-run/root/servers/@
new file mode 100644 (file)
index 0000000..ca40b38
--- /dev/null
@@ -0,0 +1,13 @@
+198.41.0.4
+192.228.79.201
+192.33.4.12
+128.8.10.90
+192.203.230.10
+192.5.5.241
+192.112.36.4
+128.63.2.53
+192.36.148.17
+192.58.128.30
+193.0.14.129
+199.7.83.42
+202.12.27.33
diff --git a/dnscache-run/run b/dnscache-run/run
new file mode 100644 (file)
index 0000000..02427e5
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+exec 2>&1
+exec <seed
+exec envdir ./env sh -c '
+  exec envuidgid Gdnscache softlimit -o250 -d "$DATALIMIT" /usr/bin/dnscache
+'