Imported Debian patch 1:1.05-8
[hcoop/zz_old/debian/djbdns.git] / dbndns / diff / 0002-Apply-fefe-s-djbdns-1.05-test23-ipv6-patch.diff
CommitLineData
b4588d5c
GP
1From 816e84a7c1357b9a60cc2102f4641735cae3a34b Mon Sep 17 00:00:00 2001
2From: Gerrit Pape <pape@smarden.org>
3Date: Mon, 12 May 2008 16:51:21 +0000
4Subject: [PATCH] Apply fefe's djbdns-1.05-test23 ipv6 patch.
5
6What is djbdns and why does it need IPv6?
7
8Most people agree that IPv6 will come sooner or later, but obviously you
9need a DNS infrastructure that supports IPv6. djbdns is a full blown
10DNS server which outperforms BIND in nearly all respects. However, it
11does not support IPv6 out of the box.
12
13Fortunately, Dan Bernstein (the author of djbdns) has defined a very
14clean API that made the conversion possible in a few days.
15
16What does your diff do?
17
18The current version adds support for AAAA records (those are the DNS
19records that store IPv6 numbers). tinydns-conf will now create
20/etc/tinydns/add-host6 and /etc/tinydns/add-alias6, and data can now
21contain records of type "6" and "3". Also, dnsq now understand AAAA
22records and a new program called "dnsip6" is the IPv6 equivalent of the
23old dnsip. [new] Automatic internal lookup of some reserved IPv6
24addresses (like "::1"). There is also experimental IPv6 transport
25support.
26
27This diff also integrates an ipv6 port of Russ Nelson's anti-Verisign
28patch. Boycott saboteurs!
29
30What does not work yet?
31
32tinydns-edit won't accept IPv6 addresses for NS or MX records yet. I
33haven't even started to look at axfr, but it should just work if you use
34my IPv6 patches for ucspi-tcp.
35
36How do reverse lookups work?
37
38The reverse lookup for 2001:658:0:2:2e0:18ff:fe98:b03d looks like this:
39
40d.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
41
42My patch will put a record like this in your data.cdb, but you still
43need to get a delegation for your range. For a /64, the delegation
44would mean leaving half the digits away, as in
452.0.0.0.0.0.0.0.8.5.6.0.1.0.0.2.ip6.int. Talk to your ISP about this!
46
47There also is a supposedly new and better scheme for doing DNS for IPv6,
48and it employs bit strings, DNAME and A6 records, which are really
49broken by design. Dan has a good write-up about this issue. Rumour has
50it that the IETF has seen the light and killed this mindblowingly bad
51proposal. I have not implemented it and probably will not in the
52future. It involves the domain ip6.arpa, in case you see that
53somewhere. (News July 2002: The IEFT really has seen the light)
54---
55 FILES | 11 +++
56 Makefile | 160 +++++++++++++++++++++++++++++----
57 TARGETS | 25 +++++
58 axfr-get.c | 9 ++
59 dns.h | 15 +++-
60 dns_ip6.c | 103 +++++++++++++++++++++
61 dns_ipq6.c | 72 +++++++++++++++
62 dns_name.c | 22 +++++
63 dns_nd6.c | 35 +++++++
64 dns_rcip.c | 25 +++---
65 dns_resolve.c | 5 +-
66 dns_sortip6.c | 20 ++++
67 dns_transmit.c | 25 +++---
68 dnscache.c | 64 ++++++++++----
69 dnsfilter.c | 5 +-
70 dnsip6.c | 40 ++++++++
71 dnsip6q.c | 43 +++++++++
72 dnsname.c | 15 +++-
73 dnsq.c | 13 ++--
74 dnstrace.c | 50 +++++++----
75 error.h | 2 +-
76 fmt_xlong.c | 22 +++++
77 haveip6.h1 | 1 +
78 haveip6.h2 | 1 +
79 haven2i.h1 | 1 +
80 haven2i.h2 | 1 +
81 hier.c | 2 +
82 ip6.h | 28 ++++++
83 ip6_fmt.c | 60 +++++++++++++
84 ip6_scan.c | 115 ++++++++++++++++++++++++
85 log.c | 39 ++++----
86 okclient.c | 18 +++-
87 printrecord.c | 10 ++
88 qlog.c | 10 +-
89 query.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++-----
90 query.h | 7 +-
91 roots.c | 17 ++--
92 scan_xlong.c | 23 +++++
93 server.c | 100 +++++++++++++++++----
94 sockaddr_in6.h1 | 21 +++++
95 sockaddr_in6.h2 | 4 +
96 socket.h | 18 ++++-
97 socket_accept6.c | 43 +++++++++
98 socket_bind.c | 2 +-
99 socket_bind6.c | 43 +++++++++
100 socket_connect6.c | 39 ++++++++
101 socket_getifidx.c | 13 +++
102 socket_noipv6.c | 7 ++
103 socket_recv6.c | 42 +++++++++
104 socket_send6.c | 39 ++++++++
105 socket_tcp6.c | 44 +++++++++
106 socket_udp6.c | 43 +++++++++
107 tdlookup.c | 54 ++++++++---
108 tinydns-conf.c | 12 +++
109 tinydns-data.c | 30 ++++++
110 tinydns-edit.c | 35 +++++++-
111 tryip6.c | 8 ++
112 tryn2i.c | 8 ++
113 trysa6.c | 8 ++
114 59 files changed, 1786 insertions(+), 197 deletions(-)
115 create mode 100644 dns_ip6.c
116 create mode 100644 dns_ipq6.c
117 create mode 100644 dns_nd6.c
118 create mode 100644 dns_sortip6.c
119 create mode 100644 dnsip6.c
120 create mode 100644 dnsip6q.c
121 create mode 100644 fmt_xlong.c
122 create mode 100644 haveip6.h1
123 create mode 100644 haveip6.h2
124 create mode 100644 haven2i.h1
125 create mode 100644 haven2i.h2
126 create mode 100644 ip6.h
127 create mode 100644 ip6_fmt.c
128 create mode 100644 ip6_scan.c
129 create mode 100644 scan_xlong.c
130 create mode 100644 sockaddr_in6.h1
131 create mode 100644 sockaddr_in6.h2
132 create mode 100644 socket_accept6.c
133 create mode 100644 socket_bind6.c
134 create mode 100644 socket_connect6.c
135 create mode 100644 socket_getifidx.c
136 create mode 100644 socket_noipv6.c
137 create mode 100644 socket_recv6.c
138 create mode 100644 socket_send6.c
139 create mode 100644 socket_tcp6.c
140 create mode 100644 socket_udp6.c
141 create mode 100644 tryip6.c
142 create mode 100644 tryn2i.c
143 create mode 100644 trysa6.c
144
145diff --git a/FILES b/FILES
146index 7adf6d4..27a4e26 100644
147--- a/FILES
148+++ b/FILES
149@@ -135,6 +135,7 @@ error_str.c
150 exit.h
151 fmt.h
152 fmt_ulong.c
153+fmt_xlong.c
154 gen_alloc.h
155 gen_allocdefs.h
156 getln.c
157@@ -151,6 +152,9 @@ iopause.h2
158 ip4.h
159 ip4_fmt.c
160 ip4_scan.c
161+ip6.h
162+ip6_fmt.c
163+ip6_scan.c
164 ndelay.h
165 ndelay_off.c
166 ndelay_on.c
167@@ -164,6 +168,7 @@ prot.h
168 readclose.c
169 readclose.h
170 scan.h
171+scan_0x.c
172 scan_ulong.c
173 seek.h
174 seek_set.c
175@@ -241,3 +246,9 @@ uint64.h2
176 warn-shsgr
177 buffer_read.c
178 buffer_write.c
179+dns_nd6.c
180+socket_udp6.c
181+socket_getifidx.c
182+tryn2i.c
183+haven2i.h1
184+haven2i.h2
185diff --git a/Makefile b/Makefile
186index 1429643..44bd989 100644
187--- a/Makefile
188+++ b/Makefile
189@@ -120,12 +120,14 @@ makelib byte_chr.o byte_copy.o byte_cr.o byte_diff.o byte_zero.o \
190 case_diffb.o case_diffs.o case_lowerb.o fmt_ulong.o ip4_fmt.o \
191 ip4_scan.o scan_ulong.o str_chr.o str_diff.o str_len.o str_rchr.o \
192 str_start.o uint16_pack.o uint16_unpack.o uint32_pack.o \
193-uint32_unpack.o
194+uint32_unpack.o ip6_fmt.o ip6_scan.o fmt_xlong.o \
195+scan_xlong.o
196 ./makelib byte.a byte_chr.o byte_copy.o byte_cr.o \
197 byte_diff.o byte_zero.o case_diffb.o case_diffs.o \
198 case_lowerb.o fmt_ulong.o ip4_fmt.o ip4_scan.o scan_ulong.o \
199 str_chr.o str_diff.o str_len.o str_rchr.o str_start.o \
200- uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o
201+ uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o \
202+ ip6_fmt.o ip6_scan.o fmt_xlong.o scan_xlong.o
203
204 byte_chr.o: \
205 compile byte_chr.c byte.h
206@@ -228,11 +230,13 @@ choose compile trydrent.c direntry.h1 direntry.h2
207 dns.a: \
208 makelib dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o dns_ipq.o dns_mx.o \
209 dns_name.o dns_nd.o dns_packet.o dns_random.o dns_rcip.o dns_rcrw.o \
210-dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o
211+dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o dns_ip6.o \
212+dns_sortip6.o dns_nd6.o dns_ipq6.o
213 ./makelib dns.a dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o \
214 dns_ipq.o dns_mx.o dns_name.o dns_nd.o dns_packet.o \
215 dns_random.o dns_rcip.o dns_rcrw.o dns_resolve.o \
216- dns_sortip.o dns_transmit.o dns_txt.o
217+ dns_sortip.o dns_transmit.o dns_txt.o dns_ip6.o dns_sortip6.o \
218+ dns_nd6.o dns_ipq6.o
219
220 dns_dfd.o: \
221 compile dns_dfd.c error.h alloc.h byte.h dns.h stralloc.h gen_alloc.h \
222@@ -254,11 +258,21 @@ compile dns_ip.c stralloc.h gen_alloc.h uint16.h byte.h dns.h \
223 stralloc.h iopause.h taia.h tai.h uint64.h taia.h
224 ./compile dns_ip.c
225
226+dns_ip6.o: \
227+compile dns_ip6.c stralloc.h gen_alloc.h uint16.h byte.h dns.h \
228+stralloc.h iopause.h taia.h tai.h uint64.h taia.h
229+ ./compile dns_ip6.c
230+
231 dns_ipq.o: \
232 compile dns_ipq.c stralloc.h gen_alloc.h case.h byte.h str.h dns.h \
233 stralloc.h iopause.h taia.h tai.h uint64.h taia.h
234 ./compile dns_ipq.c
235
236+dns_ipq6.o: \
237+compile dns_ipq6.c stralloc.h gen_alloc.h case.h byte.h str.h dns.h \
238+stralloc.h iopause.h taia.h tai.h uint64.h taia.h
239+ ./compile dns_ipq6.c
240+
241 dns_mx.o: \
242 compile dns_mx.c stralloc.h gen_alloc.h byte.h uint16.h dns.h \
243 stralloc.h iopause.h taia.h tai.h uint64.h taia.h
244@@ -274,6 +288,11 @@ compile dns_nd.c byte.h fmt.h dns.h stralloc.h gen_alloc.h iopause.h \
245 taia.h tai.h uint64.h taia.h
246 ./compile dns_nd.c
247
248+dns_nd6.o: \
249+compile dns_nd6.c byte.h fmt.h dns.h stralloc.h gen_alloc.h iopause.h \
250+taia.h tai.h uint64.h taia.h
251+ ./compile dns_nd6.c
252+
253 dns_packet.o: \
254 compile dns_packet.c error.h dns.h stralloc.h gen_alloc.h iopause.h \
255 taia.h tai.h uint64.h taia.h
256@@ -306,6 +325,11 @@ compile dns_sortip.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \
257 taia.h tai.h uint64.h taia.h
258 ./compile dns_sortip.c
259
260+dns_sortip6.o: \
261+compile dns_sortip6.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \
262+taia.h tai.h uint64.h taia.h
263+ ./compile dns_sortip6.c
264+
265 dns_transmit.o: \
266 compile dns_transmit.c socket.h uint16.h alloc.h error.h byte.h \
267 uint16.h dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h \
268@@ -369,6 +393,17 @@ compile dnsip.c buffer.h exit.h strerr.h ip4.h dns.h stralloc.h \
269 gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h
270 ./compile dnsip.c
271
272+dnsip6: \
273+load dnsip6.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \
274+byte.a socket.lib
275+ ./load dnsip6 iopause.o dns.a env.a libtai.a alloc.a \
276+ buffer.a unix.a byte.a `cat socket.lib`
277+
278+dnsip6.o: \
279+compile dnsip6.c buffer.h exit.h strerr.h ip6.h dns.h stralloc.h \
280+gen_alloc.h iopause.h taia.h tai.h uint64.h
281+ ./compile dnsip6.c
282+
283 dnsipq: \
284 load dnsipq.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \
285 byte.a socket.lib
286@@ -380,6 +415,17 @@ compile dnsipq.c buffer.h exit.h strerr.h ip4.h dns.h stralloc.h \
287 gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h
288 ./compile dnsipq.c
289
290+dnsip6q: \
291+load dnsip6q.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \
292+byte.a socket.lib
293+ ./load dnsip6q iopause.o dns.a env.a libtai.a alloc.a \
294+ buffer.a unix.a byte.a `cat socket.lib`
295+
296+dnsip6q.o: \
297+compile dnsip6q.c buffer.h exit.h strerr.h ip4.h dns.h stralloc.h \
298+gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h
299+ ./compile dnsip6q.c
300+
301 dnsmx: \
302 load dnsmx.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \
303 byte.a socket.lib
304@@ -399,7 +445,7 @@ byte.a socket.lib
305
306 dnsname.o: \
307 compile dnsname.c buffer.h exit.h strerr.h ip4.h dns.h stralloc.h \
308-gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h
309+gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h ip6.h
310 ./compile dnsname.c
311
312 dnsq: \
313@@ -484,6 +530,10 @@ fmt_ulong.o: \
314 compile fmt_ulong.c fmt.h
315 ./compile fmt_ulong.c
316
317+fmt_xlong.o: \
318+compile fmt_xlong.c scan.h
319+ ./compile fmt_xlong.c
320+
321 generic-conf.o: \
322 compile generic-conf.c strerr.h buffer.h open.h generic-conf.h \
323 buffer.h
324@@ -546,10 +596,18 @@ ip4_fmt.o: \
325 compile ip4_fmt.c fmt.h ip4.h
326 ./compile ip4_fmt.c
327
328+ip6_fmt.o: \
329+compile ip6_fmt.c fmt.h ip6.h
330+ ./compile ip6_fmt.c
331+
332 ip4_scan.o: \
333 compile ip4_scan.c scan.h ip4.h
334 ./compile ip4_scan.c
335
336+ip6_scan.o: \
337+compile ip6_scan.c scan.h ip6.h
338+ ./compile ip6_scan.c
339+
340 it: \
341 prog install instcheck
342
343@@ -626,9 +684,9 @@ iopause.h taia.h tai.h uint64.h taia.h uint16.h parsetype.h
344 ./compile parsetype.c
345
346 pickdns: \
347-load pickdns.o server.o response.o droproot.o qlog.o prot.o dns.a \
348+load pickdns.o server.o iopause.o response.o droproot.o qlog.o prot.o dns.a \
349 env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib
350- ./load pickdns server.o response.o droproot.o qlog.o \
351+ ./load pickdns server.o iopause.o response.o droproot.o qlog.o \
352 prot.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \
353 byte.a `cat socket.lib`
354
355@@ -677,7 +735,7 @@ dnscache-conf dnscache walldns-conf walldns rbldns-conf rbldns \
356 rbldns-data pickdns-conf pickdns pickdns-data tinydns-conf tinydns \
357 tinydns-data tinydns-get tinydns-edit axfr-get axfrdns-conf axfrdns \
358 dnsip dnsipq dnsname dnstxt dnsmx dnsfilter random-ip dnsqr dnsq \
359-dnstrace dnstracesort cachetest utime rts
360+dnstrace dnstracesort cachetest utime rts dnsip6 dnsip6q
361
362 prot.o: \
363 compile prot.c hasshsgr.h prot.h
364@@ -704,9 +762,9 @@ gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h
365 ./compile random-ip.c
366
367 rbldns: \
368-load rbldns.o server.o response.o dd.o droproot.o qlog.o prot.o dns.a \
369+load rbldns.o server.o iopause.o response.o dd.o droproot.o qlog.o prot.o dns.a \
370 env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib
371- ./load rbldns server.o response.o dd.o droproot.o qlog.o \
372+ ./load rbldns server.o iopause.o response.o dd.o droproot.o qlog.o \
373 prot.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \
374 byte.a `cat socket.lib`
375
376@@ -762,6 +820,10 @@ scan_ulong.o: \
377 compile scan_ulong.c scan.h
378 ./compile scan_ulong.c
379
380+scan_xlong.o: \
381+compile scan_xlong.c scan.h
382+ ./compile scan_xlong.c
383+
384 seek_set.o: \
385 compile seek_set.c seek.h
386 ./compile seek_set.c
387@@ -774,7 +836,7 @@ server.o: \
388 compile server.c byte.h case.h env.h buffer.h strerr.h ip4.h uint16.h \
389 ndelay.h socket.h uint16.h droproot.h qlog.h uint16.h response.h \
390 uint32.h dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h \
391-taia.h
392+taia.h iopause.h alloc.h str.h
393 ./compile server.c
394
395 setup: \
396@@ -796,14 +858,26 @@ socket_accept.o: \
397 compile socket_accept.c byte.h socket.h uint16.h
398 ./compile socket_accept.c
399
400+socket_accept6.o: \
401+compile socket_accept6.c byte.h socket.h uint16.h
402+ ./compile socket_accept6.c
403+
404 socket_bind.o: \
405 compile socket_bind.c byte.h socket.h uint16.h
406 ./compile socket_bind.c
407
408+socket_bind6.o: \
409+compile socket_bind6.c sockaddr_in6.h haveip6.h byte.h socket.h uint16.h uint32.h ip6.h error.h
410+ ./compile socket_bind6.c
411+
412 socket_conn.o: \
413 compile socket_conn.c byte.h socket.h uint16.h
414 ./compile socket_conn.c
415
416+socket_connect6.o: \
417+compile socket_connect6.c byte.h socket.h uint16.h uint32.h
418+ ./compile socket_connect6.c
419+
420 socket_listen.o: \
421 compile socket_listen.c socket.h uint16.h
422 ./compile socket_listen.c
423@@ -812,18 +886,47 @@ socket_recv.o: \
424 compile socket_recv.c byte.h socket.h uint16.h
425 ./compile socket_recv.c
426
427+socket_recv6.o: \
428+compile socket_recv6.c sockaddr_in6.h haveip6.h byte.h socket.h uint16.h uint32.h ip6.h error.h
429+ ./compile socket_recv6.c
430+
431 socket_send.o: \
432 compile socket_send.c byte.h socket.h uint16.h
433 ./compile socket_send.c
434
435+socket_send6.o: \
436+compile socket_send6.c byte.h socket.h uint16.h uint32.h ip6.h haveip6.h error.h
437+ ./compile socket_send6.c
438+
439 socket_tcp.o: \
440 compile socket_tcp.c ndelay.h socket.h uint16.h
441 ./compile socket_tcp.c
442
443+socket_tcp6.o: \
444+compile socket_tcp6.c ndelay.h socket.h uint16.h uint32.h haveip6.h
445+ ./compile socket_tcp6.c
446+
447 socket_udp.o: \
448 compile socket_udp.c ndelay.h socket.h uint16.h
449 ./compile socket_udp.c
450
451+socket_udp6.o: \
452+compile socket_udp6.c ndelay.h socket.h uint16.h uint32.h haveip6.h
453+ ./compile socket_udp6.c
454+
455+socket_noipv6.o: \
456+compile socket_noipv6.c haveip6.h
457+ ./compile socket_noipv6.c
458+
459+socket_getifidx.o: \
460+compile socket_getifidx.c socket.h uint16.h uint32.h haven2i.h
461+ ./compile socket_getifidx.c
462+
463+haven2i.h: \
464+tryn2i.c choose compile load socket.lib haven2i.h1 haven2i.h2
465+ cp /dev/null haven2i.h
466+ ./choose cL tryn2i haven2i.h1 haven2i.h2 socket > haven2i.h
467+
468 str_chr.o: \
469 compile str_chr.c str.h
470 ./compile str_chr.c
471@@ -965,7 +1068,7 @@ compile taia_uint.c taia.h tai.h uint64.h
472 tdlookup.o: \
473 compile tdlookup.c uint16.h open.h tai.h uint64.h cdb.h uint32.h \
474 byte.h case.h dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h \
475-taia.h seek.h response.h uint32.h
476+taia.h seek.h response.h uint32.h ip6.h
477 ./compile tdlookup.c
478
479 timeoutread.o: \
480@@ -979,10 +1082,10 @@ timeoutwrite.h
481 ./compile timeoutwrite.c
482
483 tinydns: \
484-load tinydns.o server.o droproot.o tdlookup.o response.o qlog.o \
485+load tinydns.o server.o iopause.o droproot.o tdlookup.o response.o qlog.o \
486 prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a byte.a \
487 socket.lib
488- ./load tinydns server.o droproot.o tdlookup.o response.o \
489+ ./load tinydns server.o iopause.o droproot.o tdlookup.o response.o \
490 qlog.o prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a \
491 unix.a byte.a `cat socket.lib`
492
493@@ -1005,7 +1108,7 @@ tinydns-data.o: \
494 compile tinydns-data.c uint16.h uint32.h str.h byte.h fmt.h ip4.h \
495 exit.h case.h scan.h buffer.h strerr.h getln.h buffer.h stralloc.h \
496 gen_alloc.h cdb_make.h buffer.h uint32.h stralloc.h open.h dns.h \
497-stralloc.h iopause.h taia.h tai.h uint64.h taia.h
498+stralloc.h iopause.h taia.h tai.h uint64.h taia.h ip6.h
499 ./compile tinydns-data.c
500
501 tinydns-edit: \
502@@ -1068,12 +1171,18 @@ unix.a: \
503 makelib buffer_read.o buffer_write.o error.o error_str.o ndelay_off.o \
504 ndelay_on.o open_read.o open_trunc.o openreadclose.o readclose.o \
505 seek_set.o socket_accept.o socket_bind.o socket_conn.o \
506-socket_listen.o socket_recv.o socket_send.o socket_tcp.o socket_udp.o
507+socket_listen.o socket_recv.o socket_send.o socket_tcp.o socket_udp.o \
508+socket_udp6.o socket_getifidx.o socket_recv6.o socket_send6.o \
509+socket_bind6.o socket_noipv6.o socket_tcp6.o socket_connect6.o \
510+socket_accept6.o
511 ./makelib unix.a buffer_read.o buffer_write.o error.o \
512 error_str.o ndelay_off.o ndelay_on.o open_read.o \
513 open_trunc.o openreadclose.o readclose.o seek_set.o \
514 socket_accept.o socket_bind.o socket_conn.o socket_listen.o \
515- socket_recv.o socket_send.o socket_tcp.o socket_udp.o
516+ socket_recv.o socket_send.o socket_tcp.o socket_udp.o \
517+ socket_udp6.o socket_getifidx.o socket_recv6.o socket_send6.o \
518+ socket_bind6.o socket_noipv6.o socket_tcp6.o socket_connect6.o \
519+ socket_accept6.o
520
521 utime: \
522 load utime.o byte.a
523@@ -1084,10 +1193,10 @@ compile utime.c scan.h exit.h
524 ./compile utime.c
525
526 walldns: \
527-load walldns.o server.o response.o droproot.o qlog.o prot.o dd.o \
528+load walldns.o server.o iopause.o response.o droproot.o qlog.o prot.o dd.o \
529 dns.a env.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib
530- ./load walldns server.o response.o droproot.o qlog.o \
531- prot.o dd.o dns.a env.a cdb.a alloc.a buffer.a unix.a \
532+ ./load walldns server.o iopause.o response.o droproot.o qlog.o \
533+ prot.o dd.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a \
534 byte.a `cat socket.lib`
535
536 walldns-conf: \
537@@ -1104,3 +1213,14 @@ walldns.o: \
538 compile walldns.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \
539 taia.h tai.h uint64.h taia.h dd.h response.h uint32.h
540 ./compile walldns.c
541+
542+haveip6.h: \
543+tryip6.c choose compile haveip6.h1 haveip6.h2
544+ ./choose c tryip6 haveip6.h1 haveip6.h2 > haveip6.h
545+
546+sockaddr_in6.h: \
547+trysa6.c choose compile sockaddr_in6.h1 sockaddr_in6.h2 haveip6.h
548+ ./choose c trysa6 sockaddr_in6.h1 sockaddr_in6.h2 > sockaddr_in6.h
549+
550+clean:
551+ rm -f `cat TARGETS`
552diff --git a/TARGETS b/TARGETS
553index 2490b1a..afc4c49 100644
554--- a/TARGETS
555+++ b/TARGETS
556@@ -102,6 +102,7 @@ dns_domain.o
557 dns_dtda.o
558 dns_ip.o
559 dns_ipq.o
560+dns_ipq6.o
561 dns_mx.o
562 dns_name.o
563 dns_nd.o
564@@ -180,6 +181,8 @@ dnsip.o
565 dnsip
566 dnsipq.o
567 dnsipq
568+dnsip6q.o
569+dnsip6q
570 dnsname.o
571 dnsname
572 dnstxt.o
573@@ -214,3 +217,25 @@ instcheck
574 it
575 setup
576 check
577+scan_0x.o
578+fmt_xlong.o
579+ip6_scan.o
580+ip6_fmt.o
581+dnsip6.o
582+dns_ip6.o
583+dns_sortip6.o
584+dnsip6
585+dns_nd6.o
586+socket_udp6.o
587+socket_getifidx.o
588+socket_bind6.o
589+socket_noipv6.o
590+socket_recv6.o
591+socket_send6.o
592+haveip6.h
593+haven2i.h
594+sockaddr_in6.h
595+scan_xlong.o
596+socket_accept6.o
597+socket_connect6.o
598+socket_tcp6.o
599diff --git a/axfr-get.c b/axfr-get.c
600index 75db627..f6bf5bd 100644
601--- a/axfr-get.c
602+++ b/axfr-get.c
603@@ -13,6 +13,7 @@
604 #include "byte.h"
605 #include "str.h"
606 #include "ip4.h"
607+#include "ip6.h"
608 #include "timeoutread.h"
609 #include "timeoutwrite.h"
610 #include "dns.h"
611@@ -217,6 +218,14 @@ unsigned int doit(char *buf,unsigned int len,unsigned int pos)
612 x_copy(buf,len,pos,data,4);
613 if (!stralloc_catb(&line,ipstr,ip4_fmt(ipstr,data))) return 0;
614 }
615+ else if (byte_equal(data,2,DNS_T_AAAA)) {
616+ char ipstr[IP6_FMT];
617+ if (!stralloc_copys(&line,"3")) return 0;
618+ if (!dns_domain_todot_cat(&line,d1)) return 0;
619+ if (!stralloc_cats(&line,":")) return 0;
620+ x_copy(buf,len,pos,data,16);
621+ if (!stralloc_catb(&line,ipstr,ip6_fmt_flat(ipstr,data))) return 0;
622+ }
623 else {
624 unsigned char ch;
625 unsigned char ch2;
626diff --git a/dns.h b/dns.h
627index 2f899ef..5398e2b 100644
628--- a/dns.h
629+++ b/dns.h
630@@ -35,7 +35,8 @@ struct dns_transmit {
631 struct taia deadline;
632 unsigned int pos;
633 const char *servers;
634- char localip[4];
635+ char localip[16];
636+ unsigned int scope_id;
637 char qtype[2];
638 } ;
639
640@@ -43,6 +44,7 @@ extern void dns_random_init(const char *);
641 extern unsigned int dns_random(unsigned int);
642
643 extern void dns_sortip(char *,unsigned int);
644+extern void dns_sortip6(char *,unsigned int);
645
646 extern void dns_domain_free(char **);
647 extern int dns_domain_copy(char **,const char *);
648@@ -68,10 +70,13 @@ extern struct dns_transmit dns_resolve_tx;
649
650 extern int dns_ip4_packet(stralloc *,const char *,unsigned int);
651 extern int dns_ip4(stralloc *,const stralloc *);
652+extern int dns_ip6_packet(stralloc *,char *,unsigned int);
653+extern int dns_ip6(stralloc *,stralloc *);
654 extern int dns_name_packet(stralloc *,const char *,unsigned int);
655 extern void dns_name4_domain(char *,const char *);
656 #define DNS_NAME4_DOMAIN 31
657 extern int dns_name4(stralloc *,const char *);
658+extern int dns_name6(stralloc *,const char *);
659 extern int dns_txt_packet(stralloc *,const char *,unsigned int);
660 extern int dns_txt(stralloc *,const stralloc *);
661 extern int dns_mx_packet(stralloc *,const char *,unsigned int);
662@@ -80,5 +85,13 @@ extern int dns_mx(stralloc *,const stralloc *);
663 extern int dns_resolvconfrewrite(stralloc *);
664 extern int dns_ip4_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *);
665 extern int dns_ip4_qualify(stralloc *,stralloc *,const stralloc *);
666+extern int dns_ip6_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *);
667+extern int dns_ip6_qualify(stralloc *,stralloc *,const stralloc *);
668+
669+#define DNS_IP6_INT 0
670+#define DNS_IP6_ARPA 1
671+
672+extern int dns_name6_domain(char *,const char *,int);
673+#define DNS_NAME6_DOMAIN (4*16+11)
674
675 #endif
676diff --git a/dns_ip6.c b/dns_ip6.c
677new file mode 100644
678index 0000000..30ce699
679--- /dev/null
680+++ b/dns_ip6.c
681@@ -0,0 +1,103 @@
682+#include "stralloc.h"
683+#include "uint16.h"
684+#include "byte.h"
685+#include "dns.h"
686+#include "ip4.h"
687+#include "ip6.h"
688+
689+static int dns_ip6_packet_add(stralloc *out,char *buf,unsigned int len)
690+{
691+ unsigned int pos;
692+ char header[16];
693+ uint16 numanswers;
694+ uint16 datalen;
695+
696+ pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1;
697+ uint16_unpack_big(header + 6,&numanswers);
698+ pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
699+ pos += 4;
700+
701+ while (numanswers--) {
702+ pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1;
703+ pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1;
704+ uint16_unpack_big(header + 8,&datalen);
705+ if (byte_equal(header,2,DNS_T_AAAA)) {
706+ if (byte_equal(header + 2,2,DNS_C_IN))
707+ if (datalen == 16) {
708+ if (!dns_packet_copy(buf,len,pos,header,16)) return -1;
709+ if (!stralloc_catb(out,header,16)) return -1;
710+ }
711+ } else if (byte_equal(header,2,DNS_T_A))
712+ if (byte_equal(header + 2,2,DNS_C_IN))
713+ if (datalen == 4) {
714+ byte_copy(header,12,V4mappedprefix);
715+ if (!dns_packet_copy(buf,len,pos,header+12,4)) return -1;
716+ if (!stralloc_catb(out,header,16)) return -1;
717+ }
718+ pos += datalen;
719+ }
720+
721+ dns_sortip6(out->s,out->len);
722+ return 0;
723+}
724+
725+int dns_ip6_packet(stralloc *out,char *buf,unsigned int len) {
726+ if (!stralloc_copys(out,"")) return -1;
727+ return dns_ip6_packet_add(out,buf,len);
728+}
729+
730+static char *q = 0;
731+
732+int dns_ip6(stralloc *out,stralloc *fqdn)
733+{
734+ unsigned int i;
735+ char code;
736+ char ch;
737+ char ip[16];
738+
739+ if (!stralloc_copys(out,"")) return -1;
740+ if (!stralloc_readyplus(fqdn,1)) return -1;
741+ fqdn->s[fqdn->len]=0;
742+ if ((i=ip6_scan(fqdn->s,ip))) {
743+ if (fqdn->s[i]) return -1;
744+ stralloc_copyb(out,ip,16);
745+ return 0;
746+ }
747+ code = 0;
748+ for (i = 0;i <= fqdn->len;++i) {
749+ if (i < fqdn->len)
750+ ch = fqdn->s[i];
751+ else
752+ ch = '.';
753+
754+ if ((ch == '[') || (ch == ']')) continue;
755+ if (ch == '.') {
756+ if (!stralloc_append(out,&code)) return -1;
757+ code = 0;
758+ continue;
759+ }
760+ if ((ch >= '0') && (ch <= '9')) {
761+ code *= 10;
762+ code += ch - '0';
763+ continue;
764+ }
765+
766+ if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
767+ if (!stralloc_copys(out,"")) return -1;
768+ if (dns_resolve(q,DNS_T_AAAA) != -1)
769+ if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) {
770+ dns_transmit_free(&dns_resolve_tx);
771+ dns_domain_free(&q);
772+ }
773+ if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1;
774+ if (dns_resolve(q,DNS_T_A) != -1)
775+ if (dns_ip6_packet_add(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) != -1) {
776+ dns_transmit_free(&dns_resolve_tx);
777+ dns_domain_free(&q);
778+ }
779+ return out->a>0?0:-1;
780+ }
781+
782+ out->len &= ~3;
783+ return 0;
784+}
785diff --git a/dns_ipq6.c b/dns_ipq6.c
786new file mode 100644
787index 0000000..d5cea12
788--- /dev/null
789+++ b/dns_ipq6.c
790@@ -0,0 +1,72 @@
791+#include "stralloc.h"
792+#include "case.h"
793+#include "byte.h"
794+#include "str.h"
795+#include "dns.h"
796+
797+static int doit(stralloc *work,const char *rule)
798+{
799+ char ch;
800+ unsigned int colon;
801+ unsigned int prefixlen;
802+
803+ ch = *rule++;
804+ if ((ch != '?') && (ch != '=') && (ch != '*') && (ch != '-')) return 1;
805+ colon = str_chr(rule,':');
806+ if (!rule[colon]) return 1;
807+
808+ if (work->len < colon) return 1;
809+ prefixlen = work->len - colon;
810+ if ((ch == '=') && prefixlen) return 1;
811+ if (case_diffb(rule,colon,work->s + prefixlen)) return 1;
812+ if (ch == '?') {
813+ if (byte_chr(work->s,prefixlen,'.') < prefixlen) return 1;
814+ if (byte_chr(work->s,prefixlen,':') < prefixlen) return 1;
815+ if (byte_chr(work->s,prefixlen,'[') < prefixlen) return 1;
816+ if (byte_chr(work->s,prefixlen,']') < prefixlen) return 1;
817+ }
818+
819+ work->len = prefixlen;
820+ if (ch == '-') work->len = 0;
821+ return stralloc_cats(work,rule + colon + 1);
822+}
823+
824+int dns_ip6_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules)
825+{
826+ unsigned int i;
827+ unsigned int j;
828+ unsigned int plus;
829+ unsigned int fqdnlen;
830+
831+ if (!stralloc_copy(fqdn,in)) return -1;
832+
833+ for (j = i = 0;j < rules->len;++j)
834+ if (!rules->s[j]) {
835+ if (!doit(fqdn,rules->s + i)) return -1;
836+ i = j + 1;
837+ }
838+
839+ fqdnlen = fqdn->len;
840+ plus = byte_chr(fqdn->s,fqdnlen,'+');
841+ if (plus >= fqdnlen)
842+ return dns_ip6(out,fqdn);
843+
844+ i = plus + 1;
845+ for (;;) {
846+ j = byte_chr(fqdn->s + i,fqdnlen - i,'+');
847+ byte_copy(fqdn->s + plus,j,fqdn->s + i);
848+ fqdn->len = plus + j;
849+ if (dns_ip6(out,fqdn) == -1) return -1;
850+ if (out->len) return 0;
851+ i += j;
852+ if (i >= fqdnlen) return 0;
853+ ++i;
854+ }
855+}
856+
857+int dns_ip6_qualify(stralloc *out,stralloc *fqdn,const stralloc *in)
858+{
859+ static stralloc rules;
860+ if (dns_resolvconfrewrite(&rules) == -1) return -1;
861+ return dns_ip6_qualify_rules(out,fqdn,in,&rules);
862+}
863diff --git a/dns_name.c b/dns_name.c
864index 6f7cdc3..518a0c0 100644
865--- a/dns_name.c
866+++ b/dns_name.c
867@@ -2,6 +2,7 @@
868 #include "uint16.h"
869 #include "byte.h"
870 #include "dns.h"
871+#include "ip6.h"
872
873 static char *q = 0;
874
875@@ -46,3 +47,24 @@ int dns_name4(stralloc *out,const char ip[4])
876 dns_domain_free(&q);
877 return 0;
878 }
879+
880+int dns_name6_inner(stralloc *out,const char ip[16],int t)
881+{
882+ char name[DNS_NAME6_DOMAIN];
883+
884+ dns_name6_domain(name,ip,t);
885+ if (dns_resolve(name,DNS_T_PTR) == -1) return -1;
886+ if (dns_name_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1;
887+ dns_transmit_free(&dns_resolve_tx);
888+ dns_domain_free(&q);
889+ return 0;
890+}
891+
892+int dns_name6(stralloc *out,const char ip[16])
893+{
894+ if (ip6_isv4mapped(ip))
895+ return dns_name4(out,ip+12);
896+ if (dns_name6_inner(out,ip,DNS_IP6_ARPA)) return -1;
897+ if (!out->len) return dns_name6_inner(out,ip,DNS_IP6_INT);
898+ return 0;
899+}
900diff --git a/dns_nd6.c b/dns_nd6.c
901new file mode 100644
902index 0000000..6dbeb89
903--- /dev/null
904+++ b/dns_nd6.c
905@@ -0,0 +1,35 @@
906+#include "byte.h"
907+#include "fmt.h"
908+#include "dns.h"
909+
910+/* RFC1886:
911+ * 4321:0:1:2:3:4:567:89ab
912+ * ->
913+ * 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.
914+ * 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.
915+ */
916+
917+extern char tohex(char num);
918+
919+unsigned int mkint(unsigned char a,unsigned char b) {
920+ return ((unsigned int)a << 8) + (unsigned int)b;
921+}
922+
923+int dns_name6_domain(char name[DNS_NAME6_DOMAIN],const char ip[16],int t)
924+{
925+ unsigned int j;
926+
927+ for (j=0; j<16; j++) {
928+ name[j*4]=1;
929+ name[j*4+1]=tohex(ip[15-j] & 15);
930+ name[j*4+2]=1;
931+ name[j*4+3]=tohex((unsigned char)ip[15-j] >> 4);
932+ }
933+ if (t==DNS_IP6_INT)
934+ byte_copy(name + 4*16,9,"\3ip6\3int\0");
935+ else if (t==DNS_IP6_ARPA)
936+ byte_copy(name + 4*16,10,"\3ip6\4arpa\0");
937+ else return 0;
938+ return 4*16+9+t;
939+}
940+
941diff --git a/dns_rcip.c b/dns_rcip.c
942index 97bd8f5..efd1b21 100644
943--- a/dns_rcip.c
944+++ b/dns_rcip.c
945@@ -2,12 +2,13 @@
946 #include "openreadclose.h"
947 #include "byte.h"
948 #include "ip4.h"
949+#include "ip6.h"
950 #include "env.h"
951 #include "dns.h"
952
953 static stralloc data = {0};
954
955-static int init(char ip[64])
956+static int init(char ip[256])
957 {
958 int i;
959 int j;
960@@ -20,10 +21,10 @@ static int init(char ip[64])
961 if (*x == '.')
962 ++x;
963 else {
964- i = ip4_scan(x,ip + iplen);
965+ i = ip6_scan(x,ip + iplen);
966 if (!i) break;
967 x += i;
968- iplen += 4;
969+ iplen += 16;
970 }
971 }
972
973@@ -40,10 +41,8 @@ static int init(char ip[64])
974 while ((data.s[i] == ' ') || (data.s[i] == '\t'))
975 ++i;
976 if (iplen <= 60)
977- if (ip4_scan(data.s + i,ip + iplen)) {
978- if (byte_equal(ip + iplen,4,"\0\0\0\0"))
979- byte_copy(ip + iplen,4,"\177\0\0\1");
980- iplen += 4;
981+ if (ip6_scan(data.s + i,ip + iplen)) {
982+ iplen += 16;
983 }
984 }
985 i = j + 1;
986@@ -52,19 +51,19 @@ static int init(char ip[64])
987 }
988
989 if (!iplen) {
990- byte_copy(ip,4,"\177\0\0\1");
991- iplen = 4;
992+ byte_copy(ip,16,"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1");
993+ iplen = 16;
994 }
995- byte_zero(ip + iplen,64 - iplen);
996+ byte_zero(ip + iplen,256 - iplen);
997 return 0;
998 }
999
1000 static int ok = 0;
1001 static unsigned int uses;
1002 static struct taia deadline;
1003-static char ip[64]; /* defined if ok */
1004+static char ip[256]; /* defined if ok */
1005
1006-int dns_resolvconfip(char s[64])
1007+int dns_resolvconfip(char s[256])
1008 {
1009 struct taia now;
1010
1011@@ -81,6 +80,6 @@ int dns_resolvconfip(char s[64])
1012 }
1013
1014 --uses;
1015- byte_copy(s,64,ip);
1016+ byte_copy(s,256,ip);
1017 return 0;
1018 }
1019diff --git a/dns_resolve.c b/dns_resolve.c
1020index 8bdea0d..82b5bbb 100644
1021--- a/dns_resolve.c
1022+++ b/dns_resolve.c
1023@@ -2,6 +2,7 @@
1024 #include "taia.h"
1025 #include "byte.h"
1026 #include "dns.h"
1027+#include "ip6.h"
1028
1029 struct dns_transmit dns_resolve_tx = {0};
1030
1031@@ -9,12 +10,12 @@ int dns_resolve(const char *q,const char qtype[2])
1032 {
1033 struct taia stamp;
1034 struct taia deadline;
1035- char servers[64];
1036+ char servers[256];
1037 iopause_fd x[1];
1038 int r;
1039
1040 if (dns_resolvconfip(servers) == -1) return -1;
1041- if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,"\0\0\0\0") == -1) return -1;
1042+ if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,V6any) == -1) return -1;
1043
1044 for (;;) {
1045 taia_now(&stamp);
1046diff --git a/dns_sortip6.c b/dns_sortip6.c
1047new file mode 100644
1048index 0000000..7e752e9
1049--- /dev/null
1050+++ b/dns_sortip6.c
1051@@ -0,0 +1,20 @@
1052+#include "byte.h"
1053+#include "dns.h"
1054+
1055+/* XXX: sort servers by configurable notion of closeness? */
1056+/* XXX: pay attention to competence of each server? */
1057+
1058+void dns_sortip6(char *s,unsigned int n)
1059+{
1060+ unsigned int i;
1061+ char tmp[16];
1062+
1063+ n >>= 4;
1064+ while (n > 1) {
1065+ i = dns_random(n);
1066+ --n;
1067+ byte_copy(tmp,16,s + (i << 4));
1068+ byte_copy(s + (i << 4),16,s + (n << 4));
1069+ byte_copy(s + (n << 4),16,tmp);
1070+ }
1071+}
1072diff --git a/dns_transmit.c b/dns_transmit.c
1073index 4d6e39f..cba1fd2 100644
1074--- a/dns_transmit.c
1075+++ b/dns_transmit.c
1076@@ -7,6 +7,7 @@
1077 #include "byte.h"
1078 #include "uint16.h"
1079 #include "dns.h"
1080+#include "ip6.h"
1081
1082 static int serverwantstcp(const char *buf,unsigned int len)
1083 {
1084@@ -85,9 +86,9 @@ static int randombind(struct dns_transmit *d)
1085 int j;
1086
1087 for (j = 0;j < 10;++j)
1088- if (socket_bind4(d->s1 - 1,d->localip,1025 + dns_random(64510)) == 0)
1089+ if (socket_bind6(d->s1 - 1,d->localip,1025 + dns_random(64510),d->scope_id) == 0)
1090 return 0;
1091- if (socket_bind4(d->s1 - 1,d->localip,0) == 0)
1092+ if (socket_bind6(d->s1 - 1,d->localip,0,d->scope_id) == 0)
1093 return 0;
1094 return -1;
1095 }
1096@@ -102,16 +103,16 @@ static int thisudp(struct dns_transmit *d)
1097
1098 while (d->udploop < 4) {
1099 for (;d->curserver < 16;++d->curserver) {
1100- ip = d->servers + 4 * d->curserver;
1101- if (byte_diff(ip,4,"\0\0\0\0")) {
1102+ ip = d->servers + 16 * d->curserver;
1103+ if (byte_diff(ip,16,V6any)) {
1104 d->query[2] = dns_random(256);
1105 d->query[3] = dns_random(256);
1106
1107- d->s1 = 1 + socket_udp();
1108+ d->s1 = 1 + socket_udp6();
1109 if (!d->s1) { dns_transmit_free(d); return -1; }
1110 if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
1111
1112- if (socket_connect4(d->s1 - 1,ip,53) == 0)
1113+ if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0)
1114 if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) {
1115 struct taia now;
1116 taia_now(&now);
1117@@ -153,19 +154,19 @@ static int thistcp(struct dns_transmit *d)
1118 packetfree(d);
1119
1120 for (;d->curserver < 16;++d->curserver) {
1121- ip = d->servers + 4 * d->curserver;
1122- if (byte_diff(ip,4,"\0\0\0\0")) {
1123+ ip = d->servers + 16 * d->curserver;
1124+ if (byte_diff(ip,16,V6any)) {
1125 d->query[2] = dns_random(256);
1126 d->query[3] = dns_random(256);
1127
1128- d->s1 = 1 + socket_tcp();
1129+ d->s1 = 1 + socket_tcp6();
1130 if (!d->s1) { dns_transmit_free(d); return -1; }
1131 if (randombind(d) == -1) { dns_transmit_free(d); return -1; }
1132
1133 taia_now(&now);
1134 taia_uint(&d->deadline,10);
1135 taia_add(&d->deadline,&d->deadline,&now);
1136- if (socket_connect4(d->s1 - 1,ip,53) == 0) {
1137+ if (socket_connect6(d->s1 - 1,ip,53,d->scope_id) == 0) {
1138 d->tcpstate = 2;
1139 return 0;
1140 }
1141@@ -193,7 +194,7 @@ static int nexttcp(struct dns_transmit *d)
1142 return thistcp(d);
1143 }
1144
1145-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])
1146+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])
1147 {
1148 unsigned int len;
1149
1150@@ -213,7 +214,7 @@ int dns_transmit_start(struct dns_transmit *d,const char servers[64],int flagrec
1151
1152 byte_copy(d->qtype,2,qtype);
1153 d->servers = servers;
1154- byte_copy(d->localip,4,localip);
1155+ byte_copy(d->localip,16,localip);
1156
1157 d->udploop = flagrecursive ? 1 : 0;
1158
1159diff --git a/dnscache.c b/dnscache.c
1160index 8c899a3..abcba69 100644
1161--- a/dnscache.c
1162+++ b/dnscache.c
1163@@ -5,6 +5,7 @@
1164 #include "strerr.h"
1165 #include "error.h"
1166 #include "ip4.h"
1167+#include "ip6.h"
1168 #include "uint16.h"
1169 #include "uint64.h"
1170 #include "socket.h"
1171@@ -23,6 +24,10 @@
1172 #include "okclient.h"
1173 #include "droproot.h"
1174
1175+long interface;
1176+
1177+stralloc ignoreip = {0};
1178+
1179 static int packetquery(char *buf,unsigned int len,char **q,char qtype[2],char qclass[2],char id[2])
1180 {
1181 unsigned int pos;
1182@@ -46,8 +51,8 @@ static int packetquery(char *buf,unsigned int len,char **q,char qtype[2],char qc
1183 }
1184
1185
1186-static char myipoutgoing[4];
1187-static char myipincoming[4];
1188+static char myipoutgoing[16];
1189+static char myipincoming[16];
1190 static char buf[1024];
1191 uint64 numqueries = 0;
1192
1193@@ -60,9 +65,10 @@ static struct udpclient {
1194 struct taia start;
1195 uint64 active; /* query number, if active; otherwise 0 */
1196 iopause_fd *io;
1197- char ip[4];
1198+ char ip[16];
1199 uint16 port;
1200 char id[2];
1201+ uint32 scope_id;
1202 } u[MAXUDP];
1203 int uactive = 0;
1204
1205@@ -78,7 +84,7 @@ void u_respond(int j)
1206 if (!u[j].active) return;
1207 response_id(u[j].id);
1208 if (response_len > 512) response_tc();
1209- socket_send4(udp53,response,response_len,u[j].ip,u[j].port);
1210+ socket_send6(udp53,response,response_len,u[j].ip,u[j].port,u[j].scope_id);
1211 log_querydone(&u[j].active,response_len);
1212 u[j].active = 0; --uactive;
1213 }
1214@@ -109,7 +115,7 @@ void u_new(void)
1215 x = u + j;
1216 taia_now(&x->start);
1217
1218- len = socket_recv4(udp53,buf,sizeof buf,x->ip,&x->port);
1219+ len = socket_recv6(udp53,buf,sizeof buf,x->ip,&x->port,&x->scope_id);
1220 if (len == -1) return;
1221 if (len >= sizeof buf) return;
1222 if (x->port < 1024) if (x->port != 53) return;
1223@@ -119,7 +125,7 @@ void u_new(void)
1224
1225 x->active = ++numqueries; ++uactive;
1226 log_query(&x->active,x->ip,x->port,x->id,q,qtype);
1227- switch(query_start(&x->q,q,qtype,qclass,myipoutgoing)) {
1228+ switch(query_start(&x->q,q,qtype,qclass,myipoutgoing,interface)) {
1229 case -1:
1230 u_drop(j);
1231 return;
1232@@ -128,7 +134,6 @@ void u_new(void)
1233 }
1234 }
1235
1236-
1237 static int tcp53;
1238
1239 #define MAXTCP 20
1240@@ -138,7 +143,7 @@ struct tcpclient {
1241 struct taia timeout;
1242 uint64 active; /* query number or 1, if active; otherwise 0 */
1243 iopause_fd *io;
1244- char ip[4]; /* send response to this address */
1245+ char ip[16]; /* send response to this address */
1246 uint16 port; /* send response to this port */
1247 char id[2];
1248 int tcp; /* open TCP socket, if active */
1249@@ -146,6 +151,7 @@ struct tcpclient {
1250 char *buf; /* 0, or dynamically allocated of length len */
1251 unsigned int len;
1252 unsigned int pos;
1253+ uint32 scope_id;
1254 } t[MAXTCP];
1255 int tactive = 0;
1256
1257@@ -254,7 +260,7 @@ void t_rw(int j)
1258
1259 x->active = ++numqueries;
1260 log_query(&x->active,x->ip,x->port,x->id,q,qtype);
1261- switch(query_start(&x->q,q,qtype,qclass,myipoutgoing)) {
1262+ switch(query_start(&x->q,q,qtype,qclass,myipoutgoing,interface)) {
1263 case -1:
1264 t_drop(j);
1265 return;
1266@@ -291,7 +297,7 @@ void t_new(void)
1267 x = t + j;
1268 taia_now(&x->start);
1269
1270- x->tcp = socket_accept4(tcp53,x->ip,&x->port);
1271+ x->tcp = socket_accept6(tcp53,x->ip,&x->port,&x->scope_id);
1272 if (x->tcp == -1) return;
1273 if (x->port < 1024) if (x->port != 53) { close(x->tcp); return; }
1274 if (!okclient(x->ip)) { close(x->tcp); return; }
1275@@ -389,24 +395,36 @@ char seed[128];
1276 int main()
1277 {
1278 char *x;
1279+ unsigned int i, j, k;
1280 unsigned long cachesize;
1281+ static stralloc sa = {0};
1282+
1283+ x = env_get("INTERFACE");
1284+ if (x) scan_ulong(x,&interface);
1285
1286 x = env_get("IP");
1287 if (!x)
1288 strerr_die2x(111,FATAL,"$IP not set");
1289- if (!ip4_scan(x,myipincoming))
1290+ if (!ip6_scan(x,myipincoming))
1291 strerr_die3x(111,FATAL,"unable to parse IP address ",x);
1292
1293- udp53 = socket_udp();
1294+#if 0
1295+ /* if if IP is a mapped-IPv4 address, disable IPv6 functionality */
1296+ /* this is actually a bad idea */
1297+ if (ip6_isv4mapped(myipincoming))
1298+ noipv6 = 1;
1299+#endif
1300+
1301+ udp53 = socket_udp6();
1302 if (udp53 == -1)
1303 strerr_die2sys(111,FATAL,"unable to create UDP socket: ");
1304- if (socket_bind4_reuse(udp53,myipincoming,53) == -1)
1305+ if (socket_bind6_reuse(udp53,myipincoming,53,interface) == -1)
1306 strerr_die2sys(111,FATAL,"unable to bind UDP socket: ");
1307
1308- tcp53 = socket_tcp();
1309+ tcp53 = socket_tcp6();
1310 if (tcp53 == -1)
1311 strerr_die2sys(111,FATAL,"unable to create TCP socket: ");
1312- if (socket_bind4_reuse(tcp53,myipincoming,53) == -1)
1313+ if (socket_bind6_reuse(tcp53,myipincoming,53,interface) == -1)
1314 strerr_die2sys(111,FATAL,"unable to bind TCP socket: ");
1315
1316 droproot(FATAL);
1317@@ -421,7 +439,7 @@ int main()
1318 x = env_get("IPSEND");
1319 if (!x)
1320 strerr_die2x(111,FATAL,"$IPSEND not set");
1321- if (!ip4_scan(x,myipoutgoing))
1322+ if (!ip6_scan(x,myipoutgoing))
1323 strerr_die3x(111,FATAL,"unable to parse IP address ",x);
1324
1325 x = env_get("CACHESIZE");
1326@@ -431,6 +449,20 @@ int main()
1327 if (!cache_init(cachesize))
1328 strerr_die3x(111,FATAL,"not enough memory for cache of size ",x);
1329
1330+ if (openreadclose("ignoreip",&sa,64) < 0)
1331+ strerr_die2x(111,FATAL,"trouble reading ignoreip");
1332+ for(j = k = i = 0; i < sa.len; i++)
1333+ if (sa.s[i] == '\n') {
1334+ sa.s[i] = '\0';
1335+ if (!stralloc_readyplus(&ignoreip,16))
1336+ strerr_die2x(111,FATAL,"out of memory parsing ignoreip");
1337+ if (!ip6_scan(sa.s+k,ignoreip.s+j))
1338+ strerr_die3x(111,FATAL,"unable to parse address in ignoreip ",ignoreip.s+k);
1339+ j += 16;
1340+ k = i + 1;
1341+ }
1342+ ignoreip.len = j;
1343+
1344 if (env_get("HIDETTL"))
1345 response_hidettl();
1346 if (env_get("FORWARDONLY"))
1347diff --git a/dnsfilter.c b/dnsfilter.c
1348index 9e6863a..822ff1e 100644
1349--- a/dnsfilter.c
1350+++ b/dnsfilter.c
1351@@ -12,6 +12,7 @@
1352 #include "iopause.h"
1353 #include "error.h"
1354 #include "exit.h"
1355+#include "ip6.h"
1356
1357 #define FATAL "dnsfilter: fatal: "
1358
1359@@ -44,7 +45,7 @@ int flag0 = 1;
1360 iopause_fd *io;
1361 int iolen;
1362
1363-char servers[64];
1364+char servers[256];
1365 char ip[4];
1366 char name[DNS_NAME4_DOMAIN];
1367
1368@@ -191,7 +192,7 @@ int main(int argc,char **argv)
1369 dns_name4_domain(name,ip);
1370 if (dns_resolvconfip(servers) == -1)
1371 strerr_die2sys(111,FATAL,"unable to read /etc/resolv.conf: ");
1372- if (dns_transmit_start(&x[xnum].dt,servers,1,name,DNS_T_PTR,"\0\0\0\0") == -1)
1373+ if (dns_transmit_start(&x[xnum].dt,servers,1,name,DNS_T_PTR,V6any) == -1)
1374 errout(xnum);
1375 else {
1376 x[xnum].flagactive = 1;
1377diff --git a/dnsip6.c b/dnsip6.c
1378new file mode 100644
1379index 0000000..5b65823
1380--- /dev/null
1381+++ b/dnsip6.c
1382@@ -0,0 +1,40 @@
1383+#include "buffer.h"
1384+#include "exit.h"
1385+#include "strerr.h"
1386+#include "ip6.h"
1387+#include "dns.h"
1388+
1389+#define FATAL "dnsip: fatal: "
1390+
1391+static char seed[128];
1392+
1393+static stralloc fqdn;
1394+static stralloc out;
1395+char str[IP6_FMT];
1396+
1397+main(int argc,char **argv)
1398+{
1399+ int i;
1400+
1401+ dns_random_init(seed);
1402+
1403+ if (*argv) ++argv;
1404+
1405+ while (*argv) {
1406+ if (!stralloc_copys(&fqdn,*argv))
1407+ strerr_die2x(111,FATAL,"out of memory");
1408+ if (dns_ip6(&out,&fqdn) == -1)
1409+ strerr_die4sys(111,FATAL,"unable to find IPv6 address for ",*argv,": ");
1410+
1411+ for (i = 0;i + 16 <= out.len;i += 16) {
1412+ buffer_put(buffer_1,str,ip6_fmt(str,out.s + i));
1413+ buffer_puts(buffer_1," ");
1414+ }
1415+ buffer_puts(buffer_1,"\n");
1416+
1417+ ++argv;
1418+ }
1419+
1420+ buffer_flush(buffer_1);
1421+ _exit(0);
1422+}
1423diff --git a/dnsip6q.c b/dnsip6q.c
1424new file mode 100644
1425index 0000000..82ab04e
1426--- /dev/null
1427+++ b/dnsip6q.c
1428@@ -0,0 +1,43 @@
1429+#include "buffer.h"
1430+#include "exit.h"
1431+#include "strerr.h"
1432+#include "ip6.h"
1433+#include "dns.h"
1434+
1435+#define FATAL "dnsipq: fatal: "
1436+
1437+static char seed[128];
1438+
1439+static stralloc in;
1440+static stralloc fqdn;
1441+static stralloc out;
1442+char str[IP6_FMT];
1443+
1444+int main(int argc,char **argv)
1445+{
1446+ int i;
1447+
1448+ dns_random_init(seed);
1449+
1450+ if (*argv) ++argv;
1451+
1452+ while (*argv) {
1453+ if (!stralloc_copys(&in,*argv))
1454+ strerr_die2x(111,FATAL,"out of memory");
1455+ if (dns_ip6_qualify(&out,&fqdn,&in) == -1)
1456+ strerr_die4sys(111,FATAL,"unable to find IP6 address for ",*argv,": ");
1457+
1458+ buffer_put(buffer_1,fqdn.s,fqdn.len);
1459+ buffer_puts(buffer_1," ");
1460+ for (i = 0;i + 16 <= out.len;i += 16) {
1461+ buffer_put(buffer_1,str,ip6_fmt(str,out.s + i));
1462+ buffer_puts(buffer_1," ");
1463+ }
1464+ buffer_puts(buffer_1,"\n");
1465+
1466+ ++argv;
1467+ }
1468+
1469+ buffer_flush(buffer_1);
1470+ _exit(0);
1471+}
1472diff --git a/dnsname.c b/dnsname.c
1473index 0e5eb26..ff9166d 100644
1474--- a/dnsname.c
1475+++ b/dnsname.c
1476@@ -2,6 +2,7 @@
1477 #include "exit.h"
1478 #include "strerr.h"
1479 #include "ip4.h"
1480+#include "ip6.h"
1481 #include "dns.h"
1482
1483 #define FATAL "dnsname: fatal: "
1484@@ -9,6 +10,7 @@
1485 static char seed[128];
1486
1487 char ip[4];
1488+char ip6[16];
1489 static stralloc out;
1490
1491 int main(int argc,char **argv)
1492@@ -18,10 +20,15 @@ int main(int argc,char **argv)
1493 if (*argv) ++argv;
1494
1495 while (*argv) {
1496- if (!ip4_scan(*argv,ip))
1497- strerr_die3x(111,FATAL,"unable to parse IP address ",*argv);
1498- if (dns_name4(&out,ip) == -1)
1499- strerr_die4sys(111,FATAL,"unable to find host name for ",*argv,": ");
1500+ if (ip6_scan(*argv,ip6)) {
1501+ if (dns_name6(&out,ip6) == -1)
1502+ strerr_die4sys(111,FATAL,"unable to find host name for ",*argv,": ");
1503+ } else {
1504+ if (!ip4_scan(*argv,ip))
1505+ strerr_die3x(111,FATAL,"unable to parse IP address ",*argv);
1506+ if (dns_name4(&out,ip) == -1)
1507+ strerr_die4sys(111,FATAL,"unable to find host name for ",*argv,": ");
1508+ }
1509
1510 buffer_put(buffer_1,out.s,out.len);
1511 buffer_puts(buffer_1,"\n");
1512diff --git a/dnsq.c b/dnsq.c
1513index 533e6af..9e89efe 100644
1514--- a/dnsq.c
1515+++ b/dnsq.c
1516@@ -10,6 +10,7 @@
1517 #include "printpacket.h"
1518 #include "parsetype.h"
1519 #include "dns.h"
1520+#include "ip6.h"
1521
1522 #define FATAL "dnsq: fatal: "
1523
1524@@ -24,14 +25,14 @@ void oops(void)
1525
1526 static struct dns_transmit tx;
1527
1528-int resolve(char *q,char qtype[2],char servers[64])
1529+int resolve(char *q,char qtype[2],char servers[256])
1530 {
1531 struct taia stamp;
1532 struct taia deadline;
1533 iopause_fd x[1];
1534 int r;
1535
1536- if (dns_transmit_start(&tx,servers,0,q,qtype,"\0\0\0\0") == -1) return -1;
1537+ if (dns_transmit_start(&tx,servers,0,q,qtype,V6any) == -1) return -1;
1538
1539 for (;;) {
1540 taia_now(&stamp);
1541@@ -47,7 +48,7 @@ int resolve(char *q,char qtype[2],char servers[64])
1542 return 0;
1543 }
1544
1545-char servers[64];
1546+char servers[256];
1547 static stralloc ip;
1548 static stralloc fqdn;
1549
1550@@ -73,9 +74,9 @@ int main(int argc,char **argv)
1551
1552 if (!*++argv) usage();
1553 if (!stralloc_copys(&out,*argv)) oops();
1554- if (dns_ip4_qualify(&ip,&fqdn,&out) == -1) oops();
1555- if (ip.len >= 64) ip.len = 64;
1556- byte_zero(servers,64);
1557+ if (dns_ip6_qualify(&ip,&fqdn,&out) == -1) oops();
1558+ if (ip.len >= 256) ip.len = 256;
1559+ byte_zero(servers,256);
1560 byte_copy(servers,ip.len,ip.s);
1561
1562 if (!stralloc_copys(&out,"")) oops();
1563diff --git a/dnstrace.c b/dnstrace.c
1564index 3f2159b..1d331bd 100644
1565--- a/dnstrace.c
1566+++ b/dnstrace.c
1567@@ -4,6 +4,7 @@
1568 #include "str.h"
1569 #include "byte.h"
1570 #include "ip4.h"
1571+#include "ip6.h"
1572 #include "gen_alloc.h"
1573 #include "gen_allocdefs.h"
1574 #include "exit.h"
1575@@ -30,7 +31,7 @@ void usage(void)
1576 }
1577
1578 static stralloc querystr;
1579-char ipstr[IP4_FMT];
1580+char ipstr[IP6_FMT];
1581 static stralloc tmp;
1582
1583 void printdomain(const char *d)
1584@@ -42,19 +43,19 @@ void printdomain(const char *d)
1585
1586 static struct dns_transmit tx;
1587
1588-int resolve(char *q,char qtype[2],char ip[4])
1589+int resolve(char *q,char qtype[2],char ip[16])
1590 {
1591 struct taia start;
1592 struct taia stamp;
1593 struct taia deadline;
1594- char servers[64];
1595+ char servers[256];
1596 iopause_fd x[1];
1597 int r;
1598
1599 taia_now(&start);
1600
1601- byte_zero(servers,64);
1602- byte_copy(servers,4,ip);
1603+ byte_zero(servers,256);
1604+ byte_copy(servers,16,ip);
1605
1606 if (dns_transmit_start(&tx,servers,0,q,qtype,"\0\0\0\0") == -1) return -1;
1607
1608@@ -82,7 +83,7 @@ int resolve(char *q,char qtype[2],char ip[4])
1609
1610 struct address {
1611 char *owner;
1612- char ip[4];
1613+ char ip[16];
1614 } ;
1615
1616 GEN_ALLOC_typedef(address_alloc,struct address,s,len,a)
1617@@ -117,7 +118,7 @@ struct qt {
1618 char *owner;
1619 char type[2];
1620 char *control;
1621- char ip[4];
1622+ char ip[16];
1623 } ;
1624
1625 GEN_ALLOC_typedef(qt_alloc,struct qt,s,len,a)
1626@@ -126,7 +127,7 @@ GEN_ALLOC_append(qt_alloc,struct qt,s,len,a,i,n,x,30,qt_alloc_readyplus,qt_alloc
1627
1628 static qt_alloc qt;
1629
1630-void qt_add(const char *q,const char type[2],const char *control,const char ip[4])
1631+void qt_add(const char *q,const char type[2],const char *control,const char ip[16])
1632 {
1633 struct qt x;
1634 int i;
1635@@ -137,14 +138,14 @@ void qt_add(const char *q,const char type[2],const char *control,const char ip[4
1636 if (dns_domain_equal(qt.s[i].owner,q))
1637 if (dns_domain_equal(qt.s[i].control,control))
1638 if (byte_equal(qt.s[i].type,2,type))
1639- if (byte_equal(qt.s[i].ip,4,ip))
1640+ if (byte_equal(qt.s[i].ip,16,ip))
1641 return;
1642
1643 byte_zero(&x,sizeof x);
1644 if (!dns_domain_copy(&x.owner,q)) nomem();
1645 if (!dns_domain_copy(&x.control,control)) nomem();
1646 byte_copy(x.type,2,type);
1647- byte_copy(x.ip,4,ip);
1648+ byte_copy(x.ip,16,ip);
1649 if (!qt_alloc_append(&qt,&x)) nomem();
1650 }
1651
1652@@ -203,7 +204,7 @@ void ns_add(const char *owner,const char *server)
1653 qt_add(query.s[i].owner,query.s[i].type,owner,address.s[j].ip);
1654 }
1655
1656-void address_add(const char *owner,const char ip[4])
1657+void address_add(const char *owner,const char ip[16])
1658 {
1659 struct address x;
1660 int i;
1661@@ -213,17 +214,20 @@ void address_add(const char *owner,const char ip[4])
1662 buffer_puts(buffer_1,"A:");
1663 printdomain(owner);
1664 buffer_puts(buffer_1,":");
1665- buffer_put(buffer_1,ipstr,ip4_fmt(ipstr,ip));
1666+ if (ip6_isv4mapped(ip))
1667+ buffer_put(buffer_1,ipstr,ip4_fmt(ipstr,ip+12));
1668+ else
1669+ buffer_put(buffer_1,ipstr,ip6_fmt(ipstr,ip));
1670 buffer_puts(buffer_1,"\n");
1671
1672 for (i = 0;i < address.len;++i)
1673 if (dns_domain_equal(address.s[i].owner,owner))
1674- if (byte_equal(address.s[i].ip,4,ip))
1675+ if (byte_equal(address.s[i].ip,16,ip))
1676 return;
1677
1678 byte_zero(&x,sizeof x);
1679 if (!dns_domain_copy(&x.owner,owner)) nomem();
1680- byte_copy(x.ip,4,ip);
1681+ byte_copy(x.ip,16,ip);
1682 if (!address_alloc_append(&address,&x)) nomem();
1683
1684 for (i = 0;i < ns.len;++i)
1685@@ -331,7 +335,12 @@ void parsepacket(const char *buf,unsigned int len,const char *d,const char dtype
1686 ns_add(t1,t2);
1687 }
1688 else if (typematch(header,DNS_T_A) && datalen == 4) {
1689- if (!dns_packet_copy(buf,len,pos,misc,4)) goto DIE;
1690+ if (!dns_packet_copy(buf,len,pos,misc+12,4)) goto DIE;
1691+ byte_copy(misc,12,V4mappedprefix);
1692+ address_add(t1,misc);
1693+ }
1694+ else if (typematch(header,DNS_T_AAAA) && datalen == 16) {
1695+ if (!dns_packet_copy(buf,len,pos,misc,16)) goto DIE;
1696 address_add(t1,misc);
1697 }
1698 }
1699@@ -419,8 +428,8 @@ int main(int argc,char **argv)
1700
1701 while (*++argv) {
1702 if (!stralloc_copys(&udn,*argv)) nomem();
1703- if (dns_ip4_qualify(&out,&fqdn,&udn) == -1) nomem(); /* XXX */
1704- for (i = 0;i + 4 <= out.len;i += 4)
1705+ if (dns_ip6_qualify(&out,&fqdn,&udn) == -1) nomem(); /* XXX */
1706+ for (i = 0;i + 16 <= out.len;i += 16)
1707 address_add("",out.s + i);
1708 }
1709
1710@@ -429,7 +438,7 @@ int main(int argc,char **argv)
1711 control = qt.s[i].control;
1712 if (!dns_domain_suffix(q,control)) continue;
1713 byte_copy(type,2,qt.s[i].type);
1714- byte_copy(ip,4,qt.s[i].ip);
1715+ byte_copy(ip,16,qt.s[i].ip);
1716
1717 if (!stralloc_copys(&querystr,"")) nomem();
1718 uint16_unpack_big(type,&u16);
1719@@ -439,7 +448,10 @@ int main(int argc,char **argv)
1720 if (!stralloc_cats(&querystr,":")) nomem();
1721 if (!dns_domain_todot_cat(&querystr,control)) nomem();
1722 if (!stralloc_cats(&querystr,":")) nomem();
1723- if (!stralloc_catb(&querystr,ipstr,ip4_fmt(ipstr,ip))) nomem();
1724+ if (ip6_isv4mapped(ip)) {
1725+ if (!stralloc_catb(&querystr,ipstr,ip4_fmt(ipstr,ip+12))) nomem();
1726+ } else
1727+ if (!stralloc_catb(&querystr,ipstr,ip6_fmt(ipstr,ip))) nomem();
1728 if (!stralloc_cats(&querystr,":")) nomem();
1729
1730 buffer_put(buffer_1,querystr.s,querystr.len);
1731diff --git a/error.h b/error.h
1732index 35c976e..9cdd527 100644
1733--- a/error.h
1734+++ b/error.h
1735@@ -1,7 +1,7 @@
1736 #ifndef ERROR_H
1737 #define ERROR_H
1738
1739-extern int errno;
1740+#include <errno.h>
1741
1742 extern int error_intr;
1743 extern int error_nomem;
1744diff --git a/fmt_xlong.c b/fmt_xlong.c
1745new file mode 100644
1746index 0000000..332fc9a
1747--- /dev/null
1748+++ b/fmt_xlong.c
1749@@ -0,0 +1,22 @@
1750+#include "fmt.h"
1751+
1752+char tohex(char num) {
1753+ if (num<10)
1754+ return num+'0';
1755+ else if (num<16)
1756+ return num-10+'a';
1757+ else
1758+ return -1;
1759+}
1760+
1761+unsigned int fmt_xlong(register char *s,register unsigned long u)
1762+{
1763+ register unsigned int len; register unsigned long q;
1764+ len = 1; q = u;
1765+ while (q > 15) { ++len; q /= 16; }
1766+ if (s) {
1767+ s += len;
1768+ do { *--s = tohex(u % 16); u /= 16; } while(u); /* handles u == 0 */
1769+ }
1770+ return len;
1771+}
1772diff --git a/haveip6.h1 b/haveip6.h1
1773new file mode 100644
1774index 0000000..8b13789
1775--- /dev/null
1776+++ b/haveip6.h1
1777@@ -0,0 +1 @@
1778+
1779diff --git a/haveip6.h2 b/haveip6.h2
1780new file mode 100644
1781index 0000000..5564de9
1782--- /dev/null
1783+++ b/haveip6.h2
1784@@ -0,0 +1 @@
1785+#define LIBC_HAS_IP6 1
1786diff --git a/haven2i.h1 b/haven2i.h1
1787new file mode 100644
1788index 0000000..732c485
1789--- /dev/null
1790+++ b/haven2i.h1
1791@@ -0,0 +1 @@
1792+#undef HAVE_N2I
1793diff --git a/haven2i.h2 b/haven2i.h2
1794new file mode 100644
1795index 0000000..fd50644
1796--- /dev/null
1797+++ b/haven2i.h2
1798@@ -0,0 +1 @@
1799+#define HAVE_N2I
1800diff --git a/hier.c b/hier.c
1801index b57dba0..e4b1a7f 100644
1802--- a/hier.c
1803+++ b/hier.c
1804@@ -32,7 +32,9 @@ void hier()
1805 c(auto_home,"bin","axfr-get",-1,-1,0755);
1806
1807 c(auto_home,"bin","dnsip",-1,-1,0755);
1808+ c(auto_home,"bin","dnsip6",-1,-1,0755);
1809 c(auto_home,"bin","dnsipq",-1,-1,0755);
1810+ c(auto_home,"bin","dnsip6q",-1,-1,0755);
1811 c(auto_home,"bin","dnsname",-1,-1,0755);
1812 c(auto_home,"bin","dnstxt",-1,-1,0755);
1813 c(auto_home,"bin","dnsmx",-1,-1,0755);
1814diff --git a/ip6.h b/ip6.h
1815new file mode 100644
1816index 0000000..c1135e9
1817--- /dev/null
1818+++ b/ip6.h
1819@@ -0,0 +1,28 @@
1820+#ifndef IP6_H
1821+#define IP6_H
1822+
1823+extern unsigned int ip6_scan(const char *,char *);
1824+extern unsigned int ip6_fmt(char *,const char *);
1825+
1826+extern unsigned int ip6_scan_flat(const char *,char *);
1827+extern unsigned int ip6_fmt_flat(char *,char *);
1828+
1829+/*
1830+ ip6 address syntax: (h = hex digit), no leading '0' required
1831+ 1. hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh
1832+ 2. any number of 0000 may be abbreviated as "::", but only once
1833+ flat ip6 address syntax:
1834+ hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
1835+ */
1836+
1837+#define IP6_FMT 40
1838+
1839+const static unsigned char V4mappedprefix[12]={0,0,0,0,0,0,0,0,0,0,0xff,0xff};
1840+const static unsigned char V6loopback[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
1841+const static unsigned char V6any[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1842+
1843+#define ip6_isv4mapped(ip) (byte_equal(ip,12,V4mappedprefix))
1844+
1845+const static char ip4loopback[4] = {127,0,0,1};
1846+
1847+#endif
1848diff --git a/ip6_fmt.c b/ip6_fmt.c
1849new file mode 100644
1850index 0000000..b2444bb
1851--- /dev/null
1852+++ b/ip6_fmt.c
1853@@ -0,0 +1,60 @@
1854+#include "fmt.h"
1855+#include "byte.h"
1856+#include "ip4.h"
1857+#include "ip6.h"
1858+#include <stdio.h>
1859+
1860+extern char tohex(char num);
1861+
1862+unsigned int ip6_fmt(char *s,const char ip[16])
1863+{
1864+ unsigned int len;
1865+ unsigned int i;
1866+ unsigned int temp;
1867+ unsigned int compressing;
1868+ unsigned int compressed;
1869+ int j;
1870+
1871+ len = 0; compressing = 0; compressed = 0;
1872+ for (j=0; j<16; j+=2) {
1873+ if (j==12 && ip6_isv4mapped(ip)) {
1874+ temp=ip4_fmt(s,ip+12);
1875+ len+=temp;
1876+ break;
1877+ }
1878+ temp = ((unsigned long) (unsigned char) ip[j] << 8) +
1879+ (unsigned long) (unsigned char) ip[j+1];
1880+ if (temp == 0 && !compressed) {
1881+ if (!compressing) {
1882+ compressing=1;
1883+ if (j==0) {
1884+ if (s) *s++=':'; ++len;
1885+ }
1886+ }
1887+ } else {
1888+ if (compressing) {
1889+ compressing=0; ++compressed;
1890+ if (s) *s++=':'; ++len;
1891+ }
1892+ i = fmt_xlong(s,temp); len += i; if (s) s += i;
1893+ if (j<14) {
1894+ if (s) *s++ = ':';
1895+ ++len;
1896+ }
1897+ }
1898+ }
1899+ if (compressing) { *s++=':'; ++len; }
1900+
1901+/* if (s) *s=0; */
1902+ return len;
1903+}
1904+
1905+unsigned int ip6_fmt_flat(char *s,char ip[16])
1906+{
1907+ int i;
1908+ for (i=0; i<16; i++) {
1909+ *s++=tohex((unsigned char)ip[i] >> 4);
1910+ *s++=tohex((unsigned char)ip[i] & 15);
1911+ }
1912+ return 32;
1913+}
1914diff --git a/ip6_scan.c b/ip6_scan.c
1915new file mode 100644
1916index 0000000..f355d46
1917--- /dev/null
1918+++ b/ip6_scan.c
1919@@ -0,0 +1,115 @@
1920+#include "scan.h"
1921+#include "ip4.h"
1922+#include "ip6.h"
1923+#include "byte.h"
1924+
1925+/*
1926+ * IPv6 addresses are really ugly to parse.
1927+ * Syntax: (h = hex digit)
1928+ * 1. hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh:hhhh
1929+ * 2. any number of 0000 may be abbreviated as "::", but only once
1930+ * 3. The last two words may be written as IPv4 address
1931+ */
1932+
1933+unsigned int ip6_scan(const char *s,char ip[16])
1934+{
1935+ unsigned int i;
1936+ unsigned int len=0;
1937+ unsigned long u;
1938+
1939+ char suffix[16];
1940+ int prefixlen=0;
1941+ int suffixlen=0;
1942+
1943+ if ((i=ip4_scan(s,ip+12))) {
1944+ const char *c=V4mappedprefix;
1945+ if (byte_equal(ip+12,4,V6any)) c=V6any;
1946+ for (len=0; len<12; ++len) ip[len]=c[len];
1947+ return i;
1948+ }
1949+ for (i=0; i<16; i++) ip[i]=0;
1950+ for (;;) {
1951+ if (*s == ':') {
1952+ len++;
1953+ if (s[1] == ':') { /* Found "::", skip to part 2 */
1954+ s+=2;
1955+ len++;
1956+ break;
1957+ }
1958+ s++;
1959+ }
1960+ i = scan_xlong(s,&u);
1961+ if (!i) return 0;
1962+ if (prefixlen==12 && s[i]=='.') {
1963+ /* the last 4 bytes may be written as IPv4 address */
1964+ i=ip4_scan(s,ip+12);
1965+ if (i)
1966+ return i+len;
1967+ else
1968+ return 0;
1969+ }
1970+ ip[prefixlen++] = (u >> 8);
1971+ ip[prefixlen++] = (u & 255);
1972+ s += i; len += i;
1973+ if (prefixlen==16)
1974+ return len;
1975+ }
1976+
1977+/* part 2, after "::" */
1978+ for (;;) {
1979+ if (*s == ':') {
1980+ if (suffixlen==0)
1981+ break;
1982+ s++;
1983+ len++;
1984+ } else if (suffixlen!=0)
1985+ break;
1986+ i = scan_xlong(s,&u);
1987+ if (!i) {
1988+ len--;
1989+ break;
1990+ }
1991+ if (suffixlen+prefixlen<=12 && s[i]=='.') {
1992+ int j=ip4_scan(s,suffix+suffixlen);
1993+ if (j) {
1994+ suffixlen+=4;
1995+ len+=j;
1996+ break;
1997+ } else
1998+ prefixlen=12-suffixlen; /* make end-of-loop test true */
1999+ }
2000+ suffix[suffixlen++] = (u >> 8);
2001+ suffix[suffixlen++] = (u & 255);
2002+ s += i; len += i;
2003+ if (prefixlen+suffixlen==16)
2004+ break;
2005+ }
2006+ for (i=0; i<suffixlen; i++)
2007+ ip[16-suffixlen+i] = suffix[i];
2008+ return len;
2009+}
2010+
2011+static long int fromhex(unsigned char c) {
2012+ if (c>='0' && c<='9')
2013+ return c-'0';
2014+ else if (c>='A' && c<='F')
2015+ return c-'A'+10;
2016+ else if (c>='a' && c<='f')
2017+ return c-'a'+10;
2018+ return -1;
2019+}
2020+
2021+unsigned int ip6_scan_flat(const char *s,char ip[16])
2022+{
2023+ int i;
2024+ for (i=0; i<16; i++) {
2025+ int tmp;
2026+ tmp=fromhex(*s++);
2027+ if (tmp<0) return 0;
2028+ ip[i]=tmp << 4;
2029+ tmp=fromhex(*s++);
2030+ if (tmp<0) return 0;
2031+ ip[i]+=tmp;
2032+ }
2033+ return 32;
2034+}
2035diff --git a/log.c b/log.c
2036index c43e8b0..df465e2 100644
2037--- a/log.c
2038+++ b/log.c
2039@@ -3,6 +3,7 @@
2040 #include "uint16.h"
2041 #include "error.h"
2042 #include "byte.h"
2043+#include "ip6.h"
2044 #include "log.h"
2045
2046 /* work around gcc 2.95.2 bug */
2047@@ -45,12 +46,10 @@ static void space(void)
2048 string(" ");
2049 }
2050
2051-static void ip(const char i[4])
2052+static void ip(const char i[16])
2053 {
2054- hex(i[0]);
2055- hex(i[1]);
2056- hex(i[2]);
2057- hex(i[3]);
2058+ int j;
2059+ for (j=0; j<16; ++j) hex(i[j]);
2060 }
2061
2062 static void logid(const char id[2])
2063@@ -94,7 +93,7 @@ void log_startup(void)
2064 line();
2065 }
2066
2067-void log_query(uint64 *qnum,const char client[4],unsigned int port,const char id[2],const char *q,const char qtype[2])
2068+void log_query(uint64 *qnum,const char client[16],unsigned int port,const char id[2],const char *q,const char qtype[2])
2069 {
2070 string("query "); number(*qnum); space();
2071 ip(client); string(":"); hex(port >> 8); hex(port & 255);
2072@@ -119,14 +118,14 @@ void log_querydrop(uint64 *qnum)
2073 line();
2074 }
2075
2076-void log_tcpopen(const char client[4],unsigned int port)
2077+void log_tcpopen(const char client[16],unsigned int port)
2078 {
2079 string("tcpopen ");
2080 ip(client); string(":"); hex(port >> 8); hex(port & 255);
2081 line();
2082 }
2083
2084-void log_tcpclose(const char client[4],unsigned int port)
2085+void log_tcpclose(const char client[16],unsigned int port)
2086 {
2087 const char *x = error_str(errno);
2088 string("tcpclose ");
2089@@ -135,15 +134,15 @@ void log_tcpclose(const char client[4],unsigned int port)
2090 line();
2091 }
2092
2093-void log_tx(const char *q,const char qtype[2],const char *control,const char servers[64],unsigned int gluelessness)
2094+void log_tx(const char *q,const char qtype[2],const char *control,const char servers[256],unsigned int gluelessness)
2095 {
2096 int i;
2097
2098 string("tx "); number(gluelessness); space();
2099 logtype(qtype); space(); name(q); space();
2100 name(control);
2101- for (i = 0;i < 64;i += 4)
2102- if (byte_diff(servers + i,4,"\0\0\0\0")) {
2103+ for (i = 0;i < 256;i += 16)
2104+ if (byte_diff(servers + i,16,V6any)) {
2105 space();
2106 ip(servers + i);
2107 }
2108@@ -175,21 +174,21 @@ void log_cachednxdomain(const char *dn)
2109 line();
2110 }
2111
2112-void log_nxdomain(const char server[4],const char *q,unsigned int ttl)
2113+void log_nxdomain(const char server[16],const char *q,unsigned int ttl)
2114 {
2115 string("nxdomain "); ip(server); space(); number(ttl); space();
2116 name(q);
2117 line();
2118 }
2119
2120-void log_nodata(const char server[4],const char *q,const char qtype[2],unsigned int ttl)
2121+void log_nodata(const char server[16],const char *q,const char qtype[2],unsigned int ttl)
2122 {
2123 string("nodata "); ip(server); space(); number(ttl); space();
2124 logtype(qtype); space(); name(q);
2125 line();
2126 }
2127
2128-void log_lame(const char server[4],const char *control,const char *referral)
2129+void log_lame(const char server[16],const char *control,const char *referral)
2130 {
2131 string("lame "); ip(server); space();
2132 name(control); space(); name(referral);
2133@@ -205,7 +204,7 @@ void log_servfail(const char *dn)
2134 line();
2135 }
2136
2137-void log_rr(const char server[4],const char *q,const char type[2],const char *buf,unsigned int len,unsigned int ttl)
2138+void log_rr(const char server[16],const char *q,const char type[2],const char *buf,unsigned int len,unsigned int ttl)
2139 {
2140 int i;
2141
2142@@ -222,7 +221,7 @@ void log_rr(const char server[4],const char *q,const char type[2],const char *bu
2143 line();
2144 }
2145
2146-void log_rrns(const char server[4],const char *q,const char *data,unsigned int ttl)
2147+void log_rrns(const char server[16],const char *q,const char *data,unsigned int ttl)
2148 {
2149 string("rr "); ip(server); space(); number(ttl);
2150 string(" ns "); name(q); space();
2151@@ -230,7 +229,7 @@ void log_rrns(const char server[4],const char *q,const char *data,unsigned int t
2152 line();
2153 }
2154
2155-void log_rrcname(const char server[4],const char *q,const char *data,unsigned int ttl)
2156+void log_rrcname(const char server[16],const char *q,const char *data,unsigned int ttl)
2157 {
2158 string("rr "); ip(server); space(); number(ttl);
2159 string(" cname "); name(q); space();
2160@@ -238,7 +237,7 @@ void log_rrcname(const char server[4],const char *q,const char *data,unsigned in
2161 line();
2162 }
2163
2164-void log_rrptr(const char server[4],const char *q,const char *data,unsigned int ttl)
2165+void log_rrptr(const char server[16],const char *q,const char *data,unsigned int ttl)
2166 {
2167 string("rr "); ip(server); space(); number(ttl);
2168 string(" ptr "); name(q); space();
2169@@ -246,7 +245,7 @@ void log_rrptr(const char server[4],const char *q,const char *data,unsigned int
2170 line();
2171 }
2172
2173-void log_rrmx(const char server[4],const char *q,const char *mx,const char pref[2],unsigned int ttl)
2174+void log_rrmx(const char server[16],const char *q,const char *mx,const char pref[2],unsigned int ttl)
2175 {
2176 uint16 u;
2177
2178@@ -257,7 +256,7 @@ void log_rrmx(const char server[4],const char *q,const char *mx,const char pref[
2179 line();
2180 }
2181
2182-void log_rrsoa(const char server[4],const char *q,const char *n1,const char *n2,const char misc[20],unsigned int ttl)
2183+void log_rrsoa(const char server[16],const char *q,const char *n1,const char *n2,const char misc[20],unsigned int ttl)
2184 {
2185 uint32 u;
2186 int i;
2187diff --git a/okclient.c b/okclient.c
2188index a648c02..9a0d3c6 100644
2189--- a/okclient.c
2190+++ b/okclient.c
2191@@ -2,24 +2,34 @@
2192 #include <sys/stat.h>
2193 #include "str.h"
2194 #include "ip4.h"
2195+#include "ip6.h"
2196+#include "byte.h"
2197 #include "okclient.h"
2198
2199-static char fn[3 + IP4_FMT];
2200+static char fn[3 + IP6_FMT];
2201
2202-int okclient(char ip[4])
2203+int okclient(char ip[16])
2204 {
2205 struct stat st;
2206 int i;
2207+ char sep;
2208
2209 fn[0] = 'i';
2210 fn[1] = 'p';
2211 fn[2] = '/';
2212- fn[3 + ip4_fmt(fn + 3,ip)] = 0;
2213+ if (byte_equal(ip,12,V4mappedprefix)) {
2214+ fn[3 + ip4_fmt(fn + 3,ip+12)] = 0;
2215+ sep='.';
2216+ } else {
2217+ fn[3 + ip6_fmt(fn + 3,ip)] = 0;
2218+ sep=':';
2219+ }
2220
2221 for (;;) {
2222+ if (!fn[3]) return 0;
2223 if (stat(fn,&st) == 0) return 1;
2224 /* treat temporary error as rejection */
2225- i = str_rchr(fn,'.');
2226+ i = str_rchr(fn,sep);
2227 if (!fn[i]) return 0;
2228 fn[i] = 0;
2229 }
2230diff --git a/printrecord.c b/printrecord.c
2231index ed0b42d..4bc7c3e 100644
2232--- a/printrecord.c
2233+++ b/printrecord.c
2234@@ -4,6 +4,7 @@
2235 #include "byte.h"
2236 #include "dns.h"
2237 #include "printrecord.h"
2238+#include "ip6.h"
2239
2240 static char *d;
2241
2242@@ -82,6 +83,15 @@ unsigned int printrecord_cat(stralloc *out,const char *buf,unsigned int len,unsi
2243 if (!stralloc_catulong0(out,ch,0)) return 0;
2244 }
2245 }
2246+ else if (byte_equal(misc,2,DNS_T_AAAA)) {
2247+ char ip6str[IP6_FMT];
2248+ int stringlen;
2249+ if (datalen != 16) { errno = error_proto; return 0; }
2250+ if (!stralloc_cats(out," AAAA ")) return 0;
2251+ pos = dns_packet_copy(buf,len,pos,misc,16); if (!pos) return 0;
2252+ stringlen=ip6_fmt(ip6str,misc);
2253+ if (!stralloc_catb(out,ip6str,stringlen)) return 0;
2254+ }
2255 else {
2256 if (!stralloc_cats(out," ")) return 0;
2257 uint16_unpack_big(misc,&u16);
2258diff --git a/qlog.c b/qlog.c
2259index 5c5c7ba..60816df 100644
2260--- a/qlog.c
2261+++ b/qlog.c
2262@@ -20,15 +20,15 @@ static void octal(unsigned char c)
2263 put('0' + (c & 7));
2264 }
2265
2266-void qlog(const char ip[4],uint16 port,const char id[2],const char *q,const char qtype[2],const char *result)
2267+void qlog(const char ip[16],uint16 port,const char id[2],const char *q,const char qtype[2],const char *result)
2268 {
2269 char ch;
2270 char ch2;
2271
2272- hex(ip[0]);
2273- hex(ip[1]);
2274- hex(ip[2]);
2275- hex(ip[3]);
2276+ {
2277+ int i;
2278+ for (i=0; i<16; ++i) hex(ip[i]);
2279+ }
2280 put(':');
2281 hex(port >> 8);
2282 hex(port & 255);
2283diff --git a/query.c b/query.c
2284index 46cdc00..e0f48b3 100644
2285--- a/query.c
2286+++ b/query.c
2287@@ -12,6 +12,9 @@
2288 #include "alloc.h"
2289 #include "response.h"
2290 #include "query.h"
2291+#include "ip6.h"
2292+
2293+extern stralloc ignoreip;
2294
2295 static int flagforwardonly = 0;
2296
2297@@ -110,7 +113,7 @@ static int rqa(struct query *z)
2298 return 1;
2299 }
2300
2301-static int globalip(char *d,char ip[4])
2302+static int globalip(char *d,char ip[16])
2303 {
2304 if (dns_domain_equal(d,"\011localhost\0")) {
2305 byte_copy(ip,4,"\177\0\0\1");
2306@@ -165,7 +168,7 @@ static int doit(struct query *z,int state)
2307 char *buf;
2308 unsigned int len;
2309 const char *whichserver;
2310- char header[12];
2311+ char header[24];
2312 char misc[20];
2313 unsigned int rcode;
2314 unsigned int posanswers;
2315@@ -193,6 +196,7 @@ static int doit(struct query *z,int state)
2316 int k;
2317 int p;
2318 int q;
2319+ unsigned int ii;
2320
2321 errno = error_io;
2322 if (state == 1) goto HAVEPACKET;
2323@@ -210,9 +214,10 @@ static int doit(struct query *z,int state)
2324
2325 if (globalip(d,misc)) {
2326 if (z->level) {
2327- for (k = 0;k < 64;k += 4)
2328- if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) {
2329- byte_copy(z->servers[z->level - 1] + k,4,misc);
2330+ for (k = 0;k < 256;k += 16)
2331+ if (byte_equal(z->servers[z->level - 1] + k,16,V6any)) {
2332+ byte_copy(z->servers[z->level - 1] + k,12,V4mappedprefix);
2333+ byte_copy(z->servers[z->level - 1] + k + 12,4,misc);
2334 break;
2335 }
2336 goto LOWERLEVEL;
2337@@ -227,6 +232,158 @@ static int doit(struct query *z,int state)
2338 return 1;
2339 }
2340
2341+ 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")) {
2342+ if (z->level) goto LOWERLEVEL;
2343+ if (!rqa(z)) goto DIE;
2344+ if (typematch(DNS_T_PTR,dtype)) {
2345+ if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
2346+ if (!response_addname("\016ipv6-localhost\0")) goto DIE;
2347+ if (!response_addname("\015ipv6-loopback\0")) goto DIE;
2348+ response_rfinish(RESPONSE_ANSWER);
2349+ }
2350+ cleanup(z);
2351+ return 1;
2352+ }
2353+
2354+ 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")) {
2355+ if (z->level) goto LOWERLEVEL;
2356+ if (!rqa(z)) goto DIE;
2357+ if (typematch(DNS_T_PTR,dtype)) {
2358+ if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
2359+ if (!response_addname("\015ipv6-localnet\0")) goto DIE;
2360+ response_rfinish(RESPONSE_ANSWER);
2361+ }
2362+ cleanup(z);
2363+ return 1;
2364+ }
2365+
2366+ 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")) {
2367+ if (z->level) goto LOWERLEVEL;
2368+ if (!rqa(z)) goto DIE;
2369+ if (typematch(DNS_T_PTR,dtype)) {
2370+ if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
2371+ if (!response_addname("\020ipv6-mcastprefix\0")) goto DIE;
2372+ response_rfinish(RESPONSE_ANSWER);
2373+ }
2374+ cleanup(z);
2375+ return 1;
2376+ }
2377+
2378+ 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")) {
2379+ if (z->level) goto LOWERLEVEL;
2380+ if (!rqa(z)) goto DIE;
2381+ if (typematch(DNS_T_PTR,dtype)) {
2382+ if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
2383+ if (!response_addname("\015ipv6-allnodes\0")) goto DIE;
2384+ response_rfinish(RESPONSE_ANSWER);
2385+ }
2386+ cleanup(z);
2387+ return 1;
2388+ }
2389+
2390+ 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")) {
2391+ if (z->level) goto LOWERLEVEL;
2392+ if (!rqa(z)) goto DIE;
2393+ if (typematch(DNS_T_PTR,dtype)) {
2394+ if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
2395+ if (!response_addname("\017ipv6-allrouters\0")) goto DIE;
2396+ response_rfinish(RESPONSE_ANSWER);
2397+ }
2398+ cleanup(z);
2399+ return 1;
2400+ }
2401+
2402+ 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")) {
2403+ if (z->level) goto LOWERLEVEL;
2404+ if (!rqa(z)) goto DIE;
2405+ if (typematch(DNS_T_PTR,dtype)) {
2406+ if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE;
2407+ if (!response_addname("\015ipv6-allhosts\0")) goto DIE;
2408+ response_rfinish(RESPONSE_ANSWER);
2409+ }
2410+ cleanup(z);
2411+ return 1;
2412+ }
2413+
2414+ if (dns_domain_equal(d,"\016ipv6-localhost\0") ||
2415+ dns_domain_equal(d,"\015ipv6-loopback\0"))
2416+ {
2417+ if (z->level) goto LOWERLEVEL;
2418+ if (!rqa(z)) goto DIE;
2419+ if (typematch(DNS_T_AAAA,dtype)) {
2420+ if (!response_rstart(d,DNS_T_AAAA,655360)) goto DIE;
2421+ if (!response_addbytes("\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001",16)) goto DIE;
2422+ response_rfinish(RESPONSE_ANSWER);
2423+ }
2424+ cleanup(z);
2425+ return 1;
2426+ }
2427+
2428+ if (dns_domain_equal(d,"\015ipv6-localnet\0"))
2429+ {
2430+ if (z->level) goto LOWERLEVEL;
2431+ if (!rqa(z)) goto DIE;
2432+ if (typematch(DNS_T_AAAA,dtype)) {
2433+ if (!response_rstart(d,DNS_T_AAAA,655360)) goto DIE;
2434+ if (!response_addbytes("\376\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",16)) goto DIE;
2435+ response_rfinish(RESPONSE_ANSWER);
2436+ }
2437+ cleanup(z);
2438+ return 1;
2439+ }
2440+
2441+ if (dns_domain_equal(d,"\020ipv6-mcastprefix\0"))
2442+ {
2443+ if (z->level) goto LOWERLEVEL;
2444+ if (!rqa(z)) goto DIE;
2445+ if (typematch(DNS_T_AAAA,dtype)) {
2446+ if (!response_rstart(d,DNS_T_AAAA,655360)) goto DIE;
2447+ if (!response_addbytes("\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",16)) goto DIE;
2448+ response_rfinish(RESPONSE_ANSWER);
2449+ }
2450+ cleanup(z);
2451+ return 1;
2452+ }
2453+
2454+ if (dns_domain_equal(d,"\15ipv6-allnodes\0"))
2455+ {
2456+ if (z->level) goto LOWERLEVEL;
2457+ if (!rqa(z)) goto DIE;
2458+ if (typematch(DNS_T_AAAA,dtype)) {
2459+ if (!response_rstart(d,DNS_T_AAAA,655360)) goto DIE;
2460+ if (!response_addbytes("\377\002\000\000\000\000\000\000\000\000\000\000\000\000\000\001",16)) goto DIE;
2461+ response_rfinish(RESPONSE_ANSWER);
2462+ }
2463+ cleanup(z);
2464+ return 1;
2465+ }
2466+
2467+ if (dns_domain_equal(d,"\17ipv6-allrouters\0"))
2468+ {
2469+ if (z->level) goto LOWERLEVEL;
2470+ if (!rqa(z)) goto DIE;
2471+ if (typematch(DNS_T_AAAA,dtype)) {
2472+ if (!response_rstart(d,DNS_T_AAAA,655360)) goto DIE;
2473+ if (!response_addbytes("\377\002\000\000\000\000\000\000\000\000\000\000\000\000\000\002",16)) goto DIE;
2474+ response_rfinish(RESPONSE_ANSWER);
2475+ }
2476+ cleanup(z);
2477+ return 1;
2478+ }
2479+
2480+ if (dns_domain_equal(d,"\15ipv6-allhosts\0"))
2481+ {
2482+ if (z->level) goto LOWERLEVEL;
2483+ if (!rqa(z)) goto DIE;
2484+ if (typematch(DNS_T_AAAA,dtype)) {
2485+ if (!response_rstart(d,DNS_T_AAAA,655360)) goto DIE;
2486+ if (!response_addbytes("\377\002\000\000\000\000\000\000\000\000\000\000\000\000\000\003",16)) goto DIE;
2487+ response_rfinish(RESPONSE_ANSWER);
2488+ }
2489+ cleanup(z);
2490+ return 1;
2491+ }
2492+
2493 if (dns_domain_equal(d,"\0011\0010\0010\003127\7in-addr\4arpa\0")) {
2494 if (z->level) goto LOWERLEVEL;
2495 if (!rqa(z)) goto DIE;
2496@@ -326,9 +483,10 @@ static int doit(struct query *z,int state)
2497 if (z->level) {
2498 log_cachedanswer(d,DNS_T_A);
2499 while (cachedlen >= 4) {
2500- for (k = 0;k < 64;k += 4)
2501- if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) {
2502- byte_copy(z->servers[z->level - 1] + k,4,cached);
2503+ for (k = 0;k < 256;k += 16)
2504+ if (byte_equal(z->servers[z->level - 1] + k,16,V6any)) {
2505+ byte_copy(z->servers[z->level - 1] + k,12,V4mappedprefix);
2506+ byte_copy(z->servers[z->level - 1] + k + 12,4,cached);
2507 break;
2508 }
2509 cached += 4;
2510@@ -351,7 +509,39 @@ static int doit(struct query *z,int state)
2511 }
2512 }
2513
2514- 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)) {
2515+ if (typematch(DNS_T_AAAA,dtype)) {
2516+ byte_copy(key,2,DNS_T_AAAA);
2517+ cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
2518+ if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
2519+ if (z->level) {
2520+ log_cachedanswer(d,DNS_T_AAAA);
2521+ while (cachedlen >= 16) {
2522+ for (k = 0;k < 256;k += 16)
2523+ if (byte_equal(z->servers[z->level - 1] + k,16,V6any)) {
2524+ byte_copy(z->servers[z->level - 1] + k,16,cached);
2525+ break;
2526+ }
2527+ cached += 16;
2528+ cachedlen -= 16;
2529+ }
2530+ goto LOWERLEVEL;
2531+ }
2532+
2533+ log_cachedanswer(d,DNS_T_AAAA);
2534+ if (!rqa(z)) goto DIE;
2535+ while (cachedlen >= 16) {
2536+ if (!response_rstart(d,DNS_T_AAAA,ttl)) goto DIE;
2537+ if (!response_addbytes(cached,16)) goto DIE;
2538+ response_rfinish(RESPONSE_ANSWER);
2539+ cached += 16;
2540+ cachedlen -= 16;
2541+ }
2542+ cleanup(z);
2543+ return 1;
2544+ }
2545+ }
2546+
2547+ 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)) {
2548 byte_copy(key,2,dtype);
2549 cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
2550 if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) {
2551@@ -390,7 +580,7 @@ static int doit(struct query *z,int state)
2552 cached = cache_get(key,dlen + 2,&cachedlen,&ttl);
2553 if (cached && cachedlen) {
2554 z->control[z->level] = d;
2555- byte_zero(z->servers[z->level],64);
2556+ byte_zero(z->servers[z->level],256);
2557 for (j = 0;j < QUERY_MAXNS;++j)
2558 dns_domain_free(&z->ns[z->level][j]);
2559 pos = 0;
2560@@ -423,12 +613,12 @@ static int doit(struct query *z,int state)
2561 dns_domain_free(&z->ns[z->level][j]);
2562 }
2563
2564- for (j = 0;j < 64;j += 4)
2565- if (byte_diff(z->servers[z->level] + j,4,"\0\0\0\0"))
2566+ for (j = 0;j < 256;j += 16)
2567+ if (byte_diff(z->servers[z->level] + j,16,V6any))
2568 break;
2569- if (j == 64) goto SERVFAIL;
2570+ if (j == 256) goto SERVFAIL;
2571
2572- dns_sortip(z->servers[z->level],64);
2573+ dns_sortip6(z->servers[z->level],256);
2574 if (z->level) {
2575 log_tx(z->name[z->level],DNS_T_A,z->control[z->level],z->servers[z->level],z->level);
2576 if (dns_transmit_start(&z->dt,z->servers[z->level],flagforwardonly,z->name[z->level],DNS_T_A,z->localip) == -1) goto DIE;
2577@@ -453,7 +643,7 @@ static int doit(struct query *z,int state)
2578 buf = z->dt.packet;
2579 len = z->dt.packetlen;
2580
2581- whichserver = z->dt.servers + 4 * z->dt.curserver;
2582+ whichserver = z->dt.servers + 16 * z->dt.curserver;
2583 control = z->control[z->level];
2584 d = z->name[z->level];
2585 dtype = z->level ? DNS_T_A : z->type;
2586@@ -519,7 +709,7 @@ static int doit(struct query *z,int state)
2587 if (!flagcname && !rcode && !flagout && flagreferral && !flagsoa)
2588 if (dns_domain_equal(referral,control) || !dns_domain_suffix(referral,control)) {
2589 log_lame(whichserver,control,referral);
2590- byte_zero(whichserver,4);
2591+ byte_zero(whichserver,16);
2592 goto HAVENS;
2593 }
2594
2595@@ -643,6 +833,11 @@ static int doit(struct query *z,int state)
2596 pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
2597 if (byte_equal(header + 8,2,"\0\4")) {
2598 pos = dns_packet_copy(buf,len,pos,header,4); if (!pos) goto DIE;
2599+ if (ignoreip.len)
2600+ for(ii = 0; ii < ignoreip.len; ii+= 16) {
2601+ if (byte_equal(ignoreip.s+ii,12,V4mappedprefix) &&
2602+ byte_equal(header,4,ignoreip.s+ii+12)) goto NXDOMAIN;
2603+ }
2604 save_data(header,4);
2605 log_rr(whichserver,t1,DNS_T_A,header,4,ttl);
2606 }
2607@@ -650,6 +845,23 @@ static int doit(struct query *z,int state)
2608 }
2609 save_finish(DNS_T_A,t1,ttl);
2610 }
2611+ else if (byte_equal(type,2,DNS_T_AAAA)) {
2612+ save_start();
2613+ while (i < j) {
2614+ pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE;
2615+ pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE;
2616+ if (byte_equal(header + 8,2,"\0\20")) {
2617+ pos = dns_packet_copy(buf,len,pos,header,16); if (!pos) goto DIE;
2618+ if (ignoreip.len)
2619+ for(ii = 0; ii < ignoreip.len; ii+= 16)
2620+ if (byte_equal(header,16,ignoreip.s+ii)) goto NXDOMAIN;
2621+ save_data(header,16);
2622+ log_rr(whichserver,t1,DNS_T_AAAA,header,16,ttl);
2623+ }
2624+ ++i;
2625+ }
2626+ save_finish(DNS_T_AAAA,t1,ttl);
2627+ }
2628 else {
2629 save_start();
2630 while (i < j) {
2631@@ -723,9 +935,10 @@ static int doit(struct query *z,int state)
2632 if (typematch(header,DNS_T_A))
2633 if (byte_equal(header + 2,2,DNS_C_IN)) /* should always be true */
2634 if (datalen == 4)
2635- for (k = 0;k < 64;k += 4)
2636- if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) {
2637- if (!dns_packet_copy(buf,len,pos,z->servers[z->level - 1] + k,4)) goto DIE;
2638+ for (k = 0;k < 256;k += 16)
2639+ if (byte_equal(z->servers[z->level - 1] + k,16,V6any)) {
2640+ byte_copy(z->servers[z->level - 1] + k,12,V4mappedprefix);
2641+ if (!dns_packet_copy(buf,len,pos,z->servers[z->level - 1] + k + 12,4)) goto DIE;
2642 break;
2643 }
2644 pos += datalen;
2645@@ -818,7 +1031,7 @@ static int doit(struct query *z,int state)
2646 return -1;
2647 }
2648
2649-int query_start(struct query *z,char *dn,char type[2],char class[2],char localip[4])
2650+int query_start(struct query *z,char *dn,char type[2],char class[2],char localip[16],unsigned int scope_id)
2651 {
2652 if (byte_equal(type,2,DNS_T_AXFR)) { errno = error_perm; return -1; }
2653
2654@@ -829,7 +1042,8 @@ int query_start(struct query *z,char *dn,char type[2],char class[2],char localip
2655 if (!dns_domain_copy(&z->name[0],dn)) return -1;
2656 byte_copy(z->type,2,type);
2657 byte_copy(z->class,2,class);
2658- byte_copy(z->localip,4,localip);
2659+ byte_copy(z->localip,16,localip);
2660+ z->scope_id=scope_id;
2661
2662 return doit(z,0);
2663 }
2664diff --git a/query.h b/query.h
2665index eff68b2..f179c22 100644
2666--- a/query.h
2667+++ b/query.h
2668@@ -14,16 +14,17 @@ struct query {
2669 char *name[QUERY_MAXLEVEL];
2670 char *control[QUERY_MAXLEVEL]; /* pointing inside name */
2671 char *ns[QUERY_MAXLEVEL][QUERY_MAXNS];
2672- char servers[QUERY_MAXLEVEL][64];
2673+ char servers[QUERY_MAXLEVEL][256];
2674 char *alias[QUERY_MAXALIAS];
2675 uint32 aliasttl[QUERY_MAXALIAS];
2676- char localip[4];
2677+ char localip[16];
2678+ uint32 scope_id;
2679 char type[2];
2680 char class[2];
2681 struct dns_transmit dt;
2682 } ;
2683
2684-extern int query_start(struct query *,char *,char *,char *,char *);
2685+extern int query_start(struct query *,char *,char *,char *,char *,unsigned int);
2686 extern void query_io(struct query *,iopause_fd *,struct taia *);
2687 extern int query_get(struct query *,iopause_fd *,struct taia *);
2688
2689diff --git a/roots.c b/roots.c
2690index 3cfe959..4162ec5 100644
2691--- a/roots.c
2692+++ b/roots.c
2693@@ -6,6 +6,7 @@
2694 #include "error.h"
2695 #include "direntry.h"
2696 #include "ip4.h"
2697+#include "ip6.h"
2698 #include "dns.h"
2699 #include "openreadclose.h"
2700 #include "roots.h"
2701@@ -22,7 +23,7 @@ static int roots_find(char *q)
2702 j = dns_domain_length(data.s + i);
2703 if (dns_domain_equal(data.s + i,q)) return i + j;
2704 i += j;
2705- i += 64;
2706+ i += 256;
2707 }
2708 return -1;
2709 }
2710@@ -40,12 +41,12 @@ static int roots_search(char *q)
2711 }
2712 }
2713
2714-int roots(char servers[64],char *q)
2715+int roots(char servers[256],char *q)
2716 {
2717 int r;
2718 r = roots_find(q);
2719 if (r == -1) return 0;
2720- byte_copy(servers,64,data.s + r);
2721+ byte_copy(servers,256,data.s + r);
2722 return 1;
2723 }
2724
2725@@ -60,7 +61,7 @@ static int init2(DIR *dir)
2726 const char *fqdn;
2727 static char *q;
2728 static stralloc text;
2729- char servers[64];
2730+ char servers[256];
2731 int serverslen;
2732 int i;
2733 int j;
2734@@ -86,14 +87,14 @@ static int init2(DIR *dir)
2735 for (i = 0;i < text.len;++i)
2736 if (text.s[i] == '\n') {
2737 if (serverslen <= 60)
2738- if (ip4_scan(text.s + j,servers + serverslen))
2739- serverslen += 4;
2740+ if (ip6_scan(text.s + j,servers + serverslen))
2741+ serverslen += 16;
2742 j = i + 1;
2743 }
2744- byte_zero(servers + serverslen,64 - serverslen);
2745+ byte_zero(servers + serverslen,256 - serverslen);
2746
2747 if (!stralloc_catb(&data,q,dns_domain_length(q))) return 0;
2748- if (!stralloc_catb(&data,servers,64)) return 0;
2749+ if (!stralloc_catb(&data,servers,256)) return 0;
2750 }
2751 }
2752 }
2753diff --git a/scan_xlong.c b/scan_xlong.c
2754new file mode 100644
2755index 0000000..1113433
2756--- /dev/null
2757+++ b/scan_xlong.c
2758@@ -0,0 +1,23 @@
2759+#include "scan.h"
2760+
2761+static inline int fromhex(unsigned char c) {
2762+ if (c>='0' && c<='9')
2763+ return c-'0';
2764+ else if (c>='A' && c<='F')
2765+ return c-'A'+10;
2766+ else if (c>='a' && c<='f')
2767+ return c-'a'+10;
2768+ return -1;
2769+}
2770+
2771+unsigned int scan_xlong(const char *src,unsigned long *dest) {
2772+ register const char *tmp=src;
2773+ register int l=0;
2774+ register unsigned char c;
2775+ while ((c=fromhex(*tmp))<16) {
2776+ l=(l<<4)+c;
2777+ ++tmp;
2778+ }
2779+ *dest=l;
2780+ return tmp-src;
2781+}
2782diff --git a/server.c b/server.c
2783index e486fe1..d52ce87 100644
2784--- a/server.c
2785+++ b/server.c
2786@@ -4,6 +4,7 @@
2787 #include "buffer.h"
2788 #include "strerr.h"
2789 #include "ip4.h"
2790+#include "ip6.h"
2791 #include "uint16.h"
2792 #include "ndelay.h"
2793 #include "socket.h"
2794@@ -11,13 +12,16 @@
2795 #include "qlog.h"
2796 #include "response.h"
2797 #include "dns.h"
2798+#include "alloc.h"
2799+#include "iopause.h"
2800+#include "str.h"
2801
2802 extern char *fatal;
2803 extern char *starting;
2804 extern int respond(char *,char *,char *);
2805 extern void initialize(void);
2806
2807-static char ip[4];
2808+static char ip[16];
2809 static uint16 port;
2810
2811 static char buf[513];
2812@@ -25,6 +29,11 @@ static int len;
2813
2814 static char *q;
2815
2816+void nomem()
2817+{
2818+ strerr_die2x(111,fatal,"out of memory");
2819+}
2820+
2821 static int doit(void)
2822 {
2823 unsigned int pos;
2824@@ -82,35 +91,86 @@ static int doit(void)
2825 int main()
2826 {
2827 char *x;
2828- int udp53;
2829+ int *udp53;
2830+ unsigned int off;
2831+ unsigned int cnt;
2832+ iopause_fd *iop;
2833
2834 x = env_get("IP");
2835 if (!x)
2836 strerr_die2x(111,fatal,"$IP not set");
2837- if (!ip4_scan(x,ip))
2838- strerr_die3x(111,fatal,"unable to parse IP address ",x);
2839-
2840- udp53 = socket_udp();
2841- if (udp53 == -1)
2842- strerr_die2sys(111,fatal,"unable to create UDP socket: ");
2843- if (socket_bind4_reuse(udp53,ip,53) == -1)
2844- strerr_die2sys(111,fatal,"unable to bind UDP socket: ");
2845-
2846+ off=cnt=0;
2847+ while (x[off]) {
2848+ unsigned int l;
2849+ char dummy[16];
2850+ l=ip6_scan(x+off,dummy);
2851+ if (!l)
2852+ strerr_die3x(111,fatal,"unable to parse IP address ",x+off);
2853+ cnt++;
2854+ if (!x[off+l]) break;
2855+ if (x[off+l]=='%')
2856+ while (x[off+l] && x[off+l]!=',') ++l;
2857+ if (x[off+l]!=',')
2858+ strerr_die3x(111,fatal,"unable to parse IP address ",x+off);
2859+ off+=l+1;
2860+ }
2861+ udp53=(int *) alloc(sizeof(int) *cnt);
2862+ if (!udp53) nomem();
2863+ iop=(iopause_fd *) alloc(sizeof(*iop) * cnt);
2864+ if (!iop) nomem();
2865+
2866+ off=cnt=0;
2867+ while (x[off]) {
2868+ unsigned int l;
2869+ uint32 ifid=0;
2870+ l=ip6_scan(x+off,ip);
2871+ udp53[cnt] = socket_udp6();
2872+ if (udp53[cnt] == -1)
2873+ strerr_die2sys(111,fatal,"unable to create UDP socket: ");
2874+ if (x[off+l]=='%') {
2875+ char* interface=x+off+l+1;
2876+ int Len=str_chr(interface,',');
2877+ if (interface[Len]) {
2878+ interface[Len]=0;
2879+ ifid=socket_getifidx(interface);
2880+ interface[Len]=',';
2881+ } else
2882+ ifid=socket_getifidx(interface);
2883+ l+=Len;
2884+ }
2885+ if (socket_bind6_reuse(udp53[cnt],ip,53,ifid) == -1)
2886+ strerr_die2sys(111,fatal,"unable to bind UDP socket: ");
2887+ ndelay_off(udp53[cnt]);
2888+ socket_tryreservein(udp53[cnt],65536);
2889+ iop[cnt].fd=udp53[cnt];
2890+ iop[cnt].events=IOPAUSE_READ;
2891+ cnt++;
2892+ if (!x[off+l]) break;
2893+ off+=l+1;
2894+ }
2895 droproot(fatal);
2896
2897 initialize();
2898-
2899- ndelay_off(udp53);
2900- socket_tryreservein(udp53,65536);
2901
2902 buffer_putsflush(buffer_2,starting);
2903
2904 for (;;) {
2905- len = socket_recv4(udp53,buf,sizeof buf,ip,&port);
2906- if (len < 0) continue;
2907- if (!doit()) continue;
2908- if (response_len > 512) response_tc();
2909- socket_send4(udp53,response,response_len,ip,port);
2910- /* may block for buffer space; if it fails, too bad */
2911+ struct taia stamp;
2912+ struct taia deadline;
2913+ unsigned int i;
2914+ uint32 ifid;
2915+ taia_now(&stamp);
2916+ taia_uint(&deadline,300);
2917+ taia_add(&deadline,&deadline,&stamp);
2918+ iopause(iop,cnt,&deadline,&stamp);
2919+ for (i=0;i<cnt;i++)
2920+ if (iop[i].revents) {
2921+ len = socket_recv6(udp53[i],buf,sizeof buf,ip,&port,&ifid);
2922+ if (len < 0) continue;
2923+ if (!doit()) continue;
2924+ if (response_len > 512) response_tc();
2925+ socket_send6(udp53[i],response,response_len,ip,port,ifid);
2926+ /* may block for buffer space; if it fails, too bad */
2927+ }
2928 }
2929 }
2930diff --git a/sockaddr_in6.h1 b/sockaddr_in6.h1
2931new file mode 100644
2932index 0000000..b1f8f5e
2933--- /dev/null
2934+++ b/sockaddr_in6.h1
2935@@ -0,0 +1,21 @@
2936+#include "haveip6.h"
2937+#ifdef LIBC_HAS_IP6
2938+#include <sys/types.h>
2939+#include <sys/socket.h>
2940+#define sockaddr_in6 blub
2941+#include <netinet/in.h>
2942+#undef sockaddr_in6
2943+
2944+struct sockaddr_in6 {
2945+ sa_family_t sin6_family; /* AF_INET6 */
2946+ unsigned short sin6_port; /* transport layer port # */
2947+ uint32_t sin6_flowinfo; /* IPv6 traffic class & flow info */
2948+ struct in6_addr sin6_addr; /* IPv6 address */
2949+ uint32_t sin6_scope_id; /* set of interfaces for a scope */
2950+};
2951+
2952+#else
2953+#include <sys/types.h>
2954+#include <sys/socket.h>
2955+#include <netinet/in.h>
2956+#endif
2957diff --git a/sockaddr_in6.h2 b/sockaddr_in6.h2
2958new file mode 100644
2959index 0000000..d484041
2960--- /dev/null
2961+++ b/sockaddr_in6.h2
2962@@ -0,0 +1,4 @@
2963+#include <sys/types.h>
2964+#include <sys/socket.h>
2965+#include <netinet/in.h>
2966+
2967diff --git a/socket.h b/socket.h
2968index 95e2a7c..bbb0f82 100644
2969--- a/socket.h
2970+++ b/socket.h
2971@@ -2,21 +2,37 @@
2972 #define SOCKET_H
2973
2974 #include "uint16.h"
2975+#include "uint32.h"
2976
2977 extern int socket_tcp(void);
2978 extern int socket_udp(void);
2979+extern int socket_tcp6(void);
2980+extern int socket_udp6(void);
2981
2982 extern int socket_connect4(int,const char *,uint16);
2983+extern int socket_connect6(int s,const char ip[16],uint16 port,uint32 scope_id);
2984 extern int socket_connected(int);
2985-extern int socket_bind4(int,char *,uint16);
2986+extern int socket_bind4(int,const char *,uint16);
2987 extern int socket_bind4_reuse(int,char *,uint16);
2988+extern int socket_bind6(int s,const char *ip,uint16 port,uint32 scope_id);
2989+extern int socket_bind6_reuse(int s,const char *ip,uint16 port,uint32 scope_id);
2990 extern int socket_listen(int,int);
2991 extern int socket_accept4(int,char *,uint16 *);
2992+extern int socket_accept6(int s,char *ip,uint16 *port,uint32 *scope_id);
2993 extern int socket_recv4(int,char *,int,char *,uint16 *);
2994 extern int socket_send4(int,const char *,int,const char *,uint16);
2995+extern int socket_recv6(int s,char *buf,unsigned int len,char *ip,uint16 *port,uint32 *scope_id);
2996+extern int socket_send6(int s,const char *buf,unsigned int len,const char *ip,uint16 port,uint32 scope_id);
2997 extern int socket_local4(int,char *,uint16 *);
2998 extern int socket_remote4(int,char *,uint16 *);
2999+extern int socket_local6(int s,char *ip,uint16 *port,uint32 *scope_id);
3000+extern int socket_remote6(int s,char *ip,uint16 *port,uint32 *scope_id);
3001
3002 extern void socket_tryreservein(int,int);
3003
3004+extern const char* socket_getifname(uint32 interface);
3005+extern uint32 socket_getifidx(const char *ifname);
3006+
3007+extern int noipv6;
3008+
3009 #endif
3010diff --git a/socket_accept6.c b/socket_accept6.c
3011new file mode 100644
3012index 0000000..48a0b6d
3013--- /dev/null
3014+++ b/socket_accept6.c
3015@@ -0,0 +1,43 @@
3016+#include <sys/param.h>
3017+#include <sys/socket.h>
3018+#include <netinet/in.h>
3019+#include "byte.h"
3020+#include "socket.h"
3021+#include "ip6.h"
3022+#include "haveip6.h"
3023+#include "error.h"
3024+
3025+int socket_accept6(int s,char ip[16],uint16 *port,uint32 *scope_id)
3026+{
3027+#ifdef LIBC_HAS_IP6
3028+ struct sockaddr_in6 sa;
3029+#else
3030+ struct sockaddr_in sa;
3031+#endif
3032+ unsigned int dummy = sizeof sa;
3033+ int fd;
3034+
3035+ fd = accept(s,(struct sockaddr *) &sa,&dummy);
3036+ if (fd == -1) return -1;
3037+
3038+#ifdef LIBC_HAS_IP6
3039+ if (sa.sin6_family==AF_INET) {
3040+ struct sockaddr_in *sa4=(struct sockaddr_in*)&sa;
3041+ byte_copy(ip,12,V4mappedprefix);
3042+ byte_copy(ip+12,4,(char *) &sa4->sin_addr);
3043+ uint16_unpack_big((char *) &sa4->sin_port,port);
3044+ return fd;
3045+ }
3046+ byte_copy(ip,16,(char *) &sa.sin6_addr);
3047+ uint16_unpack_big((char *) &sa.sin6_port,port);
3048+ if (scope_id) *scope_id=sa.sin6_scope_id;
3049+
3050+ return fd;
3051+#else
3052+ byte_copy(ip,12,V4mappedprefix);
3053+ byte_copy(ip+12,4,(char *) &sa.sin_addr);
3054+ uint16_unpack_big((char *) &sa.sin_port,port);
3055+ if (scope_id) *scope_id=0;
3056+ return fd;
3057+#endif
3058+}
3059diff --git a/socket_bind.c b/socket_bind.c
3060index 20830a4..a33efca 100644
3061--- a/socket_bind.c
3062+++ b/socket_bind.c
3063@@ -5,7 +5,7 @@
3064 #include "byte.h"
3065 #include "socket.h"
3066
3067-int socket_bind4(int s,char ip[4],uint16 port)
3068+int socket_bind4(int s,const char ip[4],uint16 port)
3069 {
3070 struct sockaddr_in sa;
3071
3072diff --git a/socket_bind6.c b/socket_bind6.c
3073new file mode 100644
3074index 0000000..20b22b8
3075--- /dev/null
3076+++ b/socket_bind6.c
3077@@ -0,0 +1,43 @@
3078+#include <sys/param.h>
3079+#include "sockaddr_in6.h"
3080+#include "byte.h"
3081+#include "socket.h"
3082+#include "ip6.h"
3083+#include "haveip6.h"
3084+#include "error.h"
3085+
3086+int socket_bind6(int s,const char ip[16],uint16 port,uint32 scope_id)
3087+{
3088+#ifdef LIBC_HAS_IP6
3089+ struct sockaddr_in6 sa;
3090+
3091+ if (noipv6) {
3092+#endif
3093+ int i;
3094+ for (i=0; i<16; i++)
3095+ if (ip[i]!=0) break;
3096+ if (i==16 || ip6_isv4mapped(ip))
3097+ return socket_bind4(s,ip+12,port);
3098+#ifdef LIBC_HAS_IP6
3099+ }
3100+ byte_zero(&sa,sizeof sa);
3101+ sa.sin6_family = AF_INET6;
3102+ uint16_pack_big((char *) &sa.sin6_port,port);
3103+/* implicit: sa.sin6_flowinfo = 0; */
3104+ byte_copy((char *) &sa.sin6_addr,16,ip);
3105+ sa.sin6_scope_id=scope_id;
3106+
3107+ return bind(s,(struct sockaddr *) &sa,sizeof sa);
3108+#else
3109+ errno=error_proto;
3110+ return -1;
3111+#endif
3112+}
3113+
3114+int socket_bind6_reuse(int s,const char ip[16],uint16 port,uint32 scope_id)
3115+{
3116+ int opt = 1;
3117+ setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt);
3118+ return socket_bind6(s,ip,port,scope_id);
3119+}
3120+
3121diff --git a/socket_connect6.c b/socket_connect6.c
3122new file mode 100644
3123index 0000000..d2df4a2
3124--- /dev/null
3125+++ b/socket_connect6.c
3126@@ -0,0 +1,39 @@
3127+#include <sys/param.h>
3128+#include <sys/types.h>
3129+#include <sys/socket.h>
3130+#include <netinet/in.h>
3131+#include <errno.h>
3132+#include "byte.h"
3133+#include "socket.h"
3134+#include "ip6.h"
3135+#include "haveip6.h"
3136+#include "error.h"
3137+#include "uint32.h"
3138+#include "ip4.h"
3139+
3140+int socket_connect6(int s,const char ip[16],uint16 port,uint32 scope_id)
3141+{
3142+#ifdef LIBC_HAS_IP6
3143+ struct sockaddr_in6 sa;
3144+
3145+ if (noipv6) {
3146+#endif
3147+ if (ip6_isv4mapped(ip))
3148+ return socket_connect4(s,ip+12,port);
3149+ if (byte_equal(ip,16,V6loopback))
3150+ return socket_connect4(s,ip4loopback,port);
3151+#ifdef LIBC_HAS_IP6
3152+ }
3153+ byte_zero(&sa,sizeof sa);
3154+ sa.sin6_family = PF_INET6;
3155+ uint16_pack_big((char *) &sa.sin6_port,port);
3156+ sa.sin6_flowinfo = 0;
3157+ sa.sin6_scope_id = scope_id;
3158+ byte_copy((char *) &sa.sin6_addr,16,ip);
3159+
3160+ return connect(s,(struct sockaddr *) &sa,sizeof sa);
3161+#else
3162+ errno=error_proto;
3163+ return -1;
3164+#endif
3165+}
3166diff --git a/socket_getifidx.c b/socket_getifidx.c
3167new file mode 100644
3168index 0000000..c71fc48
3169--- /dev/null
3170+++ b/socket_getifidx.c
3171@@ -0,0 +1,13 @@
3172+#include <sys/types.h>
3173+#include <sys/socket.h>
3174+#include <net/if.h>
3175+#include "socket.h"
3176+#include "haven2i.h"
3177+
3178+uint32 socket_getifidx(const char* ifname) {
3179+#ifdef HAVE_N2I
3180+ return if_nametoindex(ifname);
3181+#else
3182+ return 0;
3183+#endif
3184+}
3185diff --git a/socket_noipv6.c b/socket_noipv6.c
3186new file mode 100644
3187index 0000000..289d699
3188--- /dev/null
3189+++ b/socket_noipv6.c
3190@@ -0,0 +1,7 @@
3191+#include "haveip6.h"
3192+
3193+#ifdef LIBC_HAS_IP6
3194+int noipv6=0;
3195+#else
3196+int noipv6=1;
3197+#endif
3198diff --git a/socket_recv6.c b/socket_recv6.c
3199new file mode 100644
3200index 0000000..1fb9b4d
3201--- /dev/null
3202+++ b/socket_recv6.c
3203@@ -0,0 +1,42 @@
3204+#include <sys/param.h>
3205+#include "sockaddr_in6.h"
3206+#include "byte.h"
3207+#include "socket.h"
3208+#include "ip6.h"
3209+#include "haveip6.h"
3210+#include "error.h"
3211+
3212+int socket_recv6(int s,char *buf,unsigned int len,char ip[16],uint16 *port,uint32 *scope_id)
3213+{
3214+#ifdef LIBC_HAS_IP6
3215+ struct sockaddr_in6 sa;
3216+#else
3217+ struct sockaddr_in sa;
3218+#endif
3219+ unsigned int dummy = sizeof sa;
3220+ int r;
3221+
3222+ byte_zero(&sa,dummy);
3223+ r = recvfrom(s,buf,len,0,(struct sockaddr *) &sa,&dummy);
3224+ if (r == -1) return -1;
3225+
3226+#ifdef LIBC_HAS_IP6
3227+ if (noipv6) {
3228+ struct sockaddr_in *sa4=(struct sockaddr_in *)&sa;
3229+ byte_copy(ip,12,V4mappedprefix);
3230+ byte_copy(ip+12,4,(char *) &sa4->sin_addr);
3231+ uint16_unpack_big((char *) &sa4->sin_port,port);
3232+ return r;
3233+ }
3234+ byte_copy(ip,16,(char *) &sa.sin6_addr);
3235+ uint16_unpack_big((char *) &sa.sin6_port,port);
3236+ if (scope_id) *scope_id=sa.sin6_scope_id;
3237+#else
3238+ byte_copy(ip,12,(char *)V4mappedprefix);
3239+ byte_copy(ip+12,4,(char *) &sa.sin_addr);
3240+ uint16_unpack_big((char *) &sa.sin_port,port);
3241+ if (scope_id) *scope_id=0;
3242+#endif
3243+
3244+ return r;
3245+}
3246diff --git a/socket_send6.c b/socket_send6.c
3247new file mode 100644
3248index 0000000..ded6793
3249--- /dev/null
3250+++ b/socket_send6.c
3251@@ -0,0 +1,39 @@
3252+#include <sys/types.h>
3253+#include <sys/param.h>
3254+#include <sys/socket.h>
3255+#include <netinet/in.h>
3256+#include "byte.h"
3257+#include "socket.h"
3258+#include "ip6.h"
3259+#include "haveip6.h"
3260+#include "error.h"
3261+
3262+int socket_send6(int s,const char *buf,unsigned int len,const char ip[16],uint16 port,uint32 scope_id)
3263+{
3264+#ifdef LIBC_HAS_IP6
3265+ struct sockaddr_in6 sa;
3266+#else
3267+ struct sockaddr_in sa;
3268+#endif
3269+
3270+ byte_zero(&sa,sizeof sa);
3271+#ifdef LIBC_HAS_IP6
3272+ if (noipv6) {
3273+#endif
3274+ if (ip6_isv4mapped(ip))
3275+ return socket_send4(s,buf,len,ip+12,port);
3276+ if (byte_equal(ip,16,V6loopback))
3277+ return socket_send4(s,buf,len,ip4loopback,port);
3278+#ifdef LIBC_HAS_IP6
3279+ errno=error_proto;
3280+ return -1;
3281+ }
3282+ sa.sin6_family = AF_INET6;
3283+ uint16_pack_big((char *) &sa.sin6_port,port);
3284+ byte_copy((char *) &sa.sin6_addr,16,ip);
3285+ return sendto(s,buf,len,0,(struct sockaddr *) &sa,sizeof sa);
3286+#else
3287+ errno=error_proto;
3288+ return -1;
3289+#endif
3290+}
3291diff --git a/socket_tcp6.c b/socket_tcp6.c
3292new file mode 100644
3293index 0000000..77bf7bd
3294--- /dev/null
3295+++ b/socket_tcp6.c
3296@@ -0,0 +1,44 @@
3297+#include <sys/types.h>
3298+#include <sys/param.h>
3299+#include <sys/socket.h>
3300+#include <netinet/in.h>
3301+#include <errno.h>
3302+#include <unistd.h>
3303+#include "ndelay.h"
3304+#include "socket.h"
3305+#include "haveip6.h"
3306+#include "error.h"
3307+
3308+#ifndef EAFNOSUPPORT
3309+#define EAFNOSUPPORT EINVAL
3310+#endif
3311+
3312+int socket_tcp6(void)
3313+{
3314+#ifdef LIBC_HAS_IP6
3315+ int s;
3316+
3317+ if (noipv6) goto compat;
3318+ s = socket(PF_INET6,SOCK_STREAM,0);
3319+ if (s == -1) {
3320+ if (errno == EINVAL || errno == EAFNOSUPPORT) {
3321+compat:
3322+ s=socket(AF_INET,SOCK_STREAM,0);
3323+ noipv6=1;
3324+ if (s==-1) return -1;
3325+ } else
3326+ return -1;
3327+ }
3328+ if (ndelay_on(s) == -1) { close(s); return -1; }
3329+#ifdef IPV6_V6ONLY
3330+ {
3331+ int zero=0;
3332+ setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&zero,sizeof(zero));
3333+ }
3334+#endif
3335+ return s;
3336+#else
3337+ return socket_tcp();
3338+#endif
3339+}
3340+
3341diff --git a/socket_udp6.c b/socket_udp6.c
3342new file mode 100644
3343index 0000000..3a10f49
3344--- /dev/null
3345+++ b/socket_udp6.c
3346@@ -0,0 +1,43 @@
3347+#include <sys/types.h>
3348+#include <sys/param.h>
3349+#include <sys/socket.h>
3350+#include <netinet/in.h>
3351+#include <errno.h>
3352+#include <unistd.h>
3353+#include "ndelay.h"
3354+#include "socket.h"
3355+#include "haveip6.h"
3356+#include "error.h"
3357+
3358+#ifndef EAFNOSUPPORT
3359+#define EAFNOSUPPORT EINVAL
3360+#endif
3361+
3362+int socket_udp6(void)
3363+{
3364+#ifdef LIBC_HAS_IP6
3365+ int s;
3366+
3367+ if (noipv6) goto compat;
3368+ s = socket(PF_INET6,SOCK_DGRAM,0);
3369+ if (s == -1) {
3370+ if (errno == EINVAL || errno == EAFNOSUPPORT) {
3371+compat:
3372+ s=socket(AF_INET,SOCK_DGRAM,0);
3373+ noipv6=1;
3374+ if (s==-1) return -1;
3375+ } else
3376+ return -1;
3377+ }
3378+ if (ndelay_on(s) == -1) { close(s); return -1; }
3379+#ifdef IPV6_V6ONLY
3380+ {
3381+ int zero=0;
3382+ setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&zero,sizeof(zero));
3383+ }
3384+#endif
3385+ return s;
3386+#else
3387+ return socket_udp();
3388+#endif
3389+}
3390diff --git a/tdlookup.c b/tdlookup.c
3391index da7420d..d3e473e 100644
3392--- a/tdlookup.c
3393+++ b/tdlookup.c
3394@@ -8,6 +8,7 @@
3395 #include "dns.h"
3396 #include "seek.h"
3397 #include "response.h"
3398+#include "ip6.h"
3399
3400 static int want(const char *owner,const char type[2])
3401 {
3402@@ -119,8 +120,9 @@ static int doit(char *q,char qtype[2])
3403 char x[20];
3404 uint16 u16;
3405 char addr[8][4];
3406- int addrnum;
3407- uint32 addrttl;
3408+ char addr6[8][16];
3409+ int addrnum,addr6num;
3410+ uint32 addrttl,addr6ttl;
3411 int i;
3412
3413 anpos = response_len;
3414@@ -152,8 +154,8 @@ static int doit(char *q,char qtype[2])
3415 wild = q;
3416
3417 for (;;) {
3418- addrnum = 0;
3419- addrttl = 0;
3420+ addrnum = addr6num = 0;
3421+ addrttl = addr6ttl = 0;
3422 cdb_findstart(&c);
3423 while (r = find(wild,wild != q)) {
3424 if (r == -1) return 0;
3425@@ -171,6 +173,17 @@ static int doit(char *q,char qtype[2])
3426 if (addrnum < 1000000) ++addrnum;
3427 continue;
3428 }
3429+ if (byte_equal(type,2,DNS_T_AAAA) && (dlen - dpos == 16)) {
3430+ addr6ttl = ttl;
3431+ i = dns_random(addr6num + 1);
3432+ if (i < 8) {
3433+ if ((i < addr6num) && (addr6num < 8))
3434+ byte_copy(addr6[addr6num],16,addr6[i]);
3435+ byte_copy(addr6[i],16,data + dpos);
3436+ }
3437+ if (addr6num < 1000000) ++addr6num;
3438+ continue;
3439+ }
3440 if (!response_rstart(q,type,ttl)) return 0;
3441 if (byte_equal(type,2,DNS_T_NS) || byte_equal(type,2,DNS_T_CNAME) || byte_equal(type,2,DNS_T_PTR)) {
3442 if (!doname()) return 0;
3443@@ -195,6 +208,12 @@ static int doit(char *q,char qtype[2])
3444 if (!response_addbytes(addr[i],4)) return 0;
3445 response_rfinish(RESPONSE_ANSWER);
3446 }
3447+ for (i = 0;i < addr6num;++i)
3448+ if (i < 8) {
3449+ if (!response_rstart(q,DNS_T_AAAA,addr6ttl)) return 0;
3450+ if (!response_addbytes(addr6[i],16)) return 0;
3451+ response_rfinish(RESPONSE_ANSWER);
3452+ }
3453
3454 if (flagfound) break;
3455 if (wild == control) break;
3456@@ -259,6 +278,11 @@ static int doit(char *q,char qtype[2])
3457 if (!dobytes(4)) return 0;
3458 response_rfinish(RESPONSE_ADDITIONAL);
3459 }
3460+ else if (byte_equal(type,2,DNS_T_AAAA)) {
3461+ if (!response_rstart(d1,DNS_T_AAAA,ttl)) return 0;
3462+ if (!dobytes(16)) return 0;
3463+ response_rfinish(RESPONSE_ADDITIONAL);
3464+ }
3465 }
3466 }
3467 }
3468@@ -278,7 +302,7 @@ static int doit(char *q,char qtype[2])
3469 return 1;
3470 }
3471
3472-int respond(char *q,char qtype[2],char ip[4])
3473+int respond(char *q,char qtype[2],char ip[16])
3474 {
3475 int fd;
3476 int r;
3477@@ -292,15 +316,17 @@ int respond(char *q,char qtype[2],char ip[4])
3478 byte_zero(clientloc,2);
3479 key[0] = 0;
3480 key[1] = '%';
3481- byte_copy(key + 2,4,ip);
3482- r = cdb_find(&c,key,6);
3483- if (!r) r = cdb_find(&c,key,5);
3484- if (!r) r = cdb_find(&c,key,4);
3485- if (!r) r = cdb_find(&c,key,3);
3486- if (!r) r = cdb_find(&c,key,2);
3487- if (r == -1) return 0;
3488- if (r && (cdb_datalen(&c) == 2))
3489- if (cdb_read(&c,clientloc,2,cdb_datapos(&c)) == -1) return 0;
3490+ if (byte_equal(ip,12,V4mappedprefix)) {
3491+ byte_copy(key + 2,4,ip+12);
3492+ r = cdb_find(&c,key,6);
3493+ if (!r) r = cdb_find(&c,key,5);
3494+ if (!r) r = cdb_find(&c,key,4);
3495+ if (!r) r = cdb_find(&c,key,3);
3496+ if (!r) r = cdb_find(&c,key,2);
3497+ if (r == -1) return 0;
3498+ if (r && (cdb_datalen(&c) == 2))
3499+ if (cdb_read(&c,clientloc,2,cdb_datapos(&c)) == -1) return 0;
3500+ }
3501
3502 r = doit(q,qtype);
3503
3504diff --git a/tinydns-conf.c b/tinydns-conf.c
3505index d3a4ce5..db83f11 100644
3506--- a/tinydns-conf.c
3507+++ b/tinydns-conf.c
3508@@ -82,6 +82,18 @@ int main(int argc,char **argv)
3509 finish();
3510 perm(0755);
3511
3512+ start("root/add-host6");
3513+ outs("#!/bin/sh\nexec ");
3514+ outs(auto_home); outs("/bin/tinydns-edit data data.new add host6 ${1+\"$@\"}\n");
3515+ finish();
3516+ perm(0755);
3517+
3518+ start("root/add-alias6");
3519+ outs("#!/bin/sh\nexec ");
3520+ outs(auto_home); outs("/bin/tinydns-edit data data.new add alias6 ${1+\"$@\"}\n");
3521+ finish();
3522+ perm(0755);
3523+
3524 start("root/add-mx");
3525 outs("#!/bin/sh\nexec ");
3526 outs(auto_home); outs("/bin/tinydns-edit data data.new add mx ${1+\"$@\"}\n");
3527diff --git a/tinydns-data.c b/tinydns-data.c
3528index ba82f84..b42bd62 100644
3529--- a/tinydns-data.c
3530+++ b/tinydns-data.c
3531@@ -8,6 +8,7 @@
3532 #include "byte.h"
3533 #include "fmt.h"
3534 #include "ip4.h"
3535+#include "ip6.h"
3536 #include "exit.h"
3537 #include "case.h"
3538 #include "scan.h"
3539@@ -172,6 +173,7 @@ static stralloc f[NUMFIELDS];
3540 static char *d1;
3541 static char *d2;
3542 char dptr[DNS_NAME4_DOMAIN];
3543+char d6ptr[DNS_NAME6_DOMAIN];
3544
3545 char strnum[FMT_ULONG];
3546
3547@@ -193,6 +195,7 @@ int main()
3548 char loc[2];
3549 unsigned long u;
3550 char ip[4];
3551+ char ip6[16];
3552 char type[2];
3553 char soa[20];
3554 char buf[4];
3555@@ -339,6 +342,33 @@ int main()
3556 }
3557 break;
3558
3559+ case '6': case '3':
3560+ if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
3561+ if (!stralloc_0(&f[2])) nomem();
3562+ if (!scan_ulong(f[2].s,&ttl)) ttl = TTL_POSITIVE;
3563+ ttdparse(&f[3],ttd);
3564+ locparse(&f[4],loc);
3565+
3566+ if (!stralloc_0(&f[1])) nomem();
3567+ if (ip6_scan_flat(f[1].s,ip6)) {
3568+ rr_start(DNS_T_AAAA,ttl,ttd,loc);
3569+ rr_add(ip6,16);
3570+ rr_finish(d1);
3571+
3572+ if (line.s[0] == '6') { /* emit both .ip6.arpa and .ip6.int */
3573+ dns_name6_domain(d6ptr,ip6,DNS_IP6_ARPA);
3574+ rr_start(DNS_T_PTR,ttl,ttd,loc);
3575+ rr_addname(d1);
3576+ rr_finish(d6ptr);
3577+
3578+ dns_name6_domain(d6ptr,ip6,DNS_IP6_INT);
3579+ rr_start(DNS_T_PTR,ttl,ttd,loc);
3580+ rr_addname(d1);
3581+ rr_finish(d6ptr);
3582+ }
3583+ }
3584+ break;
3585+
3586 case '@':
3587 if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
3588 if (!stralloc_0(&f[4])) nomem();
3589diff --git a/tinydns-edit.c b/tinydns-edit.c
3590index 126a7e0..8633220 100644
3591--- a/tinydns-edit.c
3592+++ b/tinydns-edit.c
3593@@ -13,6 +13,7 @@
3594 #include "str.h"
3595 #include "fmt.h"
3596 #include "ip4.h"
3597+#include "ip6.h"
3598 #include "dns.h"
3599
3600 #define FATAL "tinydns-edit: fatal: "
3601@@ -25,7 +26,8 @@ char *fnnew;
3602
3603 void die_usage()
3604 {
3605- strerr_die1x(100,"tinydns-edit: usage: tinydns-edit data data.new add [ns|childns|host|alias|mx] domain a.b.c.d");
3606+ strerr_die1x(100,"tinydns-edit: usage: tinydns-edit data data.new add [ns|childns|host|alias|mx] domain a.b.c.d\n"
3607+ "tinydns-edit: usage: tinydns-edit data data.new add [host6|alias6] domain a:b:c:d:e:f:g:h");
3608 }
3609 void nomem()
3610 {
3611@@ -43,6 +45,7 @@ void die_write()
3612 char mode;
3613 static char *target;
3614 char targetip[4];
3615+char targetip6[16];
3616
3617 int fd;
3618 buffer b;
3619@@ -61,7 +64,9 @@ static stralloc f[NUMFIELDS];
3620 static char *d1;
3621 static char *d2;
3622 char ip[4];
3623+char ip6[16];
3624 char ipstr[IP4_FMT];
3625+char ip6str[IP6_FMT];
3626 char strnum[FMT_ULONG];
3627
3628 static char *names[26];
3629@@ -96,7 +101,9 @@ int main(int argc,char **argv)
3630 if (str_equal(*argv,"ns")) mode = '.';
3631 else if (str_equal(*argv,"childns")) mode = '&';
3632 else if (str_equal(*argv,"host")) mode = '=';
3633+ else if (str_equal(*argv,"host6")) mode = '6';
3634 else if (str_equal(*argv,"alias")) mode = '+';
3635+ else if (str_equal(*argv,"alias6")) mode = '3';
3636 else if (str_equal(*argv,"mx")) mode = '@';
3637 else die_usage();
3638
3639@@ -104,7 +111,11 @@ int main(int argc,char **argv)
3640 if (!dns_domain_fromdot(&target,*argv,str_len(*argv))) nomem();
3641
3642 if (!*++argv) die_usage();
3643- if (!ip4_scan(*argv,targetip)) die_usage();
3644+ if (mode == '6' || mode == '3') {
3645+ if (!ip6_scan(*argv,targetip6)) die_usage();
3646+ } else {
3647+ if (!ip4_scan(*argv,targetip)) die_usage();
3648+ }
3649
3650 umask(077);
3651
3652@@ -129,7 +140,7 @@ int main(int argc,char **argv)
3653 if (!dns_domain_fromdot(&names[i],f[0].s,f[0].len)) nomem();
3654 }
3655 break;
3656- case '+': case '=':
3657+ case '+': case '=': case '6': case '3':
3658 ttl = TTL_POSITIVE;
3659 break;
3660 case '@':
3661@@ -203,6 +214,18 @@ int main(int argc,char **argv)
3662 }
3663 break;
3664
3665+ case '6':
3666+ if (line.s[0] == '6') {
3667+ if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
3668+ if (dns_domain_equal(d1,target))
3669+ strerr_die2x(100,FATAL,"host name already used");
3670+ if (!stralloc_0(&f[1])) nomem();
3671+ if (ip6_scan(f[1].s,ip6))
3672+ if (byte_equal(ip,16,targetip6))
3673+ strerr_die2x(100,FATAL,"IPv6 address already used");
3674+ }
3675+ break;
3676+
3677 case '@':
3678 if (line.s[0] == '@') {
3679 if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem();
3680@@ -228,7 +251,11 @@ int main(int argc,char **argv)
3681 if (!stralloc_copyb(&f[0],&mode,1)) nomem();
3682 if (!dns_domain_todot_cat(&f[0],target)) nomem();
3683 if (!stralloc_cats(&f[0],":")) nomem();
3684- if (!stralloc_catb(&f[0],ipstr,ip4_fmt(ipstr,targetip))) nomem();
3685+ if (mode == '6' || mode == '3') {
3686+ if (!stralloc_catb(&f[0],ip6str,ip6_fmt_flat(ip6str,targetip6))) nomem();
3687+ } else {
3688+ if (!stralloc_catb(&f[0],ipstr,ip4_fmt(ipstr,targetip))) nomem();
3689+ }
3690 switch(mode) {
3691 case '.': case '&': case '@':
3692 for (i = 0;i < 26;++i)
3693diff --git a/tryip6.c b/tryip6.c
3694new file mode 100644
3695index 0000000..e0d7cfb
3696--- /dev/null
3697+++ b/tryip6.c
3698@@ -0,0 +1,8 @@
3699+#include <sys/types.h>
3700+#include <sys/socket.h>
3701+#include <netinet/in.h>
3702+
3703+main() {
3704+ struct sockaddr_in6 sa;
3705+ sa.sin6_family = PF_INET6;
3706+}
3707diff --git a/tryn2i.c b/tryn2i.c
3708new file mode 100644
3709index 0000000..84c3a08
3710--- /dev/null
3711+++ b/tryn2i.c
3712@@ -0,0 +1,8 @@
3713+#include <sys/types.h>
3714+#include <sys/socket.h>
3715+#include <net/if.h>
3716+
3717+int main() {
3718+ static char ifname[IFNAMSIZ];
3719+ char *tmp=if_indextoname(0,ifname);
3720+}
3721diff --git a/trysa6.c b/trysa6.c
3722new file mode 100644
3723index 0000000..0fd180c
3724--- /dev/null
3725+++ b/trysa6.c
3726@@ -0,0 +1,8 @@
3727+#include <sys/types.h>
3728+#include <sys/socket.h>
3729+#include <netinet/in.h>
3730+
3731+main() {
3732+ struct sockaddr_in6 sa;
3733+ sa.sin6_scope_id = 1;
3734+}
3735--
37361.6.2
3737