Browse Source

Plan 9 from Bell Labs 2007-03-24

David du Colombier 17 years ago
parent
commit
8f1b2c17c5

+ 26 - 28
dist/replica/_plan9.db

@@ -340,10 +340,10 @@
 386/bin/ndb - 20000000775 sys sys 985743147 0
 386/bin/ndb/cs - 775 sys sys 1169612028 150911
 386/bin/ndb/csquery - 775 sys sys 1168402337 61702
-386/bin/ndb/dns - 775 sys sys 1173385412 273424
-386/bin/ndb/dnsdebug - 775 sys sys 1173385413 247453
-386/bin/ndb/dnsquery - 775 sys sys 1173113879 63870
-386/bin/ndb/dnstcp - 775 sys sys 1173385415 246310
+386/bin/ndb/dns - 775 sys sys 1174704817 277690
+386/bin/ndb/dnsdebug - 775 sys sys 1174704818 252154
+386/bin/ndb/dnsquery - 775 sys sys 1174704818 64417
+386/bin/ndb/dnstcp - 775 sys sys 1174704819 250526
 386/bin/ndb/ipquery - 775 sys sys 1169612031 96994
 386/bin/ndb/mkdb - 775 sys sys 1168402340 64211
 386/bin/ndb/mkhash - 775 sys sys 1168402340 84780
@@ -405,7 +405,7 @@
 386/bin/snap - 775 sys sys 1136346852 313627
 386/bin/snapfs - 775 sys sys 1134389876 388292
 386/bin/sniffer - 775 sys sys 1038443185 99028
-386/bin/snoopy - 775 sys sys 1173385415 192339
+386/bin/snoopy - 775 sys sys 1174704819 186527
 386/bin/sort - 775 sys sys 1168402349 82523
 386/bin/spin - 775 sys sys 1134151359 758520
 386/bin/split - 775 sys sys 1168402349 75886
@@ -7690,7 +7690,7 @@ sys/man/6/mnihongo - 664 sys sys 1158064572 716
 sys/man/6/mpictures - 664 sys sys 944959678 2899
 sys/man/6/ms - 664 sys sys 958249504 6815
 sys/man/6/namespace - 664 sys sys 1048637182 1576
-sys/man/6/ndb - 664 sys sys 1158358889 6579
+sys/man/6/ndb - 664 sys sys 1174688660 6670
 sys/man/6/plot - 664 sys sys 944959679 6739
 sys/man/6/plumb - 664 sys sys 969499892 10918
 sys/man/6/regexp - 664 sys sys 954089523 2050
@@ -7748,7 +7748,7 @@ sys/man/8/mkpaqfs - 664 sys sys 1018386778 892
 sys/man/8/mksacfs - 664 sys sys 964886843 710
 sys/man/8/mouse - 664 sys sys 971455511 2476
 sys/man/8/na - 664 sys sys 958527089 859
-sys/man/8/ndb - 664 sys sys 1173401577 10952
+sys/man/8/ndb - 664 sys sys 1174626196 12927
 sys/man/8/newuser - 664 sys sys 1116954242 2418
 sys/man/8/nfsserver - 664 sys sys 1163208425 3587
 sys/man/8/pcmcia - 664 sys sys 944959679 408
@@ -12430,7 +12430,7 @@ sys/src/cmd/ip/snoopy/arp.c - 664 sys sys 1128179536 1914
 sys/src/cmd/ip/snoopy/bootp.c - 664 sys sys 1139667382 3442
 sys/src/cmd/ip/snoopy/dat.h - 664 sys sys 1146318302 1933
 sys/src/cmd/ip/snoopy/dhcp.c - 664 sys sys 1138463389 8958
-sys/src/cmd/ip/snoopy/dns.c - 664 sys sys 1144956382 14815
+sys/src/cmd/ip/snoopy/dns.c - 664 sys sys 1174678543 7931
 sys/src/cmd/ip/snoopy/dump.c - 664 sys sys 1138463389 1078
 sys/src/cmd/ip/snoopy/eap.c - 664 sys sys 1128179537 3996
 sys/src/cmd/ip/snoopy/eap_identity.c - 664 sys sys 1128179537 50
@@ -12446,7 +12446,7 @@ sys/src/cmd/ip/snoopy/il.c - 664 sys sys 1139667365 2260
 sys/src/cmd/ip/snoopy/ip.c - 664 sys sys 1128179538 4300
 sys/src/cmd/ip/snoopy/ip6.c - 664 sys sys 1128179538 5371
 sys/src/cmd/ip/snoopy/main.c - 664 sys sys 1146318297 15720
-sys/src/cmd/ip/snoopy/mkfile - 664 sys sys 1144954564 889
+sys/src/cmd/ip/snoopy/mkfile - 664 sys sys 1174626161 985
 sys/src/cmd/ip/snoopy/ninep.c - 664 sys sys 1138463390 555
 sys/src/cmd/ip/snoopy/ospf.c - 664 sys sys 1138463391 7369
 sys/src/cmd/ip/snoopy/ppp.c - 664 sys sys 1128179539 10544
@@ -12672,30 +12672,28 @@ sys/src/cmd/mtime.c - 664 sys sys 1036172302 450
 sys/src/cmd/mug.c - 664 sys sys 1157143847 24888
 sys/src/cmd/mv.c - 664 sys sys 1163029439 4682
 sys/src/cmd/ndb - 20000000775 sys sys 1080135004 0
-sys/src/cmd/ndb/convDNS2M.c - 664 sys sys 1117253517 6866
-sys/src/cmd/ndb/convM2DNS.c - 664 sys sys 1060612175 7248
+sys/src/cmd/ndb/convDNS2M.c - 664 sys sys 1174690184 6801
+sys/src/cmd/ndb/convM2DNS.c - 664 sys sys 1174690173 10779
 sys/src/cmd/ndb/cs.c - 664 sys sys 1163208159 33080
-sys/src/cmd/ndb/csquery.c - 664 sys sys 1014926159 1062
-sys/src/cmd/ndb/dblookup.c - 664 sys sys 1143749799 18249
-sys/src/cmd/ndb/dn.acid - 664 sys sys 1144950752 20174
-sys/src/cmd/ndb/dn.c - 664 sys sys 1144952448 28763
-sys/src/cmd/ndb/dnarea.c - 664 sys sys 1121972945 2128
-sys/src/cmd/ndb/dnnotify.c - 664 sys sys 1144952457 3066
-sys/src/cmd/ndb/dnresolve.c - 664 sys sys 1166760846 15351
-sys/src/cmd/ndb/dns.c - 664 sys sys 1146746848 15309
-sys/src/cmd/ndb/dns.h - 664 sys sys 1144952221 10171
-sys/src/cmd/ndb/dnsdebug.c - 664 sys sys 1144952322 8492
-sys/src/cmd/ndb/dnserver.c - 664 sys sys 1143648239 3982
-sys/src/cmd/ndb/dnsquery.c - 664 sys sys 1120564707 2198
-sys/src/cmd/ndb/dnstcp.c - 664 sys sys 1144952355 7349
-sys/src/cmd/ndb/dnudpserver.c - 664 sys sys 1144969068 5337
+sys/src/cmd/ndb/csquery.c - 664 sys sys 1174626119 1073
+sys/src/cmd/ndb/dblookup.c - 664 sys sys 1174690228 20863
+sys/src/cmd/ndb/dn.c - 664 sys sys 1174690061 32609
+sys/src/cmd/ndb/dnarea.c - 664 sys sys 1174626121 2505
+sys/src/cmd/ndb/dnnotify.c - 664 sys sys 1174626121 3122
+sys/src/cmd/ndb/dnresolve.c - 664 sys sys 1174690047 25752
+sys/src/cmd/ndb/dns.c - 664 sys sys 1174626124 15895
+sys/src/cmd/ndb/dns.h - 664 sys sys 1174690654 10460
+sys/src/cmd/ndb/dnsdebug.c - 664 sys sys 1174690026 8779
+sys/src/cmd/ndb/dnserver.c - 664 sys sys 1174626125 4400
+sys/src/cmd/ndb/dnsquery.c - 664 sys sys 1174626126 2435
+sys/src/cmd/ndb/dnstcp.c - 664 sys sys 1174689582 7445
+sys/src/cmd/ndb/dnudpserver.c - 664 sys sys 1174626126 5497
 sys/src/cmd/ndb/ipquery.c - 664 sys sys 1124711423 773
 sys/src/cmd/ndb/mkdb.c - 664 sys sys 957402054 2886
-sys/src/cmd/ndb/mkfile - 664 sys sys 1055701930 1877
+sys/src/cmd/ndb/mkfile - 664 sys sys 1174623575 1984
 sys/src/cmd/ndb/mkhash.c - 664 sys sys 1014926160 2899
 sys/src/cmd/ndb/mkhosts.c - 664 sys sys 957402054 4294
-sys/src/cmd/ndb/query.c - 664 sys sys 1078782843 1120
-sys/src/cmd/ndb/time.c - 664 sys sys 957402055 321
+sys/src/cmd/ndb/query.c - 664 sys sys 1174623580 1137
 sys/src/cmd/netstat.c - 664 sys sys 1128255434 4086
 sys/src/cmd/news.c - 664 sys sys 1014926614 3778
 sys/src/cmd/nfs.c - 664 sys sys 1050068720 31096

+ 26 - 28
dist/replica/plan9.db

@@ -340,10 +340,10 @@
 386/bin/ndb - 20000000775 sys sys 985743147 0
 386/bin/ndb/cs - 775 sys sys 1169612028 150911
 386/bin/ndb/csquery - 775 sys sys 1168402337 61702
-386/bin/ndb/dns - 775 sys sys 1173385412 273424
-386/bin/ndb/dnsdebug - 775 sys sys 1173385413 247453
-386/bin/ndb/dnsquery - 775 sys sys 1173113879 63870
-386/bin/ndb/dnstcp - 775 sys sys 1173385415 246310
+386/bin/ndb/dns - 775 sys sys 1174704817 277690
+386/bin/ndb/dnsdebug - 775 sys sys 1174704818 252154
+386/bin/ndb/dnsquery - 775 sys sys 1174704818 64417
+386/bin/ndb/dnstcp - 775 sys sys 1174704819 250526
 386/bin/ndb/ipquery - 775 sys sys 1169612031 96994
 386/bin/ndb/mkdb - 775 sys sys 1168402340 64211
 386/bin/ndb/mkhash - 775 sys sys 1168402340 84780
@@ -405,7 +405,7 @@
 386/bin/snap - 775 sys sys 1136346852 313627
 386/bin/snapfs - 775 sys sys 1134389876 388292
 386/bin/sniffer - 775 sys sys 1038443185 99028
-386/bin/snoopy - 775 sys sys 1173385415 192339
+386/bin/snoopy - 775 sys sys 1174704819 186527
 386/bin/sort - 775 sys sys 1168402349 82523
 386/bin/spin - 775 sys sys 1134151359 758520
 386/bin/split - 775 sys sys 1168402349 75886
@@ -7690,7 +7690,7 @@ sys/man/6/mnihongo - 664 sys sys 1158064572 716
 sys/man/6/mpictures - 664 sys sys 944959678 2899
 sys/man/6/ms - 664 sys sys 958249504 6815
 sys/man/6/namespace - 664 sys sys 1048637182 1576
-sys/man/6/ndb - 664 sys sys 1158358889 6579
+sys/man/6/ndb - 664 sys sys 1174688660 6670
 sys/man/6/plot - 664 sys sys 944959679 6739
 sys/man/6/plumb - 664 sys sys 969499892 10918
 sys/man/6/regexp - 664 sys sys 954089523 2050
@@ -7748,7 +7748,7 @@ sys/man/8/mkpaqfs - 664 sys sys 1018386778 892
 sys/man/8/mksacfs - 664 sys sys 964886843 710
 sys/man/8/mouse - 664 sys sys 971455511 2476
 sys/man/8/na - 664 sys sys 958527089 859
-sys/man/8/ndb - 664 sys sys 1173401577 10952
+sys/man/8/ndb - 664 sys sys 1174626196 12927
 sys/man/8/newuser - 664 sys sys 1116954242 2418
 sys/man/8/nfsserver - 664 sys sys 1163208425 3587
 sys/man/8/pcmcia - 664 sys sys 944959679 408
@@ -12430,7 +12430,7 @@ sys/src/cmd/ip/snoopy/arp.c - 664 sys sys 1128179536 1914
 sys/src/cmd/ip/snoopy/bootp.c - 664 sys sys 1139667382 3442
 sys/src/cmd/ip/snoopy/dat.h - 664 sys sys 1146318302 1933
 sys/src/cmd/ip/snoopy/dhcp.c - 664 sys sys 1138463389 8958
-sys/src/cmd/ip/snoopy/dns.c - 664 sys sys 1144956382 14815
+sys/src/cmd/ip/snoopy/dns.c - 664 sys sys 1174678543 7931
 sys/src/cmd/ip/snoopy/dump.c - 664 sys sys 1138463389 1078
 sys/src/cmd/ip/snoopy/eap.c - 664 sys sys 1128179537 3996
 sys/src/cmd/ip/snoopy/eap_identity.c - 664 sys sys 1128179537 50
@@ -12446,7 +12446,7 @@ sys/src/cmd/ip/snoopy/il.c - 664 sys sys 1139667365 2260
 sys/src/cmd/ip/snoopy/ip.c - 664 sys sys 1128179538 4300
 sys/src/cmd/ip/snoopy/ip6.c - 664 sys sys 1128179538 5371
 sys/src/cmd/ip/snoopy/main.c - 664 sys sys 1146318297 15720
-sys/src/cmd/ip/snoopy/mkfile - 664 sys sys 1144954564 889
+sys/src/cmd/ip/snoopy/mkfile - 664 sys sys 1174626161 985
 sys/src/cmd/ip/snoopy/ninep.c - 664 sys sys 1138463390 555
 sys/src/cmd/ip/snoopy/ospf.c - 664 sys sys 1138463391 7369
 sys/src/cmd/ip/snoopy/ppp.c - 664 sys sys 1128179539 10544
@@ -12672,30 +12672,28 @@ sys/src/cmd/mtime.c - 664 sys sys 1036172302 450
 sys/src/cmd/mug.c - 664 sys sys 1157143847 24888
 sys/src/cmd/mv.c - 664 sys sys 1163029439 4682
 sys/src/cmd/ndb - 20000000775 sys sys 1080135004 0
-sys/src/cmd/ndb/convDNS2M.c - 664 sys sys 1117253517 6866
-sys/src/cmd/ndb/convM2DNS.c - 664 sys sys 1060612175 7248
+sys/src/cmd/ndb/convDNS2M.c - 664 sys sys 1174690184 6801
+sys/src/cmd/ndb/convM2DNS.c - 664 sys sys 1174690173 10779
 sys/src/cmd/ndb/cs.c - 664 sys sys 1163208159 33080
-sys/src/cmd/ndb/csquery.c - 664 sys sys 1014926159 1062
-sys/src/cmd/ndb/dblookup.c - 664 sys sys 1143749799 18249
-sys/src/cmd/ndb/dn.acid - 664 sys sys 1144950752 20174
-sys/src/cmd/ndb/dn.c - 664 sys sys 1144952448 28763
-sys/src/cmd/ndb/dnarea.c - 664 sys sys 1121972945 2128
-sys/src/cmd/ndb/dnnotify.c - 664 sys sys 1144952457 3066
-sys/src/cmd/ndb/dnresolve.c - 664 sys sys 1166760846 15351
-sys/src/cmd/ndb/dns.c - 664 sys sys 1146746848 15309
-sys/src/cmd/ndb/dns.h - 664 sys sys 1144952221 10171
-sys/src/cmd/ndb/dnsdebug.c - 664 sys sys 1144952322 8492
-sys/src/cmd/ndb/dnserver.c - 664 sys sys 1143648239 3982
-sys/src/cmd/ndb/dnsquery.c - 664 sys sys 1120564707 2198
-sys/src/cmd/ndb/dnstcp.c - 664 sys sys 1144952355 7349
-sys/src/cmd/ndb/dnudpserver.c - 664 sys sys 1144969068 5337
+sys/src/cmd/ndb/csquery.c - 664 sys sys 1174626119 1073
+sys/src/cmd/ndb/dblookup.c - 664 sys sys 1174690228 20863
+sys/src/cmd/ndb/dn.c - 664 sys sys 1174690061 32609
+sys/src/cmd/ndb/dnarea.c - 664 sys sys 1174626121 2505
+sys/src/cmd/ndb/dnnotify.c - 664 sys sys 1174626121 3122
+sys/src/cmd/ndb/dnresolve.c - 664 sys sys 1174690047 25752
+sys/src/cmd/ndb/dns.c - 664 sys sys 1174626124 15895
+sys/src/cmd/ndb/dns.h - 664 sys sys 1174690654 10460
+sys/src/cmd/ndb/dnsdebug.c - 664 sys sys 1174690026 8779
+sys/src/cmd/ndb/dnserver.c - 664 sys sys 1174626125 4400
+sys/src/cmd/ndb/dnsquery.c - 664 sys sys 1174626126 2435
+sys/src/cmd/ndb/dnstcp.c - 664 sys sys 1174689582 7445
+sys/src/cmd/ndb/dnudpserver.c - 664 sys sys 1174626126 5497
 sys/src/cmd/ndb/ipquery.c - 664 sys sys 1124711423 773
 sys/src/cmd/ndb/mkdb.c - 664 sys sys 957402054 2886
-sys/src/cmd/ndb/mkfile - 664 sys sys 1055701930 1877
+sys/src/cmd/ndb/mkfile - 664 sys sys 1174623575 1984
 sys/src/cmd/ndb/mkhash.c - 664 sys sys 1014926160 2899
 sys/src/cmd/ndb/mkhosts.c - 664 sys sys 957402054 4294
-sys/src/cmd/ndb/query.c - 664 sys sys 1078782843 1120
-sys/src/cmd/ndb/time.c - 664 sys sys 957402055 321
+sys/src/cmd/ndb/query.c - 664 sys sys 1174623580 1137
 sys/src/cmd/netstat.c - 664 sys sys 1128255434 4086
 sys/src/cmd/news.c - 664 sys sys 1014926614 3778
 sys/src/cmd/nfs.c - 664 sys sys 1050068720 31096

+ 40 - 0
dist/replica/plan9.log

@@ -47915,3 +47915,43 @@
 1174595406 0 a sys/src/9/pc/etherm10g.c - 664 sys sys 1174595240 27681
 1174595406 1 c sys/src/fs/pc/etherm10g.c - 664 sys sys 1174594317 25743
 1174615207 0 c sys/src/9/pc/archmp.c - 664 sys sys 1174614168 2407
+1174626007 0 c sys/src/cmd/ip/snoopy/dns.c - 664 sys sys 1174626160 7867
+1174626007 1 c sys/src/cmd/ip/snoopy/mkfile - 664 sys sys 1174626161 985
+1174626007 2 c sys/src/cmd/ndb/convDNS2M.c - 664 sys sys 1174626114 6856
+1174626007 3 c sys/src/cmd/ndb/convM2DNS.c - 664 sys sys 1174626117 10616
+1174626007 4 c sys/src/cmd/ndb/csquery.c - 664 sys sys 1174626119 1073
+1174626007 5 c sys/src/cmd/ndb/dblookup.c - 664 sys sys 1174626119 20627
+1174626007 6 c sys/src/cmd/ndb/dn.c - 664 sys sys 1174626121 31890
+1174626007 7 c sys/src/cmd/ndb/dnarea.c - 664 sys sys 1174626121 2505
+1174626007 8 c sys/src/cmd/ndb/dnnotify.c - 664 sys sys 1174626121 3122
+1174626007 9 c sys/src/cmd/ndb/dnresolve.c - 664 sys sys 1174626123 25679
+1174626007 10 c sys/src/cmd/ndb/dns.c - 664 sys sys 1174626124 15895
+1174626007 11 c sys/src/cmd/ndb/dns.h - 664 sys sys 1174626124 10228
+1174626007 12 c sys/src/cmd/ndb/dnsdebug.c - 664 sys sys 1174626125 8646
+1174626007 13 c sys/src/cmd/ndb/dnserver.c - 664 sys sys 1174626125 4400
+1174626007 14 c sys/src/cmd/ndb/dnsquery.c - 664 sys sys 1174626126 2435
+1174626007 15 c sys/src/cmd/ndb/dnstcp.c - 664 sys sys 1174626126 7475
+1174626007 16 c sys/src/cmd/ndb/dnudpserver.c - 664 sys sys 1174626126 5497
+1174626007 17 c sys/src/cmd/ndb/mkfile - 664 sys sys 1174623575 1984
+1174626007 18 c sys/src/cmd/ndb/query.c - 664 sys sys 1174623580 1137
+1174626007 19 d sys/src/cmd/ndb/dn.acid - 664 sys sys 1144950752 0
+1174627806 0 c sys/man/8/ndb - 664 sys sys 1174626196 12927
+1174678205 0 c 386/bin/ndb/dns - 775 sys sys 1174677395 274892
+1174678205 1 c 386/bin/ndb/dnsdebug - 775 sys sys 1174677395 248903
+1174678205 2 c 386/bin/ndb/dnstcp - 775 sys sys 1174677396 247760
+1174680008 0 c sys/src/cmd/ip/snoopy/dns.c - 664 sys sys 1174678543 7931
+1174689013 0 c sys/man/6/ndb - 664 sys sys 1174688660 6670
+1174690807 0 c sys/src/cmd/ndb/convDNS2M.c - 664 sys sys 1174690184 6801
+1174690807 1 c sys/src/cmd/ndb/convM2DNS.c - 664 sys sys 1174690173 10779
+1174690807 2 c sys/src/cmd/ndb/dblookup.c - 664 sys sys 1174690228 20863
+1174690807 3 c sys/src/cmd/ndb/dn.c - 664 sys sys 1174690061 32609
+1174690807 4 c sys/src/cmd/ndb/dnresolve.c - 664 sys sys 1174690047 25752
+1174690807 5 c sys/src/cmd/ndb/dns.h - 664 sys sys 1174690654 10460
+1174690807 6 c sys/src/cmd/ndb/dnsdebug.c - 664 sys sys 1174690026 8779
+1174690807 7 c sys/src/cmd/ndb/dnstcp.c - 664 sys sys 1174689582 7445
+1174690807 8 d sys/src/cmd/ndb/time.c - 664 sys sys 957402055 0
+1174705205 0 c 386/bin/snoopy - 775 sys sys 1174704819 186527
+1174705205 1 c 386/bin/ndb/dns - 775 sys sys 1174704817 277690
+1174705205 2 c 386/bin/ndb/dnsdebug - 775 sys sys 1174704818 252154
+1174705205 3 c 386/bin/ndb/dnsquery - 775 sys sys 1174704818 64417
+1174705205 4 c 386/bin/ndb/dnstcp - 775 sys sys 1174704819 250526

+ 12 - 3
sys/man/6/ndb

@@ -155,7 +155,7 @@ the dial would connect to the SMTP port of
 A number of attributes are meaningful to programs and thus
 reserved.
 They are:
-.TF restricted
+.TF dnsdomain
 .TP
 .B sys
 system name
@@ -254,11 +254,20 @@ a time server to use (for DHCP)
 a Windows name server (for DHCP)
 .TP
 .B mx
-mail exchanger (for DNS and DHCP)
+mail exchanger (for DNS and DHCP);
+also
+.BR pref .
+.TP
+.B srv
+service location (for DNS);
+also
+.BR pri ,
+.B weight
+and
+.BR port .
 .TP
 .B soa
 start of area (for DNS)
-.sp
 .PD
 .PP
 .I Cs

+ 70 - 0
sys/man/8/ndb

@@ -263,6 +263,26 @@ sets the goal for the number of domain names cached to
 .I target
 rather than the default of 8,000.
 .TP
+.B -o
+used with
+.BR -s ,
+.B -o
+causes
+.I dns
+to assume that it straddles inside and outside networks
+and that the outside network is mounted on
+.BR /net.alt .
+Queries for inside addresses will be sent via
+.B /net/udp
+and those for outside addresses via
+.BR /net.alt/udp .
+This makes
+.I dns
+suitable for serving non-Plan-9 systems in an organization with
+firewalls, DNS proxies, etc.,
+particularly if they don't work very well.
+See `Straddling Server' below for details.
+.TP
 .B -r
 send `recursive' queries, asking the other servers
 to complete lookups.
@@ -440,6 +460,56 @@ makes
 .BI www. ...
 a synonym for the canonical name
 .BI anna. ... .
+.SS "Straddling Server"
+Many companies have an inside network
+protected from outside access with firewalls.
+They usually provide internal `root' DNS servers
+(of varying reliability and correctness)
+that serve internal domains and pass on DNS queries for
+outside domains to the outside, relaying the results
+back and caching them for future use.
+Some companies don't even let DNS queries nor replies through
+their firewalls at all, in either direction.
+.PP
+In such a situation, running
+.B "dns -so"
+on a machine that imports access to the outside network via
+.B /net.alt
+from a machine that straddles the firewalls,
+or that straddles the firewalls itself,
+will let internal machines query such a machine
+and receive answers from outside nameservers for outside addresses
+and inside nameservers for inside addresses, giving the appearance
+of a unified domain name space,
+while bypassing the corporate DNS proxies or firewalls.
+This is different from running
+.B "dns -s"
+and
+.B "dns -sRx /net.alt -f /lib/ndb/external"
+on the same machine,
+which keeps the inside and outside namespaces entirely separate.
+.PP
+Under
+.BR -o ,
+several
+.I sys
+names are significant:
+.BR inside-dom ,
+.BR inside-ns ,
+and
+.BR outside-ns .
+.I Inside-dom
+should contain a series of
+.B dom
+pairs naming domains internal to the organization.
+.I Inside-ns
+should contain a series of
+.B ip
+pairs naming the internal DNS `root' servers.
+.I Outside-ns
+should contain a series of
+.B ip
+pairs naming the external DNS servers to consult.
 .SS "DNS Queries and Debugging"
 .I Ndb/dnsquery
 can be used to query

+ 41 - 465
sys/src/cmd/ip/snoopy/dns.c

@@ -100,7 +100,8 @@ fmtrr(Msg *m, RR **rrp, int quest)
 	default:
 		break;
 	case Thinfo:
-		m->p = seprint(m->p, m->e, " cpu=%s os=%s", rr->cpu->name, rr->os->name);
+		m->p = seprint(m->p, m->e, " cpu=%s os=%s",
+			rr->cpu->name, rr->os->name);
 		break;
 	case Tcname:
 	case Tmb:
@@ -142,23 +143,29 @@ fmtrr(Msg *m, RR **rrp, int quest)
 			m->p = seprint(m->p, m->e, " txt=%q", t->p);
 		break;
 	case Tnull:
-		m->p = seprint(m->p, m->e, " null=%.*H", rr->null->dlen, rr->null->data);
+		m->p = seprint(m->p, m->e, " null=%.*H",
+			rr->null->dlen, rr->null->data);
 		break;
 	case Trp:
 		m->p = seprint(m->p, m->e, " rmb=%s", rr->rmb->name);
 		m->p = seprint(m->p, m->e, " rp=%s", rr->rp->name);
 		break;
 	case Tkey:
-		m->p = seprint(m->p, m->e, " flags=%d proto=%d alg=%d data=%.*H", rr->key->flags, rr->key->proto, rr->key->alg, rr->key->dlen, rr->key->data);
+		m->p = seprint(m->p, m->e, " flags=%d proto=%d alg=%d data=%.*H",
+			rr->key->flags, rr->key->proto, rr->key->alg,
+			rr->key->dlen, rr->key->data);
 		break;
 	case Tsig:
-		m->p = seprint(m->p, m->e, " type=%d alg=%d labels=%d ttl=%lud exp=%lud incep=%lud tag=%d signer=%s data=%.*H",
+		m->p = seprint(m->p, m->e,
+" type=%d alg=%d labels=%d ttl=%lud exp=%lud incep=%lud tag=%d signer=%s data=%.*H",
 			rr->sig->type, rr->sig->alg, rr->sig->labels,
 			rr->sig->ttl, rr->sig->exp, rr->sig->incep, rr->sig->tag,
 			rr->sig->signer->name, rr->sig->dlen, rr->sig->data);
 		break;
 	case Tcert:
-		m->p = seprint(m->p, m->e, " type=%d tag=%d alg=%d data=%.*H", rr->cert->type, rr->cert->tag, rr->cert->alg, rr->cert->dlen, rr->cert->data);
+		m->p = seprint(m->p, m->e, " type=%d tag=%d alg=%d data=%.*H",
+			rr->cert->type, rr->cert->tag, rr->cert->alg,
+			rr->cert->dlen, rr->cert->data);
 		break;
 	}
 	rrfree(rr);
@@ -175,7 +182,7 @@ p_seprint(Msg *m)
 {
 	char *e;
 
-	if((e = convM2DNS(m->ps, m->pe-m->ps, &dm)) != nil){
+	if((e = convM2DNS(m->ps, m->pe-m->ps, &dm, nil)) != nil){
 		m->p = seprint(m->p, m->e, "error: %s", e);
 		return 0;
 	}
@@ -344,13 +351,36 @@ freealldn(void)
 }
 
 
-#define now 0
+ulong now = 0;
+
+void
+dnslog(char *fmt, ...)			/* don't log */
+{
+	USED(fmt);
+}
 
 /*************************************************
- Everything below here is copied from /sys/src/cmd/ndb
- without modification and can be recopied to update.
- First parts from dn.c, then all of convM2DNS.c.
-*/
+ * Everything below here is copied from /sys/src/cmd/ndb/dns.c
+ * without modification and can be recopied to update.
+ */
+
+/*
+ *  convert an integer RR type to it's ascii name
+ */
+char*
+rrname(int type, char *buf, int len)
+{
+	char *t;
+
+	t = nil;
+	if(type >= 0 && type <= Tall)
+		t = rrtname[type];
+	if(t==nil){
+		snprint(buf, len, "%d", type);
+		t = buf;
+	}
+	return t;
+}
 
 /*
  *  free a list of resource records and any related structs
@@ -466,457 +496,3 @@ rrfree(RR *rp)
 	rp->magic = ~rp->magic;
 	free(rp);
 }
-
-typedef struct Scan	Scan;
-struct Scan
-{
-	uchar	*base;
-	uchar	*p;
-	uchar	*ep;
-	char	*err;
-};
-
-#define NAME(x)		gname(x, sp)
-#define SYMBOL(x)	(x = gsym(sp))
-#define STRING(x)	(x = gstr(sp))
-#define USHORT(x)	(x = gshort(sp))
-#define ULONG(x)	(x = glong(sp))
-#define UCHAR(x)	(x = gchar(sp))
-#define V4ADDR(x)	(x = gv4addr(sp))
-#define V6ADDR(x)	(x = gv6addr(sp))
-#define BYTES(x, y)	(y = gbytes(sp, &x, len - (sp->p - data)))
-
-static char *toolong = "too long";
-
-/*
- *  get a ushort/ulong
- */
-static ushort
-gchar(Scan *sp)
-{
-	ushort x;
-
-	if(sp->err)
-		return 0;
-	if(sp->ep - sp->p < 1){
-		sp->err = toolong;
-		return 0;
-	}
-	x = sp->p[0];
-	sp->p += 1;
-	return x;
-}
-static ushort
-gshort(Scan *sp)
-{
-	ushort x;
-
-	if(sp->err)
-		return 0;
-	if(sp->ep - sp->p < 2){
-		sp->err = toolong;
-		return 0;
-	}
-	x = (sp->p[0]<<8) | sp->p[1];
-	sp->p += 2;
-	return x;
-}
-static ulong
-glong(Scan *sp)
-{
-	ulong x;
-
-	if(sp->err)
-		return 0;
-	if(sp->ep - sp->p < 4){
-		sp->err = toolong;
-		return 0;
-	}
-	x = (sp->p[0]<<24) | (sp->p[1]<<16) | (sp->p[2]<<8) | sp->p[3];
-	sp->p += 4;
-	return x;
-}
-
-/*
- *  get an ip address
- */
-static DN*
-gv4addr(Scan *sp)
-{
-	char addr[32];
-
-	if(sp->err)
-		return 0;
-	if(sp->ep - sp->p < 4){
-		sp->err = toolong;
-		return 0;
-	}
-	snprint(addr, sizeof(addr), "%V", sp->p);
-	sp->p += 4;
-
-	return dnlookup(addr, Cin, 1);
-}
-static DN*
-gv6addr(Scan *sp)
-{
-	char addr[64];
-
-	if(sp->err)
-		return 0;
-	if(sp->ep - sp->p < IPaddrlen){
-		sp->err = toolong;
-		return 0;
-	}
-	snprint(addr, sizeof(addr), "%I", sp->p);
-	sp->p += IPaddrlen;
-
-	return dnlookup(addr, Cin, 1);
-}
-
-/*
- *  get a string.  make it an internal symbol.
- */
-static DN*
-gsym(Scan *sp)
-{
-	int n;
-	char sym[Strlen+1];
-
-	if(sp->err)
-		return 0;
-	n = *(sp->p++);
-	if(sp->p+n > sp->ep){
-		sp->err = toolong;
-		return 0;
-	}
-
-	if(n > Strlen){
-		sp->err = "illegal string";
-		return 0;
-	}
-	strncpy(sym, (char*)sp->p, n);
-	sym[n] = 0;
-	sp->p += n;
-
-	return dnlookup(sym, Csym, 1);
-}
-
-/*
- *  get a string.  don't make it an internal symbol.
- */
-static Txt*
-gstr(Scan *sp)
-{
-	int n;
-	char sym[Strlen+1];
-	Txt *t;
-
-	if(sp->err)
-		return 0;
-	n = *(sp->p++);
-	if(sp->p+n > sp->ep){
-		sp->err = toolong;
-		return 0;
-	}
-
-	if(n > Strlen){
-		sp->err = "illegal string";
-		return 0;
-	}
-	strncpy(sym, (char*)sp->p, n);
-	sym[n] = 0;
-	sp->p += n;
-
-	t = emalloc(sizeof(*t));
-	t->next = nil;
-	t->p = estrdup(sym);
-	return t;
-}
-
-/*
- *  get a sequence of bytes
- */
-static int
-gbytes(Scan *sp, uchar **p, int n)
-{
-	if(sp->err)
-		return 0;
-	if(sp->p+n > sp->ep || n < 0){
-		sp->err = toolong;
-		return 0;
-	}
-	*p = emalloc(n);
-	memmove(*p, sp->p, n);
-	sp->p += n;
-
-	return n;
-}
-
-/*
- *  get a domain name.  'to' must point to a buffer at least Domlen+1 long.
- */
-static char*
-gname(char *to, Scan *sp)
-{
-	int len, off;
-	int pointer;
-	int n;
-	char *tostart;
-	char *toend;
-	uchar *p;
-
-	tostart = to;
-	if(sp->err)
-		goto err;
-	pointer = 0;
-	p = sp->p;
-	toend = to + Domlen;
-	for(len = 0; *p; len += pointer ? 0 : (n+1)){
-		if((*p & 0xc0) == 0xc0){
-			/* pointer to other spot in message */
-			if(pointer++ > 10){
-				sp->err = "pointer loop";
-				goto err;
-			}
-			off = ((p[0]<<8) + p[1]) & 0x3ff;
-			p = sp->base + off;
-			if(p >= sp->ep){
-				sp->err = "bad pointer";
-				goto err;
-			}
-			n = 0;
-			continue;
-		}
-		n = *p++;
-		if(len + n < Domlen - 1){
-			if(to + n > toend){
-				sp->err = toolong;
-				goto err;
-			}
-			memmove(to, p, n);
-			to += n;
-		}
-		p += n;
-		if(*p){
-			if(to >= toend){
-				sp->err = toolong;
-				goto err;
-			}
-			*to++ = '.';
-		}
-	}
-	*to = 0;
-	if(pointer)
-		sp->p += len + 2;	/* + 2 for pointer */
-	else
-		sp->p += len + 1;	/* + 1 for the null domain */
-	return tostart;
-err:
-	*tostart = 0;
-	return tostart;
-}
-
-/*
- *  convert the next RR from a message
- */
-static RR*
-convM2RR(Scan *sp)
-{
-	RR *rp;
-	int type;
-	int class;
-	uchar *data;
-	int len;
-	char dname[Domlen+1];
-	Txt *t, **l;
-
-retry:
-	NAME(dname);
-	USHORT(type);
-	USHORT(class);
-
-	rp = rralloc(type);
-	rp->owner = dnlookup(dname, class, 1);
-	rp->type = type;
-
-	ULONG(rp->ttl);
-	rp->ttl += now;
-	USHORT(len);
-	data = sp->p;
-
-	if(sp->p + len > sp->ep)
-		sp->err = toolong;
-	if(sp->err){
-		rrfree(rp);
-		return 0;
-	}
-
-	switch(type){
-	default:
-		/* unknown type, just ignore it */
-		sp->p = data + len;
-		rrfree(rp);
-		goto retry;
-	case Thinfo:
-		SYMBOL(rp->cpu);
-		SYMBOL(rp->os);
-		break;
-	case Tcname:
-	case Tmb:
-	case Tmd:
-	case Tmf:
-	case Tns:
-		rp->host = dnlookup(NAME(dname), Cin, 1);
-		break;
-	case Tmg:
-	case Tmr:
-		rp->mb = dnlookup(NAME(dname), Cin, 1);
-		break;
-	case Tminfo:
-		rp->rmb = dnlookup(NAME(dname), Cin, 1);
-		rp->mb = dnlookup(NAME(dname), Cin, 1);
-		break;
-	case Tmx:
-		USHORT(rp->pref);
-		rp->host = dnlookup(NAME(dname), Cin, 1);
-		break;
-	case Ta:
-		V4ADDR(rp->ip);
-		break;
-	case Taaaa:
-		V6ADDR(rp->ip);
-		break;
-	case Tptr:
-		rp->ptr = dnlookup(NAME(dname), Cin, 1);
-		break;
-	case Tsoa:
-		rp->host = dnlookup(NAME(dname), Cin, 1);
-		rp->rmb = dnlookup(NAME(dname), Cin, 1);
-		ULONG(rp->soa->serial);
-		ULONG(rp->soa->refresh);
-		ULONG(rp->soa->retry);
-		ULONG(rp->soa->expire);
-		ULONG(rp->soa->minttl);
-		break;
-	case Ttxt:
-		l = &rp->txt;
-		*l = nil;
-		while(sp->p-data < len){
-			STRING(t);
-			*l = t;
-			l = &t->next;
-		}
-		break;
-	case Tnull:
-		BYTES(rp->null->data, rp->null->dlen);
-		break;
-	case Trp:
-		rp->rmb = dnlookup(NAME(dname), Cin, 1);
-		rp->rp = dnlookup(NAME(dname), Cin, 1);
-		break;
-	case Tkey:
-		USHORT(rp->key->flags);
-		UCHAR(rp->key->proto);
-		UCHAR(rp->key->alg);
-		BYTES(rp->key->data, rp->key->dlen);
-		break;
-	case Tsig:
-		USHORT(rp->sig->type);
-		UCHAR(rp->sig->alg);
-		UCHAR(rp->sig->labels);
-		ULONG(rp->sig->ttl);
-		ULONG(rp->sig->exp);
-		ULONG(rp->sig->incep);
-		USHORT(rp->sig->tag);
-		rp->sig->signer = dnlookup(NAME(dname), Cin, 1);
-		BYTES(rp->sig->data, rp->sig->dlen);
-		break;
-	case Tcert:
-		USHORT(rp->cert->type);
-		USHORT(rp->cert->tag);
-		UCHAR(rp->cert->alg);
-		BYTES(rp->cert->data, rp->cert->dlen);
-		break;
-	}
-	if(sp->p - data != len)
-		sp->err = "bad RR len";
-	return rp;
-}
-
-/*
- *  convert the next question from a message
- */
-static RR*
-convM2Q(Scan *sp)
-{
-	char dname[Domlen+1];
-	int type;
-	int class;
-	RR *rp;
-
-	NAME(dname);
-	USHORT(type);
-	USHORT(class);
-	if(sp->err)
-		return 0;
-
-	rp = rralloc(type);
-	rp->owner = dnlookup(dname, class, 1);
-
-	return rp;
-}
-
-static RR*
-rrloop(Scan *sp, int count, int quest)
-{
-	int i;
-	static char errbuf[64];
-	RR *first, *rp, **l;
-
-	if(sp->err)
-		return 0;
-	l = &first;
-	first = 0;
-	for(i = 0; i < count; i++){
-		rp = quest ? convM2Q(sp) : convM2RR(sp);
-		if(rp == 0)
-			break;
-		if(sp->err){
-			rrfree(rp);
-			break;
-		}
-		*l = rp;
-		l = &rp->next;
-	}
-	return first;
-}
-
-/*
- *  convert the next DNS from a message stream
- */
-char*
-convM2DNS(uchar *buf, int len, DNSmsg *m)
-{
-	Scan scan;
-	Scan *sp;
-	char *err;
-
-	scan.base = buf;
-	scan.p = buf;
-	scan.ep = buf + len;
-	scan.err = 0;
-	sp = &scan;
-	memset(m, 0, sizeof(DNSmsg));
-	USHORT(m->id);
-	USHORT(m->flags);
-	USHORT(m->qdcount);
-	USHORT(m->ancount);
-	USHORT(m->nscount);
-	USHORT(m->arcount);
-	m->qd = rrloop(sp, m->qdcount, 1);
-	m->an = rrloop(sp, m->ancount, 0);
-	m->ns = rrloop(sp, m->nscount, 0);
-	err = scan.err;				/* live with bad ar's */
-	m->ar = rrloop(sp, m->arcount, 0);
-	return err;
-}

+ 9 - 7
sys/src/cmd/ip/snoopy/mkfile

@@ -41,6 +41,7 @@ POBJS=${PROTOS:%=%.$O}
 OFILES=	main.$O\
 	y.tab.$O\
 	protos.$O\
+	convM2DNS.$O\
 	$POBJS
 
 HFILES=dat.h\
@@ -60,14 +61,16 @@ CLEANFILES=protos.c protos.h
 
 </sys/src/cmd/mkone
 
-protos.h: mkfile
+convM2DNS.$O:		/sys/src/cmd/ndb/convM2DNS.c
+	$CC $CFLAGS	/sys/src/cmd/ndb/convM2DNS.c
+
+protos.h:D: mkfile
 	{
-		for(i in $PROTOS){
+		for(i in $PROTOS)
 			echo extern Proto $i';'
-		}
-	} > protos.h
+	} >$target
 
-protos.c: mkfile
+protos.c:D: mkfile
 	{
 		echo '#include <u.h>'
 		echo '#include <libc.h>'
@@ -79,5 +82,4 @@ protos.c: mkfile
 			echo '	&'$i','
 		echo '	0,'
 		echo '};'
-	} > protos.c
-
+	} >$target

+ 17 - 22
sys/src/cmd/ndb/convDNS2M.c

@@ -17,10 +17,10 @@ struct Dict
 		ushort	offset;		/* pointer to packed name in message */
 		char	*name;		/* pointer to unpacked name in buf */
 	} x[Ndict];
-	int n;			/* size of dictionary */
-	uchar *start;		/* start of packed message */
-	char buf[4*1024];	/* buffer for unpacked names */
-	char *ep;		/* first free char in buf */
+	int	n;		/* size of dictionary */
+	uchar	*start;		/* start of packed message */
+	char	buf[4*1024];	/* buffer for unpacked names */
+	char	*ep;		/* first free char in buf */
 };
 
 #define NAME(x)		p = pname(p, ep, x, dp)
@@ -51,16 +51,7 @@ psym(uchar *p, uchar *ep, char *np)
 static uchar*
 pstr(uchar *p, uchar *ep, char *np)
 {
-	int n;
-
-	n = strlen(np);
-	if(n >= Strlen)			/* DNS maximum length string */
-		n = Strlen - 1;
-	if(ep - p < n+1)		/* see if it fits in the buffer */
-		return ep+1;
-	*p++ = n;
-	memmove(p, np, n);
-	return p + n;
+	return psym(p, ep, np);
 }
 
 static uchar*
@@ -129,17 +120,17 @@ pv6addr(uchar *p, uchar *ep, char *name)
 static uchar*
 pname(uchar *p, uchar *ep, char *np, Dict *dp)
 {
-	char *cp;
 	int i;
+	char *cp;
 	char *last;		/* last component packed */
 
-	if(strlen(np) >= Domlen)	/* make sure we don't exceed DNS limits */
+	if(strlen(np) >= Domlen) /* make sure we don't exceed DNS limits */
 		return ep+1;
 
 	last = 0;
 	while(*np){
 		/* look through every component in the dictionary for a match */
-		for(i = 0; i < dp->n; i++){
+		for(i = 0; i < dp->n; i++)
 			if(strcmp(np, dp->x[i].name) == 0){
 				if(ep - p < 2)
 					return ep+1;
@@ -147,10 +138,9 @@ pname(uchar *p, uchar *ep, char *np, Dict *dp)
 				*p++ = dp->x[i].offset;
 				return p;
 			}
-		}
 
 		/* if there's room, enter this name in dictionary */
-		if(dp->n < Ndict){
+		if(dp->n < Ndict)
 			if(last){
 				/* the whole name is already in dp->buf */
 				last = strchr(last, '.') + 1;
@@ -160,7 +150,7 @@ pname(uchar *p, uchar *ep, char *np, Dict *dp)
 			} else {
 				/* add to dp->buf */
 				i = strlen(np);
-				if(dp->ep + i + 1 < &dp->buf[sizeof(dp->buf)]){
+				if(dp->ep + i + 1 < &dp->buf[sizeof dp->buf]){
 					strcpy(dp->ep, np);
 					dp->x[dp->n].name = dp->ep;
 					last = dp->ep;
@@ -169,11 +159,10 @@ pname(uchar *p, uchar *ep, char *np, Dict *dp)
 					dp->n++;
 				}
 			}
-		}
 
 		/* put next component into message */
 		cp = strchr(np, '.');
-		if(cp == 0){
+		if(cp == nil){
 			i = strlen(np);
 			cp = np + i;	/* point to null terminator */
 		} else {
@@ -264,6 +253,12 @@ convRR2M(RR *rp, uchar *p, uchar *ep, Dict *dp)
 		ULONG(rp->soa->expire);
 		ULONG(rp->soa->minttl);
 		break;
+	case Tsrv:
+		USHORT(rp->srv->pri);
+		USHORT(rp->srv->weight);
+		USHORT(rp->srv->port);
+		STRING(rp->srv->target->name);
+		break;
 	case Ttxt:
 		for(t = rp->txt; t != nil; t = t->next)
 			STRING(t->p);

+ 196 - 106
sys/src/cmd/ndb/convM2DNS.c

@@ -9,66 +9,91 @@ struct Scan
 	uchar	*base;
 	uchar	*p;
 	uchar	*ep;
+
 	char	*err;
+	char	errbuf[256];	/* hold a formatted error sometimes */
+	int	rcode;		/* outgoing response codes (reply flags) */
 };
 
-#define NAME(x)		gname(x, sp)
-#define SYMBOL(x)	(x = gsym(sp))
-#define STRING(x)	(x = gstr(sp))
-#define USHORT(x)	(x = gshort(sp))
-#define ULONG(x)	(x = glong(sp))
-#define UCHAR(x)	(x = gchar(sp))
-#define V4ADDR(x)	(x = gv4addr(sp))
-#define V6ADDR(x)	(x = gv6addr(sp))
-#define BYTES(x, y)	(y = gbytes(sp, &x, len - (sp->p - data)))
+#define NAME(x)		gname(x, rp, sp)
+#define SYMBOL(x)	(x = gsym(rp, sp))
+#define STRING(x)	(x = gstr(rp, sp))
+#define USHORT(x)	(x = gshort(rp, sp))
+#define ULONG(x)	(x = glong(rp, sp))
+#define UCHAR(x)	(x = gchar(rp, sp))
+#define V4ADDR(x)	(x = gv4addr(rp, sp))
+#define V6ADDR(x)	(x = gv6addr(rp, sp))
+#define BYTES(x, y)	(y = gbytes(rp, sp, &x, len - (sp->p - data)))
 
-static char *toolong = "too long";
+static int
+errneg(RR *rp, Scan *sp, int actual)
+{
+	snprint(sp->errbuf, sizeof sp->errbuf, "negative len %d: %R",
+		actual, rp);
+	sp->err = sp->errbuf;
+	return 0;
+}
+
+static int
+errtoolong(RR *rp, Scan *sp, int actual, int nominal, char *where)
+{
+	char *p, *ep;
+	char ptype[64];
+
+	p =  sp->errbuf;
+	ep = sp->errbuf + sizeof sp->errbuf - 1;
+	if (where)
+		p = seprint(p, ep, "%s: ", where);
+	if (rp)
+		p = seprint(p, ep, "type %s RR: ",
+			rrname(rp->type, ptype, sizeof ptype));
+	p = seprint(p, ep, "wrong length (actual %d, nominal %d)",
+		actual, nominal);
+	if (rp)
+		seprint(p, ep, ": %R", rp);
+	sp->err = sp->errbuf;
+	return 0;
+}
 
 /*
  *  get a ushort/ulong
  */
 static ushort
-gchar(Scan *sp)
+gchar(RR *rp, Scan *sp)
 {
 	ushort x;
 
 	if(sp->err)
 		return 0;
-	if(sp->ep - sp->p < 1){
-		sp->err = toolong;
-		return 0;
-	}
+	if(sp->ep - sp->p < 1)
+		return errtoolong(rp, sp, sp->ep - sp->p, 1, "gchar");
 	x = sp->p[0];
 	sp->p += 1;
 	return x;
 }
 static ushort
-gshort(Scan *sp)
+gshort(RR *rp, Scan *sp)
 {
 	ushort x;
 
 	if(sp->err)
 		return 0;
-	if(sp->ep - sp->p < 2){
-		sp->err = toolong;
-		return 0;
-	}
-	x = (sp->p[0]<<8) | sp->p[1];
+	if(sp->ep - sp->p < 2)
+		return errtoolong(rp, sp, sp->ep - sp->p, 2, "gshort");
+	x = sp->p[0]<<8 | sp->p[1];
 	sp->p += 2;
 	return x;
 }
 static ulong
-glong(Scan *sp)
+glong(RR *rp, Scan *sp)
 {
 	ulong x;
 
 	if(sp->err)
 		return 0;
-	if(sp->ep - sp->p < 4){
-		sp->err = toolong;
-		return 0;
-	}
-	x = (sp->p[0]<<24) | (sp->p[1]<<16) | (sp->p[2]<<8) | sp->p[3];
+	if(sp->ep - sp->p < 4)
+		return errtoolong(rp, sp, sp->ep - sp->p, 4, "glong");
+	x = sp->p[0]<<24 | sp->p[1]<<16 | sp->p[2]<<8 | sp->p[3];
 	sp->p += 4;
 	return x;
 }
@@ -77,33 +102,30 @@ glong(Scan *sp)
  *  get an ip address
  */
 static DN*
-gv4addr(Scan *sp)
+gv4addr(RR *rp, Scan *sp)
 {
 	char addr[32];
 
 	if(sp->err)
 		return 0;
-	if(sp->ep - sp->p < 4){
-		sp->err = toolong;
-		return 0;
-	}
-	snprint(addr, sizeof(addr), "%V", sp->p);
+	if(sp->ep - sp->p < 4)
+		return (DN*)errtoolong(rp, sp, sp->ep - sp->p, 4, "gv4addr");
+	snprint(addr, sizeof addr, "%V", sp->p);
 	sp->p += 4;
 
 	return dnlookup(addr, Cin, 1);
 }
 static DN*
-gv6addr(Scan *sp)
+gv6addr(RR *rp, Scan *sp)
 {
 	char addr[64];
 
 	if(sp->err)
 		return 0;
-	if(sp->ep - sp->p < IPaddrlen){
-		sp->err = toolong;
-		return 0;
-	}
-	snprint(addr, sizeof(addr), "%I", sp->p);
+	if(sp->ep - sp->p < IPaddrlen)
+		return (DN*)errtoolong(rp, sp, sp->ep - sp->p, IPaddrlen,
+			"gv6addr");
+	snprint(addr, sizeof addr, "%I", sp->p);
 	sp->p += IPaddrlen;
 
 	return dnlookup(addr, Cin, 1);
@@ -113,25 +135,27 @@ gv6addr(Scan *sp)
  *  get a string.  make it an internal symbol.
  */
 static DN*
-gsym(Scan *sp)
+gsym(RR *rp, Scan *sp)
 {
 	int n;
 	char sym[Strlen+1];
 
 	if(sp->err)
 		return 0;
-	n = *(sp->p++);
-	if(sp->p+n > sp->ep){
-		sp->err = toolong;
-		return 0;
-	}
+	n = 0;
+	if (sp->p < sp->ep)
+		n = *(sp->p++);
+	if(sp->ep - sp->p < n)
+		return (DN*)errtoolong(rp, sp, sp->ep - sp->p, n, "gsym");
 
 	if(n > Strlen){
-		sp->err = "illegal string";
+		sp->err = "illegal string (symbol)";
 		return 0;
 	}
 	strncpy(sym, (char*)sp->p, n);
 	sym[n] = 0;
+	if (strlen(sym) != n)
+		sp->err = "symbol shorter than declared length";
 	sp->p += n;
 
 	return dnlookup(sym, Csym, 1);
@@ -141,7 +165,7 @@ gsym(Scan *sp)
  *  get a string.  don't make it an internal symbol.
  */
 static Txt*
-gstr(Scan *sp)
+gstr(RR *rp, Scan *sp)
 {
 	int n;
 	char sym[Strlen+1];
@@ -149,11 +173,11 @@ gstr(Scan *sp)
 
 	if(sp->err)
 		return 0;
-	n = *(sp->p++);
-	if(sp->p+n > sp->ep){
-		sp->err = toolong;
-		return 0;
-	}
+	n = 0;
+	if (sp->p < sp->ep)
+		n = *(sp->p++);
+	if(sp->ep - sp->p < n)
+		return (Txt*)errtoolong(rp, sp, sp->ep - sp->p, n, "gstr");
 
 	if(n > Strlen){
 		sp->err = "illegal string";
@@ -161,6 +185,8 @@ gstr(Scan *sp)
 	}
 	strncpy(sym, (char*)sp->p, n);
 	sym[n] = 0;
+	if (strlen(sym) != n)
+		sp->err = "string shorter than declared length";
 	sp->p += n;
 
 	t = emalloc(sizeof(*t));
@@ -173,14 +199,15 @@ gstr(Scan *sp)
  *  get a sequence of bytes
  */
 static int
-gbytes(Scan *sp, uchar **p, int n)
+gbytes(RR *rp, Scan *sp, uchar **p, int n)
 {
+	*p = nil;			/* i think this is a good idea */
 	if(sp->err)
 		return 0;
-	if(sp->p+n > sp->ep || n < 0){
-		sp->err = toolong;
-		return 0;
-	}
+	if(n < 0)
+		return errneg(rp, sp, n);
+	if(sp->ep - sp->p < n)
+		return errtoolong(rp, sp, sp->ep - sp->p, n, "gbytes");
 	*p = emalloc(n);
 	memmove(*p, sp->p, n);
 	sp->p += n;
@@ -192,13 +219,10 @@ gbytes(Scan *sp, uchar **p, int n)
  *  get a domain name.  'to' must point to a buffer at least Domlen+1 long.
  */
 static char*
-gname(char *to, Scan *sp)
+gname(char *to, RR *rp, Scan *sp)
 {
-	int len, off;
-	int pointer;
-	int n;
-	char *tostart;
-	char *toend;
+	int len, off, pointer, n;
+	char *tostart, *toend;
 	uchar *p;
 
 	tostart = to;
@@ -207,14 +231,14 @@ gname(char *to, Scan *sp)
 	pointer = 0;
 	p = sp->p;
 	toend = to + Domlen;
-	for(len = 0; *p; len += pointer ? 0 : (n+1)){
+	for(len = 0; *p && p < sp->ep; len += pointer ? 0 : (n+1)){
 		if((*p & 0xc0) == 0xc0){
 			/* pointer to other spot in message */
 			if(pointer++ > 10){
 				sp->err = "pointer loop";
 				goto err;
 			}
-			off = ((p[0]<<8) + p[1]) & 0x3ff;
+			off = (p[0]<<8 | p[1]) & 0x3ff;
 			p = sp->base + off;
 			if(p >= sp->ep){
 				sp->err = "bad pointer";
@@ -223,10 +247,12 @@ gname(char *to, Scan *sp)
 			n = 0;
 			continue;
 		}
-		n = *p++;
+		n = 0;
+		if (p < sp->ep)
+			n = *p++;
 		if(len + n < Domlen - 1){
-			if(to + n > toend){
-				sp->err = toolong;
+			if(n > toend - to){
+				errtoolong(rp, sp, toend - to, n, "gname 1");
 				goto err;
 			}
 			memmove(to, p, n);
@@ -235,7 +261,8 @@ gname(char *to, Scan *sp)
 		p += n;
 		if(*p){
 			if(to >= toend){
-				sp->err = toolong;
+				errtoolong(rp, sp, to-tostart, toend-tostart,
+					"gname 2");
 				goto err;
 			}
 			*to++ = '.';
@@ -252,18 +279,32 @@ err:
 	return tostart;
 }
 
+/*
+ * ms windows 2000 seems to get the bytes backward in the type field
+ * of ptr records, so return a format error as feedback.
+ */
+static void
+mstypehack(Scan *sp, int type, char *where)
+{
+	if ((uchar)type == 0 && (uchar)(type>>8) != 0) {
+		USED(where);
+//		dnslog("%s: byte-swapped type field in ptr rr from win2k",
+//			where);
+		if (sp->rcode == 0)
+			sp->rcode = Rformat;
+	}
+}
+
 /*
  *  convert the next RR from a message
  */
 static RR*
-convM2RR(Scan *sp)
+convM2RR(Scan *sp, char *what)
 {
-	RR *rp;
-	int type;
-	int class;
-	uchar *data;
-	int len;
+	int type, class, len;
 	char dname[Domlen+1];
+	uchar *data;
+	RR *rp = nil;
 	Txt *t, **l;
 
 retry:
@@ -271,6 +312,7 @@ retry:
 	USHORT(type);
 	USHORT(class);
 
+	mstypehack(sp, type, "convM2RR");
 	rp = rralloc(type);
 	rp->owner = dnlookup(dname, class, 1);
 	rp->type = type;
@@ -280,9 +322,20 @@ retry:
 	USHORT(len);
 	data = sp->p;
 
-	if(sp->p + len > sp->ep)
-		sp->err = toolong;
-	if(sp->err){
+	/*
+	 * ms windows generates a lot of badly-formatted hints.
+	 * hints are only advisory, so don't log complaints about them.
+	 * it also generates answers in which p overshoots ep by exactly
+	 * one byte; this seems to be harmless, so don't log them either.
+	 */
+	if (sp->ep - sp->p < len &&
+	   !(strcmp(what, "hints") == 0 ||
+	     sp->p == sp->ep + 1 && strcmp(what, "answers") == 0)) {
+		dnslog("%s sp: base %#p p %#p ep %#p len %d", what,
+			sp->base, sp->p, sp->ep, len);
+		errtoolong(rp, sp, sp->ep - sp->p, len, "convM2RR");
+	}
+	if(sp->err || sp->rcode){
 		rrfree(rp);
 		return 0;
 	}
@@ -292,6 +345,7 @@ retry:
 		/* unknown type, just ignore it */
 		sp->p = data + len;
 		rrfree(rp);
+		rp = nil;
 		goto retry;
 	case Thinfo:
 		SYMBOL(rp->cpu);
@@ -306,11 +360,11 @@ retry:
 		break;
 	case Tmg:
 	case Tmr:
-		rp->mb = dnlookup(NAME(dname), Cin, 1);
+		rp->mb  = dnlookup(NAME(dname), Cin, 1);
 		break;
 	case Tminfo:
 		rp->rmb = dnlookup(NAME(dname), Cin, 1);
-		rp->mb = dnlookup(NAME(dname), Cin, 1);
+		rp->mb  = dnlookup(NAME(dname), Cin, 1);
 		break;
 	case Tmx:
 		USHORT(rp->pref);
@@ -327,17 +381,23 @@ retry:
 		break;
 	case Tsoa:
 		rp->host = dnlookup(NAME(dname), Cin, 1);
-		rp->rmb = dnlookup(NAME(dname), Cin, 1);
+		rp->rmb  = dnlookup(NAME(dname), Cin, 1);
 		ULONG(rp->soa->serial);
 		ULONG(rp->soa->refresh);
 		ULONG(rp->soa->retry);
 		ULONG(rp->soa->expire);
 		ULONG(rp->soa->minttl);
 		break;
+	case Tsrv:
+		USHORT(rp->srv->pri);
+		USHORT(rp->srv->weight);
+		USHORT(rp->srv->port);
+		rp->srv->target = dnlookup(NAME(dname), Cin, 1);
+		break;
 	case Ttxt:
 		l = &rp->txt;
 		*l = nil;
-		while(sp->p-data < len){
+		while(sp->p - data < len){
 			STRING(t);
 			*l = t;
 			l = &t->next;
@@ -348,7 +408,7 @@ retry:
 		break;
 	case Trp:
 		rp->rmb = dnlookup(NAME(dname), Cin, 1);
-		rp->rp = dnlookup(NAME(dname), Cin, 1);
+		rp->rp  = dnlookup(NAME(dname), Cin, 1);
 		break;
 	case Tkey:
 		USHORT(rp->key->flags);
@@ -374,8 +434,26 @@ retry:
 		BYTES(rp->cert->data, rp->cert->dlen);
 		break;
 	}
-	if(sp->p - data != len)
-		sp->err = "bad RR len";
+	if(sp->p - data != len) {
+		char ptype[64];
+
+		/*
+		 * ms windows 2000 generates cname queries for reverse lookups
+		 * with this particular error.  don't bother logging it.
+		 *
+		 * server: input error: bad cname RR len (actual 2 != len 0):
+		 * 235.9.104.135.in-addr.arpa cname
+		 *	235.9.104.135.in-addr.arpa from 135.104.9.235
+		 */
+		if (type == Tcname && sp->p - data == 2 && len == 0)
+			return rp;
+
+		snprint(sp->errbuf, sizeof sp->errbuf,
+			"bad %s RR len (actual %lud != len %d): %R",
+			rrname(type, ptype, sizeof ptype),
+			sp->p - data, len, rp);
+		sp->err = sp->errbuf;
+	}
 	return rp;
 }
 
@@ -386,16 +464,16 @@ static RR*
 convM2Q(Scan *sp)
 {
 	char dname[Domlen+1];
-	int type;
-	int class;
-	RR *rp;
+	int type, class;
+	RR *rp = nil;
 
 	NAME(dname);
 	USHORT(type);
 	USHORT(class);
-	if(sp->err)
-		return 0;
+	if(sp->err || sp->rcode)
+		return nil;
 
+	mstypehack(sp, type, "convM2Q");
 	rp = rralloc(type);
 	rp->owner = dnlookup(dname, class, 1);
 
@@ -403,21 +481,20 @@ convM2Q(Scan *sp)
 }
 
 static RR*
-rrloop(Scan *sp, int count, int quest)
+rrloop(Scan *sp, char *what, int count, int quest)
 {
 	int i;
-	static char errbuf[64];
 	RR *first, *rp, **l;
 
-	if(sp->err)
-		return 0;
+	if(sp->err || sp->rcode)
+		return nil;
 	l = &first;
-	first = 0;
+	first = nil;
 	for(i = 0; i < count; i++){
-		rp = quest ? convM2Q(sp) : convM2RR(sp);
-		if(rp == 0)
+		rp = quest? convM2Q(sp): convM2RR(sp, what);
+		if(rp == nil)
 			break;
-		if(sp->err){
+		if(sp->err || sp->rcode){
 			rrfree(rp);
 			break;
 		}
@@ -428,31 +505,44 @@ rrloop(Scan *sp, int count, int quest)
 }
 
 /*
- *  convert the next DNS from a message stream
+ *  convert the next DNS from a message stream.
+ *  if there are formatting errors or the like during parsing of the message,
+ *  set *codep to the outgoing response code (e.g., Rformat), which will
+ *  abort processing and reply immediately with the outgoing response code.
  */
 char*
-convM2DNS(uchar *buf, int len, DNSmsg *m)
+convM2DNS(uchar *buf, int len, DNSmsg *m, int *codep)
 {
 	Scan scan;
 	Scan *sp;
 	char *err;
+	RR *rp = nil;
 
+	if (codep)
+		*codep = 0;
+	assert(len >= 0);
 	scan.base = buf;
 	scan.p = buf;
 	scan.ep = buf + len;
-	scan.err = 0;
+	scan.err = nil;
+	scan.errbuf[0] = '\0';
+	scan.rcode = 0;
 	sp = &scan;
-	memset(m, 0, sizeof(DNSmsg));
+
+	memset(m, 0, sizeof *m);
 	USHORT(m->id);
 	USHORT(m->flags);
 	USHORT(m->qdcount);
 	USHORT(m->ancount);
 	USHORT(m->nscount);
 	USHORT(m->arcount);
-	m->qd = rrloop(sp, m->qdcount, 1);
-	m->an = rrloop(sp, m->ancount, 0);
-	m->ns = rrloop(sp, m->nscount, 0);
+
+	m->qd = rrloop(sp, "questions",	m->qdcount, 1);
+	m->an = rrloop(sp, "answers",	m->ancount, 0);
+	m->ns = rrloop(sp, "nameservers",m->nscount, 0);
 	err = scan.err;				/* live with bad ar's */
-	m->ar = rrloop(sp, m->arcount, 0);
+	m->ar = rrloop(sp, "hints",	m->arcount, 0);
+	if (codep)
+		*codep = scan.rcode;
 	return err;
 }

+ 1 - 1
sys/src/cmd/ndb/csquery.c

@@ -22,7 +22,7 @@ query(char *addr)
 	fd = open(server, ORDWR);
 	if(fd < 0)
 		sysfatal("cannot open %s: %r", server);
-	if(write(fd, addr, strlen(addr)) <= 0){
+	if(write(fd, addr, strlen(addr)) != strlen(addr)){
 		if(!statusonly)
 			fprint(2, "translating %s: %r\n", addr);
 		status = "errors";

+ 253 - 137
sys/src/cmd/ndb/dblookup.c

@@ -6,33 +6,39 @@
 #include "dns.h"
 
 static Ndb *db;
+static Lock	dblock;
 
-static RR*	dblookup1(char*, int, int, int);
 static RR*	addrrr(Ndbtuple*, Ndbtuple*);
-static RR*	nsrr(Ndbtuple*, Ndbtuple*);
 static RR*	cnamerr(Ndbtuple*, Ndbtuple*);
+static void	createptrs(void);
+static RR*	dblookup1(char*, int, int, int);
+static RR*	doaxfr(Ndb*, char*);
+static Ndbtuple*look(Ndbtuple*, Ndbtuple*, char*);
 static RR*	mxrr(Ndbtuple*, Ndbtuple*);
-static RR*	soarr(Ndbtuple*, Ndbtuple*);
+static RR*	nsrr(Ndbtuple*, Ndbtuple*);
+static RR*	nullrr(Ndbtuple*, Ndbtuple*);
 static RR*	ptrrr(Ndbtuple*, Ndbtuple*);
-static Ndbtuple* look(Ndbtuple*, Ndbtuple*, char*);
-static RR*	doaxfr(Ndb*, char*);
-static RR*	nullrr(Ndbtuple *entry, Ndbtuple *pair);
-static RR*	txtrr(Ndbtuple *entry, Ndbtuple *pair);
-static Lock	dblock;
-static void	createptrs(void);
+static RR*	soarr(Ndbtuple*, Ndbtuple*);
+static RR*	srvrr(Ndbtuple*, Ndbtuple*);
+static RR*	txtrr(Ndbtuple*, Ndbtuple*);
 
 static int	implemented[Tall] =
 {
 	[Ta]		1,
-	[Tns]		1,
-	[Tsoa]		1,
-	[Tmx]		1,
-	[Tptr]		1,
+	[Taaaa]		1,
 	[Tcname]	1,
+	[Tmx]		1,
+	[Tns]		1,
 	[Tnull]		1,
+	[Tptr]		1,
+	[Tsoa]		1,
+	[Tsrv]		1,
 	[Ttxt]		1,
 };
 
+/* straddle server configuration */
+static Ndbtuple *indoms, *innmsrvs, *outnmsrvs;
+
 static void
 nstrcpy(char *to, char *from, int len)
 {
@@ -43,20 +49,23 @@ nstrcpy(char *to, char *from, int len)
 int
 opendatabase(void)
 {
-	char buf[256];
-	Ndb *xdb;
-
-	if(db == nil){
-		snprint(buf, sizeof(buf), "%s/ndb", mntpt);
-		xdb = ndbopen(dbfile);
-		if(xdb != nil)
-			xdb->nohash = 1;
-		db = ndbcat(ndbopen(buf), xdb);
-	}
-	if(db == nil)
-		return -1;
-	else
+	char netdbnm[256];
+	Ndb *xdb, *netdb;
+
+	if (db)
 		return 0;
+
+	xdb = ndbopen(dbfile);		/* /lib/ndb */
+	if(xdb)
+		xdb->nohash = 1;	/* seems odd */
+
+	snprint(netdbnm, sizeof netdbnm, "%s/ndb", mntpt);
+	netdb = ndbopen(netdbnm);	/* /net/ndb */
+//	if(netdb)
+//		netdb->nohash = 1;	/* cs does this; seems right */
+
+	db = ndbcat(netdb, xdb);	/* both */
+	return db? 0: -1;
 }
 
 /*
@@ -68,16 +77,17 @@ opendatabase(void)
  *  shared state there.
  *
  *  e.g. for x.research.bell-labs.com, first look for a match against
- *       the x.research.bell-labs.com.  If nothing matches, try *.research.bell-labs.com.
+ *       the x.research.bell-labs.com.  If nothing matches,
+ *	 try *.research.bell-labs.com.
  */
 RR*
 dblookup(char *name, int class, int type, int auth, int ttl)
 {
-	RR *rp, *tp;
-	char buf[256];
+	int err;
 	char *wild, *cp;
+	char buf[256];
+	RR *rp, *tp;
 	DN *dp, *ndp;
-	int err;
 	static int parallel;
 	static int parfd[2];
 	static char token[1];
@@ -89,23 +99,25 @@ dblookup(char *name, int class, int type, int auth, int ttl)
 	err = Rname;
 
 	if(type == Tall){
-		rp = 0;
+		rp = nil;
 		for (type = Ta; type < Tall; type++)
 			if(implemented[type])
 				rrcat(&rp, dblookup(name, class, type, auth, ttl));
 		return rp;
 	}
 
+	rp = nil;
+
 	lock(&dblock);
 	dp = dnlookup(name, class, 1);
+
 	if(opendatabase() < 0)
 		goto out;
 	if(dp->rr)
 		err = 0;
 
 	/* first try the given name */
-	rp = 0;
-	if(cachedb)
+	if(cfg.cachedb)
 		rp = rrlookup(dp, type, NOneg);
 	else
 		rp = dblookup1(name, type, auth, ttl);
@@ -115,7 +127,7 @@ dblookup(char *name, int class, int type, int auth, int ttl)
 	/* try lower case version */
 	for(cp = name; *cp; cp++)
 		*cp = tolower(*cp);
-	if(cachedb)
+	if(cfg.cachedb)
 		rp = rrlookup(dp, type, NOneg);
 	else
 		rp = dblookup1(name, type, auth, ttl);
@@ -124,11 +136,11 @@ dblookup(char *name, int class, int type, int auth, int ttl)
 
 	/* walk the domain name trying the wildcard '*' at each position */
 	for(wild = strchr(name, '.'); wild; wild = strchr(wild+1, '.')){
-		snprint(buf, sizeof(buf), "*%s", wild);
+		snprint(buf, sizeof buf, "*%s", wild);
 		ndp = dnlookup(buf, class, 1);
 		if(ndp->rr)
 			err = 0;
-		if(cachedb)
+		if(cfg.cachedb)
 			rp = rrlookup(ndp, type, NOneg);
 		else
 			rp = dblookup1(buf, type, auth, ttl);
@@ -137,20 +149,30 @@ dblookup(char *name, int class, int type, int auth, int ttl)
 	}
 out:
 	/* add owner to uncached records */
-	if(rp){
+	if(rp)
 		for(tp = rp; tp; tp = tp->next)
 			tp->owner = dp;
-	} else {
+	else {
 		/* don't call it non-existent if it's not ours */
-		if(err == Rname && !inmyarea(name))
+		if(err == Rname && !inmyarea(name)) {
+//			dnslog("dblookup setting Rserver for %s", name);
 			err = Rserver;
-		dp->nonexistent = err;
+		}
+		dp->respcode = err;
 	}
 
 	unlock(&dblock);
 	return rp;
 }
 
+static ulong
+intval(Ndbtuple *entry, Ndbtuple *pair, char *attr, ulong def)
+{
+	Ndbtuple *t = look(entry, pair, attr);
+
+	return (t? strtoul(t->val, 0, 10): def);
+}
+
 /*
  *  lookup an RR in the network database
  */
@@ -166,7 +188,7 @@ dblookup1(char *name, int type, int auth, int ttl)
 	RR *(*f)(Ndbtuple*, Ndbtuple*);
 	int found, x;
 
-	dp = 0;
+	dp = nil;
 	switch(type){
 	case Tptr:
 		attr = "ptr";
@@ -188,6 +210,10 @@ dblookup1(char *name, int type, int auth, int ttl)
 		attr = "soa";
 		f = soarr;
 		break;
+	case Tsrv:
+		attr = "srv";
+		f = srvrr;
+		break;
 	case Tmx:
 		attr = "mx";
 		f = mxrr;
@@ -200,21 +226,25 @@ dblookup1(char *name, int type, int auth, int ttl)
 	case Tixfr:
 		return doaxfr(db, name);
 	default:
+//		dnslog("dnlookup1(%s) bad type", name);
 		return nil;
 	}
 
 	/*
 	 *  find a matching entry in the database
 	 */
+	t = nil;
 	free(ndbgetvalue(db, &s, "dom", name, attr, &t));
 
 	/*
 	 *  hack for local names
 	 */
-	if(t == 0 && strchr(name, '.') == 0)
+	if(t == nil && strchr(name, '.') == nil)
 		free(ndbgetvalue(db, &s, "sys", name, attr, &t));
-	if(t == 0)
+	if(t == nil) {
+//		dnslog("dnlookup1(%s) name not found", name);
 		return nil;
+	}
 
 	/* search whole entry for default domain name */
 	strncpy(dname, name, sizeof dname);
@@ -225,12 +255,9 @@ dblookup1(char *name, int type, int auth, int ttl)
 		}
 
 	/* ttl is maximum of soa minttl and entry's ttl ala rfc883 */
-	nt = look(t, s.t, "ttl");
-	if(nt){
-		x = atoi(nt->val);
-		if(x > ttl)
-			ttl = x;
-	}
+	x = intval(t, s.t, "ttl", 0);
+	if(x > ttl)
+		ttl = x;
 
 	/* default ttl is one day */
 	if(ttl < 0)
@@ -255,7 +282,7 @@ dblookup1(char *name, int type, int auth, int ttl)
 			rp->db = 1;
 			if(ttl)
 				rp->ttl = ttl;
-			if(dp == 0)
+			if(dp == nil)
 				dp = dnlookup(dname, Cin, 1);
 			rp->owner = dp;
 			*l = rp;
@@ -275,7 +302,7 @@ dblookup1(char *name, int type, int auth, int ttl)
 			if(ttl)
 				rp->ttl = ttl;
 			rp->auth = auth;
-			if(dp == 0)
+			if(dp == nil)
 				dp = dnlookup(dname, Cin, 1);
 			rp->owner = dp;
 			*l = rp;
@@ -283,6 +310,7 @@ dblookup1(char *name, int type, int auth, int ttl)
 		}
 	ndbfree(t);
 
+//	dnslog("dnlookup1(%s) -> %#p", name, list);
 	return list;
 }
 
@@ -364,15 +392,11 @@ cnamerr(Ndbtuple *entry, Ndbtuple *pair)
 static RR*
 mxrr(Ndbtuple *entry, Ndbtuple *pair)
 {
-	RR * rp;
+	RR *rp;
 
 	rp = rralloc(Tmx);
 	rp->host = dnlookup(pair->val, Cin, 1);
-	pair = look(entry, pair, "pref");
-	if(pair)
-		rp->pref = atoi(pair->val);
-	else
-		rp->pref = 1;
+	rp->pref = intval(entry, pair, "pref", 1);
 	return rp;
 }
 static RR*
@@ -412,28 +436,15 @@ soarr(Ndbtuple *entry, Ndbtuple *pair)
 	for(ndb = db; ndb; ndb = ndb->next)
 		if(ndb->mtime > rp->soa->serial)
 			rp->soa->serial = ndb->mtime;
-	rp->soa->refresh = Day;
-	rp->soa->retry = Hour;
-	rp->soa->expire = Day;
-	rp->soa->minttl = Day;
-	t = look(entry, pair, "retry");
-	if(t)
-		rp->soa->retry = atoi(t->val);
-	t = look(entry, pair, "expire");
-	if(t)
-		rp->soa->expire = atoi(t->val);
-	t = look(entry, pair, "ttl");
-	if(t)
-		rp->soa->minttl = atoi(t->val);
-	t = look(entry, pair, "refresh");
-	if(t)
-		rp->soa->refresh = atoi(t->val);
-	t = look(entry, pair, "serial");
-	if(t)
-		rp->soa->serial = strtoul(t->val, 0, 10);
+
+	rp->soa->retry  = intval(entry, pair, "retry", Hour);
+	rp->soa->expire = intval(entry, pair, "expire", Day);
+	rp->soa->minttl = intval(entry, pair, "ttl", Day);
+	rp->soa->refresh = intval(entry, pair, "refresh", Day);
+	rp->soa->serial = intval(entry, pair, "serial", rp->soa->serial);
 
 	ns = look(entry, pair, "ns");
-	if(ns == 0)
+	if(ns == nil)
 		ns = look(entry, pair, "dom");
 	rp->host = dnlookup(ns->val, Cin, 1);
 
@@ -445,30 +456,43 @@ soarr(Ndbtuple *entry, Ndbtuple *pair)
 	mb = look(entry, pair, "mbox");
 	if(mb == nil)
 		mb = look(entry, pair, "mb");
-	if(mb){
+	if(mb)
 		if(strchr(mb->val, '.')) {
 			p = strchr(mb->val, '@');
 			if(p != nil)
 				*p = '.';
 			rp->rmb = dnlookup(mb->val, Cin, 1);
 		} else {
-			snprint(mailbox, sizeof(mailbox), "%s.%s",
+			snprint(mailbox, sizeof mailbox, "%s.%s",
 				mb->val, ns->val);
 			rp->rmb = dnlookup(mailbox, Cin, 1);
 		}
-	} else {
-		snprint(mailbox, sizeof(mailbox), "postmaster.%s",
-			ns->val);
+	else {
+		snprint(mailbox, sizeof mailbox, "postmaster.%s", ns->val);
 		rp->rmb = dnlookup(mailbox, Cin, 1);
 	}
 
-	/*  hang dns slaves off of the soa.  this is 
+	/*
+	 *  hang dns slaves off of the soa.  this is
 	 *  for managing the area.
 	 */
 	for(t = entry; t != nil; t = t->entry)
 		if(strcmp(t->attr, "dnsslave") == 0)
 			addserver(&rp->soa->slaves, t->val);
-			
+
+	return rp;
+}
+
+static RR*
+srvrr(Ndbtuple *entry, Ndbtuple *pair)
+{
+	RR *rp;
+
+	rp = rralloc(Tsrv);
+	rp->srv->target = dnlookup(pair->val, Cin, 1);
+	rp->srv->pri    = intval(entry, pair, "pri", 0);
+	rp->srv->weight = intval(entry, pair, "weight", 0);
+	rp->srv->port   = intval(entry, pair, "port", 0);
 	return rp;
 }
 
@@ -525,11 +549,10 @@ dbfile2area(Ndb *db)
 	Ndbtuple *t;
 
 	if(debug)
-		syslog(0, logfile, "rereading %s", db->file);
+		dnslog("rereading %s", db->file);
 	Bseek(&db->b, 0, 0);
-	while(t = ndbparse(db)){
+	while(t = ndbparse(db))
 		ndbfree(t);
-	}
 }
 
 /*
@@ -539,36 +562,31 @@ static void
 dbpair2cache(DN *dp, Ndbtuple *entry, Ndbtuple *pair)
 {
 	RR *rp;
-	Ndbtuple *t;
 	static ulong ord;
 
 	rp = 0;
 	if(cistrcmp(pair->attr, "ip") == 0){
 		dp->ordinal = ord++;
 		rp = addrrr(entry, pair);
-	} else 	if(cistrcmp(pair->attr, "ns") == 0){
+	} else 	if(cistrcmp(pair->attr, "ns") == 0)
 		rp = nsrr(entry, pair);
-	} else if(cistrcmp(pair->attr, "soa") == 0){
+	else if(cistrcmp(pair->attr, "soa") == 0) {
 		rp = soarr(entry, pair);
 		addarea(dp, rp, pair);
-	} else if(cistrcmp(pair->attr, "mx") == 0){
+	} else if(cistrcmp(pair->attr, "mx") == 0)
 		rp = mxrr(entry, pair);
-	} else if(cistrcmp(pair->attr, "cname") == 0){
+	else if(cistrcmp(pair->attr, "cname") == 0)
 		rp = cnamerr(entry, pair);
-	} else if(cistrcmp(pair->attr, "nullrr") == 0){
+	else if(cistrcmp(pair->attr, "nullrr") == 0)
 		rp = nullrr(entry, pair);
-	} else if(cistrcmp(pair->attr, "txtrr") == 0){
+	else if(cistrcmp(pair->attr, "txtrr") == 0)
 		rp = txtrr(entry, pair);
-	}
-
-	if(rp == 0)
+	if(rp == nil)
 		return;
 
 	rp->owner = dp;
 	rp->db = 1;
-	t = look(entry, pair, "ttl");
-	if(t)
-		rp->ttl = atoi(t->val);
+	rp->ttl = intval(entry, pair, "ttl", rp->ttl);
 	rrattach(rp, 0);
 }
 static void
@@ -577,7 +595,7 @@ dbtuple2cache(Ndbtuple *t)
 	Ndbtuple *et, *nt;
 	DN *dp;
 
-	for(et = t; et; et = et->entry){
+	for(et = t; et; et = et->entry)
 		if(strcmp(et->attr, "dom") == 0){
 			dp = dnlookup(et->val, Cin, 1);
 
@@ -594,7 +612,6 @@ dbtuple2cache(Ndbtuple *t)
 				nt->ptr = 0;
 			}
 		}
-	}
 }
 static void
 dbfile2cache(Ndb *db)
@@ -602,21 +619,44 @@ dbfile2cache(Ndb *db)
 	Ndbtuple *t;
 
 	if(debug)
-		syslog(0, logfile, "rereading %s", db->file);
+		dnslog("rereading %s", db->file);
 	Bseek(&db->b, 0, 0);
 	while(t = ndbparse(db)){
 		dbtuple2cache(t);
 		ndbfree(t);
 	}
 }
+
+/* called with dblock held */
+static void
+loaddomsrvs(void)
+{
+	Ndbs s;
+
+	if (!cfg.inside || !cfg.straddle || !cfg.serve)
+		return;
+	if (indoms) {
+		ndbfree(indoms);
+		ndbfree(innmsrvs);
+		ndbfree(outnmsrvs);
+		indoms = innmsrvs = outnmsrvs = nil;
+	}
+	if (db == nil)
+		opendatabase();
+	free(ndbgetvalue(db, &s, "sys", "inside-dom", "dom", &indoms));
+	free(ndbgetvalue(db, &s, "sys", "inside-ns",  "ip",  &innmsrvs));
+	free(ndbgetvalue(db, &s, "sys", "outside-ns", "ip",  &outnmsrvs));
+	dnslog("[%d] ndb changed: reloaded inside-dom, inside-ns, outside-ns",
+		getpid());
+}
+
 void
 db2cache(int doit)
 {
+	ulong youngest, temp;
 	Ndb *ndb;
 	Dir *d;
-	ulong youngest, temp;
-	static ulong lastcheck;
-	static ulong lastyoungest;
+	static ulong lastcheck, lastyoungest;
 
 	/* no faster than once every 2 minutes */
 	if(now < lastcheck + 2*Min && !doit)
@@ -641,45 +681,46 @@ db2cache(int doit)
 	for(;;){
 		lastcheck = now;
 		youngest = 0;
-		for(ndb = db; ndb; ndb = ndb->next){
-			/* the dirfstat avoids walking the mount table each time */
+		for(ndb = db; ndb; ndb = ndb->next)
+			/* dirfstat avoids walking the mount table each time */
 			if((d = dirfstat(Bfildes(&ndb->b))) != nil ||
 			   (d = dirstat(ndb->file)) != nil){
-				temp = d->mtime;		/* ulong vs int crap */
+				temp = d->mtime;	/* ulong vs int crap */
 				if(temp > youngest)
 					youngest = temp;
 				free(d);
 			}
-		}
 		if(!doit && youngest == lastyoungest)
 			break;
-	
+
 		/* forget our area definition */
 		freearea(&owned);
 		freearea(&delegated);
-	
+
 		/* reopen all the files (to get oldest for time stamp) */
 		for(ndb = db; ndb; ndb = ndb->next)
 			ndbreopen(ndb);
 
-		if(cachedb){
+		/* reload straddle-server configuration */
+		loaddomsrvs();
+
+		if(cfg.cachedb){
 			/* mark all db records as timed out */
 			dnagedb();
-	
+
 			/* read in new entries */
 			for(ndb = db; ndb; ndb = ndb->next)
 				dbfile2cache(ndb);
-	
-			/* mark as authentic anything in our domain */
+
+			/* mark as authoritative anything in our domain */
 			dnauthdb();
-	
+
 			/* remove old entries */
 			dnageall(1);
-		} else {
+		} else
 			/* read all the soa's to get database defaults */
 			for(ndb = db; ndb; ndb = ndb->next)
 				dbfile2area(ndb);
-		}
 
 		doit = 0;
 		lastyoungest = youngest;
@@ -703,7 +744,7 @@ lookupinfo(char *attr)
 
 	snprint(buf, sizeof buf, "%I", ipaddr);
 	a[0] = attr;
-	
+
 	lock(&dblock);
 	if(opendatabase() < 0){
 		unlock(&dblock);
@@ -714,7 +755,7 @@ lookupinfo(char *attr)
 	return t;
 }
 
-char *localservers = "local#dns#servers";
+char *localservers =	  "local#dns#servers";
 char *localserverprefix = "local#dns#server";
 
 /*
@@ -740,7 +781,8 @@ baddelegation(RR *rp, RR *nsrp, uchar *addr)
 		if(rp->owner != nsrp->owner)
 		if(subsume(rp->owner->name, nsrp->owner->name) &&
 		   strcmp(nsrp->owner->name, localservers) != 0){
-			syslog(0, logfile, "delegation loop %R -> %R from %I", nsrp, rp, addr);
+			dnslog("delegation loop %R -> %R from %I",
+				nsrp, rp, addr);
 			return 1;
 		}
 
@@ -749,7 +791,8 @@ baddelegation(RR *rp, RR *nsrp, uchar *addr)
 			if(rp->host && cistrcmp(rp->host->name, nt->val) == 0)
 				break;
 		if(nt != nil && !inmyarea(rp->owner->name)){
-			syslog(0, logfile, "bad delegation %R from %I", rp, addr);
+			dnslog("bad delegation %R from %I",
+				rp, addr);
 			return 1;
 		}
 	}
@@ -766,7 +809,7 @@ addlocaldnsserver(DN *dp, int class, char *ipaddr, int i)
 
 	/* ns record for name server, make up an impossible name */
 	rp = rralloc(Tns);
-	snprint(buf, sizeof(buf), "%s%d", localserverprefix, i);
+	snprint(buf, sizeof buf, "%s%d", localserverprefix, i);
 	nsdp = dnlookup(buf, class, 1);
 	rp->host = nsdp;
 	rp->owner = dp;
@@ -792,12 +835,12 @@ addlocaldnsserver(DN *dp, int class, char *ipaddr, int i)
 RR*
 dnsservers(int class)
 {
+	int i, n;
+	char *p, *buf;
+	char *args[5];
 	Ndbtuple *t, *nt;
 	RR *nsrp;
 	DN *dp;
-	char *p;
-	int i, n;
-	char *buf, *args[5];
 
 	dp = dnlookup(localservers, class, 1);
 	nsrp = rrlookup(dp, Tns, NOneg);
@@ -880,12 +923,10 @@ static void
 createptrs(void)
 {
 	int len, dlen, n;
-	Area *s;
+	char buf[Domlen+1], ipa[48];
 	char *f[40];
-	char buf[Domlen+1];
-	uchar net[IPaddrlen];
-	uchar mask[IPaddrlen];
-	char ipa[48];
+	uchar net[IPaddrlen], mask[IPaddrlen];
+	Area *s;
 	Ndbtuple *t, *nt;
 
 	dlen = strlen(v4ptrdom);
@@ -897,8 +938,8 @@ createptrs(void)
 			continue;
 
 		/* get mask and net value */
-		strncpy(buf, s->soarr->owner->name, sizeof(buf));
-		buf[sizeof(buf)-1] = 0;
+		strncpy(buf, s->soarr->owner->name, sizeof buf);
+		buf[sizeof buf-1] = 0;
 		n = getfields(buf, f, nelem(f), 0, ".");
 		memset(mask, 0xff, IPaddrlen);
 		ipmove(net, v4prefix);
@@ -928,10 +969,10 @@ createptrs(void)
 			net[IPv4off+3] = atoi(f[0]);
 			sprint(ipa, "%I", net);
 			t = ndbipinfo(db, "ip", ipa, attribs, 1);
-			if(t == nil) /* could be a reverse with no forward */
+			if(t == nil)	/* could be a reverse with no forward */
 				continue;
 			nt = look(t, t, "ipmask");
-			if(nt == nil){	/* we're confused */
+			if(nt == nil){		/* we're confused */
 				ndbfree(t);
 				continue;
 			}
@@ -942,7 +983,82 @@ createptrs(void)
 			continue;
 		}
 
-		/* go through all domain entries looking for RR's in this network and create ptrs */
+		/*
+		 * go through all domain entries looking for RR's
+		 * in this network and create ptrs
+		 */
 		dnptr(net, mask, s->soarr->owner->name, 6-n, 0);
 	}
 }
+
+/*
+ * is this domain (or DOMAIN or Domain or dOMAIN)
+ * internal to our organisation (behind our firewall)?
+ * only inside straddling servers care, everybody else gets told `yes',
+ * so they'll use mntpt for their queries.
+ */
+int
+insideaddr(char *dom)
+{
+	int domlen, vallen, rv;
+	Ndbtuple *t;
+
+	if (!cfg.inside || !cfg.straddle || !cfg.serve)
+		return 1;
+
+	lock(&dblock);
+	if (indoms == nil)
+		loaddomsrvs();
+	if (indoms == nil) {
+		unlock(&dblock);
+		return 1;	/* no "inside" sys, try inside nameservers */
+	}
+
+	rv = 0;
+	domlen = strlen(dom);
+	for (t = indoms; t != nil; t = t->entry) {
+		if (strcmp(t->attr, "dom") != 0)
+			continue;
+		vallen = strlen(t->val);
+		if (cistrcmp(dom, t->val) == 0 ||
+		    domlen > vallen &&
+		     cistrcmp(dom + domlen - vallen, t->val) == 0 &&
+		     dom[domlen - vallen - 1] == '.') {
+			rv = 1;
+			break;
+		}
+	}
+	unlock(&dblock);
+	return rv;
+}
+
+int
+insidens(uchar *ip)
+{
+	uchar ipa[IPaddrlen];
+	Ndbtuple *t;
+
+	for (t = innmsrvs; t != nil; t = t->entry)
+		if (strcmp(t->attr, "ip") == 0) {
+			parseip(ipa, t->val);
+			if (memcmp(ipa, ip, sizeof ipa) == 0)
+				return 1;
+		}
+	return 0;
+}
+
+uchar *
+outsidens(int n)
+{
+	int i;
+	Ndbtuple *t;
+	static uchar ipa[IPaddrlen];
+
+	i = 0;
+	for (t = outnmsrvs; t != nil; t = t->entry)
+		if (strcmp(t->attr, "ip") == 0 && i++ == n) {
+			parseip(ipa, t->val);
+			return ipa;
+		}
+	return nil;
+}

+ 0 - 1142
sys/src/cmd/ndb/dn.acid

@@ -1,1142 +0,0 @@
-sizeof_1_ = 8;
-aggr _1_
-{
-	'U' 0 lo;
-	'U' 4 hi;
-};
-
-defn
-_1_(addr) {
-	complex _1_ addr;
-	print("	lo	", addr.lo, "\n");
-	print("	hi	", addr.hi, "\n");
-};
-
-sizeofFPdbleword = 8;
-aggr FPdbleword
-{
-	'F' 0 x;
-	{
-	'U' 0 lo;
-	'U' 4 hi;
-	};
-};
-
-defn
-FPdbleword(addr) {
-	complex FPdbleword addr;
-	print("	x	", addr.x, "\n");
-	print("_1_ {\n");
-		_1_(addr+0);
-	print("}\n");
-};
-
-UTFmax = 3;
-Runesync = 128;
-Runeself = 128;
-Runeerror = 65533;
-sizeofFmt = 48;
-aggr Fmt
-{
-	'b' 0 runes;
-	'X' 4 start;
-	'X' 8 to;
-	'X' 12 stop;
-	'X' 16 flush;
-	'X' 20 farg;
-	'D' 24 nfmt;
-	'X' 28 args;
-	'D' 32 r;
-	'D' 36 width;
-	'D' 40 prec;
-	'U' 44 flags;
-};
-
-defn
-Fmt(addr) {
-	complex Fmt addr;
-	print("	runes	", addr.runes, "\n");
-	print("	start	", addr.start\X, "\n");
-	print("	to	", addr.to\X, "\n");
-	print("	stop	", addr.stop\X, "\n");
-	print("	flush	", addr.flush\X, "\n");
-	print("	farg	", addr.farg\X, "\n");
-	print("	nfmt	", addr.nfmt, "\n");
-	print("	args	", addr.args\X, "\n");
-	print("	r	", addr.r, "\n");
-	print("	width	", addr.width, "\n");
-	print("	prec	", addr.prec, "\n");
-	print("	flags	", addr.flags, "\n");
-};
-
-FmtWidth = 1;
-FmtLeft = 2;
-FmtPrec = 4;
-FmtSharp = 8;
-FmtSpace = 16;
-FmtSign = 32;
-FmtZero = 64;
-FmtUnsigned = 128;
-FmtShort = 256;
-FmtLong = 512;
-FmtVLong = 1024;
-FmtComma = 2048;
-FmtByte = 4096;
-FmtFlag = 8192;
-sizeofTm = 40;
-aggr Tm
-{
-	'D' 0 sec;
-	'D' 4 min;
-	'D' 8 hour;
-	'D' 12 mday;
-	'D' 16 mon;
-	'D' 20 year;
-	'D' 24 wday;
-	'D' 28 yday;
-	'a' 32 zone;
-	'D' 36 tzoff;
-};
-
-defn
-Tm(addr) {
-	complex Tm addr;
-	print("	sec	", addr.sec, "\n");
-	print("	min	", addr.min, "\n");
-	print("	hour	", addr.hour, "\n");
-	print("	mday	", addr.mday, "\n");
-	print("	mon	", addr.mon, "\n");
-	print("	year	", addr.year, "\n");
-	print("	wday	", addr.wday, "\n");
-	print("	yday	", addr.yday, "\n");
-	print("	zone	", addr.zone, "\n");
-	print("	tzoff	", addr.tzoff, "\n");
-};
-
-PNPROC = 1;
-PNGROUP = 2;
-Profoff = 0;
-Profuser = 1;
-Profkernel = 2;
-Proftime = 3;
-Profsample = 4;
-sizeofLock = 4;
-aggr Lock
-{
-	'D' 0 val;
-};
-
-defn
-Lock(addr) {
-	complex Lock addr;
-	print("	val	", addr.val, "\n");
-};
-
-sizeofQLp = 12;
-aggr QLp
-{
-	'D' 0 inuse;
-	'A' QLp 4 next;
-	'C' 8 state;
-};
-
-defn
-QLp(addr) {
-	complex QLp addr;
-	print("	inuse	", addr.inuse, "\n");
-	print("	next	", addr.next\X, "\n");
-	print("	state	", addr.state, "\n");
-};
-
-sizeofQLock = 16;
-aggr QLock
-{
-	Lock 0 lock;
-	'D' 4 locked;
-	'A' QLp 8 $head;
-	'A' QLp 12 $tail;
-};
-
-defn
-QLock(addr) {
-	complex QLock addr;
-	print("Lock lock {\n");
-	Lock(addr.lock);
-	print("}\n");
-	print("	locked	", addr.locked, "\n");
-	print("	$head	", addr.$head\X, "\n");
-	print("	$tail	", addr.$tail\X, "\n");
-};
-
-sizeofRWLock = 20;
-aggr RWLock
-{
-	Lock 0 lock;
-	'D' 4 readers;
-	'D' 8 writer;
-	'A' QLp 12 $head;
-	'A' QLp 16 $tail;
-};
-
-defn
-RWLock(addr) {
-	complex RWLock addr;
-	print("Lock lock {\n");
-	Lock(addr.lock);
-	print("}\n");
-	print("	readers	", addr.readers, "\n");
-	print("	writer	", addr.writer, "\n");
-	print("	$head	", addr.$head\X, "\n");
-	print("	$tail	", addr.$tail\X, "\n");
-};
-
-sizeofRendez = 12;
-aggr Rendez
-{
-	'A' QLock 0 l;
-	'A' QLp 4 $head;
-	'A' QLp 8 $tail;
-};
-
-defn
-Rendez(addr) {
-	complex Rendez addr;
-	print("	l	", addr.l\X, "\n");
-	print("	$head	", addr.$head\X, "\n");
-	print("	$tail	", addr.$tail\X, "\n");
-};
-
-sizeofNetConnInfo = 36;
-aggr NetConnInfo
-{
-	'X' 0 dir;
-	'X' 4 root;
-	'X' 8 spec;
-	'X' 12 lsys;
-	'X' 16 lserv;
-	'X' 20 rsys;
-	'X' 24 rserv;
-	'X' 28 laddr;
-	'X' 32 raddr;
-};
-
-defn
-NetConnInfo(addr) {
-	complex NetConnInfo addr;
-	print("	dir	", addr.dir\X, "\n");
-	print("	root	", addr.root\X, "\n");
-	print("	spec	", addr.spec\X, "\n");
-	print("	lsys	", addr.lsys\X, "\n");
-	print("	lserv	", addr.lserv\X, "\n");
-	print("	rsys	", addr.rsys\X, "\n");
-	print("	rserv	", addr.rserv\X, "\n");
-	print("	laddr	", addr.laddr\X, "\n");
-	print("	raddr	", addr.raddr\X, "\n");
-};
-
-RFNAMEG = 1;
-RFENVG = 2;
-RFFDG = 4;
-RFNOTEG = 8;
-RFPROC = 16;
-RFMEM = 32;
-RFNOWAIT = 64;
-RFCNAMEG = 1024;
-RFCENVG = 2048;
-RFCFDG = 4096;
-RFREND = 8192;
-RFNOMNT = 16384;
-sizeofQid = 16;
-aggr Qid
-{
-	'W' 0 path;
-	'U' 8 vers;
-	'b' 12 type;
-};
-
-defn
-Qid(addr) {
-	complex Qid addr;
-	print("	path	", addr.path, "\n");
-	print("	vers	", addr.vers, "\n");
-	print("	type	", addr.type, "\n");
-};
-
-sizeofDir = 60;
-aggr Dir
-{
-	'u' 0 type;
-	'U' 4 dev;
-	Qid 8 qid;
-	'U' 24 mode;
-	'U' 28 atime;
-	'U' 32 mtime;
-	'V' 36 length;
-	'X' 44 name;
-	'X' 48 uid;
-	'X' 52 gid;
-	'X' 56 muid;
-};
-
-defn
-Dir(addr) {
-	complex Dir addr;
-	print("	type	", addr.type, "\n");
-	print("	dev	", addr.dev, "\n");
-	print("Qid qid {\n");
-	Qid(addr.qid);
-	print("}\n");
-	print("	mode	", addr.mode, "\n");
-	print("	atime	", addr.atime, "\n");
-	print("	mtime	", addr.mtime, "\n");
-	print("	length	", addr.length, "\n");
-	print("	name	", addr.name\X, "\n");
-	print("	uid	", addr.uid\X, "\n");
-	print("	gid	", addr.gid\X, "\n");
-	print("	muid	", addr.muid\X, "\n");
-};
-
-sizeofWaitmsg = 20;
-aggr Waitmsg
-{
-	'D' 0 pid;
-	'a' 4 time;
-	'X' 16 msg;
-};
-
-defn
-Waitmsg(addr) {
-	complex Waitmsg addr;
-	print("	pid	", addr.pid, "\n");
-	print("	time	", addr.time, "\n");
-	print("	msg	", addr.msg\X, "\n");
-};
-
-sizeofIOchunk = 8;
-aggr IOchunk
-{
-	'X' 0 addr;
-	'U' 4 len;
-};
-
-defn
-IOchunk(addr) {
-	complex IOchunk addr;
-	print("	addr	", addr.addr\X, "\n");
-	print("	len	", addr.len, "\n");
-};
-
-IPaddrlen = 16;
-IPv4addrlen = 4;
-IPv4off = 12;
-IPllen = 4;
-sizeofIplifc = 60;
-aggr Iplifc
-{
-	'A' Iplifc 0 next;
-	'a' 4 ip;
-	'a' 20 mask;
-	'a' 36 net;
-	'U' 52 preflt;
-	'U' 56 validlt;
-};
-
-defn
-Iplifc(addr) {
-	complex Iplifc addr;
-	print("	next	", addr.next\X, "\n");
-	print("	ip	", addr.ip, "\n");
-	print("	mask	", addr.mask, "\n");
-	print("	net	", addr.net, "\n");
-	print("	preflt	", addr.preflt, "\n");
-	print("	validlt	", addr.validlt, "\n");
-};
-
-sizeofIpv6rp = 36;
-aggr Ipv6rp
-{
-	'D' 0 mflag;
-	'D' 4 oflag;
-	'D' 8 maxraint;
-	'D' 12 minraint;
-	'D' 16 linkmtu;
-	'D' 20 reachtime;
-	'D' 24 rxmitra;
-	'D' 28 ttl;
-	'D' 32 routerlt;
-};
-
-defn
-Ipv6rp(addr) {
-	complex Ipv6rp addr;
-	print("	mflag	", addr.mflag, "\n");
-	print("	oflag	", addr.oflag, "\n");
-	print("	maxraint	", addr.maxraint, "\n");
-	print("	minraint	", addr.minraint, "\n");
-	print("	linkmtu	", addr.linkmtu, "\n");
-	print("	reachtime	", addr.reachtime, "\n");
-	print("	rxmitra	", addr.rxmitra, "\n");
-	print("	ttl	", addr.ttl, "\n");
-	print("	routerlt	", addr.routerlt, "\n");
-};
-
-sizeofIpifc = 136;
-aggr Ipifc
-{
-	'A' Ipifc 0 next;
-	'A' Iplifc 4 lifc;
-	'D' 8 index;
-	'a' 12 dev;
-	'b' 76 sendra6;
-	'b' 77 recvra6;
-	'D' 80 mtu;
-	'U' 84 pktin;
-	'U' 88 pktout;
-	'U' 92 errin;
-	'U' 96 errout;
-	Ipv6rp 100 rp;
-};
-
-defn
-Ipifc(addr) {
-	complex Ipifc addr;
-	print("	next	", addr.next\X, "\n");
-	print("	lifc	", addr.lifc\X, "\n");
-	print("	index	", addr.index, "\n");
-	print("	dev	", addr.dev, "\n");
-	print("	sendra6	", addr.sendra6, "\n");
-	print("	recvra6	", addr.recvra6, "\n");
-	print("	mtu	", addr.mtu, "\n");
-	print("	pktin	", addr.pktin, "\n");
-	print("	pktout	", addr.pktout, "\n");
-	print("	errin	", addr.errin, "\n");
-	print("	errout	", addr.errout, "\n");
-	print("Ipv6rp rp {\n");
-	Ipv6rp(addr.rp);
-	print("}\n");
-};
-
-OUdphdrsize = 36;
-sizeofOUdphdr = 36;
-aggr OUdphdr
-{
-	'a' 0 raddr;
-	'a' 16 laddr;
-	'a' 32 rport;
-	'a' 34 lport;
-};
-
-defn
-OUdphdr(addr) {
-	complex OUdphdr addr;
-	print("	raddr	", addr.raddr, "\n");
-	print("	laddr	", addr.laddr, "\n");
-	print("	rport	", addr.rport, "\n");
-	print("	lport	", addr.lport, "\n");
-};
-
-Udphdrsize = 52;
-sizeofUdphdr = 52;
-aggr Udphdr
-{
-	'a' 0 raddr;
-	'a' 16 laddr;
-	'a' 32 ifcaddr;
-	'a' 48 rport;
-	'a' 50 lport;
-};
-
-defn
-Udphdr(addr) {
-	complex Udphdr addr;
-	print("	raddr	", addr.raddr, "\n");
-	print("	laddr	", addr.laddr, "\n");
-	print("	ifcaddr	", addr.ifcaddr, "\n");
-	print("	rport	", addr.rport, "\n");
-	print("	lport	", addr.lport, "\n");
-};
-
-sizeofPool = 88;
-aggr Pool
-{
-	'X' 0 name;
-	'U' 4 maxsize;
-	'U' 8 cursize;
-	'U' 12 curfree;
-	'U' 16 curalloc;
-	'U' 20 minarena;
-	'U' 24 quantum;
-	'U' 28 minblock;
-	'X' 32 freeroot;
-	'X' 36 arenalist;
-	'X' 40 alloc;
-	'X' 44 merge;
-	'X' 48 move;
-	'D' 52 flags;
-	'D' 56 nfree;
-	'D' 60 lastcompact;
-	'X' 64 lock;
-	'X' 68 unlock;
-	'X' 72 print;
-	'X' 76 panic;
-	'X' 80 logstack;
-	'X' 84 private;
-};
-
-defn
-Pool(addr) {
-	complex Pool addr;
-	print("	name	", addr.name\X, "\n");
-	print("	maxsize	", addr.maxsize, "\n");
-	print("	cursize	", addr.cursize, "\n");
-	print("	curfree	", addr.curfree, "\n");
-	print("	curalloc	", addr.curalloc, "\n");
-	print("	minarena	", addr.minarena, "\n");
-	print("	quantum	", addr.quantum, "\n");
-	print("	minblock	", addr.minblock, "\n");
-	print("	freeroot	", addr.freeroot\X, "\n");
-	print("	arenalist	", addr.arenalist\X, "\n");
-	print("	alloc	", addr.alloc\X, "\n");
-	print("	merge	", addr.merge\X, "\n");
-	print("	move	", addr.move\X, "\n");
-	print("	flags	", addr.flags, "\n");
-	print("	nfree	", addr.nfree, "\n");
-	print("	lastcompact	", addr.lastcompact, "\n");
-	print("	lock	", addr.lock\X, "\n");
-	print("	unlock	", addr.unlock\X, "\n");
-	print("	print	", addr.print\X, "\n");
-	print("	panic	", addr.panic\X, "\n");
-	print("	logstack	", addr.logstack\X, "\n");
-	print("	private	", addr.private\X, "\n");
-};
-
-complex Pool mainmem;
-complex Pool imagmem;
-POOL_ANTAGONISM = 1;
-POOL_PARANOIA = 2;
-POOL_VERBOSITY = 4;
-POOL_DEBUGGING = 8;
-POOL_LOGGING = 16;
-POOL_TOLERANCE = 32;
-POOL_NOREUSE = 64;
-Ta = 1;
-Tns = 2;
-Tmd = 3;
-Tmf = 4;
-Tcname = 5;
-Tsoa = 6;
-Tmb = 7;
-Tmg = 8;
-Tmr = 9;
-Tnull = 10;
-Twks = 11;
-Tptr = 12;
-Thinfo = 13;
-Tminfo = 14;
-Tmx = 15;
-Ttxt = 16;
-Trp = 17;
-Tafsdb = 18;
-Tx25 = 19;
-Tisdn = 20;
-Trt = 21;
-Tnsap = 22;
-Tnsapptr = 23;
-Tsig = 24;
-Tkey = 25;
-Tpx = 26;
-Tgpos = 27;
-Taaaa = 28;
-Tloc = 29;
-Tnxt = 30;
-Teid = 31;
-Tnimloc = 32;
-Tsrv = 33;
-Tatma = 34;
-Tnaptr = 35;
-Tkx = 36;
-Tcert = 37;
-Ta6 = 38;
-Tdname = 39;
-Tsink = 40;
-Topt = 41;
-Tapl = 42;
-Tds = 43;
-Tsshfp = 44;
-Tipseckey = 45;
-Trrsig = 46;
-Tnsec = 47;
-Tdnskey = 48;
-Tspf = 99;
-Tuinfo = 100;
-Tuid = 101;
-Tgid = 102;
-Tunspec = 103;
-Ttkey = 249;
-Ttsig = 250;
-Tixfr = 251;
-Taxfr = 252;
-Tmailb = 253;
-Tmaila = 254;
-Tall = 255;
-Csym = 0;
-Cin = 1;
-Ccs = 2;
-Cch = 3;
-Chs = 4;
-Call = 255;
-Oquery = 0;
-Oinverse = 2048;
-Ostatus = 4096;
-Onotify = 8192;
-Oupdate = 10240;
-Omask = 30720;
-Rok = 0;
-Rformat = 1;
-Rserver = 2;
-Rname = 3;
-Runimplimented = 4;
-Rrefused = 5;
-Ryxdomain = 6;
-Ryxrrset = 7;
-Rnxrrset = 8;
-Rnotauth = 9;
-Rnotzone = 10;
-Rbadvers = 16;
-Rbadkey = 17;
-Rbadtime = 18;
-Rbadmode = 19;
-Rbadname = 20;
-Rbadalg = 21;
-Rmask = 31;
-Rtimeout = 32;
-Fresp = 32768;
-Fauth = 1024;
-Ftrunc = 512;
-Frecurse = 256;
-Fcanrec = 128;
-Domlen = 256;
-Labellen = 256;
-Strlen = 256;
-Iplen = 32;
-Min = 60;
-Hour = 3600;
-Day = 86400;
-Week = 604800;
-Year = 31449600;
-DEFTTL = 86400;
-Reserved = 300;
-Maxudp = 512;
-Maxudpin = 2048;
-HTLEN = 4096;
-RRmagic = 3735927486;
-DNmagic = 2702221584;
-Maxactive = 32;
-sizeofRequest = 20;
-aggr Request
-{
-	'D' 0 isslave;
-	'U' 4 aborttime;
-	'a' 8 mret;
-	'D' 16 id;
-};
-
-defn
-Request(addr) {
-	complex Request addr;
-	print("	isslave	", addr.isslave, "\n");
-	print("	aborttime	", addr.aborttime, "\n");
-	print("	mret	", addr.mret, "\n");
-	print("	id	", addr.id, "\n");
-};
-
-sizeofDN = 32;
-aggr DN
-{
-	'A' DN 0 next;
-	'U' 4 magic;
-	'X' 8 name;
-	'X' 12 rr;
-	'U' 16 referenced;
-	'U' 20 lookuptime;
-	'u' 24 class;
-	'C' 26 refs;
-	'C' 27 nonexistent;
-	'U' 28 ordinal;
-};
-
-defn
-DN(addr) {
-	complex DN addr;
-	print("	next	", addr.next\X, "\n");
-	print("	magic	", addr.magic, "\n");
-	print("	name	", addr.name\X, "\n");
-	print("	rr	", addr.rr\X, "\n");
-	print("	referenced	", addr.referenced, "\n");
-	print("	lookuptime	", addr.lookuptime, "\n");
-	print("	class	", addr.class, "\n");
-	print("	refs	", addr.refs, "\n");
-	print("	nonexistent	", addr.nonexistent, "\n");
-	print("	ordinal	", addr.ordinal, "\n");
-};
-
-sizeofKey = 20;
-aggr Key
-{
-	'D' 0 flags;
-	'D' 4 proto;
-	'D' 8 alg;
-	'D' 12 dlen;
-	'X' 16 data;
-};
-
-defn
-Key(addr) {
-	complex Key addr;
-	print("	flags	", addr.flags, "\n");
-	print("	proto	", addr.proto, "\n");
-	print("	alg	", addr.alg, "\n");
-	print("	dlen	", addr.dlen, "\n");
-	print("	data	", addr.data\X, "\n");
-};
-
-sizeofCert = 20;
-aggr Cert
-{
-	'D' 0 type;
-	'D' 4 tag;
-	'D' 8 alg;
-	'D' 12 dlen;
-	'X' 16 data;
-};
-
-defn
-Cert(addr) {
-	complex Cert addr;
-	print("	type	", addr.type, "\n");
-	print("	tag	", addr.tag, "\n");
-	print("	alg	", addr.alg, "\n");
-	print("	dlen	", addr.dlen, "\n");
-	print("	data	", addr.data\X, "\n");
-};
-
-sizeofSig = 40;
-aggr Sig
-{
-	'D' 0 type;
-	'D' 4 alg;
-	'D' 8 labels;
-	'U' 12 ttl;
-	'U' 16 exp;
-	'U' 20 incep;
-	'D' 24 tag;
-	'A' DN 28 signer;
-	'D' 32 dlen;
-	'X' 36 data;
-};
-
-defn
-Sig(addr) {
-	complex Sig addr;
-	print("	type	", addr.type, "\n");
-	print("	alg	", addr.alg, "\n");
-	print("	labels	", addr.labels, "\n");
-	print("	ttl	", addr.ttl, "\n");
-	print("	exp	", addr.exp, "\n");
-	print("	incep	", addr.incep, "\n");
-	print("	tag	", addr.tag, "\n");
-	print("	signer	", addr.signer\X, "\n");
-	print("	dlen	", addr.dlen, "\n");
-	print("	data	", addr.data\X, "\n");
-};
-
-sizeofNull = 8;
-aggr Null
-{
-	'D' 0 dlen;
-	'X' 4 data;
-};
-
-defn
-Null(addr) {
-	complex Null addr;
-	print("	dlen	", addr.dlen, "\n");
-	print("	data	", addr.data\X, "\n");
-};
-
-sizeofTxt = 8;
-aggr Txt
-{
-	'A' Txt 0 next;
-	'X' 4 p;
-};
-
-defn
-Txt(addr) {
-	complex Txt addr;
-	print("	next	", addr.next\X, "\n");
-	print("	p	", addr.p\X, "\n");
-};
-
-sizeof_2_ = 4;
-aggr _2_
-{
-	'A' DN 0 negsoaowner;
-	'A' DN 0 host;
-	'A' DN 0 cpu;
-	'A' DN 0 mb;
-	'A' DN 0 ip;
-	'A' DN 0 rp;
-	'D' 0 cruftlen;
-	'U' 0 arg0;
-};
-
-defn
-_2_(addr) {
-	complex _2_ addr;
-	print("	negsoaowner	", addr.negsoaowner\X, "\n");
-	print("	host	", addr.host\X, "\n");
-	print("	cpu	", addr.cpu\X, "\n");
-	print("	mb	", addr.mb\X, "\n");
-	print("	ip	", addr.ip\X, "\n");
-	print("	rp	", addr.rp\X, "\n");
-	print("	cruftlen	", addr.cruftlen, "\n");
-	print("	arg0	", addr.arg0, "\n");
-};
-
-sizeof_3_ = 4;
-aggr _3_
-{
-	'D' 0 negrcode;
-	'A' DN 0 rmb;
-	'A' DN 0 ptr;
-	'A' DN 0 os;
-	'U' 0 pref;
-	'U' 0 $local;
-	'U' 0 arg1;
-};
-
-defn
-_3_(addr) {
-	complex _3_ addr;
-	print("	negrcode	", addr.negrcode, "\n");
-	print("	rmb	", addr.rmb\X, "\n");
-	print("	ptr	", addr.ptr\X, "\n");
-	print("	os	", addr.os\X, "\n");
-	print("	pref	", addr.pref, "\n");
-	print("	$local	", addr.$local, "\n");
-	print("	arg1	", addr.arg1, "\n");
-};
-
-sizeof_4_ = 4;
-aggr _4_
-{
-	'X' 0 soa;
-	'A' Key 0 key;
-	'A' Cert 0 cert;
-	'A' Sig 0 sig;
-	'A' Null 0 null;
-	'A' Txt 0 txt;
-};
-
-defn
-_4_(addr) {
-	complex _4_ addr;
-	print("	soa	", addr.soa\X, "\n");
-	print("	key	", addr.key\X, "\n");
-	print("	cert	", addr.cert\X, "\n");
-	print("	sig	", addr.sig\X, "\n");
-	print("	null	", addr.null\X, "\n");
-	print("	txt	", addr.txt\X, "\n");
-};
-
-sizeofRR = 52;
-aggr RR
-{
-	'A' RR 0 next;
-	'U' 4 magic;
-	'A' DN 8 owner;
-	'b' 12 negative;
-	'U' 16 pc;
-	'U' 20 ttl;
-	'U' 24 expire;
-	'u' 28 type;
-	'u' 30 query;
-	'b' 32 auth;
-	'b' 33 db;
-	'b' 34 cached;
-	'U' 36 marker;
-	{
-	'A' DN 40 negsoaowner;
-	'A' DN 40 host;
-	'A' DN 40 cpu;
-	'A' DN 40 mb;
-	'A' DN 40 ip;
-	'A' DN 40 rp;
-	'D' 40 cruftlen;
-	'U' 40 arg0;
-	};
-	{
-	'D' 44 negrcode;
-	'A' DN 44 rmb;
-	'A' DN 44 ptr;
-	'A' DN 44 os;
-	'U' 44 pref;
-	'U' 44 $local;
-	'U' 44 arg1;
-	};
-	{
-	'X' 48 soa;
-	'A' Key 48 key;
-	'A' Cert 48 cert;
-	'A' Sig 48 sig;
-	'A' Null 48 null;
-	'A' Txt 48 txt;
-	};
-};
-
-defn
-RR(addr) {
-	complex RR addr;
-	print("	next	", addr.next\X, "\n");
-	print("	magic	", addr.magic, "\n");
-	print("	owner	", addr.owner\X, "\n");
-	print("	negative	", addr.negative, "\n");
-	print("	pc	", addr.pc, "\n");
-	print("	ttl	", addr.ttl, "\n");
-	print("	expire	", addr.expire, "\n");
-	print("	type	", addr.type, "\n");
-	print("	query	", addr.query, "\n");
-	print("	auth	", addr.auth, "\n");
-	print("	db	", addr.db, "\n");
-	print("	cached	", addr.cached, "\n");
-	print("	marker	", addr.marker, "\n");
-	print("_2_ {\n");
-		_2_(addr+40);
-	print("}\n");
-	print("_3_ {\n");
-		_3_(addr+44);
-	print("}\n");
-	print("_4_ {\n");
-		_4_(addr+48);
-	print("}\n");
-};
-
-sizeofServer = 8;
-aggr Server
-{
-	'A' Server 0 next;
-	'X' 4 name;
-};
-
-defn
-Server(addr) {
-	complex Server addr;
-	print("	next	", addr.next\X, "\n");
-	print("	name	", addr.name\X, "\n");
-};
-
-sizeofSOA = 24;
-aggr SOA
-{
-	'U' 0 serial;
-	'U' 4 refresh;
-	'U' 8 retry;
-	'U' 12 expire;
-	'U' 16 minttl;
-	'A' Server 20 slaves;
-};
-
-defn
-SOA(addr) {
-	complex SOA addr;
-	print("	serial	", addr.serial, "\n");
-	print("	refresh	", addr.refresh, "\n");
-	print("	retry	", addr.retry, "\n");
-	print("	expire	", addr.expire, "\n");
-	print("	minttl	", addr.minttl, "\n");
-	print("	slaves	", addr.slaves\X, "\n");
-};
-
-sizeofDNSmsg = 40;
-aggr DNSmsg
-{
-	'u' 0 id;
-	'D' 4 flags;
-	'D' 8 qdcount;
-	'A' RR 12 qd;
-	'D' 16 ancount;
-	'A' RR 20 an;
-	'D' 24 nscount;
-	'A' RR 28 ns;
-	'D' 32 arcount;
-	'A' RR 36 ar;
-};
-
-defn
-DNSmsg(addr) {
-	complex DNSmsg addr;
-	print("	id	", addr.id, "\n");
-	print("	flags	", addr.flags, "\n");
-	print("	qdcount	", addr.qdcount, "\n");
-	print("	qd	", addr.qd\X, "\n");
-	print("	ancount	", addr.ancount, "\n");
-	print("	an	", addr.an\X, "\n");
-	print("	nscount	", addr.nscount, "\n");
-	print("	ns	", addr.ns\X, "\n");
-	print("	arcount	", addr.arcount, "\n");
-	print("	ar	", addr.ar\X, "\n");
-};
-
-sizeofArea = 20;
-aggr Area
-{
-	'A' Area 0 next;
-	'D' 4 len;
-	'A' RR 8 soarr;
-	'D' 12 neednotify;
-	'D' 16 needrefresh;
-};
-
-defn
-Area(addr) {
-	complex Area addr;
-	print("	next	", addr.next\X, "\n");
-	print("	len	", addr.len, "\n");
-	print("	soarr	", addr.soarr\X, "\n");
-	print("	neednotify	", addr.neednotify, "\n");
-	print("	needrefresh	", addr.needrefresh, "\n");
-};
-
-Recurse = 0;
-Dontrecurse = 1;
-NOneg = 2;
-OKneg = 3;
-complex Area owned;
-complex Area delegated;
-sizeof_5_ = 24;
-aggr _5_
-{
-	{
-	'D' 0 val;
-	};
-	'U' 4 names;
-	'U' 8 oldest;
-	'D' 12 active;
-	'D' 16 mutex;
-	'D' 20 id;
-};
-
-defn
-_5_(addr) {
-	complex _5_ addr;
-	print("Lock {\n");
-		Lock(addr+0);
-	print("}\n");
-	print("	names	", addr.names, "\n");
-	print("	oldest	", addr.oldest, "\n");
-	print("	active	", addr.active, "\n");
-	print("	mutex	", addr.mutex, "\n");
-	print("	id	", addr.id, "\n");
-};
-
-complex _5_ dnvars;
-complex Lock dnlock;
-complex DN dnlookup:l;
-complex DN dnlookup:dp;
-complex DN dndump:dp;
-complex RR dndump:rp;
-complex DN dnpurge:dp;
-complex RR dnpurge:rp;
-complex RR dnpurge:srp;
-complex DN dnage:dp;
-complex RR dnage:l;
-complex RR dnage:rp;
-complex RR dnage:next;
-complex DN dnageall:dp;
-complex DN dnageall:l;
-complex RR dnageall:rp;
-complex DN dnagedb:dp;
-complex RR dnagedb:rp;
-complex DN dnauthdb:dp;
-complex Area dnauthdb:area;
-complex RR dnauthdb:rp;
-complex Request getactivity:req;
-complex RR rrattach1:new;
-complex RR rrattach1:l;
-complex RR rrattach1:rp;
-complex DN rrattach1:dp;
-complex RR rrattach:rp;
-complex RR rrattach:next;
-complex RR rralloc:rp;
-complex RR rrfree:rp;
-complex DN rrfree:dp;
-complex RR rrfree:nrp;
-complex Txt rrfree:t;
-complex RR rrfreelist:rp;
-complex RR rrfreelist:next;
-complex RR rrcopy:rp;
-complex RR rrcopy:last;
-complex RR rrcopy:nrp;
-complex SOA rrcopy:soa;
-complex Key rrcopy:key;
-complex Cert rrcopy:cert;
-complex Sig rrcopy:sig;
-complex Null rrcopy:null;
-complex Txt rrcopy:t;
-complex Txt rrcopy:nt;
-complex Txt rrcopy:l;
-complex DN rrlookup:dp;
-complex RR rrlookup:rp;
-complex RR rrlookup:first;
-complex RR rrlookup:last;
-complex RR rrcat:start;
-complex RR rrcat:rp;
-complex RR rrcat:last;
-complex RR rrremneg:l;
-complex RR rrremneg:nl;
-complex RR rrremneg:rp;
-complex RR rrremneg:first;
-complex RR rrremtype:l;
-complex RR rrremtype:nl;
-complex RR rrremtype:rp;
-complex RR rrremtype:first;
-complex Fmt rrfmt:f;
-complex RR rrfmt:rp;
-complex Fmt rrfmt:fstr;
-complex Server rrfmt:s;
-complex Txt rrfmt:t;
-complex Fmt rravfmt:f;
-complex RR rravfmt:rp;
-complex Fmt rravfmt:fstr;
-complex Server rravfmt:s;
-complex Txt rravfmt:t;
-complex Request slave:req;
-complex DN dncheck:dp;
-complex RR dncheck:rp;
-complex Pool mainmem;
-complex RR rrequiv:r1;
-complex RR rrequiv:r2;
-complex RR unique:rp;
-complex RR unique:l;
-complex RR unique:nrp;
-complex RR randomize:rp;
-complex RR randomize:first;
-complex RR randomize:last;
-complex RR randomize:x;
-complex RR randomize:base;
-complex Fmt sencodefmt:f;
-complex DN mkptr:dp;
-complex DN mkptr:ipdp;
-complex RR mkptr:rp;
-complex DN dnptr:dp;
-complex RR dnptr:rp;
-complex RR dnptr:nrp;
-complex RR dnptr:first;
-complex RR dnptr:l;
-complex Server freeserverlist:s;
-complex Server freeserverlist:next;
-complex Server addserver:l;
-complex Server addserver:s;
-complex Server copyserverlist:s;
-complex Server copyserverlist:ns;

File diff suppressed because it is too large
+ 293 - 143
sys/src/cmd/ndb/dn.c


+ 30 - 28
sys/src/cmd/ndb/dnarea.c

@@ -5,8 +5,7 @@
 #include <ip.h>
 #include "dns.h"
 
-Area *owned;
-Area *delegated;
+Area *owned, *delegated;
 
 /*
  *  true if a name is in our area
@@ -25,18 +24,19 @@ inmyarea(char *name)
 			if(len == s->len || name[len - s->len - 1] == '.')
 				break;
 	}
-	if(s == 0)
-		return 0;
+	if(s == nil)
+		return nil;
 
+	/* name is in area `s' */
 	for(d = delegated; d; d = d->next){
 		if(d->len > len)
 			continue;
 		if(cistrcmp(d->soarr->owner->name, name + len - d->len) == 0)
 			if(len == d->len || name[len - d->len - 1] == '.')
-				return 0;
+				return nil; /* name is in a delegated subarea */
 	}
 
-	return s;
+	return s;	/* name is in area `s' and not in a delegated subarea */
 }
 
 /*
@@ -46,13 +46,18 @@ inmyarea(char *name)
 void
 addarea(DN *dp, RR *rp, Ndbtuple *t)
 {
-	Area **l, *s;
+	Area *s;
+	Area **l;
 
 	if(t->val[0])
 		l = &delegated;
 	else
 		l = &owned;
 
+	for (s = *l; s != nil; s = s->next)
+		if (strcmp(dp->name, s->soarr->owner->name) == 0)
+			return;		/* we've already got one */
+
 	/*
 	 *  The area contains a copy of the soa rr that created it.
 	 *  The owner of the the soa rr should stick around as long
@@ -67,7 +72,8 @@ addarea(DN *dp, RR *rp, Ndbtuple *t)
 	s->neednotify = 1;
 	s->needrefresh = 0;
 
-syslog(0, logfile, "new area %s", dp->name);
+	dnslog("new area %s %s", dp->name,
+		l == &delegated? "delegated": "owned");
 
 	s->next = *l;
 	*l = s;
@@ -81,6 +87,7 @@ freearea(Area **l)
 	while(s = *l){
 		*l = s->next;
 		rrfree(s->soarr);
+		memset(s, 0, sizeof *s);	/* cause trouble */
 		free(s);
 	}
 }
@@ -105,26 +112,21 @@ refresh_areas(Area *s)
 			continue;
 		}
 
-		switch(pid = fork()){
-		case -1:
-			break;
-		case 0:
-			execl(zonerefreshprogram, "zonerefresh", s->soarr->owner->name, nil);
-			exits(0);
-			break;
-		default:
-			for(;;){
-				w = wait();
-				if(w == nil)
-					break;
-				if(w->pid == pid){
-					if(w->msg == nil || *w->msg == 0)
-						s->needrefresh = 0;
-					free(w);
-					break;
-				}
-				free(w);
-			}
+		pid = fork();
+		if (pid == -1) {
+			sleep(1000);	/* don't try it again immediately */
+			continue;
+		}
+		if (pid == 0){
+			execl(zonerefreshprogram, "zonerefresh",
+				s->soarr->owner->name, nil);
+			exits("exec zonerefresh failed");
 		}
+		while ((w = wait()) != nil && w->pid != pid)
+			free(w);
+		if (w && w->pid == pid)
+			if(w->msg == nil || *w->msg == '\0')
+				s->needrefresh = 0;
+		free(w);
 	}
 }

+ 16 - 17
sys/src/cmd/ndb/dnnotify.c

@@ -29,26 +29,24 @@ dnnotify(DNSmsg *reqp, DNSmsg *repp, Request *)
 	if(repp->qd->type != Tsoa)
 		return;
 
-syslog(0, logfile, "notification for %s", repp->qd->owner->name);
+dnslog("notification for %s", repp->qd->owner->name);
 
 	/* is it something we care about? */
 	a = inmyarea(repp->qd->owner->name);
 	if(a == nil)
 		return;
 
-syslog(0, logfile, "serial old %lud new %lud", a->soarr->soa->serial, repp->qd->soa->serial);
+dnslog("serial old %lud new %lud", a->soarr->soa->serial, repp->qd->soa->serial);
 
 	/* do nothing if it didn't change */
-	if(a->soarr->soa->serial== repp->qd->soa->serial)
-		return;
-
-	a->needrefresh = 1;
+	if(a->soarr->soa->serial != repp->qd->soa->serial)
+		a->needrefresh = 1;
 }
 
 static void
 ding(void*, char *msg)
 {
-	if(strstr(msg, "alarm"))
+	if(strstr(msg, "alarm") != nil)
 		noted(NCONT);
 	else
 		noted(NDFLT);
@@ -59,11 +57,10 @@ static void
 send_notify(char *slave, RR *soa, Request *req)
 {
 	int i, len, n, reqno, status, fd;
-	uchar obuf[Maxudp+OUdphdrsize];
-	uchar ibuf[Maxudp+OUdphdrsize];
+	char *err;
+	uchar ibuf[Maxudp+OUdphdrsize], obuf[Maxudp+OUdphdrsize];
 	RR *rp;
 	OUdphdr *up = (OUdphdr*)obuf;
-	char *err;
 	DNSmsg repmsg;
 
 	/* create the request */
@@ -71,9 +68,9 @@ send_notify(char *slave, RR *soa, Request *req)
 	n = mkreq(soa->owner, Cin, obuf, Fauth | Onotify, reqno);
 
 	/* get an address */
-	if(strcmp(ipattr(slave), "ip") == 0) {
+	if(strcmp(ipattr(slave), "ip") == 0)
 		parseip(up->raddr, slave);
-	} else {
+	else {
 		rp = dnresolve(slave, Cin, Ta, req, nil, 0, 1, 1, &status);
 		if(rp == nil)
 			return;
@@ -81,7 +78,7 @@ send_notify(char *slave, RR *soa, Request *req)
 		rrfree(rp);
 	}
 
-	fd = udpport();
+	fd = udpport(nil);
 	if(fd < 0)
 		return;
 
@@ -90,7 +87,7 @@ send_notify(char *slave, RR *soa, Request *req)
 	/* send 3 times or until we get anything back */
 	n += OUdphdrsize;
 	for(i = 0; i < 3; i++){
-syslog(0, logfile, "sending %d byte notify to %s/%I.%d about %s", n, slave, up->raddr, nhgets(up->rport), soa->owner->name);
+dnslog("sending %d byte notify to %s/%I.%d about %s", n, slave, up->raddr, nhgets(up->rport), soa->owner->name);
 		if(write(fd, obuf, n) != n)
 			break;
 		alarm(2*1000);
@@ -98,13 +95,13 @@ syslog(0, logfile, "sending %d byte notify to %s/%I.%d about %s", n, slave, up->
 		alarm(0);
 		if(len <= OUdphdrsize)
 			continue;
-		err = convM2DNS(&ibuf[OUdphdrsize], len, &repmsg);
+		memset(&repmsg, 0, sizeof repmsg);
+		err = convM2DNS(&ibuf[OUdphdrsize], len, &repmsg, nil);
 		if(err != nil)
 			continue;
 		if(repmsg.id == reqno && (repmsg.flags & Omask) == Onotify)
 			break;
 	}
-
 	close(fd);
 }
 
@@ -147,7 +144,9 @@ notifyproc(void)
 		return;
 	}
 
-	req.isslave = 1;	/* son't fork off subprocesses */
+	procsetname("notify slaves");
+	memset(&req, 0, sizeof req);
+	req.isslave = 1;	/* don't fork off subprocesses */
 
 	for(;;){
 		getactivity(&req, 0);

+ 529 - 116
sys/src/cmd/ndb/dnresolve.c

@@ -1,7 +1,9 @@
 #include <u.h>
 #include <libc.h>
+#include <ip.h>
+#include <bio.h>
+#include <ndb.h>
 #include "dns.h"
-#include "ip.h"
 
 enum
 {
@@ -12,23 +14,50 @@ enum
 static int	netquery(DN*, int, RR*, Request*, int);
 static RR*	dnresolve1(char*, int, int, Request*, int, int);
 
-char *LOG = "dns";
+/*
+ * reading /proc/pid/args yields either "name" or "name [display args]",
+ * so return only display args, if any.
+ */
+static char *
+procgetname(void)
+{
+	int fd, n;
+	char *lp, *rp;
+	char buf[256];
+
+	snprint(buf, sizeof buf, "#p/%d/args", getpid());
+	if((fd = open(buf, OREAD)) < 0)
+		return strdup("");
+	*buf = '\0';
+	n = read(fd, buf, sizeof buf-1);
+	close(fd);
+	if (n >= 0)
+		buf[n] = '\0';
+	if ((lp = strchr(buf, '[')) == nil ||
+	    (rp = strrchr(buf, ']')) == nil)
+		return strdup("");
+	*rp = '\0';
+	return strdup(lp+1);
+}
 
 /*
  *  lookup 'type' info for domain name 'name'.  If it doesn't exist, try
  *  looking it up as a canonical name.
  */
 RR*
-dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, int recurse, int rooted, int *status)
+dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth,
+	int recurse, int rooted, int *status)
 {
 	RR *rp, *nrp, *drp;
 	DN *dp;
 	int loops;
+	char *procname;
 	char nname[Domlen];
 
 	if(status)
 		*status = 0;
 
+	procname = procgetname();
 	/*
 	 *  hack for systems that don't have resolve search
 	 *  lists.  Just look up the simple name in the database.
@@ -37,14 +66,18 @@ dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, int
 		rp = nil;
 		drp = domainlist(class);
 		for(nrp = drp; nrp != nil; nrp = nrp->next){
-			snprint(nname, sizeof(nname), "%s.%s", name, nrp->ptr->name);
-			rp = dnresolve(nname, class, type, req,cn, depth, recurse, rooted, status);
+			snprint(nname, sizeof nname, "%s.%s", name,
+				nrp->ptr->name);
+			rp = dnresolve(nname, class, type, req, cn, depth,
+				recurse, rooted, status);
 			rrfreelist(rrremneg(&rp));
 			if(rp != nil)
 				break;
 		}
 		if(drp != nil)
 			rrfree(drp);
+		procsetname(procname);
+		free(procname);
 		return rp;
 	}
 
@@ -52,13 +85,16 @@ dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, int
 	 *  try the name directly
 	 */
 	rp = dnresolve1(name, class, type, req, depth, recurse);
-	if(rp)
+	if(rp) {
+		procsetname(procname);
+		free(procname);
 		return randomize(rp);
+	}
 
 	/* try it as a canonical name if we weren't told the name didn't exist */
 	dp = dnlookup(name, class, 0);
-	if(type != Tptr && dp->nonexistent != Rname){
-		for(loops=0; rp == nil && loops < 32; loops++){
+	if(type != Tptr && dp->respcode != Rname)
+		for(loops = 0; rp == nil && loops < 32; loops++){
 			rp = dnresolve1(name, class, Tcname, req, depth, recurse);
 			if(rp == nil)
 				break;
@@ -68,37 +104,39 @@ dnresolve(char *name, int class, int type, Request *req, RR **cn, int depth, int
 				rp = nil;
 				break;
 			}
-	
+
 			name = rp->host->name;
 			if(cn)
 				rrcat(cn, rp);
 			else
 				rrfreelist(rp);
-	
+
 			rp = dnresolve1(name, class, type, req, depth, recurse);
 		}
-	}
 
 	/* distinction between not found and not good */
-	if(rp == 0 && status != 0 && dp->nonexistent != 0)
-		*status = dp->nonexistent;
+	if(rp == nil && status != nil && dp->respcode != 0)
+		*status = dp->respcode;
 
+	procsetname(procname);
+	free(procname);
 	return randomize(rp);
 }
 
 static RR*
-dnresolve1(char *name, int class, int type, Request *req, int depth, int recurse)
+dnresolve1(char *name, int class, int type, Request *req, int depth,
+	int recurse)
 {
 	DN *dp, *nsdp;
 	RR *rp, *nsrp, *dbnsrp;
 	char *cp;
 
 	if(debug)
-		syslog(0, LOG, "[%d] dnresolve1 %s %d %d", getpid(), name, type, class);
+		dnslog("[%d] dnresolve1 %s %d %d", getpid(), name, type, class);
 
 	/* only class Cin implemented so far */
 	if(class != Cin)
-		return 0;
+		return nil;
 
 	dp = dnlookup(name, class, 1);
 
@@ -106,24 +144,22 @@ dnresolve1(char *name, int class, int type, Request *req, int depth, int recurse
 	 *  Try the cache first
 	 */
 	rp = rrlookup(dp, type, OKneg);
-	if(rp){
+	if(rp)
 		if(rp->db){
-			/* unauthenticated db entries are hints */
+			/* unauthoritative db entries are hints */
 			if(rp->auth)
 				return rp;
-		} else {
+		} else
 			/* cached entry must still be valid */
-			if(rp->ttl > now){
+			if(rp->ttl > now)
 				/* but Tall entries are special */
 				if(type != Tall || rp->query == Tall)
 					return rp;
-			}
-		}
-	}
+
 	rrfreelist(rp);
 
 	/*
-	 * try the cache for a canonical name. if found punt 
+	 * try the cache for a canonical name. if found punt
 	 * since we'll find it during the canonical name search
 	 * in dnresolve().
 	 */
@@ -131,14 +167,14 @@ dnresolve1(char *name, int class, int type, Request *req, int depth, int recurse
 		rp = rrlookup(dp, Tcname, NOneg);
 		rrfreelist(rp);
 		if(rp)
-			return 0;
+			return nil;
 	}
 
 	/*
-	 *  if we're running as just a resolver, go to our
+	 *  if we're running as just a resolver, query our
 	 *  designated name servers
 	 */
-	if(resolver){
+	if(cfg.resolver){
 		nsrp = randomize(getdnsservers(class));
 		if(nsrp != nil) {
 			if(netquery(dp, type, nsrp, req, depth+1)){
@@ -161,6 +197,7 @@ dnresolve1(char *name, int class, int type, Request *req, int depth, int recurse
 		dbnsrp = randomize(dblookup(cp, class, Tns, 0, 0));
 		if(dbnsrp && dbnsrp->local){
 			rp = dblookup(name, class, type, 1, dbnsrp->ttl);
+//			dnslog("dnresolve1: local domain %s -> %#p", name, rp);
 			rrfreelist(dbnsrp);
 			return rp;
 		}
@@ -190,7 +227,8 @@ dnresolve1(char *name, int class, int type, Request *req, int depth, int recurse
 		if(nsrp){
 			rrfreelist(dbnsrp);
 
-			/* try the name servers found in cache */
+			/* query the name servers found in cache */
+//			dnslog("dnresolve1: %s: trying ns in cache", dp->name);
 			if(netquery(dp, type, nsrp, req, depth+1)){
 				rrfreelist(nsrp);
 				return rrlookup(dp, type, OKneg);
@@ -202,6 +240,7 @@ dnresolve1(char *name, int class, int type, Request *req, int depth, int recurse
 		/* use ns from db */
 		if(dbnsrp){
 			/* try the name servers found in db */
+//			dnslog("dnresolve1: %s: trying ns in db", dp->name);
 			if(netquery(dp, type, dbnsrp, req, depth+1)){
 				/* we got an answer */
 				rrfreelist(dbnsrp);
@@ -221,7 +260,8 @@ dnresolve1(char *name, int class, int type, Request *req, int depth, int recurse
 }
 
 /*
- *  walk a domain name one element to the right.  return a pointer to that element.
+ *  walk a domain name one element to the right.
+ *  return a pointer to that element.
  *  in other words, return a pointer to the parent domain name.
  */
 char*
@@ -246,14 +286,13 @@ static char *hmsg = "headers";
 static char *ohmsg = "oldheaders";
 
 int
-udpport(void)
+udpport(char *mtpt)
 {
 	int fd, ctl;
-	char ds[64];
-	char adir[64];
+	char ds[64], adir[64];
 
 	/* get a udp port */
-	snprint(ds, sizeof(ds), "%s/udp!*!0", mntpt);
+	snprint(ds, sizeof ds, "%s/udp!*!0", (mtpt? mtpt: "/net"));
 	ctl = announce(ds, adir);
 	if(ctl < 0){
 		/* warning("can't get udp port"); */
@@ -269,14 +308,11 @@ udpport(void)
 	write(ctl, ohmsg, strlen(ohmsg));
 
 	/* grab the data file */
-	snprint(ds, sizeof(ds), "%s/data", adir);
+	snprint(ds, sizeof ds, "%s/data", adir);
 	fd = open(ds, ORDWR);
 	close(ctl);
-	if(fd < 0){
-		warning("can't open udp port: %r");
-		return -1;
-	}
-
+	if(fd < 0)
+		warning("can't open udp port %s: %r", ds);
 	return fd;
 }
 
@@ -300,7 +336,7 @@ mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno)
 	m.qd->type = type;
 	len = convDNS2M(&m, &buf[OUdphdrsize], Maxudp);
 	if(len < 0)
-		abort(); /* "can't convert" */;
+		abort();	/* "can't convert" */
 	rrfree(m.qd);
 	return len;
 }
@@ -323,14 +359,16 @@ freeanswers(DNSmsg *mp)
 	rrfreelist(mp->an);
 	rrfreelist(mp->ns);
 	rrfreelist(mp->ar);
+	mp->qd = mp->an = mp->ns = mp->ar = nil;
 }
 
 /*
- *  read replies to a request.  ignore any of the wrong type.  wait at most 5 seconds.
+ *  read replies to a request.  ignore any of the wrong type.
+ *  wait at most until endtime.
  */
 static int
-readreply(int fd, DN *dp, int type, ushort req,
-	  uchar *ibuf, DNSmsg *mp, ulong endtime, Request *reqp)
+readreply(int fd, DN *dp, int type, ushort req, uchar *ibuf, DNSmsg *mp,
+	ulong endtime, Request *reqp)
 {
 	char *err;
 	int len;
@@ -340,7 +378,7 @@ readreply(int fd, DN *dp, int type, ushort req,
 	notify(ding);
 
 	for(; ; freeanswers(mp)){
-		now = time(0);
+		now = time(nil);
 		if(now >= endtime)
 			return -1;	/* timed out */
 
@@ -351,12 +389,12 @@ readreply(int fd, DN *dp, int type, ushort req,
 		len -= OUdphdrsize;
 		if(len < 0)
 			return -1;	/* timed out */
-		
+
 		/* convert into internal format  */
 		memset(mp, 0, sizeof(*mp));
-		err = convM2DNS(&ibuf[OUdphdrsize], len, mp);
+		err = convM2DNS(&ibuf[OUdphdrsize], len, mp, nil);
 		if(err){
-			syslog(0, LOG, "input err %s: %I", err, ibuf);
+			dnslog("input err: %s: %I", err, ibuf);
 			continue;
 		}
 		if(debug)
@@ -364,22 +402,22 @@ readreply(int fd, DN *dp, int type, ushort req,
 
 		/* answering the right question? */
 		if(mp->id != req){
-			syslog(0, LOG, "%d: id %d instead of %d: %I", reqp->id,
+			dnslog("%d: id %d instead of %d: %I", reqp->id,
 					mp->id, req, ibuf);
 			continue;
 		}
 		if(mp->qd == 0){
-			syslog(0, LOG, "%d: no question RR: %I", reqp->id, ibuf);
+			dnslog("%d: no question RR: %I", reqp->id, ibuf);
 			continue;
 		}
 		if(mp->qd->owner != dp){
-			syslog(0, LOG, "%d: owner %s instead of %s: %I", reqp->id,
-				mp->qd->owner->name, dp->name, ibuf);
+			dnslog("%d: owner %s instead of %s: %I",
+				reqp->id, mp->qd->owner->name, dp->name, ibuf);
 			continue;
 		}
 		if(mp->qd->type != type){
-			syslog(0, LOG, "%d: type %d instead of %d: %I", reqp->id,
-				mp->qd->type, type, ibuf);
+			dnslog("%d: type %d instead of %d: %I",
+				reqp->id, mp->qd->type, type, ibuf);
 			continue;
 		}
 
@@ -406,10 +444,9 @@ contains(RR *rp1, RR *rp2)
 			if(trp1->owner == trp2->owner)
 				break;
 		}
-		if(trp1 == 0)
+		if(trp1 == nil)
 			return 0;
 	}
-
 	return 1;
 }
 
@@ -420,7 +457,7 @@ struct Dest
 	uchar	a[IPaddrlen];	/* ip address */
 	DN	*s;		/* name server */
 	int	nx;		/* number of transmissions */
-	int	code;
+	int	code;		/* response code; used to clear dp->respcode */
 };
 
 
@@ -431,14 +468,12 @@ int
 ipisbm(uchar *ip)
 {
 	if(isv4(ip)){
-		if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
+		if (ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0 ||
+		    ipcmp(ip, IPv4bcast) == 0)
 			return 4;
-		if(ipcmp(ip, IPv4bcast) == 0)
-			return 4;
-	} else {
+	} else
 		if(ip[0] == 0xff)
 			return 6;
-	}
 	return 0;
 }
 
@@ -446,7 +481,7 @@ ipisbm(uchar *ip)
  *  Get next server address
  */
 static int
-serveraddrs(RR *nsrp, Dest *dest, int nd, int depth, Request *reqp)
+serveraddrs(DN *dp, RR *nsrp, Dest *dest, int nd, int depth, Request *reqp)
 {
 	RR *rp, *arp, *trp;
 	Dest *cur;
@@ -481,7 +516,7 @@ serveraddrs(RR *nsrp, Dest *dest, int nd, int depth, Request *reqp)
 	 *  server addresses, try resolving one via the network.
 	 *  Mark any we try to resolve so we don't try a second time.
 	 */
-	if(arp == 0){
+	if(arp == 0)
 		for(rp = nsrp; rp; rp = rp->next){
 			if(rp->marker)
 				continue;
@@ -493,12 +528,12 @@ serveraddrs(RR *nsrp, Dest *dest, int nd, int depth, Request *reqp)
 			if(subsume(rp->owner->name, rp->host->name))
 				continue;
 
-			arp = dnresolve(rp->host->name, Cin, Ta, reqp, 0, depth+1, Recurse, 1, 0);
+			arp = dnresolve(rp->host->name, Cin, Ta, reqp, 0,
+				depth+1, Recurse, 1, 0);
 			rrfreelist(rrremneg(&arp));
 			if(arp)
 				break;
 		}
-	}
 
 	/* use any addresses that we found */
 	for(trp = arp; trp; trp = trp->next){
@@ -506,7 +541,13 @@ serveraddrs(RR *nsrp, Dest *dest, int nd, int depth, Request *reqp)
 			break;
 		cur = &dest[nd];
 		parseip(cur->a, trp->ip->name);
-		if(ipisbm(cur->a))
+		/*
+		 * straddling servers can reject all nameservers if they are all
+		 * inside, so be sure to list at least one outside ns at
+		 * the end of the ns list in /lib/ndb for `dom='.
+		 */
+		if (ipisbm(cur->a) ||
+		    cfg.straddle && !insideaddr(dp->name) && insidens(cur->a))
 			continue;
 		cur->nx = 0;
 		cur->s = trp->owner;
@@ -527,14 +568,14 @@ cacheneg(DN *dp, int type, int rcode, RR *soarr)
 	DN *soaowner;
 	ulong ttl;
 
-	/* no cache time specified, don' make anything up */
+	/* no cache time specified, don't make anything up */
 	if(soarr != nil){
 		if(soarr->next != nil){
 			rrfreelist(soarr->next);
 			soarr->next = nil;
 		}
 		soaowner = soarr->owner;
-	} else 
+	} else
 		soaowner = nil;
 
 	/* the attach can cause soarr to be freed so mine it now */
@@ -555,21 +596,44 @@ cacheneg(DN *dp, int type, int rcode, RR *soarr)
 	rrattach(rp, 1);
 }
 
+static int
+setdestoutns(Dest *p, int n)
+{
+	uchar *outns = outsidens(n);
+
+	memset(p, 0, sizeof *p);
+	if (outns == nil) {
+		if (n == 0)
+			dnslog("[%d] no outside-ns in ndb", getpid());
+		return -1;
+	}
+	memmove(p->a, outns, sizeof p->a);
+	p->s = dnlookup("outside-ns-ips", Cin, 1);
+	return 0;
+}
+
 /*
  *  query name servers.  If the name server returns a pointer to another
  *  name server, recurse.
  */
 static int
-netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, uchar *ibuf, uchar *obuf)
+netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth,
+	uchar *ibuf, uchar *obuf, int waitsecs, int inns)
 {
-	int ndest, j, len, replywaits, rv;
+	int ndest, j, len, replywaits, rv, n;
 	ushort req;
-	RR *tp, *soarr;
-	Dest *p, *l, *np;
+	ulong endtime;
+	char buf[12];
 	DN *ndp;
-	Dest dest[Maxdest];
 	DNSmsg m;
-	ulong endtime;
+	Dest *p, *l, *np;
+	Dest dest[Maxdest];
+	RR *tp, *soarr;
+//	char fdbuf[1024];
+
+//	fd2path(fd, fdbuf, sizeof fdbuf);
+//	dnslog("netquery: on %s for %s %s ns", fdbuf, dp->name,
+//		(inns? "inside": "outside"));
 
 	/* pack request into a message */
 	req = rand();
@@ -584,21 +648,29 @@ netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, uchar *i
 	 *  each cycle send one more message than the previous.
 	 */
 	for(ndest = 1; ndest < Maxdest; ndest++){
-		p = dest;
-
-		endtime = time(0);
-		if(endtime >= reqp->aborttime)
+//		dnslog("netquery1 xmit loop: now %ld aborttime %ld", time(nil),
+//			reqp->aborttime);
+		if(time(nil) >= reqp->aborttime)
 			break;
 
 		/* get a server address if we need one */
+		p = dest;
 		if(ndest > l - p){
-			j = serveraddrs(nsrp, dest, l - p, depth, reqp);
+			j = serveraddrs(dp, nsrp, dest, l - p, depth, reqp);
 			l = &dest[j];
 		}
 
 		/* no servers, punt */
 		if(l == dest)
-			break;
+			if (cfg.straddle && cfg.inside) {
+				p = l = dest;
+				for(n = 0; n < Maxdest; n++, l++)
+					if (setdestoutns(l, n) < 0)
+						break;
+			} else {
+//				dnslog("netquery1: %s: no servers", dp->name);
+				break;
+			}
 
 		/* send to first 'ndest' destinations */
 		j = 0;
@@ -613,10 +685,15 @@ netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, uchar *i
 			if((1<<p->nx) > ndest)
 				continue;
 
-			memmove(obuf, p->a, sizeof(p->a));
+			memmove(obuf, p->a, sizeof p->a);
+			procsetname("req slave: %sside query to %I/%s %s %s",
+				(inns? "in": "out"), obuf, p->s->name, dp->name,
+				rrname(type, buf, sizeof buf));
 			if(debug)
 				logsend(reqp->id, depth, obuf, p->s->name,
 					dp->name, type);
+
+			/* actually send the UDP packet */
 			if(write(fd, obuf, len + OUdphdrsize) < 0)
 				warning("sending udp msg %r");
 			p->nx++;
@@ -624,18 +701,27 @@ netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, uchar *i
 		if(j == 0)
 			break;		/* no destinations left */
 
-		/* wait up to 5 seconds for replies */
-		endtime = time(0) + 5;
+		endtime = time(nil) + waitsecs;
 		if(endtime > reqp->aborttime)
 			endtime = reqp->aborttime;
 
+//		dnslog(
+//		    "netquery1 reply wait: now %ld aborttime %ld endtime %ld",
+//			time(nil), reqp->aborttime, endtime);
 		for(replywaits = 0; replywaits < ndest; replywaits++){
-			if(readreply(fd, dp, type, req, ibuf, &m, endtime, reqp) < 0)
+			procsetname(
+			    "req slave: reading %sside reply from %I for %s %s",
+				(inns? "in": "out"), obuf, dp->name,
+				rrname(type, buf, sizeof buf));
+			memset(&m, 0, sizeof m);
+			if(readreply(fd, dp, type, req, ibuf, &m, endtime, reqp)
+			    < 0)
 				break;		/* timed out */
 
+//			dnslog("netquery1 got reply from %I", ibuf);
 			/* find responder */
 			for(p = dest; p < l; p++)
-				if(memcmp(p->a, ibuf, sizeof(p->a)) == 0)
+				if(memcmp(p->a, ibuf, sizeof p->a) == 0)
 					break;
 
 			/* remove all addrs of responding server from list */
@@ -645,42 +731,54 @@ netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, uchar *i
 
 			/* ignore any error replies */
 			if((m.flags & Rmask) == Rserver){
+//				dnslog(
+//				 "netquery1 got Rserver for dest %s of name %s",
+//					p->s->name, dp->name);
 				rrfreelist(m.qd);
 				rrfreelist(m.an);
 				rrfreelist(m.ar);
 				rrfreelist(m.ns);
-				if(p != l)
+				if(p != l) {
+//					dnslog(
+//	"netquery1 setting Rserver for dest %s of name %s due to Rserver reply",
+//						p->s->name, dp->name);
 					p->code = Rserver;
+				}
 				continue;
 			}
 
 			/* ignore any bad delegations */
 			if(m.ns && baddelegation(m.ns, nsrp, ibuf)){
+//				dnslog("netquery1 got a bad delegation from %s",
+//					p->s->name);
 				rrfreelist(m.ns);
 				m.ns = nil;
 				if(m.an == nil){
 					rrfreelist(m.qd);
 					rrfreelist(m.ar);
-					if(p != l)
+					if(p != l) {
+//						dnslog(
+//"netquery1 setting Rserver for dest %s of name %s due to bad delegation",
+//							p->s->name, dp->name);
 						p->code = Rserver;
+					}
 					continue;
 				}
 			}
 
-
 			/* remove any soa's from the authority section */
 			soarr = rrremtype(&m.ns, Tsoa);
 
 			/* incorporate answers */
 			if(m.an)
-				rrattach(m.an, (m.flags & Fauth) ? 1 : 0);
+				rrattach(m.an, (m.flags & Fauth) != 0);
 			if(m.ar)
 				rrattach(m.ar, 0);
 			if(m.ns){
 				ndp = m.ns->owner;
 				rrattach(m.ns, 0);
 			} else
-				ndp = 0;
+				ndp = nil;
 
 			/* free the question */
 			if(m.qd)
@@ -692,15 +790,16 @@ netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, uchar *i
 			 */
 			if(m.an != nil || (m.flags & Fauth)){
 				if(m.an == nil && (m.flags & Rmask) == Rname)
-					dp->nonexistent = Rname;
+					dp->respcode = Rname;
 				else
-					dp->nonexistent = 0;
+					dp->respcode = 0;
 
 				/*
 				 *  cache any negative responses, free soarr
 				 */
 				if((m.flags & Fauth) && m.an == nil)
-					cacheneg(dp, type, (m.flags & Rmask), soarr);
+					cacheneg(dp, type, (m.flags & Rmask),
+						soarr);
 				else
 					rrfreelist(soarr);
 				return 1;
@@ -708,13 +807,24 @@ netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, uchar *i
 			rrfreelist(soarr);
 
 			/*
-			 *  if we've been given better name servers
-			 *  recurse
+			 *  if we've been given better name servers,
+			 *  recurse.  we're called from udpquery, called from
+			 *  netquery, which current holds dp->querylck,
+			 *  so release it now and acquire it upon return.
 			 */
 			if(m.ns){
 				tp = rrlookup(ndp, Tns, NOneg);
 				if(!contains(nsrp, tp)){
-					rv = netquery(dp, type, tp, reqp, depth+1);
+					procsetname(
+					 "req slave: recursive query for %s %s",
+						dp->name,
+						rrname(type, buf, sizeof buf));
+					qunlock(&dp->querylck);
+
+					rv = netquery(dp, type, tp, reqp,
+						depth+1);
+
+					qlock(&dp->querylck);
 					rrfreelist(tp);
 					return rv;
 				} else
@@ -723,44 +833,347 @@ netquery1(int fd, DN *dp, int type, RR *nsrp, Request *reqp, int depth, uchar *i
 		}
 	}
 
-	/* if all servers returned failure, propogate it */
-	dp->nonexistent = Rserver;
+	/* if all servers returned failure, propagate it */
+	dp->respcode = Rserver;
 	for(p = dest; p < l; p++)
 		if(p->code != Rserver)
-			dp->nonexistent = 0;
+			dp->respcode = 0;
+
+//	if (dp->respcode)
+//		dnslog("netquery1 setting Rserver for %s", dp->name);
 
 	return 0;
 }
 
-static int
-netquery(DN *dp, int type, RR *nsrp, Request *reqp, int depth)
+/*
+ *  run a command with a supplied fd as standard input
+ */
+char *
+system(int fd, char *cmd)
 {
-	uchar *obuf;
-	uchar *ibuf;
-	RR *rp;
-	int fd, rv;
+	int pid, p, i;
+	static Waitmsg msg;
+
+	if((pid = fork()) == -1)
+		sysfatal("fork failed: %r");
+	else if(pid == 0){
+		dup(fd, 0);
+		close(fd);
+		for (i = 3; i < 200; i++)
+			close(i);		/* don't leak fds */
+		execl("/bin/rc", "rc", "-c", cmd, nil);
+		sysfatal("exec rc: %r");
+	}
+	for(p = waitpid(); p >= 0; p = waitpid())
+		if(p == pid)
+			return msg.msg;
+	return "lost child";
+}
 
-	if(depth > 12)
-		return 0;
+enum { Hurry, Patient, };
+enum { Outns, Inns, };
+enum { Remntretry = 15, };	/* min. sec.s between remount attempts */
+
+static int
+udpquery(char *mntpt, DN *dp, int type, RR *nsrp, Request *reqp, int depth,
+	int patient, int inns)
+{
+	int fd, rv = 0;
+	long now;
+	char *msg;
+	uchar *obuf, *ibuf;
+	static QLock mntlck;
+	static ulong lastmount;
 
 	/* use alloced buffers rather than ones from the stack */
 	ibuf = emalloc(Maxudpin+OUdphdrsize);
 	obuf = emalloc(Maxudp+OUdphdrsize);
 
-	slave(reqp);
+	fd = udpport(mntpt);
+	while (fd < 0 && cfg.straddle && strcmp(mntpt, "/net.alt") == 0) {
+		/* HACK: remount /net.alt */
+		now = time(nil);
+		if (now < lastmount + Remntretry)
+			sleep((lastmount + Remntretry - now)*1000);
+		qlock(&mntlck);
+		fd = udpport(mntpt);	/* try again under lock */
+		if (fd < 0) {
+			dnslog("[%d] remounting /net.alt", getpid());
+			unmount(nil, "/net.alt");
+
+			msg = system(open("/dev/null", ORDWR), "outside");
+
+			lastmount = time(nil);
+			if (msg && *msg) {
+				dnslog("[%d] can't remount /net.alt: %s",
+					getpid(), msg);
+				sleep(10*1000);		/* don't spin wildly */
+			} else
+				fd = udpport(mntpt);
+		}
+		qunlock(&mntlck);
+	}
+	if(fd >= 0) {
+		reqp->aborttime = time(nil) + (patient? Maxreqtm: Maxreqtm/2);
+//		dnslog("udpquery: %s/udp for %s with %s ns", mntpt, dp->name,
+//			(inns? "inside": "outside"));
+		rv = netquery1(fd, dp, type, nsrp, reqp, depth,
+			ibuf, obuf, (patient? 15: 10), inns);
+		close(fd);
+	} else
+		dnslog("can't get udpport for %s query of name %s: %r",
+			mntpt, dp->name);
+
+	free(obuf);
+	free(ibuf);
+	return rv;
+}
+
+static int
+dnssetup(int domount, char *dns, char *srv, char *mtpt)
+{
+	int fd;
+
+	fd = open(dns, ORDWR);
+	if(fd < 0){
+		if(domount == 0){
+			werrstr("can't open %s: %r", mtpt);
+			return -1;
+		}
+		fd = open(srv, ORDWR);
+		if(fd < 0){
+			werrstr("can't open %s: %r", srv);
+			return -1;
+		}
+		if(mount(fd, -1, mtpt, MBEFORE, "") < 0){
+			werrstr("can't mount(%s, %s): %r", srv, mtpt);
+			return -1;
+		}
+		fd = open(mtpt, ORDWR);
+		if(fd < 0)
+			werrstr("can't open %s: %r", mtpt);
+	}
+	return fd;
+}
+
+static RR *
+rrparse(char *lines)
+{
+	int nl, nf, ln, type;
+	char *line[100];
+	char *field[32];
+	RR *rp, *rplist;
+//	Server *s;
+	SOA *soa;
+	Srv *srv;
+//	Txt *t;
+
+	rplist = nil;
+	nl = tokenize(lines, line, nelem(line));
+	for (ln = 0; ln < nl; ln++) {
+		if (*line[ln] == '!' || *line[ln] == '?')
+			continue;		/* error */
+		nf = tokenize(line[ln], field, nelem(field));
+		if (nf < 2)
+			continue;		/* mal-formed */
+		type = rrtype(field[1]);
+		rp = rralloc(type);
+		rp->owner = dnlookup(field[0], Cin, 1);
+		rp->next = rplist;
+		rplist = rp;
+		switch (type) {		/* TODO: copy fields to *rp */
+		case Thinfo:
+			// "\t%s %s", dnname(rp->cpu), dnname(rp->os));
+			break;
+		case Tcname:
+		case Tmb:
+		case Tmd:
+		case Tmf:
+		case Tns:
+			// "\t%s", dnname(rp->host));
+			break;
+		case Tmg:
+		case Tmr:
+			// "\t%s", dnname(rp->mb));
+			break;
+		case Tminfo:
+			// "\t%s %s", dnname(rp->mb), dnname(rp->rmb));
+			break;
+		case Tmx:
+			// "\t%lud %s", rp->pref, dnname(rp->host));
+			break;
+		case Ta:
+		case Taaaa:
+			// "\t%s", dnname(rp->ip));	// TODO parseip
+			break;
+		case Tptr:
+			// "\t%s", dnname(rp->ptr));
+			break;
+		case Tsoa:
+			soa = rp->soa;
+			USED(soa);
+			// "\t%s %s %lud %lud %lud %lud %lud",
+			//	dnname(rp->host), dnname(rp->rmb),
+			//	(soa? soa->serial: 0),
+			//	(soa? soa->refresh: 0), (soa? soa->retry: 0),
+			//	(soa? soa->expire: 0), (soa? soa->minttl: 0));
+			break;
+		case Tsrv:
+			srv = rp->srv;
+			USED(srv);
+			break;
+		case Tnull:
+			// "\t%.*H", rp->null->dlen, rp->null->data);
+			break;
+		case Ttxt:
+			// for(t = rp->txt; t != nil; t = t->next)
+			//	"%s", t->p);
+			break;
+		case Trp:
+			// "\t%s %s", dnname(rp->rmb), dnname(rp->rp));
+			break;
+		case Tkey:
+			// "\t%d %d %d", rp->key->flags, rp->key->proto, rp->key->alg);
+			break;
+		case Tsig:
+			// "\t%d %d %d %lud %lud %lud %d %s",
+			//	rp->sig->type, rp->sig->alg, rp->sig->labels,
+			//	rp->sig->ttl, rp->sig->exp, rp->sig->incep,
+			//	rp->sig->tag, dnname(rp->sig->signer));
+			break;
+		case Tcert:
+			// "\t%d %d %d", rp->cert->type, rp->cert->tag, rp->cert->alg);
+			break;
+		}
+	}
+	return nil;
+}
+
+static int
+querydns(int fd, char *line, int n)
+{
+	int rv = 0;
+	char buf[1024];
+
+	seek(fd, 0, 0);
+	if(write(fd, line, n) != n)
+		return rv;
+
+	seek(fd, 0, 0);
+	buf[0] = '\0';
+	while((n = read(fd, buf, sizeof buf - 1)) > 0) {
+		buf[n] = 0;
+		rrattach(rrparse(buf), 1);	/* incorporate answers */
+		rv = 1;
+		buf[0] = '\0';
+	}
+	return rv;
+}
+
+static void
+askoutdns(DN *dp, int type)		/* ask /net.alt/dns directly */
+{
+	int len;
+	char buf[32];
+	char *query;
+	char *mtpt = "/net.alt";
+	char *dns =  "/net.alt/dns";
+	char *srv =  "/srv/dns_net.alt";
+	static int fd = -1;
+
+	if (fd < 0)
+		fd = dnssetup(1, dns, srv, mtpt);
+
+	query = smprint("%s %s\n", dp->name, rrname(type, buf, sizeof buf));
+	len = strlen(query);
+	if (!querydns(fd, query, len)) {
+		close(fd);
+		/* could run outside here */
+		fd = dnssetup(1, dns, srv, mtpt);
+		querydns(fd, query, len);
+	}
+	free(query);
+}
+
+/* look up (dp->name,type) via *nsrp with results in *reqp */
+static int
+netquery(DN *dp, int type, RR *nsrp, Request *reqp, int depth)
+{
+	int lock, rv, triedin, inname;
+	RR *rp;
+
+	if(depth > 12)			/* in a recursive loop? */
+		return 0;
+
+	slave(reqp);			/* might fork */
+	/* if so, parent process longjmped to req->mret; we're child slave */
+	if (!reqp->isslave)
+		dnslog("[%d] netquery: slave returned with reqp->isslave==0",
+			getpid());
+
+	/* don't lock before call to slave so only children can block */
+	lock = reqp->isslave != 0;
+	if(lock) {
+		procsetname("waiting for query lock on %s", dp->name);
+		/* don't make concurrent queries for this name */
+		qlock(&dp->querylck);
+		procsetname("netquery: %s", dp->name);
+	}
 
 	/* prepare server RR's for incremental lookup */
 	for(rp = nsrp; rp; rp = rp->next)
 		rp->marker = 0;
 
-	fd = udpport();
-	if(fd < 0)
-		rv = 0;
-	else
-		rv = netquery1(fd, dp, type, nsrp, reqp, depth, ibuf, obuf);
-	close(fd);
-	free(ibuf);
-	free(obuf);
+	rv = 0;				/* pessimism */
+	triedin = 0;
+	/*
+	 * normal resolvers and servers will just use mntpt for all addresses,
+	 * even on the outside.  straddling servers will use mntpt (/net)
+	 * for inside addresses and /net.alt for outside addresses,
+	 * thus bypassing other inside nameservers.
+	 */
+	inname = insideaddr(dp->name);
+	if (!cfg.straddle || inname) {
+		rv = udpquery(mntpt, dp, type, nsrp, reqp, depth, Hurry,
+			(cfg.inside? Inns: Outns));
+		triedin = 1;
+	}
+
+	/*
+	 * if we're still looking, are inside, and have an outside domain,
+	 * try it on our outside interface, if any.
+	 */
+	if (rv == 0 && cfg.inside && !inname) {
+		if (triedin)
+			dnslog(
+	   "[%d] netquery: internal nameservers failed for %s; trying external",
+				getpid(), dp->name);
+
+		/* prepare server RR's for incremental lookup */
+		for(rp = nsrp; rp; rp = rp->next)
+			rp->marker = 0;
+
+		rv = udpquery("/net.alt", dp, type, nsrp, reqp, depth, Patient,
+			Outns);
+	}
+	if (0 && rv == 0)		/* TODO: ask /net.alt/dns directly */
+		askoutdns(dp, type);
+
+	if(lock)
+		qunlock(&dp->querylck);
 
 	return rv;
 }
+
+int
+seerootns(void)
+{
+	char root[] = "";
+	Request req;
+
+	memset(&req, 0, sizeof req);
+	req.isslave = 1;
+	req.aborttime = now + Maxreqtm*2;	/* be patient */
+	return netquery(dnlookup(root, Cin, 1), Tns,
+		dblookup(root, Cin, Tns, 0, 0), &req, 0);
+}

+ 165 - 152
sys/src/cmd/ndb/dns.c

@@ -11,12 +11,12 @@
 enum
 {
 	Maxrequest=		1024,
-	Ncache=			8,
-	Maxpath=		128,
 	Maxreply=		512,
 	Maxrrr=			16,
 	Maxfdata=		8192,
 
+	Defmaxage=		60*60,		/* 1 hour */
+
 	Qdir=			0,
 	Qdns=			1,
 };
@@ -42,9 +42,9 @@ struct Mfile
 	ushort		nrr;		/* number of rr's */
 };
 
-//
-//  active local requests
-//
+/*
+ *  active local requests
+ */
 struct Job
 {
 	Job	*next;
@@ -60,145 +60,149 @@ struct {
 	Mfile	*inuse;		/* active mfile's */
 } mfalloc;
 
-int	mfd[2];
+Cfg	cfg;
 int	debug;
-int traceactivity;
-int	cachedb;
+uchar	ipaddr[IPaddrlen];	/* my ip address */
+int	maxage = Defmaxage;
+int	mfd[2];
+int	needrefresh;
 ulong	now;
+int	sendnotifies;
 int	testing;
 char	*trace;
-int	needrefresh;
-int	resolver;
-uchar	ipaddr[IPaddrlen];	/* my ip address */
-int	maxage;
+int	traceactivity;
 char	*zonerefreshprogram;
-int	sendnotifies;
 
-void	rversion(Job*);
+char	*logfile = "dns";	/* or "dns.test" */
+char	*dbfile;
+char	mntpt[Maxpath];
+
+int	fillreply(Mfile*, int);
+void	freejob(Job*);
+void	io(void);
+void	mountinit(char*, char*);
+Job*	newjob(void);
+void	rattach(Job*, Mfile*);
 void	rauth(Job*);
+void	rclunk(Job*, Mfile*);
+void	rcreate(Job*, Mfile*);
 void	rflush(Job*);
-void	rattach(Job*, Mfile*);
-char*	rwalk(Job*, Mfile*);
 void	ropen(Job*, Mfile*);
-void	rcreate(Job*, Mfile*);
 void	rread(Job*, Mfile*);
-void	rwrite(Job*, Mfile*, Request*);
-void	rclunk(Job*, Mfile*);
 void	rremove(Job*, Mfile*);
 void	rstat(Job*, Mfile*);
+void	rversion(Job*);
+char*	rwalk(Job*, Mfile*);
+void	rwrite(Job*, Mfile*, Request*);
 void	rwstat(Job*, Mfile*);
 void	sendmsg(Job*, char*);
-void	mountinit(char*, char*);
-void	io(void);
-int	fillreply(Mfile*, int);
-Job*	newjob(void);
-void	freejob(Job*);
 void	setext(char*, int, char*);
 
-char	*logfile = "dns";
-char	*dbfile;
-char	mntpt[Maxpath];
-char	*LOG;
-
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-rRs] [-f ndb-file] [-x netmtpt]\n", argv0);
+	fprint(2, "usage: %s [-norRst] [-a maxage] [-f ndb-file] [-N target] "
+		"[-x netmtpt] [-z refreshprog]\n", argv0);
 	exits("usage");
 }
 
 void
 main(int argc, char *argv[])
 {
-	int	serve;
-	char	servefile[Maxpath];
-	char	ext[Maxpath];
-	char	*p;
+	char	servefile[Maxpath], ext[Maxpath];
 
-	serve = 0;
-	setnetmtpt(mntpt, sizeof(mntpt), nil);
+	setnetmtpt(mntpt, sizeof mntpt, nil);
 	ext[0] = 0;
 	ARGBEGIN{
+	case 'a':
+		maxage = atol(EARGF(usage()));
+		if (maxage <= 0)
+			maxage = Defmaxage;
+		break;
 	case 'd':
 		debug = 1;
 		traceactivity = 1;
 		break;
 	case 'f':
-		p = ARGF();
-		if(p == nil)
-			usage();
-		dbfile = p;
+		dbfile = EARGF(usage());
 		break;
-	case 'x':
-		p = ARGF();
-		if(p == nil)
-			usage();
-		setnetmtpt(mntpt, sizeof(mntpt), p);
-		setext(ext, sizeof(ext), mntpt);
+	case 'n':
+		sendnotifies = 1;
+		break;
+	case 'N':
+		target = atol(EARGF(usage()));
+		if (target < 100)
+			target = 100;
+		break;
+	case 'o':
+		cfg.straddle = 1;	/* straddle inside & outside networks */
 		break;
 	case 'r':
-		resolver = 1;
+		cfg.resolver = 1;
 		break;
 	case 'R':
 		norecursion = 1;
 		break;
 	case 's':
-		serve = 1;	/* serve network */
-		cachedb = 1;
-		break;
-	case 'a':
-		p = ARGF();
-		if(p == nil)
-			usage();
-		maxage = atoi(p);
+		cfg.serve = 1;		/* serve network */
+		cfg.cachedb = 1;
 		break;
 	case 't':
 		testing = 1;
 		break;
-	case 'z':
-		zonerefreshprogram = ARGF();
+	case 'x':
+		setnetmtpt(mntpt, sizeof mntpt, EARGF(usage()));
+		setext(ext, sizeof ext, mntpt);
 		break;
-	case 'n':
-		sendnotifies = 1;
+	case 'z':
+		zonerefreshprogram = EARGF(usage());
 		break;
 	}ARGEND
 	USED(argc);
 	USED(argv);
 
-if(testing) mainmem->flags |= POOL_NOREUSE;
+	if(testing)
+		mainmem->flags |= POOL_NOREUSE | POOL_ANTAGONISM;
 	rfork(RFREND|RFNOTEG);
 
+	cfg.inside = (*mntpt == '\0' || strcmp(mntpt, "/net") == 0);
+
 	/* start syslog before we fork */
 	fmtinstall('F', fcallfmt);
 	dninit();
 	if(myipaddr(ipaddr, mntpt) < 0)
 		sysfatal("can't read my ip address");
-
-	syslog(0, logfile, "starting dns on %I", ipaddr);
+	dnslog("starting %s%sdns %s%son %I's %s",
+		(cfg.straddle? "straddling ": ""),
+		(cfg.cachedb? "caching ": ""),
+		(cfg.serve?   "udp server ": ""),
+		(cfg.resolver? "resolver ": ""), ipaddr, mntpt);
 
 	opendatabase();
 
-	snprint(servefile, sizeof(servefile), "#s/dns%s", ext);
+	snprint(servefile, sizeof servefile, "#s/dns%s", ext);
 	unmount(servefile, mntpt);
 	remove(servefile);
 	mountinit(servefile, mntpt);
 
-	now = time(0);
+	now = time(nil);
 	srand(now*getpid());
 	db2cache(1);
 
-	if(serve)
+	if (cfg.straddle && !seerootns())
+		dnslog("straddle server misconfigured; can't see root name servers");
+	if(cfg.serve)
 		dnudpserver(mntpt);
 	if(sendnotifies)
 		notifyproc();
 
 	io();
-	syslog(0, logfile, "io returned, exiting");
+	dnslog("io returned, exiting");
 	exits(0);
 }
 
 /*
- *  if a mount point is specified, set the cs extention to be the mount point
+ *  if a mount point is specified, set the cs extension to be the mount point
  *  with '_'s replacing '/'s
  */
 void
@@ -230,6 +234,7 @@ mountinit(char *service, char *mntpt)
 	switch(rfork(RFFDG|RFPROC|RFNAMEG)){
 	case 0:
 		close(p[1]);
+		procsetname("main");
 		break;
 	case -1:
 		abort(); /* "fork failed\n" */;
@@ -242,7 +247,7 @@ mountinit(char *service, char *mntpt)
 		f = create(service, 1, 0666);
 		if(f < 0)
 			abort(); /* service */;
-		snprint(buf, sizeof(buf), "%d", p[1]);
+		snprint(buf, sizeof buf, "%d", p[1]);
 		if(write(f, buf, strlen(buf)) != strlen(buf))
 			abort(); /* "write %s", service */;
 		close(f);
@@ -263,14 +268,13 @@ newfid(int fid, int needunused)
 	Mfile *mf;
 
 	lock(&mfalloc);
-	for(mf = mfalloc.inuse; mf != nil; mf = mf->next){
+	for(mf = mfalloc.inuse; mf != nil; mf = mf->next)
 		if(mf->fid == fid){
 			unlock(&mfalloc);
 			if(needunused)
 				return nil;
 			return mf;
 		}
-	}
 	mf = emalloc(sizeof(*mf));
 	if(mf == nil)
 		sysfatal("out of memory");
@@ -287,16 +291,16 @@ freefid(Mfile *mf)
 	Mfile **l;
 
 	lock(&mfalloc);
-	for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next){
+	for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next)
 		if(*l == mf){
 			*l = mf->next;
 			if(mf->user)
 				free(mf->user);
+			memset(mf, 0, sizeof *mf);	/* cause trouble */
 			free(mf);
 			unlock(&mfalloc);
 			return;
 		}
-	}
 	sysfatal("freeing unused fid");
 }
 
@@ -321,7 +325,7 @@ newjob(void)
 {
 	Job *job;
 
-	job = emalloc(sizeof(*job));
+	job = emalloc(sizeof *job);
 	lock(&joblock);
 	job->next = joblist;
 	joblist = job;
@@ -336,13 +340,13 @@ freejob(Job *job)
 	Job **l;
 
 	lock(&joblock);
-	for(l = &joblist; *l; l = &(*l)->next){
-		if((*l) == job){
+	for(l = &joblist; *l; l = &(*l)->next)
+		if(*l == job){
 			*l = job->next;
+			memset(job, 0, sizeof *job);	/* cause trouble */
 			free(job);
 			break;
 		}
-	}
 	unlock(&joblock);
 }
 
@@ -352,12 +356,11 @@ flushjob(int tag)
 	Job *job;
 
 	lock(&joblock);
-	for(job = joblist; job; job = job->next){
+	for(job = joblist; job; job = job->next)
 		if(job->request.tag == tag && job->request.type != Tflush){
 			job->flushed = 1;
 			break;
 		}
-	}
 	unlock(&joblock);
 }
 
@@ -370,6 +373,7 @@ io(void)
 	Request req;
 	Job *job;
 
+	memset(&req, 0, sizeof req);
 	/*
 	 *  a slave process is sometimes forked to wait for replies from other
 	 *  servers.  The master process returns immediately via a longjmp
@@ -377,13 +381,15 @@ io(void)
 	 */
 	if(setjmp(req.mret))
 		putactivity(0);
+	procsetname("main 9p reading loop");
 	req.isslave = 0;
 	for(;;){
 		n = read9pmsg(mfd[0], mdata, sizeof mdata);
 		if(n<=0){
-			syslog(0, logfile, "error reading mntpt: %r");
+			dnslog("error reading mntpt: %r");
 			exits(0);
 		}
+
 		job = newjob();
 		if(convM2S(mdata, n, &job->request) != n){
 			freejob(job);
@@ -391,14 +397,14 @@ io(void)
 		}
 		mf = newfid(job->request.fid, 0);
 		if(debug)
-			syslog(0, logfile, "%F", &job->request);
+			dnslog("%F", &job->request);
 
 		getactivity(&req, 0);
-		req.aborttime = now + 60;	/* don't spend more than 60 seconds */
+		req.aborttime = now + Maxreqtm;
 
 		switch(job->request.type){
 		default:
-			syslog(1, logfile, "unknown request type %d", job->request.type);
+			warning("unknown request type %d", job->request.type);
 			break;
 		case Tversion:
 			rversion(job);
@@ -442,7 +448,7 @@ io(void)
 		}
 
 		freejob(job);
-	
+
 		/*
 		 *  slave processes die after replying
 		 */
@@ -450,7 +456,7 @@ io(void)
 			putactivity(0);
 			_exits(0);
 		}
-	
+
 		putactivity(0);
 	}
 }
@@ -502,16 +508,15 @@ rattach(Job *job, Mfile *mf)
 char*
 rwalk(Job *job, Mfile *mf)
 {
+	int i, nelems;
 	char *err;
 	char **elems;
-	int nelems;
-	int i;
 	Mfile *nmf;
 	Qid qid;
 
 	err = 0;
 	nmf = nil;
-	elems = job->request.wname;
+	elems  = job->request.wname;
 	nelems = job->request.nwname;
 	job->reply.nwqid = 0;
 
@@ -527,17 +532,18 @@ rwalk(Job *job, Mfile *mf)
 	/* else nmf will be nil */
 
 	qid = mf->qid;
-	if(nelems > 0){
+	if(nelems > 0)
 		/* walk fid */
 		for(i=0; i<nelems && i<MAXWELEM; i++){
 			if((qid.type & QTDIR) == 0){
 				err = "not a directory";
 				break;
 			}
-			if(strcmp(elems[i], "..") == 0 || strcmp(elems[i], ".") == 0){
+			if (strcmp(elems[i], "..") == 0 ||
+			    strcmp(elems[i], ".") == 0){
 				qid.type = QTDIR;
 				qid.path = Qdir;
-    Found:
+Found:
 				job->reply.wqid[i] = qid;
 				job->reply.nwqid++;
 				continue;
@@ -550,9 +556,8 @@ rwalk(Job *job, Mfile *mf)
 			err = "file does not exist";
 			break;
 		}
-	}
 
-    send:
+send:
 	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
 		freefid(nmf);
 	if(err == nil)
@@ -569,10 +574,9 @@ ropen(Job *job, Mfile *mf)
 
 	err = 0;
 	mode = job->request.mode;
-	if(mf->qid.type & QTDIR){
+	if(mf->qid.type & QTDIR)
 		if(mode)
 			err = "permission denied";
-	}
 	job->reply.qid = mf->qid;
 	job->reply.iounit = 0;
 	sendmsg(job, err);
@@ -588,19 +592,22 @@ rcreate(Job *job, Mfile *mf)
 void
 rread(Job *job, Mfile *mf)
 {
-	int i, n, cnt;
-	long off;
-	Dir dir;
-	uchar buf[Maxfdata];
-	char *err;
+	int i, n;
 	long clock;
+	ulong cnt;
+	vlong off;
+	char *err;
+	uchar buf[Maxfdata];
+	Dir dir;
 
 	n = 0;
-	err = 0;
+	err = nil;
 	off = job->request.offset;
 	cnt = job->request.count;
+	*buf = '\0';
+	job->reply.data = (char*)buf;
 	if(mf->qid.type & QTDIR){
-		clock = time(0);
+		clock = time(nil);
 		if(off == 0){
 			dir.name = "dns";
 			dir.qid.type = QTFILE;
@@ -608,27 +615,26 @@ rread(Job *job, Mfile *mf)
 			dir.qid.path = Qdns;
 			dir.mode = 0666;
 			dir.length = 0;
-			dir.uid = mf->user;
-			dir.gid = mf->user;
-			dir.muid = mf->user;
-			dir.atime = clock;	/* wrong */
-			dir.mtime = clock;	/* wrong */
+			dir.uid = dir.gid = dir.muid = mf->user;
+			dir.atime = dir.mtime = clock;		/* wrong */
 			n = convD2M(&dir, buf, sizeof buf);
 		}
-		job->reply.data = (char*)buf;
-	} else {
+	} else if (off < 0)
+		err = "negative read offset";
+	else {
+		/* first offset will always be zero */
 		for(i = 1; i <= mf->nrr; i++)
 			if(mf->rr[i] > off)
 				break;
-		if(i > mf->nrr)
-			goto send;
-		if(off + cnt > mf->rr[i])
-			n = mf->rr[i] - off;
-		else
-			n = cnt;
-		job->reply.data = mf->reply + off;
+		if(i <= mf->nrr) {
+			if(off + cnt > mf->rr[i])
+				n = mf->rr[i] - off;
+			else
+				n = cnt;
+			assert(n >= 0);
+			job->reply.data = mf->reply + off;
+		}
 	}
-send:
 	job->reply.count = n;
 	sendmsg(job, err);
 }
@@ -636,18 +642,22 @@ send:
 void
 rwrite(Job *job, Mfile *mf, Request *req)
 {
-	int cnt, rooted, status;
+	int rooted, status, wantsav;
 	long n;
+	ulong cnt;
 	char *err, *p, *atype;
 	RR *rp, *tp, *neg;
-	int wantsav;
 
-	err = 0;
+	err = nil;
 	cnt = job->request.count;
 	if(mf->qid.type & QTDIR){
 		err = "can't write directory";
 		goto send;
 	}
+	if (job->request.offset != 0) {
+		err = "writing at non-zero offset";
+		goto send;
+	}
 	if(cnt >= Maxrequest){
 		err = "request too long";
 		goto send;
@@ -659,16 +669,16 @@ rwrite(Job *job, Mfile *mf, Request *req)
 	/*
 	 *  special commands
 	 */
-	if(strncmp(job->request.data, "debug", 5)==0 && job->request.data[5] == 0){
+	if(strcmp(job->request.data, "debug")==0){
 		debug ^= 1;
 		goto send;
-	} else if(strncmp(job->request.data, "dump", 4)==0 && job->request.data[4] == 0){
+	} else if(strcmp(job->request.data, "dump")==0){
 		dndump("/lib/ndb/dnsdump");
 		goto send;
-	} else if(strncmp(job->request.data, "refresh", 7)==0 && job->request.data[7] == 0){
+	} else if(strcmp(job->request.data, "refresh")==0){
 		needrefresh = 1;
 		goto send;
-	} else if(strncmp(job->request.data, "poolcheck", 9)==0 && job->request.data[9] == 0){
+	} else if(strcmp(job->request.data, "poolcheck")==0){
 		poolcheck(mainmem);
 		goto send;
 	}
@@ -702,6 +712,7 @@ rwrite(Job *job, Mfile *mf, Request *req)
 		goto send;
 	}
 
+	/* normal request: domain [type] */
 	mf->type = rrtype(atype);
 	if(mf->type < 0){
 		err = "unknown type";
@@ -721,15 +732,19 @@ rwrite(Job *job, Mfile *mf, Request *req)
 		p++;
 	} else
 		wantsav = 0;
+
 	dncheck(0, 1);
+	status = 0;
 	rp = dnresolve(p, Cin, mf->type, req, 0, 0, Recurse, rooted, &status);
+
 	dncheck(0, 1);
 	neg = rrremneg(&rp);
 	if(neg){
 		status = neg->negrcode;
 		rrfreelist(neg);
 	}
-	if(rp == 0){
+
+	if(rp == nil)
 		switch(status){
 		case Rname:
 			err = "name does not exist";
@@ -741,27 +756,28 @@ rwrite(Job *job, Mfile *mf, Request *req)
 			err = "resource does not exist";
 			break;
 		}
-	} else {
+	else {
 		lock(&joblock);
 		if(!job->flushed){
 			/* format data to be read later */
 			n = 0;
 			mf->nrr = 0;
 			for(tp = rp; mf->nrr < Maxrrr-1 && n < Maxreply && tp &&
-					tsame(mf->type, tp->type); tp = tp->next){
+			    tsame(mf->type, tp->type); tp = tp->next){
 				mf->rr[mf->nrr++] = n;
 				if(wantsav)
-					n += snprint(mf->reply+n, Maxreply-n, "%Q", tp);
+					n += snprint(mf->reply+n, Maxreply-n,
+						"%Q", tp);
 				else
-					n += snprint(mf->reply+n, Maxreply-n, "%R", tp);
+					n += snprint(mf->reply+n, Maxreply-n,
+						"%R", tp);
 			}
 			mf->rr[mf->nrr] = n;
 		}
 		unlock(&joblock);
 		rrfreelist(rp);
 	}
-
-    send:
+send:
 	dncheck(0, 1);
 	job->reply.count = cnt;
 	sendmsg(job, err);
@@ -796,10 +812,8 @@ rstat(Job *job, Mfile *mf)
 	}
 	dir.qid = mf->qid;
 	dir.length = 0;
-	dir.uid = mf->user;
-	dir.gid = mf->user;
-	dir.muid = mf->user;
-	dir.atime = dir.mtime = time(0);
+	dir.uid = dir.gid = dir.muid = mf->user;
+	dir.atime = dir.mtime = time(nil);
 	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
 	job->reply.stat = buf;
 	sendmsg(job, 0);
@@ -821,15 +835,14 @@ sendmsg(Job *job, char *err)
 
 	if(err){
 		job->reply.type = Rerror;
-		snprint(ename, sizeof(ename), "dns: %s", err);
+		snprint(ename, sizeof ename, "dns: %s", err);
 		job->reply.ename = ename;
-	}else{
+	}else
 		job->reply.type = job->request.type+1;
-	}
 	job->reply.tag = job->request.tag;
 	n = convS2M(&job->reply, mdata, sizeof mdata);
 	if(n == 0){
-		syslog(1, logfile, "sendmsg convS2M of %F returns 0", &job->reply);
+		warning("sendmsg convS2M of %F returns 0", &job->reply);
 		abort();
 	}
 	lock(&joblock);
@@ -838,7 +851,7 @@ sendmsg(Job *job, char *err)
 			sysfatal("mount write");
 	unlock(&joblock);
 	if(debug)
-		syslog(0, logfile, "%F %d", &job->reply, n);
+		dnslog("%F %d", &job->reply, n);
 }
 
 /*
@@ -849,21 +862,20 @@ logreply(int id, uchar *addr, DNSmsg *mp)
 {
 	RR *rp;
 
-	syslog(0, LOG, "%d: rcvd %I flags:%s%s%s%s%s", id, addr,
-		mp->flags & Fauth ? " auth" : "",
-		mp->flags & Ftrunc ? " trunc" : "",
-		mp->flags & Frecurse ? " rd" : "",
-		mp->flags & Fcanrec ? " ra" : "",
-		mp->flags & (Fauth|Rname) == (Fauth|Rname) ?
-		" nx" : "");
+	dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr,
+		mp->flags & Fauth? " auth": "",
+		mp->flags & Ftrunc? " trunc": "",
+		mp->flags & Frecurse? " rd": "",
+		mp->flags & Fcanrec? " ra": "",
+		(mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
 	for(rp = mp->qd; rp != nil; rp = rp->next)
-		syslog(0, LOG, "%d: rcvd %I qd %s", id, addr, rp->owner->name);
+		dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name);
 	for(rp = mp->an; rp != nil; rp = rp->next)
-		syslog(0, LOG, "%d: rcvd %I an %R", id, addr, rp);
+		dnslog("%d: rcvd %I an %R", id, addr, rp);
 	for(rp = mp->ns; rp != nil; rp = rp->next)
-		syslog(0, LOG, "%d: rcvd %I ns %R", id, addr, rp);
+		dnslog("%d: rcvd %I ns %R", id, addr, rp);
 	for(rp = mp->ar; rp != nil; rp = rp->next)
-		syslog(0, LOG, "%d: rcvd %I ar %R", id, addr, rp);
+		dnslog("%d: rcvd %I ar %R", id, addr, rp);
 }
 
 void
@@ -871,8 +883,9 @@ logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
 {
 	char buf[12];
 
-	syslog(0, LOG, "[%d] %d.%d: sending to %I/%s %s %s",
-		getpid(), id, subid, addr, sname, rname, rrname(type, buf, sizeof buf));
+	dnslog("[%d] %d.%d: sending to %I/%s %s %s",
+		getpid(), id, subid, addr, sname, rname,
+		rrname(type, buf, sizeof buf));
 }
 
 RR*

+ 169 - 134
sys/src/cmd/ndb/dns.h

@@ -3,7 +3,7 @@ typedef struct Ndbtuple Ndbtuple;
 enum
 {
 	/* RR types; see: http://www.iana.org/assignments/dns-parameters */
-	Ta=			1,
+	Ta=		1,
 	Tns=		2,
 	Tmd=		3,
 	Tmf=		4,
@@ -63,7 +63,7 @@ enum
 	Ttsig=	250,	/* transaction signature */
 	Tixfr=	251,	/* incremental zone transfer */
 	Taxfr=	252,	/* zone transfer */
-	Tmailb=	253,	/* { Tmb, Tmg, Tmr } */	
+	Tmailb=	253,	/* { Tmb, Tmg, Tmr } */
 	Tmaila= 254,	/* obsolete */
 	Tall=	255,	/* all records */
 
@@ -105,7 +105,7 @@ enum
 	Rbadname=	20,		/* duplicate key name */
 	Rbadalg=	21,		/* algorithm not supported */
 	Rmask=		0x1f,	/* mask for response */
-	Rtimeout=	0x20,	/* timeout sending (for internal use only) */
+	Rtimeout=	1<<5,	/* timeout sending (for internal use only) */
 
 	/* bits in flag word (other than opcode and response) */
 	Fresp=		1<<15,	/* message is a response */
@@ -137,24 +137,30 @@ enum
 	/* length of domain name hash table */
 	HTLEN= 		4*1024,
 
+	Maxpath=	128,	/* size of mntpt */
+
 	RRmagic=	0xdeadbabe,
 	DNmagic=	0xa110a110,
 
 	/* parallelism */
 	Maxactive=	32,
+
+	Maxreqtm=	60,	/* max. seconds to process a request */
 };
 
+typedef struct Area	Area;
+typedef struct Block	Block;
+typedef struct Cert	Cert;
 typedef struct DN	DN;
 typedef struct DNSmsg	DNSmsg;
-typedef struct RR	RR;
-typedef struct SOA	SOA;
-typedef struct Area	Area;
-typedef struct Request	Request;
 typedef struct Key	Key;
-typedef struct Cert	Cert;
-typedef struct Sig	Sig;
 typedef struct Null	Null;
+typedef struct RR	RR;
+typedef struct Request	Request;
+typedef struct SOA	SOA;
 typedef struct Server	Server;
+typedef struct Sig	Sig;
+typedef struct Srv	Srv;
 typedef struct Txt	Txt;
 
 /*
@@ -181,46 +187,46 @@ struct DN
 	ulong	lookuptime;	/* last time we tried to get a better value */
 	ushort	class;		/* RR class */
 	char	refs;		/* for mark and sweep */
-	char	nonexistent;	/* true if we get an authoritative nx for this domain */
+	uchar	respcode;	/* response code */
+/* was:	char	nonexistent; /* true if we get an authoritative nx for this domain */
 	ulong	ordinal;
+	QLock	querylck;	/* permit only 1 query per domain name at a time */
 };
 
 /*
  *  security info
  */
+struct Block
+{
+	int	dlen;
+	uchar	*data;
+};
 struct Key
 {
 	int	flags;
 	int	proto;
 	int	alg;
-	int	dlen;
-	uchar	*data;
+	Block;
 };
 struct Cert
 {
 	int	type;
 	int	tag;
 	int	alg;
-	int	dlen;
-	uchar	*data;
+	Block;
 };
 struct Sig
 {
-	int	type;
-	int	alg;
+	Cert;
 	int	labels;
 	ulong	ttl;
 	ulong	exp;
 	ulong	incep;
-	int	tag;
 	DN	*signer;
-	int	dlen;
-	uchar	*data;
 };
 struct Null
 {
-	int	dlen;
-	uchar	*data;
+	Block;
 };
 
 /*
@@ -240,28 +246,28 @@ struct RR
 	RR	*next;
 	ulong	magic;
 	DN	*owner;		/* domain that owns this resource record */
-	uchar	negative;	/* this is a cached negative response */
 	uintptr	pc;
 	ulong	ttl;		/* time to live to be passed on */
 	ulong	expire;		/* time this entry expires locally */
-	ushort	type;		/* RR type */
-	ushort	query;		/* query tyis is in response to */
-	uchar	auth;		/* authoritative */
-	uchar	db;		/* from database */
-	uchar	cached;		/* rr in cache */
 	ulong	marker;		/* used locally when scanning rrlists */
-	union {
+	ushort	type;		/* RR type */
+	ushort	query;		/* query type is in response to */
+	uchar	auth;		/* flag: authoritative */
+	uchar	db;		/* flag: from database */
+	uchar	cached;		/* flag: rr in cache */
+	uchar	negative;	/* flag: this is a cached negative response */
+
+	union {			/* discriminated how? negative & type? */
 		DN	*negsoaowner;	/* soa for cached negative response */
 		DN	*host;	/* hostname - soa, cname, mb, md, mf, mx, ns */
 		DN	*cpu;	/* cpu type - hinfo */
 		DN	*mb;	/* mailbox - mg, minfo */
-		DN	*ip;	/* ip addrss - a */
+		DN	*ip;	/* ip address - a */
 		DN	*rp;	/* rp arg - rp */
-		int	cruftlen;
 		ulong	arg0;
 	};
-	union {
-		int	negrcode;	/* response code for cached negative response */
+	union {			/* discriminated how? negative & type? */
+		int	negrcode; /* response code for cached negative response */
 		DN	*rmb;	/* responsible maibox - minfo, soa, rp */
 		DN	*ptr;	/* pointer to domain name - ptr */
 		DN	*os;	/* operating system - hinfo */
@@ -269,13 +275,14 @@ struct RR
 		ulong	local;	/* ns served from local database - ns */
 		ulong	arg1;
 	};
-	union {
+	union {			/* discriminated by type */
 		SOA	*soa;	/* soa timers - soa */
 		Key	*key;
 		Cert	*cert;
 		Sig	*sig;
 		Null	*null;
 		Txt	*txt;
+		Srv	*srv;
 	};
 };
 
@@ -289,18 +296,31 @@ struct Server
 };
 
 /*
- *  timers for a start of authenticated record
+ *  timers for a start-of-authority record.  all ulongs are in seconds.
  */
 struct SOA
 {
-	ulong	serial;		/* zone serial # (sec) - soa */
-	ulong	refresh;	/* zone refresh interval (sec) - soa */
-	ulong	retry;		/* zone retry interval (sec) - soa */
-	ulong	expire;		/* time to expiration (sec) - soa */
-	ulong	minttl;		/* minimum time to live for any entry (sec) - soa */
+	ulong	serial;		/* zone serial # */
+	ulong	refresh;	/* zone refresh interval */
+	ulong	retry;		/* zone retry interval */
+	ulong	expire;		/* time to expiration */
+	ulong	minttl;		/* min. time to live for any entry */
+
 	Server	*slaves;	/* slave servers */
 };
 
+/*
+ * srv (service location) record (rfc2782):
+ * _service._proto.name ttl class(IN) 'SRV' priority weight port target
+ */
+struct Srv
+{
+	ushort	pri;
+	ushort	weight;
+	ushort	port;
+	DN	*target;
+};
+
 /*
  *  domain messages
  */
@@ -323,12 +343,21 @@ struct DNSmsg
  */
 struct Area
 {
-	Area		*next;
+	Area	*next;
 
-	int		len;		/* strlen(area->soarr->owner->name) */
-	RR		*soarr;		/* soa defining this area */
-	int		neednotify;
-	int		needrefresh;
+	int	len;		/* strlen(area->soarr->owner->name) */
+	RR	*soarr;		/* soa defining this area */
+	int	neednotify;
+	int	needrefresh;
+};
+
+typedef struct Cfg Cfg;
+struct Cfg {
+	int	cachedb;
+	int	resolver;
+	int	serve;
+	int	inside;
+	int	straddle;
 };
 
 enum
@@ -339,114 +368,120 @@ enum
 	OKneg,
 };
 
+extern Cfg	cfg;
+extern char	*dbfile;
+extern int	debug;
+extern Area	*delegated;
+extern char	*logfile;
+extern int	maxage;		/* age of oldest entry in cache (secs) */
+extern char	mntpt[];
+extern int	needrefresh;
+extern int	norecursion;
+extern ulong	now;		/* time base */
+extern Area	*owned;
+extern int	sendnotifies;
+extern ulong	target;
+extern int	testing;	/* test cache whenever removing a DN */
+extern char	*trace;
+extern int	traceactivity;
+extern char	*zonerefreshprogram;
+
+#pragma	varargck	type	"R"	RR*
+#pragma	varargck	type	"Q"	RR*
+
+
 /* dn.c */
 extern char	*rrtname[];
 extern char	*rname[];
+extern unsigned	nrname;
 extern char	*opname[];
-extern void	db2cache(int);
-extern void	dninit(void);
-extern DN*	dnlookup(char*, int, int);
-extern void	dnage(DN*);
-extern void	dnageall(int);
-extern void	dnagedb(void);
-extern void	dnauthdb(void);
-extern void	dnget(void);
-extern void	dnpurge(void);
-extern void	dnput(void);
-extern Area*	inmyarea(char*);
-extern void	rrattach(RR*, int);
-extern RR*	rralloc(int);
-extern void	rrfree(RR*);
-extern void	rrfreelist(RR*);
-extern RR*	rrlookup(DN*, int, int);
-extern RR*	rrcat(RR**, RR*);
-extern RR**	rrcopy(RR*, RR**);
-extern RR*	rrremneg(RR**);
-extern RR*	rrremtype(RR**, int);
-extern int	rrfmt(Fmt*);
-extern int	rravfmt(Fmt*);
-extern int	rrsupported(int);
-extern int	rrtype(char*);
-extern char*	rrname(int, char*, int);
-extern int	tsame(int, int);
-extern void	dndump(char*);
-extern int	getactivity(Request*, int);
-extern void	putactivity(int);
-extern void	abort(); /* char*, ... */;
-extern void	warning(char*, ...);
-extern void	slave(Request*);
-extern void	dncheck(void*, int);
-extern void	unique(RR*);
-extern int	subsume(char*, char*);
-extern RR*	randomize(RR*);
-extern void*	emalloc(int);
-extern char*	estrdup(char*);
-extern void	dnptr(uchar*, uchar*, char*, int, int);
-extern void	addserver(Server**, char*);
-extern Server*	copyserverlist(Server*);
-extern void	freeserverlist(Server*);
+
+void	abort(); /* char*, ... */;
+void	addserver(Server**, char*);
+Server*	copyserverlist(Server*);
+void	db2cache(int);
+void	dnage(DN*);
+void	dnageall(int);
+void	dnagedb(void);
+void	dnauthdb(void);
+void	dncheck(void*, int);
+void	dndump(char*);
+void	dnget(void);
+void	dninit(void);
+DN*	dnlookup(char*, int, int);
+void	dnptr(uchar*, uchar*, char*, int, int);
+void	dnpurge(void);
+void	dnput(void);
+void	dnslog(char*, ...);
+void*	emalloc(int);
+char*	estrdup(char*);
+void	freeserverlist(Server*);
+int	getactivity(Request*, int);
+Area*	inmyarea(char*);
+void	putactivity(int);
+RR*	randomize(RR*);
+RR*	rralloc(int);
+void	rrattach(RR*, int);
+int	rravfmt(Fmt*);
+RR*	rrcat(RR**, RR*);
+RR**	rrcopy(RR*, RR**);
+int	rrfmt(Fmt*);
+void	rrfree(RR*);
+void	rrfreelist(RR*);
+RR*	rrlookup(DN*, int, int);
+char*	rrname(int, char*, int);
+RR*	rrremneg(RR**);
+RR*	rrremtype(RR**, int);
+int	rrsupported(int);
+int	rrtype(char*);
+void	slave(Request*);
+int	subsume(char*, char*);
+int	tsame(int, int);
+void	unique(RR*);
+void	warning(char*, ...);
 
 /* dnarea.c */
-extern void	refresh_areas(Area*);
-extern void	freearea(Area**);
-extern void	addarea(DN *dp, RR *rp, Ndbtuple *t);
+void	refresh_areas(Area*);
+void	freearea(Area**);
+void	addarea(DN *dp, RR *rp, Ndbtuple *t);
 
 /* dblookup.c */
-extern RR*	dblookup(char*, int, int, int, int);
-extern RR*	dbinaddr(DN*, int);
-extern int	baddelegation(RR*, RR*, uchar*);
-extern RR*	dnsservers(int);
-extern RR*	domainlist(int);
-extern int	opendatabase(void);
+int	baddelegation(RR*, RR*, uchar*);
+RR*	dbinaddr(DN*, int);
+RR*	dblookup(char*, int, int, int, int);
+RR*	dnsservers(int);
+RR*	domainlist(int);
+int	insideaddr(char *dom);
+int	insidens(uchar *ip);
+int	opendatabase(void);
+uchar*	outsidens(int);
 
 /* dns.c */
-extern char*	walkup(char*);
-extern RR*	getdnsservers(int);
-extern void	logreply(int, uchar*, DNSmsg*);
-extern void	logsend(int, int, uchar*, char*, char*, int);
+char*	walkup(char*);
+RR*	getdnsservers(int);
+void	logreply(int, uchar*, DNSmsg*);
+void	logsend(int, int, uchar*, char*, char*, int);
+void	procsetname(char *fmt, ...);
 
 /* dnresolve.c */
-extern RR*	dnresolve(char*, int, int, Request*, RR**, int, int, int, int*);
-extern int	udpport(void);
-extern int	mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno);
+RR*	dnresolve(char*, int, int, Request*, RR**, int, int, int, int*);
+int	udpport(char *);
+int	mkreq(DN *dp, int type, uchar *buf, int flags, ushort reqno);
+int	seerootns(void);
 
 /* dnserver.c */
-extern void	dnserver(DNSmsg*, DNSmsg*, Request*);
-extern void	dnudpserver(char*);
-extern void	dntcpserver(char*);
+void	dnserver(DNSmsg*, DNSmsg*, Request*, uchar *, int);
+void	dnudpserver(char*);
+void	dntcpserver(char*);
 
 /* dnnotify.c */
-extern void	dnnotify(DNSmsg*, DNSmsg*, Request*);
-extern void	notifyproc(void);
+void	dnnotify(DNSmsg*, DNSmsg*, Request*);
+void	notifyproc(void);
 
 /* convDNS2M.c */
-extern int	convDNS2M(DNSmsg*, uchar*, int);
+int	convDNS2M(DNSmsg*, uchar*, int);
 
 /* convM2DNS.c */
-extern char*	convM2DNS(uchar*, int, DNSmsg*);
-
-/* malloc.c */
-extern void	mallocsanity(void*);
-extern void	lasthist(void*, int, ulong);
-
-extern int debug;
-extern int traceactivity;
-extern char	*trace;
-extern int	testing;	/* test cache whenever removing a DN */
-extern int	cachedb;
-extern int	needrefresh;
-extern char	*dbfile;
-extern char	mntpt[];
-extern char	*logfile;
-extern int	resolver;
-extern int	norecursion;
-extern int	maxage;		/* age of oldest entry in cache (secs) */
-extern char	*zonerefreshprogram;
-extern int	sendnotifies;
-extern ulong	now;		/* time base */
-extern Area	*owned;
-extern Area	*delegated;
-
-#pragma	varargck	type	"R"	RR*
-#pragma	varargck	type	"Q"	RR*
+char*	convM2DNS(uchar*, int, DNSmsg*, int*);
 
+#pragma varargck argpos dnslog 1

+ 82 - 79
sys/src/cmd/ndb/dnsdebug.c

@@ -6,40 +6,42 @@
 #include <ndb.h>
 #include "dns.h"
 
-enum
-{
+enum {
 	Maxrequest=		128,
-	Ncache=			8,
-	Maxpath=		128,
-	Maxreply=		512,
-	Maxrrr=			16,
 };
 
+Cfg cfg;
+
 static char *servername;
 static RR *serverrr;
 static RR *serveraddrs;
 
+char	*dbfile;
 int	debug;
-int	cachedb;
+uchar	ipaddr[IPaddrlen];	/* my ip address */
+char	*logfile = "dnsdebug";
+int	maxage  = 60*60;
+char	mntpt[Maxpath];
+int	needrefresh;
 ulong	now;
 int	testing;
-int traceactivity;
 char	*trace;
-int	needrefresh;
-int	resolver;
-uchar	ipaddr[IPaddrlen];	/* my ip address */
-int	maxage;
-char	*logfile = "dns";
-char	*dbfile;
-char	mntpt[Maxpath];
+int	traceactivity;
 char	*zonerefreshprogram;
 
-int prettyrrfmt(Fmt*);
-void preloadserveraddrs(void);
-void squirrelserveraddrs(void);
-int setserver(char*);
-void doquery(char*, char*);
-void docmd(int, char**);
+void	docmd(int, char**);
+void	doquery(char*, char*);
+void	preloadserveraddrs(void);
+int	prettyrrfmt(Fmt*);
+int	setserver(char*);
+void	squirrelserveraddrs(void);
+
+void
+usage(void)
+{
+	fprint(2, "%s: [-rx] [-f db-file]\n", argv0);
+	exits("usage");
+}
 
 void
 main(int argc, char *argv[])
@@ -50,28 +52,31 @@ main(int argc, char *argv[])
 	char *f[4];
 
 	strcpy(mntpt, "/net");
+	cfg.inside = 1;
 
 	ARGBEGIN{
+	case 'f':
+		dbfile = EARGF(usage());
+		break;
 	case 'r':
-		resolver = 1;
+		cfg.resolver = 1;
 		break;
 	case 'x':
 		dbfile = "/lib/ndb/external";
 		strcpy(mntpt, "/net.alt");
 		break;
-	case 'f':
-		dbfile = ARGF();
-		break;
+	default:
+		usage();
 	}ARGEND
 
-	now = time(0);
+	now = time(nil);
 	dninit();
 	fmtinstall('R', prettyrrfmt);
 	if(myipaddr(ipaddr, mntpt) < 0)
 		sysfatal("can't read my ip address");
 	opendatabase();
 
-	if(resolver)
+	if(cfg.resolver)
 		squirrelserveraddrs();
 
 	debug = 1;
@@ -85,14 +90,10 @@ main(int argc, char *argv[])
 	for(print("> "); p = Brdline(&in, '\n'); print("> ")){
 		p[Blinelen(&in)-1] = 0;
 		n = tokenize(p, f, 3);
-		if(n<1)
-			continue;
-
-		/* flush the cache */
-		dnpurge();
-
-		docmd(n, f);
-
+		if(n>=1) {
+			dnpurge();		/* flush the cache */
+			docmd(n, f);
+		}
 	}
 	exits(0);
 }
@@ -138,7 +139,7 @@ prettyrrfmt(Fmt *f)
 	p = buf;
 	e = buf + sizeof(buf);
 	p = seprint(p, e, "%-32.32s %-15.15s %-5.5s", rp->owner->name,
-		longtime(rp->db ? rp->ttl : (rp->ttl-now)),
+		longtime(rp->db? rp->ttl: (rp->ttl - now)),
 		rrname(rp->type, buf, sizeof buf));
 
 	if(rp->negative){
@@ -155,30 +156,38 @@ prettyrrfmt(Fmt *f)
 	case Tmd:
 	case Tmf:
 	case Tns:
-		seprint(p, e, "\t%s", rp->host->name);
+		seprint(p, e, "\t%s", (rp->host? rp->host->name: ""));
 		break;
 	case Tmg:
 	case Tmr:
-		seprint(p, e, "\t%s", rp->mb->name);
+		seprint(p, e, "\t%s", (rp->mb? rp->mb->name: ""));
 		break;
 	case Tminfo:
-		seprint(p, e, "\t%s %s", rp->mb->name, rp->rmb->name);
+		seprint(p, e, "\t%s %s", (rp->mb? rp->mb->name: ""),
+			(rp->rmb? rp->rmb->name: ""));
 		break;
 	case Tmx:
-		seprint(p, e, "\t%lud %s", rp->pref, rp->host->name);
+		seprint(p, e, "\t%lud %s", rp->pref,
+			(rp->host? rp->host->name: ""));
 		break;
 	case Ta:
 	case Taaaa:
-		seprint(p, e, "\t%s", rp->ip->name);
+		seprint(p, e, "\t%s", (rp->ip? rp->ip->name: ""));
 		break;
 	case Tptr:
-		seprint(p, e, "\t%s", rp->ptr->name);
+		seprint(p, e, "\t%s", (rp->ptr? rp->ptr->name: ""));
 		break;
 	case Tsoa:
-		seprint(p, e, "\t%s %s %lud %lud %lud %lud %lud", rp->host->name,
-			rp->rmb->name, rp->soa->serial, rp->soa->refresh, rp->soa->retry,
+		seprint(p, e, "\t%s %s %lud %lud %lud %lud %lud",
+			rp->host->name, rp->rmb->name, rp->soa->serial,
+			rp->soa->refresh, rp->soa->retry,
 			rp->soa->expire, rp->soa->minttl);
 		break;
+	case Tsrv:
+		seprint(p, e, "\t%ud %ud %ud %s",
+			rp->srv->pri, rp->srv->weight, rp->srv->port,
+			rp->srv->target->name);
+		break;
 	case Tnull:
 		seprint(p, e, "\t%.*H", rp->null->dlen, rp->null->data);
 		break;
@@ -196,15 +205,14 @@ prettyrrfmt(Fmt *f)
 		break;
 	case Tsig:
 		seprint(p, e, "\t%d %d %d %lud %lud %lud %d %s",
-			rp->sig->type, rp->sig->alg, rp->sig->labels, rp->sig->ttl,
-			rp->sig->exp, rp->sig->incep, rp->sig->tag, rp->sig->signer->name);
+			rp->sig->type, rp->sig->alg, rp->sig->labels,
+			rp->sig->ttl, rp->sig->exp, rp->sig->incep,
+			rp->sig->tag, rp->sig->signer->name);
 		break;
 	case Tcert:
 		seprint(p, e, "\t%d %d %d",
 			rp->sig->type, rp->sig->tag, rp->sig->alg);
 		break;
-	default:
-		break;
 	}
 out:
 	return fmtstrcpy(f, buf);
@@ -224,8 +232,7 @@ void
 logreply(int id, uchar *addr, DNSmsg *mp)
 {
 	RR *rp;
-	char buf[12];
-	char resp[32];
+	char buf[12], resp[32];
 
 	switch(mp->flags & Rmask){
 	case Rok:
@@ -252,14 +259,14 @@ logreply(int id, uchar *addr, DNSmsg *mp)
 	}
 
 	print("%d: rcvd %s from %I (%s%s%s%s%s)\n", id, resp, addr,
-		mp->flags & Fauth ? "authoritative" : "",
-		mp->flags & Ftrunc ? " truncated" : "",
-		mp->flags & Frecurse ? " recurse" : "",
-		mp->flags & Fcanrec ? " can_recurse" : "",
-		mp->flags & (Fauth|Rname) == (Fauth|Rname) ?
-		" nx" : "");
+		mp->flags & Fauth? "authoritative": "",
+		mp->flags & Ftrunc? " truncated": "",
+		mp->flags & Frecurse? " recurse": "",
+		mp->flags & Fcanrec? " can_recurse": "",
+		(mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
 	for(rp = mp->qd; rp != nil; rp = rp->next)
-		print("\tQ:    %s %s\n", rp->owner->name, rrname(rp->type, buf, sizeof buf));
+		print("\tQ:    %s %s\n", rp->owner->name,
+			rrname(rp->type, buf, sizeof buf));
 	logsection("Ans:  ", mp->an);
 	logsection("Auth: ", mp->ns);
 	logsection("Hint: ", mp->ar);
@@ -296,7 +303,7 @@ squirrelserveraddrs(void)
 	Request req;
 
 	/* look up the resolver address first */
-	resolver = 0;
+	cfg.resolver = 0;
 	debug = 0;
 	if(serveraddrs)
 		rrfreelist(serveraddrs);
@@ -312,12 +319,12 @@ squirrelserveraddrs(void)
 			continue;
 		}
 		req.isslave = 1;
-		req.aborttime = now + 60;	/* don't spend more than 60 seconds */
+		req.aborttime = now + Maxreqtm*2;	/* be patient */
 		*l = dnresolve(rp->host->name, Cin, Ta, &req, 0, 0, Recurse, 0, 0);
 		while(*l != nil)
 			l = &(*l)->next;
 	}
-	resolver = 1;
+	cfg.resolver = 1;
 	debug = 1;
 }
 
@@ -325,7 +332,7 @@ void
 preloadserveraddrs(void)
 {
 	RR *rp, **l, *first;
-	
+
 	l = &first;
 	for(rp = serveraddrs; rp != nil; rp = rp->next){
 		rrcopy(rp, l);
@@ -339,7 +346,7 @@ setserver(char *server)
 	if(servername != nil){
 		free(servername);
 		servername = nil;
-		resolver = 0;
+		cfg.resolver = 0;
 	}
 	if(server == nil || *server == 0)
 		return 0;
@@ -347,33 +354,30 @@ setserver(char *server)
 	squirrelserveraddrs();
 	if(serveraddrs == nil){
 		print("can't resolve %s\n", servername);
-		resolver = 0;
-	} else {
-		resolver = 1;
-	}
-	return resolver ? 0 : -1;
+		cfg.resolver = 0;
+	} else
+		cfg.resolver = 1;
+	return cfg.resolver? 0: -1;
 }
 
 void
 doquery(char *name, char *tstr)
 {
-	Request req;
-	RR *rr, *rp;
-	int len, type;
+	int len, type, rooted;
 	char *p, *np;
-	int rooted;
 	char buf[1024];
+	RR *rr, *rp;
+	Request req;
 
-	if(resolver)
+	if(cfg.resolver)
 		preloadserveraddrs();
 
 	/* default to an "ip" request if alpha, "ptr" if numeric */
-	if(tstr == nil || *tstr == 0) {
+	if(tstr == nil || *tstr == 0)
 		if(strcmp(ipattr(name), "ip") == 0)
 			tstr = "ptr";
 		else
 			tstr = "ip";
-	}
 
 	/* if name end in '.', remove it */
 	len = strlen(name);
@@ -414,9 +418,10 @@ doquery(char *name, char *tstr)
 		return;
 	}
 
+	memset(&req, 0, sizeof req);
 	getactivity(&req, 0);
 	req.isslave = 1;
-	req.aborttime = now + 60;	/* don't spend more than 60 seconds */
+	req.aborttime = now + Maxreqtm*2;	/* be patient */
 	rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0);
 	if(rr){
 		print("----------------------------\n");
@@ -435,8 +440,7 @@ docmd(int n, char **f)
 	int tmpsrv;
 	char *name, *type;
 
-	name = nil;
-	type = nil;
+	name = type = nil;
 	tmpsrv = 0;
 
 	if(*f[0] == '@') {
@@ -452,7 +456,7 @@ docmd(int n, char **f)
 			tmpsrv = 1;
 			break;
 		}
-	} else {
+	} else
 		switch(n){
 		case 2:
 			type = f[1];
@@ -461,7 +465,6 @@ docmd(int n, char **f)
 			name = f[0];
 			break;
 		}
-	}
 
 	if(name == nil)
 		return;

+ 40 - 27
sys/src/cmd/ndb/dnserver.c

@@ -6,8 +6,6 @@
 static RR*	doextquery(DNSmsg*, Request*, int);
 static void	hint(RR**, RR*);
 
-extern char *logfile;
-
 /* set in dns.c */
 int	norecursion;		/* don't allow recursive requests */
 
@@ -15,18 +13,18 @@ int	norecursion;		/* don't allow recursive requests */
  *  answer a dns request
  */
 void
-dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req)
+dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req, uchar *srcip, int rcode)
 {
-	RR *tp, *neg;
-	char *cp;
+	int recursionflag;
+	char *cp, *errmsg;
+	char tname[32];
 	DN *nsdp, *dp;
 	Area *myarea;
-	char tname[32];
-	int recursionflag;
+	RR *tp, *neg;
 
 	dncheck(nil, 1);
 
-	recursionflag = norecursion?0:Fcanrec;
+	recursionflag = norecursion? 0: Fcanrec;
 	memset(repp, 0, sizeof(*repp));
 	repp->id = reqp->id;
 	repp->flags = Fresp | recursionflag | Oquery;
@@ -34,17 +32,29 @@ dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req)
 	/* move one question from reqp to repp */
 	tp = reqp->qd;
 	reqp->qd = tp->next;
-	tp->next = 0;
+	tp->next = nil;
 	repp->qd = tp;
 
+	if (rcode) {
+		errmsg = "";
+		if (rcode >= 0 && rcode < nrname)
+			errmsg = rname[rcode];
+		dnslog("server: response code 0%o (%s), req from %I",
+			rcode, errmsg, srcip);
+		/* provide feedback to clients who send us trash */
+		repp->flags = (rcode&Rmask) | Fresp | Fcanrec | Oquery;
+		return;
+	}
 	if(!rrsupported(repp->qd->type)){
-		syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname));
+		dnslog("server: unsupported request %s from %I",
+			rrname(repp->qd->type, tname, sizeof tname), srcip);
 		repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
 		return;
 	}
 
 	if(repp->qd->owner->class != Cin){
-		syslog(0, logfile, "server: class %d", repp->qd->owner->class);
+		dnslog("server: unsupported class %d from %I",
+			repp->qd->owner->class, srcip);
 		repp->flags = Runimplimented | Fresp | Fcanrec | Oquery;
 		return;
 	}
@@ -52,17 +62,20 @@ dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req)
 	myarea = inmyarea(repp->qd->owner->name);
 	if(myarea != nil) {
 		if(repp->qd->type == Tixfr || repp->qd->type == Taxfr){
-			syslog(0, logfile, "server: request %s", rrname(repp->qd->type, tname, sizeof tname));
-			repp->flags = Runimplimented | Fresp | recursionflag | Oquery;
+			dnslog(
+			    "server: unsupported xfr request %s for %s from %I",
+				rrname(repp->qd->type, tname, sizeof tname),
+				repp->qd->owner->name, srcip);
+			repp->flags = Runimplimented | Fresp | recursionflag |
+				Oquery;
 			return;
 		}
-	} else {
+	} else
 		if(norecursion) {
 			/* we don't recurse and we're not authoritative */
 			repp->flags = Rok | Fresp | Oquery;
 			return;
 		}
-	}
 
 	/*
 	 *  get the answer if we can
@@ -77,22 +90,22 @@ dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req)
 		repp->flags |= Fauth;
 
 	/* pass on error codes */
-	if(repp->an == 0){
+	if(repp->an == nil){
 		dp = dnlookup(repp->qd->owner->name, repp->qd->owner->class, 0);
-		if(dp->rr == 0)
+		if(dp->rr == nil)
 			if(reqp->flags & Frecurse)
-				repp->flags |= dp->nonexistent|Fauth;
+				repp->flags |= dp->respcode | Fauth;
 	}
 
-	if(myarea == nil){
+	if(myarea == nil)
 		/*
 		 *  add name server if we know
 		 */
 		for(cp = repp->qd->owner->name; cp; cp = walkup(cp)){
 			nsdp = dnlookup(cp, repp->qd->owner->class, 0);
-			if(nsdp == 0)
+			if(nsdp == nil)
 				continue;
-	
+
 			repp->ns = rrlookup(nsdp, Tns, OKneg);
 			if(repp->ns){
 				/* don't pass on anything we know is wrong */
@@ -102,12 +115,11 @@ dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req)
 				}
 				break;
 			}
-	
+
 			repp->ns = dblookup(cp, repp->qd->owner->class, Tns, 0, 0);
 			if(repp->ns)
 				break;
 		}
-	}
 
 	/*
 	 *  add ip addresses as hints
@@ -120,18 +132,19 @@ dnserver(DNSmsg *reqp, DNSmsg *repp, Request *req)
 	}
 
 	/*
-	 *  add an soa to the authority section to help client with negative caching
+	 *  add an soa to the authority section to help client
+	 *  with negative caching
 	 */
-	if(repp->an == nil){
+	if(repp->an == nil)
 		if(myarea != nil){
 			rrcopy(myarea->soarr, &tp);
 			rrcat(&repp->ns, tp);
 		} else if(neg != nil) {
 			if(neg->negsoaowner != nil)
-				rrcat(&repp->ns, rrlookup(neg->negsoaowner, Tsoa, NOneg));
+				rrcat(&repp->ns, rrlookup(neg->negsoaowner,
+					Tsoa, NOneg));
 			repp->flags |= neg->negrcode;
 		}
-	}
 
 	/*
 	 *  get rid of duplicates

+ 62 - 35
sys/src/cmd/ndb/dnsquery.c

@@ -6,28 +6,13 @@
 #include "dns.h"
 #include "ip.h"
 
-void
-main(int argc, char *argv[])
-{
-	int fd, n, len, domount;
-	Biobuf in;
-	char line[1024], *lp, *p, *np, *mtpt, *srv, *dns;
-	char buf[1024];
+static int domount;
+static char *mtpt, *dns, *srv;
 
-	dns = "/net/dns";
-	mtpt = "/net";
-	srv = "/srv/dns";
-	domount = 1;
-	ARGBEGIN {
-	case 'x':
-		dns = "/net.alt/dns";
-		mtpt = "/net.alt";
-		srv = "/srv/dns_net.alt";
-		break;
-	default:
-		fprint(2, "usage: %s -x [dns-mount-point]\n", argv0);
-		exits("usage");
-	} ARGEND;
+static int
+setup(int argc, char **argv)
+{
+	int fd;
 
 	if(argc == 1){
 		domount = 0;
@@ -55,6 +40,35 @@ main(int argc, char *argv[])
 			exits(0);
 		}
 	}
+	return fd;
+}
+
+static void
+querydns(int fd, char *line, int n)
+{
+	char buf[1024];
+
+	seek(fd, 0, 0);
+	if(write(fd, line, n) != n) {
+		print("!%r\n");
+		return;
+	}
+	seek(fd, 0, 0);
+	buf[0] = '\0';
+	while((n = read(fd, buf, sizeof(buf))) > 0){
+		buf[n] = '\0';
+		print("%s\n", buf);
+	}
+}
+
+static void
+query(int fd)
+{
+	int n, len;
+	char line[1024], *lp, *p, *np;
+	char buf[1024];
+	Biobuf in;
+
 	Binit(&in, 0, OREAD);
 	for(print("> "); lp = Brdline(&in, '\n'); print("> ")){
 		n = Blinelen(&in) -1;
@@ -68,8 +82,9 @@ main(int argc, char *argv[])
 		if(!*lp)
 			continue;
 		strcpy(line, lp);
+
 		/* default to an "ip" request if alpha, "ptr" if numeric */
-		if(strchr(line, ' ')==0) {
+		if(strchr(line, ' ') == nil)
 			if(strcmp(ipattr(line), "ip") == 0) {
 				strcat(line, " ptr");
 				n += 4;
@@ -77,11 +92,10 @@ main(int argc, char *argv[])
 				strcat(line, " ip");
 				n += 3;
 			}
-		}
 
 		/* inverse queries may need to be permuted */
-		if(n > 4 && strcmp("ptr", &line[n-3]) == 0
-		&& strstr(line, "IN-ADDR") == 0 && strstr(line, "in-addr") == 0){
+		if(n > 4 && strcmp("ptr", &line[n-3]) == 0 &&
+		    cistrstr(line, "in-addr") == 0){
 			for(p = line; *p; p++)
 				if(*p == ' '){
 					*p = '.';
@@ -105,16 +119,29 @@ main(int argc, char *argv[])
 			n = strlen(line);
 		}
 
-		seek(fd, 0, 0);
-		if(write(fd, line, n) < 0) {
-			print("!%r\n");
-			continue;
-		}
-		seek(fd, 0, 0);
-		while((n = read(fd, buf, sizeof(buf))) > 0){
-			buf[n] = 0;
-			print("%s\n", buf);
-		}
+		querydns(fd, line, n);
 	}
+	Bterm(&in);
+}
+
+void
+main(int argc, char *argv[])
+{
+	mtpt = "/net";
+	dns = "/net/dns";
+	srv = "/srv/dns";
+	domount = 1;
+	ARGBEGIN {
+	case 'x':
+		mtpt = "/net.alt";
+		dns = "/net.alt/dns";
+		srv = "/srv/dns_net.alt";
+		break;
+	default:
+		fprint(2, "usage: %s [-x] [dns-mount-point]\n", argv0);
+		exits("usage");
+	} ARGEND;
+
+	query(setup(argc, argv));
 	exits(0);
 }

+ 94 - 89
sys/src/cmd/ndb/dnstcp.c

@@ -1,27 +1,24 @@
+/*
+ * dnstcp - serve dns via tcp
+ */
 #include <u.h>
 #include <libc.h>
 #include <ip.h>
 #include "dns.h"
 
-enum
-{
-	Maxpath=		128,
-};
+Cfg cfg;
 
-char	*logfile = "dns";
+char	*caller = "";
 char	*dbfile;
 int	debug;
-int	cachedb = 1;
-int	testing;
-int traceactivity;
-int	needrefresh;
-int 	resolver;
+uchar	ipaddr[IPaddrlen];	/* my ip address */
+char	*logfile = "dns";
+int	maxage = 60*60;
 char	mntpt[Maxpath];
-char	*caller = "";
+int	needrefresh;
 ulong	now;
-int	maxage;
-uchar	ipaddr[IPaddrlen];	/* my ip address */
-char	*LOG;
+int	testing;
+int	traceactivity;
 char	*zonerefreshprogram;
 
 static int	readmsg(int, uchar*, int);
@@ -40,18 +37,15 @@ usage(void)
 void
 main(int argc, char *argv[])
 {
-	int len;
-	Request req;
-	DNSmsg reqmsg, repmsg;
+	int len, rcode;
 	uchar buf[512];
 	char tname[32];
-	char *err;
-	char *ext = "";
+	char *err, *ext = "";
+	Request req;
+	DNSmsg reqmsg, repmsg;
 
+	cfg.cachedb = 1;
 	ARGBEGIN{
-	case 'R':
-		norecursion = 1;
-		break;
 	case 'd':
 		debug++;
 		break;
@@ -59,7 +53,10 @@ main(int argc, char *argv[])
 		dbfile = EARGF(usage());
 		break;
 	case 'r':
-		resolver = 1;
+		cfg.resolver = 1;
+		break;
+	case 'R':
+		norecursion = 1;
 		break;
 	case 'x':
 		ext = EARGF(usage());
@@ -75,69 +72,73 @@ main(int argc, char *argv[])
 	if(argc > 0)
 		getcaller(argv[0]);
 
+	cfg.inside = 1;
 	dninit();
 
-	snprint(mntpt, sizeof(mntpt), "/net%s", ext);
+	snprint(mntpt, sizeof mntpt, "/net%s", ext);
 	if(myipaddr(ipaddr, mntpt) < 0)
 		sysfatal("can't read my ip address");
-	syslog(0, logfile, "dnstcp call from %s to %I", caller, ipaddr);
+	dnslog("dnstcp call from %s to %I", caller, ipaddr);
 
 	db2cache(1);
 
+	memset(&req, 0, sizeof req);
 	setjmp(req.mret);
 	req.isslave = 0;
+	procsetname("main loop");
 
 	/* loop on requests */
 	for(;; putactivity(0)){
-		now = time(0);
-		memset(&repmsg, 0, sizeof(repmsg));
+		now = time(nil);
+		memset(&repmsg, 0, sizeof repmsg);
 		alarm(10*60*1000);
-		len = readmsg(0, buf, sizeof(buf));
+		len = readmsg(0, buf, sizeof buf);
 		alarm(0);
 		if(len <= 0)
 			break;
 		getactivity(&req, 0);
 		req.aborttime = now + 15*Min;
-		err = convM2DNS(buf, len, &reqmsg);
+		rcode = 0;
+		memset(&reqmsg, 0, sizeof reqmsg);
+		err = convM2DNS(buf, len, &reqmsg, &rcode);
 		if(err){
-			syslog(0, logfile, "server: input error: %s from %I", err, buf);
-			break;
-		}
-		if(reqmsg.qdcount < 1){
-			syslog(0, logfile, "server: no questions from %I", buf);
+			/* first bytes in buf are source IP addr */
+			dnslog("server: input error: %s from %I",
+				err, buf);
 			break;
 		}
-		if(reqmsg.flags & Fresp){
-			syslog(0, logfile, "server: reply not request from %I", buf);
-			break;
-		}
-		if((reqmsg.flags & Omask) != Oquery){
-			syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf);
-			break;
-		}
-
+		if (rcode == 0)
+			if(reqmsg.qdcount < 1){
+				dnslog(
+					"server: no questions from %I", buf);
+				break;
+			} else if(reqmsg.flags & Fresp){
+				dnslog(
+				    "server: reply not request from %I", buf);
+				break;
+			} else if((reqmsg.flags & Omask) != Oquery){
+				dnslog("server: op %d from %I",
+					reqmsg.flags & Omask, buf);
+				break;
+			}
 		if(debug)
-			syslog(0, logfile, "[%d] %d: serve (%s) %d %s %s",
-				getpid(),
-				req.id, caller,
-				reqmsg.id,
-				reqmsg.qd->owner->name,
+			dnslog("[%d] %d: serve (%s) %d %s %s",
+				getpid(), req.id, caller,
+				reqmsg.id, reqmsg.qd->owner->name,
 				rrname(reqmsg.qd->type, tname, sizeof tname));
 
 		/* loop through each question */
-		while(reqmsg.qd){
-			if(reqmsg.qd->type == Taxfr){
+		while(reqmsg.qd)
+			if(reqmsg.qd->type == Taxfr)
 				dnzone(&reqmsg, &repmsg, &req);
-			} else {
-				dnserver(&reqmsg, &repmsg, &req);
+			else {
+				dnserver(&reqmsg, &repmsg, &req, buf, rcode);
 				reply(1, &repmsg, &req);
 				rrfreelist(repmsg.qd);
 				rrfreelist(repmsg.an);
 				rrfreelist(repmsg.ns);
 				rrfreelist(repmsg.ar);
 			}
-		}
-
 		rrfreelist(reqmsg.qd);
 		rrfreelist(reqmsg.an);
 		rrfreelist(reqmsg.ns);
@@ -159,7 +160,7 @@ readmsg(int fd, uchar *buf, int max)
 
 	if(readn(fd, x, 2) != 2)
 		return -1;
-	n = (x[0]<<8) | x[1];
+	n = x[0]<<8 | x[1];
 	if(n > max)
 		return -1;
 	if(readn(fd, buf, n) != n)
@@ -176,28 +177,29 @@ reply(int fd, DNSmsg *rep, Request *req)
 	RR *rp;
 
 	if(debug){
-		syslog(0, logfile, "%d: reply (%s) %s %s %ux",
+		dnslog("%d: reply (%s) %s %s %ux",
 			req->id, caller,
 			rep->qd->owner->name,
 			rrname(rep->qd->type, tname, sizeof tname),
 			rep->flags);
 		for(rp = rep->an; rp; rp = rp->next)
-			syslog(0, logfile, "an %R", rp);
+			dnslog("an %R", rp);
 		for(rp = rep->ns; rp; rp = rp->next)
-			syslog(0, logfile, "ns %R", rp);
+			dnslog("ns %R", rp);
 		for(rp = rep->ar; rp; rp = rp->next)
-			syslog(0, logfile, "ar %R", rp);
+			dnslog("ar %R", rp);
 	}
 
 
 	len = convDNS2M(rep, buf+2, sizeof(buf) - 2);
 	if(len <= 0)
-		abort(); /* "dnserver: converting reply" */;
+		abort();	/* "dnserver: converting reply" */
 	buf[0] = len>>8;
 	buf[1] = len;
 	rv = write(fd, buf, len+2);
 	if(rv != len+2){
-		syslog(0, logfile, "[%d] sending reply: %d instead of %d", getpid(), rv, len+2);
+		dnslog("[%d] sending reply: %d instead of %d",
+			getpid(), rv, len+2);
 		exits(0);
 	}
 }
@@ -225,7 +227,7 @@ inzone(DN *dp, char *name, int namelen, int depth)
 {
 	int n;
 
-	if(dp->name == 0)
+	if(dp->name == nil)
 		return 0;
 	if(numelem(dp->name) != depth)
 		return 0;
@@ -262,10 +264,11 @@ dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req)
 	if(repp->an == 0)
 		goto out;
 	rrfreelist(repp->an);
+	repp->an = nil;
 
 	nlen = strlen(dp->name);
 
-	/* construct a breadth first search of the name space (hard with a hash) */
+	/* construct a breadth-first search of the name space (hard with a hash) */
 	repp->an = &r;
 	for(depth = numelem(dp->name); ; depth++){
 		found = 0;
@@ -273,14 +276,15 @@ dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req)
 			for(ndp = ht[h]; ndp; ndp = ndp->next)
 				if(inzone(ndp, dp->name, nlen, depth)){
 					for(rp = ndp->rr; rp; rp = rp->next){
-						/* there shouldn't be negatives, but just in case */
-						if(rp->negative)
-							continue;
-
-						/* don't send an soa's, ns's are enough */
-						if(rp->type == Tsoa)
+						/*
+						 * there shouldn't be negatives,
+						 * but just in case.
+						 * don't send any soa's,
+						 * ns's are enough.
+						 */
+						if (rp->negative ||
+						    rp->type == Tsoa)
 							continue;
-
 						r = *rp;
 						r.next = 0;
 						reply(1, repp, req);
@@ -295,8 +299,10 @@ dnzone(DNSmsg *reqp, DNSmsg *repp, Request *req)
 	repp->an = rrlookup(dp, Tsoa, NOneg);
 	reply(1, repp, req);
 	rrfreelist(repp->an);
+	repp->an = nil;
 out:
 	rrfree(repp->qd);
+	repp->qd = nil;
 }
 
 static void
@@ -309,7 +315,7 @@ getcaller(char *dir)
 	fd = open(remote, OREAD);
 	if(fd < 0)
 		return;
-	n = read(fd, remote, sizeof(remote)-1);
+	n = read(fd, remote, sizeof remote - 1);
 	close(fd);
 	if(n <= 0)
 		return;
@@ -327,14 +333,14 @@ refreshmain(char *net)
 
 	snprint(file, sizeof(file), "%s/dns", net);
 	if(debug)
-		syslog(0, logfile, "refreshing %s", file);
+		dnslog("refreshing %s", file);
 	fd = open(file, ORDWR);
-	if(fd < 0){
-		syslog(0, logfile, "can't refresh %s", file);
-		return;
+	if(fd < 0)
+		dnslog("can't refresh %s", file);
+	else {
+		fprint(fd, "refresh");
+		close(fd);
 	}
-	fprint(fd, "refresh");
-	close(fd);
 }
 
 /*
@@ -345,21 +351,20 @@ logreply(int id, uchar *addr, DNSmsg *mp)
 {
 	RR *rp;
 
-	syslog(0, LOG, "%d: rcvd %I flags:%s%s%s%s%s", id, addr,
-		mp->flags & Fauth ? " auth" : "",
-		mp->flags & Ftrunc ? " trunc" : "",
-		mp->flags & Frecurse ? " rd" : "",
-		mp->flags & Fcanrec ? " ra" : "",
-		mp->flags & (Fauth|Rname) == (Fauth|Rname) ?
-		" nx" : "");
+	dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr,
+		mp->flags & Fauth? " auth": "",
+		mp->flags & Ftrunc? " trunc": "",
+		mp->flags & Frecurse? " rd": "",
+		mp->flags & Fcanrec? " ra": "",
+		(mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
 	for(rp = mp->qd; rp != nil; rp = rp->next)
-		syslog(0, LOG, "%d: rcvd %I qd %s", id, addr, rp->owner->name);
+		dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name);
 	for(rp = mp->an; rp != nil; rp = rp->next)
-		syslog(0, LOG, "%d: rcvd %I an %R", id, addr, rp);
+		dnslog("%d: rcvd %I an %R", id, addr, rp);
 	for(rp = mp->ns; rp != nil; rp = rp->next)
-		syslog(0, LOG, "%d: rcvd %I ns %R", id, addr, rp);
+		dnslog("%d: rcvd %I ns %R", id, addr, rp);
 	for(rp = mp->ar; rp != nil; rp = rp->next)
-		syslog(0, LOG, "%d: rcvd %I ar %R", id, addr, rp);
+		dnslog("%d: rcvd %I ar %R", id, addr, rp);
 }
 
 void
@@ -367,7 +372,7 @@ logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
 {
 	char buf[12];
 
-	syslog(0, LOG, "%d.%d: sending to %I/%s %s %s",
+	dnslog("%d.%d: sending to %I/%s %s %s",
 		id, subid, addr, sname, rname, rrname(type, buf, sizeof buf));
 }
 

+ 54 - 47
sys/src/cmd/ndb/dnudpserver.c

@@ -6,8 +6,6 @@
 static int	udpannounce(char*);
 static void	reply(int, uchar*, DNSmsg*, Request*);
 
-extern char *logfile;
-
 static void
 ding(void *x, char *msg)
 {
@@ -40,10 +38,10 @@ clientrxmit(DNSmsg *req, uchar *buf)
 	OUdphdr *uh;
 
 	uh = (OUdphdr *)buf;
-	empty = 0;
+	empty = nil;
 	for(p = inprog; p < &inprog[Maxactive]; p++){
 		if(p->inuse == 0){
-			if(empty == 0)
+			if(empty == nil)
 				empty = p;
 			continue;
 		}
@@ -51,10 +49,10 @@ clientrxmit(DNSmsg *req, uchar *buf)
 		if(req->qd->owner == p->owner)
 		if(req->qd->type == p->type)
 		if(memcmp(uh, &p->uh, OUdphdrsize) == 0)
-			return 0;
+			return nil;
 	}
-	if(empty == 0)
-		return 0;	/* shouldn't happen - see slave() and definition of Maxactive */
+	if(empty == nil)
+		return nil; /* shouldn't happen: see slave() & Maxactive def'n */
 
 	empty->id = req->id;
 	empty->owner = req->qd->owner;
@@ -70,13 +68,13 @@ clientrxmit(DNSmsg *req, uchar *buf)
 void
 dnudpserver(char *mntpt)
 {
-	int fd, len, op;
-	Request req;
-	DNSmsg reqmsg, repmsg;
+	int fd, len, op, rcode;
 	uchar buf[OUdphdrsize + Maxudp + 1024];
 	char *err;
-	Inprogress *p;
 	char tname[32];
+	Request req;
+	DNSmsg reqmsg, repmsg;
+	Inprogress *p;
 	OUdphdr *uh;
 
 	/* fork sharing text, data, and bss with parent */
@@ -92,67 +90,78 @@ dnudpserver(char *mntpt)
 	fd = -1;
 	notify(ding);
 restart:
+	procsetname("udp server announcing");
 	if(fd >= 0)
 		close(fd);
 	while((fd = udpannounce(mntpt)) < 0)
 		sleep(5000);
+
+	procsetname("udp server loop");
+	memset(&req, 0, sizeof req);
 	if(setjmp(req.mret))
 		putactivity(0);
 	req.isslave = 0;
+	req.id = 0;
+	req.aborttime = 0;
 
 	/* loop on requests */
 	for(;; putactivity(0)){
-		memset(&repmsg, 0, sizeof(repmsg));
-		memset(&reqmsg, 0, sizeof(reqmsg));
+		memset(&repmsg, 0, sizeof repmsg);
+		memset(&reqmsg, 0, sizeof reqmsg);
 		alarm(60*1000);
-		len = read(fd, buf, sizeof(buf));
+		len = read(fd, buf, sizeof buf);
 		alarm(0);
 		if(len <= OUdphdrsize)
 			goto restart;
 		uh = (OUdphdr*)buf;
 		len -= OUdphdrsize;
+		// dnslog("read received UDP from %I to %I",
+		//	((OUdphdr*)buf)->raddr, ((OUdphdr*)buf)->laddr);
 		getactivity(&req, 0);
-		req.aborttime = now + 30;	/* don't spend more than 30 seconds */
-		err = convM2DNS(&buf[OUdphdrsize], len, &reqmsg);
+		req.aborttime = now + Maxreqtm;
+		rcode = 0;
+		err = convM2DNS(&buf[OUdphdrsize], len, &reqmsg, &rcode);
 		if(err){
-			syslog(0, logfile, "server: input error: %s from %I", err, buf);
+			/* first bytes in buf are source IP addr */
+			dnslog("server: input error: %s from %I", err, buf);
 			continue;
 		}
-		if(reqmsg.qdcount < 1){
-			syslog(0, logfile, "server: no questions from %I", buf);
-			goto freereq;
-		}
-		if(reqmsg.flags & Fresp){
-			syslog(0, logfile, "server: reply not request from %I", buf);
-			goto freereq;
-		}
+		if (rcode == 0)
+			if(reqmsg.qdcount < 1){
+				dnslog("server: no questions from %I", buf);
+				goto freereq;
+			} else if(reqmsg.flags & Fresp){
+				dnslog("server: reply not request from %I", buf);
+				goto freereq;
+			}
 		op = reqmsg.flags & Omask;
 		if(op != Oquery && op != Onotify){
-			syslog(0, logfile, "server: op %d from %I", reqmsg.flags & Omask, buf);
+			dnslog("server: op %d from %I",
+				reqmsg.flags & Omask, buf);
 			goto freereq;
 		}
 
 		if(debug || (trace && subsume(trace, reqmsg.qd->owner->name))){
-			syslog(0, logfile, "%d: serve (%I/%d) %d %s %s",
-				req.id, buf, ((uh->rport[0])<<8)+uh->rport[1],
+			dnslog("%d: serve (%I/%d) %d %s %s",
+				req.id, buf, uh->rport[0]<<8 | uh->rport[1],
 				reqmsg.id,
 				reqmsg.qd->owner->name,
 				rrname(reqmsg.qd->type, tname, sizeof tname));
 		}
 
 		p = clientrxmit(&reqmsg, buf);
-		if(p == 0){
+		if(p == nil){
 			if(debug)
-				syslog(0, logfile, "%d: duplicate", req.id);
+				dnslog("%d: duplicate", req.id);
 			goto freereq;
 		}
 
 		/* loop through each question */
 		while(reqmsg.qd){
-			memset(&repmsg, 0, sizeof(repmsg));
+			memset(&repmsg, 0, sizeof repmsg);
 			switch(op){
 			case Oquery:
-				dnserver(&reqmsg, &repmsg, &req);
+				dnserver(&reqmsg, &repmsg, &req, buf, rcode);
 				break;
 			case Onotify:
 				dnnotify(&reqmsg, &repmsg, &req);
@@ -166,7 +175,6 @@ restart:
 		}
 
 		p->inuse = 0;
-
 freereq:
 		rrfreelist(reqmsg.qd);
 		rrfreelist(reqmsg.an);
@@ -177,7 +185,6 @@ freereq:
 			putactivity(0);
 			_exits(0);
 		}
-
 	}
 }
 
@@ -190,10 +197,9 @@ static char *ohmsg = "oldheaders";
 static int
 udpannounce(char *mntpt)
 {
-	static int whined;
 	int data, ctl;
-	char dir[64];
-	char datafile[64+6];
+	char dir[64], datafile[64+6];
+	static int whined;
 
 	/* get a udp port */
 	sprint(datafile, "%s/udp!*!dns", mntpt);
@@ -207,7 +213,7 @@ udpannounce(char *mntpt)
 
 	/* turn on header style interface */
 	if(write(ctl, hmsg, strlen(hmsg)) , 0)
-		abort(); /* hmsg */;
+		abort();			/* hmsg */
 	write(ctl, ohmsg, strlen(ohmsg));
 	data = open(datafile, ORDWR);
 	if(data < 0){
@@ -229,24 +235,25 @@ reply(int fd, uchar *buf, DNSmsg *rep, Request *reqp)
 	RR *rp;
 
 	if(debug || (trace && subsume(trace, rep->qd->owner->name)))
-		syslog(0, logfile, "%d: reply (%I/%d) %d %s %s an %R ns %R ar %R",
-			reqp->id, buf, ((buf[4])<<8)+buf[5],
+		dnslog("%d: reply (%I/%d) %d %s %s qd %R an %R ns %R ar %R",
+			reqp->id, buf, buf[4]<<8 | buf[5],
 			rep->id, rep->qd->owner->name,
-			rrname(rep->qd->type, tname, sizeof tname), rep->an, rep->ns, rep->ar);
+			rrname(rep->qd->type, tname, sizeof tname),
+			rep->qd, rep->an, rep->ns, rep->ar);
 
 	len = convDNS2M(rep, &buf[OUdphdrsize], Maxudp);
 	if(len <= 0){
-		syslog(0, logfile, "error converting reply: %s %d", rep->qd->owner->name,
-			rep->qd->type);
+		dnslog("error converting reply: %s %d",
+			rep->qd->owner->name, rep->qd->type);
 		for(rp = rep->an; rp; rp = rp->next)
-			syslog(0, logfile, "an %R", rp);
+			dnslog("an %R", rp);
 		for(rp = rep->ns; rp; rp = rp->next)
-			syslog(0, logfile, "ns %R", rp);
+			dnslog("ns %R", rp);
 		for(rp = rep->ar; rp; rp = rp->next)
-			syslog(0, logfile, "ar %R", rp);
+			dnslog("ar %R", rp);
 		return;
 	}
 	len += OUdphdrsize;
 	if(write(fd, buf, len) != len)
-		syslog(0, logfile, "error sending reply: %r");
+		dnslog("error sending reply: %r");
 }

+ 0 - 26
sys/src/cmd/ndb/time.c

@@ -1,26 +0,0 @@
-#include <u.h>
-#include <libc.h>
-
-static Lock tlock;
-
-long
-time(long *tp)
-{
-	char b[20];
-	static int f = -1;
-	long t;
-
-	lock(&tlock);
-	memset(b, 0, sizeof(b));
-	f = open("/dev/time", OREAD|OCEXEC);
-	if(f >= 0) {
-		seek(f, 0, 0);
-		read(f, b, sizeof(b));
-	}
-	t = atol(b);
-	if(tp)
-		*tp = t;
-	unlock(&tlock);
-
-	return t;
-}

Some files were not shown because too many files changed in this diff