From 0e5b2871ca6456b01d4bf037a6e68badf1ff1a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henryk=20Pl=C3=B6tz?= Date: Fri, 3 Oct 2014 19:58:52 +0200 Subject: Initial commit of djbdns-1.05.tar.gz Source was http://cr.yp.to/djbdns/djbdns-1.05.tar.gz, SHA1 2efdb3a039d0c548f40936aa9cb30829e0ce8c3d --- CHANGES | 376 +++++++++++++++++++ FILES | 243 ++++++++++++ Makefile | 1106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ README | 7 + SYSDEPS | 10 + TARGETS | 216 +++++++++++ TINYDNS | 25 ++ TODO | 12 + VERSION | 1 + alloc.c | 31 ++ alloc.h | 8 + alloc_re.c | 17 + auto-str.c | 40 ++ auto_home.h | 6 + axfr-get.c | 373 +++++++++++++++++++ axfrdns-conf.c | 71 ++++ axfrdns.c | 378 +++++++++++++++++++ buffer.c | 10 + buffer.h | 59 +++ buffer_1.c | 5 + buffer_2.c | 5 + buffer_copy.c | 16 + buffer_get.c | 67 ++++ buffer_put.c | 88 +++++ buffer_read.c | 7 + buffer_write.c | 7 + byte.h | 13 + byte_chr.c | 20 + byte_copy.c | 14 + byte_cr.c | 16 + byte_diff.c | 16 + byte_zero.c | 13 + cache.c | 207 +++++++++++ cache.h | 12 + cachetest.c | 32 ++ case.h | 13 + case_diffb.c | 18 + case_diffs.c | 17 + case_lowerb.c | 12 + cdb.c | 136 +++++++ cdb.h | 37 ++ cdb_hash.c | 21 ++ cdb_make.c | 152 ++++++++ cdb_make.h | 39 ++ chkshsgr.c | 10 + choose.sh | 18 + conf-cc | 3 + conf-home | 4 + conf-ld | 3 + dd.c | 36 ++ dd.h | 6 + direntry.h1 | 10 + direntry.h2 | 10 + dns.h | 84 +++++ dns_dfd.c | 69 ++++ dns_domain.c | 74 ++++ dns_dtda.c | 35 ++ dns_ip.c | 75 ++++ dns_ipq.c | 71 ++++ dns_mx.c | 49 +++ dns_name.c | 48 +++ dns_nd.c | 24 ++ dns_packet.c | 77 ++++ dns_random.c | 63 ++++ dns_rcip.c | 86 +++++ dns_rcrw.c | 131 +++++++ dns_resolve.c | 29 ++ dns_sortip.c | 20 + dns_transmit.c | 366 ++++++++++++++++++ dns_txt.c | 59 +++ dnscache-conf.c | 169 +++++++++ dnscache.c | 447 ++++++++++++++++++++++ dnsfilter.c | 214 +++++++++++ dnsip.c | 40 ++ dnsipq.c | 43 +++ dnsmx.c | 64 ++++ dnsname.c | 34 ++ dnsq.c | 98 +++++ dnsqr.c | 66 ++++ dnsroots.global | 13 + dnstrace.c | 474 ++++++++++++++++++++++++ dnstracesort.sh | 51 +++ dnstxt.c | 33 ++ droproot.c | 33 ++ droproot.h | 6 + env.c | 15 + env.h | 8 + error.c | 123 +++++++ error.h | 27 ++ error_str.c | 267 ++++++++++++++ exit.h | 6 + find-systype.sh | 143 +++++++ fmt.h | 25 ++ fmt_ulong.c | 13 + gen_alloc.h | 7 + gen_allocdefs.h | 34 ++ generic-conf.c | 99 +++++ generic-conf.h | 20 + getln.c | 14 + getln.h | 10 + getln2.c | 24 ++ hasdevtcp.h1 | 1 + hasdevtcp.h2 | 2 + hasshsgr.h1 | 1 + hasshsgr.h2 | 2 + hier.c | 42 +++ install.c | 151 ++++++++ instcheck.c | 108 ++++++ iopause.c | 76 ++++ iopause.h1 | 19 + iopause.h2 | 18 + ip4.h | 9 + ip4_fmt.c | 18 + ip4_scan.c | 19 + log.c | 288 +++++++++++++++ log.h | 36 ++ ndelay.h | 7 + ndelay_off.c | 12 + ndelay_on.c | 12 + okclient.c | 26 ++ okclient.h | 6 + open.h | 10 + open_read.c | 6 + open_trunc.c | 6 + openreadclose.c | 16 + openreadclose.h | 8 + parsetype.c | 31 ++ parsetype.h | 6 + pickdns-conf.c | 66 ++++ pickdns-data.c | 230 ++++++++++++ pickdns.c | 101 +++++ printpacket.c | 90 +++++ printpacket.h | 8 + printrecord.c | 115 ++++++ printrecord.h | 9 + prot.c | 19 + prot.h | 7 + qlog.c | 63 ++++ qlog.h | 8 + query.c | 851 ++++++++++++++++++++++++++++++++++++++++++ query.h | 32 ++ random-ip.c | 80 ++++ rbldns-conf.c | 71 ++++ rbldns-data.c | 128 +++++++ rbldns.c | 116 ++++++ readclose.c | 21 ++ readclose.h | 9 + response.c | 121 ++++++ response.h | 27 ++ roots.c | 127 +++++++ roots.h | 8 + rts.exp | 1072 +++++++++++++++++++++++++++++++++++++++++++++++++++++ rts.sh | 1 + rts.tests | 767 ++++++++++++++++++++++++++++++++++++++ scan.h | 28 ++ scan_ulong.c | 14 + seek.h | 15 + seek_set.c | 7 + select.h1 | 10 + select.h2 | 11 + server.c | 116 ++++++ sgetopt.c | 51 +++ sgetopt.h | 21 ++ socket.h | 22 ++ socket_accept.c | 21 ++ socket_bind.c | 33 ++ socket_conn.c | 33 ++ socket_listen.c | 10 + socket_recv.c | 21 ++ socket_send.c | 18 + socket_tcp.c | 17 + socket_udp.c | 17 + str.h | 14 + str_chr.c | 17 + str_diff.c | 15 + str_len.c | 14 + str_rchr.c | 20 + str_start.c | 13 + stralloc.h | 29 ++ stralloc_cat.c | 7 + stralloc_catb.c | 12 + stralloc_cats.c | 8 + stralloc_copy.c | 7 + stralloc_eady.c | 6 + stralloc_num.c | 29 ++ stralloc_opyb.c | 11 + stralloc_opys.c | 8 + stralloc_pend.c | 5 + strerr.h | 78 ++++ strerr_die.c | 31 ++ strerr_sys.c | 12 + subgetopt.c | 65 ++++ subgetopt.h | 24 ++ tai.h | 26 ++ tai_add.c | 6 + tai_now.c | 7 + tai_pack.c | 16 + tai_sub.c | 6 + tai_uint.c | 6 + tai_unpack.c | 16 + taia.h | 34 ++ taia_add.c | 18 + taia_approx.c | 6 + taia_frac.c | 6 + taia_less.c | 12 + taia_now.c | 12 + taia_pack.c | 20 + taia_sub.c | 21 ++ taia_tai.c | 6 + taia_uint.c | 10 + tdlookup.c | 310 ++++++++++++++++ timeoutread.c | 28 ++ timeoutread.h | 6 + timeoutwrite.c | 28 ++ timeoutwrite.h | 6 + tinydns-conf.c | 98 +++++ tinydns-data.c | 456 +++++++++++++++++++++++ tinydns-edit.c | 257 +++++++++++++ tinydns-get.c | 76 ++++ tinydns.c | 11 + trycpp.c | 7 + trydrent.c | 8 + trylsock.c | 4 + trypoll.c | 18 + tryshsgr.c | 14 + trysysel.c | 8 + tryulong32.c | 11 + tryulong64.c | 11 + uint16.h | 11 + uint16_pack.c | 13 + uint16_unpack.c | 23 ++ uint32.h1 | 11 + uint32.h2 | 11 + uint32_pack.c | 21 ++ uint32_unpack.c | 31 ++ uint64.h1 | 8 + uint64.h2 | 8 + utime.c | 24 ++ walldns-conf.c | 58 +++ walldns.c | 57 +++ warn-auto.sh | 2 + warn-shsgr | 3 + x86cpuid.c | 38 ++ 243 files changed, 15929 insertions(+) create mode 100644 CHANGES create mode 100644 FILES create mode 100644 Makefile create mode 100644 README create mode 100644 SYSDEPS create mode 100644 TARGETS create mode 100644 TINYDNS create mode 100644 TODO create mode 100644 VERSION create mode 100644 alloc.c create mode 100644 alloc.h create mode 100644 alloc_re.c create mode 100644 auto-str.c create mode 100644 auto_home.h create mode 100644 axfr-get.c create mode 100644 axfrdns-conf.c create mode 100644 axfrdns.c create mode 100644 buffer.c create mode 100644 buffer.h create mode 100644 buffer_1.c create mode 100644 buffer_2.c create mode 100644 buffer_copy.c create mode 100644 buffer_get.c create mode 100644 buffer_put.c create mode 100644 buffer_read.c create mode 100644 buffer_write.c create mode 100644 byte.h create mode 100644 byte_chr.c create mode 100644 byte_copy.c create mode 100644 byte_cr.c create mode 100644 byte_diff.c create mode 100644 byte_zero.c create mode 100644 cache.c create mode 100644 cache.h create mode 100644 cachetest.c create mode 100644 case.h create mode 100644 case_diffb.c create mode 100644 case_diffs.c create mode 100644 case_lowerb.c create mode 100644 cdb.c create mode 100644 cdb.h create mode 100644 cdb_hash.c create mode 100644 cdb_make.c create mode 100644 cdb_make.h create mode 100644 chkshsgr.c create mode 100644 choose.sh create mode 100644 conf-cc create mode 100644 conf-home create mode 100644 conf-ld create mode 100644 dd.c create mode 100644 dd.h create mode 100644 direntry.h1 create mode 100644 direntry.h2 create mode 100644 dns.h create mode 100644 dns_dfd.c create mode 100644 dns_domain.c create mode 100644 dns_dtda.c create mode 100644 dns_ip.c create mode 100644 dns_ipq.c create mode 100644 dns_mx.c create mode 100644 dns_name.c create mode 100644 dns_nd.c create mode 100644 dns_packet.c create mode 100644 dns_random.c create mode 100644 dns_rcip.c create mode 100644 dns_rcrw.c create mode 100644 dns_resolve.c create mode 100644 dns_sortip.c create mode 100644 dns_transmit.c create mode 100644 dns_txt.c create mode 100644 dnscache-conf.c create mode 100644 dnscache.c create mode 100644 dnsfilter.c create mode 100644 dnsip.c create mode 100644 dnsipq.c create mode 100644 dnsmx.c create mode 100644 dnsname.c create mode 100644 dnsq.c create mode 100644 dnsqr.c create mode 100644 dnsroots.global create mode 100644 dnstrace.c create mode 100644 dnstracesort.sh create mode 100644 dnstxt.c create mode 100644 droproot.c create mode 100644 droproot.h create mode 100644 env.c create mode 100644 env.h create mode 100644 error.c create mode 100644 error.h create mode 100644 error_str.c create mode 100644 exit.h create mode 100644 find-systype.sh create mode 100644 fmt.h create mode 100644 fmt_ulong.c create mode 100644 gen_alloc.h create mode 100644 gen_allocdefs.h create mode 100644 generic-conf.c create mode 100644 generic-conf.h create mode 100644 getln.c create mode 100644 getln.h create mode 100644 getln2.c create mode 100644 hasdevtcp.h1 create mode 100644 hasdevtcp.h2 create mode 100644 hasshsgr.h1 create mode 100644 hasshsgr.h2 create mode 100644 hier.c create mode 100644 install.c create mode 100644 instcheck.c create mode 100644 iopause.c create mode 100644 iopause.h1 create mode 100644 iopause.h2 create mode 100644 ip4.h create mode 100644 ip4_fmt.c create mode 100644 ip4_scan.c create mode 100644 log.c create mode 100644 log.h create mode 100644 ndelay.h create mode 100644 ndelay_off.c create mode 100644 ndelay_on.c create mode 100644 okclient.c create mode 100644 okclient.h create mode 100644 open.h create mode 100644 open_read.c create mode 100644 open_trunc.c create mode 100644 openreadclose.c create mode 100644 openreadclose.h create mode 100644 parsetype.c create mode 100644 parsetype.h create mode 100644 pickdns-conf.c create mode 100644 pickdns-data.c create mode 100644 pickdns.c create mode 100644 printpacket.c create mode 100644 printpacket.h create mode 100644 printrecord.c create mode 100644 printrecord.h create mode 100644 prot.c create mode 100644 prot.h create mode 100644 qlog.c create mode 100644 qlog.h create mode 100644 query.c create mode 100644 query.h create mode 100644 random-ip.c create mode 100644 rbldns-conf.c create mode 100644 rbldns-data.c create mode 100644 rbldns.c create mode 100644 readclose.c create mode 100644 readclose.h create mode 100644 response.c create mode 100644 response.h create mode 100644 roots.c create mode 100644 roots.h create mode 100644 rts.exp create mode 100644 rts.sh create mode 100644 rts.tests create mode 100644 scan.h create mode 100644 scan_ulong.c create mode 100644 seek.h create mode 100644 seek_set.c create mode 100644 select.h1 create mode 100644 select.h2 create mode 100644 server.c create mode 100644 sgetopt.c create mode 100644 sgetopt.h create mode 100644 socket.h create mode 100644 socket_accept.c create mode 100644 socket_bind.c create mode 100644 socket_conn.c create mode 100644 socket_listen.c create mode 100644 socket_recv.c create mode 100644 socket_send.c create mode 100644 socket_tcp.c create mode 100644 socket_udp.c create mode 100644 str.h create mode 100644 str_chr.c create mode 100644 str_diff.c create mode 100644 str_len.c create mode 100644 str_rchr.c create mode 100644 str_start.c create mode 100644 stralloc.h create mode 100644 stralloc_cat.c create mode 100644 stralloc_catb.c create mode 100644 stralloc_cats.c create mode 100644 stralloc_copy.c create mode 100644 stralloc_eady.c create mode 100644 stralloc_num.c create mode 100644 stralloc_opyb.c create mode 100644 stralloc_opys.c create mode 100644 stralloc_pend.c create mode 100644 strerr.h create mode 100644 strerr_die.c create mode 100644 strerr_sys.c create mode 100644 subgetopt.c create mode 100644 subgetopt.h create mode 100644 tai.h create mode 100644 tai_add.c create mode 100644 tai_now.c create mode 100644 tai_pack.c create mode 100644 tai_sub.c create mode 100644 tai_uint.c create mode 100644 tai_unpack.c create mode 100644 taia.h create mode 100644 taia_add.c create mode 100644 taia_approx.c create mode 100644 taia_frac.c create mode 100644 taia_less.c create mode 100644 taia_now.c create mode 100644 taia_pack.c create mode 100644 taia_sub.c create mode 100644 taia_tai.c create mode 100644 taia_uint.c create mode 100644 tdlookup.c create mode 100644 timeoutread.c create mode 100644 timeoutread.h create mode 100644 timeoutwrite.c create mode 100644 timeoutwrite.h create mode 100644 tinydns-conf.c create mode 100644 tinydns-data.c create mode 100644 tinydns-edit.c create mode 100644 tinydns-get.c create mode 100644 tinydns.c create mode 100644 trycpp.c create mode 100644 trydrent.c create mode 100644 trylsock.c create mode 100644 trypoll.c create mode 100644 tryshsgr.c create mode 100644 trysysel.c create mode 100644 tryulong32.c create mode 100644 tryulong64.c create mode 100644 uint16.h create mode 100644 uint16_pack.c create mode 100644 uint16_unpack.c create mode 100644 uint32.h1 create mode 100644 uint32.h2 create mode 100644 uint32_pack.c create mode 100644 uint32_unpack.c create mode 100644 uint64.h1 create mode 100644 uint64.h2 create mode 100644 utime.c create mode 100644 walldns-conf.c create mode 100644 walldns.c create mode 100644 warn-auto.sh create mode 100644 warn-shsgr create mode 100644 x86cpuid.c diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..2442a0c --- /dev/null +++ b/CHANGES @@ -0,0 +1,376 @@ +19991129 + version: dnscache 0.50, alpha. not released yet. +19991223 + version: dnscache 0.60, alpha. +19991224 + internal: dns_sortip() takes length argument. + api: dns_ip4() sorts output. currently this means just random. + api: added socket_bind4_reuse(). removed reuse from bind4(). + ui: used bind4_reuse() for port 53, bind4() otherwise. + internal: eliminated some unused variables. + internal: prototypes in cdb.h, cdbmake.h, cdbmss.h. + internal: prototypes in case.h, env.h, fmt.h, scan.h, str.h. + internal: prototypes in stralloc.h. + internal: prototypes in error.h, strerr.h. + internal: prototypes in ndelay.h, open.h, seek.h. + internal: prototypes in sgetopt.h, subgetopt.h. + internal: prototypes in tai.h, taia.h. + internal: added some missing declarations. + bug: query.c checked void response_finishanswer() return code. + impact: cached responses were dropped on systems that + didn't follow the traditional C return behavior. fix: + obvious. tnx Giles Lean. + internal: switched from taia_addsec() to taia_uint(). + api: switched to uint16 for socket_* port numbers. + internal: integrated uint16_pack() and friends. + ui: dnscache allows (recursive) queries from port 53. + ui: dnscache has 10-second idle timer on TCP read/write. + ui: dnscache limits itself to 20 concurrent TCP connections. + internal: moved dns_domain_fromdot() to separate file. + ui: supported \X, \1, \12, \123 in dns_domain_fromdot(). + ui: supported \123 in dns_domain_todot_append(). + version: dnscache 0.61, alpha. +19991230 + api: added dns_ip4_qualify(). + api: added dns_resolvconfrewrite(). + ui: added dnsipq. + api: dns_ip4() checks for (strings of) IP addresses. +20000106 + port: Solaris needs /dev/udp, not just /dev/tcp. impact: + dnscache and tinydns would stop immediately under + Solaris. fix: create /dev/udp in configure; and have + tinydns create socket before chroot. tnx Louis Theran. + internal: moved dns_name4_domain() to dns_nd.c. + ui: tinydns no longer excludes screwy queries from its log. + internal: moved respond() to tdlookup.c under new name. + ui: added tinydns-get. + ui: rewrote tinydns-data for new data format. + internal: expanded rts to cover tinydns-data using tinydns-get. +20000107 + ui: tinydns-data allows arbitrary case in domain names. + ui: dnscache supports preconfigured servers for non-root + domains. + ui: dnscache uses textual addresses for preconfigured servers. +20000108 + ui: tinydns-data excludes the additional and authority sections + if doing so helps meet the 512-byte UDP limit. + version: dnscache 0.70, beta. +20000114 + internal: in log.c, ulong() now prints a uint64. + internal: added cache_motion, query_count, log_stats. + ui: dnscache now prints queries/motion stats after typical + response packets. +20000115 + internal: added droproot.c. used in tinydns and dnscache. + internal: moved tinydns log() to qlog.c under new name. + ui: added walldns, configure-wd. + ui: configure-td now creates an empty root/data. + ui: added tinydns-edit. + ui: configure-td now sets up root/add-{ns,childns,host,mx}. +20000116 + ui: renamed configure* as *-conf. + ui: added axfrdns, axfrdns-conf. + ui: added axfr-get. + ui: dnscache-conf 10.* or 192.168.* now sets IPSEND=0.0.0.0. +20000117 + ui: added pickdns, pickdns-conf, pickdns-data. + version: dnscache 0.75, beta. +20000118 + internal: address* -> address_* in pickdns-data.c. + internal: start writing cdb earlier in pickdns-data.c. + internal: keep track of namelen in pickdns-data.c. + ui: added client-location variability to pickdns, pickdns-data. + ui: qlog logs short packets. + ui: qlog logs header if RD or other unusual bits are set. + ui: qlog logs non-Internet classes. + api: dns_domain_todot_append() -> dns_domain_todot_cat(). + ui: axfr-get prints A records more nicely. tnx Russ Nelson. + ui: tinydns, pickdns, and walldns respond REFUSED to multiple + queries, strange classes, and strange header bits. + pickdns and walldns also respond REFUSED to unrecognized + domain names. +20000120 + ui: dns_resolvconfip() and dns_resolvconfrewrite() reread after + 10 minutes or 10000 uses. + ui: dns_resolvconfrewrite() treats "domain" like "search". + ui: dns_resolvconfrewrite() supports $LOCALDOMAIN. + ui: dns_resolvconfrewrite() supports gethostname(). + api: dns_ip4_qualify() -> dns_ip4_qualify_rules(). new function + under the old name uses dns_resolvconfrewrite(). + internal: cleaned up log.h. +20000121 + port: the gcc 2.95.2 -O2 optimizer can destroy parameters in a + function that calls another function with a long long + argument. impact: gcc 2.95.2 kills dnscache in + log_query(). fix: pass log_stats() inputs by reference, + and pass uint64's through a variable inside log.c. + internal: introduced x_* in axfr-get. + internal: more format verification in axfr-get. + ui: minimal Z support in tinydns-data. + ui: axfr-get prints Z lines. + ui: juggled axfr-get to support BIND 8's many-answers option. + ui: axfr-get prints common characters readably rather than in + octal. tnx Karsten Thygesen. + ui: install copies VERSION into .../etc. +20000122 + ui: dns_domain_todot_cat() now lowercases everything. + internal: split printrecord.c out of tinydns-get. + ui: added dnstrace. +20000123 + version: dnscache 0.76, beta. +20000124 + port: Solaris needs socket libraries for dnstrace. impact: + couldn't compile under Solaris. fix: use socket.lib. + tnx Karsten Thygesen. +20000126 + ui: dns_resolvconfip() supports $DNSCACHEIP. + ui: changed tinydns-get arg order. + internal: split printpacket.c out of tinydns-get. + ui: added dnsquery. + internal: merged case.a, fs.a, str.a, uint.a, ip4.a into byte.a. + internal: merged strerr.a into buffer.a. + internal: merged stralloc.a, getln.a into alloc.a. + internal: merged error.a, open.a, seek.a, ndelay.a, socket.a + into unix.a. + internal: used catulong in axfr-get.c. + ui: packet-parsing errors produce error_proto. + ui: axfr-get goes out of its way to reject wildcards. + internal: introduced generic-conf.c. + internal: upgraded timeoutread and timeoutwrite to iopause. +20000127 + ui: revamped details of the log formats. + ui: full Z support in tinydns-data. + ui: axfr-get accepts authority records and additional records. + ui: axfrdns tries to imitate BIND's handling of glue. + internal: expanded rts to try out the servers and *-conf. + ui: added rbldns. +20000128 + ui: increased MAXNS to 16 in query.h. +20000129 + version: DNScache 0.80, beta. +20000205 + ui: tinydns-data supports ^, for the benefit of people stuck + behind reverse CNAMEs. tnx Petr Novotny. +20000206 + ui: rbldns supports $. + ui: tinydns-data supports C. CNAME is overridden by NS; CNAME + overrides other records; no multiple CNAMEs. + ui: axfr-get supports C. + ui: axfr-get no longer rejects wildcards, except for NS. + internal: eliminated flagempty from tinydns-data. + internal: cleaned up delegation/NXDOMAIN loops in tinydns-data. + internal: reorganized packet_start interface in tinydns-data. + ui: tinydns-data supports BIND-style wildcards, except for NS. + version: DNScache 0.81, beta. +20000207 + ui: renamed dnsquery as dnsq, to eliminate name conflict with + Beecher dnsquery program. tnx Anand Buddhdev. +20000208 + ui: tinydns-edit supports add alias. + ui: tinydns-conf sets up root/add-alias. +20000209 + ui: dnscache-conf now sets IPSEND=0.0.0.0 in all cases. + ui: dnsq and dnstrace allow server names. + ui: dnsq and dnstrace allow type names. +20000210 + internal: response_tc() reduces len, simplifying udprespond(). + ui: response_tc() now truncates immediately after query. this + should work around the Squid parsing bug reported by + Stuart Henderson. +20000211 + ui: tinydns-get allows type names. + ui: tinydns-data prints query name for >512 error. tnx Uwe Ohse. + version: DNScache 0.82, beta. +20000212 + ui: dns_transmit starts with loop 1 for recursive queries. + ui: dnscache tries to allocate 128K of incoming UDP buffer + space. tnx Jeremy Hansen. +20000213 + ui: tinydns tries to allocate 64K of incoming UDP buffer space. + internal: renamed response_*answer as response_r*. + internal: expanded response_rfinish to allow au and ar. + internal: expanded response_rstart to allow any ttl. + internal: rewrote tinydns-data, tinydns, tinydns-get, axfrdns + for compact new data.cdb format. a few ui effects: empty + nodes produce NXDOMAIN; wildcards affect empty nodes. + ui: response_addname() tries more extensive compression. +20000215 + ui: tinydns-edit takes fn arguments. tnx Jason R. Mastaler. +20000218 + internal: upgraded to new cdb library. + internal: added globalip(). + ui: dnscache assigns IP addresses to dotted-decimal domain + names in canonical form. + internal: merged handling of C and ^ in tinydns-data. + port: FreeBSD 3.4-RELEASE poll() doesn't think that regular + files are readable. impact: under FreeBSD 3.4-RELEASE, + dnsfilter hangs waiting to read from regular files. tnx + Kenji Rikitake. fix: check for this bug in trypoll.c. +20000219 + ui: tinydns-data supports time-to-die. + ui: changed home directory from /usr/local/dnscache to + /usr/local; moved @ from home/etc to home/etc/dnscache. + internal: reorganized response.c. +20000220 + ui: tinydns-data allows omitted numeric fields in Z lines. tnx + Timothy L. Mayo. + version: DNScache 0.85, beta. +20000222 + ui: dns_transmit_get() pauses after server failure, if udploop + is 2. + internal: sped up name handling in response.c. +20000223 + ui: dnscache ignores some garbage in queries: AA, !RD, RA, Z, + RCODE, AN, AU, AR. (note that responses still say RD.) + this allows bogus queries from Ultrix versions of BIND. + internal: split dd.c out of query.c. + internal: split server.c out of tinydns. + internal: rewrote walldns, pickdns, rbldns to use server.c. + ui: server.c allows some garbage in queries: RA, Z, RCODE, AN, + AU, AR. + ui: axfrdns logs packets. + ui: walldns supports dotted-decimal IP addresses. +20000224 + ui: revamped qlog, again. + ui: better error message in dnscache-conf.c. tnx Chris Johnson. +20000225 + version: DNScache 0.90, gamma. +20000226 + internal: dnscache-conf sets up dnscache/run to avoid env. tnx + Chris Cappuccio. +20000227 + ui: tinydns-data uses server name instead of a.ns.domain for + automatic primary in SOA. tnx Frank Tegtmeyer. +20000228 + bug: axfrdns doesn't set aa bit in responses. impact: named-xfer + refuses to do zone transfers from axfrdns. fix: set aa + bit. tnx Peter Hunter. + ui: server.c now accepts packets from low ports. sigh. +20000229 + version: DNScache 0.91, gamma. +20000307 + internal: switched from slurp to openreadclose. +20000308 + ui: dns_transmit_get() pauses after recv() failure (such as + connection-refused), if udploop is 2. + ui: tinydns-data uses refresh 16384, retry 2048, expire 1048576. + tnx Frank Tegtmeyer. + version: DNScache 0.92, gamma. +20000314 + portability problem: the poll() emulation in RedHat 5.1 doesn't + clear revents when select() returns 0. tnx Petr Novotny. + impact: dns_transmit_get() never times out; + dns_resolve() busy-loops. fix: clear revents before + poll(). +20000315 + ui: axfr-get grabs zones when serials drop. tnx Frank Tegtmeyer. + version: DNScache 0.93, gamma. +20000323 + ui: dns_rcip() accepts 0.0.0.0 in /etc/resolv.conf as 127.0.0.1. + tnx Chris Saia. +20000325 + version: DNScache 1.00. +20000914 + ui: axfr-get decodes PTR. tnx to various people. + ui: added dnsqr. +20000915 + portability problem: on some buggy kernels, accept() fails to + copy O_NONBLOCK. tnx Pavel Kankovsky. impact: with these + kernels, dnscache hangs if a TCP connection times out. + fix: ndelay_on() after accept(). + ui: dnscache discards non-recursive queries. + ui: *-conf use envdir in */run. + internal: reorganized seed_addtime() calls in dnscache-conf. + ui: tinydns-data prohibits PTR in generic records. +20000917 + ui: dns_transmit_get() does not pause after most recv() errors. + still pauses after connection-refused when udploop is 2. + version: djbdns 1.01. +20000922 + portability problem: Linux distributions use bash as /bin/sh; + bash destroys $UID. dorks. impact: dnscache and axfrdns + run as root. fix: envdir, then sh, then envuidgid. but + /bin/sh really has to stop polluting the environment. +20000923 + ui: install /etc/dnsroots.global. dnscache-conf tries + dnsroots.local, then dnsroots.global. + ui: no longer install home/etc/dnscache. + version: djbdns 1.02. +20001224 + ui: new dnstrace output format. + ui: dnstrace shows all servers providing each ns/a line. + ui: added dnstracesort. +20001225 + internal: response_rstart() and response_cname() use uint32 ttl. + internal: added response_hidettl(). + internal: cache_get() returns ttl. + internal: dnscache keeps track of ttls for aliases. + ui: dnscache returns ttl unless $HIDETTL is set. + ui: dnscache returns ttl 655360 for localhost et al. +20001226 + ui: dnscache supports $FORWARDONLY. tnx to several people for + the suggestion. tnx Dan Peterson for sample code. + ui: dnscache now logs sequential query numbers, not indices. + internal: revamped dnscache to separate udp from tcp. + ui: dnscache reports uactive, tactive separately. + ui: dnscache reports tcpopen/tcpclose by port and ip. + ui: dnscache artificially times out oldest UDP query if UDP + table is full, and oldest TCP connection if TCP table is + full. + ui: dnscache reports broken pipe when a TCP client sends FIN. +20001228 + ui: dnstrace supports dd. + ui: dnscache logs stats when it handles 1.0.0.127.in-addr.arpa. + ui: pickdns actively refuses queries for unknown types. + ui: pickdns responds to MX queries. tnx Mike Batchelor. + internal: added const at various places. + internal: removed some unused variables. + internal: used time_t in tai_now.c. + internal: used stdlib.h in alloc.c. + api: split dns_domain_suffix() into suffix(), suffixpos(). + internal: switched to buffer_unix*. + internal: included unistd.h for various declarations. +20010103 + ui: increased maximum data size from 512 bytes to 32767 bytes in + tinydns, tinydns-get, axfrdns. allows big TXT records. + ui: dnsmx reformats name when it prints an artificial 0 MX. +20010105 + ui: increased MAXLEVEL to 5. the Internet is becoming more + glueless every day. +20010106 + version: djbdns 1.03. +20010113 + ui: increased MAXALIAS to 16. + ui: dnscache no longer caches SERVFAIL. per-ip is obviously the + way to go. + ui: tinydns et al. now respond FORMERR to non-Internet-class + queries. + ui: tdlookup now returns A records in a random order in the + answer section, and truncates the list after 8 records. + ui: tinydns-data skips lines starting -. +20010114 + internal: documented the tinydns data.cdb format. + ui: tinydns-data, tinydns, tinydns-get, axfrdns support client + differentiation. + ui: dnsqr aborts if it is given an extra argument. +20010117 + ui: dnstracesort removes duplicate lines. + ui: dnstracesort prints glue. + ui: dnstrace uses a ``start'' IP address for the root glue. +20010121 + version: djbdns 1.04. +20010206 + internal: response_query() takes a class argument. + internal: query_start() takes a class argument. + internal: packetquery() takes a class argument. + ui: tinydns et al., axfrdns, and dnscache repeat qclass * in + response to bogus * queries. tnx Mike Batchelor. + ui: axfrdns rejects queries for weird classes. + ui: axfrdns uses query ID instead of ID 0 in the series of AXFR + response messages between the SOAs, to support the AXFR + client in BIND 9. + ui: axfrdns sets AA in the series of AXFR response messages. +20010211 + ui: servers print starting message. + internal: some respond() declarations. + version: djbdns 1.05. diff --git a/FILES b/FILES new file mode 100644 index 0000000..7adf6d4 --- /dev/null +++ b/FILES @@ -0,0 +1,243 @@ +README +TODO +CHANGES +VERSION +FILES +SYSDEPS +TARGETS +Makefile +dnsroots.global +TINYDNS +conf-cc +conf-ld +conf-home +rts.sh +rts.tests +rts.exp +dnscache-conf.c +hasdevtcp.h1 +hasdevtcp.h2 +dnscache.c +server.c +walldns-conf.c +walldns.c +rbldns-conf.c +rbldns.c +rbldns-data.c +pickdns-conf.c +pickdns.c +pickdns-data.c +dnsipq.c +tinydns-conf.c +tinydns.c +tdlookup.c +tinydns-get.c +tinydns-data.c +tinydns-edit.c +axfrdns-conf.c +axfrdns.c +axfr-get.c +dnsip.c +dnsname.c +dnstxt.c +dnsmx.c +dnsfilter.c +random-ip.c +dnsqr.c +dnsq.c +dnstrace.c +dnstracesort.sh +utime.c +cachetest.c +generic-conf.h +generic-conf.c +dd.h +dd.c +droproot.h +droproot.c +response.h +response.c +query.h +query.c +cache.h +cache.c +log.h +log.c +okclient.h +okclient.c +roots.h +roots.c +qlog.h +qlog.c +printrecord.h +printrecord.c +printpacket.h +printpacket.c +parsetype.h +parsetype.c +dns.h +dns_dfd.c +dns_domain.c +dns_dtda.c +dns_ip.c +dns_ipq.c +dns_mx.c +dns_name.c +dns_nd.c +dns_packet.c +dns_random.c +dns_rcip.c +dns_rcrw.c +dns_resolve.c +dns_sortip.c +dns_transmit.c +dns_txt.c +choose.sh +warn-auto.sh +find-systype.sh +trycpp.c +x86cpuid.c +alloc.c +alloc.h +alloc_re.c +auto-str.c +auto_home.h +buffer.c +buffer.h +buffer_1.c +buffer_2.c +buffer_copy.c +buffer_get.c +buffer_put.c +byte.h +byte_chr.c +byte_copy.c +byte_cr.c +byte_diff.c +byte_zero.c +case.h +case_diffb.c +case_diffs.c +case_lowerb.c +cdb.c +cdb.h +cdb_hash.c +cdb_make.c +cdb_make.h +chkshsgr.c +direntry.h1 +direntry.h2 +env.c +env.h +error.c +error.h +error_str.c +exit.h +fmt.h +fmt_ulong.c +gen_alloc.h +gen_allocdefs.h +getln.c +getln.h +getln2.c +hasshsgr.h1 +hasshsgr.h2 +hier.c +install.c +instcheck.c +iopause.c +iopause.h1 +iopause.h2 +ip4.h +ip4_fmt.c +ip4_scan.c +ndelay.h +ndelay_off.c +ndelay_on.c +open.h +open_read.c +open_trunc.c +openreadclose.c +openreadclose.h +prot.c +prot.h +readclose.c +readclose.h +scan.h +scan_ulong.c +seek.h +seek_set.c +select.h1 +select.h2 +sgetopt.c +sgetopt.h +socket.h +socket_accept.c +socket_bind.c +socket_conn.c +socket_listen.c +socket_recv.c +socket_send.c +socket_tcp.c +socket_udp.c +str.h +str_chr.c +str_diff.c +str_len.c +str_rchr.c +str_start.c +stralloc.h +stralloc_cat.c +stralloc_catb.c +stralloc_cats.c +stralloc_copy.c +stralloc_eady.c +stralloc_num.c +stralloc_opyb.c +stralloc_opys.c +stralloc_pend.c +strerr.h +strerr_die.c +strerr_sys.c +subgetopt.c +subgetopt.h +tai.h +tai_add.c +tai_now.c +tai_pack.c +tai_sub.c +tai_uint.c +tai_unpack.c +taia.h +taia_add.c +taia_approx.c +taia_frac.c +taia_less.c +taia_now.c +taia_pack.c +taia_sub.c +taia_tai.c +taia_uint.c +timeoutread.c +timeoutread.h +timeoutwrite.c +timeoutwrite.h +trydrent.c +trylsock.c +trypoll.c +tryshsgr.c +trysysel.c +tryulong32.c +tryulong64.c +uint16.h +uint16_pack.c +uint16_unpack.c +uint32.h1 +uint32.h2 +uint32_pack.c +uint32_unpack.c +uint64.h1 +uint64.h2 +warn-shsgr +buffer_read.c +buffer_write.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1429643 --- /dev/null +++ b/Makefile @@ -0,0 +1,1106 @@ +# Don't edit Makefile! Use conf-* for configuration. + +SHELL=/bin/sh + +default: it + +alloc.a: \ +makelib alloc.o alloc_re.o getln.o getln2.o stralloc_cat.o \ +stralloc_catb.o stralloc_cats.o stralloc_copy.o stralloc_eady.o \ +stralloc_num.o stralloc_opyb.o stralloc_opys.o stralloc_pend.o + ./makelib alloc.a alloc.o alloc_re.o getln.o getln2.o \ + stralloc_cat.o stralloc_catb.o stralloc_cats.o \ + stralloc_copy.o stralloc_eady.o stralloc_num.o \ + stralloc_opyb.o stralloc_opys.o stralloc_pend.o + +alloc.o: \ +compile alloc.c alloc.h error.h + ./compile alloc.c + +alloc_re.o: \ +compile alloc_re.c alloc.h byte.h + ./compile alloc_re.c + +auto-str: \ +load auto-str.o buffer.a unix.a byte.a + ./load auto-str buffer.a unix.a byte.a + +auto-str.o: \ +compile auto-str.c buffer.h exit.h + ./compile auto-str.c + +auto_home.c: \ +auto-str conf-home + ./auto-str auto_home `head -1 conf-home` > auto_home.c + +auto_home.o: \ +compile auto_home.c + ./compile auto_home.c + +axfr-get: \ +load axfr-get.o iopause.o timeoutread.o timeoutwrite.o dns.a libtai.a \ +alloc.a buffer.a unix.a byte.a + ./load axfr-get iopause.o timeoutread.o timeoutwrite.o \ + dns.a libtai.a alloc.a buffer.a unix.a byte.a + +axfr-get.o: \ +compile axfr-get.c uint32.h uint16.h stralloc.h gen_alloc.h error.h \ +strerr.h getln.h buffer.h stralloc.h buffer.h exit.h open.h scan.h \ +byte.h str.h ip4.h timeoutread.h timeoutwrite.h dns.h stralloc.h \ +iopause.h taia.h tai.h uint64.h taia.h + ./compile axfr-get.c + +axfrdns: \ +load axfrdns.o iopause.o droproot.o tdlookup.o response.o qlog.o \ +prot.o timeoutread.o timeoutwrite.o dns.a libtai.a alloc.a env.a \ +cdb.a buffer.a unix.a byte.a + ./load axfrdns iopause.o droproot.o tdlookup.o response.o \ + qlog.o prot.o timeoutread.o timeoutwrite.o dns.a libtai.a \ + alloc.a env.a cdb.a buffer.a unix.a byte.a + +axfrdns-conf: \ +load axfrdns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a + ./load axfrdns-conf generic-conf.o auto_home.o buffer.a \ + unix.a byte.a + +axfrdns-conf.o: \ +compile axfrdns-conf.c strerr.h exit.h auto_home.h generic-conf.h \ +buffer.h + ./compile axfrdns-conf.c + +axfrdns.o: \ +compile axfrdns.c droproot.h exit.h env.h uint32.h uint16.h ip4.h \ +tai.h uint64.h buffer.h timeoutread.h timeoutwrite.h open.h seek.h \ +cdb.h uint32.h stralloc.h gen_alloc.h strerr.h str.h byte.h case.h \ +dns.h stralloc.h iopause.h taia.h tai.h taia.h scan.h qlog.h uint16.h \ +response.h uint32.h + ./compile axfrdns.c + +buffer.a: \ +makelib buffer.o buffer_1.o buffer_2.o buffer_copy.o buffer_get.o \ +buffer_put.o strerr_die.o strerr_sys.o + ./makelib buffer.a buffer.o buffer_1.o buffer_2.o \ + buffer_copy.o buffer_get.o buffer_put.o strerr_die.o \ + strerr_sys.o + +buffer.o: \ +compile buffer.c buffer.h + ./compile buffer.c + +buffer_1.o: \ +compile buffer_1.c buffer.h + ./compile buffer_1.c + +buffer_2.o: \ +compile buffer_2.c buffer.h + ./compile buffer_2.c + +buffer_copy.o: \ +compile buffer_copy.c buffer.h + ./compile buffer_copy.c + +buffer_get.o: \ +compile buffer_get.c buffer.h byte.h error.h + ./compile buffer_get.c + +buffer_put.o: \ +compile buffer_put.c buffer.h str.h byte.h error.h + ./compile buffer_put.c + +buffer_read.o: \ +compile buffer_read.c buffer.h + ./compile buffer_read.c + +buffer_write.o: \ +compile buffer_write.c buffer.h + ./compile buffer_write.c + +byte.a: \ +makelib byte_chr.o byte_copy.o byte_cr.o byte_diff.o byte_zero.o \ +case_diffb.o case_diffs.o case_lowerb.o fmt_ulong.o ip4_fmt.o \ +ip4_scan.o scan_ulong.o str_chr.o str_diff.o str_len.o str_rchr.o \ +str_start.o uint16_pack.o uint16_unpack.o uint32_pack.o \ +uint32_unpack.o + ./makelib byte.a byte_chr.o byte_copy.o byte_cr.o \ + byte_diff.o byte_zero.o case_diffb.o case_diffs.o \ + case_lowerb.o fmt_ulong.o ip4_fmt.o ip4_scan.o scan_ulong.o \ + str_chr.o str_diff.o str_len.o str_rchr.o str_start.o \ + uint16_pack.o uint16_unpack.o uint32_pack.o uint32_unpack.o + +byte_chr.o: \ +compile byte_chr.c byte.h + ./compile byte_chr.c + +byte_copy.o: \ +compile byte_copy.c byte.h + ./compile byte_copy.c + +byte_cr.o: \ +compile byte_cr.c byte.h + ./compile byte_cr.c + +byte_diff.o: \ +compile byte_diff.c byte.h + ./compile byte_diff.c + +byte_zero.o: \ +compile byte_zero.c byte.h + ./compile byte_zero.c + +cache.o: \ +compile cache.c alloc.h byte.h uint32.h exit.h tai.h uint64.h cache.h \ +uint32.h uint64.h + ./compile cache.c + +cachetest: \ +load cachetest.o cache.o libtai.a buffer.a alloc.a unix.a byte.a + ./load cachetest cache.o libtai.a buffer.a alloc.a unix.a \ + byte.a + +cachetest.o: \ +compile cachetest.c buffer.h exit.h cache.h uint32.h uint64.h str.h + ./compile cachetest.c + +case_diffb.o: \ +compile case_diffb.c case.h + ./compile case_diffb.c + +case_diffs.o: \ +compile case_diffs.c case.h + ./compile case_diffs.c + +case_lowerb.o: \ +compile case_lowerb.c case.h + ./compile case_lowerb.c + +cdb.a: \ +makelib cdb.o cdb_hash.o cdb_make.o + ./makelib cdb.a cdb.o cdb_hash.o cdb_make.o + +cdb.o: \ +compile cdb.c error.h seek.h byte.h cdb.h uint32.h + ./compile cdb.c + +cdb_hash.o: \ +compile cdb_hash.c cdb.h uint32.h + ./compile cdb_hash.c + +cdb_make.o: \ +compile cdb_make.c seek.h error.h alloc.h cdb.h uint32.h cdb_make.h \ +buffer.h uint32.h + ./compile cdb_make.c + +check: \ +it instcheck + ./instcheck + +chkshsgr: \ +load chkshsgr.o + ./load chkshsgr + +chkshsgr.o: \ +compile chkshsgr.c exit.h + ./compile chkshsgr.c + +choose: \ +warn-auto.sh choose.sh conf-home + cat warn-auto.sh choose.sh \ + | sed s}HOME}"`head -1 conf-home`"}g \ + > choose + chmod 755 choose + +compile: \ +warn-auto.sh conf-cc + ( cat warn-auto.sh; \ + echo exec "`head -1 conf-cc`" '-c $${1+"$$@"}' \ + ) > compile + chmod 755 compile + +dd.o: \ +compile dd.c dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h \ +uint64.h taia.h dd.h + ./compile dd.c + +direntry.h: \ +choose compile trydrent.c direntry.h1 direntry.h2 + ./choose c trydrent direntry.h1 direntry.h2 > direntry.h + +dns.a: \ +makelib dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o dns_ipq.o dns_mx.o \ +dns_name.o dns_nd.o dns_packet.o dns_random.o dns_rcip.o dns_rcrw.o \ +dns_resolve.o dns_sortip.o dns_transmit.o dns_txt.o + ./makelib dns.a dns_dfd.o dns_domain.o dns_dtda.o dns_ip.o \ + dns_ipq.o dns_mx.o dns_name.o dns_nd.o dns_packet.o \ + dns_random.o dns_rcip.o dns_rcrw.o dns_resolve.o \ + dns_sortip.o dns_transmit.o dns_txt.o + +dns_dfd.o: \ +compile dns_dfd.c error.h alloc.h byte.h dns.h stralloc.h gen_alloc.h \ +iopause.h taia.h tai.h uint64.h taia.h + ./compile dns_dfd.c + +dns_domain.o: \ +compile dns_domain.c error.h alloc.h case.h byte.h dns.h stralloc.h \ +gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile dns_domain.c + +dns_dtda.o: \ +compile dns_dtda.c stralloc.h gen_alloc.h dns.h stralloc.h iopause.h \ +taia.h tai.h uint64.h taia.h + ./compile dns_dtda.c + +dns_ip.o: \ +compile dns_ip.c stralloc.h gen_alloc.h uint16.h byte.h dns.h \ +stralloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile dns_ip.c + +dns_ipq.o: \ +compile dns_ipq.c stralloc.h gen_alloc.h case.h byte.h str.h dns.h \ +stralloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile dns_ipq.c + +dns_mx.o: \ +compile dns_mx.c stralloc.h gen_alloc.h byte.h uint16.h dns.h \ +stralloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile dns_mx.c + +dns_name.o: \ +compile dns_name.c stralloc.h gen_alloc.h uint16.h byte.h dns.h \ +stralloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile dns_name.c + +dns_nd.o: \ +compile dns_nd.c byte.h fmt.h dns.h stralloc.h gen_alloc.h iopause.h \ +taia.h tai.h uint64.h taia.h + ./compile dns_nd.c + +dns_packet.o: \ +compile dns_packet.c error.h dns.h stralloc.h gen_alloc.h iopause.h \ +taia.h tai.h uint64.h taia.h + ./compile dns_packet.c + +dns_random.o: \ +compile dns_random.c dns.h stralloc.h gen_alloc.h iopause.h taia.h \ +tai.h uint64.h taia.h taia.h uint32.h + ./compile dns_random.c + +dns_rcip.o: \ +compile dns_rcip.c taia.h tai.h uint64.h openreadclose.h stralloc.h \ +gen_alloc.h byte.h ip4.h env.h dns.h stralloc.h iopause.h taia.h \ +taia.h + ./compile dns_rcip.c + +dns_rcrw.o: \ +compile dns_rcrw.c taia.h tai.h uint64.h env.h byte.h str.h \ +openreadclose.h stralloc.h gen_alloc.h dns.h stralloc.h iopause.h \ +taia.h taia.h + ./compile dns_rcrw.c + +dns_resolve.o: \ +compile dns_resolve.c iopause.h taia.h tai.h uint64.h taia.h byte.h \ +dns.h stralloc.h gen_alloc.h iopause.h taia.h + ./compile dns_resolve.c + +dns_sortip.o: \ +compile dns_sortip.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \ +taia.h tai.h uint64.h taia.h + ./compile dns_sortip.c + +dns_transmit.o: \ +compile dns_transmit.c socket.h uint16.h alloc.h error.h byte.h \ +uint16.h dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h \ +taia.h + ./compile dns_transmit.c + +dns_txt.o: \ +compile dns_txt.c stralloc.h gen_alloc.h uint16.h byte.h dns.h \ +stralloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile dns_txt.c + +dnscache: \ +load dnscache.o droproot.o okclient.o log.o cache.o query.o \ +response.o dd.o roots.o iopause.o prot.o dns.a env.a alloc.a buffer.a \ +libtai.a unix.a byte.a socket.lib + ./load dnscache droproot.o okclient.o log.o cache.o \ + query.o response.o dd.o roots.o iopause.o prot.o dns.a \ + env.a alloc.a buffer.a libtai.a unix.a byte.a `cat \ + socket.lib` + +dnscache-conf: \ +load dnscache-conf.o generic-conf.o auto_home.o libtai.a buffer.a \ +unix.a byte.a + ./load dnscache-conf generic-conf.o auto_home.o libtai.a \ + buffer.a unix.a byte.a + +dnscache-conf.o: \ +compile dnscache-conf.c hasdevtcp.h strerr.h buffer.h uint32.h taia.h \ +tai.h uint64.h str.h open.h error.h exit.h auto_home.h generic-conf.h \ +buffer.h + ./compile dnscache-conf.c + +dnscache.o: \ +compile dnscache.c env.h exit.h scan.h strerr.h error.h ip4.h \ +uint16.h uint64.h socket.h uint16.h dns.h stralloc.h gen_alloc.h \ +iopause.h taia.h tai.h uint64.h taia.h taia.h byte.h roots.h fmt.h \ +iopause.h query.h dns.h uint32.h alloc.h response.h uint32.h cache.h \ +uint32.h uint64.h ndelay.h log.h uint64.h okclient.h droproot.h + ./compile dnscache.c + +dnsfilter: \ +load dnsfilter.o iopause.o getopt.a dns.a env.a libtai.a alloc.a \ +buffer.a unix.a byte.a socket.lib + ./load dnsfilter iopause.o getopt.a dns.a env.a libtai.a \ + alloc.a buffer.a unix.a byte.a `cat socket.lib` + +dnsfilter.o: \ +compile dnsfilter.c strerr.h buffer.h stralloc.h gen_alloc.h alloc.h \ +dns.h stralloc.h iopause.h taia.h tai.h uint64.h taia.h ip4.h byte.h \ +scan.h taia.h sgetopt.h subgetopt.h iopause.h error.h exit.h + ./compile dnsfilter.c + +dnsip: \ +load dnsip.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \ +byte.a socket.lib + ./load dnsip iopause.o dns.a env.a libtai.a alloc.a \ + buffer.a unix.a byte.a `cat socket.lib` + +dnsip.o: \ +compile dnsip.c buffer.h exit.h strerr.h ip4.h dns.h stralloc.h \ +gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile dnsip.c + +dnsipq: \ +load dnsipq.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \ +byte.a socket.lib + ./load dnsipq iopause.o dns.a env.a libtai.a alloc.a \ + buffer.a unix.a byte.a `cat socket.lib` + +dnsipq.o: \ +compile dnsipq.c buffer.h exit.h strerr.h ip4.h dns.h stralloc.h \ +gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile dnsipq.c + +dnsmx: \ +load dnsmx.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \ +byte.a socket.lib + ./load dnsmx iopause.o dns.a env.a libtai.a alloc.a \ + buffer.a unix.a byte.a `cat socket.lib` + +dnsmx.o: \ +compile dnsmx.c buffer.h exit.h strerr.h uint16.h byte.h str.h fmt.h \ +dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile dnsmx.c + +dnsname: \ +load dnsname.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \ +byte.a socket.lib + ./load dnsname iopause.o dns.a env.a libtai.a alloc.a \ + buffer.a unix.a byte.a `cat socket.lib` + +dnsname.o: \ +compile dnsname.c buffer.h exit.h strerr.h ip4.h dns.h stralloc.h \ +gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile dnsname.c + +dnsq: \ +load dnsq.o iopause.o printrecord.o printpacket.o parsetype.o dns.a \ +env.a libtai.a buffer.a alloc.a unix.a byte.a socket.lib + ./load dnsq iopause.o printrecord.o printpacket.o \ + parsetype.o dns.a env.a libtai.a buffer.a alloc.a unix.a \ + byte.a `cat socket.lib` + +dnsq.o: \ +compile dnsq.c uint16.h strerr.h buffer.h scan.h str.h byte.h error.h \ +ip4.h iopause.h taia.h tai.h uint64.h printpacket.h stralloc.h \ +gen_alloc.h parsetype.h dns.h stralloc.h iopause.h taia.h + ./compile dnsq.c + +dnsqr: \ +load dnsqr.o iopause.o printrecord.o printpacket.o parsetype.o dns.a \ +env.a libtai.a buffer.a alloc.a unix.a byte.a socket.lib + ./load dnsqr iopause.o printrecord.o printpacket.o \ + parsetype.o dns.a env.a libtai.a buffer.a alloc.a unix.a \ + byte.a `cat socket.lib` + +dnsqr.o: \ +compile dnsqr.c uint16.h strerr.h buffer.h scan.h str.h byte.h \ +error.h iopause.h taia.h tai.h uint64.h printpacket.h stralloc.h \ +gen_alloc.h parsetype.h dns.h stralloc.h iopause.h taia.h + ./compile dnsqr.c + +dnstrace: \ +load dnstrace.o dd.o iopause.o printrecord.o parsetype.o dns.a env.a \ +libtai.a alloc.a buffer.a unix.a byte.a socket.lib + ./load dnstrace dd.o iopause.o printrecord.o parsetype.o \ + dns.a env.a libtai.a alloc.a buffer.a unix.a byte.a `cat \ + socket.lib` + +dnstrace.o: \ +compile dnstrace.c uint16.h uint32.h fmt.h str.h byte.h ip4.h \ +gen_alloc.h gen_allocdefs.h exit.h buffer.h stralloc.h gen_alloc.h \ +error.h strerr.h iopause.h taia.h tai.h uint64.h printrecord.h \ +stralloc.h alloc.h parsetype.h dd.h dns.h stralloc.h iopause.h taia.h + ./compile dnstrace.c + +dnstracesort: \ +warn-auto.sh dnstracesort.sh conf-home + cat warn-auto.sh dnstracesort.sh \ + | sed s}HOME}"`head -1 conf-home`"}g \ + > dnstracesort + chmod 755 dnstracesort + +dnstxt: \ +load dnstxt.o iopause.o dns.a env.a libtai.a alloc.a buffer.a unix.a \ +byte.a socket.lib + ./load dnstxt iopause.o dns.a env.a libtai.a alloc.a \ + buffer.a unix.a byte.a `cat socket.lib` + +dnstxt.o: \ +compile dnstxt.c buffer.h exit.h strerr.h dns.h stralloc.h \ +gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile dnstxt.c + +droproot.o: \ +compile droproot.c env.h scan.h prot.h strerr.h + ./compile droproot.c + +env.a: \ +makelib env.o + ./makelib env.a env.o + +env.o: \ +compile env.c str.h env.h + ./compile env.c + +error.o: \ +compile error.c error.h + ./compile error.c + +error_str.o: \ +compile error_str.c error.h + ./compile error_str.c + +fmt_ulong.o: \ +compile fmt_ulong.c fmt.h + ./compile fmt_ulong.c + +generic-conf.o: \ +compile generic-conf.c strerr.h buffer.h open.h generic-conf.h \ +buffer.h + ./compile generic-conf.c + +getln.o: \ +compile getln.c byte.h getln.h buffer.h stralloc.h gen_alloc.h + ./compile getln.c + +getln2.o: \ +compile getln2.c byte.h getln.h buffer.h stralloc.h gen_alloc.h + ./compile getln2.c + +getopt.a: \ +makelib sgetopt.o subgetopt.o + ./makelib getopt.a sgetopt.o subgetopt.o + +hasdevtcp.h: \ +systype hasdevtcp.h1 hasdevtcp.h2 + ( case "`cat systype`" in \ + sunos-5.*) cat hasdevtcp.h2 ;; \ + *) cat hasdevtcp.h1 ;; \ + esac ) > hasdevtcp.h + +hasshsgr.h: \ +choose compile load tryshsgr.c hasshsgr.h1 hasshsgr.h2 chkshsgr \ +warn-shsgr + ./chkshsgr || ( cat warn-shsgr; exit 1 ) + ./choose clr tryshsgr hasshsgr.h1 hasshsgr.h2 > hasshsgr.h + +hier.o: \ +compile hier.c auto_home.h + ./compile hier.c + +install: \ +load install.o hier.o auto_home.o buffer.a unix.a byte.a + ./load install hier.o auto_home.o buffer.a unix.a byte.a + +install.o: \ +compile install.c buffer.h strerr.h error.h open.h exit.h + ./compile install.c + +instcheck: \ +load instcheck.o hier.o auto_home.o buffer.a unix.a byte.a + ./load instcheck hier.o auto_home.o buffer.a unix.a byte.a + +instcheck.o: \ +compile instcheck.c strerr.h error.h exit.h + ./compile instcheck.c + +iopause.h: \ +choose compile load trypoll.c iopause.h1 iopause.h2 + ./choose clr trypoll iopause.h1 iopause.h2 > iopause.h + +iopause.o: \ +compile iopause.c taia.h tai.h uint64.h select.h iopause.h taia.h + ./compile iopause.c + +ip4_fmt.o: \ +compile ip4_fmt.c fmt.h ip4.h + ./compile ip4_fmt.c + +ip4_scan.o: \ +compile ip4_scan.c scan.h ip4.h + ./compile ip4_scan.c + +it: \ +prog install instcheck + +libtai.a: \ +makelib tai_add.o tai_now.o tai_pack.o tai_sub.o tai_uint.o \ +tai_unpack.o taia_add.o taia_approx.o taia_frac.o taia_less.o \ +taia_now.o taia_pack.o taia_sub.o taia_tai.o taia_uint.o + ./makelib libtai.a tai_add.o tai_now.o tai_pack.o \ + tai_sub.o tai_uint.o tai_unpack.o taia_add.o taia_approx.o \ + taia_frac.o taia_less.o taia_now.o taia_pack.o taia_sub.o \ + taia_tai.o taia_uint.o + +load: \ +warn-auto.sh conf-ld + ( cat warn-auto.sh; \ + echo 'main="$$1"; shift'; \ + echo exec "`head -1 conf-ld`" \ + '-o "$$main" "$$main".o $${1+"$$@"}' \ + ) > load + chmod 755 load + +log.o: \ +compile log.c buffer.h uint32.h uint16.h error.h byte.h log.h \ +uint64.h + ./compile log.c + +makelib: \ +warn-auto.sh systype + ( cat warn-auto.sh; \ + echo 'main="$$1"; shift'; \ + echo 'rm -f "$$main"'; \ + echo 'ar cr "$$main" $${1+"$$@"}'; \ + case "`cat systype`" in \ + sunos-5.*) ;; \ + unix_sv*) ;; \ + irix64-*) ;; \ + irix-*) ;; \ + dgux-*) ;; \ + hp-ux-*) ;; \ + sco*) ;; \ + *) echo 'ranlib "$$main"' ;; \ + esac \ + ) > makelib + chmod 755 makelib + +ndelay_off.o: \ +compile ndelay_off.c ndelay.h + ./compile ndelay_off.c + +ndelay_on.o: \ +compile ndelay_on.c ndelay.h + ./compile ndelay_on.c + +okclient.o: \ +compile okclient.c str.h ip4.h okclient.h + ./compile okclient.c + +open_read.o: \ +compile open_read.c open.h + ./compile open_read.c + +open_trunc.o: \ +compile open_trunc.c open.h + ./compile open_trunc.c + +openreadclose.o: \ +compile openreadclose.c error.h open.h readclose.h stralloc.h \ +gen_alloc.h openreadclose.h stralloc.h + ./compile openreadclose.c + +parsetype.o: \ +compile parsetype.c scan.h byte.h case.h dns.h stralloc.h gen_alloc.h \ +iopause.h taia.h tai.h uint64.h taia.h uint16.h parsetype.h + ./compile parsetype.c + +pickdns: \ +load pickdns.o server.o response.o droproot.o qlog.o prot.o dns.a \ +env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib + ./load pickdns server.o response.o droproot.o qlog.o \ + prot.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \ + byte.a `cat socket.lib` + +pickdns-conf: \ +load pickdns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a + ./load pickdns-conf generic-conf.o auto_home.o buffer.a \ + unix.a byte.a + +pickdns-conf.o: \ +compile pickdns-conf.c strerr.h exit.h auto_home.h generic-conf.h \ +buffer.h + ./compile pickdns-conf.c + +pickdns-data: \ +load pickdns-data.o cdb.a dns.a alloc.a buffer.a unix.a byte.a + ./load pickdns-data cdb.a dns.a alloc.a buffer.a unix.a \ + byte.a + +pickdns-data.o: \ +compile pickdns-data.c buffer.h exit.h cdb_make.h buffer.h uint32.h \ +open.h alloc.h gen_allocdefs.h stralloc.h gen_alloc.h getln.h \ +buffer.h stralloc.h case.h strerr.h str.h byte.h scan.h fmt.h ip4.h \ +dns.h stralloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile pickdns-data.c + +pickdns.o: \ +compile pickdns.c byte.h case.h dns.h stralloc.h gen_alloc.h \ +iopause.h taia.h tai.h uint64.h taia.h open.h cdb.h uint32.h \ +response.h uint32.h + ./compile pickdns.c + +printpacket.o: \ +compile printpacket.c uint16.h uint32.h error.h byte.h dns.h \ +stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h \ +printrecord.h stralloc.h printpacket.h stralloc.h + ./compile printpacket.c + +printrecord.o: \ +compile printrecord.c uint16.h uint32.h error.h byte.h dns.h \ +stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h \ +printrecord.h stralloc.h + ./compile printrecord.c + +prog: \ +dnscache-conf dnscache walldns-conf walldns rbldns-conf rbldns \ +rbldns-data pickdns-conf pickdns pickdns-data tinydns-conf tinydns \ +tinydns-data tinydns-get tinydns-edit axfr-get axfrdns-conf axfrdns \ +dnsip dnsipq dnsname dnstxt dnsmx dnsfilter random-ip dnsqr dnsq \ +dnstrace dnstracesort cachetest utime rts + +prot.o: \ +compile prot.c hasshsgr.h prot.h + ./compile prot.c + +qlog.o: \ +compile qlog.c buffer.h qlog.h uint16.h + ./compile qlog.c + +query.o: \ +compile query.c error.h roots.h log.h uint64.h case.h cache.h \ +uint32.h uint64.h byte.h dns.h stralloc.h gen_alloc.h iopause.h \ +taia.h tai.h uint64.h taia.h uint64.h uint32.h uint16.h dd.h alloc.h \ +response.h uint32.h query.h dns.h uint32.h + ./compile query.c + +random-ip: \ +load random-ip.o dns.a libtai.a buffer.a unix.a byte.a + ./load random-ip dns.a libtai.a buffer.a unix.a byte.a + +random-ip.o: \ +compile random-ip.c buffer.h exit.h fmt.h scan.h dns.h stralloc.h \ +gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile random-ip.c + +rbldns: \ +load rbldns.o server.o response.o dd.o droproot.o qlog.o prot.o dns.a \ +env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib + ./load rbldns server.o response.o dd.o droproot.o qlog.o \ + prot.o dns.a env.a libtai.a cdb.a alloc.a buffer.a unix.a \ + byte.a `cat socket.lib` + +rbldns-conf: \ +load rbldns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a + ./load rbldns-conf generic-conf.o auto_home.o buffer.a \ + unix.a byte.a + +rbldns-conf.o: \ +compile rbldns-conf.c strerr.h exit.h auto_home.h generic-conf.h \ +buffer.h + ./compile rbldns-conf.c + +rbldns-data: \ +load rbldns-data.o cdb.a alloc.a buffer.a unix.a byte.a + ./load rbldns-data cdb.a alloc.a buffer.a unix.a byte.a + +rbldns-data.o: \ +compile rbldns-data.c buffer.h exit.h cdb_make.h buffer.h uint32.h \ +open.h stralloc.h gen_alloc.h getln.h buffer.h stralloc.h strerr.h \ +byte.h scan.h fmt.h ip4.h + ./compile rbldns-data.c + +rbldns.o: \ +compile rbldns.c str.h byte.h ip4.h open.h env.h cdb.h uint32.h dns.h \ +stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h dd.h \ +strerr.h response.h uint32.h + ./compile rbldns.c + +readclose.o: \ +compile readclose.c error.h readclose.h stralloc.h gen_alloc.h + ./compile readclose.c + +response.o: \ +compile response.c dns.h stralloc.h gen_alloc.h iopause.h taia.h \ +tai.h uint64.h taia.h byte.h uint16.h response.h uint32.h + ./compile response.c + +roots.o: \ +compile roots.c open.h error.h str.h byte.h error.h direntry.h ip4.h \ +dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h \ +openreadclose.h stralloc.h roots.h + ./compile roots.c + +rts: \ +warn-auto.sh rts.sh conf-home + cat warn-auto.sh rts.sh \ + | sed s}HOME}"`head -1 conf-home`"}g \ + > rts + chmod 755 rts + +scan_ulong.o: \ +compile scan_ulong.c scan.h + ./compile scan_ulong.c + +seek_set.o: \ +compile seek_set.c seek.h + ./compile seek_set.c + +select.h: \ +choose compile trysysel.c select.h1 select.h2 + ./choose c trysysel select.h1 select.h2 > select.h + +server.o: \ +compile server.c byte.h case.h env.h buffer.h strerr.h ip4.h uint16.h \ +ndelay.h socket.h uint16.h droproot.h qlog.h uint16.h response.h \ +uint32.h dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h \ +taia.h + ./compile server.c + +setup: \ +it install + ./install + +sgetopt.o: \ +compile sgetopt.c buffer.h sgetopt.h subgetopt.h subgetopt.h + ./compile sgetopt.c + +socket.lib: \ +trylsock.c compile load + ( ( ./compile trylsock.c && \ + ./load trylsock -lsocket -lnsl ) >/dev/null 2>&1 \ + && echo -lsocket -lnsl || exit 0 ) > socket.lib + rm -f trylsock.o trylsock + +socket_accept.o: \ +compile socket_accept.c byte.h socket.h uint16.h + ./compile socket_accept.c + +socket_bind.o: \ +compile socket_bind.c byte.h socket.h uint16.h + ./compile socket_bind.c + +socket_conn.o: \ +compile socket_conn.c byte.h socket.h uint16.h + ./compile socket_conn.c + +socket_listen.o: \ +compile socket_listen.c socket.h uint16.h + ./compile socket_listen.c + +socket_recv.o: \ +compile socket_recv.c byte.h socket.h uint16.h + ./compile socket_recv.c + +socket_send.o: \ +compile socket_send.c byte.h socket.h uint16.h + ./compile socket_send.c + +socket_tcp.o: \ +compile socket_tcp.c ndelay.h socket.h uint16.h + ./compile socket_tcp.c + +socket_udp.o: \ +compile socket_udp.c ndelay.h socket.h uint16.h + ./compile socket_udp.c + +str_chr.o: \ +compile str_chr.c str.h + ./compile str_chr.c + +str_diff.o: \ +compile str_diff.c str.h + ./compile str_diff.c + +str_len.o: \ +compile str_len.c str.h + ./compile str_len.c + +str_rchr.o: \ +compile str_rchr.c str.h + ./compile str_rchr.c + +str_start.o: \ +compile str_start.c str.h + ./compile str_start.c + +stralloc_cat.o: \ +compile stralloc_cat.c byte.h stralloc.h gen_alloc.h + ./compile stralloc_cat.c + +stralloc_catb.o: \ +compile stralloc_catb.c stralloc.h gen_alloc.h byte.h + ./compile stralloc_catb.c + +stralloc_cats.o: \ +compile stralloc_cats.c byte.h str.h stralloc.h gen_alloc.h + ./compile stralloc_cats.c + +stralloc_copy.o: \ +compile stralloc_copy.c byte.h stralloc.h gen_alloc.h + ./compile stralloc_copy.c + +stralloc_eady.o: \ +compile stralloc_eady.c alloc.h stralloc.h gen_alloc.h \ +gen_allocdefs.h + ./compile stralloc_eady.c + +stralloc_num.o: \ +compile stralloc_num.c stralloc.h gen_alloc.h + ./compile stralloc_num.c + +stralloc_opyb.o: \ +compile stralloc_opyb.c stralloc.h gen_alloc.h byte.h + ./compile stralloc_opyb.c + +stralloc_opys.o: \ +compile stralloc_opys.c byte.h str.h stralloc.h gen_alloc.h + ./compile stralloc_opys.c + +stralloc_pend.o: \ +compile stralloc_pend.c alloc.h stralloc.h gen_alloc.h \ +gen_allocdefs.h + ./compile stralloc_pend.c + +strerr_die.o: \ +compile strerr_die.c buffer.h exit.h strerr.h + ./compile strerr_die.c + +strerr_sys.o: \ +compile strerr_sys.c error.h strerr.h + ./compile strerr_sys.c + +subgetopt.o: \ +compile subgetopt.c subgetopt.h + ./compile subgetopt.c + +systype: \ +find-systype.sh conf-cc conf-ld trycpp.c x86cpuid.c + ( cat warn-auto.sh; \ + echo CC=\'`head -1 conf-cc`\'; \ + echo LD=\'`head -1 conf-ld`\'; \ + cat find-systype.sh; \ + ) | sh > systype + +tai_add.o: \ +compile tai_add.c tai.h uint64.h + ./compile tai_add.c + +tai_now.o: \ +compile tai_now.c tai.h uint64.h + ./compile tai_now.c + +tai_pack.o: \ +compile tai_pack.c tai.h uint64.h + ./compile tai_pack.c + +tai_sub.o: \ +compile tai_sub.c tai.h uint64.h + ./compile tai_sub.c + +tai_uint.o: \ +compile tai_uint.c tai.h uint64.h + ./compile tai_uint.c + +tai_unpack.o: \ +compile tai_unpack.c tai.h uint64.h + ./compile tai_unpack.c + +taia_add.o: \ +compile taia_add.c taia.h tai.h uint64.h + ./compile taia_add.c + +taia_approx.o: \ +compile taia_approx.c taia.h tai.h uint64.h + ./compile taia_approx.c + +taia_frac.o: \ +compile taia_frac.c taia.h tai.h uint64.h + ./compile taia_frac.c + +taia_less.o: \ +compile taia_less.c taia.h tai.h uint64.h + ./compile taia_less.c + +taia_now.o: \ +compile taia_now.c taia.h tai.h uint64.h + ./compile taia_now.c + +taia_pack.o: \ +compile taia_pack.c taia.h tai.h uint64.h + ./compile taia_pack.c + +taia_sub.o: \ +compile taia_sub.c taia.h tai.h uint64.h + ./compile taia_sub.c + +taia_tai.o: \ +compile taia_tai.c taia.h tai.h uint64.h + ./compile taia_tai.c + +taia_uint.o: \ +compile taia_uint.c taia.h tai.h uint64.h + ./compile taia_uint.c + +tdlookup.o: \ +compile tdlookup.c uint16.h open.h tai.h uint64.h cdb.h uint32.h \ +byte.h case.h dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h \ +taia.h seek.h response.h uint32.h + ./compile tdlookup.c + +timeoutread.o: \ +compile timeoutread.c error.h iopause.h taia.h tai.h uint64.h \ +timeoutread.h + ./compile timeoutread.c + +timeoutwrite.o: \ +compile timeoutwrite.c error.h iopause.h taia.h tai.h uint64.h \ +timeoutwrite.h + ./compile timeoutwrite.c + +tinydns: \ +load tinydns.o server.o droproot.o tdlookup.o response.o qlog.o \ +prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a byte.a \ +socket.lib + ./load tinydns server.o droproot.o tdlookup.o response.o \ + qlog.o prot.o dns.a libtai.a env.a cdb.a alloc.a buffer.a \ + unix.a byte.a `cat socket.lib` + +tinydns-conf: \ +load tinydns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a + ./load tinydns-conf generic-conf.o auto_home.o buffer.a \ + unix.a byte.a + +tinydns-conf.o: \ +compile tinydns-conf.c strerr.h exit.h auto_home.h generic-conf.h \ +buffer.h + ./compile tinydns-conf.c + +tinydns-data: \ +load tinydns-data.o cdb.a dns.a alloc.a buffer.a unix.a byte.a + ./load tinydns-data cdb.a dns.a alloc.a buffer.a unix.a \ + byte.a + +tinydns-data.o: \ +compile tinydns-data.c uint16.h uint32.h str.h byte.h fmt.h ip4.h \ +exit.h case.h scan.h buffer.h strerr.h getln.h buffer.h stralloc.h \ +gen_alloc.h cdb_make.h buffer.h uint32.h stralloc.h open.h dns.h \ +stralloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile tinydns-data.c + +tinydns-edit: \ +load tinydns-edit.o dns.a alloc.a buffer.a unix.a byte.a + ./load tinydns-edit dns.a alloc.a buffer.a unix.a byte.a + +tinydns-edit.o: \ +compile tinydns-edit.c stralloc.h gen_alloc.h buffer.h exit.h open.h \ +getln.h buffer.h stralloc.h strerr.h scan.h byte.h str.h fmt.h ip4.h \ +dns.h stralloc.h iopause.h taia.h tai.h uint64.h taia.h + ./compile tinydns-edit.c + +tinydns-get: \ +load tinydns-get.o tdlookup.o response.o printpacket.o printrecord.o \ +parsetype.o dns.a libtai.a cdb.a buffer.a alloc.a unix.a byte.a + ./load tinydns-get tdlookup.o response.o printpacket.o \ + printrecord.o parsetype.o dns.a libtai.a cdb.a buffer.a \ + alloc.a unix.a byte.a + +tinydns-get.o: \ +compile tinydns-get.c str.h byte.h scan.h exit.h stralloc.h \ +gen_alloc.h buffer.h strerr.h uint16.h response.h uint32.h case.h \ +printpacket.h stralloc.h parsetype.h ip4.h dns.h stralloc.h iopause.h \ +taia.h tai.h uint64.h taia.h + ./compile tinydns-get.c + +tinydns.o: \ +compile tinydns.c dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h \ +uint64.h taia.h + ./compile tinydns.c + +uint16_pack.o: \ +compile uint16_pack.c uint16.h + ./compile uint16_pack.c + +uint16_unpack.o: \ +compile uint16_unpack.c uint16.h + ./compile uint16_unpack.c + +uint32.h: \ +tryulong32.c compile load uint32.h1 uint32.h2 + ( ( ./compile tryulong32.c && ./load tryulong32 && \ + ./tryulong32 ) >/dev/null 2>&1 \ + && cat uint32.h2 || cat uint32.h1 ) > uint32.h + rm -f tryulong32.o tryulong32 + +uint32_pack.o: \ +compile uint32_pack.c uint32.h + ./compile uint32_pack.c + +uint32_unpack.o: \ +compile uint32_unpack.c uint32.h + ./compile uint32_unpack.c + +uint64.h: \ +choose compile load tryulong64.c uint64.h1 uint64.h2 + ./choose clr tryulong64 uint64.h1 uint64.h2 > uint64.h + +unix.a: \ +makelib buffer_read.o buffer_write.o error.o error_str.o ndelay_off.o \ +ndelay_on.o open_read.o open_trunc.o openreadclose.o readclose.o \ +seek_set.o socket_accept.o socket_bind.o socket_conn.o \ +socket_listen.o socket_recv.o socket_send.o socket_tcp.o socket_udp.o + ./makelib unix.a buffer_read.o buffer_write.o error.o \ + error_str.o ndelay_off.o ndelay_on.o open_read.o \ + open_trunc.o openreadclose.o readclose.o seek_set.o \ + socket_accept.o socket_bind.o socket_conn.o socket_listen.o \ + socket_recv.o socket_send.o socket_tcp.o socket_udp.o + +utime: \ +load utime.o byte.a + ./load utime byte.a + +utime.o: \ +compile utime.c scan.h exit.h + ./compile utime.c + +walldns: \ +load walldns.o server.o response.o droproot.o qlog.o prot.o dd.o \ +dns.a env.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib + ./load walldns server.o response.o droproot.o qlog.o \ + prot.o dd.o dns.a env.a cdb.a alloc.a buffer.a unix.a \ + byte.a `cat socket.lib` + +walldns-conf: \ +load walldns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a + ./load walldns-conf generic-conf.o auto_home.o buffer.a \ + unix.a byte.a + +walldns-conf.o: \ +compile walldns-conf.c strerr.h exit.h auto_home.h generic-conf.h \ +buffer.h + ./compile walldns-conf.c + +walldns.o: \ +compile walldns.c byte.h dns.h stralloc.h gen_alloc.h iopause.h \ +taia.h tai.h uint64.h taia.h dd.h response.h uint32.h + ./compile walldns.c diff --git a/README b/README new file mode 100644 index 0000000..a9617eb --- /dev/null +++ b/README @@ -0,0 +1,7 @@ +djbdns 1.05 +20010211 +Copyright 2001 +D. J. Bernstein + +djbdns home page: http://cr.yp.to/djbdns.html +Installation instructions: http://cr.yp.to/djbdns/install.html diff --git a/SYSDEPS b/SYSDEPS new file mode 100644 index 0000000..060bbc0 --- /dev/null +++ b/SYSDEPS @@ -0,0 +1,10 @@ +VERSION +systype +uint32.h +uint64.h +select.h +iopause.h +direntry.h +hasshsgr.h +hasdevtcp.h +socket.lib diff --git a/TARGETS b/TARGETS new file mode 100644 index 0000000..2490b1a --- /dev/null +++ b/TARGETS @@ -0,0 +1,216 @@ +load +compile +systype +hasdevtcp.h +uint32.h +choose +uint64.h +dnscache-conf.o +generic-conf.o +auto-str.o +makelib +buffer.o +buffer_1.o +buffer_2.o +buffer_copy.o +buffer_get.o +buffer_put.o +strerr_die.o +strerr_sys.o +buffer.a +buffer_read.o +buffer_write.o +error.o +error_str.o +ndelay_off.o +ndelay_on.o +open_read.o +open_trunc.o +openreadclose.o +readclose.o +seek_set.o +socket_accept.o +socket_bind.o +socket_conn.o +socket_listen.o +socket_recv.o +socket_send.o +socket_tcp.o +socket_udp.o +unix.a +byte_chr.o +byte_copy.o +byte_cr.o +byte_diff.o +byte_zero.o +case_diffb.o +case_diffs.o +case_lowerb.o +fmt_ulong.o +ip4_fmt.o +ip4_scan.o +scan_ulong.o +str_chr.o +str_diff.o +str_len.o +str_rchr.o +str_start.o +uint16_pack.o +uint16_unpack.o +uint32_pack.o +uint32_unpack.o +byte.a +auto-str +auto_home.c +auto_home.o +tai_add.o +tai_now.o +tai_pack.o +tai_sub.o +tai_uint.o +tai_unpack.o +taia_add.o +taia_approx.o +taia_frac.o +taia_less.o +taia_now.o +taia_pack.o +taia_sub.o +taia_tai.o +taia_uint.o +libtai.a +dnscache-conf +iopause.h +dnscache.o +droproot.o +okclient.o +log.o +cache.o +query.o +response.o +dd.o +direntry.h +roots.o +select.h +iopause.o +chkshsgr.o +chkshsgr +hasshsgr.h +prot.o +dns_dfd.o +dns_domain.o +dns_dtda.o +dns_ip.o +dns_ipq.o +dns_mx.o +dns_name.o +dns_nd.o +dns_packet.o +dns_random.o +dns_rcip.o +dns_rcrw.o +dns_resolve.o +dns_sortip.o +dns_transmit.o +dns_txt.o +dns.a +env.o +env.a +alloc.o +alloc_re.o +getln.o +getln2.o +stralloc_cat.o +stralloc_catb.o +stralloc_cats.o +stralloc_copy.o +stralloc_eady.o +stralloc_num.o +stralloc_opyb.o +stralloc_opys.o +stralloc_pend.o +alloc.a +socket.lib +dnscache +walldns-conf.o +walldns-conf +walldns.o +server.o +qlog.o +cdb.o +cdb_hash.o +cdb_make.o +cdb.a +walldns +rbldns-conf.o +rbldns-conf +rbldns.o +rbldns +rbldns-data.o +rbldns-data +pickdns-conf.o +pickdns-conf +pickdns.o +pickdns +pickdns-data.o +pickdns-data +tinydns-conf.o +tinydns-conf +tinydns.o +tdlookup.o +tinydns +tinydns-data.o +tinydns-data +tinydns-get.o +printpacket.o +printrecord.o +parsetype.o +tinydns-get +tinydns-edit.o +tinydns-edit +axfr-get.o +timeoutread.o +timeoutwrite.o +axfr-get +axfrdns-conf.o +axfrdns-conf +axfrdns.o +axfrdns +dnsip.o +dnsip +dnsipq.o +dnsipq +dnsname.o +dnsname +dnstxt.o +dnstxt +dnsmx.o +dnsmx +dnsfilter.o +sgetopt.o +subgetopt.o +getopt.a +dnsfilter +random-ip.o +random-ip +dnsqr.o +dnsqr +dnsq.o +dnsq +dnstrace.o +dnstrace +dnstracesort +cachetest.o +cachetest +utime.o +utime +rts +prog +install.o +hier.o +install +instcheck.o +instcheck +it +setup +check diff --git a/TINYDNS b/TINYDNS new file mode 100644 index 0000000..2e41a9a --- /dev/null +++ b/TINYDNS @@ -0,0 +1,25 @@ +The tinydns data.cdb format is subject to change. If you want to write +code that relies on something here, let me know. + +Keys starting with the two bytes \000\045 are locations. The rest of the +key is an IP prefix, normally between 0 and 4 bytes long. The data is a +2-byte location. + +Other keys are owner names for DNS records. The data begins with a +header in the following format: + + * a 2-byte type; + * either \075, or \076 with a 2-byte location; + * a 4-byte TTL; + * an 8-byte timestamp. + +(Exception: Wildcard records replace \075 with \052 and \076 with \053; +also, the owner name omits the wildcard.) The data continues in a +type-specific format: + + * SOA: first domain name, second domain name, 20-byte miscellany. + * NS or PTR or CNAME: domain name. + * MX: 2-byte preference, domain name. + * Other types: no special structure. + +Domain names, types, and numbers are in DNS packet format. diff --git a/TODO b/TODO new file mode 100644 index 0000000..8931a9a --- /dev/null +++ b/TODO @@ -0,0 +1,12 @@ +end-to-end nym-based security +link-level security + +try to get the root authorities to set up a secure, usable NS-list system +have dnscache-conf keep track of copies of dnsroots.global +incorporate automatic NS-list upgrades + +consider dead-server table in dnscache or in kernel + +IPv6 lookups +maybe reverse IPv6 lookups; what a mess +DNS over IPv6 diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..835d795 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +djbdns 1.05 diff --git a/alloc.c b/alloc.c new file mode 100644 index 0000000..b94e23a --- /dev/null +++ b/alloc.c @@ -0,0 +1,31 @@ +#include +#include "alloc.h" +#include "error.h" + +#define ALIGNMENT 16 /* XXX: assuming that this alignment is enough */ +#define SPACE 2048 /* must be multiple of ALIGNMENT */ + +typedef union { char irrelevant[ALIGNMENT]; double d; } aligned; +static aligned realspace[SPACE / ALIGNMENT]; +#define space ((char *) realspace) +static unsigned int avail = SPACE; /* multiple of ALIGNMENT; 0<=avail<=SPACE */ + +/*@null@*//*@out@*/char *alloc(n) +unsigned int n; +{ + char *x; + n = ALIGNMENT + n - (n & (ALIGNMENT - 1)); /* XXX: could overflow */ + if (n <= avail) { avail -= n; return space + avail; } + x = malloc(n); + if (!x) errno = error_nomem; + return x; +} + +void alloc_free(x) +char *x; +{ + if (x >= space) + if (x < space + SPACE) + return; /* XXX: assuming that pointers are flat */ + free(x); +} diff --git a/alloc.h b/alloc.h new file mode 100644 index 0000000..1b1d893 --- /dev/null +++ b/alloc.h @@ -0,0 +1,8 @@ +#ifndef ALLOC_H +#define ALLOC_H + +extern /*@null@*//*@out@*/char *alloc(); +extern void alloc_free(); +extern int alloc_re(); + +#endif diff --git a/alloc_re.c b/alloc_re.c new file mode 100644 index 0000000..feb8b49 --- /dev/null +++ b/alloc_re.c @@ -0,0 +1,17 @@ +#include "alloc.h" +#include "byte.h" + +int alloc_re(x,m,n) +char **x; +unsigned int m; +unsigned int n; +{ + char *y; + + y = alloc(n); + if (!y) return 0; + byte_copy(y,m,*x); + alloc_free(*x); + *x = y; + return 1; +} diff --git a/auto-str.c b/auto-str.c new file mode 100644 index 0000000..374af92 --- /dev/null +++ b/auto-str.c @@ -0,0 +1,40 @@ +#include "buffer.h" +#include "exit.h" + +char bspace[256]; +buffer b = BUFFER_INIT(buffer_unixwrite,1,bspace,sizeof bspace); + +void puts(const char *s) +{ + if (buffer_puts(&b,s) == -1) _exit(111); +} + +int main(int argc,char **argv) +{ + char *name; + char *value; + unsigned char ch; + char octal[4]; + + name = argv[1]; + if (!name) _exit(100); + value = argv[2]; + if (!value) _exit(100); + + puts("const char "); + puts(name); + puts("[] = \"\\\n"); + + while (ch = *value++) { + puts("\\"); + octal[3] = 0; + octal[2] = '0' + (ch & 7); ch >>= 3; + octal[1] = '0' + (ch & 7); ch >>= 3; + octal[0] = '0' + (ch & 7); + puts(octal); + } + + puts("\\\n\";\n"); + if (buffer_flush(&b) == -1) _exit(111); + _exit(0); +} diff --git a/auto_home.h b/auto_home.h new file mode 100644 index 0000000..bd59284 --- /dev/null +++ b/auto_home.h @@ -0,0 +1,6 @@ +#ifndef AUTO_HOME_H +#define AUTO_HOME_H + +extern const char auto_home[]; + +#endif diff --git a/axfr-get.c b/axfr-get.c new file mode 100644 index 0000000..75db627 --- /dev/null +++ b/axfr-get.c @@ -0,0 +1,373 @@ +#include +#include +#include "uint32.h" +#include "uint16.h" +#include "stralloc.h" +#include "error.h" +#include "strerr.h" +#include "getln.h" +#include "buffer.h" +#include "exit.h" +#include "open.h" +#include "scan.h" +#include "byte.h" +#include "str.h" +#include "ip4.h" +#include "timeoutread.h" +#include "timeoutwrite.h" +#include "dns.h" + +#define FATAL "axfr-get: fatal: " + +void die_usage(void) +{ + strerr_die1x(100,"axfr-get: usage: axfr-get zone fn fn.tmp"); +} +void die_generate(void) +{ + strerr_die2sys(111,FATAL,"unable to generate AXFR query: "); +} +void die_parse(void) +{ + strerr_die2sys(111,FATAL,"unable to parse AXFR results: "); +} +unsigned int x_copy(char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen) +{ + pos = dns_packet_copy(buf,len,pos,out,outlen); + if (!pos) die_parse(); + return pos; +} +unsigned int x_getname(char *buf,unsigned int len,unsigned int pos,char **out) +{ + pos = dns_packet_getname(buf,len,pos,out); + if (!pos) die_parse(); + return pos; +} +unsigned int x_skipname(char *buf,unsigned int len,unsigned int pos) +{ + pos = dns_packet_skipname(buf,len,pos); + if (!pos) die_parse(); + return pos; +} + +static char *zone; +unsigned int zonelen; +char *fn; +char *fntmp; + +void die_netread(void) +{ + strerr_die2sys(111,FATAL,"unable to read from network: "); +} +void die_netwrite(void) +{ + strerr_die2sys(111,FATAL,"unable to write to network: "); +} +void die_read(void) +{ + strerr_die4sys(111,FATAL,"unable to read ",fn,": "); +} +void die_write(void) +{ + strerr_die4sys(111,FATAL,"unable to write ",fntmp,": "); +} + +int saferead(int fd,char *buf,unsigned int len) +{ + int r; + r = timeoutread(60,fd,buf,len); + if (r == 0) { errno = error_proto; die_parse(); } + if (r <= 0) die_netread(); + return r; +} +int safewrite(int fd,char *buf,unsigned int len) +{ + int r; + r = timeoutwrite(60,fd,buf,len); + if (r <= 0) die_netwrite(); + return r; +} +char netreadspace[1024]; +buffer netread = BUFFER_INIT(saferead,6,netreadspace,sizeof netreadspace); +char netwritespace[1024]; +buffer netwrite = BUFFER_INIT(safewrite,7,netwritespace,sizeof netwritespace); + +void netget(char *buf,unsigned int len) +{ + int r; + + while (len > 0) { + r = buffer_get(&netread,buf,len); + buf += r; len -= r; + } +} + +int fd; +buffer b; +char bspace[1024]; + +void put(char *buf,unsigned int len) +{ + if (buffer_put(&b,buf,len) == -1) die_write(); +} + +int printable(char ch) +{ + if (ch == '.') return 1; + if ((ch >= 'a') && (ch <= 'z')) return 1; + if ((ch >= '0') && (ch <= '9')) return 1; + if ((ch >= 'A') && (ch <= 'Z')) return 1; + if (ch == '-') return 1; + return 0; +} + +static char *d1; +static char *d2; +static char *d3; + +stralloc line; +int match; + +int numsoa; + +unsigned int doit(char *buf,unsigned int len,unsigned int pos) +{ + char data[20]; + uint32 ttl; + uint16 dlen; + uint16 typenum; + uint32 u32; + int i; + + pos = x_getname(buf,len,pos,&d1); + pos = x_copy(buf,len,pos,data,10); + uint16_unpack_big(data,&typenum); + uint32_unpack_big(data + 4,&ttl); + uint16_unpack_big(data + 8,&dlen); + if (len - pos < dlen) { errno = error_proto; return 0; } + len = pos + dlen; + + if (!dns_domain_suffix(d1,zone)) return len; + if (byte_diff(data + 2,2,DNS_C_IN)) return len; + + if (byte_equal(data,2,DNS_T_SOA)) { + if (++numsoa >= 2) return len; + pos = x_getname(buf,len,pos,&d2); + pos = x_getname(buf,len,pos,&d3); + x_copy(buf,len,pos,data,20); + uint32_unpack_big(data,&u32); + if (!stralloc_copys(&line,"#")) return 0; + if (!stralloc_catulong0(&line,u32,0)) return 0; + if (!stralloc_cats(&line," auto axfr-get\n")) return 0; + if (!stralloc_cats(&line,"Z")) return 0; + if (!dns_domain_todot_cat(&line,d1)) return 0; + if (!stralloc_cats(&line,":")) return 0; + if (!dns_domain_todot_cat(&line,d2)) return 0; + if (!stralloc_cats(&line,".:")) return 0; + if (!dns_domain_todot_cat(&line,d3)) return 0; + if (!stralloc_cats(&line,".")) return 0; + for (i = 0;i < 5;++i) { + uint32_unpack_big(data + 4 * i,&u32); + if (!stralloc_cats(&line,":")) return 0; + if (!stralloc_catulong0(&line,u32,0)) return 0; + } + } + else if (byte_equal(data,2,DNS_T_NS)) { + if (!stralloc_copys(&line,"&")) return 0; + if (byte_equal(d1,2,"\1*")) { errno = error_proto; return 0; } + if (!dns_domain_todot_cat(&line,d1)) return 0; + if (!stralloc_cats(&line,"::")) return 0; + x_getname(buf,len,pos,&d1); + if (!dns_domain_todot_cat(&line,d1)) return 0; + if (!stralloc_cats(&line,".")) return 0; + } + else if (byte_equal(data,2,DNS_T_CNAME)) { + if (!stralloc_copys(&line,"C")) return 0; + if (!dns_domain_todot_cat(&line,d1)) return 0; + if (!stralloc_cats(&line,":")) return 0; + x_getname(buf,len,pos,&d1); + if (!dns_domain_todot_cat(&line,d1)) return 0; + if (!stralloc_cats(&line,".")) return 0; + } + else if (byte_equal(data,2,DNS_T_PTR)) { + if (!stralloc_copys(&line,"^")) return 0; + if (!dns_domain_todot_cat(&line,d1)) return 0; + if (!stralloc_cats(&line,":")) return 0; + x_getname(buf,len,pos,&d1); + if (!dns_domain_todot_cat(&line,d1)) return 0; + if (!stralloc_cats(&line,".")) return 0; + } + else if (byte_equal(data,2,DNS_T_MX)) { + uint16 dist; + if (!stralloc_copys(&line,"@")) return 0; + if (!dns_domain_todot_cat(&line,d1)) return 0; + if (!stralloc_cats(&line,"::")) return 0; + pos = x_copy(buf,len,pos,data,2); + uint16_unpack_big(data,&dist); + x_getname(buf,len,pos,&d1); + if (!dns_domain_todot_cat(&line,d1)) return 0; + if (!stralloc_cats(&line,".:")) return 0; + if (!stralloc_catulong0(&line,dist,0)) return 0; + } + else if (byte_equal(data,2,DNS_T_A) && (dlen == 4)) { + char ipstr[IP4_FMT]; + if (!stralloc_copys(&line,"+")) return 0; + if (!dns_domain_todot_cat(&line,d1)) return 0; + if (!stralloc_cats(&line,":")) return 0; + x_copy(buf,len,pos,data,4); + if (!stralloc_catb(&line,ipstr,ip4_fmt(ipstr,data))) return 0; + } + else { + unsigned char ch; + unsigned char ch2; + if (!stralloc_copys(&line,":")) return 0; + if (!dns_domain_todot_cat(&line,d1)) return 0; + if (!stralloc_cats(&line,":")) return 0; + if (!stralloc_catulong0(&line,typenum,0)) return 0; + if (!stralloc_cats(&line,":")) return 0; + for (i = 0;i < dlen;++i) { + pos = x_copy(buf,len,pos,data,1); + ch = data[0]; + if (printable(ch)) { + if (!stralloc_catb(&line,&ch,1)) return 0; + } + else { + if (!stralloc_cats(&line,"\\")) return 0; + ch2 = '0' + ((ch >> 6) & 7); + if (!stralloc_catb(&line,&ch2,1)) return 0; + ch2 = '0' + ((ch >> 3) & 7); + if (!stralloc_catb(&line,&ch2,1)) return 0; + ch2 = '0' + (ch & 7); + if (!stralloc_catb(&line,&ch2,1)) return 0; + } + } + } + if (!stralloc_cats(&line,":")) return 0; + if (!stralloc_catulong0(&line,ttl,0)) return 0; + if (!stralloc_cats(&line,"\n")) return 0; + put(line.s,line.len); + + return len; +} + +stralloc packet; + +int main(int argc,char **argv) +{ + char out[20]; + unsigned long u; + uint16 dlen; + unsigned int pos; + uint32 oldserial = 0; + uint32 newserial = 0; + uint16 numqueries; + uint16 numanswers; + + if (!*argv) die_usage(); + + if (!*++argv) die_usage(); + if (!dns_domain_fromdot(&zone,*argv,str_len(*argv))) die_generate(); + zonelen = dns_domain_length(zone); + + if (!*++argv) die_usage(); + fn = *argv; + if (!*++argv) die_usage(); + fntmp = *argv; + + fd = open_read(fn); + if (fd == -1) { + if (errno != error_noent) die_read(); + } + else { + buffer_init(&b,buffer_unixread,fd,bspace,sizeof bspace); + if (getln(&b,&line,&match,'\n') == -1) die_read(); + if (!stralloc_0(&line)) die_read(); + if (line.s[0] == '#') { + scan_ulong(line.s + 1,&u); + oldserial = u; + } + close(fd); + } + + if (!stralloc_copyb(&packet,"\0\0\0\0\0\1\0\0\0\0\0\0",12)) die_generate(); + if (!stralloc_catb(&packet,zone,zonelen)) die_generate(); + if (!stralloc_catb(&packet,DNS_T_SOA DNS_C_IN,4)) die_generate(); + uint16_pack_big(out,packet.len); + buffer_put(&netwrite,out,2); + buffer_put(&netwrite,packet.s,packet.len); + buffer_flush(&netwrite); + + netget(out,2); + uint16_unpack_big(out,&dlen); + if (!stralloc_ready(&packet,dlen)) die_parse(); + netget(packet.s,dlen); + packet.len = dlen; + + pos = x_copy(packet.s,packet.len,0,out,12); + uint16_unpack_big(out + 4,&numqueries); + uint16_unpack_big(out + 6,&numanswers); + + while (numqueries) { + --numqueries; + pos = x_skipname(packet.s,packet.len,pos); + pos += 4; + } + + if (!numanswers) { errno = error_proto; die_parse(); } + pos = x_getname(packet.s,packet.len,pos,&d1); + if (!dns_domain_equal(zone,d1)) { errno = error_proto; die_parse(); } + pos = x_copy(packet.s,packet.len,pos,out,10); + if (byte_diff(out,4,DNS_T_SOA DNS_C_IN)) { errno = error_proto; die_parse(); } + pos = x_skipname(packet.s,packet.len,pos); + pos = x_skipname(packet.s,packet.len,pos); + pos = x_copy(packet.s,packet.len,pos,out,4); + + uint32_unpack_big(out,&newserial); + + + if (oldserial && newserial) /* allow 0 for very recently modified zones */ + if (oldserial == newserial) /* allow serial numbers to move backwards */ + _exit(0); + + + fd = open_trunc(fntmp); + if (fd == -1) die_write(); + buffer_init(&b,buffer_unixwrite,fd,bspace,sizeof bspace); + + if (!stralloc_copyb(&packet,"\0\0\0\0\0\1\0\0\0\0\0\0",12)) die_generate(); + if (!stralloc_catb(&packet,zone,zonelen)) die_generate(); + if (!stralloc_catb(&packet,DNS_T_AXFR DNS_C_IN,4)) die_generate(); + uint16_pack_big(out,packet.len); + buffer_put(&netwrite,out,2); + buffer_put(&netwrite,packet.s,packet.len); + buffer_flush(&netwrite); + + numsoa = 0; + while (numsoa < 2) { + netget(out,2); + uint16_unpack_big(out,&dlen); + if (!stralloc_ready(&packet,dlen)) die_parse(); + netget(packet.s,dlen); + packet.len = dlen; + + pos = x_copy(packet.s,packet.len,0,out,12); + uint16_unpack_big(out + 4,&numqueries); + + while (numqueries) { + --numqueries; + pos = x_skipname(packet.s,packet.len,pos); + pos += 4; + } + while (pos < packet.len) { + pos = doit(packet.s,packet.len,pos); + if (!pos) die_parse(); + } + } + + if (buffer_flush(&b) == -1) die_write(); + if (fsync(fd) == -1) die_write(); + if (close(fd) == -1) die_write(); /* NFS dorks */ + if (rename(fntmp,fn) == -1) + strerr_die6sys(111,FATAL,"unable to move ",fntmp," to ",fn,": "); + _exit(0); +} diff --git a/axfrdns-conf.c b/axfrdns-conf.c new file mode 100644 index 0000000..4dc8657 --- /dev/null +++ b/axfrdns-conf.c @@ -0,0 +1,71 @@ +#include +#include +#include "strerr.h" +#include "exit.h" +#include "auto_home.h" +#include "generic-conf.h" + +#define FATAL "axfrdns-conf: fatal: " + +void usage(void) +{ + strerr_die1x(100,"axfrdns-conf: usage: axfrdns-conf acct logacct /axfrdns /tinydns myip"); +} + +char *dir; +char *user; +char *loguser; +struct passwd *pw; +char *myip; +char *tinydns; + +int main(int argc,char **argv) +{ + user = argv[1]; + if (!user) usage(); + loguser = argv[2]; + if (!loguser) usage(); + dir = argv[3]; + if (!dir) usage(); + if (dir[0] != '/') usage(); + tinydns = argv[4]; + if (!tinydns) usage(); + if (tinydns[0] != '/') usage(); + myip = argv[5]; + if (!myip) usage(); + + pw = getpwnam(loguser); + if (!pw) + strerr_die3x(111,FATAL,"unknown account ",loguser); + + init(dir,FATAL); + makelog(loguser,pw->pw_uid,pw->pw_gid); + + makedir("env"); + perm(02755); + start("env/ROOT"); outs(tinydns); outs("/root\n"); finish(); + perm(0644); + start("env/IP"); outs(myip); outs("\n"); finish(); + perm(0644); + + start("run"); + outs("#!/bin/sh\nexec 2>&1\nexec envdir ./env sh -c '\n exec envuidgid "); outs(user); + outs(" softlimit -d300000 tcpserver -vDRHl0 -x tcp.cdb -- \"$IP\" 53 "); + outs(auto_home); outs("/bin/axfrdns\n'\n"); + finish(); + perm(0755); + + start("Makefile"); + outs("tcp.cdb: tcp\n"); + outs("\ttcprules tcp.cdb tcp.tmp < tcp\n"); + finish(); + perm(0644); + + start("tcp"); + outs("# sample line: 1.2.3.4:allow,AXFR=\"heaven.af.mil/3.2.1.in-addr.arpa\"\n"); + outs(":deny\n"); + finish(); + perm(0644); + + _exit(0); +} diff --git a/axfrdns.c b/axfrdns.c new file mode 100644 index 0000000..7079850 --- /dev/null +++ b/axfrdns.c @@ -0,0 +1,378 @@ +#include +#include "droproot.h" +#include "exit.h" +#include "env.h" +#include "uint32.h" +#include "uint16.h" +#include "ip4.h" +#include "tai.h" +#include "buffer.h" +#include "timeoutread.h" +#include "timeoutwrite.h" +#include "open.h" +#include "seek.h" +#include "cdb.h" +#include "stralloc.h" +#include "strerr.h" +#include "str.h" +#include "byte.h" +#include "case.h" +#include "dns.h" +#include "scan.h" +#include "qlog.h" +#include "response.h" + +extern int respond(char *,char *,char *); + +#define FATAL "axfrdns: fatal: " + +void nomem() +{ + strerr_die2x(111,FATAL,"out of memory"); +} +void die_truncated() +{ + strerr_die2x(111,FATAL,"truncated request"); +} +void die_netwrite() +{ + strerr_die2sys(111,FATAL,"unable to write to network: "); +} +void die_netread() +{ + strerr_die2sys(111,FATAL,"unable to read from network: "); +} +void die_outside() +{ + strerr_die2x(111,FATAL,"unable to locate information in data.cdb"); +} +void die_cdbread() +{ + strerr_die2sys(111,FATAL,"unable to read data.cdb: "); +} +void die_cdbformat() +{ + strerr_die3x(111,FATAL,"unable to read data.cdb: ","format error"); +} + +int safewrite(int fd,char *buf,unsigned int len) +{ + int w; + + w = timeoutwrite(60,fd,buf,len); + if (w <= 0) die_netwrite(); + return w; +} + +char netwritespace[1024]; +buffer netwrite = BUFFER_INIT(safewrite,1,netwritespace,sizeof netwritespace); + +void print(char *buf,unsigned int len) +{ + char tcpheader[2]; + uint16_pack_big(tcpheader,len); + buffer_put(&netwrite,tcpheader,2); + buffer_put(&netwrite,buf,len); + buffer_flush(&netwrite); +} + +char *axfr; +static char *axfrok; + +void axfrcheck(char *q) +{ + int i; + int j; + + if (!axfr) return; + + i = j = 0; + for (;;) { + if (!axfr[i] || (axfr[i] == '/')) { + if (i > j) { + if (!dns_domain_fromdot(&axfrok,axfr + j,i - j)) nomem(); + if (dns_domain_equal(q,axfrok)) return; + } + j = i + 1; + } + if (!axfr[i]) break; + ++i; + } + + strerr_die2x(111,FATAL,"disallowed zone transfer request"); +} + +static char *zone; +unsigned int zonelen; +char typeclass[4]; + +int fdcdb; +buffer bcdb; +char bcdbspace[1024]; + +void get(char *buf,unsigned int len) +{ + int r; + + while (len > 0) { + r = buffer_get(&bcdb,buf,len); + if (r < 0) die_cdbread(); + if (!r) die_cdbformat(); + buf += r; + len -= r; + } +} + +char ip[4]; +unsigned long port; +char clientloc[2]; + +struct tai now; +char data[32767]; +uint32 dlen; +uint32 dpos; + +void copy(char *buf,unsigned int len) +{ + dpos = dns_packet_copy(data,dlen,dpos,buf,len); + if (!dpos) die_cdbread(); +} + +void doname(stralloc *sa) +{ + static char *d; + dpos = dns_packet_getname(data,dlen,dpos,&d); + if (!dpos) die_cdbread(); + if (!stralloc_catb(sa,d,dns_domain_length(d))) nomem(); +} + +int build(stralloc *sa,char *q,int flagsoa,char id[2]) +{ + unsigned int rdatapos; + char misc[20]; + char type[2]; + char recordloc[2]; + char ttl[4]; + char ttd[8]; + struct tai cutoff; + + dpos = 0; + copy(type,2); + if (flagsoa) if (byte_diff(type,2,DNS_T_SOA)) return 0; + if (!flagsoa) if (byte_equal(type,2,DNS_T_SOA)) return 0; + + if (!stralloc_copyb(sa,id,2)) nomem(); + if (!stralloc_catb(sa,"\204\000\0\0\0\1\0\0\0\0",10)) nomem(); + copy(misc,1); + if ((misc[0] == '=' + 1) || (misc[0] == '*' + 1)) { + --misc[0]; + copy(recordloc,2); + if (byte_diff(recordloc,2,clientloc)) return 0; + } + if (misc[0] == '*') { + if (flagsoa) return 0; + if (!stralloc_catb(sa,"\1*",2)) nomem(); + } + if (!stralloc_catb(sa,q,dns_domain_length(q))) nomem(); + if (!stralloc_catb(sa,type,2)) nomem(); + + copy(ttl,4); + copy(ttd,8); + if (byte_diff(ttd,8,"\0\0\0\0\0\0\0\0")) { + tai_unpack(ttd,&cutoff); + if (byte_equal(ttl,4,"\0\0\0\0")) { + if (tai_less(&cutoff,&now)) return 0; + uint32_pack_big(ttl,2); + } + else + if (!tai_less(&cutoff,&now)) return 0; + } + + if (!stralloc_catb(sa,DNS_C_IN,2)) nomem(); + if (!stralloc_catb(sa,ttl,4)) nomem(); + if (!stralloc_catb(sa,"\0\0",2)) nomem(); + rdatapos = sa->len; + + if (byte_equal(type,2,DNS_T_SOA)) { + doname(sa); + doname(sa); + copy(misc,20); + if (!stralloc_catb(sa,misc,20)) nomem(); + } + else if (byte_equal(type,2,DNS_T_NS) || byte_equal(type,2,DNS_T_PTR) || byte_equal(type,2,DNS_T_CNAME)) { + doname(sa); + } + else if (byte_equal(type,2,DNS_T_MX)) { + copy(misc,2); + if (!stralloc_catb(sa,misc,2)) nomem(); + doname(sa); + } + else + if (!stralloc_catb(sa,data + dpos,dlen - dpos)) nomem(); + + if (sa->len > 65535) die_cdbformat(); + uint16_pack_big(sa->s + rdatapos - 2,sa->len - rdatapos); + return 1; +} + +static struct cdb c; +static char *q; +static stralloc soa; +static stralloc message; + +void doaxfr(char id[2]) +{ + char key[512]; + uint32 klen; + char num[4]; + uint32 eod; + uint32 pos; + int r; + + axfrcheck(zone); + + tai_now(&now); + cdb_init(&c,fdcdb); + + byte_zero(clientloc,2); + key[0] = 0; + key[1] = '%'; + byte_copy(key + 2,4,ip); + r = cdb_find(&c,key,6); + if (!r) r = cdb_find(&c,key,5); + if (!r) r = cdb_find(&c,key,4); + if (!r) r = cdb_find(&c,key,3); + if (!r) r = cdb_find(&c,key,2); + if (r == -1) die_cdbread(); + if (r && (cdb_datalen(&c) == 2)) + if (cdb_read(&c,clientloc,2,cdb_datapos(&c)) == -1) die_cdbread(); + + cdb_findstart(&c); + for (;;) { + r = cdb_findnext(&c,zone,zonelen); + if (r == -1) die_cdbread(); + if (!r) die_outside(); + dlen = cdb_datalen(&c); + if (dlen > sizeof data) die_cdbformat(); + if (cdb_read(&c,data,dlen,cdb_datapos(&c)) == -1) die_cdbformat(); + if (build(&soa,zone,1,id)) break; + } + + cdb_free(&c); + print(soa.s,soa.len); + + seek_begin(fdcdb); + buffer_init(&bcdb,buffer_unixread,fdcdb,bcdbspace,sizeof bcdbspace); + + pos = 0; + get(num,4); pos += 4; + uint32_unpack(num,&eod); + while (pos < 2048) { get(num,4); pos += 4; } + + while (pos < eod) { + if (eod - pos < 8) die_cdbformat(); + get(num,4); pos += 4; + uint32_unpack(num,&klen); + get(num,4); pos += 4; + uint32_unpack(num,&dlen); + if (eod - pos < klen) die_cdbformat(); + pos += klen; + if (eod - pos < dlen) die_cdbformat(); + pos += dlen; + + if (klen > sizeof key) die_cdbformat(); + get(key,klen); + if (dlen > sizeof data) die_cdbformat(); + get(data,dlen); + + if ((klen > 1) && (key[0] == 0)) continue; /* location */ + if (klen < 1) die_cdbformat(); + if (dns_packet_getname(key,klen,0,&q) != klen) die_cdbformat(); + if (!dns_domain_suffix(q,zone)) continue; + if (!build(&message,q,0,id)) continue; + print(message.s,message.len); + } + + print(soa.s,soa.len); +} + +void netread(char *buf,unsigned int len) +{ + int r; + + while (len > 0) { + r = timeoutread(60,0,buf,len); + if (r == 0) _exit(0); + if (r < 0) die_netread(); + buf += r; len -= r; + } +} + +char tcpheader[2]; +char buf[512]; +uint16 len; + +static char seed[128]; + +int main() +{ + unsigned int pos; + char header[12]; + char qtype[2]; + char qclass[2]; + const char *x; + + droproot(FATAL); + dns_random_init(seed); + + axfr = env_get("AXFR"); + + x = env_get("TCPREMOTEIP"); + if (x && ip4_scan(x,ip)) + ; + else + byte_zero(ip,4); + + x = env_get("TCPREMOTEPORT"); + if (!x) x = "0"; + scan_ulong(x,&port); + + for (;;) { + netread(tcpheader,2); + uint16_unpack_big(tcpheader,&len); + if (len > 512) strerr_die2x(111,FATAL,"excessively large request"); + netread(buf,len); + + pos = dns_packet_copy(buf,len,0,header,12); if (!pos) die_truncated(); + if (header[2] & 254) strerr_die2x(111,FATAL,"bogus query"); + if (header[4] || (header[5] != 1)) strerr_die2x(111,FATAL,"bogus query"); + + pos = dns_packet_getname(buf,len,pos,&zone); if (!pos) die_truncated(); + zonelen = dns_domain_length(zone); + pos = dns_packet_copy(buf,len,pos,qtype,2); if (!pos) die_truncated(); + pos = dns_packet_copy(buf,len,pos,qclass,2); if (!pos) die_truncated(); + + if (byte_diff(qclass,2,DNS_C_IN) && byte_diff(qclass,2,DNS_C_ANY)) + strerr_die2x(111,FATAL,"bogus query: bad class"); + + qlog(ip,port,header,zone,qtype," "); + + if (byte_equal(qtype,2,DNS_T_AXFR)) { + case_lowerb(zone,zonelen); + fdcdb = open_read("data.cdb"); + if (fdcdb == -1) die_cdbread(); + doaxfr(header); + close(fdcdb); + } + else { + if (!response_query(zone,qtype,qclass)) nomem(); + response[2] |= 4; + case_lowerb(zone,zonelen); + response_id(header); + response[3] &= ~128; + if (!(header[2] & 1)) response[2] &= ~1; + if (!respond(zone,qtype,ip)) die_outside(); + print(response,response_len); + } + } +} diff --git a/buffer.c b/buffer.c new file mode 100644 index 0000000..f44a697 --- /dev/null +++ b/buffer.c @@ -0,0 +1,10 @@ +#include "buffer.h" + +void buffer_init(buffer *s,int (*op)(),int fd,char *buf,unsigned int len) +{ + s->x = buf; + s->fd = fd; + s->op = op; + s->p = 0; + s->n = len; +} diff --git a/buffer.h b/buffer.h new file mode 100644 index 0000000..fcdc253 --- /dev/null +++ b/buffer.h @@ -0,0 +1,59 @@ +#ifndef BUFFER_H +#define BUFFER_H + +typedef struct buffer { + char *x; + unsigned int p; + unsigned int n; + int fd; + int (*op)(); +} buffer; + +#define BUFFER_INIT(op,fd,buf,len) { (buf), 0, (len), (fd), (op) } +#define BUFFER_INSIZE 8192 +#define BUFFER_OUTSIZE 8192 + +extern void buffer_init(buffer *,int (*)(),int,char *,unsigned int); + +extern int buffer_flush(buffer *); +extern int buffer_put(buffer *,const char *,unsigned int); +extern int buffer_putalign(buffer *,const char *,unsigned int); +extern int buffer_putflush(buffer *,const char *,unsigned int); +extern int buffer_puts(buffer *,const char *); +extern int buffer_putsalign(buffer *,const char *); +extern int buffer_putsflush(buffer *,const char *); + +#define buffer_PUTC(s,c) \ + ( ((s)->n != (s)->p) \ + ? ( (s)->x[(s)->p++] = (c), 0 ) \ + : buffer_put((s),&(c),1) \ + ) + +extern int buffer_get(buffer *,char *,unsigned int); +extern int buffer_bget(buffer *,char *,unsigned int); +extern int buffer_feed(buffer *); + +extern char *buffer_peek(buffer *); +extern void buffer_seek(buffer *,unsigned int); + +#define buffer_PEEK(s) ( (s)->x + (s)->n ) +#define buffer_SEEK(s,len) ( ( (s)->p -= (len) ) , ( (s)->n += (len) ) ) + +#define buffer_GETC(s,c) \ + ( ((s)->p > 0) \ + ? ( *(c) = (s)->x[(s)->n], buffer_SEEK((s),1), 1 ) \ + : buffer_get((s),(c),1) \ + ) + +extern int buffer_copy(buffer *,buffer *); + +extern int buffer_unixread(int,char *,unsigned int); +extern int buffer_unixwrite(int,const char *,unsigned int); + +extern buffer *buffer_0; +extern buffer *buffer_0small; +extern buffer *buffer_1; +extern buffer *buffer_1small; +extern buffer *buffer_2; + +#endif diff --git a/buffer_1.c b/buffer_1.c new file mode 100644 index 0000000..2b6464a --- /dev/null +++ b/buffer_1.c @@ -0,0 +1,5 @@ +#include "buffer.h" + +char buffer_1_space[BUFFER_OUTSIZE]; +static buffer it = BUFFER_INIT(buffer_unixwrite,1,buffer_1_space,sizeof buffer_1_space); +buffer *buffer_1 = ⁢ diff --git a/buffer_2.c b/buffer_2.c new file mode 100644 index 0000000..268de19 --- /dev/null +++ b/buffer_2.c @@ -0,0 +1,5 @@ +#include "buffer.h" + +char buffer_2_space[256]; +static buffer it = BUFFER_INIT(buffer_unixwrite,2,buffer_2_space,sizeof buffer_2_space); +buffer *buffer_2 = ⁢ diff --git a/buffer_copy.c b/buffer_copy.c new file mode 100644 index 0000000..dc4d4b1 --- /dev/null +++ b/buffer_copy.c @@ -0,0 +1,16 @@ +#include "buffer.h" + +int buffer_copy(buffer *bout,buffer *bin) +{ + int n; + char *x; + + for (;;) { + n = buffer_feed(bin); + if (n < 0) return -2; + if (!n) return 0; + x = buffer_PEEK(bin); + if (buffer_put(bout,x,n) == -1) return -3; + buffer_SEEK(bin,n); + } +} diff --git a/buffer_get.c b/buffer_get.c new file mode 100644 index 0000000..937b75e --- /dev/null +++ b/buffer_get.c @@ -0,0 +1,67 @@ +#include "buffer.h" +#include "byte.h" +#include "error.h" + +static int oneread(int (*op)(),int fd,char *buf,unsigned int len) +{ + int r; + + for (;;) { + r = op(fd,buf,len); + if (r == -1) if (errno == error_intr) continue; + return r; + } +} + +static int getthis(buffer *s,char *buf,unsigned int len) +{ + if (len > s->p) len = s->p; + s->p -= len; + byte_copy(buf,len,s->x + s->n); + s->n += len; + return len; +} + +int buffer_feed(buffer *s) +{ + int r; + + if (s->p) return s->p; + r = oneread(s->op,s->fd,s->x,s->n); + if (r <= 0) return r; + s->p = r; + s->n -= r; + if (s->n > 0) byte_copyr(s->x + s->n,r,s->x); + return r; +} + +int buffer_bget(buffer *s,char *buf,unsigned int len) +{ + int r; + + if (s->p > 0) return getthis(s,buf,len); + if (s->n <= len) return oneread(s->op,s->fd,buf,s->n); + r = buffer_feed(s); if (r <= 0) return r; + return getthis(s,buf,len); +} + +int buffer_get(buffer *s,char *buf,unsigned int len) +{ + int r; + + if (s->p > 0) return getthis(s,buf,len); + if (s->n <= len) return oneread(s->op,s->fd,buf,len); + r = buffer_feed(s); if (r <= 0) return r; + return getthis(s,buf,len); +} + +char *buffer_peek(buffer *s) +{ + return s->x + s->n; +} + +void buffer_seek(buffer *s,unsigned int len) +{ + s->n += len; + s->p -= len; +} diff --git a/buffer_put.c b/buffer_put.c new file mode 100644 index 0000000..f875f3f --- /dev/null +++ b/buffer_put.c @@ -0,0 +1,88 @@ +#include "buffer.h" +#include "str.h" +#include "byte.h" +#include "error.h" + +static int allwrite(int (*op)(),int fd,const char *buf,unsigned int len) +{ + int w; + + while (len) { + w = op(fd,buf,len); + if (w == -1) { + if (errno == error_intr) continue; + return -1; /* note that some data may have been written */ + } + if (w == 0) ; /* luser's fault */ + buf += w; + len -= w; + } + return 0; +} + +int buffer_flush(buffer *s) +{ + int p; + + p = s->p; + if (!p) return 0; + s->p = 0; + return allwrite(s->op,s->fd,s->x,p); +} + +int buffer_putalign(buffer *s,const char *buf,unsigned int len) +{ + unsigned int n; + + while (len > (n = s->n - s->p)) { + byte_copy(s->x + s->p,n,buf); s->p += n; buf += n; len -= n; + if (buffer_flush(s) == -1) return -1; + } + /* now len <= s->n - s->p */ + byte_copy(s->x + s->p,len,buf); + s->p += len; + return 0; +} + +int buffer_put(buffer *s,const char *buf,unsigned int len) +{ + unsigned int n; + + n = s->n; + if (len > n - s->p) { + if (buffer_flush(s) == -1) return -1; + /* now s->p == 0 */ + if (n < BUFFER_OUTSIZE) n = BUFFER_OUTSIZE; + while (len > s->n) { + if (n > len) n = len; + if (allwrite(s->op,s->fd,buf,n) == -1) return -1; + buf += n; + len -= n; + } + } + /* now len <= s->n - s->p */ + byte_copy(s->x + s->p,len,buf); + s->p += len; + return 0; +} + +int buffer_putflush(buffer *s,const char *buf,unsigned int len) +{ + if (buffer_flush(s) == -1) return -1; + return allwrite(s->op,s->fd,buf,len); +} + +int buffer_putsalign(buffer *s,const char *buf) +{ + return buffer_putalign(s,buf,str_len(buf)); +} + +int buffer_puts(buffer *s,const char *buf) +{ + return buffer_put(s,buf,str_len(buf)); +} + +int buffer_putsflush(buffer *s,const char *buf) +{ + return buffer_putflush(s,buf,str_len(buf)); +} diff --git a/buffer_read.c b/buffer_read.c new file mode 100644 index 0000000..286a06c --- /dev/null +++ b/buffer_read.c @@ -0,0 +1,7 @@ +#include +#include "buffer.h" + +int buffer_unixread(int fd,char *buf,unsigned int len) +{ + return read(fd,buf,len); +} diff --git a/buffer_write.c b/buffer_write.c new file mode 100644 index 0000000..fbd26d0 --- /dev/null +++ b/buffer_write.c @@ -0,0 +1,7 @@ +#include +#include "buffer.h" + +int buffer_unixwrite(int fd,const char *buf,unsigned int len) +{ + return write(fd,buf,len); +} diff --git a/byte.h b/byte.h new file mode 100644 index 0000000..de06c69 --- /dev/null +++ b/byte.h @@ -0,0 +1,13 @@ +#ifndef BYTE_H +#define BYTE_H + +extern unsigned int byte_chr(); +extern unsigned int byte_rchr(); +extern void byte_copy(); +extern void byte_copyr(); +extern int byte_diff(); +extern void byte_zero(); + +#define byte_equal(s,n,t) (!byte_diff((s),(n),(t))) + +#endif diff --git a/byte_chr.c b/byte_chr.c new file mode 100644 index 0000000..f81dde8 --- /dev/null +++ b/byte_chr.c @@ -0,0 +1,20 @@ +#include "byte.h" + +unsigned int byte_chr(s,n,c) +char *s; +register unsigned int n; +int c; +{ + register char ch; + register char *t; + + ch = c; + t = s; + for (;;) { + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + if (!n) break; if (*t == ch) break; ++t; --n; + } + return t - s; +} diff --git a/byte_copy.c b/byte_copy.c new file mode 100644 index 0000000..eaad11b --- /dev/null +++ b/byte_copy.c @@ -0,0 +1,14 @@ +#include "byte.h" + +void byte_copy(to,n,from) +register char *to; +register unsigned int n; +register char *from; +{ + for (;;) { + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + if (!n) return; *to++ = *from++; --n; + } +} diff --git a/byte_cr.c b/byte_cr.c new file mode 100644 index 0000000..3e7a1d5 --- /dev/null +++ b/byte_cr.c @@ -0,0 +1,16 @@ +#include "byte.h" + +void byte_copyr(to,n,from) +register char *to; +register unsigned int n; +register char *from; +{ + to += n; + from += n; + for (;;) { + if (!n) return; *--to = *--from; --n; + if (!n) return; *--to = *--from; --n; + if (!n) return; *--to = *--from; --n; + if (!n) return; *--to = *--from; --n; + } +} diff --git a/byte_diff.c b/byte_diff.c new file mode 100644 index 0000000..cdbd760 --- /dev/null +++ b/byte_diff.c @@ -0,0 +1,16 @@ +#include "byte.h" + +int byte_diff(s,n,t) +register char *s; +register unsigned int n; +register char *t; +{ + for (;;) { + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + if (!n) return 0; if (*s != *t) break; ++s; ++t; --n; + } + return ((int)(unsigned int)(unsigned char) *s) + - ((int)(unsigned int)(unsigned char) *t); +} diff --git a/byte_zero.c b/byte_zero.c new file mode 100644 index 0000000..92009ba --- /dev/null +++ b/byte_zero.c @@ -0,0 +1,13 @@ +#include "byte.h" + +void byte_zero(s,n) +char *s; +register unsigned int n; +{ + for (;;) { + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + if (!n) break; *s++ = 0; --n; + } +} diff --git a/cache.c b/cache.c new file mode 100644 index 0000000..6302428 --- /dev/null +++ b/cache.c @@ -0,0 +1,207 @@ +#include "alloc.h" +#include "byte.h" +#include "uint32.h" +#include "exit.h" +#include "tai.h" +#include "cache.h" + +uint64 cache_motion = 0; + +static char *x = 0; +static uint32 size; +static uint32 hsize; +static uint32 writer; +static uint32 oldest; +static uint32 unused; + +/* +100 <= size <= 1000000000. +4 <= hsize <= size/16. +hsize is a power of 2. + +hsize <= writer <= oldest <= unused <= size. +If oldest == unused then unused == size. + +x is a hash table with the following structure: +x[0...hsize-1]: hsize/4 head links. +x[hsize...writer-1]: consecutive entries, newest entry on the right. +x[writer...oldest-1]: free space for new entries. +x[oldest...unused-1]: consecutive entries, oldest entry on the left. +x[unused...size-1]: unused. + +Each hash bucket is a linked list containing the following items: +the head link, the newest entry, the second-newest entry, etc. +Each link is a 4-byte number giving the xor of +the positions of the adjacent items in the list. + +Entries are always inserted immediately after the head and removed at the tail. + +Each entry contains the following information: +4-byte link; 4-byte keylen; 4-byte datalen; 8-byte expire time; key; data. +*/ + +#define MAXKEYLEN 1000 +#define MAXDATALEN 1000000 + +static void cache_impossible(void) +{ + _exit(111); +} + +static void set4(uint32 pos,uint32 u) +{ + if (pos > size - 4) cache_impossible(); + uint32_pack(x + pos,u); +} + +static uint32 get4(uint32 pos) +{ + uint32 result; + if (pos > size - 4) cache_impossible(); + uint32_unpack(x + pos,&result); + return result; +} + +static unsigned int hash(const char *key,unsigned int keylen) +{ + unsigned int result = 5381; + + while (keylen) { + result = (result << 5) + result; + result ^= (unsigned char) *key; + ++key; + --keylen; + } + result <<= 2; + result &= hsize - 4; + return result; +} + +char *cache_get(const char *key,unsigned int keylen,unsigned int *datalen,uint32 *ttl) +{ + struct tai expire; + struct tai now; + uint32 pos; + uint32 prevpos; + uint32 nextpos; + uint32 u; + unsigned int loop; + double d; + + if (!x) return 0; + if (keylen > MAXKEYLEN) return 0; + + prevpos = hash(key,keylen); + pos = get4(prevpos); + loop = 0; + + while (pos) { + if (get4(pos + 4) == keylen) { + if (pos + 20 + keylen > size) cache_impossible(); + if (byte_equal(key,keylen,x + pos + 20)) { + tai_unpack(x + pos + 12,&expire); + tai_now(&now); + if (tai_less(&expire,&now)) return 0; + + tai_sub(&expire,&expire,&now); + d = tai_approx(&expire); + if (d > 604800) d = 604800; + *ttl = d; + + u = get4(pos + 8); + if (u > size - pos - 20 - keylen) cache_impossible(); + *datalen = u; + + return x + pos + 20 + keylen; + } + } + nextpos = prevpos ^ get4(pos); + prevpos = pos; + pos = nextpos; + if (++loop > 100) return 0; /* to protect against hash flooding */ + } + + return 0; +} + +void cache_set(const char *key,unsigned int keylen,const char *data,unsigned int datalen,uint32 ttl) +{ + struct tai now; + struct tai expire; + unsigned int entrylen; + unsigned int keyhash; + uint32 pos; + + if (!x) return; + if (keylen > MAXKEYLEN) return; + if (datalen > MAXDATALEN) return; + + if (!ttl) return; + if (ttl > 604800) ttl = 604800; + + entrylen = keylen + datalen + 20; + + while (writer + entrylen > oldest) { + if (oldest == unused) { + if (writer <= hsize) return; + unused = writer; + oldest = hsize; + writer = hsize; + } + + pos = get4(oldest); + set4(pos,get4(pos) ^ oldest); + + oldest += get4(oldest + 4) + get4(oldest + 8) + 20; + if (oldest > unused) cache_impossible(); + if (oldest == unused) { + unused = size; + oldest = size; + } + } + + keyhash = hash(key,keylen); + + tai_now(&now); + tai_uint(&expire,ttl); + tai_add(&expire,&expire,&now); + + pos = get4(keyhash); + if (pos) + set4(pos,get4(pos) ^ keyhash ^ writer); + set4(writer,pos ^ keyhash); + set4(writer + 4,keylen); + set4(writer + 8,datalen); + tai_pack(x + writer + 12,&expire); + byte_copy(x + writer + 20,keylen,key); + byte_copy(x + writer + 20 + keylen,datalen,data); + + set4(keyhash,writer); + writer += entrylen; + cache_motion += entrylen; +} + +int cache_init(unsigned int cachesize) +{ + if (x) { + alloc_free(x); + x = 0; + } + + if (cachesize > 1000000000) cachesize = 1000000000; + if (cachesize < 100) cachesize = 100; + size = cachesize; + + hsize = 4; + while (hsize <= (size >> 5)) hsize <<= 1; + + x = alloc(size); + if (!x) return 0; + byte_zero(x,size); + + writer = hsize; + oldest = size; + unused = size; + + return 1; +} diff --git a/cache.h b/cache.h new file mode 100644 index 0000000..f5306c5 --- /dev/null +++ b/cache.h @@ -0,0 +1,12 @@ +#ifndef CACHE_H +#define CACHE_H + +#include "uint32.h" +#include "uint64.h" + +extern uint64 cache_motion; +extern int cache_init(unsigned int); +extern void cache_set(const char *,unsigned int,const char *,unsigned int,uint32); +extern char *cache_get(const char *,unsigned int,unsigned int *,uint32 *); + +#endif diff --git a/cachetest.c b/cachetest.c new file mode 100644 index 0000000..c689862 --- /dev/null +++ b/cachetest.c @@ -0,0 +1,32 @@ +#include "buffer.h" +#include "exit.h" +#include "cache.h" +#include "str.h" + +int main(int argc,char **argv) +{ + int i; + char *x; + char *y; + unsigned int u; + uint32 ttl; + + if (!cache_init(200)) _exit(111); + + if (*argv) ++argv; + + while (x = *argv++) { + i = str_chr(x,':'); + if (x[i]) + cache_set(x,i,x + i + 1,str_len(x) - i - 1,86400); + else { + y = cache_get(x,i,&u,&ttl); + if (y) + buffer_put(buffer_1,y,u); + buffer_puts(buffer_1,"\n"); + } + } + + buffer_flush(buffer_1); + _exit(0); +} diff --git a/case.h b/case.h new file mode 100644 index 0000000..8293a04 --- /dev/null +++ b/case.h @@ -0,0 +1,13 @@ +#ifndef CASE_H +#define CASE_H + +extern void case_lowers(char *); +extern void case_lowerb(char *,unsigned int); +extern int case_diffs(const char *,const char *); +extern int case_diffb(const char *,unsigned int,const char *); +extern int case_starts(const char *,const char *); +extern int case_startb(const char *,unsigned int,const char *); + +#define case_equals(s,t) (!case_diffs((s),(t))) + +#endif diff --git a/case_diffb.c b/case_diffb.c new file mode 100644 index 0000000..b62a4b2 --- /dev/null +++ b/case_diffb.c @@ -0,0 +1,18 @@ +#include "case.h" + +int case_diffb(register const char *s,register unsigned int len,register const char *t) +{ + register unsigned char x; + register unsigned char y; + + while (len > 0) { + --len; + x = *s++ - 'A'; + if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; + y = *t++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (x != y) + return ((int)(unsigned int) x) - ((int)(unsigned int) y); + } + return 0; +} diff --git a/case_diffs.c b/case_diffs.c new file mode 100644 index 0000000..683977a --- /dev/null +++ b/case_diffs.c @@ -0,0 +1,17 @@ +#include "case.h" + +int case_diffs(register const char *s,register const char *t) +{ + register unsigned char x; + register unsigned char y; + + for (;;) { + x = *s++ - 'A'; + if (x <= 'Z' - 'A') x += 'a'; else x += 'A'; + y = *t++ - 'A'; + if (y <= 'Z' - 'A') y += 'a'; else y += 'A'; + if (x != y) break; + if (!x) break; + } + return ((int)(unsigned int) x) - ((int)(unsigned int) y); +} diff --git a/case_lowerb.c b/case_lowerb.c new file mode 100644 index 0000000..829c981 --- /dev/null +++ b/case_lowerb.c @@ -0,0 +1,12 @@ +#include "case.h" + +void case_lowerb(char *s,unsigned int len) +{ + unsigned char x; + while (len > 0) { + --len; + x = *s - 'A'; + if (x <= 'Z' - 'A') *s = x + 'a'; + ++s; + } +} diff --git a/cdb.c b/cdb.c new file mode 100644 index 0000000..3ba1ea3 --- /dev/null +++ b/cdb.c @@ -0,0 +1,136 @@ +/* Public domain. */ + +#include +#include +#include +#include +#include "error.h" +#include "seek.h" +#include "byte.h" +#include "cdb.h" + +void cdb_free(struct cdb *c) +{ + if (c->map) { + munmap(c->map,c->size); + c->map = 0; + } +} + +void cdb_findstart(struct cdb *c) +{ + c->loop = 0; +} + +void cdb_init(struct cdb *c,int fd) +{ + struct stat st; + char *x; + + cdb_free(c); + cdb_findstart(c); + c->fd = fd; + + if (fstat(fd,&st) == 0) + if (st.st_size <= 0xffffffff) { + x = mmap(0,st.st_size,PROT_READ,MAP_SHARED,fd,0); + if (x + 1) { + c->size = st.st_size; + c->map = x; + } + } +} + +int cdb_read(struct cdb *c,char *buf,unsigned int len,uint32 pos) +{ + if (c->map) { + if ((pos > c->size) || (c->size - pos < len)) goto FORMAT; + byte_copy(buf,len,c->map + pos); + } + else { + if (seek_set(c->fd,pos) == -1) return -1; + while (len > 0) { + int r; + do + r = read(c->fd,buf,len); + while ((r == -1) && (errno == error_intr)); + if (r == -1) return -1; + if (r == 0) goto FORMAT; + buf += r; + len -= r; + } + } + return 0; + + FORMAT: + errno = error_proto; + return -1; +} + +static int match(struct cdb *c,const char *key,unsigned int len,uint32 pos) +{ + char buf[32]; + int n; + + while (len > 0) { + n = sizeof buf; + if (n > len) n = len; + if (cdb_read(c,buf,n,pos) == -1) return -1; + if (byte_diff(buf,n,key)) return 0; + pos += n; + key += n; + len -= n; + } + return 1; +} + +int cdb_findnext(struct cdb *c,const char *key,unsigned int len) +{ + char buf[8]; + uint32 pos; + uint32 u; + + if (!c->loop) { + u = cdb_hash(key,len); + if (cdb_read(c,buf,8,(u << 3) & 2047) == -1) return -1; + uint32_unpack(buf + 4,&c->hslots); + if (!c->hslots) return 0; + uint32_unpack(buf,&c->hpos); + c->khash = u; + u >>= 8; + u %= c->hslots; + u <<= 3; + c->kpos = c->hpos + u; + } + + while (c->loop < c->hslots) { + if (cdb_read(c,buf,8,c->kpos) == -1) return -1; + uint32_unpack(buf + 4,&pos); + if (!pos) return 0; + c->loop += 1; + c->kpos += 8; + if (c->kpos == c->hpos + (c->hslots << 3)) c->kpos = c->hpos; + uint32_unpack(buf,&u); + if (u == c->khash) { + if (cdb_read(c,buf,8,pos) == -1) return -1; + uint32_unpack(buf,&u); + if (u == len) + switch(match(c,key,len,pos + 8)) { + case -1: + return -1; + case 1: + uint32_unpack(buf + 4,&c->dlen); + c->dpos = pos + 8 + len; + return 1; + } + } + } + + return 0; +} + +int cdb_find(struct cdb *c,const char *key,unsigned int len) +{ + cdb_findstart(c); + return cdb_findnext(c,key,len); +} diff --git a/cdb.h b/cdb.h new file mode 100644 index 0000000..65d0b1a --- /dev/null +++ b/cdb.h @@ -0,0 +1,37 @@ +/* Public domain. */ + +#ifndef CDB_H +#define CDB_H + +#include "uint32.h" + +#define CDB_HASHSTART 5381 +extern uint32 cdb_hashadd(uint32,unsigned char); +extern uint32 cdb_hash(const char *,unsigned int); + +struct cdb { + char *map; /* 0 if no map is available */ + int fd; + uint32 size; /* initialized if map is nonzero */ + uint32 loop; /* number of hash slots searched under this key */ + uint32 khash; /* initialized if loop is nonzero */ + uint32 kpos; /* initialized if loop is nonzero */ + uint32 hpos; /* initialized if loop is nonzero */ + uint32 hslots; /* initialized if loop is nonzero */ + uint32 dpos; /* initialized if cdb_findnext() returns 1 */ + uint32 dlen; /* initialized if cdb_findnext() returns 1 */ +} ; + +extern void cdb_free(struct cdb *); +extern void cdb_init(struct cdb *,int fd); + +extern int cdb_read(struct cdb *,char *,unsigned int,uint32); + +extern void cdb_findstart(struct cdb *); +extern int cdb_findnext(struct cdb *,const char *,unsigned int); +extern int cdb_find(struct cdb *,const char *,unsigned int); + +#define cdb_datapos(c) ((c)->dpos) +#define cdb_datalen(c) ((c)->dlen) + +#endif diff --git a/cdb_hash.c b/cdb_hash.c new file mode 100644 index 0000000..71102e1 --- /dev/null +++ b/cdb_hash.c @@ -0,0 +1,21 @@ +/* Public domain. */ + +#include "cdb.h" + +uint32 cdb_hashadd(uint32 h,unsigned char c) +{ + h += (h << 5); + return h ^ c; +} + +uint32 cdb_hash(const char *buf,unsigned int len) +{ + uint32 h; + + h = CDB_HASHSTART; + while (len) { + h = cdb_hashadd(h,*buf++); + --len; + } + return h; +} diff --git a/cdb_make.c b/cdb_make.c new file mode 100644 index 0000000..278420f --- /dev/null +++ b/cdb_make.c @@ -0,0 +1,152 @@ +/* Public domain. */ + +#include "seek.h" +#include "error.h" +#include "alloc.h" +#include "cdb.h" +#include "cdb_make.h" + +int cdb_make_start(struct cdb_make *c,int fd) +{ + c->head = 0; + c->split = 0; + c->hash = 0; + c->numentries = 0; + c->fd = fd; + c->pos = sizeof c->final; + buffer_init(&c->b,buffer_unixwrite,fd,c->bspace,sizeof c->bspace); + return seek_set(fd,c->pos); +} + +static int posplus(struct cdb_make *c,uint32 len) +{ + uint32 newpos = c->pos + len; + if (newpos < len) { errno = error_nomem; return -1; } + c->pos = newpos; + return 0; +} + +int cdb_make_addend(struct cdb_make *c,unsigned int keylen,unsigned int datalen,uint32 h) +{ + struct cdb_hplist *head; + + head = c->head; + if (!head || (head->num >= CDB_HPLIST)) { + head = (struct cdb_hplist *) alloc(sizeof(struct cdb_hplist)); + if (!head) return -1; + head->num = 0; + head->next = c->head; + c->head = head; + } + head->hp[head->num].h = h; + head->hp[head->num].p = c->pos; + ++head->num; + ++c->numentries; + if (posplus(c,8) == -1) return -1; + if (posplus(c,keylen) == -1) return -1; + if (posplus(c,datalen) == -1) return -1; + return 0; +} + +int cdb_make_addbegin(struct cdb_make *c,unsigned int keylen,unsigned int datalen) +{ + char buf[8]; + + if (keylen > 0xffffffff) { errno = error_nomem; return -1; } + if (datalen > 0xffffffff) { errno = error_nomem; return -1; } + + uint32_pack(buf,keylen); + uint32_pack(buf + 4,datalen); + if (buffer_putalign(&c->b,buf,8) == -1) return -1; + return 0; +} + +int cdb_make_add(struct cdb_make *c,const char *key,unsigned int keylen,const char *data,unsigned int datalen) +{ + if (cdb_make_addbegin(c,keylen,datalen) == -1) return -1; + if (buffer_putalign(&c->b,key,keylen) == -1) return -1; + if (buffer_putalign(&c->b,data,datalen) == -1) return -1; + return cdb_make_addend(c,keylen,datalen,cdb_hash(key,keylen)); +} + +int cdb_make_finish(struct cdb_make *c) +{ + char buf[8]; + int i; + uint32 len; + uint32 u; + uint32 memsize; + uint32 count; + uint32 where; + struct cdb_hplist *x; + struct cdb_hp *hp; + + for (i = 0;i < 256;++i) + c->count[i] = 0; + + for (x = c->head;x;x = x->next) { + i = x->num; + while (i--) + ++c->count[255 & x->hp[i].h]; + } + + memsize = 1; + for (i = 0;i < 256;++i) { + u = c->count[i] * 2; + if (u > memsize) + memsize = u; + } + + memsize += c->numentries; /* no overflow possible up to now */ + u = (uint32) 0 - (uint32) 1; + u /= sizeof(struct cdb_hp); + if (memsize > u) { errno = error_nomem; return -1; } + + c->split = (struct cdb_hp *) alloc(memsize * sizeof(struct cdb_hp)); + if (!c->split) return -1; + + c->hash = c->split + c->numentries; + + u = 0; + for (i = 0;i < 256;++i) { + u += c->count[i]; /* bounded by numentries, so no overflow */ + c->start[i] = u; + } + + for (x = c->head;x;x = x->next) { + i = x->num; + while (i--) + c->split[--c->start[255 & x->hp[i].h]] = x->hp[i]; + } + + for (i = 0;i < 256;++i) { + count = c->count[i]; + + len = count + count; /* no overflow possible */ + uint32_pack(c->final + 8 * i,c->pos); + uint32_pack(c->final + 8 * i + 4,len); + + for (u = 0;u < len;++u) + c->hash[u].h = c->hash[u].p = 0; + + hp = c->split + c->start[i]; + for (u = 0;u < count;++u) { + where = (hp->h >> 8) % len; + while (c->hash[where].p) + if (++where == len) + where = 0; + c->hash[where] = *hp++; + } + + for (u = 0;u < len;++u) { + uint32_pack(buf,c->hash[u].h); + uint32_pack(buf + 4,c->hash[u].p); + if (buffer_putalign(&c->b,buf,8) == -1) return -1; + if (posplus(c,8) == -1) return -1; + } + } + + if (buffer_flush(&c->b) == -1) return -1; + if (seek_begin(c->fd) == -1) return -1; + return buffer_putflush(&c->b,c->final,sizeof c->final); +} diff --git a/cdb_make.h b/cdb_make.h new file mode 100644 index 0000000..49ea719 --- /dev/null +++ b/cdb_make.h @@ -0,0 +1,39 @@ +/* Public domain. */ + +#ifndef CDB_MAKE_H +#define CDB_MAKE_H + +#include "buffer.h" +#include "uint32.h" + +#define CDB_HPLIST 1000 + +struct cdb_hp { uint32 h; uint32 p; } ; + +struct cdb_hplist { + struct cdb_hp hp[CDB_HPLIST]; + struct cdb_hplist *next; + int num; +} ; + +struct cdb_make { + char bspace[8192]; + char final[2048]; + uint32 count[256]; + uint32 start[256]; + struct cdb_hplist *head; + struct cdb_hp *split; /* includes space for hash */ + struct cdb_hp *hash; + uint32 numentries; + buffer b; + uint32 pos; + int fd; +} ; + +extern int cdb_make_start(struct cdb_make *,int); +extern int cdb_make_addbegin(struct cdb_make *,unsigned int,unsigned int); +extern int cdb_make_addend(struct cdb_make *,unsigned int,unsigned int,uint32); +extern int cdb_make_add(struct cdb_make *,const char *,unsigned int,const char *,unsigned int); +extern int cdb_make_finish(struct cdb_make *); + +#endif diff --git a/chkshsgr.c b/chkshsgr.c new file mode 100644 index 0000000..2b942d8 --- /dev/null +++ b/chkshsgr.c @@ -0,0 +1,10 @@ +#include "exit.h" + +int main() +{ + short x[4]; + + x[0] = x[1] = 0; + if (getgroups(1,x) == 0) if (setgroups(1,x) == -1) _exit(1); + _exit(0); +} diff --git a/choose.sh b/choose.sh new file mode 100644 index 0000000..feff2da --- /dev/null +++ b/choose.sh @@ -0,0 +1,18 @@ + +result="$4" + +case "$1" in + *c*) ./compile $2.c >/dev/null 2>&1 || result="$3" ;; +esac + +case "$1" in + *l*) ./load $2 >/dev/null 2>&1 || result="$3" ;; +esac + +case "$1" in + *r*) ./$2 >/dev/null 2>&1 || result="$3" ;; +esac + +rm -f $2.o $2 + +exec cat "$result" diff --git a/conf-cc b/conf-cc new file mode 100644 index 0000000..b315ecb --- /dev/null +++ b/conf-cc @@ -0,0 +1,3 @@ +gcc -O2 -Wimplicit -Wunused -Wcomment -Wchar-subscripts -Wuninitialized -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings + +This will be used to compile .c files. diff --git a/conf-home b/conf-home new file mode 100644 index 0000000..e5e30ed --- /dev/null +++ b/conf-home @@ -0,0 +1,4 @@ +/usr/local + +This is the dnscache home directory. Programs will be installed in +.../bin. diff --git a/conf-ld b/conf-ld new file mode 100644 index 0000000..59a0de7 --- /dev/null +++ b/conf-ld @@ -0,0 +1,3 @@ +gcc -s + +This will be used to link .o files into an executable. diff --git a/dd.c b/dd.c new file mode 100644 index 0000000..778cbdc --- /dev/null +++ b/dd.c @@ -0,0 +1,36 @@ +#include "dns.h" +#include "dd.h" + +int dd(const char *q,const char *base,char ip[4]) +{ + int j; + unsigned int x; + + for (j = 0;;++j) { + if (dns_domain_equal(q,base)) return j; + if (j >= 4) return -1; + + if (*q <= 0) return -1; + if (*q >= 4) return -1; + if ((q[1] < '0') || (q[1] > '9')) return -1; + x = q[1] - '0'; + if (*q == 1) { + ip[j] = x; + q += 2; + continue; + } + if (!x) return -1; + if ((q[2] < '0') || (q[2] > '9')) return -1; + x = x * 10 + (q[2] - '0'); + if (*q == 2) { + ip[j] = x; + q += 3; + continue; + } + if ((q[3] < '0') || (q[3] > '9')) return -1; + x = x * 10 + (q[3] - '0'); + if (x > 255) return -1; + ip[j] = x; + q += 4; + } +} diff --git a/dd.h b/dd.h new file mode 100644 index 0000000..c090358 --- /dev/null +++ b/dd.h @@ -0,0 +1,6 @@ +#ifndef DD_H +#define DD_H + +extern int dd(const char *,const char *,char *); + +#endif diff --git a/direntry.h1 b/direntry.h1 new file mode 100644 index 0000000..446d5c7 --- /dev/null +++ b/direntry.h1 @@ -0,0 +1,10 @@ +#ifndef DIRENTRY_H +#define DIRENTRY_H + +/* sysdep: -dirent */ + +#include +#include +#define direntry struct direct + +#endif diff --git a/direntry.h2 b/direntry.h2 new file mode 100644 index 0000000..d1628a9 --- /dev/null +++ b/direntry.h2 @@ -0,0 +1,10 @@ +#ifndef DIRENTRY_H +#define DIRENTRY_H + +/* sysdep: +dirent */ + +#include +#include +#define direntry struct dirent + +#endif diff --git a/dns.h b/dns.h new file mode 100644 index 0000000..2f899ef --- /dev/null +++ b/dns.h @@ -0,0 +1,84 @@ +#ifndef DNS_H +#define DNS_H + +#include "stralloc.h" +#include "iopause.h" +#include "taia.h" + +#define DNS_C_IN "\0\1" +#define DNS_C_ANY "\0\377" + +#define DNS_T_A "\0\1" +#define DNS_T_NS "\0\2" +#define DNS_T_CNAME "\0\5" +#define DNS_T_SOA "\0\6" +#define DNS_T_PTR "\0\14" +#define DNS_T_HINFO "\0\15" +#define DNS_T_MX "\0\17" +#define DNS_T_TXT "\0\20" +#define DNS_T_RP "\0\21" +#define DNS_T_SIG "\0\30" +#define DNS_T_KEY "\0\31" +#define DNS_T_AAAA "\0\34" +#define DNS_T_AXFR "\0\374" +#define DNS_T_ANY "\0\377" + +struct dns_transmit { + char *query; /* 0, or dynamically allocated */ + unsigned int querylen; + char *packet; /* 0, or dynamically allocated */ + unsigned int packetlen; + int s1; /* 0, or 1 + an open file descriptor */ + int tcpstate; + unsigned int udploop; + unsigned int curserver; + struct taia deadline; + unsigned int pos; + const char *servers; + char localip[4]; + char qtype[2]; +} ; + +extern void dns_random_init(const char *); +extern unsigned int dns_random(unsigned int); + +extern void dns_sortip(char *,unsigned int); + +extern void dns_domain_free(char **); +extern int dns_domain_copy(char **,const char *); +extern unsigned int dns_domain_length(const char *); +extern int dns_domain_equal(const char *,const char *); +extern int dns_domain_suffix(const char *,const char *); +extern unsigned int dns_domain_suffixpos(const char *,const char *); +extern int dns_domain_fromdot(char **,const char *,unsigned int); +extern int dns_domain_todot_cat(stralloc *,const char *); + +extern unsigned int dns_packet_copy(const char *,unsigned int,unsigned int,char *,unsigned int); +extern unsigned int dns_packet_getname(const char *,unsigned int,unsigned int,char **); +extern unsigned int dns_packet_skipname(const char *,unsigned int,unsigned int); + +extern int dns_transmit_start(struct dns_transmit *,const char *,int,const char *,const char *,const char *); +extern void dns_transmit_free(struct dns_transmit *); +extern void dns_transmit_io(struct dns_transmit *,iopause_fd *,struct taia *); +extern int dns_transmit_get(struct dns_transmit *,const iopause_fd *,const struct taia *); + +extern int dns_resolvconfip(char *); +extern int dns_resolve(const char *,const char *); +extern struct dns_transmit dns_resolve_tx; + +extern int dns_ip4_packet(stralloc *,const char *,unsigned int); +extern int dns_ip4(stralloc *,const stralloc *); +extern int dns_name_packet(stralloc *,const char *,unsigned int); +extern void dns_name4_domain(char *,const char *); +#define DNS_NAME4_DOMAIN 31 +extern int dns_name4(stralloc *,const char *); +extern int dns_txt_packet(stralloc *,const char *,unsigned int); +extern int dns_txt(stralloc *,const stralloc *); +extern int dns_mx_packet(stralloc *,const char *,unsigned int); +extern int dns_mx(stralloc *,const stralloc *); + +extern int dns_resolvconfrewrite(stralloc *); +extern int dns_ip4_qualify_rules(stralloc *,stralloc *,const stralloc *,const stralloc *); +extern int dns_ip4_qualify(stralloc *,stralloc *,const stralloc *); + +#endif diff --git a/dns_dfd.c b/dns_dfd.c new file mode 100644 index 0000000..7edef6f --- /dev/null +++ b/dns_dfd.c @@ -0,0 +1,69 @@ +#include "error.h" +#include "alloc.h" +#include "byte.h" +#include "dns.h" + +int dns_domain_fromdot(char **out,const char *buf,unsigned int n) +{ + char label[63]; + unsigned int labellen = 0; /* <= sizeof label */ + char name[255]; + unsigned int namelen = 0; /* <= sizeof name */ + char ch; + char *x; + + errno = error_proto; + + for (;;) { + if (!n) break; + ch = *buf++; --n; + if (ch == '.') { + if (labellen) { + if (namelen + labellen + 1 > sizeof name) return 0; + name[namelen++] = labellen; + byte_copy(name + namelen,labellen,label); + namelen += labellen; + labellen = 0; + } + continue; + } + if (ch == '\\') { + if (!n) break; + ch = *buf++; --n; + if ((ch >= '0') && (ch <= '7')) { + ch -= '0'; + if (n && (*buf >= '0') && (*buf <= '7')) { + ch <<= 3; + ch += *buf - '0'; + ++buf; --n; + if (n && (*buf >= '0') && (*buf <= '7')) { + ch <<= 3; + ch += *buf - '0'; + ++buf; --n; + } + } + } + } + if (labellen >= sizeof label) return 0; + label[labellen++] = ch; + } + + if (labellen) { + if (namelen + labellen + 1 > sizeof name) return 0; + name[namelen++] = labellen; + byte_copy(name + namelen,labellen,label); + namelen += labellen; + labellen = 0; + } + + if (namelen + 1 > sizeof name) return 0; + name[namelen++] = 0; + + x = alloc(namelen); + if (!x) return 0; + byte_copy(x,namelen,name); + + if (*out) alloc_free(*out); + *out = x; + return 1; +} diff --git a/dns_domain.c b/dns_domain.c new file mode 100644 index 0000000..b931f1d --- /dev/null +++ b/dns_domain.c @@ -0,0 +1,74 @@ +#include "error.h" +#include "alloc.h" +#include "case.h" +#include "byte.h" +#include "dns.h" + +unsigned int dns_domain_length(const char *dn) +{ + const char *x; + unsigned char c; + + x = dn; + while (c = *x++) + x += (unsigned int) c; + return x - dn; +} + +void dns_domain_free(char **out) +{ + if (*out) { + alloc_free(*out); + *out = 0; + } +} + +int dns_domain_copy(char **out,const char *in) +{ + unsigned int len; + char *x; + + len = dns_domain_length(in); + x = alloc(len); + if (!x) return 0; + byte_copy(x,len,in); + if (*out) alloc_free(*out); + *out = x; + return 1; +} + +int dns_domain_equal(const char *dn1,const char *dn2) +{ + unsigned int len; + + len = dns_domain_length(dn1); + if (len != dns_domain_length(dn2)) return 0; + + if (case_diffb(dn1,len,dn2)) return 0; /* safe since 63 < 'A' */ + return 1; +} + +int dns_domain_suffix(const char *big,const char *little) +{ + unsigned char c; + + for (;;) { + if (dns_domain_equal(big,little)) return 1; + c = *big++; + if (!c) return 0; + big += c; + } +} + +unsigned int dns_domain_suffixpos(const char *big,const char *little) +{ + const char *orig = big; + unsigned char c; + + for (;;) { + if (dns_domain_equal(big,little)) return big - orig; + c = *big++; + if (!c) return 0; + big += c; + } +} diff --git a/dns_dtda.c b/dns_dtda.c new file mode 100644 index 0000000..ba1db4f --- /dev/null +++ b/dns_dtda.c @@ -0,0 +1,35 @@ +#include "stralloc.h" +#include "dns.h" + +int dns_domain_todot_cat(stralloc *out,const char *d) +{ + char ch; + char ch2; + unsigned char ch3; + char buf[4]; + + if (!*d) + return stralloc_append(out,"."); + + for (;;) { + ch = *d++; + while (ch--) { + ch2 = *d++; + if ((ch2 >= 'A') && (ch2 <= 'Z')) + ch2 += 32; + if (((ch2 >= 'a') && (ch2 <= 'z')) || ((ch2 >= '0') && (ch2 <= '9')) || (ch2 == '-') || (ch2 == '_')) { + if (!stralloc_append(out,&ch2)) return 0; + } + else { + ch3 = ch2; + buf[3] = '0' + (ch3 & 7); ch3 >>= 3; + buf[2] = '0' + (ch3 & 7); ch3 >>= 3; + buf[1] = '0' + (ch3 & 7); + buf[0] = '\\'; + if (!stralloc_catb(out,buf,4)) return 0; + } + } + if (!*d) return 1; + if (!stralloc_append(out,".")) return 0; + } +} diff --git a/dns_ip.c b/dns_ip.c new file mode 100644 index 0000000..e7c3a9a --- /dev/null +++ b/dns_ip.c @@ -0,0 +1,75 @@ +#include "stralloc.h" +#include "uint16.h" +#include "byte.h" +#include "dns.h" + +int dns_ip4_packet(stralloc *out,const char *buf,unsigned int len) +{ + unsigned int pos; + char header[12]; + uint16 numanswers; + uint16 datalen; + + if (!stralloc_copys(out,"")) return -1; + + pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1; + uint16_unpack_big(header + 6,&numanswers); + pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1; + pos += 4; + + while (numanswers--) { + pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1; + uint16_unpack_big(header + 8,&datalen); + if (byte_equal(header,2,DNS_T_A)) + if (byte_equal(header + 2,2,DNS_C_IN)) + if (datalen == 4) { + if (!dns_packet_copy(buf,len,pos,header,4)) return -1; + if (!stralloc_catb(out,header,4)) return -1; + } + pos += datalen; + } + + dns_sortip(out->s,out->len); + return 0; +} + +static char *q = 0; + +int dns_ip4(stralloc *out,const stralloc *fqdn) +{ + unsigned int i; + char code; + char ch; + + if (!stralloc_copys(out,"")) return -1; + code = 0; + for (i = 0;i <= fqdn->len;++i) { + if (i < fqdn->len) + ch = fqdn->s[i]; + else + ch = '.'; + + if ((ch == '[') || (ch == ']')) continue; + if (ch == '.') { + if (!stralloc_append(out,&code)) return -1; + code = 0; + continue; + } + if ((ch >= '0') && (ch <= '9')) { + code *= 10; + code += ch - '0'; + continue; + } + + if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1; + if (dns_resolve(q,DNS_T_A) == -1) return -1; + if (dns_ip4_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1; + dns_transmit_free(&dns_resolve_tx); + dns_domain_free(&q); + return 0; + } + + out->len &= ~3; + return 0; +} diff --git a/dns_ipq.c b/dns_ipq.c new file mode 100644 index 0000000..5b65e23 --- /dev/null +++ b/dns_ipq.c @@ -0,0 +1,71 @@ +#include "stralloc.h" +#include "case.h" +#include "byte.h" +#include "str.h" +#include "dns.h" + +static int doit(stralloc *work,const char *rule) +{ + char ch; + unsigned int colon; + unsigned int prefixlen; + + ch = *rule++; + if ((ch != '?') && (ch != '=') && (ch != '*') && (ch != '-')) return 1; + colon = str_chr(rule,':'); + if (!rule[colon]) return 1; + + if (work->len < colon) return 1; + prefixlen = work->len - colon; + if ((ch == '=') && prefixlen) return 1; + if (case_diffb(rule,colon,work->s + prefixlen)) return 1; + if (ch == '?') { + if (byte_chr(work->s,prefixlen,'.') < prefixlen) return 1; + if (byte_chr(work->s,prefixlen,'[') < prefixlen) return 1; + if (byte_chr(work->s,prefixlen,']') < prefixlen) return 1; + } + + work->len = prefixlen; + if (ch == '-') work->len = 0; + return stralloc_cats(work,rule + colon + 1); +} + +int dns_ip4_qualify_rules(stralloc *out,stralloc *fqdn,const stralloc *in,const stralloc *rules) +{ + unsigned int i; + unsigned int j; + unsigned int plus; + unsigned int fqdnlen; + + if (!stralloc_copy(fqdn,in)) return -1; + + for (j = i = 0;j < rules->len;++j) + if (!rules->s[j]) { + if (!doit(fqdn,rules->s + i)) return -1; + i = j + 1; + } + + fqdnlen = fqdn->len; + plus = byte_chr(fqdn->s,fqdnlen,'+'); + if (plus >= fqdnlen) + return dns_ip4(out,fqdn); + + i = plus + 1; + for (;;) { + j = byte_chr(fqdn->s + i,fqdnlen - i,'+'); + byte_copy(fqdn->s + plus,j,fqdn->s + i); + fqdn->len = plus + j; + if (dns_ip4(out,fqdn) == -1) return -1; + if (out->len) return 0; + i += j; + if (i >= fqdnlen) return 0; + ++i; + } +} + +int dns_ip4_qualify(stralloc *out,stralloc *fqdn,const stralloc *in) +{ + static stralloc rules; + if (dns_resolvconfrewrite(&rules) == -1) return -1; + return dns_ip4_qualify_rules(out,fqdn,in,&rules); +} diff --git a/dns_mx.c b/dns_mx.c new file mode 100644 index 0000000..8d38a7f --- /dev/null +++ b/dns_mx.c @@ -0,0 +1,49 @@ +#include "stralloc.h" +#include "byte.h" +#include "uint16.h" +#include "dns.h" + +static char *q = 0; + +int dns_mx_packet(stralloc *out,const char *buf,unsigned int len) +{ + unsigned int pos; + char header[12]; + char pref[2]; + uint16 numanswers; + uint16 datalen; + + if (!stralloc_copys(out,"")) return -1; + + pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1; + uint16_unpack_big(header + 6,&numanswers); + pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1; + pos += 4; + + while (numanswers--) { + pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1; + uint16_unpack_big(header + 8,&datalen); + if (byte_equal(header,2,DNS_T_MX)) + if (byte_equal(header + 2,2,DNS_C_IN)) { + if (!dns_packet_copy(buf,len,pos,pref,2)) return -1; + if (!dns_packet_getname(buf,len,pos + 2,&q)) return -1; + if (!stralloc_catb(out,pref,2)) return -1; + if (!dns_domain_todot_cat(out,q)) return -1; + if (!stralloc_0(out)) return -1; + } + pos += datalen; + } + + return 0; +} + +int dns_mx(stralloc *out,const stralloc *fqdn) +{ + if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1; + if (dns_resolve(q,DNS_T_MX) == -1) return -1; + if (dns_mx_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1; + dns_transmit_free(&dns_resolve_tx); + dns_domain_free(&q); + return 0; +} diff --git a/dns_name.c b/dns_name.c new file mode 100644 index 0000000..6f7cdc3 --- /dev/null +++ b/dns_name.c @@ -0,0 +1,48 @@ +#include "stralloc.h" +#include "uint16.h" +#include "byte.h" +#include "dns.h" + +static char *q = 0; + +int dns_name_packet(stralloc *out,const char *buf,unsigned int len) +{ + unsigned int pos; + char header[12]; + uint16 numanswers; + uint16 datalen; + + if (!stralloc_copys(out,"")) return -1; + + pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1; + uint16_unpack_big(header + 6,&numanswers); + pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1; + pos += 4; + + while (numanswers--) { + pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1; + uint16_unpack_big(header + 8,&datalen); + if (byte_equal(header,2,DNS_T_PTR)) + if (byte_equal(header + 2,2,DNS_C_IN)) { + if (!dns_packet_getname(buf,len,pos,&q)) return -1; + if (!dns_domain_todot_cat(out,q)) return -1; + return 0; + } + pos += datalen; + } + + return 0; +} + +int dns_name4(stralloc *out,const char ip[4]) +{ + char name[DNS_NAME4_DOMAIN]; + + dns_name4_domain(name,ip); + if (dns_resolve(name,DNS_T_PTR) == -1) return -1; + if (dns_name_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1; + dns_transmit_free(&dns_resolve_tx); + dns_domain_free(&q); + return 0; +} diff --git a/dns_nd.c b/dns_nd.c new file mode 100644 index 0000000..aa54e5d --- /dev/null +++ b/dns_nd.c @@ -0,0 +1,24 @@ +#include "byte.h" +#include "fmt.h" +#include "dns.h" + +void dns_name4_domain(char name[DNS_NAME4_DOMAIN],const char ip[4]) +{ + unsigned int namelen; + unsigned int i; + + namelen = 0; + i = fmt_ulong(name + namelen + 1,(unsigned long) (unsigned char) ip[3]); + name[namelen++] = i; + namelen += i; + i = fmt_ulong(name + namelen + 1,(unsigned long) (unsigned char) ip[2]); + name[namelen++] = i; + namelen += i; + i = fmt_ulong(name + namelen + 1,(unsigned long) (unsigned char) ip[1]); + name[namelen++] = i; + namelen += i; + i = fmt_ulong(name + namelen + 1,(unsigned long) (unsigned char) ip[0]); + name[namelen++] = i; + namelen += i; + byte_copy(name + namelen,14,"\7in-addr\4arpa\0"); +} diff --git a/dns_packet.c b/dns_packet.c new file mode 100644 index 0000000..6d66eeb --- /dev/null +++ b/dns_packet.c @@ -0,0 +1,77 @@ +/* +DNS should have used LZ77 instead of its own sophomoric compression algorithm. +*/ + +#include "error.h" +#include "dns.h" + +unsigned int dns_packet_copy(const char *buf,unsigned int len,unsigned int pos,char *out,unsigned int outlen) +{ + while (outlen) { + if (pos >= len) { errno = error_proto; return 0; } + *out = buf[pos++]; + ++out; --outlen; + } + return pos; +} + +unsigned int dns_packet_skipname(const char *buf,unsigned int len,unsigned int pos) +{ + unsigned char ch; + + for (;;) { + if (pos >= len) break; + ch = buf[pos++]; + if (ch >= 192) return pos + 1; + if (ch >= 64) break; + if (!ch) return pos; + pos += ch; + } + + errno = error_proto; + return 0; +} + +unsigned int dns_packet_getname(const char *buf,unsigned int len,unsigned int pos,char **d) +{ + unsigned int loop = 0; + unsigned int state = 0; + unsigned int firstcompress = 0; + unsigned int where; + unsigned char ch; + char name[255]; + unsigned int namelen = 0; + + for (;;) { + if (pos >= len) goto PROTO; ch = buf[pos++]; + if (++loop >= 1000) goto PROTO; + + if (state) { + if (namelen + 1 > sizeof name) goto PROTO; name[namelen++] = ch; + --state; + } + else { + while (ch >= 192) { + where = ch; where -= 192; where <<= 8; + if (pos >= len) goto PROTO; ch = buf[pos++]; + if (!firstcompress) firstcompress = pos; + pos = where + ch; + if (pos >= len) goto PROTO; ch = buf[pos++]; + if (++loop >= 1000) goto PROTO; + } + if (ch >= 64) goto PROTO; + if (namelen + 1 > sizeof name) goto PROTO; name[namelen++] = ch; + if (!ch) break; + state = ch; + } + } + + if (!dns_domain_copy(d,name)) return 0; + + if (firstcompress) return firstcompress; + return pos; + + PROTO: + errno = error_proto; + return 0; +} diff --git a/dns_random.c b/dns_random.c new file mode 100644 index 0000000..2158ed4 --- /dev/null +++ b/dns_random.c @@ -0,0 +1,63 @@ +#include +#include "dns.h" +#include "taia.h" +#include "uint32.h" + +static uint32 seed[32]; +static uint32 in[12]; +static uint32 out[8]; +static int outleft = 0; + +#define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b)))) +#define MUSH(i,b) x = t[i] += (((x ^ seed[i]) + sum) ^ ROTATE(x,b)); + +static void surf(void) +{ + uint32 t[12]; uint32 x; uint32 sum = 0; + int r; int i; int loop; + + for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i]; + for (i = 0;i < 8;++i) out[i] = seed[24 + i]; + x = t[11]; + for (loop = 0;loop < 2;++loop) { + for (r = 0;r < 16;++r) { + sum += 0x9e3779b9; + MUSH(0,5) MUSH(1,7) MUSH(2,9) MUSH(3,13) + MUSH(4,5) MUSH(5,7) MUSH(6,9) MUSH(7,13) + MUSH(8,5) MUSH(9,7) MUSH(10,9) MUSH(11,13) + } + for (i = 0;i < 8;++i) out[i] ^= t[i + 4]; + } +} + +void dns_random_init(const char data[128]) +{ + int i; + struct taia t; + char tpack[16]; + + for (i = 0;i < 32;++i) + uint32_unpack(data + 4 * i,seed + i); + + taia_now(&t); + taia_pack(tpack,&t); + for (i = 0;i < 4;++i) + uint32_unpack(tpack + 4 * i,in + 4 + i); + + in[8] = getpid(); + in[9] = getppid(); + /* more space in 10 and 11, but this is probably enough */ +} + +unsigned int dns_random(unsigned int n) +{ + if (!n) return 0; + + if (!outleft) { + if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3]; + surf(); + outleft = 8; + } + + return out[--outleft] % n; +} diff --git a/dns_rcip.c b/dns_rcip.c new file mode 100644 index 0000000..97bd8f5 --- /dev/null +++ b/dns_rcip.c @@ -0,0 +1,86 @@ +#include "taia.h" +#include "openreadclose.h" +#include "byte.h" +#include "ip4.h" +#include "env.h" +#include "dns.h" + +static stralloc data = {0}; + +static int init(char ip[64]) +{ + int i; + int j; + int iplen = 0; + char *x; + + x = env_get("DNSCACHEIP"); + if (x) + while (iplen <= 60) { + if (*x == '.') + ++x; + else { + i = ip4_scan(x,ip + iplen); + if (!i) break; + x += i; + iplen += 4; + } + } + + if (!iplen) { + i = openreadclose("/etc/resolv.conf",&data,64); + if (i == -1) return -1; + if (i) { + if (!stralloc_append(&data,"\n")) return -1; + i = 0; + for (j = 0;j < data.len;++j) + if (data.s[j] == '\n') { + if (byte_equal("nameserver ",11,data.s + i) || byte_equal("nameserver\t",11,data.s + i)) { + i += 10; + while ((data.s[i] == ' ') || (data.s[i] == '\t')) + ++i; + if (iplen <= 60) + if (ip4_scan(data.s + i,ip + iplen)) { + if (byte_equal(ip + iplen,4,"\0\0\0\0")) + byte_copy(ip + iplen,4,"\177\0\0\1"); + iplen += 4; + } + } + i = j + 1; + } + } + } + + if (!iplen) { + byte_copy(ip,4,"\177\0\0\1"); + iplen = 4; + } + byte_zero(ip + iplen,64 - iplen); + return 0; +} + +static int ok = 0; +static unsigned int uses; +static struct taia deadline; +static char ip[64]; /* defined if ok */ + +int dns_resolvconfip(char s[64]) +{ + struct taia now; + + taia_now(&now); + if (taia_less(&deadline,&now)) ok = 0; + if (!uses) ok = 0; + + if (!ok) { + if (init(ip) == -1) return -1; + taia_uint(&deadline,600); + taia_add(&deadline,&now,&deadline); + uses = 10000; + ok = 1; + } + + --uses; + byte_copy(s,64,ip); + return 0; +} diff --git a/dns_rcrw.c b/dns_rcrw.c new file mode 100644 index 0000000..a43f39f --- /dev/null +++ b/dns_rcrw.c @@ -0,0 +1,131 @@ +#include +#include "taia.h" +#include "env.h" +#include "byte.h" +#include "str.h" +#include "openreadclose.h" +#include "dns.h" + +static stralloc data = {0}; + +static int init(stralloc *rules) +{ + char host[256]; + const char *x; + int i; + int j; + int k; + + if (!stralloc_copys(rules,"")) return -1; + + x = env_get("DNSREWRITEFILE"); + if (!x) x = "/etc/dnsrewrite"; + + i = openreadclose(x,&data,64); + if (i == -1) return -1; + + if (i) { + if (!stralloc_append(&data,"\n")) return -1; + i = 0; + for (j = 0;j < data.len;++j) + if (data.s[j] == '\n') { + if (!stralloc_catb(rules,data.s + i,j - i)) return -1; + while (rules->len) { + if (rules->s[rules->len - 1] != ' ') + if (rules->s[rules->len - 1] != '\t') + if (rules->s[rules->len - 1] != '\r') + break; + --rules->len; + } + if (!stralloc_0(rules)) return -1; + i = j + 1; + } + return 0; + } + + x = env_get("LOCALDOMAIN"); + if (x) { + if (!stralloc_copys(&data,x)) return -1; + if (!stralloc_append(&data," ")) return -1; + if (!stralloc_copys(rules,"?:")) return -1; + i = 0; + for (j = 0;j < data.len;++j) + if (data.s[j] == ' ') { + if (!stralloc_cats(rules,"+.")) return -1; + if (!stralloc_catb(rules,data.s + i,j - i)) return -1; + i = j + 1; + } + if (!stralloc_0(rules)) return -1; + if (!stralloc_cats(rules,"*.:")) return -1; + if (!stralloc_0(rules)) return -1; + return 0; + } + + i = openreadclose("/etc/resolv.conf",&data,64); + if (i == -1) return -1; + + if (i) { + if (!stralloc_append(&data,"\n")) return -1; + i = 0; + for (j = 0;j < data.len;++j) + if (data.s[j] == '\n') { + if (byte_equal("search ",7,data.s + i) || byte_equal("search\t",7,data.s + i) || byte_equal("domain ",7,data.s + i) || byte_equal("domain\t",7,data.s + i)) { + if (!stralloc_copys(rules,"?:")) return -1; + i += 7; + while (i < j) { + k = byte_chr(data.s + i,j - i,' '); + k = byte_chr(data.s + i,k,'\t'); + if (!k) { ++i; continue; } + if (!stralloc_cats(rules,"+.")) return -1; + if (!stralloc_catb(rules,data.s + i,k)) return -1; + i += k; + } + if (!stralloc_0(rules)) return -1; + if (!stralloc_cats(rules,"*.:")) return -1; + if (!stralloc_0(rules)) return -1; + return 0; + } + i = j + 1; + } + } + + host[0] = 0; + if (gethostname(host,sizeof host) == -1) return -1; + host[(sizeof host) - 1] = 0; + i = str_chr(host,'.'); + if (host[i]) { + if (!stralloc_copys(rules,"?:")) return -1; + if (!stralloc_cats(rules,host + i)) return -1; + if (!stralloc_0(rules)) return -1; + } + if (!stralloc_cats(rules,"*.:")) return -1; + if (!stralloc_0(rules)) return -1; + + return 0; +} + +static int ok = 0; +static unsigned int uses; +static struct taia deadline; +static stralloc rules = {0}; /* defined if ok */ + +int dns_resolvconfrewrite(stralloc *out) +{ + struct taia now; + + taia_now(&now); + if (taia_less(&deadline,&now)) ok = 0; + if (!uses) ok = 0; + + if (!ok) { + if (init(&rules) == -1) return -1; + taia_uint(&deadline,600); + taia_add(&deadline,&now,&deadline); + uses = 10000; + ok = 1; + } + + --uses; + if (!stralloc_copy(out,&rules)) return -1; + return 0; +} diff --git a/dns_resolve.c b/dns_resolve.c new file mode 100644 index 0000000..8bdea0d --- /dev/null +++ b/dns_resolve.c @@ -0,0 +1,29 @@ +#include "iopause.h" +#include "taia.h" +#include "byte.h" +#include "dns.h" + +struct dns_transmit dns_resolve_tx = {0}; + +int dns_resolve(const char *q,const char qtype[2]) +{ + struct taia stamp; + struct taia deadline; + char servers[64]; + iopause_fd x[1]; + int r; + + if (dns_resolvconfip(servers) == -1) return -1; + if (dns_transmit_start(&dns_resolve_tx,servers,1,q,qtype,"\0\0\0\0") == -1) return -1; + + for (;;) { + taia_now(&stamp); + taia_uint(&deadline,120); + taia_add(&deadline,&deadline,&stamp); + dns_transmit_io(&dns_resolve_tx,x,&deadline); + iopause(x,1,&deadline,&stamp); + r = dns_transmit_get(&dns_resolve_tx,x,&stamp); + if (r == -1) return -1; + if (r == 1) return 0; + } +} diff --git a/dns_sortip.c b/dns_sortip.c new file mode 100644 index 0000000..af9b235 --- /dev/null +++ b/dns_sortip.c @@ -0,0 +1,20 @@ +#include "byte.h" +#include "dns.h" + +/* XXX: sort servers by configurable notion of closeness? */ +/* XXX: pay attention to competence of each server? */ + +void dns_sortip(char *s,unsigned int n) +{ + unsigned int i; + char tmp[4]; + + n >>= 2; + while (n > 1) { + i = dns_random(n); + --n; + byte_copy(tmp,4,s + (i << 2)); + byte_copy(s + (i << 2),4,s + (n << 2)); + byte_copy(s + (n << 2),4,tmp); + } +} diff --git a/dns_transmit.c b/dns_transmit.c new file mode 100644 index 0000000..4d6e39f --- /dev/null +++ b/dns_transmit.c @@ -0,0 +1,366 @@ +#include +#include +#include +#include "socket.h" +#include "alloc.h" +#include "error.h" +#include "byte.h" +#include "uint16.h" +#include "dns.h" + +static int serverwantstcp(const char *buf,unsigned int len) +{ + char out[12]; + + if (!dns_packet_copy(buf,len,0,out,12)) return 1; + if (out[2] & 2) return 1; + return 0; +} + +static int serverfailed(const char *buf,unsigned int len) +{ + char out[12]; + unsigned int rcode; + + if (!dns_packet_copy(buf,len,0,out,12)) return 1; + rcode = out[3]; + rcode &= 15; + if (rcode && (rcode != 3)) { errno = error_again; return 1; } + return 0; +} + +static int irrelevant(const struct dns_transmit *d,const char *buf,unsigned int len) +{ + char out[12]; + char *dn; + unsigned int pos; + + pos = dns_packet_copy(buf,len,0,out,12); if (!pos) return 1; + if (byte_diff(out,2,d->query + 2)) return 1; + if (out[4] != 0) return 1; + if (out[5] != 1) return 1; + + dn = 0; + pos = dns_packet_getname(buf,len,pos,&dn); if (!pos) return 1; + if (!dns_domain_equal(dn,d->query + 14)) { alloc_free(dn); return 1; } + alloc_free(dn); + + pos = dns_packet_copy(buf,len,pos,out,4); if (!pos) return 1; + if (byte_diff(out,2,d->qtype)) return 1; + if (byte_diff(out + 2,2,DNS_C_IN)) return 1; + + return 0; +} + +static void packetfree(struct dns_transmit *d) +{ + if (!d->packet) return; + alloc_free(d->packet); + d->packet = 0; +} + +static void queryfree(struct dns_transmit *d) +{ + if (!d->query) return; + alloc_free(d->query); + d->query = 0; +} + +static void socketfree(struct dns_transmit *d) +{ + if (!d->s1) return; + close(d->s1 - 1); + d->s1 = 0; +} + +void dns_transmit_free(struct dns_transmit *d) +{ + queryfree(d); + socketfree(d); + packetfree(d); +} + +static int randombind(struct dns_transmit *d) +{ + int j; + + for (j = 0;j < 10;++j) + if (socket_bind4(d->s1 - 1,d->localip,1025 + dns_random(64510)) == 0) + return 0; + if (socket_bind4(d->s1 - 1,d->localip,0) == 0) + return 0; + return -1; +} + +static const int timeouts[4] = { 1, 3, 11, 45 }; + +static int thisudp(struct dns_transmit *d) +{ + const char *ip; + + socketfree(d); + + while (d->udploop < 4) { + for (;d->curserver < 16;++d->curserver) { + ip = d->servers + 4 * d->curserver; + if (byte_diff(ip,4,"\0\0\0\0")) { + d->query[2] = dns_random(256); + d->query[3] = dns_random(256); + + d->s1 = 1 + socket_udp(); + if (!d->s1) { dns_transmit_free(d); return -1; } + if (randombind(d) == -1) { dns_transmit_free(d); return -1; } + + if (socket_connect4(d->s1 - 1,ip,53) == 0) + if (send(d->s1 - 1,d->query + 2,d->querylen - 2,0) == d->querylen - 2) { + struct taia now; + taia_now(&now); + taia_uint(&d->deadline,timeouts[d->udploop]); + taia_add(&d->deadline,&d->deadline,&now); + d->tcpstate = 0; + return 0; + } + + socketfree(d); + } + } + + ++d->udploop; + d->curserver = 0; + } + + dns_transmit_free(d); return -1; +} + +static int firstudp(struct dns_transmit *d) +{ + d->curserver = 0; + return thisudp(d); +} + +static int nextudp(struct dns_transmit *d) +{ + ++d->curserver; + return thisudp(d); +} + +static int thistcp(struct dns_transmit *d) +{ + struct taia now; + const char *ip; + + socketfree(d); + packetfree(d); + + for (;d->curserver < 16;++d->curserver) { + ip = d->servers + 4 * d->curserver; + if (byte_diff(ip,4,"\0\0\0\0")) { + d->query[2] = dns_random(256); + d->query[3] = dns_random(256); + + d->s1 = 1 + socket_tcp(); + if (!d->s1) { dns_transmit_free(d); return -1; } + if (randombind(d) == -1) { dns_transmit_free(d); return -1; } + + taia_now(&now); + taia_uint(&d->deadline,10); + taia_add(&d->deadline,&d->deadline,&now); + if (socket_connect4(d->s1 - 1,ip,53) == 0) { + d->tcpstate = 2; + return 0; + } + if ((errno == error_inprogress) || (errno == error_wouldblock)) { + d->tcpstate = 1; + return 0; + } + + socketfree(d); + } + } + + dns_transmit_free(d); return -1; +} + +static int firsttcp(struct dns_transmit *d) +{ + d->curserver = 0; + return thistcp(d); +} + +static int nexttcp(struct dns_transmit *d) +{ + ++d->curserver; + return thistcp(d); +} + +int dns_transmit_start(struct dns_transmit *d,const char servers[64],int flagrecursive,const char *q,const char qtype[2],const char localip[4]) +{ + unsigned int len; + + dns_transmit_free(d); + errno = error_io; + + len = dns_domain_length(q); + d->querylen = len + 18; + d->query = alloc(d->querylen); + if (!d->query) return -1; + + uint16_pack_big(d->query,len + 16); + byte_copy(d->query + 2,12,flagrecursive ? "\0\0\1\0\0\1\0\0\0\0\0\0" : "\0\0\0\0\0\1\0\0\0\0\0\0gcc-bug-workaround"); + byte_copy(d->query + 14,len,q); + byte_copy(d->query + 14 + len,2,qtype); + byte_copy(d->query + 16 + len,2,DNS_C_IN); + + byte_copy(d->qtype,2,qtype); + d->servers = servers; + byte_copy(d->localip,4,localip); + + d->udploop = flagrecursive ? 1 : 0; + + if (len + 16 > 512) return firsttcp(d); + return firstudp(d); +} + +void dns_transmit_io(struct dns_transmit *d,iopause_fd *x,struct taia *deadline) +{ + x->fd = d->s1 - 1; + + switch(d->tcpstate) { + case 0: case 3: case 4: case 5: + x->events = IOPAUSE_READ; + break; + case 1: case 2: + x->events = IOPAUSE_WRITE; + break; + } + + if (taia_less(&d->deadline,deadline)) + *deadline = d->deadline; +} + +int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when) +{ + char udpbuf[513]; + unsigned char ch; + int r; + int fd; + + errno = error_io; + fd = d->s1 - 1; + + if (!x->revents) { + if (taia_less(when,&d->deadline)) return 0; + errno = error_timeout; + if (d->tcpstate == 0) return nextudp(d); + return nexttcp(d); + } + + if (d->tcpstate == 0) { +/* +have attempted to send UDP query to each server udploop times +have sent query to curserver on UDP socket s +*/ + r = recv(fd,udpbuf,sizeof udpbuf,0); + if (r <= 0) { + if (errno == error_connrefused) if (d->udploop == 2) return 0; + return nextudp(d); + } + if (r + 1 > sizeof udpbuf) return 0; + + if (irrelevant(d,udpbuf,r)) return 0; + if (serverwantstcp(udpbuf,r)) return firsttcp(d); + if (serverfailed(udpbuf,r)) { + if (d->udploop == 2) return 0; + return nextudp(d); + } + socketfree(d); + + d->packetlen = r; + d->packet = alloc(d->packetlen); + if (!d->packet) { dns_transmit_free(d); return -1; } + byte_copy(d->packet,d->packetlen,udpbuf); + queryfree(d); + return 1; + } + + if (d->tcpstate == 1) { +/* +have sent connection attempt to curserver on TCP socket s +pos not defined +*/ + if (!socket_connected(fd)) return nexttcp(d); + d->pos = 0; + d->tcpstate = 2; + return 0; + } + + if (d->tcpstate == 2) { +/* +have connection to curserver on TCP socket s +have sent pos bytes of query +*/ + r = write(fd,d->query + d->pos,d->querylen - d->pos); + if (r <= 0) return nexttcp(d); + d->pos += r; + if (d->pos == d->querylen) { + struct taia now; + taia_now(&now); + taia_uint(&d->deadline,10); + taia_add(&d->deadline,&d->deadline,&now); + d->tcpstate = 3; + } + return 0; + } + + if (d->tcpstate == 3) { +/* +have sent entire query to curserver on TCP socket s +pos not defined +*/ + r = read(fd,&ch,1); + if (r <= 0) return nexttcp(d); + d->packetlen = ch; + d->tcpstate = 4; + return 0; + } + + if (d->tcpstate == 4) { +/* +have sent entire query to curserver on TCP socket s +pos not defined +have received one byte of packet length into packetlen +*/ + r = read(fd,&ch,1); + if (r <= 0) return nexttcp(d); + d->packetlen <<= 8; + d->packetlen += ch; + d->tcpstate = 5; + d->pos = 0; + d->packet = alloc(d->packetlen); + if (!d->packet) { dns_transmit_free(d); return -1; } + return 0; + } + + if (d->tcpstate == 5) { +/* +have sent entire query to curserver on TCP socket s +have received entire packet length into packetlen +packet is allocated +have received pos bytes of packet +*/ + r = read(fd,d->packet + d->pos,d->packetlen - d->pos); + if (r <= 0) return nexttcp(d); + d->pos += r; + if (d->pos < d->packetlen) return 0; + + socketfree(d); + if (irrelevant(d,d->packet,d->packetlen)) return nexttcp(d); + if (serverwantstcp(d->packet,d->packetlen)) return nexttcp(d); + if (serverfailed(d->packet,d->packetlen)) return nexttcp(d); + + queryfree(d); + return 1; + } + + return 0; +} diff --git a/dns_txt.c b/dns_txt.c new file mode 100644 index 0000000..44deafe --- /dev/null +++ b/dns_txt.c @@ -0,0 +1,59 @@ +#include "stralloc.h" +#include "uint16.h" +#include "byte.h" +#include "dns.h" + +int dns_txt_packet(stralloc *out,const char *buf,unsigned int len) +{ + unsigned int pos; + char header[12]; + uint16 numanswers; + uint16 datalen; + char ch; + unsigned int txtlen; + int i; + + if (!stralloc_copys(out,"")) return -1; + + pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return -1; + uint16_unpack_big(header + 6,&numanswers); + pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1; + pos += 4; + + while (numanswers--) { + pos = dns_packet_skipname(buf,len,pos); if (!pos) return -1; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) return -1; + uint16_unpack_big(header + 8,&datalen); + if (byte_equal(header,2,DNS_T_TXT)) + if (byte_equal(header + 2,2,DNS_C_IN)) { + if (pos + datalen > len) return -1; + txtlen = 0; + for (i = 0;i < datalen;++i) { + ch = buf[pos + i]; + if (!txtlen) + txtlen = (unsigned char) ch; + else { + --txtlen; + if (ch < 32) ch = '?'; + if (ch > 126) ch = '?'; + if (!stralloc_append(out,&ch)) return -1; + } + } + } + pos += datalen; + } + + return 0; +} + +static char *q = 0; + +int dns_txt(stralloc *out,const stralloc *fqdn) +{ + if (!dns_domain_fromdot(&q,fqdn->s,fqdn->len)) return -1; + if (dns_resolve(q,DNS_T_TXT) == -1) return -1; + if (dns_txt_packet(out,dns_resolve_tx.packet,dns_resolve_tx.packetlen) == -1) return -1; + dns_transmit_free(&dns_resolve_tx); + dns_domain_free(&q); + return 0; +} diff --git a/dnscache-conf.c b/dnscache-conf.c new file mode 100644 index 0000000..e8c12be --- /dev/null +++ b/dnscache-conf.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include "hasdevtcp.h" +#ifdef HASDEVTCP +#include +#endif +#include +#include "strerr.h" +#include "buffer.h" +#include "uint32.h" +#include "taia.h" +#include "str.h" +#include "open.h" +#include "error.h" +#include "exit.h" +#include "auto_home.h" +#include "generic-conf.h" + +#define FATAL "dnscache-conf: fatal: " + +void usage(void) +{ + strerr_die1x(100,"dnscache-conf: usage: dnscache-conf acct logacct /dnscache [ myip ]"); +} + +int fdrootservers; +char rootserversbuf[64]; +buffer ssrootservers; + +char *dir; +char *user; +char *loguser; +struct passwd *pw; +const char *myip; + +uint32 seed[32]; +int seedpos = 0; + +void seed_adduint32(uint32 u) +{ + int i; + + seed[seedpos] += u; + if (++seedpos == 32) { + for (i = 0;i < 32;++i) { + u = ((u ^ seed[i]) + 0x9e3779b9) ^ (u << 7) ^ (u >> 25); + seed[i] = u; + } + seedpos = 0; + } +} + +void seed_addtime(void) +{ + struct taia t; + char tpack[TAIA_PACK]; + int i; + + taia_now(&t); + taia_pack(tpack,&t); + for (i = 0;i < TAIA_PACK;++i) + seed_adduint32(tpack[i]); +} + +int main(int argc,char **argv) +{ + seed_addtime(); + seed_adduint32(getpid()); + seed_adduint32(getppid()); + seed_adduint32(getuid()); + seed_adduint32(getgid()); + + user = argv[1]; + if (!user) usage(); + loguser = argv[2]; + if (!loguser) usage(); + dir = argv[3]; + if (!dir) usage(); + if (dir[0] != '/') usage(); + myip = argv[4]; + if (!myip) myip = "127.0.0.1"; + + pw = getpwnam(loguser); + seed_addtime(); + if (!pw) + strerr_die3x(111,FATAL,"unknown account ",loguser); + + if (chdir(auto_home) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",auto_home,": "); + + fdrootservers = open_read("/etc/dnsroots.local"); + if (fdrootservers == -1) { + if (errno != error_noent) + strerr_die2sys(111,FATAL,"unable to open /etc/dnsroots.local: "); + fdrootservers = open_read("/etc/dnsroots.global"); + if (fdrootservers == -1) + strerr_die2sys(111,FATAL,"unable to open /etc/dnsroots.global: "); + } + + init(dir,FATAL); + + seed_addtime(); makedir("log"); + seed_addtime(); perm(02755); + seed_addtime(); makedir("log/main"); + seed_addtime(); owner(pw->pw_uid,pw->pw_gid); + seed_addtime(); perm(02755); + seed_addtime(); start("log/status"); finish(); + seed_addtime(); owner(pw->pw_uid,pw->pw_gid); + seed_addtime(); perm(0644); + seed_addtime(); makedir("env"); + seed_addtime(); perm(02755); + seed_addtime(); start("env/ROOT"); outs(dir); outs("/root\n"); finish(); + seed_addtime(); perm(0644); + seed_addtime(); start("env/IP"); outs(myip); outs("\n"); finish(); + seed_addtime(); perm(0644); + seed_addtime(); start("env/IPSEND"); outs("0.0.0.0\n"); finish(); + seed_addtime(); perm(0644); + seed_addtime(); start("env/CACHESIZE"); outs("1000000\n"); finish(); + seed_addtime(); perm(0644); + seed_addtime(); start("env/DATALIMIT"); outs("3000000\n"); finish(); + seed_addtime(); perm(0644); + seed_addtime(); start("run"); + outs("#!/bin/sh\nexec 2>&1\nexec +#include "env.h" +#include "exit.h" +#include "scan.h" +#include "strerr.h" +#include "error.h" +#include "ip4.h" +#include "uint16.h" +#include "uint64.h" +#include "socket.h" +#include "dns.h" +#include "taia.h" +#include "byte.h" +#include "roots.h" +#include "fmt.h" +#include "iopause.h" +#include "query.h" +#include "alloc.h" +#include "response.h" +#include "cache.h" +#include "ndelay.h" +#include "log.h" +#include "okclient.h" +#include "droproot.h" + +static int packetquery(char *buf,unsigned int len,char **q,char qtype[2],char qclass[2],char id[2]) +{ + unsigned int pos; + char header[12]; + + errno = error_proto; + pos = dns_packet_copy(buf,len,0,header,12); if (!pos) return 0; + if (header[2] & 128) return 0; /* must not respond to responses */ + if (!(header[2] & 1)) return 0; /* do not respond to non-recursive queries */ + if (header[2] & 120) return 0; + if (header[2] & 2) return 0; + if (byte_diff(header + 4,2,"\0\1")) return 0; + + pos = dns_packet_getname(buf,len,pos,q); if (!pos) return 0; + pos = dns_packet_copy(buf,len,pos,qtype,2); if (!pos) return 0; + pos = dns_packet_copy(buf,len,pos,qclass,2); if (!pos) return 0; + if (byte_diff(qclass,2,DNS_C_IN) && byte_diff(qclass,2,DNS_C_ANY)) return 0; + + byte_copy(id,2,header); + return 1; +} + + +static char myipoutgoing[4]; +static char myipincoming[4]; +static char buf[1024]; +uint64 numqueries = 0; + + +static int udp53; + +#define MAXUDP 200 +static struct udpclient { + struct query q; + struct taia start; + uint64 active; /* query number, if active; otherwise 0 */ + iopause_fd *io; + char ip[4]; + uint16 port; + char id[2]; +} u[MAXUDP]; +int uactive = 0; + +void u_drop(int j) +{ + if (!u[j].active) return; + log_querydrop(&u[j].active); + u[j].active = 0; --uactive; +} + +void u_respond(int j) +{ + if (!u[j].active) return; + response_id(u[j].id); + if (response_len > 512) response_tc(); + socket_send4(udp53,response,response_len,u[j].ip,u[j].port); + log_querydone(&u[j].active,response_len); + u[j].active = 0; --uactive; +} + +void u_new(void) +{ + int j; + int i; + struct udpclient *x; + int len; + static char *q = 0; + char qtype[2]; + char qclass[2]; + + for (j = 0;j < MAXUDP;++j) + if (!u[j].active) + break; + + if (j >= MAXUDP) { + j = 0; + for (i = 1;i < MAXUDP;++i) + if (taia_less(&u[i].start,&u[j].start)) + j = i; + errno = error_timeout; + u_drop(j); + } + + x = u + j; + taia_now(&x->start); + + len = socket_recv4(udp53,buf,sizeof buf,x->ip,&x->port); + if (len == -1) return; + if (len >= sizeof buf) return; + if (x->port < 1024) if (x->port != 53) return; + if (!okclient(x->ip)) return; + + if (!packetquery(buf,len,&q,qtype,qclass,x->id)) return; + + x->active = ++numqueries; ++uactive; + log_query(&x->active,x->ip,x->port,x->id,q,qtype); + switch(query_start(&x->q,q,qtype,qclass,myipoutgoing)) { + case -1: + u_drop(j); + return; + case 1: + u_respond(j); + } +} + + +static int tcp53; + +#define MAXTCP 20 +struct tcpclient { + struct query q; + struct taia start; + struct taia timeout; + uint64 active; /* query number or 1, if active; otherwise 0 */ + iopause_fd *io; + char ip[4]; /* send response to this address */ + uint16 port; /* send response to this port */ + char id[2]; + int tcp; /* open TCP socket, if active */ + int state; + char *buf; /* 0, or dynamically allocated of length len */ + unsigned int len; + unsigned int pos; +} t[MAXTCP]; +int tactive = 0; + +/* +state 1: buf 0; normal state at beginning of TCP connection +state 2: buf 0; have read 1 byte of query packet length into len +state 3: buf allocated; have read pos bytes of buf +state 0: buf 0; handling query in q +state -1: buf allocated; have written pos bytes +*/ + +void t_free(int j) +{ + if (!t[j].buf) return; + alloc_free(t[j].buf); + t[j].buf = 0; +} + +void t_timeout(int j) +{ + struct taia now; + if (!t[j].active) return; + taia_now(&now); + taia_uint(&t[j].timeout,10); + taia_add(&t[j].timeout,&t[j].timeout,&now); +} + +void t_close(int j) +{ + if (!t[j].active) return; + t_free(j); + log_tcpclose(t[j].ip,t[j].port); + close(t[j].tcp); + t[j].active = 0; --tactive; +} + +void t_drop(int j) +{ + log_querydrop(&t[j].active); + errno = error_pipe; + t_close(j); +} + +void t_respond(int j) +{ + if (!t[j].active) return; + log_querydone(&t[j].active,response_len); + response_id(t[j].id); + t[j].len = response_len + 2; + t_free(j); + t[j].buf = alloc(response_len + 2); + if (!t[j].buf) { t_close(j); return; } + uint16_pack_big(t[j].buf,response_len); + byte_copy(t[j].buf + 2,response_len,response); + t[j].pos = 0; + t[j].state = -1; +} + +void t_rw(int j) +{ + struct tcpclient *x; + char ch; + static char *q = 0; + char qtype[2]; + char qclass[2]; + int r; + + x = t + j; + if (x->state == -1) { + r = write(x->tcp,x->buf + x->pos,x->len - x->pos); + if (r <= 0) { t_close(j); return; } + x->pos += r; + if (x->pos == x->len) { + t_free(j); + x->state = 1; /* could drop connection immediately */ + } + return; + } + + r = read(x->tcp,&ch,1); + if (r == 0) { errno = error_pipe; t_close(j); return; } + if (r < 0) { t_close(j); return; } + + if (x->state == 1) { + x->len = (unsigned char) ch; + x->len <<= 8; + x->state = 2; + return; + } + if (x->state == 2) { + x->len += (unsigned char) ch; + if (!x->len) { errno = error_proto; t_close(j); return; } + x->buf = alloc(x->len); + if (!x->buf) { t_close(j); return; } + x->pos = 0; + x->state = 3; + return; + } + + if (x->state != 3) return; /* impossible */ + + x->buf[x->pos++] = ch; + if (x->pos < x->len) return; + + if (!packetquery(x->buf,x->len,&q,qtype,qclass,x->id)) { t_close(j); return; } + + x->active = ++numqueries; + log_query(&x->active,x->ip,x->port,x->id,q,qtype); + switch(query_start(&x->q,q,qtype,qclass,myipoutgoing)) { + case -1: + t_drop(j); + return; + case 1: + t_respond(j); + return; + } + t_free(j); + x->state = 0; +} + +void t_new(void) +{ + int i; + int j; + struct tcpclient *x; + + for (j = 0;j < MAXTCP;++j) + if (!t[j].active) + break; + + if (j >= MAXTCP) { + j = 0; + for (i = 1;i < MAXTCP;++i) + if (taia_less(&t[i].start,&t[j].start)) + j = i; + errno = error_timeout; + if (t[j].state == 0) + t_drop(j); + else + t_close(j); + } + + x = t + j; + taia_now(&x->start); + + x->tcp = socket_accept4(tcp53,x->ip,&x->port); + if (x->tcp == -1) return; + if (x->port < 1024) if (x->port != 53) { close(x->tcp); return; } + if (!okclient(x->ip)) { close(x->tcp); return; } + if (ndelay_on(x->tcp) == -1) { close(x->tcp); return; } /* Linux bug */ + + x->active = 1; ++tactive; + x->state = 1; + t_timeout(j); + + log_tcpopen(x->ip,x->port); +} + + +iopause_fd io[3 + MAXUDP + MAXTCP]; +iopause_fd *udp53io; +iopause_fd *tcp53io; + +static void doit(void) +{ + int j; + struct taia deadline; + struct taia stamp; + int iolen; + int r; + + for (;;) { + taia_now(&stamp); + taia_uint(&deadline,120); + taia_add(&deadline,&deadline,&stamp); + + iolen = 0; + + udp53io = io + iolen++; + udp53io->fd = udp53; + udp53io->events = IOPAUSE_READ; + + tcp53io = io + iolen++; + tcp53io->fd = tcp53; + tcp53io->events = IOPAUSE_READ; + + for (j = 0;j < MAXUDP;++j) + if (u[j].active) { + u[j].io = io + iolen++; + query_io(&u[j].q,u[j].io,&deadline); + } + for (j = 0;j < MAXTCP;++j) + if (t[j].active) { + t[j].io = io + iolen++; + if (t[j].state == 0) + query_io(&t[j].q,t[j].io,&deadline); + else { + if (taia_less(&t[j].timeout,&deadline)) deadline = t[j].timeout; + t[j].io->fd = t[j].tcp; + t[j].io->events = (t[j].state > 0) ? IOPAUSE_READ : IOPAUSE_WRITE; + } + } + + iopause(io,iolen,&deadline,&stamp); + + for (j = 0;j < MAXUDP;++j) + if (u[j].active) { + r = query_get(&u[j].q,u[j].io,&stamp); + if (r == -1) u_drop(j); + if (r == 1) u_respond(j); + } + + for (j = 0;j < MAXTCP;++j) + if (t[j].active) { + if (t[j].io->revents) + t_timeout(j); + if (t[j].state == 0) { + r = query_get(&t[j].q,t[j].io,&stamp); + if (r == -1) t_drop(j); + if (r == 1) t_respond(j); + } + else + if (t[j].io->revents || taia_less(&t[j].timeout,&stamp)) + t_rw(j); + } + + if (udp53io) + if (udp53io->revents) + u_new(); + + if (tcp53io) + if (tcp53io->revents) + t_new(); + } +} + +#define FATAL "dnscache: fatal: " + +char seed[128]; + +int main() +{ + char *x; + unsigned long cachesize; + + x = env_get("IP"); + if (!x) + strerr_die2x(111,FATAL,"$IP not set"); + if (!ip4_scan(x,myipincoming)) + strerr_die3x(111,FATAL,"unable to parse IP address ",x); + + udp53 = socket_udp(); + if (udp53 == -1) + strerr_die2sys(111,FATAL,"unable to create UDP socket: "); + if (socket_bind4_reuse(udp53,myipincoming,53) == -1) + strerr_die2sys(111,FATAL,"unable to bind UDP socket: "); + + tcp53 = socket_tcp(); + if (tcp53 == -1) + strerr_die2sys(111,FATAL,"unable to create TCP socket: "); + if (socket_bind4_reuse(tcp53,myipincoming,53) == -1) + strerr_die2sys(111,FATAL,"unable to bind TCP socket: "); + + droproot(FATAL); + + socket_tryreservein(udp53,131072); + + byte_zero(seed,sizeof seed); + read(0,seed,sizeof seed); + dns_random_init(seed); + close(0); + + x = env_get("IPSEND"); + if (!x) + strerr_die2x(111,FATAL,"$IPSEND not set"); + if (!ip4_scan(x,myipoutgoing)) + strerr_die3x(111,FATAL,"unable to parse IP address ",x); + + x = env_get("CACHESIZE"); + if (!x) + strerr_die2x(111,FATAL,"$CACHESIZE not set"); + scan_ulong(x,&cachesize); + if (!cache_init(cachesize)) + strerr_die3x(111,FATAL,"not enough memory for cache of size ",x); + + if (env_get("HIDETTL")) + response_hidettl(); + if (env_get("FORWARDONLY")) + query_forwardonly(); + + if (!roots_init()) + strerr_die2sys(111,FATAL,"unable to read servers: "); + + if (socket_listen(tcp53,20) == -1) + strerr_die2sys(111,FATAL,"unable to listen on TCP socket: "); + + log_startup(); + doit(); +} diff --git a/dnsfilter.c b/dnsfilter.c new file mode 100644 index 0000000..9e6863a --- /dev/null +++ b/dnsfilter.c @@ -0,0 +1,214 @@ +#include +#include "strerr.h" +#include "buffer.h" +#include "stralloc.h" +#include "alloc.h" +#include "dns.h" +#include "ip4.h" +#include "byte.h" +#include "scan.h" +#include "taia.h" +#include "sgetopt.h" +#include "iopause.h" +#include "error.h" +#include "exit.h" + +#define FATAL "dnsfilter: fatal: " + +void nomem(void) +{ + strerr_die2x(111,FATAL,"out of memory"); +} + +struct line { + stralloc left; + stralloc middle; + stralloc right; + struct dns_transmit dt; + int flagactive; + iopause_fd *io; +} *x; +struct line tmp; +unsigned int xmax = 1000; +unsigned int xnum = 0; +unsigned int numactive = 0; +unsigned int maxactive = 10; + +static stralloc partial; + +char inbuf[1024]; +int inbuflen = 0; +iopause_fd *inio; +int flag0 = 1; + +iopause_fd *io; +int iolen; + +char servers[64]; +char ip[4]; +char name[DNS_NAME4_DOMAIN]; + +void errout(int i) +{ + int j; + + if (!stralloc_copys(&x[i].middle,":")) nomem(); + if (!stralloc_cats(&x[i].middle,error_str(errno))) nomem(); + for (j = 0;j < x[i].middle.len;++j) + if (x[i].middle.s[j] == ' ') + x[i].middle.s[j] = '-'; +} + +int main(int argc,char **argv) +{ + struct taia stamp; + struct taia deadline; + int opt; + unsigned long u; + int i; + int j; + int r; + + while ((opt = getopt(argc,argv,"c:l:")) != opteof) + switch(opt) { + case 'c': + scan_ulong(optarg,&u); + if (u < 1) u = 1; + if (u > 1000) u = 1000; + maxactive = u; + break; + case 'l': + scan_ulong(optarg,&u); + if (u < 1) u = 1; + if (u > 1000000) u = 1000000; + xmax = u; + break; + default: + strerr_die1x(111,"dnsfilter: usage: dnsfilter [ -c concurrency ] [ -l lines ]"); + } + + x = (struct line *) alloc(xmax * sizeof(struct line)); + if (!x) nomem(); + byte_zero(x,xmax * sizeof(struct line)); + + io = (iopause_fd *) alloc((xmax + 1) * sizeof(iopause_fd)); + if (!io) nomem(); + + if (!stralloc_copys(&partial,"")) nomem(); + + + while (flag0 || inbuflen || partial.len || xnum) { + taia_now(&stamp); + taia_uint(&deadline,120); + taia_add(&deadline,&deadline,&stamp); + + iolen = 0; + + if (flag0) + if (inbuflen < sizeof inbuf) { + inio = io + iolen++; + inio->fd = 0; + inio->events = IOPAUSE_READ; + } + + for (i = 0;i < xnum;++i) + if (x[i].flagactive) { + x[i].io = io + iolen++; + dns_transmit_io(&x[i].dt,x[i].io,&deadline); + } + + iopause(io,iolen,&deadline,&stamp); + + if (flag0) + if (inbuflen < sizeof inbuf) + if (inio->revents) { + r = read(0,inbuf + inbuflen,(sizeof inbuf) - inbuflen); + if (r <= 0) + flag0 = 0; + else + inbuflen += r; + } + + for (i = 0;i < xnum;++i) + if (x[i].flagactive) { + r = dns_transmit_get(&x[i].dt,x[i].io,&stamp); + if (r == -1) { + errout(i); + x[i].flagactive = 0; + --numactive; + } + else if (r == 1) { + if (dns_name_packet(&x[i].middle,x[i].dt.packet,x[i].dt.packetlen) == -1) + errout(i); + if (x[i].middle.len) + if (!stralloc_cats(&x[i].left,"=")) nomem(); + x[i].flagactive = 0; + --numactive; + } + } + + for (;;) { + + if (xnum && !x[0].flagactive) { + buffer_put(buffer_1,x[0].left.s,x[0].left.len); + buffer_put(buffer_1,x[0].middle.s,x[0].middle.len); + buffer_put(buffer_1,x[0].right.s,x[0].right.len); + buffer_flush(buffer_1); + --xnum; + tmp = x[0]; + for (i = 0;i < xnum;++i) x[i] = x[i + 1]; + x[xnum] = tmp; + continue; + } + + if ((xnum < xmax) && (numactive < maxactive)) { + i = byte_chr(inbuf,inbuflen,'\n'); + if (inbuflen && (i == inbuflen)) { + if (!stralloc_catb(&partial,inbuf,inbuflen)) nomem(); + inbuflen = 0; + continue; + } + + if ((i < inbuflen) || (!flag0 && partial.len)) { + if (i < inbuflen) ++i; + if (!stralloc_catb(&partial,inbuf,i)) nomem(); + inbuflen -= i; + for (j = 0;j < inbuflen;++j) inbuf[j] = inbuf[j + i]; + + if (partial.len) { + i = byte_chr(partial.s,partial.len,'\n'); + i = byte_chr(partial.s,i,'\t'); + i = byte_chr(partial.s,i,' '); + + if (!stralloc_copyb(&x[xnum].left,partial.s,i)) nomem(); + if (!stralloc_copys(&x[xnum].middle,"")) nomem(); + if (!stralloc_copyb(&x[xnum].right,partial.s + i,partial.len - i)) nomem(); + x[xnum].flagactive = 0; + + partial.len = i; + if (!stralloc_0(&partial)) nomem(); + if (ip4_scan(partial.s,ip)) { + dns_name4_domain(name,ip); + if (dns_resolvconfip(servers) == -1) + strerr_die2sys(111,FATAL,"unable to read /etc/resolv.conf: "); + if (dns_transmit_start(&x[xnum].dt,servers,1,name,DNS_T_PTR,"\0\0\0\0") == -1) + errout(xnum); + else { + x[xnum].flagactive = 1; + ++numactive; + } + } + ++xnum; + } + + partial.len = 0; + continue; + } + } + + break; + } + } + + _exit(0); +} diff --git a/dnsip.c b/dnsip.c new file mode 100644 index 0000000..60c5d3d --- /dev/null +++ b/dnsip.c @@ -0,0 +1,40 @@ +#include "buffer.h" +#include "exit.h" +#include "strerr.h" +#include "ip4.h" +#include "dns.h" + +#define FATAL "dnsip: fatal: " + +static char seed[128]; + +static stralloc fqdn; +static stralloc out; +char str[IP4_FMT]; + +int main(int argc,char **argv) +{ + int i; + + dns_random_init(seed); + + if (*argv) ++argv; + + while (*argv) { + if (!stralloc_copys(&fqdn,*argv)) + strerr_die2x(111,FATAL,"out of memory"); + if (dns_ip4(&out,&fqdn) == -1) + strerr_die4sys(111,FATAL,"unable to find IP address for ",*argv,": "); + + for (i = 0;i + 4 <= out.len;i += 4) { + buffer_put(buffer_1,str,ip4_fmt(str,out.s + i)); + buffer_puts(buffer_1," "); + } + buffer_puts(buffer_1,"\n"); + + ++argv; + } + + buffer_flush(buffer_1); + _exit(0); +} diff --git a/dnsipq.c b/dnsipq.c new file mode 100644 index 0000000..8e34928 --- /dev/null +++ b/dnsipq.c @@ -0,0 +1,43 @@ +#include "buffer.h" +#include "exit.h" +#include "strerr.h" +#include "ip4.h" +#include "dns.h" + +#define FATAL "dnsipq: fatal: " + +static char seed[128]; + +static stralloc in; +static stralloc fqdn; +static stralloc out; +char str[IP4_FMT]; + +int main(int argc,char **argv) +{ + int i; + + dns_random_init(seed); + + if (*argv) ++argv; + + while (*argv) { + if (!stralloc_copys(&in,*argv)) + strerr_die2x(111,FATAL,"out of memory"); + if (dns_ip4_qualify(&out,&fqdn,&in) == -1) + strerr_die4sys(111,FATAL,"unable to find IP address for ",*argv,": "); + + buffer_put(buffer_1,fqdn.s,fqdn.len); + buffer_puts(buffer_1," "); + for (i = 0;i + 4 <= out.len;i += 4) { + buffer_put(buffer_1,str,ip4_fmt(str,out.s + i)); + buffer_puts(buffer_1," "); + } + buffer_puts(buffer_1,"\n"); + + ++argv; + } + + buffer_flush(buffer_1); + _exit(0); +} diff --git a/dnsmx.c b/dnsmx.c new file mode 100644 index 0000000..5d75d39 --- /dev/null +++ b/dnsmx.c @@ -0,0 +1,64 @@ +#include "buffer.h" +#include "exit.h" +#include "strerr.h" +#include "uint16.h" +#include "byte.h" +#include "str.h" +#include "fmt.h" +#include "dns.h" + +#define FATAL "dnsmx: fatal: " + +void nomem(void) +{ + strerr_die2x(111,FATAL,"out of memory"); +} + +static char seed[128]; + +static stralloc fqdn; +static char *q; +static stralloc out; +char strnum[FMT_ULONG]; + +int main(int argc,char **argv) +{ + int i; + int j; + uint16 pref; + + dns_random_init(seed); + + if (*argv) ++argv; + + while (*argv) { + if (!stralloc_copys(&fqdn,*argv)) nomem(); + if (dns_mx(&out,&fqdn) == -1) + strerr_die4sys(111,FATAL,"unable to find MX records for ",*argv,": "); + + if (!out.len) { + if (!dns_domain_fromdot(&q,*argv,str_len(*argv))) nomem(); + if (!stralloc_copys(&out,"0 ")) nomem(); + if (!dns_domain_todot_cat(&out,q)) nomem(); + if (!stralloc_cats(&out,"\n")) nomem(); + buffer_put(buffer_1,out.s,out.len); + } + else { + i = 0; + while (i + 2 < out.len) { + j = byte_chr(out.s + i + 2,out.len - i - 2,0); + uint16_unpack_big(out.s + i,&pref); + buffer_put(buffer_1,strnum,fmt_ulong(strnum,pref)); + buffer_puts(buffer_1," "); + buffer_put(buffer_1,out.s + i + 2,j); + buffer_puts(buffer_1,"\n"); + i += j + 3; + } + } + + ++argv; + } + + buffer_flush(buffer_1); + _exit(0); +} diff --git a/dnsname.c b/dnsname.c new file mode 100644 index 0000000..0e5eb26 --- /dev/null +++ b/dnsname.c @@ -0,0 +1,34 @@ +#include "buffer.h" +#include "exit.h" +#include "strerr.h" +#include "ip4.h" +#include "dns.h" + +#define FATAL "dnsname: fatal: " + +static char seed[128]; + +char ip[4]; +static stralloc out; + +int main(int argc,char **argv) +{ + dns_random_init(seed); + + if (*argv) ++argv; + + while (*argv) { + if (!ip4_scan(*argv,ip)) + strerr_die3x(111,FATAL,"unable to parse IP address ",*argv); + if (dns_name4(&out,ip) == -1) + strerr_die4sys(111,FATAL,"unable to find host name for ",*argv,": "); + + buffer_put(buffer_1,out.s,out.len); + buffer_puts(buffer_1,"\n"); + + ++argv; + } + + buffer_flush(buffer_1); + _exit(0); +} diff --git a/dnsq.c b/dnsq.c new file mode 100644 index 0000000..533e6af --- /dev/null +++ b/dnsq.c @@ -0,0 +1,98 @@ +#include "uint16.h" +#include "strerr.h" +#include "buffer.h" +#include "scan.h" +#include "str.h" +#include "byte.h" +#include "error.h" +#include "ip4.h" +#include "iopause.h" +#include "printpacket.h" +#include "parsetype.h" +#include "dns.h" + +#define FATAL "dnsq: fatal: " + +void usage(void) +{ + strerr_die1x(100,"dnsq: usage: dnsq type name server"); +} +void oops(void) +{ + strerr_die2sys(111,FATAL,"unable to parse: "); +} + +static struct dns_transmit tx; + +int resolve(char *q,char qtype[2],char servers[64]) +{ + struct taia stamp; + struct taia deadline; + iopause_fd x[1]; + int r; + + if (dns_transmit_start(&tx,servers,0,q,qtype,"\0\0\0\0") == -1) return -1; + + for (;;) { + taia_now(&stamp); + taia_uint(&deadline,120); + taia_add(&deadline,&deadline,&stamp); + dns_transmit_io(&tx,x,&deadline); + iopause(x,1,&deadline,&stamp); + r = dns_transmit_get(&tx,x,&stamp); + if (r == -1) return -1; + if (r == 1) break; + } + + return 0; +} + +char servers[64]; +static stralloc ip; +static stralloc fqdn; + +char type[2]; +static char *q; + +static stralloc out; + +static char seed[128]; + +int main(int argc,char **argv) +{ + uint16 u16; + + dns_random_init(seed); + + if (!*argv) usage(); + if (!*++argv) usage(); + if (!parsetype(*argv,type)) usage(); + + if (!*++argv) usage(); + if (!dns_domain_fromdot(&q,*argv,str_len(*argv))) oops(); + + if (!*++argv) usage(); + if (!stralloc_copys(&out,*argv)) oops(); + if (dns_ip4_qualify(&ip,&fqdn,&out) == -1) oops(); + if (ip.len >= 64) ip.len = 64; + byte_zero(servers,64); + byte_copy(servers,ip.len,ip.s); + + if (!stralloc_copys(&out,"")) oops(); + uint16_unpack_big(type,&u16); + if (!stralloc_catulong0(&out,u16,0)) oops(); + if (!stralloc_cats(&out," ")) oops(); + if (!dns_domain_todot_cat(&out,q)) oops(); + if (!stralloc_cats(&out,":\n")) oops(); + + if (resolve(q,type,servers) == -1) { + if (!stralloc_cats(&out,error_str(errno))) oops(); + if (!stralloc_cats(&out,"\n")) oops(); + } + else { + if (!printpacket_cat(&out,tx.packet,tx.packetlen)) oops(); + } + + buffer_putflush(buffer_1,out.s,out.len); + _exit(0); +} diff --git a/dnsqr.c b/dnsqr.c new file mode 100644 index 0000000..ff8ea6e --- /dev/null +++ b/dnsqr.c @@ -0,0 +1,66 @@ +#include "uint16.h" +#include "strerr.h" +#include "buffer.h" +#include "scan.h" +#include "str.h" +#include "byte.h" +#include "error.h" +#include "iopause.h" +#include "printpacket.h" +#include "parsetype.h" +#include "dns.h" + +#define FATAL "dnsqr: fatal: " + +void usage(void) +{ + strerr_die1x(100,"dnsqr: usage: dnsqr type name"); +} +void oops(void) +{ + strerr_die2sys(111,FATAL,"unable to parse: "); +} + +char type[2]; +static char *q; + +static stralloc out; + +static char seed[128]; + +int main(int argc,char **argv) +{ + uint16 u16; + + dns_random_init(seed); + + if (!*argv) usage(); + if (!*++argv) usage(); + if (!parsetype(*argv,type)) usage(); + + if (!*++argv) usage(); + if (!dns_domain_fromdot(&q,*argv,str_len(*argv))) oops(); + + if (*++argv) usage(); + + if (!stralloc_copys(&out,"")) oops(); + uint16_unpack_big(type,&u16); + if (!stralloc_catulong0(&out,u16,0)) oops(); + if (!stralloc_cats(&out," ")) oops(); + if (!dns_domain_todot_cat(&out,q)) oops(); + if (!stralloc_cats(&out,":\n")) oops(); + + if (dns_resolve(q,type) == -1) { + if (!stralloc_cats(&out,error_str(errno))) oops(); + if (!stralloc_cats(&out,"\n")) oops(); + } + else { + if (dns_resolve_tx.packetlen < 4) oops(); + dns_resolve_tx.packet[2] &= ~1; + dns_resolve_tx.packet[3] &= ~128; + if (!printpacket_cat(&out,dns_resolve_tx.packet,dns_resolve_tx.packetlen)) oops(); + } + + buffer_putflush(buffer_1,out.s,out.len); + _exit(0); +} diff --git a/dnsroots.global b/dnsroots.global new file mode 100644 index 0000000..3b567e1 --- /dev/null +++ b/dnsroots.global @@ -0,0 +1,13 @@ +198.41.0.4 +128.9.0.107 +192.33.4.12 +128.8.10.90 +192.203.230.10 +192.5.5.241 +192.112.36.4 +128.63.2.53 +192.36.148.17 +198.41.0.10 +193.0.14.129 +198.32.64.12 +202.12.27.33 diff --git a/dnstrace.c b/dnstrace.c new file mode 100644 index 0000000..3f2159b --- /dev/null +++ b/dnstrace.c @@ -0,0 +1,474 @@ +#include "uint16.h" +#include "uint32.h" +#include "fmt.h" +#include "str.h" +#include "byte.h" +#include "ip4.h" +#include "gen_alloc.h" +#include "gen_allocdefs.h" +#include "exit.h" +#include "buffer.h" +#include "stralloc.h" +#include "error.h" +#include "strerr.h" +#include "iopause.h" +#include "printrecord.h" +#include "alloc.h" +#include "parsetype.h" +#include "dd.h" +#include "dns.h" + +#define FATAL "dnstrace: fatal: " + +void nomem(void) +{ + strerr_die2x(111,FATAL,"out of memory"); +} +void usage(void) +{ + strerr_die1x(100,"dnstrace: usage: dnstrace type name rootip ..."); +} + +static stralloc querystr; +char ipstr[IP4_FMT]; +static stralloc tmp; + +void printdomain(const char *d) +{ + if (!stralloc_copys(&tmp,"")) nomem(); + if (!dns_domain_todot_cat(&tmp,d)) nomem(); + buffer_put(buffer_1,tmp.s,tmp.len); +} + +static struct dns_transmit tx; + +int resolve(char *q,char qtype[2],char ip[4]) +{ + struct taia start; + struct taia stamp; + struct taia deadline; + char servers[64]; + iopause_fd x[1]; + int r; + + taia_now(&start); + + byte_zero(servers,64); + byte_copy(servers,4,ip); + + if (dns_transmit_start(&tx,servers,0,q,qtype,"\0\0\0\0") == -1) return -1; + + for (;;) { + taia_now(&stamp); + taia_uint(&deadline,120); + taia_add(&deadline,&deadline,&stamp); + dns_transmit_io(&tx,x,&deadline); + iopause(x,1,&deadline,&stamp); + r = dns_transmit_get(&tx,x,&stamp); + if (r == -1) return -1; + if (r == 1) break; + } + + taia_now(&stamp); + taia_sub(&stamp,&stamp,&start); + taia_uint(&deadline,1); + if (taia_less(&deadline,&stamp)) { + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"ALERT:took more than 1 second\n"); + } + + return 0; +} + +struct address { + char *owner; + char ip[4]; +} ; + +GEN_ALLOC_typedef(address_alloc,struct address,s,len,a) +GEN_ALLOC_readyplus(address_alloc,struct address,s,len,a,i,n,x,30,address_alloc_readyplus) +GEN_ALLOC_append(address_alloc,struct address,s,len,a,i,n,x,30,address_alloc_readyplus,address_alloc_append) + +static address_alloc address; + +struct ns { + char *owner; + char *ns; +} ; + +GEN_ALLOC_typedef(ns_alloc,struct ns,s,len,a) +GEN_ALLOC_readyplus(ns_alloc,struct ns,s,len,a,i,n,x,30,ns_alloc_readyplus) +GEN_ALLOC_append(ns_alloc,struct ns,s,len,a,i,n,x,30,ns_alloc_readyplus,ns_alloc_append) + +static ns_alloc ns; + +struct query { + char *owner; + char type[2]; +} ; + +GEN_ALLOC_typedef(query_alloc,struct query,s,len,a) +GEN_ALLOC_readyplus(query_alloc,struct query,s,len,a,i,n,x,30,query_alloc_readyplus) +GEN_ALLOC_append(query_alloc,struct query,s,len,a,i,n,x,30,query_alloc_readyplus,query_alloc_append) + +static query_alloc query; + +struct qt { + char *owner; + char type[2]; + char *control; + char ip[4]; +} ; + +GEN_ALLOC_typedef(qt_alloc,struct qt,s,len,a) +GEN_ALLOC_readyplus(qt_alloc,struct qt,s,len,a,i,n,x,30,qt_alloc_readyplus) +GEN_ALLOC_append(qt_alloc,struct qt,s,len,a,i,n,x,30,qt_alloc_readyplus,qt_alloc_append) + +static qt_alloc qt; + +void qt_add(const char *q,const char type[2],const char *control,const char ip[4]) +{ + struct qt x; + int i; + + if (!*q) return; /* don't ask the roots about our artificial . host */ + + for (i = 0;i < qt.len;++i) + if (dns_domain_equal(qt.s[i].owner,q)) + if (dns_domain_equal(qt.s[i].control,control)) + if (byte_equal(qt.s[i].type,2,type)) + if (byte_equal(qt.s[i].ip,4,ip)) + return; + + byte_zero(&x,sizeof x); + if (!dns_domain_copy(&x.owner,q)) nomem(); + if (!dns_domain_copy(&x.control,control)) nomem(); + byte_copy(x.type,2,type); + byte_copy(x.ip,4,ip); + if (!qt_alloc_append(&qt,&x)) nomem(); +} + +void query_add(const char *owner,const char type[2]) +{ + struct query x; + int i; + int j; + + for (i = 0;i < query.len;++i) + if (dns_domain_equal(query.s[i].owner,owner)) + if (byte_equal(query.s[i].type,2,type)) + return; + + byte_zero(&x,sizeof x); + if (!dns_domain_copy(&x.owner,owner)) nomem(); + byte_copy(x.type,2,type); + if (!query_alloc_append(&query,&x)) nomem(); + + for (i = 0;i < ns.len;++i) + if (dns_domain_suffix(owner,ns.s[i].owner)) + for (j = 0;j < address.len;++j) + if (dns_domain_equal(ns.s[i].ns,address.s[j].owner)) + qt_add(owner,type,ns.s[i].owner,address.s[j].ip); +} + +void ns_add(const char *owner,const char *server) +{ + struct ns x; + int i; + int j; + + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"NS:"); + printdomain(owner); + buffer_puts(buffer_1,":"); + printdomain(server); + buffer_puts(buffer_1,"\n"); + + for (i = 0;i < ns.len;++i) + if (dns_domain_equal(ns.s[i].owner,owner)) + if (dns_domain_equal(ns.s[i].ns,server)) + return; + + query_add(server,DNS_T_A); + + byte_zero(&x,sizeof x); + if (!dns_domain_copy(&x.owner,owner)) nomem(); + if (!dns_domain_copy(&x.ns,server)) nomem(); + if (!ns_alloc_append(&ns,&x)) nomem(); + + for (i = 0;i < query.len;++i) + if (dns_domain_suffix(query.s[i].owner,owner)) + for (j = 0;j < address.len;++j) + if (dns_domain_equal(server,address.s[j].owner)) + qt_add(query.s[i].owner,query.s[i].type,owner,address.s[j].ip); +} + +void address_add(const char *owner,const char ip[4]) +{ + struct address x; + int i; + int j; + + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"A:"); + printdomain(owner); + buffer_puts(buffer_1,":"); + buffer_put(buffer_1,ipstr,ip4_fmt(ipstr,ip)); + buffer_puts(buffer_1,"\n"); + + for (i = 0;i < address.len;++i) + if (dns_domain_equal(address.s[i].owner,owner)) + if (byte_equal(address.s[i].ip,4,ip)) + return; + + byte_zero(&x,sizeof x); + if (!dns_domain_copy(&x.owner,owner)) nomem(); + byte_copy(x.ip,4,ip); + if (!address_alloc_append(&address,&x)) nomem(); + + for (i = 0;i < ns.len;++i) + if (dns_domain_equal(ns.s[i].ns,owner)) + for (j = 0;j < query.len;++j) + if (dns_domain_suffix(query.s[j].owner,ns.s[i].owner)) + qt_add(query.s[j].owner,query.s[j].type,ns.s[i].owner,ip); +} + +char seed[128]; + +static char *t1; +static char *t2; +static char *referral; +static char *cname; + +static int typematch(const char rtype[2],const char qtype[2]) +{ + return byte_equal(qtype,2,rtype) || byte_equal(qtype,2,DNS_T_ANY); +} + +void parsepacket(const char *buf,unsigned int len,const char *d,const char dtype[2],const char *control) +{ + char misc[20]; + char header[12]; + unsigned int pos; + uint16 numanswers; + unsigned int posanswers; + uint16 numauthority; + unsigned int posauthority; + uint16 numglue; + unsigned int posglue; + uint16 datalen; + unsigned int rcode; + int flagout; + int flagcname; + int flagreferral; + int flagsoa; + int j; + const char *x; + + pos = dns_packet_copy(buf,len,0,header,12); if (!pos) goto DIE; + pos = dns_packet_skipname(buf,len,pos); if (!pos) goto DIE; + pos += 4; + + uint16_unpack_big(header + 6,&numanswers); + uint16_unpack_big(header + 8,&numauthority); + uint16_unpack_big(header + 10,&numglue); + + rcode = header[3] & 15; + if (rcode && (rcode != 3)) { errno = error_proto; goto DIE; } /* impossible */ + + flagout = 0; + flagcname = 0; + flagreferral = 0; + flagsoa = 0; + posanswers = pos; + for (j = 0;j < numanswers;++j) { + pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + if (dns_domain_equal(t1,d)) + if (byte_equal(header + 2,2,DNS_C_IN)) + if (typematch(header,dtype)) + flagout = 1; + else if (typematch(header,DNS_T_CNAME)) { + if (!dns_packet_getname(buf,len,pos,&cname)) goto DIE; + flagcname = 1; + } + uint16_unpack_big(header + 8,&datalen); + pos += datalen; + } + posauthority = pos; + for (j = 0;j < numauthority;++j) { + pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + if (typematch(header,DNS_T_SOA)) + flagsoa = 1; + else if (typematch(header,DNS_T_NS)) { + flagreferral = 1; + if (!dns_domain_copy(&referral,t1)) goto DIE; + } + uint16_unpack_big(header + 8,&datalen); + pos += datalen; + } + posglue = pos; + + if (!flagcname && !rcode && !flagout && flagreferral && !flagsoa) + if (dns_domain_equal(referral,control) || !dns_domain_suffix(referral,control)) { + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"ALERT:lame server; refers to "); + printdomain(referral); + buffer_puts(buffer_1,"\n"); + return; + } + + pos = posanswers; + for (j = 0;j < numanswers + numauthority + numglue;++j) { + pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + uint16_unpack_big(header + 8,&datalen); + if (dns_domain_suffix(t1,control)) + if (byte_equal(header + 2,2,DNS_C_IN)) { + if (typematch(header,DNS_T_NS)) { + if (!dns_packet_getname(buf,len,pos,&t2)) goto DIE; + ns_add(t1,t2); + } + else if (typematch(header,DNS_T_A) && datalen == 4) { + if (!dns_packet_copy(buf,len,pos,misc,4)) goto DIE; + address_add(t1,misc); + } + } + pos += datalen; + } + + + if (flagcname) { + query_add(cname,dtype); + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"CNAME:"); + printdomain(cname); + buffer_puts(buffer_1,"\n"); + return; + } + if (rcode == 3) { + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"NXDOMAIN\n"); + return; + } + if (flagout || flagsoa || !flagreferral) { + if (!flagout) { + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"NODATA\n"); + return; + } + pos = posanswers; + for (j = 0;j < numanswers + numauthority + numglue;++j) { + pos = printrecord(&tmp,buf,len,pos,d,dtype); + if (!pos) goto DIE; + if (tmp.len) { + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"answer:"); + buffer_put(buffer_1,tmp.s,tmp.len); /* includes \n */ + } + } + return; + } + + if (!dns_domain_suffix(d,referral)) goto DIE; + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"see:"); + printdomain(referral); + buffer_puts(buffer_1,"\n"); + return; + + DIE: + x = error_str(errno); + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"ALERT:unable to parse response packet; "); + buffer_puts(buffer_1,x); + buffer_puts(buffer_1,"\n"); +} + +int main(int argc,char **argv) +{ + static stralloc out; + static stralloc fqdn; + static stralloc udn; + static char *q; + char *control; + char type[2]; + char ip[64]; + int i; + uint16 u16; + + dns_random_init(seed); + + if (!stralloc_copys(&querystr,"0:.:.:start:")) nomem(); + + if (!address_alloc_readyplus(&address,1)) nomem(); + if (!query_alloc_readyplus(&query,1)) nomem(); + if (!ns_alloc_readyplus(&ns,1)) nomem(); + if (!qt_alloc_readyplus(&qt,1)) nomem(); + + if (!*argv) usage(); + if (!*++argv) usage(); + if (!parsetype(*argv,type)) usage(); + + if (!*++argv) usage(); + if (!dns_domain_fromdot(&q,*argv,str_len(*argv))) nomem(); + + query_add(q,type); + ns_add("",""); + + while (*++argv) { + if (!stralloc_copys(&udn,*argv)) nomem(); + if (dns_ip4_qualify(&out,&fqdn,&udn) == -1) nomem(); /* XXX */ + for (i = 0;i + 4 <= out.len;i += 4) + address_add("",out.s + i); + } + + for (i = 0;i < qt.len;++i) { + if (!dns_domain_copy(&q,qt.s[i].owner)) nomem(); + control = qt.s[i].control; + if (!dns_domain_suffix(q,control)) continue; + byte_copy(type,2,qt.s[i].type); + byte_copy(ip,4,qt.s[i].ip); + + if (!stralloc_copys(&querystr,"")) nomem(); + uint16_unpack_big(type,&u16); + if (!stralloc_catulong0(&querystr,u16,0)) nomem(); + if (!stralloc_cats(&querystr,":")) nomem(); + if (!dns_domain_todot_cat(&querystr,q)) nomem(); + if (!stralloc_cats(&querystr,":")) nomem(); + if (!dns_domain_todot_cat(&querystr,control)) nomem(); + if (!stralloc_cats(&querystr,":")) nomem(); + if (!stralloc_catb(&querystr,ipstr,ip4_fmt(ipstr,ip))) nomem(); + if (!stralloc_cats(&querystr,":")) nomem(); + + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"tx\n"); + buffer_flush(buffer_1); + + if (resolve(q,type,ip) == -1) { + const char *x = error_str(errno); + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"ALERT:query failed; "); + buffer_puts(buffer_1,x); + buffer_puts(buffer_1,"\n"); + } + else + parsepacket(tx.packet,tx.packetlen,q,type,control); + + if (dns_domain_equal(q,"\011localhost\0")) { + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"ALERT:some caches do not handle localhost internally\n"); + address_add(q,"\177\0\0\1"); + } + if (dd(q,"",ip) == 4) { + buffer_put(buffer_1,querystr.s,querystr.len); + buffer_puts(buffer_1,"ALERT:some caches do not handle IP addresses internally\n"); + address_add(q,ip); + } + + buffer_flush(buffer_1); + } + + _exit(0); +} diff --git a/dnstracesort.sh b/dnstracesort.sh new file mode 100644 index 0000000..e57359c --- /dev/null +++ b/dnstracesort.sh @@ -0,0 +1,51 @@ +awk -F: ' + BEGIN { OFS=":" } + { + if ($5 == "tx") next + if ($5 == "A") { + print "glue",$6,$3,$4,"answer",$6" A "$7 + next + } + if ($5 == "NS") { + print "glue",$6,$3,$4,"answer",$6" NS "$7 + next + } + print + } +' | sort -t: +0 -2 +4 +3 -4 +2 -3 | uniq | awk -F: ' + { + type = $1 + q = $2 + c = $3 + ip = sprintf("%-16s",$4) + + if (q != lastq) { print ""; lastq = q } + + if ($5 == "ALERT") { + result = "A\bAL\bLE\bER\bRT\bT:\b: " $6 + } + else if ($5 == "answer") { + if (index($6,q" ") == 1) + $6 = substr($6,length(q) + 2) + result = $6 + } + else if ($5 == "see") { + result = "see " $6 + } + else if ($5 == "CNAME") { + result = "CNAME "$6 + } + else + result = $5 + + if (c != ".") { + q = substr(q,1,length(q) - length(c)) + for (i = 1;i <= length(c);++i) { + ci = substr(c,i,1) + q = q "_\b" ci + } + } + + print type,q,ip,result + } +' diff --git a/dnstxt.c b/dnstxt.c new file mode 100644 index 0000000..0880b30 --- /dev/null +++ b/dnstxt.c @@ -0,0 +1,33 @@ +#include "buffer.h" +#include "exit.h" +#include "strerr.h" +#include "dns.h" + +#define FATAL "dnstxt: fatal: " + +static char seed[128]; + +static stralloc fqdn; +static stralloc out; + +int main(int argc,char **argv) +{ + dns_random_init(seed); + + if (*argv) ++argv; + + while (*argv) { + if (!stralloc_copys(&fqdn,*argv)) + strerr_die2x(111,FATAL,"out of memory"); + if (dns_txt(&out,&fqdn) == -1) + strerr_die4sys(111,FATAL,"unable to find TXT records for ",*argv,": "); + + buffer_put(buffer_1,out.s,out.len); + buffer_puts(buffer_1,"\n"); + + ++argv; + } + + buffer_flush(buffer_1); + _exit(0); +} diff --git a/droproot.c b/droproot.c new file mode 100644 index 0000000..33e8f18 --- /dev/null +++ b/droproot.c @@ -0,0 +1,33 @@ +#include +#include "env.h" +#include "scan.h" +#include "prot.h" +#include "strerr.h" + +void droproot(const char *fatal) +{ + char *x; + unsigned long id; + + x = env_get("ROOT"); + if (!x) + strerr_die2x(111,fatal,"$ROOT not set"); + if (chdir(x) == -1) + strerr_die4sys(111,fatal,"unable to chdir to ",x,": "); + if (chroot(".") == -1) + strerr_die4sys(111,fatal,"unable to chroot to ",x,": "); + + x = env_get("GID"); + if (!x) + strerr_die2x(111,fatal,"$GID not set"); + scan_ulong(x,&id); + if (prot_gid((int) id) == -1) + strerr_die2sys(111,fatal,"unable to setgid: "); + + x = env_get("UID"); + if (!x) + strerr_die2x(111,fatal,"$UID not set"); + scan_ulong(x,&id); + if (prot_uid((int) id) == -1) + strerr_die2sys(111,fatal,"unable to setuid: "); +} diff --git a/droproot.h b/droproot.h new file mode 100644 index 0000000..b8a53a7 --- /dev/null +++ b/droproot.h @@ -0,0 +1,6 @@ +#ifndef DROPROOT_H +#define DROPROOT_H + +extern void droproot(const char *); + +#endif diff --git a/env.c b/env.c new file mode 100644 index 0000000..86849a2 --- /dev/null +++ b/env.c @@ -0,0 +1,15 @@ +#include "str.h" +#include "env.h" + +extern /*@null@*/char *env_get(const char *s) +{ + int i; + unsigned int len; + + if (!s) return 0; + len = str_len(s); + for (i = 0;environ[i];++i) + if (str_start(environ[i],s) && (environ[i][len] == '=')) + return environ[i] + len + 1; + return 0; +} diff --git a/env.h b/env.h new file mode 100644 index 0000000..d7ecf48 --- /dev/null +++ b/env.h @@ -0,0 +1,8 @@ +#ifndef ENV_H +#define ENV_H + +extern char **environ; + +extern /*@null@*/char *env_get(const char *); + +#endif diff --git a/error.c b/error.c new file mode 100644 index 0000000..14adef0 --- /dev/null +++ b/error.c @@ -0,0 +1,123 @@ +#include +#include "error.h" + +/* warning: as coverage improves here, should update error_{str,temp} */ + +int error_intr = +#ifdef EINTR +EINTR; +#else +-1; +#endif + +int error_nomem = +#ifdef ENOMEM +ENOMEM; +#else +-2; +#endif + +int error_noent = +#ifdef ENOENT +ENOENT; +#else +-3; +#endif + +int error_txtbsy = +#ifdef ETXTBSY +ETXTBSY; +#else +-4; +#endif + +int error_io = +#ifdef EIO +EIO; +#else +-5; +#endif + +int error_exist = +#ifdef EEXIST +EEXIST; +#else +-6; +#endif + +int error_timeout = +#ifdef ETIMEDOUT +ETIMEDOUT; +#else +-7; +#endif + +int error_inprogress = +#ifdef EINPROGRESS +EINPROGRESS; +#else +-8; +#endif + +int error_wouldblock = +#ifdef EWOULDBLOCK +EWOULDBLOCK; +#else +-9; +#endif + +int error_again = +#ifdef EAGAIN +EAGAIN; +#else +-10; +#endif + +int error_pipe = +#ifdef EPIPE +EPIPE; +#else +-11; +#endif + +int error_perm = +#ifdef EPERM +EPERM; +#else +-12; +#endif + +int error_acces = +#ifdef EACCES +EACCES; +#else +-13; +#endif + +int error_nodevice = +#ifdef ENXIO +ENXIO; +#else +-14; +#endif + +int error_proto = +#ifdef EPROTO +EPROTO; +#else +-15; +#endif + +int error_isdir = +#ifdef EISDIR +EISDIR; +#else +-16; +#endif + +int error_connrefused = +#ifdef ECONNREFUSED +ECONNREFUSED; +#else +-17; +#endif diff --git a/error.h b/error.h new file mode 100644 index 0000000..35c976e --- /dev/null +++ b/error.h @@ -0,0 +1,27 @@ +#ifndef ERROR_H +#define ERROR_H + +extern int errno; + +extern int error_intr; +extern int error_nomem; +extern int error_noent; +extern int error_txtbsy; +extern int error_io; +extern int error_exist; +extern int error_timeout; +extern int error_inprogress; +extern int error_wouldblock; +extern int error_again; +extern int error_pipe; +extern int error_perm; +extern int error_acces; +extern int error_nodevice; +extern int error_proto; +extern int error_isdir; +extern int error_connrefused; + +extern const char *error_str(int); +extern int error_temp(int); + +#endif diff --git a/error_str.c b/error_str.c new file mode 100644 index 0000000..74e1330 --- /dev/null +++ b/error_str.c @@ -0,0 +1,267 @@ +#include +#include "error.h" + +#define X(e,s) if (i == e) return s; + +const char *error_str(int i) +{ + X(0,"no error") + X(error_intr,"interrupted system call") + X(error_nomem,"out of memory") + X(error_noent,"file does not exist") + X(error_txtbsy,"text busy") + X(error_io,"input/output error") + X(error_exist,"file already exists") + X(error_timeout,"timed out") + X(error_inprogress,"operation in progress") + X(error_again,"temporary failure") + X(error_wouldblock,"input/output would block") + X(error_pipe,"broken pipe") + X(error_perm,"permission denied") + X(error_acces,"access denied") + X(error_nodevice,"device not configured") + X(error_proto,"protocol error") + X(error_isdir,"is a directory") + X(error_connrefused,"connection refused") +#ifdef ESRCH + X(ESRCH,"no such process") +#endif +#ifdef E2BIG + X(E2BIG,"argument list too long") +#endif +#ifdef ENOEXEC + X(ENOEXEC,"exec format error") +#endif +#ifdef EBADF + X(EBADF,"file descriptor not open") +#endif +#ifdef ECHILD + X(ECHILD,"no child processes") +#endif +#ifdef EDEADLK + X(EDEADLK,"operation would cause deadlock") +#endif +#ifdef EFAULT + X(EFAULT,"bad address") +#endif +#ifdef ENOTBLK + X(ENOTBLK,"not a block device") +#endif +#ifdef EBUSY + X(EBUSY,"device busy") +#endif +#ifdef EXDEV + X(EXDEV,"cross-device link") +#endif +#ifdef ENODEV + X(ENODEV,"device does not support operation") +#endif +#ifdef ENOTDIR + X(ENOTDIR,"not a directory") +#endif +#ifdef EINVAL + X(EINVAL,"invalid argument") +#endif +#ifdef ENFILE + X(ENFILE,"system cannot open more files") +#endif +#ifdef EMFILE + X(EMFILE,"process cannot open more files") +#endif +#ifdef ENOTTY + X(ENOTTY,"not a tty") +#endif +#ifdef EFBIG + X(EFBIG,"file too big") +#endif +#ifdef ENOSPC + X(ENOSPC,"out of disk space") +#endif +#ifdef ESPIPE + X(ESPIPE,"unseekable descriptor") +#endif +#ifdef EROFS + X(EROFS,"read-only file system") +#endif +#ifdef EMLINK + X(EMLINK,"too many links") +#endif +#ifdef EDOM + X(EDOM,"input out of range") +#endif +#ifdef ERANGE + X(ERANGE,"output out of range") +#endif +#ifdef EALREADY + X(EALREADY,"operation already in progress") +#endif +#ifdef ENOTSOCK + X(ENOTSOCK,"not a socket") +#endif +#ifdef EDESTADDRREQ + X(EDESTADDRREQ,"destination address required") +#endif +#ifdef EMSGSIZE + X(EMSGSIZE,"message too long") +#endif +#ifdef EPROTOTYPE + X(EPROTOTYPE,"incorrect protocol type") +#endif +#ifdef ENOPROTOOPT + X(ENOPROTOOPT,"protocol not available") +#endif +#ifdef EPROTONOSUPPORT + X(EPROTONOSUPPORT,"protocol not supported") +#endif +#ifdef ESOCKTNOSUPPORT + X(ESOCKTNOSUPPORT,"socket type not supported") +#endif +#ifdef EOPNOTSUPP + X(EOPNOTSUPP,"operation not supported") +#endif +#ifdef EPFNOSUPPORT + X(EPFNOSUPPORT,"protocol family not supported") +#endif +#ifdef EAFNOSUPPORT + X(EAFNOSUPPORT,"address family not supported") +#endif +#ifdef EADDRINUSE + X(EADDRINUSE,"address already used") +#endif +#ifdef EADDRNOTAVAIL + X(EADDRNOTAVAIL,"address not available") +#endif +#ifdef ENETDOWN + X(ENETDOWN,"network down") +#endif +#ifdef ENETUNREACH + X(ENETUNREACH,"network unreachable") +#endif +#ifdef ENETRESET + X(ENETRESET,"network reset") +#endif +#ifdef ECONNABORTED + X(ECONNABORTED,"connection aborted") +#endif +#ifdef ECONNRESET + X(ECONNRESET,"connection reset") +#endif +#ifdef ENOBUFS + X(ENOBUFS,"out of buffer space") +#endif +#ifdef EISCONN + X(EISCONN,"already connected") +#endif +#ifdef ENOTCONN + X(ENOTCONN,"not connected") +#endif +#ifdef ESHUTDOWN + X(ESHUTDOWN,"socket shut down") +#endif +#ifdef ETOOMANYREFS + X(ETOOMANYREFS,"too many references") +#endif +#ifdef ELOOP + X(ELOOP,"symbolic link loop") +#endif +#ifdef ENAMETOOLONG + X(ENAMETOOLONG,"file name too long") +#endif +#ifdef EHOSTDOWN + X(EHOSTDOWN,"host down") +#endif +#ifdef EHOSTUNREACH + X(EHOSTUNREACH,"host unreachable") +#endif +#ifdef ENOTEMPTY + X(ENOTEMPTY,"directory not empty") +#endif +#ifdef EPROCLIM + X(EPROCLIM,"too many processes") +#endif +#ifdef EUSERS + X(EUSERS,"too many users") +#endif +#ifdef EDQUOT + X(EDQUOT,"disk quota exceeded") +#endif +#ifdef ESTALE + X(ESTALE,"stale NFS file handle") +#endif +#ifdef EREMOTE + X(EREMOTE,"too many levels of remote in path") +#endif +#ifdef EBADRPC + X(EBADRPC,"RPC structure is bad") +#endif +#ifdef ERPCMISMATCH + X(ERPCMISMATCH,"RPC version mismatch") +#endif +#ifdef EPROGUNAVAIL + X(EPROGUNAVAIL,"RPC program unavailable") +#endif +#ifdef EPROGMISMATCH + X(EPROGMISMATCH,"program version mismatch") +#endif +#ifdef EPROCUNAVAIL + X(EPROCUNAVAIL,"bad procedure for program") +#endif +#ifdef ENOLCK + X(ENOLCK,"no locks available") +#endif +#ifdef ENOSYS + X(ENOSYS,"system call not available") +#endif +#ifdef EFTYPE + X(EFTYPE,"bad file type") +#endif +#ifdef EAUTH + X(EAUTH,"authentication error") +#endif +#ifdef ENEEDAUTH + X(ENEEDAUTH,"not authenticated") +#endif +#ifdef ENOSTR + X(ENOSTR,"not a stream device") +#endif +#ifdef ETIME + X(ETIME,"timer expired") +#endif +#ifdef ENOSR + X(ENOSR,"out of stream resources") +#endif +#ifdef ENOMSG + X(ENOMSG,"no message of desired type") +#endif +#ifdef EBADMSG + X(EBADMSG,"bad message type") +#endif +#ifdef EIDRM + X(EIDRM,"identifier removed") +#endif +#ifdef ENONET + X(ENONET,"machine not on network") +#endif +#ifdef ERREMOTE + X(ERREMOTE,"object not local") +#endif +#ifdef ENOLINK + X(ENOLINK,"link severed") +#endif +#ifdef EADV + X(EADV,"advertise error") +#endif +#ifdef ESRMNT + X(ESRMNT,"srmount error") +#endif +#ifdef ECOMM + X(ECOMM,"communication error") +#endif +#ifdef EMULTIHOP + X(EMULTIHOP,"multihop attempted") +#endif +#ifdef EREMCHG + X(EREMCHG,"remote address changed") +#endif + return "unknown error"; +} diff --git a/exit.h b/exit.h new file mode 100644 index 0000000..39011c8 --- /dev/null +++ b/exit.h @@ -0,0 +1,6 @@ +#ifndef EXIT_H +#define EXIT_H + +extern void _exit(); + +#endif diff --git a/find-systype.sh b/find-systype.sh new file mode 100644 index 0000000..9f6e565 --- /dev/null +++ b/find-systype.sh @@ -0,0 +1,143 @@ +# oper-:arch-:syst-:chip-:kern- +# oper = operating system type; e.g., sunos-4.1.4 +# arch = machine language; e.g., sparc +# syst = which binaries can run; e.g., sun4 +# chip = chip model; e.g., micro-2-80 +# kern = kernel version; e.g., sun4m +# dependence: arch --- chip +# \ \ +# oper --- syst --- kern +# so, for example, syst is interpreted in light of oper, but chip is not. +# anyway, no slashes, no extra colons, no uppercase letters. +# the point of the extra -'s is to ease parsing: can add hierarchies later. +# e.g., *:i386-*:*:pentium-*:* would handle pentium-100 as well as pentium, +# and i386-486 (486s do have more instructions, you know) as well as i386. +# the idea here is to include ALL useful available information. + +exec 2>/dev/null + +sys="`uname -s | tr '/:[A-Z]' '..[a-z]'`" +if [ x"$sys" != x ] +then + unamer="`uname -r | tr /: ..`" + unamem="`uname -m | tr /: ..`" + unamev="`uname -v | tr /: ..`" + + case "$sys" in + bsd.os|freebsd|netbsd|openbsd) + # in bsd 4.4, uname -v does not have useful info. + # in bsd 4.4, uname -m is arch, not chip. + oper="$sys-$unamer" + arch="$unamem" + syst="" + chip="`sysctl -n hw.model`" # hopefully + kern="" + ;; + linux) + # as in bsd 4.4, uname -v does not have useful info. + oper="$sys-$unamer" + syst="" + chip="$unamem" + kern="" + case "$chip" in + i386|i486|i586|i686) + arch="i386" + ;; + alpha) + arch="alpha" + ;; + esac + ;; + aix) + # naturally IBM has to get uname -r and uname -v backwards. dorks. + oper="$sys-$unamev-$unamer" + arch="`arch | tr /: ..`" + syst="" + chip="$unamem" + kern="" + ;; + sunos) + oper="$sys-$unamer-$unamev" + arch="`(uname -p || mach) | tr /: ..`" + syst="`arch | tr /: ..`" + chip="$unamem" # this is wrong; is there any way to get the real info? + kern="`arch -k | tr /: ..`" + ;; + unix_sv) + oper="$sys-$unamer-$unamev" + arch="`uname -m`" + syst="" + chip="$unamem" + kern="" + ;; + *) + oper="$sys-$unamer-$unamev" + arch="`arch | tr /: ..`" + syst="" + chip="$unamem" + kern="" + ;; + esac +else + gcc -c trycpp.c + gcc -o trycpp trycpp.o + case `./trycpp` in + nextstep) + oper="nextstep-`hostinfo | sed -n 's/^[ ]*NeXT Mach \([^:]*\):.*$/\1/p'`" + arch="`hostinfo | sed -n 's/^Processor type: \(.*\) (.*)$/\1/p' | tr /: ..`" + syst="" + chip="`hostinfo | sed -n 's/^Processor type: .* (\(.*\))$/\1/p' | tr ' /:' '...'`" + kern="" + ;; + *) + oper="unknown" + arch="" + syst="" + chip="" + kern="" + ;; + esac + rm -f trycpp.o trycpp +fi + +case "$chip" in +80486) + # let's try to be consistent here. (BSD/OS) + chip=i486 + ;; +i486DX) + # respect the hyphen hierarchy. (FreeBSD) + chip=i486-dx + ;; +i486.DX2) + # respect the hyphen hierarchy. (FreeBSD) + chip=i486-dx2 + ;; +Intel.586) + # no, you nitwits, there is no such chip. (NeXTStep) + chip=pentium + ;; +i586) + # no, you nitwits, there is no such chip. (Linux) + chip=pentium + ;; +i686) + # STOP SAYING THAT! (Linux) + chip=ppro +esac + +if gcc -c x86cpuid.c +then + if gcc -o x86cpuid x86cpuid.o + then + x86cpuid="`./x86cpuid | tr /: ..`" + case "$x86cpuid" in + ?*) + chip="$x86cpuid" + ;; + esac + fi +fi +rm -f x86cpuid x86cpuid.o + +echo "$oper-:$arch-:$syst-:$chip-:$kern-" | tr ' [A-Z]' '.[a-z]' diff --git a/fmt.h b/fmt.h new file mode 100644 index 0000000..b0bfce5 --- /dev/null +++ b/fmt.h @@ -0,0 +1,25 @@ +#ifndef FMT_H +#define FMT_H + +#define FMT_ULONG 40 /* enough space to hold 2^128 - 1 in decimal, plus \0 */ +#define FMT_LEN ((char *) 0) /* convenient abbreviation */ + +extern unsigned int fmt_uint(char *,unsigned int); +extern unsigned int fmt_uint0(char *,unsigned int,unsigned int); +extern unsigned int fmt_xint(char *,unsigned int); +extern unsigned int fmt_nbbint(char *,unsigned int,unsigned int,unsigned int,unsigned int); +extern unsigned int fmt_ushort(char *,unsigned short); +extern unsigned int fmt_xshort(char *,unsigned short); +extern unsigned int fmt_nbbshort(char *,unsigned int,unsigned int,unsigned int,unsigned short); +extern unsigned int fmt_ulong(char *,unsigned long); +extern unsigned int fmt_xlong(char *,unsigned long); +extern unsigned int fmt_nbblong(char *,unsigned int,unsigned int,unsigned int,unsigned long); + +extern unsigned int fmt_plusminus(char *,int); +extern unsigned int fmt_minus(char *,int); +extern unsigned int fmt_0x(char *,int); + +extern unsigned int fmt_str(char *,const char *); +extern unsigned int fmt_strn(char *,const char *,unsigned int); + +#endif diff --git a/fmt_ulong.c b/fmt_ulong.c new file mode 100644 index 0000000..db48bfd --- /dev/null +++ b/fmt_ulong.c @@ -0,0 +1,13 @@ +#include "fmt.h" + +unsigned int fmt_ulong(register char *s,register unsigned long u) +{ + register unsigned int len; register unsigned long q; + len = 1; q = u; + while (q > 9) { ++len; q /= 10; } + if (s) { + s += len; + do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */ + } + return len; +} diff --git a/gen_alloc.h b/gen_alloc.h new file mode 100644 index 0000000..b94a956 --- /dev/null +++ b/gen_alloc.h @@ -0,0 +1,7 @@ +#ifndef GEN_ALLOC_H +#define GEN_ALLOC_H + +#define GEN_ALLOC_typedef(ta,type,field,len,a) \ + typedef struct ta { type *field; unsigned int len; unsigned int a; } ta; + +#endif diff --git a/gen_allocdefs.h b/gen_allocdefs.h new file mode 100644 index 0000000..5e136c0 --- /dev/null +++ b/gen_allocdefs.h @@ -0,0 +1,34 @@ +#ifndef GEN_ALLOC_DEFS_H +#define GEN_ALLOC_DEFS_H + +#define GEN_ALLOC_ready(ta,type,field,len,a,i,n,x,base,ta_ready) \ +int ta_ready(register ta *x,register unsigned int n) \ +{ register unsigned int i; \ + if (x->field) { \ + i = x->a; \ + if (n > i) { \ + x->a = base + n + (n >> 3); \ + if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \ + x->a = i; return 0; } \ + return 1; } \ + x->len = 0; \ + return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); } + +#define GEN_ALLOC_readyplus(ta,type,field,len,a,i,n,x,base,ta_rplus) \ +int ta_rplus(register ta *x,register unsigned int n) \ +{ register unsigned int i; \ + if (x->field) { \ + i = x->a; n += x->len; \ + if (n > i) { \ + x->a = base + n + (n >> 3); \ + if (alloc_re(&x->field,i * sizeof(type),x->a * sizeof(type))) return 1; \ + x->a = i; return 0; } \ + return 1; } \ + x->len = 0; \ + return !!(x->field = (type *) alloc((x->a = n) * sizeof(type))); } + +#define GEN_ALLOC_append(ta,type,field,len,a,i,n,x,base,ta_rplus,ta_append) \ +int ta_append(register ta *x,register const type *i) \ +{ if (!ta_rplus(x,1)) return 0; x->field[x->len++] = *i; return 1; } + +#endif diff --git a/generic-conf.c b/generic-conf.c new file mode 100644 index 0000000..db4aa1d --- /dev/null +++ b/generic-conf.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include "strerr.h" +#include "buffer.h" +#include "open.h" +#include "generic-conf.h" + +static const char *fatal; +static const char *dir; +static const char *fn; + +static int fd; +static char buf[1024]; +static buffer ss; + +void init(const char *d,const char *f) +{ + dir = d; + fatal = f; + umask(022); + if (mkdir(dir,0700) == -1) + strerr_die4sys(111,fatal,"unable to create ",dir,": "); + if (chmod(dir,03755) == -1) + strerr_die4sys(111,fatal,"unable to set mode of ",dir,": "); + if (chdir(dir) == -1) + strerr_die4sys(111,fatal,"unable to switch to ",dir,": "); +} + +void fail(void) +{ + strerr_die6sys(111,fatal,"unable to create ",dir,"/",fn,": "); +} + +void makedir(const char *s) +{ + fn = s; + if (mkdir(fn,0700) == -1) fail(); +} + +void start(const char *s) +{ + fn = s; + fd = open_trunc(fn); + if (fd == -1) fail(); + buffer_init(&ss,buffer_unixwrite,fd,buf,sizeof buf); +} + +void outs(const char *s) +{ + if (buffer_puts(&ss,s) == -1) fail(); +} + +void out(const char *s,unsigned int len) +{ + if (buffer_put(&ss,s,len) == -1) fail(); +} + +void copyfrom(buffer *b) +{ + if (buffer_copy(&ss,b) < 0) fail(); +} + +void finish(void) +{ + if (buffer_flush(&ss) == -1) fail(); + if (fsync(fd) == -1) fail(); + close(fd); +} + +void perm(int mode) +{ + if (chmod(fn,mode) == -1) fail(); +} + +void owner(int uid,int gid) +{ + if (chown(fn,uid,gid) == -1) fail(); +} + +void makelog(const char *user,int uid,int gid) +{ + makedir("log"); + perm(02755); + makedir("log/main"); + owner(uid,gid); + perm(02755); + start("log/status"); + finish(); + owner(uid,gid); + perm(0644); + + start("log/run"); + outs("#!/bin/sh\nexec"); + outs(" setuidgid "); outs(user); + outs(" multilog t ./main\n"); + finish(); + perm(0755); +} diff --git a/generic-conf.h b/generic-conf.h new file mode 100644 index 0000000..41dbeea --- /dev/null +++ b/generic-conf.h @@ -0,0 +1,20 @@ +#ifndef GENERIC_CONF_H +#define GENERIC_CONF_H + +#include "buffer.h" + +extern void init(const char *,const char *); + +extern void makedir(const char *); + +extern void start(const char *); +extern void outs(const char *); +extern void out(const char *,unsigned int); +extern void copyfrom(buffer *); +extern void finish(void); + +extern void perm(int); +extern void owner(int,int); +extern void makelog(const char *,int,int); + +#endif diff --git a/getln.c b/getln.c new file mode 100644 index 0000000..489621c --- /dev/null +++ b/getln.c @@ -0,0 +1,14 @@ +#include "byte.h" +#include "getln.h" + +int getln(buffer *ss,stralloc *sa,int *match,int sep) +{ + char *cont; + unsigned int clen; + + if (getln2(ss,sa,&cont,&clen,sep) == -1) return -1; + if (!clen) { *match = 0; return 0; } + if (!stralloc_catb(sa,cont,clen)) return -1; + *match = 1; + return 0; +} diff --git a/getln.h b/getln.h new file mode 100644 index 0000000..3cae45f --- /dev/null +++ b/getln.h @@ -0,0 +1,10 @@ +#ifndef GETLN_H +#define GETLN_H + +#include "buffer.h" +#include "stralloc.h" + +extern int getln(buffer *,stralloc *,int *,int); +extern int getln2(buffer *,stralloc *,char **,unsigned int *,int); + +#endif diff --git a/getln2.c b/getln2.c new file mode 100644 index 0000000..bf622a4 --- /dev/null +++ b/getln2.c @@ -0,0 +1,24 @@ +#include "byte.h" +#include "getln.h" + +int getln2(buffer *ss,stralloc *sa,char **cont,unsigned int *clen,int sep) +{ + register char *x; + register unsigned int i; + int n; + + if (!stralloc_ready(sa,0)) return -1; + sa->len = 0; + + for (;;) { + n = buffer_feed(ss); + if (n < 0) return -1; + if (n == 0) { *clen = 0; return 0; } + x = buffer_PEEK(ss); + i = byte_chr(x,n,sep); + if (i < n) { buffer_SEEK(ss,*clen = i + 1); *cont = x; return 0; } + if (!stralloc_readyplus(sa,n)) return -1; + i = sa->len; + sa->len = i + buffer_get(ss,sa->s + i,n); + } +} diff --git a/hasdevtcp.h1 b/hasdevtcp.h1 new file mode 100644 index 0000000..65e880e --- /dev/null +++ b/hasdevtcp.h1 @@ -0,0 +1 @@ +/* sysdep: -devtcp */ diff --git a/hasdevtcp.h2 b/hasdevtcp.h2 new file mode 100644 index 0000000..b12ffe8 --- /dev/null +++ b/hasdevtcp.h2 @@ -0,0 +1,2 @@ +/* sysdep: +devtcp */ +#define HASDEVTCP 1 diff --git a/hasshsgr.h1 b/hasshsgr.h1 new file mode 100644 index 0000000..d11c988 --- /dev/null +++ b/hasshsgr.h1 @@ -0,0 +1 @@ +/* sysdep: -shortsetgroups */ diff --git a/hasshsgr.h2 b/hasshsgr.h2 new file mode 100644 index 0000000..db6a830 --- /dev/null +++ b/hasshsgr.h2 @@ -0,0 +1,2 @@ +/* sysdep: +shortsetgroups */ +#define HASSHORTSETGROUPS 1 diff --git a/hier.c b/hier.c new file mode 100644 index 0000000..4aef75b --- /dev/null +++ b/hier.c @@ -0,0 +1,42 @@ +#include "auto_home.h" + +void hier() +{ + c("/","etc","dnsroots.global",-1,-1,0644); + + h(auto_home,-1,-1,02755); + d(auto_home,"bin",-1,-1,02755); + + c(auto_home,"bin","dnscache-conf",-1,-1,0755); + c(auto_home,"bin","tinydns-conf",-1,-1,0755); + c(auto_home,"bin","walldns-conf",-1,-1,0755); + c(auto_home,"bin","rbldns-conf",-1,-1,0755); + c(auto_home,"bin","pickdns-conf",-1,-1,0755); + c(auto_home,"bin","axfrdns-conf",-1,-1,0755); + + c(auto_home,"bin","dnscache",-1,-1,0755); + c(auto_home,"bin","tinydns",-1,-1,0755); + c(auto_home,"bin","walldns",-1,-1,0755); + c(auto_home,"bin","rbldns",-1,-1,0755); + c(auto_home,"bin","pickdns",-1,-1,0755); + c(auto_home,"bin","axfrdns",-1,-1,0755); + + c(auto_home,"bin","tinydns-get",-1,-1,0755); + c(auto_home,"bin","tinydns-data",-1,-1,0755); + c(auto_home,"bin","tinydns-edit",-1,-1,0755); + c(auto_home,"bin","rbldns-data",-1,-1,0755); + c(auto_home,"bin","pickdns-data",-1,-1,0755); + c(auto_home,"bin","axfr-get",-1,-1,0755); + + c(auto_home,"bin","dnsip",-1,-1,0755); + c(auto_home,"bin","dnsipq",-1,-1,0755); + c(auto_home,"bin","dnsname",-1,-1,0755); + c(auto_home,"bin","dnstxt",-1,-1,0755); + c(auto_home,"bin","dnsmx",-1,-1,0755); + c(auto_home,"bin","dnsfilter",-1,-1,0755); + c(auto_home,"bin","random-ip",-1,-1,0755); + c(auto_home,"bin","dnsqr",-1,-1,0755); + c(auto_home,"bin","dnsq",-1,-1,0755); + c(auto_home,"bin","dnstrace",-1,-1,0755); + c(auto_home,"bin","dnstracesort",-1,-1,0755); +} diff --git a/install.c b/install.c new file mode 100644 index 0000000..62f0e7f --- /dev/null +++ b/install.c @@ -0,0 +1,151 @@ +#include +#include +#include +#include "buffer.h" +#include "strerr.h" +#include "error.h" +#include "open.h" +#include "exit.h" + +extern void hier(); + +#define FATAL "install: fatal: " + +int fdsourcedir = -1; + +void h(home,uid,gid,mode) +char *home; +int uid; +int gid; +int mode; +{ + if (mkdir(home,0700) == -1) + if (errno != error_exist) + strerr_die4sys(111,FATAL,"unable to mkdir ",home,": "); + if (chown(home,uid,gid) == -1) + strerr_die4sys(111,FATAL,"unable to chown ",home,": "); + if (chmod(home,mode) == -1) + strerr_die4sys(111,FATAL,"unable to chmod ",home,": "); +} + +void d(home,subdir,uid,gid,mode) +char *home; +char *subdir; +int uid; +int gid; +int mode; +{ + if (chdir(home) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); + if (mkdir(subdir,0700) == -1) + if (errno != error_exist) + strerr_die6sys(111,FATAL,"unable to mkdir ",home,"/",subdir,": "); + if (chown(subdir,uid,gid) == -1) + strerr_die6sys(111,FATAL,"unable to chown ",home,"/",subdir,": "); + if (chmod(subdir,mode) == -1) + strerr_die6sys(111,FATAL,"unable to chmod ",home,"/",subdir,": "); +} + +char inbuf[BUFFER_INSIZE]; +char outbuf[BUFFER_OUTSIZE]; +buffer ssin; +buffer ssout; + +void c(home,subdir,file,uid,gid,mode) +char *home; +char *subdir; +char *file; +int uid; +int gid; +int mode; +{ + int fdin; + int fdout; + + if (fchdir(fdsourcedir) == -1) + strerr_die2sys(111,FATAL,"unable to switch back to source directory: "); + + fdin = open_read(file); + if (fdin == -1) + strerr_die4sys(111,FATAL,"unable to read ",file,": "); + buffer_init(&ssin,buffer_unixread,fdin,inbuf,sizeof inbuf); + + if (chdir(home) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); + if (chdir(subdir) == -1) + strerr_die6sys(111,FATAL,"unable to switch to ",home,"/",subdir,": "); + + fdout = open_trunc(file); + if (fdout == -1) + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + buffer_init(&ssout,buffer_unixwrite,fdout,outbuf,sizeof outbuf); + + switch(buffer_copy(&ssout,&ssin)) { + case -2: + strerr_die4sys(111,FATAL,"unable to read ",file,": "); + case -3: + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + } + + close(fdin); + if (buffer_flush(&ssout) == -1) + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + if (fsync(fdout) == -1) + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + if (close(fdout) == -1) /* NFS silliness */ + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + + if (chown(file,uid,gid) == -1) + strerr_die6sys(111,FATAL,"unable to chown .../",subdir,"/",file,": "); + if (chmod(file,mode) == -1) + strerr_die6sys(111,FATAL,"unable to chmod .../",subdir,"/",file,": "); +} + +void z(home,subdir,file,len,uid,gid,mode) +char *home; +char *subdir; +char *file; +int len; +int uid; +int gid; +int mode; +{ + int fdout; + + if (chdir(home) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); + if (chdir(subdir) == -1) + strerr_die6sys(111,FATAL,"unable to switch to ",home,"/",subdir,": "); + + fdout = open_trunc(file); + if (fdout == -1) + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + buffer_init(&ssout,buffer_unixwrite,fdout,outbuf,sizeof outbuf); + + while (len-- > 0) + if (buffer_put(&ssout,"",1) == -1) + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + + if (buffer_flush(&ssout) == -1) + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + if (fsync(fdout) == -1) + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + if (close(fdout) == -1) /* NFS silliness */ + strerr_die6sys(111,FATAL,"unable to write .../",subdir,"/",file,": "); + + if (chown(file,uid,gid) == -1) + strerr_die6sys(111,FATAL,"unable to chown .../",subdir,"/",file,": "); + if (chmod(file,mode) == -1) + strerr_die6sys(111,FATAL,"unable to chmod .../",subdir,"/",file,": "); +} + +int main() +{ + fdsourcedir = open_read("."); + if (fdsourcedir == -1) + strerr_die2sys(111,FATAL,"unable to open current directory: "); + + umask(077); + hier(); + _exit(0); +} diff --git a/instcheck.c b/instcheck.c new file mode 100644 index 0000000..06ed547 --- /dev/null +++ b/instcheck.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include "strerr.h" +#include "error.h" +#include "exit.h" + +extern void hier(); + +#define FATAL "instcheck: fatal: " +#define WARNING "instcheck: warning: " + +void perm(prefix1,prefix2,prefix3,file,type,uid,gid,mode) +char *prefix1; +char *prefix2; +char *prefix3; +char *file; +int type; +int uid; +int gid; +int mode; +{ + struct stat st; + + if (stat(file,&st) == -1) { + if (errno == error_noent) + strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," does not exist",0); + else + strerr_warn4(WARNING,"unable to stat .../",file,": ",&strerr_sys); + return; + } + + if ((uid != -1) && (st.st_uid != uid)) + strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong owner",0); + if ((gid != -1) && (st.st_gid != gid)) + strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong group",0); + if ((st.st_mode & 07777) != mode) + strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong permissions",0); + if ((st.st_mode & S_IFMT) != type) + strerr_warn6(WARNING,prefix1,prefix2,prefix3,file," has wrong type",0); +} + +void h(home,uid,gid,mode) +char *home; +int uid; +int gid; +int mode; +{ + perm("","","",home,S_IFDIR,uid,gid,mode); +} + +void d(home,subdir,uid,gid,mode) +char *home; +char *subdir; +int uid; +int gid; +int mode; +{ + if (chdir(home) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); + perm("",home,"/",subdir,S_IFDIR,uid,gid,mode); +} + +void p(home,fifo,uid,gid,mode) +char *home; +char *fifo; +int uid; +int gid; +int mode; +{ + if (chdir(home) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); + perm("",home,"/",fifo,S_IFIFO,uid,gid,mode); +} + +void c(home,subdir,file,uid,gid,mode) +char *home; +char *subdir; +char *file; +int uid; +int gid; +int mode; +{ + if (chdir(home) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); + if (chdir(subdir) == -1) + strerr_die6sys(111,FATAL,"unable to switch to ",home,"/",subdir,": "); + perm(".../",subdir,"/",file,S_IFREG,uid,gid,mode); +} + +void z(home,file,len,uid,gid,mode) +char *home; +char *file; +int len; +int uid; +int gid; +int mode; +{ + if (chdir(home) == -1) + strerr_die4sys(111,FATAL,"unable to switch to ",home,": "); + perm("",home,"/",file,S_IFREG,uid,gid,mode); +} + +int main() +{ + hier(); + _exit(0); +} diff --git a/iopause.c b/iopause.c new file mode 100644 index 0000000..b8034de --- /dev/null +++ b/iopause.c @@ -0,0 +1,76 @@ +#include "taia.h" +#include "select.h" +#include "iopause.h" + +void iopause(iopause_fd *x,unsigned int len,struct taia *deadline,struct taia *stamp) +{ + struct taia t; + int millisecs; + double d; + int i; + + if (taia_less(deadline,stamp)) + millisecs = 0; + else { + t = *stamp; + taia_sub(&t,deadline,&t); + d = taia_approx(&t); + if (d > 1000.0) d = 1000.0; + millisecs = d * 1000.0 + 20.0; + } + + for (i = 0;i < len;++i) + x[i].revents = 0; + +#ifdef IOPAUSE_POLL + + poll(x,len,millisecs); + /* XXX: some kernels apparently need x[0] even if len is 0 */ + /* XXX: how to handle EAGAIN? are kernels really this dumb? */ + /* XXX: how to handle EINVAL? when exactly can this happen? */ + +#else +{ + + struct timeval tv; + fd_set rfds; + fd_set wfds; + int nfds; + int fd; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + + nfds = 1; + for (i = 0;i < len;++i) { + fd = x[i].fd; + if (fd < 0) continue; + if (fd >= 8 * sizeof(fd_set)) continue; /*XXX*/ + + if (fd >= nfds) nfds = fd + 1; + if (x[i].events & IOPAUSE_READ) FD_SET(fd,&rfds); + if (x[i].events & IOPAUSE_WRITE) FD_SET(fd,&wfds); + } + + tv.tv_sec = millisecs / 1000; + tv.tv_usec = 1000 * (millisecs % 1000); + + if (select(nfds,&rfds,&wfds,(fd_set *) 0,&tv) <= 0) + return; + /* XXX: for EBADF, could seek out and destroy the bad descriptor */ + + for (i = 0;i < len;++i) { + fd = x[i].fd; + if (fd < 0) continue; + if (fd >= 8 * sizeof(fd_set)) continue; /*XXX*/ + + if (x[i].events & IOPAUSE_READ) + if (FD_ISSET(fd,&rfds)) x[i].revents |= IOPAUSE_READ; + if (x[i].events & IOPAUSE_WRITE) + if (FD_ISSET(fd,&wfds)) x[i].revents |= IOPAUSE_WRITE; + } + +} +#endif + +} diff --git a/iopause.h1 b/iopause.h1 new file mode 100644 index 0000000..dae0a33 --- /dev/null +++ b/iopause.h1 @@ -0,0 +1,19 @@ +#ifndef IOPAUSE_H +#define IOPAUSE_H + +/* sysdep: -poll */ + +typedef struct { + int fd; + short events; + short revents; +} iopause_fd; + +#define IOPAUSE_READ 1 +#define IOPAUSE_WRITE 4 + +#include "taia.h" + +extern void iopause(iopause_fd *,unsigned int,struct taia *,struct taia *); + +#endif diff --git a/iopause.h2 b/iopause.h2 new file mode 100644 index 0000000..2cf5cf8 --- /dev/null +++ b/iopause.h2 @@ -0,0 +1,18 @@ +#ifndef IOPAUSE_H +#define IOPAUSE_H + +/* sysdep: +poll */ +#define IOPAUSE_POLL + +#include +#include + +typedef struct pollfd iopause_fd; +#define IOPAUSE_READ POLLIN +#define IOPAUSE_WRITE POLLOUT + +#include "taia.h" + +extern void iopause(iopause_fd *,unsigned int,struct taia *,struct taia *); + +#endif diff --git a/ip4.h b/ip4.h new file mode 100644 index 0000000..923d0ed --- /dev/null +++ b/ip4.h @@ -0,0 +1,9 @@ +#ifndef IP4_H +#define IP4_H + +extern unsigned int ip4_scan(const char *,char *); +extern unsigned int ip4_fmt(char *,const char *); + +#define IP4_FMT 20 + +#endif diff --git a/ip4_fmt.c b/ip4_fmt.c new file mode 100644 index 0000000..bbad4c7 --- /dev/null +++ b/ip4_fmt.c @@ -0,0 +1,18 @@ +#include "fmt.h" +#include "ip4.h" + +unsigned int ip4_fmt(char *s,const char ip[4]) +{ + unsigned int len; + unsigned int i; + + len = 0; + i = fmt_ulong(s,(unsigned long) (unsigned char) ip[0]); len += i; if (s) s += i; + if (s) *s++ = '.'; ++len; + i = fmt_ulong(s,(unsigned long) (unsigned char) ip[1]); len += i; if (s) s += i; + if (s) *s++ = '.'; ++len; + i = fmt_ulong(s,(unsigned long) (unsigned char) ip[2]); len += i; if (s) s += i; + if (s) *s++ = '.'; ++len; + i = fmt_ulong(s,(unsigned long) (unsigned char) ip[3]); len += i; if (s) s += i; + return len; +} diff --git a/ip4_scan.c b/ip4_scan.c new file mode 100644 index 0000000..e9538ec --- /dev/null +++ b/ip4_scan.c @@ -0,0 +1,19 @@ +#include "scan.h" +#include "ip4.h" + +unsigned int ip4_scan(const char *s,char ip[4]) +{ + unsigned int i; + unsigned int len; + unsigned long u; + + len = 0; + i = scan_ulong(s,&u); if (!i) return 0; ip[0] = u; s += i; len += i; + if (*s != '.') return 0; ++s; ++len; + i = scan_ulong(s,&u); if (!i) return 0; ip[1] = u; s += i; len += i; + if (*s != '.') return 0; ++s; ++len; + i = scan_ulong(s,&u); if (!i) return 0; ip[2] = u; s += i; len += i; + if (*s != '.') return 0; ++s; ++len; + i = scan_ulong(s,&u); if (!i) return 0; ip[3] = u; s += i; len += i; + return len; +} diff --git a/log.c b/log.c new file mode 100644 index 0000000..c43e8b0 --- /dev/null +++ b/log.c @@ -0,0 +1,288 @@ +#include "buffer.h" +#include "uint32.h" +#include "uint16.h" +#include "error.h" +#include "byte.h" +#include "log.h" + +/* work around gcc 2.95.2 bug */ +#define number(x) ( (u64 = (x)), u64_print() ) +static uint64 u64; +static void u64_print(void) +{ + char buf[20]; + unsigned int pos; + + pos = sizeof buf; + do { + if (!pos) break; + buf[--pos] = '0' + (u64 % 10); + u64 /= 10; + } while(u64); + + buffer_put(buffer_2,buf + pos,sizeof buf - pos); +} + +static void hex(unsigned char c) +{ + buffer_put(buffer_2,"0123456789abcdef" + (c >> 4),1); + buffer_put(buffer_2,"0123456789abcdef" + (c & 15),1); +} + +static void string(const char *s) +{ + buffer_puts(buffer_2,s); +} + +static void line(void) +{ + string("\n"); + buffer_flush(buffer_2); +} + +static void space(void) +{ + string(" "); +} + +static void ip(const char i[4]) +{ + hex(i[0]); + hex(i[1]); + hex(i[2]); + hex(i[3]); +} + +static void logid(const char id[2]) +{ + hex(id[0]); + hex(id[1]); +} + +static void logtype(const char type[2]) +{ + uint16 u; + + uint16_unpack_big(type,&u); + number(u); +} + +static void name(const char *q) +{ + char ch; + int state; + + if (!*q) { + string("."); + return; + } + while (state = *q++) { + while (state) { + ch = *q++; + --state; + if ((ch <= 32) || (ch > 126)) ch = '?'; + if ((ch >= 'A') && (ch <= 'Z')) ch += 32; + buffer_put(buffer_2,&ch,1); + } + string("."); + } +} + +void log_startup(void) +{ + string("starting"); + line(); +} + +void log_query(uint64 *qnum,const char client[4],unsigned int port,const char id[2],const char *q,const char qtype[2]) +{ + string("query "); number(*qnum); space(); + ip(client); string(":"); hex(port >> 8); hex(port & 255); + string(":"); logid(id); space(); + logtype(qtype); space(); name(q); + line(); +} + +void log_querydone(uint64 *qnum,unsigned int len) +{ + string("sent "); number(*qnum); space(); + number(len); + line(); +} + +void log_querydrop(uint64 *qnum) +{ + const char *x = error_str(errno); + + string("drop "); number(*qnum); space(); + string(x); + line(); +} + +void log_tcpopen(const char client[4],unsigned int port) +{ + string("tcpopen "); + ip(client); string(":"); hex(port >> 8); hex(port & 255); + line(); +} + +void log_tcpclose(const char client[4],unsigned int port) +{ + const char *x = error_str(errno); + string("tcpclose "); + ip(client); string(":"); hex(port >> 8); hex(port & 255); space(); + string(x); + line(); +} + +void log_tx(const char *q,const char qtype[2],const char *control,const char servers[64],unsigned int gluelessness) +{ + int i; + + string("tx "); number(gluelessness); space(); + logtype(qtype); space(); name(q); space(); + name(control); + for (i = 0;i < 64;i += 4) + if (byte_diff(servers + i,4,"\0\0\0\0")) { + space(); + ip(servers + i); + } + line(); +} + +void log_cachedanswer(const char *q,const char type[2]) +{ + string("cached "); logtype(type); space(); + name(q); + line(); +} + +void log_cachedcname(const char *dn,const char *dn2) +{ + string("cached cname "); name(dn); space(); name(dn2); + line(); +} + +void log_cachedns(const char *control,const char *ns) +{ + string("cached ns "); name(control); space(); name(ns); + line(); +} + +void log_cachednxdomain(const char *dn) +{ + string("cached nxdomain "); name(dn); + line(); +} + +void log_nxdomain(const char server[4],const char *q,unsigned int ttl) +{ + string("nxdomain "); ip(server); space(); number(ttl); space(); + name(q); + line(); +} + +void log_nodata(const char server[4],const char *q,const char qtype[2],unsigned int ttl) +{ + string("nodata "); ip(server); space(); number(ttl); space(); + logtype(qtype); space(); name(q); + line(); +} + +void log_lame(const char server[4],const char *control,const char *referral) +{ + string("lame "); ip(server); space(); + name(control); space(); name(referral); + line(); +} + +void log_servfail(const char *dn) +{ + const char *x = error_str(errno); + + string("servfail "); name(dn); space(); + string(x); + line(); +} + +void log_rr(const char server[4],const char *q,const char type[2],const char *buf,unsigned int len,unsigned int ttl) +{ + int i; + + string("rr "); ip(server); space(); number(ttl); space(); + logtype(type); space(); name(q); space(); + + for (i = 0;i < len;++i) { + hex(buf[i]); + if (i > 30) { + string("..."); + break; + } + } + line(); +} + +void log_rrns(const char server[4],const char *q,const char *data,unsigned int ttl) +{ + string("rr "); ip(server); space(); number(ttl); + string(" ns "); name(q); space(); + name(data); + line(); +} + +void log_rrcname(const char server[4],const char *q,const char *data,unsigned int ttl) +{ + string("rr "); ip(server); space(); number(ttl); + string(" cname "); name(q); space(); + name(data); + line(); +} + +void log_rrptr(const char server[4],const char *q,const char *data,unsigned int ttl) +{ + string("rr "); ip(server); space(); number(ttl); + string(" ptr "); name(q); space(); + name(data); + line(); +} + +void log_rrmx(const char server[4],const char *q,const char *mx,const char pref[2],unsigned int ttl) +{ + uint16 u; + + string("rr "); ip(server); space(); number(ttl); + string(" mx "); name(q); space(); + uint16_unpack_big(pref,&u); + number(u); space(); name(mx); + line(); +} + +void log_rrsoa(const char server[4],const char *q,const char *n1,const char *n2,const char misc[20],unsigned int ttl) +{ + uint32 u; + int i; + + string("rr "); ip(server); space(); number(ttl); + string(" soa "); name(q); space(); + name(n1); space(); name(n2); + for (i = 0;i < 20;i += 4) { + uint32_unpack_big(misc + i,&u); + space(); number(u); + } + line(); +} + +void log_stats(void) +{ + extern uint64 numqueries; + extern uint64 cache_motion; + extern int uactive; + extern int tactive; + + string("stats "); + number(numqueries); space(); + number(cache_motion); space(); + number(uactive); space(); + number(tactive); + line(); +} diff --git a/log.h b/log.h new file mode 100644 index 0000000..fe62fa3 --- /dev/null +++ b/log.h @@ -0,0 +1,36 @@ +#ifndef LOG_H +#define LOG_H + +#include "uint64.h" + +extern void log_startup(void); + +extern void log_query(uint64 *,const char *,unsigned int,const char *,const char *,const char *); +extern void log_querydrop(uint64 *); +extern void log_querydone(uint64 *,unsigned int); + +extern void log_tcpopen(const char *,unsigned int); +extern void log_tcpclose(const char *,unsigned int); + +extern void log_cachedanswer(const char *,const char *); +extern void log_cachedcname(const char *,const char *); +extern void log_cachednxdomain(const char *); +extern void log_cachedns(const char *,const char *); + +extern void log_tx(const char *,const char *,const char *,const char *,unsigned int); + +extern void log_nxdomain(const char *,const char *,unsigned int); +extern void log_nodata(const char *,const char *,const char *,unsigned int); +extern void log_servfail(const char *); +extern void log_lame(const char *,const char *,const char *); + +extern void log_rr(const char *,const char *,const char *,const char *,unsigned int,unsigned int); +extern void log_rrns(const char *,const char *,const char *,unsigned int); +extern void log_rrcname(const char *,const char *,const char *,unsigned int); +extern void log_rrptr(const char *,const char *,const char *,unsigned int); +extern void log_rrmx(const char *,const char *,const char *,const char *,unsigned int); +extern void log_rrsoa(const char *,const char *,const char *,const char *,const char *,unsigned int); + +extern void log_stats(void); + +#endif diff --git a/ndelay.h b/ndelay.h new file mode 100644 index 0000000..60b788c --- /dev/null +++ b/ndelay.h @@ -0,0 +1,7 @@ +#ifndef NDELAY_H +#define NDELAY_H + +extern int ndelay_on(int); +extern int ndelay_off(int); + +#endif diff --git a/ndelay_off.c b/ndelay_off.c new file mode 100644 index 0000000..9daa8cd --- /dev/null +++ b/ndelay_off.c @@ -0,0 +1,12 @@ +#include +#include +#include "ndelay.h" + +#ifndef O_NONBLOCK +#define O_NONBLOCK O_NDELAY +#endif + +int ndelay_off(int fd) +{ + return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK); +} diff --git a/ndelay_on.c b/ndelay_on.c new file mode 100644 index 0000000..eccd8c8 --- /dev/null +++ b/ndelay_on.c @@ -0,0 +1,12 @@ +#include +#include +#include "ndelay.h" + +#ifndef O_NONBLOCK +#define O_NONBLOCK O_NDELAY +#endif + +int ndelay_on(int fd) +{ + return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK); +} diff --git a/okclient.c b/okclient.c new file mode 100644 index 0000000..a648c02 --- /dev/null +++ b/okclient.c @@ -0,0 +1,26 @@ +#include +#include +#include "str.h" +#include "ip4.h" +#include "okclient.h" + +static char fn[3 + IP4_FMT]; + +int okclient(char ip[4]) +{ + struct stat st; + int i; + + fn[0] = 'i'; + fn[1] = 'p'; + fn[2] = '/'; + fn[3 + ip4_fmt(fn + 3,ip)] = 0; + + for (;;) { + if (stat(fn,&st) == 0) return 1; + /* treat temporary error as rejection */ + i = str_rchr(fn,'.'); + if (!fn[i]) return 0; + fn[i] = 0; + } +} diff --git a/okclient.h b/okclient.h new file mode 100644 index 0000000..e9b7dd6 --- /dev/null +++ b/okclient.h @@ -0,0 +1,6 @@ +#ifndef OKCLIENT_H +#define OKCLIENT_H + +extern int okclient(char *); + +#endif diff --git a/open.h b/open.h new file mode 100644 index 0000000..1fcd99f --- /dev/null +++ b/open.h @@ -0,0 +1,10 @@ +#ifndef OPEN_H +#define OPEN_H + +extern int open_read(const char *); +extern int open_excl(const char *); +extern int open_append(const char *); +extern int open_trunc(const char *); +extern int open_write(const char *); + +#endif diff --git a/open_read.c b/open_read.c new file mode 100644 index 0000000..2a63a25 --- /dev/null +++ b/open_read.c @@ -0,0 +1,6 @@ +#include +#include +#include "open.h" + +int open_read(const char *fn) +{ return open(fn,O_RDONLY | O_NDELAY); } diff --git a/open_trunc.c b/open_trunc.c new file mode 100644 index 0000000..9d0f1dc --- /dev/null +++ b/open_trunc.c @@ -0,0 +1,6 @@ +#include +#include +#include "open.h" + +int open_trunc(const char *fn) +{ return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644); } diff --git a/openreadclose.c b/openreadclose.c new file mode 100644 index 0000000..cbc5c6c --- /dev/null +++ b/openreadclose.c @@ -0,0 +1,16 @@ +#include "error.h" +#include "open.h" +#include "readclose.h" +#include "openreadclose.h" + +int openreadclose(const char *fn,stralloc *sa,unsigned int bufsize) +{ + int fd; + fd = open_read(fn); + if (fd == -1) { + if (errno == error_noent) return 0; + return -1; + } + if (readclose(fd,sa,bufsize) == -1) return -1; + return 1; +} diff --git a/openreadclose.h b/openreadclose.h new file mode 100644 index 0000000..2d4042e --- /dev/null +++ b/openreadclose.h @@ -0,0 +1,8 @@ +#ifndef OPENREADCLOSE_H +#define OPENREADCLOSE_H + +#include "stralloc.h" + +extern int openreadclose(const char *,stralloc *,unsigned int); + +#endif diff --git a/parsetype.c b/parsetype.c new file mode 100644 index 0000000..167aaa4 --- /dev/null +++ b/parsetype.c @@ -0,0 +1,31 @@ +#include "scan.h" +#include "byte.h" +#include "case.h" +#include "dns.h" +#include "uint16.h" +#include "parsetype.h" + +int parsetype(char *s,char type[2]) +{ + unsigned long u; + + if (!s[scan_ulong(s,&u)]) uint16_pack_big(type,u); + else if (case_equals(s,"any")) byte_copy(type,2,DNS_T_ANY); + else if (case_equals(s,"a")) byte_copy(type,2,DNS_T_A); + else if (case_equals(s,"ns")) byte_copy(type,2,DNS_T_NS); + else if (case_equals(s,"mx")) byte_copy(type,2,DNS_T_MX); + else if (case_equals(s,"ptr")) byte_copy(type,2,DNS_T_PTR); + else if (case_equals(s,"txt")) byte_copy(type,2,DNS_T_TXT); + else if (case_equals(s,"cname")) byte_copy(type,2,DNS_T_CNAME); + else if (case_equals(s,"soa")) byte_copy(type,2,DNS_T_SOA); + else if (case_equals(s,"hinfo")) byte_copy(type,2,DNS_T_HINFO); + else if (case_equals(s,"rp")) byte_copy(type,2,DNS_T_RP); + else if (case_equals(s,"sig")) byte_copy(type,2,DNS_T_SIG); + else if (case_equals(s,"key")) byte_copy(type,2,DNS_T_KEY); + else if (case_equals(s,"aaaa")) byte_copy(type,2,DNS_T_AAAA); + else if (case_equals(s,"axfr")) byte_copy(type,2,DNS_T_AXFR); + else + return 0; + + return 1; +} diff --git a/parsetype.h b/parsetype.h new file mode 100644 index 0000000..4851725 --- /dev/null +++ b/parsetype.h @@ -0,0 +1,6 @@ +#ifndef PARSETYPE_H +#define PARSETYPE_H + +extern int parsetype(char *,char *); + +#endif diff --git a/pickdns-conf.c b/pickdns-conf.c new file mode 100644 index 0000000..9edd184 --- /dev/null +++ b/pickdns-conf.c @@ -0,0 +1,66 @@ +#include +#include +#include "strerr.h" +#include "exit.h" +#include "auto_home.h" +#include "generic-conf.h" + +#define FATAL "pickdns-conf: fatal: " + +void usage(void) +{ + strerr_die1x(100,"pickdns-conf: usage: pickdns-conf acct logacct /pickdns myip"); +} + +char *dir; +char *user; +char *loguser; +struct passwd *pw; +char *myip; + +int main(int argc,char **argv) +{ + user = argv[1]; + if (!user) usage(); + loguser = argv[2]; + if (!loguser) usage(); + dir = argv[3]; + if (!dir) usage(); + if (dir[0] != '/') usage(); + myip = argv[4]; + if (!myip) usage(); + + pw = getpwnam(loguser); + if (!pw) + strerr_die3x(111,FATAL,"unknown account ",loguser); + + init(dir,FATAL); + makelog(loguser,pw->pw_uid,pw->pw_gid); + + makedir("env"); + perm(02755); + start("env/ROOT"); outs(dir); outs("/root\n"); finish(); + perm(0644); + start("env/IP"); outs(myip); outs("\n"); finish(); + perm(0644); + + start("run"); + outs("#!/bin/sh\nexec 2>&1\nexec envuidgid "); outs(user); + outs(" envdir ./env softlimit -d250000 "); + outs(auto_home); outs("/bin/pickdns\n"); + finish(); + perm(0755); + + makedir("root"); + perm(02755); + start("root/data"); + finish(); + perm(0644); + start("root/Makefile"); + outs("data.cdb: data\n"); + outs("\t"); outs(auto_home); outs("/bin/pickdns-data\n"); + finish(); + perm(0644); + + _exit(0); +} diff --git a/pickdns-data.c b/pickdns-data.c new file mode 100644 index 0000000..60cabb0 --- /dev/null +++ b/pickdns-data.c @@ -0,0 +1,230 @@ +#include +#include +#include +#include +#include "buffer.h" +#include "exit.h" +#include "cdb_make.h" +#include "open.h" +#include "alloc.h" +#include "gen_allocdefs.h" +#include "stralloc.h" +#include "getln.h" +#include "case.h" +#include "strerr.h" +#include "str.h" +#include "byte.h" +#include "scan.h" +#include "fmt.h" +#include "ip4.h" +#include "dns.h" + +#define FATAL "pickdns-data: fatal: " + +void nomem(void) +{ + strerr_die2x(111,FATAL,"out of memory"); +} + +void ipprefix_cat(stralloc *out,char *s) +{ + unsigned long u; + char ch; + unsigned int j; + + for (;;) + if (*s == '.') + ++s; + else { + j = scan_ulong(s,&u); + if (!j) return; + s += j; + ch = u; + if (!stralloc_catb(out,&ch,1)) nomem(); + } +} + +struct address { + char *name; + unsigned int namelen; + char ip[4]; + char location[2]; +} ; + +int address_diff(struct address *p,struct address *q) +{ + int r; + + r = byte_diff(p->location,2,q->location); + if (r < 0) return -1; + if (r > 0) return 1; + if (p->namelen < q->namelen) return -1; + if (p->namelen > q->namelen) return 1; + return case_diffb(p->name,p->namelen,q->name); +} + +void address_sort(struct address *z,unsigned int n) +{ + unsigned int i; + unsigned int j; + unsigned int p; + unsigned int q; + struct address t; + + i = j = n; + --z; + + while (j > 1) { + if (i > 1) { --i; t = z[i]; } + else { t = z[j]; z[j] = z[i]; --j; } + q = i; + while ((p = q * 2) < j) { + if (address_diff(&z[p + 1],&z[p]) >= 0) ++p; + z[q] = z[p]; q = p; + } + if (p == j) { + z[q] = z[p]; q = p; + } + while ((q > i) && (address_diff(&t,&z[p = q/2]) > 0)) { + z[q] = z[p]; q = p; + } + z[q] = t; + } +} + +GEN_ALLOC_typedef(address_alloc,struct address,s,len,a) +GEN_ALLOC_readyplus(address_alloc,struct address,s,len,a,i,n,x,30,address_alloc_readyplus) +GEN_ALLOC_append(address_alloc,struct address,s,len,a,i,n,x,30,address_alloc_readyplus,address_alloc_append) + +static address_alloc x; + +int fd; +buffer b; +char bspace[1024]; + +int fdcdb; +struct cdb_make cdb; +static stralloc key; +static stralloc result; + +static stralloc line; +int match = 1; +unsigned long linenum = 0; + +#define NUMFIELDS 3 +static stralloc f[NUMFIELDS]; + +char strnum[FMT_ULONG]; + +void syntaxerror(const char *why) +{ + strnum[fmt_ulong(strnum,linenum)] = 0; + strerr_die4x(111,FATAL,"unable to parse data line ",strnum,why); +} +void die_datatmp(void) +{ + strerr_die2sys(111,FATAL,"unable to create data.tmp: "); +} + +int main() +{ + struct address t; + int i; + int j; + int k; + char ch; + + umask(022); + + if (!address_alloc_readyplus(&x,0)) nomem(); + + fd = open_read("data"); + if (fd == -1) strerr_die2sys(111,FATAL,"unable to open data: "); + buffer_init(&b,buffer_unixread,fd,bspace,sizeof bspace); + + fdcdb = open_trunc("data.tmp"); + if (fdcdb == -1) die_datatmp(); + if (cdb_make_start(&cdb,fdcdb) == -1) die_datatmp(); + + while (match) { + ++linenum; + if (getln(&b,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read line: "); + + while (line.len) { + ch = line.s[line.len - 1]; + if ((ch != ' ') && (ch != '\t') && (ch != '\n')) break; + --line.len; + } + if (!line.len) continue; + + j = 1; + for (i = 0;i < NUMFIELDS;++i) { + if (j >= line.len) { + if (!stralloc_copys(&f[i],"")) nomem(); + } + else { + k = byte_chr(line.s + j,line.len - j,':'); + if (!stralloc_copyb(&f[i],line.s + j,k)) nomem(); + j += k + 1; + } + } + + switch(line.s[0]) { + default: + syntaxerror(": unrecognized leading character"); + case '#': + break; + case '-': + break; + case '+': + byte_zero(&t,sizeof t); + if (!dns_domain_fromdot(&t.name,f[0].s,f[0].len)) nomem(); + t.namelen = dns_domain_length(t.name); + case_lowerb(t.name,t.namelen); + if (!stralloc_0(&f[1])) nomem(); + if (!ip4_scan(f[1].s,t.ip)) syntaxerror(": malformed IP address"); + if (!stralloc_0(&f[2])) nomem(); + if (!stralloc_0(&f[2])) nomem(); + byte_copy(t.location,2,f[2].s); + if (!address_alloc_append(&x,&t)) nomem(); + break; + case '%': + if (!stralloc_0(&f[0])) nomem(); + if (!stralloc_0(&f[0])) nomem(); + if (!stralloc_copyb(&result,f[0].s,2)) nomem(); + if (!stralloc_0(&f[1])) nomem(); + if (!stralloc_copys(&key,"%")) nomem(); + ipprefix_cat(&key,f[1].s); + if (cdb_make_add(&cdb,key.s,key.len,result.s,result.len) == -1) + die_datatmp(); + break; + } + } + + close(fd); + address_sort(x.s,x.len); + + i = 0; + while (i < x.len) { + for (j = i + 1;j < x.len;++j) + if (address_diff(x.s + i,x.s + j)) + break; + if (!stralloc_copys(&key,"+")) nomem(); + if (!stralloc_catb(&key,x.s[i].location,2)) nomem(); + if (!stralloc_catb(&key,x.s[i].name,x.s[i].namelen)) nomem(); + if (!stralloc_copys(&result,"")) nomem(); + while (i < j) + if (!stralloc_catb(&result,x.s[i++].ip,4)) nomem(); + if (cdb_make_add(&cdb,key.s,key.len,result.s,result.len) == -1) + die_datatmp(); + } + + if (cdb_make_finish(&cdb) == -1) die_datatmp(); + if (fsync(fdcdb) == -1) die_datatmp(); + if (close(fdcdb) == -1) die_datatmp(); /* NFS stupidity */ + if (rename("data.tmp","data.cdb") == -1) + strerr_die2sys(111,FATAL,"unable to move data.tmp to data.cdb: "); + + _exit(0); +} diff --git a/pickdns.c b/pickdns.c new file mode 100644 index 0000000..28c4ba5 --- /dev/null +++ b/pickdns.c @@ -0,0 +1,101 @@ +#include +#include "byte.h" +#include "case.h" +#include "dns.h" +#include "open.h" +#include "cdb.h" +#include "response.h" + +const char *fatal = "pickdns: fatal: "; +const char *starting = "starting pickdns\n"; + +static char seed[128]; + +void initialize(void) +{ + dns_random_init(seed); +} + +static struct cdb c; +static char key[258]; +static char data[512]; + +static int doit(char *q,char qtype[2],char ip[4]) +{ + int r; + uint32 dlen; + unsigned int qlen; + int flaga; + int flagmx; + + qlen = dns_domain_length(q); + if (qlen > 255) return 0; /* impossible */ + + flaga = byte_equal(qtype,2,DNS_T_A); + flagmx = byte_equal(qtype,2,DNS_T_MX); + if (byte_equal(qtype,2,DNS_T_ANY)) flaga = flagmx = 1; + if (!flaga && !flagmx) goto REFUSE; + + key[0] = '%'; + byte_copy(key + 1,4,ip); + + r = cdb_find(&c,key,5); + if (!r) r = cdb_find(&c,key,4); + if (!r) r = cdb_find(&c,key,3); + if (!r) r = cdb_find(&c,key,2); + if (r == -1) return 0; + + key[0] = '+'; + byte_zero(key + 1,2); + if (r && (cdb_datalen(&c) == 2)) + if (cdb_read(&c,key + 1,2,cdb_datapos(&c)) == -1) return 0; + + byte_copy(key + 3,qlen,q); + case_lowerb(key + 3,qlen + 3); + + r = cdb_find(&c,key,qlen + 3); + if (!r) { + byte_zero(key + 1,2); + r = cdb_find(&c,key,qlen + 3); + } + if (!r) goto REFUSE; + if (r == -1) return 0; + dlen = cdb_datalen(&c); + + if (dlen > 512) dlen = 512; + if (cdb_read(&c,data,dlen,cdb_datapos(&c)) == -1) return 0; + + if (flaga) { + dns_sortip(data,dlen); + if (dlen > 12) dlen = 12; + while (dlen >= 4) { + dlen -= 4; + if (!response_rstart(q,DNS_T_A,5)) return 0; + if (!response_addbytes(data + dlen,4)) return 0; + response_rfinish(RESPONSE_ANSWER); + } + } + + return 1; + + + REFUSE: + response[2] &= ~4; + response[3] &= ~15; + response[3] |= 5; + return 1; +} + +int respond(char *q,char qtype[2],char ip[4]) +{ + int fd; + int result; + + fd = open_read("data.cdb"); + if (fd == -1) return 0; + cdb_init(&c,fd); + result = doit(q,qtype,ip); + cdb_free(&c); + close(fd); + return result; +} diff --git a/printpacket.c b/printpacket.c new file mode 100644 index 0000000..7571e08 --- /dev/null +++ b/printpacket.c @@ -0,0 +1,90 @@ +#include "uint16.h" +#include "uint32.h" +#include "error.h" +#include "byte.h" +#include "dns.h" +#include "printrecord.h" +#include "printpacket.h" + +static char *d; + +#define X(s) if (!stralloc_cats(out,s)) return 0; +#define NUM(u) if (!stralloc_catulong0(out,u,0)) return 0; + +unsigned int printpacket_cat(stralloc *out,char *buf,unsigned int len) +{ + uint16 numqueries; + uint16 numanswers; + uint16 numauthority; + uint16 numglue; + unsigned int pos; + char data[12]; + uint16 type; + + pos = dns_packet_copy(buf,len,0,data,12); if (!pos) return 0; + + uint16_unpack_big(data + 4,&numqueries); + uint16_unpack_big(data + 6,&numanswers); + uint16_unpack_big(data + 8,&numauthority); + uint16_unpack_big(data + 10,&numglue); + + NUM(len) + X(" bytes, ") + NUM(numqueries) + X("+") + NUM(numanswers) + X("+") + NUM(numauthority) + X("+") + NUM(numglue) + X(" records") + + if (data[2] & 128) X(", response") + if (data[2] & 120) X(", weird op") + if (data[2] & 4) X(", authoritative") + if (data[2] & 2) X(", truncated") + if (data[2] & 1) X(", weird rd") + if (data[3] & 128) X(", weird ra") + switch(data[3] & 15) { + case 0: X(", noerror"); break; + case 3: X(", nxdomain"); break; + case 4: X(", notimp"); break; + case 5: X(", refused"); break; + default: X(", weird rcode"); + } + if (data[3] & 112) X(", weird z") + + X("\n") + + while (numqueries) { + --numqueries; + X("query: ") + + pos = dns_packet_getname(buf,len,pos,&d); if (!pos) return 0; + pos = dns_packet_copy(buf,len,pos,data,4); if (!pos) return 0; + + if (byte_diff(data + 2,2,DNS_C_IN)) { + X("weird class") + } + else { + uint16_unpack_big(data,&type); + NUM(type) + X(" ") + if (!dns_domain_todot_cat(out,d)) return 0; + } + X("\n") + } + + for (;;) { + if (numanswers) { --numanswers; X("answer: ") } + else if (numauthority) { --numauthority; X("authority: ") } + else if (numglue) { --numglue; X("additional: ") } + else break; + + pos = printrecord_cat(out,buf,len,pos,0,0); + if (!pos) return 0; + } + + if (pos != len) { errno = error_proto; return 0; } + return 1; +} diff --git a/printpacket.h b/printpacket.h new file mode 100644 index 0000000..8c8946d --- /dev/null +++ b/printpacket.h @@ -0,0 +1,8 @@ +#ifndef PRINTPACKET_H +#define PRINTPACKET_H + +#include "stralloc.h" + +extern unsigned int printpacket_cat(stralloc *,char *,unsigned int); + +#endif diff --git a/printrecord.c b/printrecord.c new file mode 100644 index 0000000..ed0b42d --- /dev/null +++ b/printrecord.c @@ -0,0 +1,115 @@ +#include "uint16.h" +#include "uint32.h" +#include "error.h" +#include "byte.h" +#include "dns.h" +#include "printrecord.h" + +static char *d; + +unsigned int printrecord_cat(stralloc *out,const char *buf,unsigned int len,unsigned int pos,const char *q,const char qtype[2]) +{ + const char *x; + char misc[20]; + uint16 datalen; + uint16 u16; + uint32 u32; + unsigned int newpos; + int i; + unsigned char ch; + + pos = dns_packet_getname(buf,len,pos,&d); if (!pos) return 0; + pos = dns_packet_copy(buf,len,pos,misc,10); if (!pos) return 0; + uint16_unpack_big(misc + 8,&datalen); + newpos = pos + datalen; + + if (q) { + if (!dns_domain_equal(d,q)) + return newpos; + if (byte_diff(qtype,2,misc) && byte_diff(qtype,2,DNS_T_ANY)) + return newpos; + } + + if (!dns_domain_todot_cat(out,d)) return 0; + if (!stralloc_cats(out," ")) return 0; + uint32_unpack_big(misc + 4,&u32); + if (!stralloc_catulong0(out,u32,0)) return 0; + + if (byte_diff(misc + 2,2,DNS_C_IN)) { + if (!stralloc_cats(out," weird class\n")) return 0; + return newpos; + } + + x = 0; + if (byte_equal(misc,2,DNS_T_NS)) x = " NS "; + if (byte_equal(misc,2,DNS_T_PTR)) x = " PTR "; + if (byte_equal(misc,2,DNS_T_CNAME)) x = " CNAME "; + if (x) { + pos = dns_packet_getname(buf,len,pos,&d); if (!pos) return 0; + if (!stralloc_cats(out,x)) return 0; + if (!dns_domain_todot_cat(out,d)) return 0; + } + else if (byte_equal(misc,2,DNS_T_MX)) { + if (!stralloc_cats(out," MX ")) return 0; + pos = dns_packet_copy(buf,len,pos,misc,2); if (!pos) return 0; + pos = dns_packet_getname(buf,len,pos,&d); if (!pos) return 0; + uint16_unpack_big(misc,&u16); + if (!stralloc_catulong0(out,u16,0)) return 0; + if (!stralloc_cats(out," ")) return 0; + if (!dns_domain_todot_cat(out,d)) return 0; + } + else if (byte_equal(misc,2,DNS_T_SOA)) { + if (!stralloc_cats(out," SOA ")) return 0; + pos = dns_packet_getname(buf,len,pos,&d); if (!pos) return 0; + if (!dns_domain_todot_cat(out,d)) return 0; + if (!stralloc_cats(out," ")) return 0; + pos = dns_packet_getname(buf,len,pos,&d); if (!pos) return 0; + if (!dns_domain_todot_cat(out,d)) return 0; + pos = dns_packet_copy(buf,len,pos,misc,20); if (!pos) return 0; + for (i = 0;i < 5;++i) { + if (!stralloc_cats(out," ")) return 0; + uint32_unpack_big(misc + 4 * i,&u32); + if (!stralloc_catulong0(out,u32,0)) return 0; + } + } + else if (byte_equal(misc,2,DNS_T_A)) { + if (datalen != 4) { errno = error_proto; return 0; } + if (!stralloc_cats(out," A ")) return 0; + pos = dns_packet_copy(buf,len,pos,misc,4); if (!pos) return 0; + for (i = 0;i < 4;++i) { + ch = misc[i]; + if (i) if (!stralloc_cats(out,".")) return 0; + if (!stralloc_catulong0(out,ch,0)) return 0; + } + } + else { + if (!stralloc_cats(out," ")) return 0; + uint16_unpack_big(misc,&u16); + if (!stralloc_catulong0(out,u16,0)) return 0; + if (!stralloc_cats(out," ")) return 0; + while (datalen--) { + pos = dns_packet_copy(buf,len,pos,misc,1); if (!pos) return 0; + if ((misc[0] >= 33) && (misc[0] <= 126) && (misc[0] != '\\')) { + if (!stralloc_catb(out,misc,1)) return 0; + } + else { + ch = misc[0]; + misc[3] = '0' + (7 & ch); ch >>= 3; + misc[2] = '0' + (7 & ch); ch >>= 3; + misc[1] = '0' + (7 & ch); + misc[0] = '\\'; + if (!stralloc_catb(out,misc,4)) return 0; + } + } + } + + if (!stralloc_cats(out,"\n")) return 0; + if (pos != newpos) { errno = error_proto; return 0; } + return newpos; +} + +unsigned int printrecord(stralloc *out,const char *buf,unsigned int len,unsigned int pos,const char *q,const char qtype[2]) +{ + if (!stralloc_copys(out,"")) return 0; + return printrecord_cat(out,buf,len,pos,q,qtype); +} diff --git a/printrecord.h b/printrecord.h new file mode 100644 index 0000000..f6bc9f7 --- /dev/null +++ b/printrecord.h @@ -0,0 +1,9 @@ +#ifndef PRINTRECORD_H +#define PRINTRECORD_H + +#include "stralloc.h" + +extern unsigned int printrecord_cat(stralloc *,const char *,unsigned int,unsigned int,const char *,const char *); +extern unsigned int printrecord(stralloc *,const char *,unsigned int,unsigned int,const char *,const char *); + +#endif diff --git a/prot.c b/prot.c new file mode 100644 index 0000000..0a8a373 --- /dev/null +++ b/prot.c @@ -0,0 +1,19 @@ +#include "hasshsgr.h" +#include "prot.h" + +int prot_gid(int gid) +{ +#ifdef HASSHORTSETGROUPS + short x[2]; + x[0] = gid; x[1] = 73; /* catch errors */ + if (setgroups(1,x) == -1) return -1; +#else + if (setgroups(1,&gid) == -1) return -1; +#endif + return setgid(gid); /* _should_ be redundant, but on some systems it isn't */ +} + +int prot_uid(int uid) +{ + return setuid(uid); +} diff --git a/prot.h b/prot.h new file mode 100644 index 0000000..7dd0503 --- /dev/null +++ b/prot.h @@ -0,0 +1,7 @@ +#ifndef PROT_H +#define PROT_H + +extern int prot_gid(int); +extern int prot_uid(int); + +#endif diff --git a/qlog.c b/qlog.c new file mode 100644 index 0000000..5c5c7ba --- /dev/null +++ b/qlog.c @@ -0,0 +1,63 @@ +#include "buffer.h" +#include "qlog.h" + +static void put(char c) +{ + buffer_put(buffer_2,&c,1); +} + +static void hex(unsigned char c) +{ + put("0123456789abcdef"[(c >> 4) & 15]); + put("0123456789abcdef"[c & 15]); +} + +static void octal(unsigned char c) +{ + put('\\'); + put('0' + ((c >> 6) & 7)); + put('0' + ((c >> 3) & 7)); + put('0' + (c & 7)); +} + +void qlog(const char ip[4],uint16 port,const char id[2],const char *q,const char qtype[2],const char *result) +{ + char ch; + char ch2; + + hex(ip[0]); + hex(ip[1]); + hex(ip[2]); + hex(ip[3]); + put(':'); + hex(port >> 8); + hex(port & 255); + put(':'); + hex(id[0]); + hex(id[1]); + buffer_puts(buffer_2,result); + hex(qtype[0]); + hex(qtype[1]); + put(' '); + + if (!*q) + put('.'); + else + for (;;) { + ch = *q++; + while (ch--) { + ch2 = *q++; + if ((ch2 >= 'A') && (ch2 <= 'Z')) + ch2 += 32; + if (((ch2 >= 'a') && (ch2 <= 'z')) || ((ch2 >= '0') && (ch2 <= '9')) || (ch2 == '-') || (ch2 == '_')) + put(ch2); + else + octal(ch2); + } + if (!*q) break; + put('.'); + } + + put('\n'); + buffer_flush(buffer_2); +} diff --git a/qlog.h b/qlog.h new file mode 100644 index 0000000..a1eb206 --- /dev/null +++ b/qlog.h @@ -0,0 +1,8 @@ +#ifndef QLOG_H +#define QLOG_H + +#include "uint16.h" + +extern void qlog(const char *,uint16,const char *,const char *,const char *,const char *); + +#endif diff --git a/query.c b/query.c new file mode 100644 index 0000000..46cdc00 --- /dev/null +++ b/query.c @@ -0,0 +1,851 @@ +#include "error.h" +#include "roots.h" +#include "log.h" +#include "case.h" +#include "cache.h" +#include "byte.h" +#include "dns.h" +#include "uint64.h" +#include "uint32.h" +#include "uint16.h" +#include "dd.h" +#include "alloc.h" +#include "response.h" +#include "query.h" + +static int flagforwardonly = 0; + +void query_forwardonly(void) +{ + flagforwardonly = 1; +} + +static void cachegeneric(const char type[2],const char *d,const char *data,unsigned int datalen,uint32 ttl) +{ + unsigned int len; + char key[257]; + + len = dns_domain_length(d); + if (len > 255) return; + + byte_copy(key,2,type); + byte_copy(key + 2,len,d); + case_lowerb(key + 2,len); + + cache_set(key,len + 2,data,datalen,ttl); +} + +static char save_buf[8192]; +static unsigned int save_len; +static unsigned int save_ok; + +static void save_start(void) +{ + save_len = 0; + save_ok = 1; +} + +static void save_data(const char *buf,unsigned int len) +{ + if (!save_ok) return; + if (len > (sizeof save_buf) - save_len) { save_ok = 0; return; } + byte_copy(save_buf + save_len,len,buf); + save_len += len; +} + +static void save_finish(const char type[2],const char *d,uint32 ttl) +{ + if (!save_ok) return; + cachegeneric(type,d,save_buf,save_len,ttl); +} + + +static int typematch(const char rtype[2],const char qtype[2]) +{ + return byte_equal(qtype,2,rtype) || byte_equal(qtype,2,DNS_T_ANY); +} + +static uint32 ttlget(char buf[4]) +{ + uint32 ttl; + + uint32_unpack_big(buf,&ttl); + if (ttl > 1000000000) return 0; + if (ttl > 604800) return 604800; + return ttl; +} + + +static void cleanup(struct query *z) +{ + int j; + int k; + + dns_transmit_free(&z->dt); + for (j = 0;j < QUERY_MAXALIAS;++j) + dns_domain_free(&z->alias[j]); + for (j = 0;j < QUERY_MAXLEVEL;++j) { + dns_domain_free(&z->name[j]); + for (k = 0;k < QUERY_MAXNS;++k) + dns_domain_free(&z->ns[j][k]); + } +} + +static int rqa(struct query *z) +{ + int i; + + for (i = QUERY_MAXALIAS - 1;i >= 0;--i) + if (z->alias[i]) { + if (!response_query(z->alias[i],z->type,z->class)) return 0; + while (i > 0) { + if (!response_cname(z->alias[i],z->alias[i - 1],z->aliasttl[i])) return 0; + --i; + } + if (!response_cname(z->alias[0],z->name[0],z->aliasttl[0])) return 0; + return 1; + } + + if (!response_query(z->name[0],z->type,z->class)) return 0; + return 1; +} + +static int globalip(char *d,char ip[4]) +{ + if (dns_domain_equal(d,"\011localhost\0")) { + byte_copy(ip,4,"\177\0\0\1"); + return 1; + } + if (dd(d,"",ip) == 4) return 1; + return 0; +} + +static char *t1 = 0; +static char *t2 = 0; +static char *t3 = 0; +static char *cname = 0; +static char *referral = 0; +static unsigned int *records = 0; + +static int smaller(char *buf,unsigned int len,unsigned int pos1,unsigned int pos2) +{ + char header1[12]; + char header2[12]; + int r; + unsigned int len1; + unsigned int len2; + + pos1 = dns_packet_getname(buf,len,pos1,&t1); + dns_packet_copy(buf,len,pos1,header1,10); + pos2 = dns_packet_getname(buf,len,pos2,&t2); + dns_packet_copy(buf,len,pos2,header2,10); + + r = byte_diff(header1,4,header2); + if (r < 0) return 1; + if (r > 0) return 0; + + len1 = dns_domain_length(t1); + len2 = dns_domain_length(t2); + if (len1 < len2) return 1; + if (len1 > len2) return 0; + + r = case_diffb(t1,len1,t2); + if (r < 0) return 1; + if (r > 0) return 0; + + if (pos1 < pos2) return 1; + return 0; +} + +static int doit(struct query *z,int state) +{ + char key[257]; + char *cached; + unsigned int cachedlen; + char *buf; + unsigned int len; + const char *whichserver; + char header[12]; + char misc[20]; + unsigned int rcode; + unsigned int posanswers; + uint16 numanswers; + unsigned int posauthority; + uint16 numauthority; + unsigned int posglue; + uint16 numglue; + unsigned int pos; + unsigned int pos2; + uint16 datalen; + char *control; + char *d; + const char *dtype; + unsigned int dlen; + int flagout; + int flagcname; + int flagreferral; + int flagsoa; + uint32 ttl; + uint32 soattl; + uint32 cnamettl; + int i; + int j; + int k; + int p; + int q; + + errno = error_io; + if (state == 1) goto HAVEPACKET; + if (state == -1) { + log_servfail(z->name[z->level]); + goto SERVFAIL; + } + + + NEWNAME: + if (++z->loop == 100) goto DIE; + d = z->name[z->level]; + dtype = z->level ? DNS_T_A : z->type; + dlen = dns_domain_length(d); + + if (globalip(d,misc)) { + if (z->level) { + for (k = 0;k < 64;k += 4) + if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) { + byte_copy(z->servers[z->level - 1] + k,4,misc); + break; + } + goto LOWERLEVEL; + } + if (!rqa(z)) goto DIE; + if (typematch(DNS_T_A,dtype)) { + if (!response_rstart(d,DNS_T_A,655360)) goto DIE; + if (!response_addbytes(misc,4)) goto DIE; + response_rfinish(RESPONSE_ANSWER); + } + cleanup(z); + return 1; + } + + if (dns_domain_equal(d,"\0011\0010\0010\003127\7in-addr\4arpa\0")) { + if (z->level) goto LOWERLEVEL; + if (!rqa(z)) goto DIE; + if (typematch(DNS_T_PTR,dtype)) { + if (!response_rstart(d,DNS_T_PTR,655360)) goto DIE; + if (!response_addname("\011localhost\0")) goto DIE; + response_rfinish(RESPONSE_ANSWER); + } + cleanup(z); + log_stats(); + return 1; + } + + if (dlen <= 255) { + byte_copy(key,2,DNS_T_ANY); + byte_copy(key + 2,dlen,d); + case_lowerb(key + 2,dlen); + cached = cache_get(key,dlen + 2,&cachedlen,&ttl); + if (cached) { + log_cachednxdomain(d); + goto NXDOMAIN; + } + + byte_copy(key,2,DNS_T_CNAME); + cached = cache_get(key,dlen + 2,&cachedlen,&ttl); + if (cached) { + if (typematch(DNS_T_CNAME,dtype)) { + log_cachedanswer(d,DNS_T_CNAME); + if (!rqa(z)) goto DIE; + if (!response_cname(z->name[0],cached,ttl)) goto DIE; + cleanup(z); + return 1; + } + log_cachedcname(d,cached); + if (!dns_domain_copy(&cname,cached)) goto DIE; + goto CNAME; + } + + if (typematch(DNS_T_NS,dtype)) { + byte_copy(key,2,DNS_T_NS); + cached = cache_get(key,dlen + 2,&cachedlen,&ttl); + if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) { + log_cachedanswer(d,DNS_T_NS); + if (!rqa(z)) goto DIE; + pos = 0; + while (pos = dns_packet_getname(cached,cachedlen,pos,&t2)) { + if (!response_rstart(d,DNS_T_NS,ttl)) goto DIE; + if (!response_addname(t2)) goto DIE; + response_rfinish(RESPONSE_ANSWER); + } + cleanup(z); + return 1; + } + } + + if (typematch(DNS_T_PTR,dtype)) { + byte_copy(key,2,DNS_T_PTR); + cached = cache_get(key,dlen + 2,&cachedlen,&ttl); + if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) { + log_cachedanswer(d,DNS_T_PTR); + if (!rqa(z)) goto DIE; + pos = 0; + while (pos = dns_packet_getname(cached,cachedlen,pos,&t2)) { + if (!response_rstart(d,DNS_T_PTR,ttl)) goto DIE; + if (!response_addname(t2)) goto DIE; + response_rfinish(RESPONSE_ANSWER); + } + cleanup(z); + return 1; + } + } + + if (typematch(DNS_T_MX,dtype)) { + byte_copy(key,2,DNS_T_MX); + cached = cache_get(key,dlen + 2,&cachedlen,&ttl); + if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) { + log_cachedanswer(d,DNS_T_MX); + if (!rqa(z)) goto DIE; + pos = 0; + while (pos = dns_packet_copy(cached,cachedlen,pos,misc,2)) { + pos = dns_packet_getname(cached,cachedlen,pos,&t2); + if (!pos) break; + if (!response_rstart(d,DNS_T_MX,ttl)) goto DIE; + if (!response_addbytes(misc,2)) goto DIE; + if (!response_addname(t2)) goto DIE; + response_rfinish(RESPONSE_ANSWER); + } + cleanup(z); + return 1; + } + } + + if (typematch(DNS_T_A,dtype)) { + byte_copy(key,2,DNS_T_A); + cached = cache_get(key,dlen + 2,&cachedlen,&ttl); + if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) { + if (z->level) { + log_cachedanswer(d,DNS_T_A); + while (cachedlen >= 4) { + for (k = 0;k < 64;k += 4) + if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) { + byte_copy(z->servers[z->level - 1] + k,4,cached); + break; + } + cached += 4; + cachedlen -= 4; + } + goto LOWERLEVEL; + } + + log_cachedanswer(d,DNS_T_A); + if (!rqa(z)) goto DIE; + while (cachedlen >= 4) { + if (!response_rstart(d,DNS_T_A,ttl)) goto DIE; + if (!response_addbytes(cached,4)) goto DIE; + response_rfinish(RESPONSE_ANSWER); + cached += 4; + cachedlen -= 4; + } + cleanup(z); + return 1; + } + } + + if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_CNAME,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype)) { + byte_copy(key,2,dtype); + cached = cache_get(key,dlen + 2,&cachedlen,&ttl); + if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) { + log_cachedanswer(d,dtype); + if (!rqa(z)) goto DIE; + while (cachedlen >= 2) { + uint16_unpack_big(cached,&datalen); + cached += 2; + cachedlen -= 2; + if (datalen > cachedlen) goto DIE; + if (!response_rstart(d,dtype,ttl)) goto DIE; + if (!response_addbytes(cached,datalen)) goto DIE; + response_rfinish(RESPONSE_ANSWER); + cached += datalen; + cachedlen -= datalen; + } + cleanup(z); + return 1; + } + } + } + + for (;;) { + if (roots(z->servers[z->level],d)) { + for (j = 0;j < QUERY_MAXNS;++j) + dns_domain_free(&z->ns[z->level][j]); + z->control[z->level] = d; + break; + } + + if (!flagforwardonly && (z->level < 2)) + if (dlen < 255) { + byte_copy(key,2,DNS_T_NS); + byte_copy(key + 2,dlen,d); + case_lowerb(key + 2,dlen); + cached = cache_get(key,dlen + 2,&cachedlen,&ttl); + if (cached && cachedlen) { + z->control[z->level] = d; + byte_zero(z->servers[z->level],64); + for (j = 0;j < QUERY_MAXNS;++j) + dns_domain_free(&z->ns[z->level][j]); + pos = 0; + j = 0; + while (pos = dns_packet_getname(cached,cachedlen,pos,&t1)) { + log_cachedns(d,t1); + if (j < QUERY_MAXNS) + if (!dns_domain_copy(&z->ns[z->level][j++],t1)) goto DIE; + } + break; + } + } + + if (!*d) goto DIE; + j = 1 + (unsigned int) (unsigned char) *d; + dlen -= j; + d += j; + } + + + HAVENS: + for (j = 0;j < QUERY_MAXNS;++j) + if (z->ns[z->level][j]) { + if (z->level + 1 < QUERY_MAXLEVEL) { + if (!dns_domain_copy(&z->name[z->level + 1],z->ns[z->level][j])) goto DIE; + dns_domain_free(&z->ns[z->level][j]); + ++z->level; + goto NEWNAME; + } + dns_domain_free(&z->ns[z->level][j]); + } + + for (j = 0;j < 64;j += 4) + if (byte_diff(z->servers[z->level] + j,4,"\0\0\0\0")) + break; + if (j == 64) goto SERVFAIL; + + dns_sortip(z->servers[z->level],64); + if (z->level) { + log_tx(z->name[z->level],DNS_T_A,z->control[z->level],z->servers[z->level],z->level); + if (dns_transmit_start(&z->dt,z->servers[z->level],flagforwardonly,z->name[z->level],DNS_T_A,z->localip) == -1) goto DIE; + } + else { + log_tx(z->name[0],z->type,z->control[0],z->servers[0],0); + if (dns_transmit_start(&z->dt,z->servers[0],flagforwardonly,z->name[0],z->type,z->localip) == -1) goto DIE; + } + return 0; + + + LOWERLEVEL: + dns_domain_free(&z->name[z->level]); + for (j = 0;j < QUERY_MAXNS;++j) + dns_domain_free(&z->ns[z->level][j]); + --z->level; + goto HAVENS; + + + HAVEPACKET: + if (++z->loop == 100) goto DIE; + buf = z->dt.packet; + len = z->dt.packetlen; + + whichserver = z->dt.servers + 4 * z->dt.curserver; + control = z->control[z->level]; + d = z->name[z->level]; + dtype = z->level ? DNS_T_A : z->type; + + pos = dns_packet_copy(buf,len,0,header,12); if (!pos) goto DIE; + pos = dns_packet_skipname(buf,len,pos); if (!pos) goto DIE; + pos += 4; + posanswers = pos; + + uint16_unpack_big(header + 6,&numanswers); + uint16_unpack_big(header + 8,&numauthority); + uint16_unpack_big(header + 10,&numglue); + + rcode = header[3] & 15; + if (rcode && (rcode != 3)) goto DIE; /* impossible; see irrelevant() */ + + flagout = 0; + flagcname = 0; + flagreferral = 0; + flagsoa = 0; + soattl = 0; + cnamettl = 0; + for (j = 0;j < numanswers;++j) { + pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + + if (dns_domain_equal(t1,d)) + if (byte_equal(header + 2,2,DNS_C_IN)) { /* should always be true */ + if (typematch(header,dtype)) + flagout = 1; + else if (typematch(header,DNS_T_CNAME)) { + if (!dns_packet_getname(buf,len,pos,&cname)) goto DIE; + flagcname = 1; + cnamettl = ttlget(header + 4); + } + } + + uint16_unpack_big(header + 8,&datalen); + pos += datalen; + } + posauthority = pos; + + for (j = 0;j < numauthority;++j) { + pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + + if (typematch(header,DNS_T_SOA)) { + flagsoa = 1; + soattl = ttlget(header + 4); + if (soattl > 3600) soattl = 3600; + } + else if (typematch(header,DNS_T_NS)) { + flagreferral = 1; + if (!dns_domain_copy(&referral,t1)) goto DIE; + } + + uint16_unpack_big(header + 8,&datalen); + pos += datalen; + } + posglue = pos; + + + if (!flagcname && !rcode && !flagout && flagreferral && !flagsoa) + if (dns_domain_equal(referral,control) || !dns_domain_suffix(referral,control)) { + log_lame(whichserver,control,referral); + byte_zero(whichserver,4); + goto HAVENS; + } + + + if (records) { alloc_free(records); records = 0; } + + k = numanswers + numauthority + numglue; + records = (unsigned int *) alloc(k * sizeof(unsigned int)); + if (!records) goto DIE; + + pos = posanswers; + for (j = 0;j < k;++j) { + records[j] = pos; + pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + uint16_unpack_big(header + 8,&datalen); + pos += datalen; + } + + i = j = k; + while (j > 1) { + if (i > 1) { --i; pos = records[i - 1]; } + else { pos = records[j - 1]; records[j - 1] = records[i - 1]; --j; } + + q = i; + while ((p = q * 2) < j) { + if (!smaller(buf,len,records[p],records[p - 1])) ++p; + records[q - 1] = records[p - 1]; q = p; + } + if (p == j) { + records[q - 1] = records[p - 1]; q = p; + } + while ((q > i) && smaller(buf,len,records[(p = q/2) - 1],pos)) { + records[q - 1] = records[p - 1]; q = p; + } + records[q - 1] = pos; + } + + i = 0; + while (i < k) { + char type[2]; + + pos = dns_packet_getname(buf,len,records[i],&t1); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + ttl = ttlget(header + 4); + + byte_copy(type,2,header); + if (byte_diff(header + 2,2,DNS_C_IN)) { ++i; continue; } + + for (j = i + 1;j < k;++j) { + pos = dns_packet_getname(buf,len,records[j],&t2); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + if (!dns_domain_equal(t1,t2)) break; + if (byte_diff(header,2,type)) break; + if (byte_diff(header + 2,2,DNS_C_IN)) break; + } + + if (!dns_domain_suffix(t1,control)) { i = j; continue; } + if (!roots_same(t1,control)) { i = j; continue; } + + if (byte_equal(type,2,DNS_T_ANY)) + ; + else if (byte_equal(type,2,DNS_T_AXFR)) + ; + else if (byte_equal(type,2,DNS_T_SOA)) { + while (i < j) { + pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE; + pos = dns_packet_getname(buf,len,pos + 10,&t2); if (!pos) goto DIE; + pos = dns_packet_getname(buf,len,pos,&t3); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,misc,20); if (!pos) goto DIE; + if (records[i] < posauthority) + log_rrsoa(whichserver,t1,t2,t3,misc,ttl); + ++i; + } + } + else if (byte_equal(type,2,DNS_T_CNAME)) { + pos = dns_packet_skipname(buf,len,records[j - 1]); if (!pos) goto DIE; + pos = dns_packet_getname(buf,len,pos + 10,&t2); if (!pos) goto DIE; + log_rrcname(whichserver,t1,t2,ttl); + cachegeneric(DNS_T_CNAME,t1,t2,dns_domain_length(t2),ttl); + } + else if (byte_equal(type,2,DNS_T_PTR)) { + save_start(); + while (i < j) { + pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE; + pos = dns_packet_getname(buf,len,pos + 10,&t2); if (!pos) goto DIE; + log_rrptr(whichserver,t1,t2,ttl); + save_data(t2,dns_domain_length(t2)); + ++i; + } + save_finish(DNS_T_PTR,t1,ttl); + } + else if (byte_equal(type,2,DNS_T_NS)) { + save_start(); + while (i < j) { + pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE; + pos = dns_packet_getname(buf,len,pos + 10,&t2); if (!pos) goto DIE; + log_rrns(whichserver,t1,t2,ttl); + save_data(t2,dns_domain_length(t2)); + ++i; + } + save_finish(DNS_T_NS,t1,ttl); + } + else if (byte_equal(type,2,DNS_T_MX)) { + save_start(); + while (i < j) { + pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos + 10,misc,2); if (!pos) goto DIE; + pos = dns_packet_getname(buf,len,pos,&t2); if (!pos) goto DIE; + log_rrmx(whichserver,t1,t2,misc,ttl); + save_data(misc,2); + save_data(t2,dns_domain_length(t2)); + ++i; + } + save_finish(DNS_T_MX,t1,ttl); + } + else if (byte_equal(type,2,DNS_T_A)) { + save_start(); + while (i < j) { + pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + if (byte_equal(header + 8,2,"\0\4")) { + pos = dns_packet_copy(buf,len,pos,header,4); if (!pos) goto DIE; + save_data(header,4); + log_rr(whichserver,t1,DNS_T_A,header,4,ttl); + } + ++i; + } + save_finish(DNS_T_A,t1,ttl); + } + else { + save_start(); + while (i < j) { + pos = dns_packet_skipname(buf,len,records[i]); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + uint16_unpack_big(header + 8,&datalen); + if (datalen > len - pos) goto DIE; + save_data(header + 8,2); + save_data(buf + pos,datalen); + log_rr(whichserver,t1,type,buf + pos,datalen,ttl); + ++i; + } + save_finish(type,t1,ttl); + } + + i = j; + } + + alloc_free(records); records = 0; + + + if (flagcname) { + ttl = cnamettl; + CNAME: + if (!z->level) { + if (z->alias[QUERY_MAXALIAS - 1]) goto DIE; + for (j = QUERY_MAXALIAS - 1;j > 0;--j) + z->alias[j] = z->alias[j - 1]; + for (j = QUERY_MAXALIAS - 1;j > 0;--j) + z->aliasttl[j] = z->aliasttl[j - 1]; + z->alias[0] = z->name[0]; + z->aliasttl[0] = ttl; + z->name[0] = 0; + } + if (!dns_domain_copy(&z->name[z->level],cname)) goto DIE; + goto NEWNAME; + } + + if (rcode == 3) { + log_nxdomain(whichserver,d,soattl); + cachegeneric(DNS_T_ANY,d,"",0,soattl); + + NXDOMAIN: + if (z->level) goto LOWERLEVEL; + if (!rqa(z)) goto DIE; + response_nxdomain(); + cleanup(z); + return 1; + } + + if (!flagout && flagsoa) + if (byte_diff(DNS_T_ANY,2,dtype)) + if (byte_diff(DNS_T_AXFR,2,dtype)) + if (byte_diff(DNS_T_CNAME,2,dtype)) { + save_start(); + save_finish(dtype,d,soattl); + log_nodata(whichserver,d,dtype,soattl); + } + + log_stats(); + + + if (flagout || flagsoa || !flagreferral) { + if (z->level) { + pos = posanswers; + for (j = 0;j < numanswers;++j) { + pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + uint16_unpack_big(header + 8,&datalen); + if (dns_domain_equal(t1,d)) + if (typematch(header,DNS_T_A)) + if (byte_equal(header + 2,2,DNS_C_IN)) /* should always be true */ + if (datalen == 4) + for (k = 0;k < 64;k += 4) + if (byte_equal(z->servers[z->level - 1] + k,4,"\0\0\0\0")) { + if (!dns_packet_copy(buf,len,pos,z->servers[z->level - 1] + k,4)) goto DIE; + break; + } + pos += datalen; + } + goto LOWERLEVEL; + } + + if (!rqa(z)) goto DIE; + + pos = posanswers; + for (j = 0;j < numanswers;++j) { + pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + ttl = ttlget(header + 4); + uint16_unpack_big(header + 8,&datalen); + if (dns_domain_equal(t1,d)) + if (byte_equal(header + 2,2,DNS_C_IN)) /* should always be true */ + if (typematch(header,dtype)) { + if (!response_rstart(t1,header,ttl)) goto DIE; + + if (typematch(header,DNS_T_NS) || typematch(header,DNS_T_CNAME) || typematch(header,DNS_T_PTR)) { + if (!dns_packet_getname(buf,len,pos,&t2)) goto DIE; + if (!response_addname(t2)) goto DIE; + } + else if (typematch(header,DNS_T_MX)) { + pos2 = dns_packet_copy(buf,len,pos,misc,2); if (!pos2) goto DIE; + if (!response_addbytes(misc,2)) goto DIE; + if (!dns_packet_getname(buf,len,pos2,&t2)) goto DIE; + if (!response_addname(t2)) goto DIE; + } + else if (typematch(header,DNS_T_SOA)) { + pos2 = dns_packet_getname(buf,len,pos,&t2); if (!pos2) goto DIE; + if (!response_addname(t2)) goto DIE; + pos2 = dns_packet_getname(buf,len,pos2,&t3); if (!pos2) goto DIE; + if (!response_addname(t3)) goto DIE; + pos2 = dns_packet_copy(buf,len,pos2,misc,20); if (!pos2) goto DIE; + if (!response_addbytes(misc,20)) goto DIE; + } + else { + if (pos + datalen > len) goto DIE; + if (!response_addbytes(buf + pos,datalen)) goto DIE; + } + + response_rfinish(RESPONSE_ANSWER); + } + + pos += datalen; + } + + cleanup(z); + return 1; + } + + + if (!dns_domain_suffix(d,referral)) goto DIE; + control = d + dns_domain_suffixpos(d,referral); + z->control[z->level] = control; + byte_zero(z->servers[z->level],64); + for (j = 0;j < QUERY_MAXNS;++j) + dns_domain_free(&z->ns[z->level][j]); + k = 0; + + pos = posauthority; + for (j = 0;j < numauthority;++j) { + pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE; + pos = dns_packet_copy(buf,len,pos,header,10); if (!pos) goto DIE; + uint16_unpack_big(header + 8,&datalen); + if (dns_domain_equal(referral,t1)) /* should always be true */ + if (typematch(header,DNS_T_NS)) /* should always be true */ + if (byte_equal(header + 2,2,DNS_C_IN)) /* should always be true */ + if (k < QUERY_MAXNS) + if (!dns_packet_getname(buf,len,pos,&z->ns[z->level][k++])) goto DIE; + pos += datalen; + } + + goto HAVENS; + + + SERVFAIL: + if (z->level) goto LOWERLEVEL; + if (!rqa(z)) goto DIE; + response_servfail(); + cleanup(z); + return 1; + + + DIE: + cleanup(z); + if (records) { alloc_free(records); records = 0; } + return -1; +} + +int query_start(struct query *z,char *dn,char type[2],char class[2],char localip[4]) +{ + if (byte_equal(type,2,DNS_T_AXFR)) { errno = error_perm; return -1; } + + cleanup(z); + z->level = 0; + z->loop = 0; + + if (!dns_domain_copy(&z->name[0],dn)) return -1; + byte_copy(z->type,2,type); + byte_copy(z->class,2,class); + byte_copy(z->localip,4,localip); + + return doit(z,0); +} + +int query_get(struct query *z,iopause_fd *x,struct taia *stamp) +{ + switch(dns_transmit_get(&z->dt,x,stamp)) { + case 1: + return doit(z,1); + case -1: + return doit(z,-1); + } + return 0; +} + +void query_io(struct query *z,iopause_fd *x,struct taia *deadline) +{ + dns_transmit_io(&z->dt,x,deadline); +} diff --git a/query.h b/query.h new file mode 100644 index 0000000..eff68b2 --- /dev/null +++ b/query.h @@ -0,0 +1,32 @@ +#ifndef QUERY_H +#define QUERY_H + +#include "dns.h" +#include "uint32.h" + +#define QUERY_MAXLEVEL 5 +#define QUERY_MAXALIAS 16 +#define QUERY_MAXNS 16 + +struct query { + unsigned int loop; + unsigned int level; + char *name[QUERY_MAXLEVEL]; + char *control[QUERY_MAXLEVEL]; /* pointing inside name */ + char *ns[QUERY_MAXLEVEL][QUERY_MAXNS]; + char servers[QUERY_MAXLEVEL][64]; + char *alias[QUERY_MAXALIAS]; + uint32 aliasttl[QUERY_MAXALIAS]; + char localip[4]; + char type[2]; + char class[2]; + struct dns_transmit dt; +} ; + +extern int query_start(struct query *,char *,char *,char *,char *); +extern void query_io(struct query *,iopause_fd *,struct taia *); +extern int query_get(struct query *,iopause_fd *,struct taia *); + +extern void query_forwardonly(void); + +#endif diff --git a/random-ip.c b/random-ip.c new file mode 100644 index 0000000..bfd516c --- /dev/null +++ b/random-ip.c @@ -0,0 +1,80 @@ +#include "buffer.h" +#include "exit.h" +#include "fmt.h" +#include "scan.h" +#include "dns.h" + +char ip[4]; +int ipfixed = 0; +unsigned long loops = 10000; +unsigned char tab[256]; + +char strnum[FMT_ULONG]; + +char seed[128]; + +int main(int argc,char **argv) +{ + unsigned long u; + int i; + int j; + unsigned char c; + + dns_random_init(seed); + + for (i = 0;i < 256;++i) tab[i] = i; + for (j = 256;j > 0;--j) { + i = dns_random(j); + c = tab[j - 1]; + tab[j - 1] = tab[i]; + tab[i] = c; + } + + if (*argv) ++argv; + if (*argv) scan_ulong(*argv++,&loops); + if (*argv) { scan_ulong(*argv++,&u); ip[0] = u; ipfixed = 1; } + if (*argv) { scan_ulong(*argv++,&u); ip[1] = u; ipfixed = 2; } + if (*argv) { scan_ulong(*argv++,&u); ip[2] = u; ipfixed = 3; } + if (*argv) { scan_ulong(*argv++,&u); ip[3] = u; ipfixed = 4; } + + if (ipfixed >= 1) if (loops > 16777216) loops = 16777216; + if (ipfixed >= 2) if (loops > 65536) loops = 65536; + if (ipfixed >= 3) if (loops > 256) loops = 256; + if (ipfixed >= 4) if (loops > 1) loops = 1; + + while (loops) { + --loops; + u = loops; + for (i = ipfixed;i < 4;++i) { ip[i] = u & 255; u >>= 8; } + if (ipfixed == 3) { + c = ip[3]; + ip[3] = tab[c]; + } + else if (ipfixed < 3) { + c = 0; + for (j = 0;j < 100;++j) { + for (i = ipfixed;i < 4;++i) { + c ^= (unsigned char) ip[i]; + c = tab[c]; + ip[i] = c; + } + } + } + + u = (unsigned char) ip[0]; + buffer_put(buffer_1,strnum,fmt_ulong(strnum,u)); + buffer_puts(buffer_1,"."); + u = (unsigned char) ip[1]; + buffer_put(buffer_1,strnum,fmt_ulong(strnum,u)); + buffer_puts(buffer_1,"."); + u = (unsigned char) ip[2]; + buffer_put(buffer_1,strnum,fmt_ulong(strnum,u)); + buffer_puts(buffer_1,"."); + u = (unsigned char) ip[3]; + buffer_put(buffer_1,strnum,fmt_ulong(strnum,u)); + buffer_puts(buffer_1,"\n"); + } + + buffer_flush(buffer_1); + _exit(0); +} diff --git a/rbldns-conf.c b/rbldns-conf.c new file mode 100644 index 0000000..79d446f --- /dev/null +++ b/rbldns-conf.c @@ -0,0 +1,71 @@ +#include +#include +#include "strerr.h" +#include "exit.h" +#include "auto_home.h" +#include "generic-conf.h" + +#define FATAL "rbldns-conf: fatal: " + +void usage(void) +{ + strerr_die1x(100,"rbldns-conf: usage: rbldns-conf acct logacct /rbldns myip base"); +} + +char *dir; +char *user; +char *loguser; +struct passwd *pw; +char *myip; +char *base; + +int main(int argc,char **argv) +{ + user = argv[1]; + if (!user) usage(); + loguser = argv[2]; + if (!loguser) usage(); + dir = argv[3]; + if (!dir) usage(); + if (dir[0] != '/') usage(); + myip = argv[4]; + if (!myip) usage(); + base = argv[5]; + if (!base) usage(); + + pw = getpwnam(loguser); + if (!pw) + strerr_die3x(111,FATAL,"unknown account ",loguser); + + init(dir,FATAL); + makelog(loguser,pw->pw_uid,pw->pw_gid); + + makedir("env"); + perm(02755); + start("env/ROOT"); outs(dir); outs("/root\n"); finish(); + perm(0644); + start("env/IP"); outs(myip); outs("\n"); finish(); + perm(0644); + start("env/BASE"); outs(base); outs("\n"); finish(); + perm(0644); + + start("run"); + outs("#!/bin/sh\nexec 2>&1\nexec envuidgid "); outs(user); + outs(" envdir ./env softlimit -d250000 "); + outs(auto_home); outs("/bin/rbldns\n"); + finish(); + perm(0755); + + makedir("root"); + perm(02755); + start("root/data"); + finish(); + perm(0644); + start("root/Makefile"); + outs("data.cdb: data\n"); + outs("\t"); outs(auto_home); outs("/bin/rbldns-data\n"); + finish(); + perm(0644); + + _exit(0); +} diff --git a/rbldns-data.c b/rbldns-data.c new file mode 100644 index 0000000..ed495db --- /dev/null +++ b/rbldns-data.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include "buffer.h" +#include "exit.h" +#include "cdb_make.h" +#include "open.h" +#include "stralloc.h" +#include "getln.h" +#include "strerr.h" +#include "byte.h" +#include "scan.h" +#include "fmt.h" +#include "ip4.h" + +#define FATAL "rbldns-data: fatal: " + +void nomem(void) +{ + strerr_die2x(111,FATAL,"out of memory"); +} + +int fd; +buffer b; +char bspace[1024]; + +int fdcdb; +struct cdb_make cdb; +static stralloc tmp; + +static stralloc line; +int match = 1; +unsigned long linenum = 0; + +char strnum[FMT_ULONG]; + +void syntaxerror(const char *why) +{ + strnum[fmt_ulong(strnum,linenum)] = 0; + strerr_die4x(111,FATAL,"unable to parse data line ",strnum,why); +} +void die_datatmp(void) +{ + strerr_die2sys(111,FATAL,"unable to create data.tmp: "); +} + +int main() +{ + char ip[4]; + unsigned long u; + unsigned int j; + unsigned int k; + char ch; + + umask(022); + + fd = open_read("data"); + if (fd == -1) strerr_die2sys(111,FATAL,"unable to open data: "); + buffer_init(&b,buffer_unixread,fd,bspace,sizeof bspace); + + fdcdb = open_trunc("data.tmp"); + if (fdcdb == -1) die_datatmp(); + if (cdb_make_start(&cdb,fdcdb) == -1) die_datatmp(); + + while (match) { + ++linenum; + if (getln(&b,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read line: "); + + while (line.len) { + ch = line.s[line.len - 1]; + if ((ch != ' ') && (ch != '\t') && (ch != '\n')) break; + --line.len; + } + if (!line.len) continue; + + switch(line.s[0]) { + default: + syntaxerror(": unrecognized leading character"); + case '#': + break; + case ':': + j = byte_chr(line.s + 1,line.len - 1,':'); + if (j >= line.len - 1) syntaxerror(": missing colon"); + if (ip4_scan(line.s + 1,ip) != j) syntaxerror(": malformed IP address"); + if (!stralloc_copyb(&tmp,ip,4)) nomem(); + if (!stralloc_catb(&tmp,line.s + j + 2,line.len - j - 2)) nomem(); + if (cdb_make_add(&cdb,"",0,tmp.s,tmp.len) == -1) + die_datatmp(); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (!stralloc_0(&line)) nomem(); + j = 0; + if (!stralloc_copys(&tmp,"")) nomem(); + for (;;) { + k = scan_ulong(line.s + j,&u); + if (!k) break; + ch = u; + if (!stralloc_catb(&tmp,&ch,1)) nomem(); + j += k; + if (line.s[j] != '.') break; + ++j; + } + if (!stralloc_catb(&tmp,"\0\0\0\0",4)) nomem(); + tmp.len = 4; + if (line.s[j] == '/') + scan_ulong(line.s + j + 1,&u); + else + u = 32; + if (u > 32) u = 32; + ch = u; + if (!stralloc_catb(&tmp,&ch,1)) nomem(); + if (cdb_make_add(&cdb,tmp.s,tmp.len,"",0) == -1) + die_datatmp(); + break; + } + } + + if (cdb_make_finish(&cdb) == -1) die_datatmp(); + if (fsync(fdcdb) == -1) die_datatmp(); + if (close(fdcdb) == -1) die_datatmp(); /* NFS stupidity */ + if (rename("data.tmp","data.cdb") == -1) + strerr_die2sys(111,FATAL,"unable to move data.tmp to data.cdb: "); + + _exit(0); +} diff --git a/rbldns.c b/rbldns.c new file mode 100644 index 0000000..2c13c27 --- /dev/null +++ b/rbldns.c @@ -0,0 +1,116 @@ +#include +#include "str.h" +#include "byte.h" +#include "ip4.h" +#include "open.h" +#include "env.h" +#include "cdb.h" +#include "dns.h" +#include "dd.h" +#include "strerr.h" +#include "response.h" + +static char *base; + +static struct cdb c; +static char key[5]; +static char data[100 + IP4_FMT]; + +static int doit(char *q,char qtype[2]) +{ + int flaga; + int flagtxt; + char ch; + char reverseip[4]; + char ip[4]; + uint32 ipnum; + int r; + uint32 dlen; + int i; + + flaga = byte_equal(qtype,2,DNS_T_A); + flagtxt = byte_equal(qtype,2,DNS_T_TXT); + if (byte_equal(qtype,2,DNS_T_ANY)) flaga = flagtxt = 1; + if (!flaga && !flagtxt) goto REFUSE; + + if (dd(q,base,reverseip) != 4) goto REFUSE; + uint32_unpack(reverseip,&ipnum); + uint32_pack_big(ip,ipnum); + + for (i = 0;i <= 24;++i) { + ipnum >>= i; + ipnum <<= i; + uint32_pack_big(key,ipnum); + key[4] = 32 - i; + r = cdb_find(&c,key,5); + if (r == -1) return 0; + if (r) break; + } + if (!r) { response_nxdomain(); return 1; } + + r = cdb_find(&c,"",0); + if (r == -1) return 0; + if (r && ((dlen = cdb_datalen(&c)) >= 4)) { + if (dlen > 100) dlen = 100; + if (cdb_read(&c,data,dlen,cdb_datapos(&c)) == -1) return 0; + } + else { + dlen = 12; + byte_copy(data,dlen,"\177\0\0\2Listed $"); + } + + if ((dlen >= 5) && (data[dlen - 1] == '$')) { + --dlen; + dlen += ip4_fmt(data + dlen,ip); + } + + if (flaga) { + if (!response_rstart(q,DNS_T_A,2048)) return 0; + if (!response_addbytes(data,4)) return 0; + response_rfinish(RESPONSE_ANSWER); + } + if (flagtxt) { + if (!response_rstart(q,DNS_T_TXT,2048)) return 0; + ch = dlen - 4; + if (!response_addbytes(&ch,1)) return 0; + if (!response_addbytes(data + 4,dlen - 4)) return 0; + response_rfinish(RESPONSE_ANSWER); + } + + return 1; + + + REFUSE: + response[2] &= ~4; + response[3] &= ~15; + response[3] |= 5; + return 1; +} + +int respond(char *q,char qtype[2],char ip[4]) +{ + int fd; + int result; + + fd = open_read("data.cdb"); + if (fd == -1) return 0; + cdb_init(&c,fd); + result = doit(q,qtype); + cdb_free(&c); + close(fd); + return result; +} + +const char *fatal = "rbldns: fatal: "; +const char *starting = "starting rbldns\n"; + +void initialize(void) +{ + char *x; + + x = env_get("BASE"); + if (!x) + strerr_die2x(111,fatal,"$BASE not set"); + if (!dns_domain_fromdot(&base,x,str_len(x))) + strerr_die2x(111,fatal,"unable to parse $BASE"); +} diff --git a/readclose.c b/readclose.c new file mode 100644 index 0000000..b9368cf --- /dev/null +++ b/readclose.c @@ -0,0 +1,21 @@ +#include +#include "error.h" +#include "readclose.h" + +int readclose_append(int fd,stralloc *sa,unsigned int bufsize) +{ + int r; + for (;;) { + if (!stralloc_readyplus(sa,bufsize)) { close(fd); return -1; } + r = read(fd,sa->s + sa->len,bufsize); + if (r == -1) if (errno == error_intr) continue; + if (r <= 0) { close(fd); return r; } + sa->len += r; + } +} + +int readclose(int fd,stralloc *sa,unsigned int bufsize) +{ + if (!stralloc_copys(sa,"")) { close(fd); return -1; } + return readclose_append(fd,sa,bufsize); +} diff --git a/readclose.h b/readclose.h new file mode 100644 index 0000000..49afd6c --- /dev/null +++ b/readclose.h @@ -0,0 +1,9 @@ +#ifndef READCLOSE_H +#define READCLOSE_H + +#include "stralloc.h" + +extern int readclose_append(int,stralloc *,unsigned int); +extern int readclose(int,stralloc *,unsigned int); + +#endif diff --git a/response.c b/response.c new file mode 100644 index 0000000..ba90c89 --- /dev/null +++ b/response.c @@ -0,0 +1,121 @@ +#include "dns.h" +#include "byte.h" +#include "uint16.h" +#include "response.h" + +char response[65535]; +unsigned int response_len = 0; /* <= 65535 */ +static unsigned int tctarget; + +#define NAMES 100 +static char name[NAMES][128]; +static unsigned int name_ptr[NAMES]; /* each < 16384 */ +static unsigned int name_num; + +int response_addbytes(const char *buf,unsigned int len) +{ + if (len > 65535 - response_len) return 0; + byte_copy(response + response_len,len,buf); + response_len += len; + return 1; +} + +int response_addname(const char *d) +{ + unsigned int dlen; + unsigned int i; + char buf[2]; + + dlen = dns_domain_length(d); + + while (*d) { + for (i = 0;i < name_num;++i) + if (dns_domain_equal(d,name[i])) { + uint16_pack_big(buf,49152 + name_ptr[i]); + return response_addbytes(buf,2); + } + if (dlen <= 128) + if (name_num < NAMES) { + byte_copy(name[name_num],dlen,d); + name_ptr[name_num] = response_len; + ++name_num; + } + i = (unsigned char) *d; + ++i; + if (!response_addbytes(d,i)) return 0; + d += i; + dlen -= i; + } + return response_addbytes(d,1); +} + +int response_query(const char *q,const char qtype[2],const char qclass[2]) +{ + response_len = 0; + name_num = 0; + if (!response_addbytes("\0\0\201\200\0\1\0\0\0\0\0\0",12)) return 0; + if (!response_addname(q)) return 0; + if (!response_addbytes(qtype,2)) return 0; + if (!response_addbytes(qclass,2)) return 0; + tctarget = response_len; + return 1; +} + +static unsigned int dpos; + +static int flaghidettl = 0; + +void response_hidettl(void) +{ + flaghidettl = 1; +} + +int response_rstart(const char *d,const char type[2],uint32 ttl) +{ + char ttlstr[4]; + if (!response_addname(d)) return 0; + if (!response_addbytes(type,2)) return 0; + if (!response_addbytes(DNS_C_IN,2)) return 0; + if (flaghidettl) ttl = 0; + uint32_pack_big(ttlstr,ttl); + if (!response_addbytes(ttlstr,4)) return 0; + if (!response_addbytes("\0\0",2)) return 0; + dpos = response_len; + return 1; +} + +void response_rfinish(int x) +{ + uint16_pack_big(response + dpos - 2,response_len - dpos); + if (!++response[x + 1]) ++response[x]; +} + +int response_cname(const char *c,const char *d,uint32 ttl) +{ + if (!response_rstart(c,DNS_T_CNAME,ttl)) return 0; + if (!response_addname(d)) return 0; + response_rfinish(RESPONSE_ANSWER); + return 1; +} + +void response_nxdomain(void) +{ + response[3] |= 3; + response[2] |= 4; +} + +void response_servfail(void) +{ + response[3] |= 2; +} + +void response_id(const char id[2]) +{ + byte_copy(response,2,id); +} + +void response_tc(void) +{ + response[2] |= 2; + response_len = tctarget; +} diff --git a/response.h b/response.h new file mode 100644 index 0000000..206b1d4 --- /dev/null +++ b/response.h @@ -0,0 +1,27 @@ +#ifndef RESPONSE_H +#define RESPONSE_H + +#include "uint32.h" + +extern char response[]; +extern unsigned int response_len; + +extern int response_query(const char *,const char *,const char *); +extern void response_nxdomain(void); +extern void response_servfail(void); +extern void response_id(const char *); +extern void response_tc(void); + +extern int response_addbytes(const char *,unsigned int); +extern int response_addname(const char *); +extern void response_hidettl(void); +extern int response_rstart(const char *,const char *,uint32); +extern void response_rfinish(int); + +#define RESPONSE_ANSWER 6 +#define RESPONSE_AUTHORITY 8 +#define RESPONSE_ADDITIONAL 10 + +extern int response_cname(const char *,const char *,uint32); + +#endif diff --git a/roots.c b/roots.c new file mode 100644 index 0000000..3cfe959 --- /dev/null +++ b/roots.c @@ -0,0 +1,127 @@ +#include +#include "open.h" +#include "error.h" +#include "str.h" +#include "byte.h" +#include "error.h" +#include "direntry.h" +#include "ip4.h" +#include "dns.h" +#include "openreadclose.h" +#include "roots.h" + +static stralloc data; + +static int roots_find(char *q) +{ + int i; + int j; + + i = 0; + while (i < data.len) { + j = dns_domain_length(data.s + i); + if (dns_domain_equal(data.s + i,q)) return i + j; + i += j; + i += 64; + } + return -1; +} + +static int roots_search(char *q) +{ + int r; + + for (;;) { + r = roots_find(q); + if (r >= 0) return r; + if (!*q) return -1; /* user misconfiguration */ + q += *q; + q += 1; + } +} + +int roots(char servers[64],char *q) +{ + int r; + r = roots_find(q); + if (r == -1) return 0; + byte_copy(servers,64,data.s + r); + return 1; +} + +int roots_same(char *q,char *q2) +{ + return roots_search(q) == roots_search(q2); +} + +static int init2(DIR *dir) +{ + direntry *d; + const char *fqdn; + static char *q; + static stralloc text; + char servers[64]; + int serverslen; + int i; + int j; + + for (;;) { + errno = 0; + d = readdir(dir); + if (!d) { + if (errno) return 0; + return 1; + } + + if (d->d_name[0] != '.') { + if (openreadclose(d->d_name,&text,32) != 1) return 0; + if (!stralloc_append(&text,"\n")) return 0; + + fqdn = d->d_name; + if (str_equal(fqdn,"@")) fqdn = "."; + if (!dns_domain_fromdot(&q,fqdn,str_len(fqdn))) return 0; + + serverslen = 0; + j = 0; + for (i = 0;i < text.len;++i) + if (text.s[i] == '\n') { + if (serverslen <= 60) + if (ip4_scan(text.s + j,servers + serverslen)) + serverslen += 4; + j = i + 1; + } + byte_zero(servers + serverslen,64 - serverslen); + + if (!stralloc_catb(&data,q,dns_domain_length(q))) return 0; + if (!stralloc_catb(&data,servers,64)) return 0; + } + } +} + +static int init1(void) +{ + DIR *dir; + int r; + + if (chdir("servers") == -1) return 0; + dir = opendir("."); + if (!dir) return 0; + r = init2(dir); + closedir(dir); + return r; +} + +int roots_init(void) +{ + int fddir; + int r; + + if (!stralloc_copys(&data,"")) return 0; + + fddir = open_read("."); + if (fddir == -1) return 0; + r = init1(); + if (fchdir(fddir) == -1) r = 0; + close(fddir); + return r; +} diff --git a/roots.h b/roots.h new file mode 100644 index 0000000..5f89142 --- /dev/null +++ b/roots.h @@ -0,0 +1,8 @@ +#ifndef ROOTS_H +#define ROOTS_H + +extern int roots(char *,char *); +extern int roots_same(char *,char *); +extern int roots_init(void); + +#endif diff --git a/rts.exp b/rts.exp new file mode 100644 index 0000000..fd40964 --- /dev/null +++ b/rts.exp @@ -0,0 +1,1072 @@ +--- dnscache-conf works +--- tinydns-conf works +--- pickdns-conf works +--- walldns-conf works +--- rbldns-conf works +--- axfrdns-conf works +--- cache handles simple example + + + + + +un + + + + +un +deux + + + +un +deux +trois + + +un +deux +trois +quatre + +un +deux +trois +quatre +cinq +een +deux +trois +quatre +cinq +een +twee +trois +quatre +cinq +een +twee +drie +quatre +cinq +een +twee +drie +vier +cinq +een +twee +drie +vier +vijf +0 +--- cache handles overwriting + + + + + +un + + + + +een + + + + +een +deux + + + +een +twee + + + +een +twee +trois + + +een +twee +drie + + + +twee +drie +quatre + + +twee +drie +vier + + + +drie +vier +cinq + + +drie +vier +vijf +0 +--- cache handles long chains +1 +2 +3 +4 +5 +6 +7 +8 +9 +0 +--- dnsip finds IP address of network-surveys.cr.yp.to +131.193.178.100 +0 +--- dnsip does not find nonexistent.cr.yp.to + +0 +--- dnsip rejects overly long domain names +dnsip: fatal: unable to find IP address for x.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789: protocol error +111 +--- dnsip handles IP address on input +1.2.3.4 +127.0.0.1 +10.43.166.133 +10.43.166.133 +0 +--- dnsip allows 0 to be omitted +127.0.0.1 +0 +--- dnsip handles multiple IP addresses on input +1.2.3.4 5.6.7.8 9.10.11.12 13.14.15.16 +0 +--- dnsipq handles simple examples +1.2.3.4 1.2.3.4 +localhost 127.0.0.1 +localhost 127.0.0.1 +5.6.7.8 5.6.7.8 +network-surveys.cr.yp.to 131.193.178.100 +nonexistent.whatever.cr.yp.to +0 +--- dnsmx finds MX record for network-surveys.cr.yp.to +0 a.mx.network-surveys.cr.yp.to +0 +--- dnsmx manufactures MX record for nonexistent.cr.yp.to +0 nonexistent.cr.yp.to +0 +--- dnsmx rejects overly long domain names +dnsmx: fatal: unable to find MX records for 0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789: protocol error +111 +--- dnstxt finds TXT record for leap.yp.to +8222222206660602022066620620. +0 +--- dnstxt does not find nonexistent.cr.yp.to + +0 +--- dnstxt rejects overly long domain names +dnstxt: fatal: unable to find TXT records for 0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789: protocol error +111 +--- dnsname finds host name of 131.193.178.100 +network-surveys.cr.yp.to +0 +--- dnsname does not find 127.5.6.7 + +0 +--- dnsname rejects misformatted IP addresses +dnsname: fatal: unable to parse IP address 1.2.3 +111 +--- dnsfilter finds some host names +131.193.178.100+one=network-surveys.cr.yp.to two three +127.5.6.7+one two three +10+one two three +0 +--- tinydns-data complains about unrecognized initial characters +tinydns-data: fatal: unable to parse data line 3: unrecognized leading character +111 +--- tinydns-data complains if it cannot create data.tmp +tinydns-data: fatal: unable to create data.tmp: symbolic link loop +111 +--- tinydns-data handles simple example +0 +--- tinydns-data produces A records +1 wormhole.movie.edu: +117 bytes, 1+2+2+1 records, response, authoritative, noerror +additional: a.ns.movie.edu 259200 A 192.249.249.3 +answer: wormhole.movie.edu 86400 A 192.249.249.1 +answer: wormhole.movie.edu 86400 A 192.253.253.1 +authority: movie.edu 259200 NS a.ns.movie.edu +authority: movie.edu 259200 NS wormhole.movie.edu +query: 1 wormhole.movie.edu +0 +--- tinydns-data produces NS records +2 movie.edu: +117 bytes, 1+2+0+3 records, response, authoritative, noerror +query: 2 movie.edu +answer: movie.edu 259200 NS a.ns.movie.edu +answer: movie.edu 259200 NS wormhole.movie.edu +additional: a.ns.movie.edu 259200 A 192.249.249.3 +additional: wormhole.movie.edu 86400 A 192.249.249.1 +additional: wormhole.movie.edu 86400 A 192.253.253.1 +0 +--- tinydns-data produces SOA records +6 movie.edu: +164 bytes, 1+1+2+3 records, response, authoritative, noerror +query: 6 movie.edu +answer: movie.edu 2560 SOA a.ns.movie.edu hostmaster.movie.edu 987654321 16384 2048 1048576 2560 +authority: movie.edu 259200 NS a.ns.movie.edu +authority: movie.edu 259200 NS wormhole.movie.edu +additional: a.ns.movie.edu 259200 A 192.249.249.3 +additional: wormhole.movie.edu 86400 A 192.249.249.1 +additional: wormhole.movie.edu 86400 A 192.253.253.1 +0 +--- tinydns-data produces PTR records +12 1.253.253.192.in-addr.arpa: +175 bytes, 1+1+3+3 records, response, authoritative, noerror +query: 12 1.253.253.192.in-addr.arpa +answer: 1.253.253.192.in-addr.arpa 86400 PTR wormhole.movie.edu +authority: 253.253.192.in-addr.arpa 259200 NS a.ns.253.253.192.in-addr.arpa +authority: 253.253.192.in-addr.arpa 259200 NS b.ns.253.253.192.in-addr.arpa +authority: 253.253.192.in-addr.arpa 259200 NS c.ns.253.253.192.in-addr.arpa +additional: a.ns.253.253.192.in-addr.arpa 259200 A 192.249.249.3 +additional: b.ns.253.253.192.in-addr.arpa 259200 A 192.249.249.1 +additional: c.ns.253.253.192.in-addr.arpa 259200 A 192.253.253.1 +0 +--- tinydns-data produces MX records +15 movie.edu: +154 bytes, 1+1+2+4 records, response, authoritative, noerror +query: 15 movie.edu +answer: movie.edu 86400 MX 0 a.mx.movie.edu +authority: movie.edu 259200 NS a.ns.movie.edu +authority: movie.edu 259200 NS wormhole.movie.edu +additional: a.mx.movie.edu 86400 A 192.249.249.1 +additional: a.ns.movie.edu 259200 A 192.249.249.3 +additional: wormhole.movie.edu 86400 A 192.249.249.1 +additional: wormhole.movie.edu 86400 A 192.253.253.1 +0 +--- tinydns-data produces TXT records +16 movie.edu: +146 bytes, 1+1+2+3 records, response, authoritative, noerror +query: 16 movie.edu +answer: movie.edu 86400 16 \020Movie\040University +authority: movie.edu 259200 NS a.ns.movie.edu +authority: movie.edu 259200 NS wormhole.movie.edu +additional: a.ns.movie.edu 259200 A 192.249.249.3 +additional: wormhole.movie.edu 86400 A 192.249.249.1 +additional: wormhole.movie.edu 86400 A 192.253.253.1 +0 +--- tinydns-data produces AXFR responses +252 movie.edu: +27 bytes, 1+0+0+0 records, response, authoritative, notimp +query: 252 movie.edu +0 +--- tinydns-data produces ANY responses +255 movie.edu: +293 bytes, 1+9+0+4 records, response, authoritative, noerror +query: 255 movie.edu +answer: movie.edu 2560 SOA a.ns.movie.edu hostmaster.movie.edu 987654321 16384 2048 1048576 2560 +answer: movie.edu 259200 NS a.ns.movie.edu +answer: movie.edu 259200 NS wormhole.movie.edu +answer: movie.edu 86400 MX 0 a.mx.movie.edu +answer: movie.edu 86400 16 \020Movie\040University +answer: movie.edu 86400 12345 One +answer: movie.edu 86400 12345 Two +answer: movie.edu 86400 12346 Three +answer: movie.edu 86400 12346 Four +additional: a.ns.movie.edu 259200 A 192.249.249.3 +additional: wormhole.movie.edu 86400 A 192.249.249.1 +additional: wormhole.movie.edu 86400 A 192.253.253.1 +additional: a.mx.movie.edu 86400 A 192.249.249.1 +0 +--- tinydns-data produces records of any type +12345 movie.edu: +147 bytes, 1+2+2+3 records, response, authoritative, noerror +query: 12345 movie.edu +answer: movie.edu 86400 12345 One +answer: movie.edu 86400 12345 Two +authority: movie.edu 259200 NS a.ns.movie.edu +authority: movie.edu 259200 NS wormhole.movie.edu +additional: a.ns.movie.edu 259200 A 192.249.249.3 +additional: wormhole.movie.edu 86400 A 192.249.249.1 +additional: wormhole.movie.edu 86400 A 192.253.253.1 +0 +12346 movie.edu: +150 bytes, 1+2+2+3 records, response, authoritative, noerror +query: 12346 movie.edu +answer: movie.edu 86400 12346 Three +answer: movie.edu 86400 12346 Four +authority: movie.edu 259200 NS a.ns.movie.edu +authority: movie.edu 259200 NS wormhole.movie.edu +additional: a.ns.movie.edu 259200 A 192.249.249.3 +additional: wormhole.movie.edu 86400 A 192.249.249.1 +additional: wormhole.movie.edu 86400 A 192.253.253.1 +0 +--- tinydns-data produces NODATA responses +54321 movie.edu: +79 bytes, 1+0+1+0 records, response, authoritative, noerror +query: 54321 movie.edu +authority: movie.edu 2560 SOA a.ns.movie.edu hostmaster.movie.edu 987654321 16384 2048 1048576 2560 +0 +--- tinydns-data produces NXDOMAIN responses +1 this.does.not.exist.movie.edu: +99 bytes, 1+0+1+0 records, response, authoritative, nxdomain +query: 1 this.does.not.exist.movie.edu +authority: movie.edu 2560 SOA a.ns.movie.edu hostmaster.movie.edu 987654321 16384 2048 1048576 2560 +0 +--- tinydns-data produces NXDOMAIN responses for suffixes +1 ns.movie.edu: +79 bytes, 1+0+1+0 records, response, authoritative, nxdomain +query: 1 ns.movie.edu +authority: movie.edu 2560 SOA a.ns.movie.edu hostmaster.movie.edu 987654321 16384 2048 1048576 2560 +0 +--- tinydns-data produces NXDOMAIN ANY responses for suffixes +255 ns.movie.edu: +79 bytes, 1+0+1+0 records, response, authoritative, nxdomain +query: 255 ns.movie.edu +authority: movie.edu 2560 SOA a.ns.movie.edu hostmaster.movie.edu 987654321 16384 2048 1048576 2560 +0 +--- tinydns-data does not produce responses outside its bailiwick +1 edu: +0 +--- tinydns-data does not include TXT in additional sections +1 blah.movie.edu: +62 bytes, 1+1+1+0 records, response, authoritative, noerror +query: 1 blah.movie.edu +answer: blah.movie.edu 259200 A 1.2.3.4 +authority: blah.movie.edu 259200 NS blah.movie.edu +0 +--- tinydns-data handles another example +0 +--- tinydns-data uses serial 1 for mtime 0 +255 test: +152 bytes, 1+3+0+3 records, response, authoritative, noerror +query: 255 test +answer: test 2560 SOA a.ns.test hostmaster.test 1 16384 2048 1048576 2560 +answer: test 259200 NS a.ns.test +answer: test 259200 NS b.ns.test +additional: a.ns.test 259200 A 10.2.3.4 +additional: b.ns.test 259200 A 10.2.3.6 +additional: b.ns.test 259200 A 10.2.3.5 +0 +--- tinydns-data does not split size-127 TXT records +16 127.test: +249 bytes, 1+1+2+3 records, response, authoritative, noerror +query: 16 127.test +answer: 127.test 86400 16 \1770123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456 +authority: test 259200 NS a.ns.test +authority: test 259200 NS b.ns.test +additional: a.ns.test 259200 A 10.2.3.4 +additional: b.ns.test 259200 A 10.2.3.6 +additional: b.ns.test 259200 A 10.2.3.5 +0 +--- tinydns-data splits size-128 TXT records +16 128.test: +251 bytes, 1+1+2+3 records, response, authoritative, noerror +query: 16 128.test +answer: 128.test 86400 16 \1770123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\0017 +authority: test 259200 NS a.ns.test +authority: test 259200 NS b.ns.test +additional: a.ns.test 259200 A 10.2.3.4 +additional: b.ns.test 259200 A 10.2.3.6 +additional: b.ns.test 259200 A 10.2.3.5 +0 +--- tinydns-data splits size-254 TXT records +16 254.test: +377 bytes, 1+1+2+3 records, response, authoritative, noerror +query: 16 254.test +answer: 254.test 86400 16 \1770123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\1777890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123 +authority: test 259200 NS a.ns.test +authority: test 259200 NS b.ns.test +additional: a.ns.test 259200 A 10.2.3.4 +additional: b.ns.test 259200 A 10.2.3.6 +additional: b.ns.test 259200 A 10.2.3.5 +0 +--- tinydns-data doubly splits size-255 TXT records +16 255.test: +379 bytes, 1+1+2+3 records, response, authoritative, noerror +query: 16 255.test +answer: 255.test 86400 16 \1770123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\1777890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123\0014 +authority: test 259200 NS a.ns.test +authority: test 259200 NS b.ns.test +additional: a.ns.test 259200 A 10.2.3.4 +additional: b.ns.test 259200 A 10.2.3.6 +additional: b.ns.test 259200 A 10.2.3.5 +0 +--- tinydns-data excludes the additional section if necessary +16 387.test: +512 bytes, 1+1+2+3 records, response, authoritative, noerror +query: 16 387.test +answer: 387.test 86400 16 \1770123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\1777890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123\1774567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\006123456 +authority: test 259200 NS a.ns.test +authority: test 259200 NS b.ns.test +additional: a.ns.test 259200 A 10.2.3.4 +additional: b.ns.test 259200 A 10.2.3.6 +additional: b.ns.test 259200 A 10.2.3.5 +0 +16 388.test: +465 bytes, 1+1+2+0 records, response, authoritative, noerror +query: 16 388.test +answer: 388.test 86400 16 \1770123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\1777890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123\1774567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\0071234567 +authority: test 259200 NS a.ns.test +authority: test 259200 NS b.ns.test +0 +--- tinydns-data excludes the authority section if necessary +16 435.test: +512 bytes, 1+1+2+0 records, response, authoritative, noerror +query: 16 435.test +answer: 435.test 86400 16 \1770123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\1777890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123\17745678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678906123456789012345678901234567890123456789012345678901234 +authority: test 259200 NS a.ns.test +authority: test 259200 NS b.ns.test +0 +16 436.test: +478 bytes, 1+1+0+0 records, response, authoritative, noerror +query: 16 436.test +answer: 436.test 86400 16 \1770123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\1777890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123\177456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789071234567890123456789012345678901234567890123456789012345 +0 +--- tinydns-data handles size-1000 TXT records +16 1000.test: +1047 bytes, 1+1+0+0 records, response, authoritative, noerror +query: 16 1000.test +answer: 1000.test 86400 16 \1770123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\1777890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123\1774567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\1771234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567\1778901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234\1775678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901\1772345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678o901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +0 +--- tinydns-data handles unusual characters in owner names +1 \000\001\177\200\277\056\056\056.test: +130 bytes, 1+1+2+3 records, response, authoritative, noerror +query: 1 \000\001\177\200\277\056\056\056.test +answer: \000\001\177\200\277\056\056\056.test 86400 A 10.5.6.7 +authority: test 259200 NS a.ns.test +authority: test 259200 NS b.ns.test +additional: a.ns.test 259200 A 10.2.3.4 +additional: b.ns.test 259200 A 10.2.3.6 +additional: b.ns.test 259200 A 10.2.3.5 +0 +--- tinydns-data handles unusual characters in PTR results +12 7.6.5.10.in-addr.arpa: +99 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 12 7.6.5.10.in-addr.arpa +answer: 7.6.5.10.in-addr.arpa 86400 PTR \000\001\177\200\277\056\056\056.test +authority: 7.6.5.10.in-addr.arpa 259200 NS ns.7.6.5.10.in-addr.arpa +additional: ns.7.6.5.10.in-addr.arpa 259200 A 10.5.6.7 +0 +--- tinydns-data handles delegations +1 x.\000\001\177\200\277\056\056\056.test: +66 bytes, 1+0+1+1 records, response, noerror +query: 1 x.\000\001\177\200\277\056\056\056.test +authority: x.\000\001\177\200\277\056\056\056.test 259200 NS ns.x.\000\001\177\200\277\056\056\056.test +additional: ns.x.\000\001\177\200\277\056\056\056.test 259200 A 10.8.9.10 +0 +1 ns.x.\000\001\177\200\277\056\056\056.test: +66 bytes, 1+0+1+1 records, response, noerror +query: 1 ns.x.\000\001\177\200\277\056\056\056.test +authority: x.\000\001\177\200\277\056\056\056.test 259200 NS ns.x.\000\001\177\200\277\056\056\056.test +additional: ns.x.\000\001\177\200\277\056\056\056.test 259200 A 10.8.9.10 +0 +1 z.y.x.\000\001\177\200\277\056\056\056.test: +70 bytes, 1+0+1+1 records, response, noerror +query: 1 z.y.x.\000\001\177\200\277\056\056\056.test +authority: x.\000\001\177\200\277\056\056\056.test 259200 NS ns.x.\000\001\177\200\277\056\056\056.test +additional: ns.x.\000\001\177\200\277\056\056\056.test 259200 A 10.8.9.10 +0 +--- tinydns-data handles another example +0 +--- tinydns-data handles TTLs +255 test: +202 bytes, 1+6+0+2 records, response, authoritative, noerror +query: 255 test +answer: test 98765 SOA primary.server host.master 1234567 2345678 3456789 4567890 5678901 +answer: test 37 NS ns.test +answer: test 41 MX 0 mx.test +answer: test 42 16 \004Text +answer: test 43 12345 Binary +answer: test 39 A 1.2.3.4 +additional: ns.test 37 A 1.2.3.4 +additional: mx.test 41 A 1.2.3.4 +0 +255 www.test: +75 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 255 www.test +answer: www.test 40 A 1.2.3.4 +authority: test 37 NS ns.test +additional: ns.test 37 A 1.2.3.4 +0 +255 child.test: +61 bytes, 1+0+1+1 records, response, noerror +query: 255 child.test +authority: child.test 38 NS ns.child.test +additional: ns.child.test 38 A 1.2.3.5 +0 +--- tinydns-data handles CNAMEs +255 mail.test: +78 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 255 mail.test +answer: mail.test 44 CNAME www.test +authority: test 37 NS ns.test +additional: ns.test 37 A 1.2.3.4 +0 +5 mail.test: +78 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 5 mail.test +answer: mail.test 44 CNAME www.test +authority: test 37 NS ns.test +additional: ns.test 37 A 1.2.3.4 +0 +1 mail.test: +78 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 1 mail.test +answer: mail.test 44 CNAME www.test +authority: test 37 NS ns.test +additional: ns.test 37 A 1.2.3.4 +0 +255 foo.mail.test: +92 bytes, 1+0+1+0 records, response, authoritative, nxdomain +query: 255 foo.mail.test +authority: test 98765 SOA primary.server host.master 1234567 2345678 3456789 4567890 5678901 +0 +--- tinydns-data does not apply wildcard A to base name +1 wild.test: +88 bytes, 1+0+1+0 records, response, authoritative, nxdomain +query: 1 wild.test +authority: test 98765 SOA primary.server host.master 1234567 2345678 3456789 4567890 5678901 +0 +--- tinydns-data handles wildcard A records +1 x.wild.test: +78 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 1 x.wild.test +answer: x.wild.test 45 A 1.2.3.6 +authority: test 37 NS ns.test +additional: ns.test 37 A 1.2.3.4 +0 +1 xy.wild.test: +79 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 1 xy.wild.test +answer: xy.wild.test 45 A 1.2.3.6 +authority: test 37 NS ns.test +additional: ns.test 37 A 1.2.3.4 +0 +1 x.z.wild.test: +80 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 1 x.z.wild.test +answer: x.z.wild.test 45 A 1.2.3.6 +authority: test 37 NS ns.test +additional: ns.test 37 A 1.2.3.4 +0 +--- tinydns-data handles wildcard MX records +255 wild.test: +88 bytes, 1+0+1+0 records, response, authoritative, nxdomain +query: 255 wild.test +authority: test 98765 SOA primary.server host.master 1234567 2345678 3456789 4567890 5678901 +0 +--- tinydns-data does not apply wildcard MX to base name +255 x.wild.test: +115 bytes, 1+2+1+2 records, response, authoritative, noerror +query: 255 x.wild.test +answer: x.wild.test 46 MX 54321 mail.wild.test +answer: x.wild.test 45 A 1.2.3.6 +authority: test 37 NS ns.test +additional: mail.wild.test 46 A 1.2.3.7 +additional: ns.test 37 A 1.2.3.4 +0 +255 xy.wild.test: +116 bytes, 1+2+1+2 records, response, authoritative, noerror +query: 255 xy.wild.test +answer: xy.wild.test 46 MX 54321 mail.wild.test +answer: xy.wild.test 45 A 1.2.3.6 +authority: test 37 NS ns.test +additional: mail.wild.test 46 A 1.2.3.7 +additional: ns.test 37 A 1.2.3.4 +0 +15 x.z.wild.test: +101 bytes, 1+1+1+2 records, response, authoritative, noerror +query: 15 x.z.wild.test +answer: x.z.wild.test 46 MX 54321 mail.wild.test +authority: test 37 NS ns.test +additional: mail.wild.test 46 A 1.2.3.7 +additional: ns.test 37 A 1.2.3.4 +0 +255 x.z.wild.test: +117 bytes, 1+2+1+2 records, response, authoritative, noerror +query: 255 x.z.wild.test +answer: x.z.wild.test 46 MX 54321 mail.wild.test +answer: x.z.wild.test 45 A 1.2.3.6 +authority: test 37 NS ns.test +additional: mail.wild.test 46 A 1.2.3.7 +additional: ns.test 37 A 1.2.3.4 +0 +255 \052.wild.test: +115 bytes, 1+2+1+2 records, response, authoritative, noerror +query: 255 \052.wild.test +answer: \052.wild.test 46 MX 54321 mail.wild.test +answer: \052.wild.test 45 A 1.2.3.6 +authority: test 37 NS ns.test +additional: mail.wild.test 46 A 1.2.3.7 +additional: ns.test 37 A 1.2.3.4 +0 +--- tinydns-data uses wildcard under base of sub-wildcard +255 alias.wild.test: +119 bytes, 1+2+1+2 records, response, authoritative, noerror +query: 255 alias.wild.test +answer: alias.wild.test 46 MX 54321 mail.wild.test +answer: alias.wild.test 45 A 1.2.3.6 +authority: test 37 NS ns.test +additional: mail.wild.test 46 A 1.2.3.7 +additional: ns.test 37 A 1.2.3.4 +0 +--- tinydns-data handles wildcard CNAME records +255 xyz.alias.wild.test: +84 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 255 xyz.alias.wild.test +answer: xyz.alias.wild.test 50 CNAME wild.test +authority: test 37 NS ns.test +additional: ns.test 37 A 1.2.3.4 +0 +255 \052.alias.wild.test: +82 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 255 \052.alias.wild.test +answer: \052.alias.wild.test 50 CNAME wild.test +authority: test 37 NS ns.test +additional: ns.test 37 A 1.2.3.4 +0 +--- tinydns-data lets explicit record override wildcard +255 override.wild.test: +85 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 255 override.wild.test +answer: override.wild.test 47 A 1.2.3.8 +authority: test 37 NS ns.test +additional: ns.test 37 A 1.2.3.4 +0 +--- tinydns-data handles overrides sanely +255 x.override.wild.test: +124 bytes, 1+2+1+2 records, response, authoritative, noerror +query: 255 x.override.wild.test +answer: x.override.wild.test 46 MX 54321 mail.wild.test +answer: x.override.wild.test 45 A 1.2.3.6 +authority: test 37 NS ns.test +additional: mail.wild.test 46 A 1.2.3.7 +additional: ns.test 37 A 1.2.3.4 +0 +--- tinydns-data overrides wildcard with subdomain wildcard +255 x.wild.wild.test: +83 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 255 x.wild.wild.test +answer: x.wild.wild.test 48 A 1.2.3.9 +authority: test 37 NS ns.test +additional: ns.test 37 A 1.2.3.4 +0 +--- tinydns-data overrides wildcard with delegation +255 child.wild.test: +69 bytes, 1+0+1+1 records, response, noerror +query: 255 child.wild.test +authority: child.wild.test 259200 NS 49.ns.child.wild.test +additional: 49.ns.child.wild.test 259200 A 1.2.3.10 +0 +255 x.child.wild.test: +71 bytes, 1+0+1+1 records, response, noerror +query: 255 x.child.wild.test +authority: child.wild.test 259200 NS 49.ns.child.wild.test +additional: 49.ns.child.wild.test 259200 A 1.2.3.10 +0 +--- tinydns-data handles another example +0 +--- tinydns-data handles ending time +255 www.four: +0 +255 www.six: +74 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 255 www.six +answer: www.six 3600 A 1.2.3.6 +authority: six 3600 NS ns.six +additional: ns.six 3600 A 1.2.3.6 +0 +--- tinydns-data handles starting time +255 www.five: +75 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 255 www.five +answer: www.five 86400 A 1.2.3.5 +authority: five 259200 NS ns.five +additional: ns.five 259200 A 1.2.3.5 +0 +255 www.seven: +0 +--- tinydns-edit handles simple examples +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 + +.heaven.af.mil:1.2.3.5:a:259200 +.heaven.af.mil:1.2.3.6:b:259200 +&sub.heaven.af.mil:1.2.10.11:a:259200 +&sub.heaven.af.mil:1.2.10.12:b:259200 +=lion.heaven.af.mil:1.2.3.4:86400 +=tiger.heaven.af.mil:1.2.3.5:86400 +=bear.heaven.af.mil:1.2.3.6:86400 ++www.heaven.af.mil:1.2.3.4:86400 +@heaven.af.mil:1.2.3.4:a::86400 +@heaven.af.mil:1.2.3.7:b::86400 +--- tinydns-edit rejects hosts with old names or IP addresses +tinydns-edit: fatal: IP address already used +100 +tinydns-edit: fatal: host name already used +100 + +.heaven.af.mil:1.2.3.5:a:259200 +.heaven.af.mil:1.2.3.6:b:259200 +&sub.heaven.af.mil:1.2.10.11:a:259200 +&sub.heaven.af.mil:1.2.10.12:b:259200 +=lion.heaven.af.mil:1.2.3.4:86400 +=tiger.heaven.af.mil:1.2.3.5:86400 +=bear.heaven.af.mil:1.2.3.6:86400 ++www.heaven.af.mil:1.2.3.4:86400 +@heaven.af.mil:1.2.3.4:a::86400 +@heaven.af.mil:1.2.3.7:b::86400 +--- tinydns-edit recognizes alternate forms of host names +tinydns-edit: fatal: host name already used +100 + +.heaven.af.mil:1.2.3.5:a:259200 +.heaven.af.mil:1.2.3.6:b:259200 +&sub.heaven.af.mil:1.2.10.11:a:259200 +&sub.heaven.af.mil:1.2.10.12:b:259200 +=lion.heaven.af.mil:1.2.3.4:86400 +=tiger.heaven.af.mil:1.2.3.5:86400 +=bear.heaven.af.mil:1.2.3.6:86400 ++www.heaven.af.mil:1.2.3.4:86400 +@heaven.af.mil:1.2.3.4:a::86400 +@heaven.af.mil:1.2.3.7:b::86400 +--- tinydns-edit copies TTLs from previous NS records +0 +.test:1.2.3.4:a:3600 +.test:1.2.3.5:b:3600 +--- dnscache handles dotted-decimal names +255 127.43.123.234: +48 bytes, 1+1+0+0 records, response, noerror +query: 255 127.43.123.234 +answer: 127.43.123.234 655360 A 127.43.123.234 +0 +--- tinydns works + +127.43.0.100 +127.43.0.101 +0 +1234 a.mx.test +45678 b.mx.test +0 +255 www.test: +91 bytes, 1+2+1+1 records, response, authoritative, noerror +additional: ns.test 259200 A 127.43.0.2 +answer: www.test 86400 A 127.43.0.100 +answer: www.test 86400 A 127.43.0.101 +authority: test 259200 NS ns.test +query: 255 www.test +0 +255 test: +173 bytes, 1+4+0+3 records, response, authoritative, noerror +query: 255 test +answer: test 2560 SOA ns.test hostmaster.test 987654321 16384 2048 1048576 2560 +answer: test 259200 NS ns.test +answer: test 86400 MX 1234 a.mx.test +answer: test 86400 MX 45678 b.mx.test +additional: ns.test 259200 A 127.43.0.2 +additional: a.mx.test 86400 A 127.43.0.100 +additional: b.mx.test 86400 A 127.43.0.101 +0 +--- dnscache handles large TXT records +0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +--- walldns handles in-addr.arpa names +7.6.43.127.in-addr.arpa +0 +234.123.43.127.in-addr.arpa +0 +127.43.123.234 +0 +255 234.123.43.127.in-addr.arpa: +75 bytes, 1+2+0+0 records, response, authoritative, noerror +query: 255 234.123.43.127.in-addr.arpa +answer: 234.123.43.127.in-addr.arpa 655360 A 127.43.123.234 +answer: 234.123.43.127.in-addr.arpa 655360 PTR 234.123.43.127.in-addr.arpa +0 +--- walldns handles dotted-decimal names +255 127.43.123.234: +48 bytes, 1+1+0+0 records, response, authoritative, noerror +query: 255 127.43.123.234 +answer: 127.43.123.234 655360 A 127.43.123.234 +0 +--- walldns rejects other names +255 blah.test: +temporary failure +0 +--- rbldns works +127.0.0.3 +0 +See http://www.rbl.test/5.4.3.2 +0 +255 2.3.4.5.rbl.test: +94 bytes, 1+2+0+0 records, response, authoritative, noerror +query: 255 2.3.4.5.rbl.test +answer: 2.3.4.5.rbl.test 2048 A 127.0.0.3 +answer: 2.3.4.5.rbl.test 2048 16 \037See\040http://www.rbl.test/5.4.3.2 +0 +127.0.0.3 +0 +See http://www.rbl.test/4.1.255.200 +0 +255 200.255.1.4.rbl.test: +102 bytes, 1+2+0+0 records, response, authoritative, noerror +query: 255 200.255.1.4.rbl.test +answer: 200.255.1.4.rbl.test 2048 A 127.0.0.3 +answer: 200.255.1.4.rbl.test 2048 16 #See\040http://www.rbl.test/4.1.255.200 +0 +127.0.0.3 +0 +See http://www.rbl.test/4.0.255.200 +0 +255 200.255.0.4.rbl.test: +102 bytes, 1+2+0+0 records, response, authoritative, noerror +query: 255 200.255.0.4.rbl.test +answer: 200.255.0.4.rbl.test 2048 A 127.0.0.3 +answer: 200.255.0.4.rbl.test 2048 16 #See\040http://www.rbl.test/4.0.255.200 +0 +127.0.0.3 +0 +See http://www.rbl.test/4.0.0.1 +0 +255 1.0.0.4.rbl.test: +94 bytes, 1+2+0+0 records, response, authoritative, noerror +query: 255 1.0.0.4.rbl.test +answer: 1.0.0.4.rbl.test 2048 A 127.0.0.3 +answer: 1.0.0.4.rbl.test 2048 16 \037See\040http://www.rbl.test/4.0.0.1 +0 + +0 + +0 +255 0.0.0.4.rbl.test: +34 bytes, 1+0+0+0 records, response, authoritative, nxdomain +query: 255 0.0.0.4.rbl.test +0 +--- tinydns handles differentiation + +0 +127.43.0.102 +0 + +127.43.0.100 +127.43.0.102 +0 + +127.43.0.100 +127.43.0.102 +0 +255 pick.test5: +81 bytes, 1+0+1+0 records, response, authoritative, nxdomain +query: 255 pick.test5 +authority: test5 2560 SOA me.ns.test5 hostmaster.test5 987654321 16384 2048 1048576 2560 +0 +255 pick2.test5: +81 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 255 pick2.test5 +answer: pick2.test5 86400 A 127.43.0.102 +authority: test5 259200 NS me.ns.test5 +additional: me.ns.test5 259200 A 127.43.0.2 +0 +255 pick3.test5: +97 bytes, 1+2+1+1 records, response, authoritative, noerror +additional: me.ns.test5 259200 A 127.43.0.2 +answer: pick3.test5 86400 A 127.43.0.100 +answer: pick3.test5 86400 A 127.43.0.102 +authority: test5 259200 NS me.ns.test5 +query: 255 pick3.test5 +0 +103 bytes, 1+2+1+1 records, response, authoritative, noerror +255 really.wild.test5: +additional: me.ns.test5 259200 A 127.43.0.2 +answer: really.wild.test5 86400 A 127.43.0.100 +answer: really.wild.test5 86400 A 127.43.0.102 +authority: test5 259200 NS me.ns.test5 +query: 255 really.wild.test5 +0 +--- tinydns-get handles differentiation +255 pick.test5: +80 bytes, 1+1+1+1 records, response, authoritative, noerror +query: 255 pick.test5 +answer: pick.test5 86400 A 127.43.0.101 +authority: test5 259200 NS ex.ns.test5 +additional: ex.ns.test5 259200 A 127.43.0.2 +0 +255 pick2.test5: +82 bytes, 1+0+1+0 records, response, authoritative, nxdomain +query: 255 pick2.test5 +authority: test5 2560 SOA ex.ns.test5 hostmaster.test5 987654321 16384 2048 1048576 2560 +0 +255 pick3.test5: +97 bytes, 1+2+1+1 records, response, authoritative, noerror +additional: ex.ns.test5 259200 A 127.43.0.2 +answer: pick3.test5 86400 A 127.43.0.100 +answer: pick3.test5 86400 A 127.43.0.101 +authority: test5 259200 NS ex.ns.test5 +query: 255 pick3.test5 +0 +103 bytes, 1+2+1+1 records, response, authoritative, noerror +255 really.wild.test5: +additional: ex.ns.test5 259200 A 127.43.0.2 +answer: really.wild.test5 86400 A 127.43.0.100 +answer: really.wild.test5 86400 A 127.43.0.101 +authority: test5 259200 NS ex.ns.test5 +query: 255 really.wild.test5 +0 +255 pick.test5: +81 bytes, 1+0+1+0 records, response, authoritative, nxdomain +query: 255 pick.test5 +authority: test5 2560 SOA i4.ns.test5 hostmaster.test5 987654321 16384 2048 1048576 2560 +0 +255 pick2.test5: +82 bytes, 1+0+1+0 records, response, authoritative, nxdomain +query: 255 pick2.test5 +authority: test5 2560 SOA i4.ns.test5 hostmaster.test5 987654321 16384 2048 1048576 2560 +0 +255 pick3.test5: +97 bytes, 1+2+1+1 records, response, authoritative, noerror +additional: i4.ns.test5 259200 A 127.43.0.2 +answer: pick3.test5 86400 A 127.43.0.100 +answer: pick3.test5 86400 A 127.43.0.104 +authority: test5 259200 NS i4.ns.test5 +query: 255 pick3.test5 +0 +103 bytes, 1+2+1+1 records, response, authoritative, noerror +255 really.wild.test5: +additional: i4.ns.test5 259200 A 127.43.0.2 +answer: really.wild.test5 86400 A 127.43.0.100 +answer: really.wild.test5 86400 A 127.43.0.104 +authority: test5 259200 NS i4.ns.test5 +query: 255 really.wild.test5 +0 +--- pickdns works +127.43.0.101 +0 +127.43.0.102 +0 +255 pick.test: +43 bytes, 1+1+0+0 records, response, authoritative, noerror +query: 255 pick.test +answer: pick.test 5 A 127.43.0.101 +0 +--- pickdns answers MX +0 pick.test +0 +--- pickdns rejects queries for unknown information +255 pick11.test: +temporary failure +0 +16 pick2.test: +temporary failure +0 +--- axfrdns rejects unauthorized transfer attempts +axfr-get: fatal: unable to parse AXFR results: protocol error +111 +axfr-get: fatal: unable to parse AXFR results: protocol error +111 +--- axfrdns works +0 +#987654321 auto axfr-get +Ztest:ns.test.:hostmaster.test.:987654321:16384:2048:1048576:2560:2560 +&test::ns.test.:259200 ++ns.test:127.43.0.2:259200 ++www.test:127.43.0.100:86400 ++www.test:127.43.0.101:86400 +@test::a.mx.test.:1234:86400 ++a.mx.test:127.43.0.100:86400 +@test::b.mx.test.:45678:86400 ++b.mx.test:127.43.0.101:86400 +&pick.test::ns.pick.test.:259200 ++ns.pick.test:127.43.0.3:259200 +&pick2.test::ns.pick2.test.:259200 ++ns.pick2.test:127.43.0.3:259200 +&rbl.test::ns.rbl.test.:259200 ++ns.rbl.test:127.43.0.5:259200 +:big.test:16:\1770123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\1777890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123\1774567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\1771234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567\1778901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234\1775678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901\1772345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678o901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789:86400 +--- axfrdns handles differentiation +0 +#987654321 auto axfr-get +Ztest5:me.ns.test5.:hostmaster.test5.:987654321:16384:2048:1048576:2560:2560 +&test5::me.ns.test5.:259200 ++me.ns.test5:127.43.0.2:259200 ++pick2.test5:127.43.0.102:86400 ++pick3.test5:127.43.0.100:86400 ++pick3.test5:127.43.0.102:86400 ++\052.wild.test5:127.43.0.100:86400 ++\052.wild.test5:127.43.0.102:86400 +0 +#987654321 auto axfr-get +Ztest5:i3.ns.test5.:hostmaster.test5.:987654321:16384:2048:1048576:2560:2560 +&test5::i3.ns.test5.:259200 ++i3.ns.test5:127.43.0.2:259200 ++pick3.test5:127.43.0.100:86400 ++pick3.test5:127.43.0.103:86400 ++\052.wild.test5:127.43.0.100:86400 ++\052.wild.test5:127.43.0.103:86400 +0 +#987654321 auto axfr-get +Ztest5:i4.ns.test5.:hostmaster.test5.:987654321:16384:2048:1048576:2560:2560 +&test5::i4.ns.test5.:259200 ++i4.ns.test5:127.43.0.2:259200 ++pick3.test5:127.43.0.100:86400 ++pick3.test5:127.43.0.104:86400 ++\052.wild.test5:127.43.0.100:86400 ++\052.wild.test5:127.43.0.104:86400 +0 +#987654321 auto axfr-get +Ztest5:i5.ns.test5.:hostmaster.test5.:987654321:16384:2048:1048576:2560:2560 +&test5::i5.ns.test5.:259200 ++i5.ns.test5:127.43.0.2:259200 ++pick3.test5:127.43.0.100:86400 ++pick3.test5:127.43.0.105:86400 ++\052.wild.test5:127.43.0.100:86400 ++\052.wild.test5:127.43.0.105:86400 +--- axfrdns gives authoritative answers +255 test4: +727 bytes, 1+12+0+0 records, response, authoritative, noerror +query: 255 test4 +answer: test4 2560 SOA ns.test4 hostmaster.test4 987654321 16384 2048 1048576 2560 +answer: test4 259200 NS ns.test4 +answer: test4 86400 16 3001234567890123456789012345678901234567890123456789 +answer: test4 86400 16 3101234567890123456789012345678901234567890123456789 +answer: test4 86400 16 3201234567890123456789012345678901234567890123456789 +answer: test4 86400 16 3301234567890123456789012345678901234567890123456789 +answer: test4 86400 16 3401234567890123456789012345678901234567890123456789 +answer: test4 86400 16 3501234567890123456789012345678901234567890123456789 +answer: test4 86400 16 3601234567890123456789012345678901234567890123456789 +answer: test4 86400 16 3701234567890123456789012345678901234567890123456789 +answer: test4 86400 16 3801234567890123456789012345678901234567890123456789 +answer: test4 86400 16 3901234567890123456789012345678901234567890123456789 +0 +--- axfrdns handles size-1000 TXT records +255 big.test: +1046 bytes, 1+1+0+0 records, response, authoritative, noerror +query: 255 big.test +answer: big.test 86400 16 \1770123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456\1777890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123\1774567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\1771234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567\1778901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234\1775678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901\1772345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678o901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +0 +--- axfr-get handles zones with wildcards +0 +#987654321 auto axfr-get +Ztest2:ns.test2.:hostmaster.test2.:987654321:16384:2048:1048576:2560:2560 +&test2::ns.test2.:259200 ++ns.test2:127.43.0.2:259200 ++\052.test2:127.43.0.102:86400 +C\052.www.test2:www.test2.:5000 ++one.test2:127.43.0.103:86400 ++two.test2:127.43.0.104:2 diff --git a/rts.sh b/rts.sh new file mode 100644 index 0000000..c71e839 --- /dev/null +++ b/rts.sh @@ -0,0 +1 @@ +env - PATH="`pwd`:$PATH" sh rts.tests 2>&1 | cat -v diff --git a/rts.tests b/rts.tests new file mode 100644 index 0000000..ee2be85 --- /dev/null +++ b/rts.tests @@ -0,0 +1,767 @@ +# Requirements: +# You are running as root. +# You have dns{cache,log}, {tiny,pick,wall,axfr,rbl}dns accounts. +# You have local IP addresses 127.43.0.{1,2,3,4,5}. +# You are connected to the Internet. +# +# Some features not tested here: +# dns_random works. +# random-ip works. +# dnstrace works. +# dnstracesort works. +# dns_resolvconfrewrite rereads after 10 minutes or 10000 uses. +# dns_resolvconfip rereads after 10 minutes or 10000 uses. +# /etc/resolv.conf is parsed properly. +# dns_transmit handles timeouts properly. +# dns_transmit falls back to TCP properly. +# dns_transmit handles various strange situations: e.g., NOTIMP. + + +umask 022 + +rm -rf rts-tmp +service=`pwd`/rts-tmp/service + +mkdir rts-tmp +mkdir $service + +echo ' +*.b:.2.3.4 +=localhost:localhost. +-.localhost:localhost. +?:+.yp.to+.cr.yp.to+.whatever.cr.yp.to +*.: +' > rts-tmp/rewrite + +DNSREWRITEFILE=rts-tmp/rewrite; export DNSREWRITEFILE +DNSCACHEIP=127.555.0.1; export DNSCACHEIP + + +echo '--- dnscache-conf works' +dnscache-conf dnscache dnslog $service/dnscache 127.555.0.1 +echo 127.555.0.2 > $service/dnscache/root/servers/tEST +echo 127.555.0.2 > $service/dnscache/root/servers/tEST5 +echo 127.555.0.4 > $service/dnscache/root/servers/43.127.iN-aDDR.aRPA +touch $service/dnscache/root/ip/127.43.0.1 +supervise $service/dnscache | supervise $service/dnscache/log & + +echo '--- tinydns-conf works' +tinydns-conf tinydns dnslog $service/tinydns 127.555.0.2 +supervise $service/tinydns | supervise $service/tinydns/log & + +echo '--- pickdns-conf works' +pickdns-conf pickdns dnslog $service/pickdns 127.555.0.3 +supervise $service/pickdns | supervise $service/pickdns/log & + +echo '--- walldns-conf works' +walldns-conf walldns dnslog $service/walldns 127.555.0.4 +supervise $service/walldns | supervise $service/walldns/log & + +echo '--- rbldns-conf works' +rbldns-conf rbldns dnslog $service/rbldns 127.555.0.5 RbL.TeSt +supervise $service/rbldns | supervise $service/rbldns/log & + +echo '--- axfrdns-conf works' +axfrdns-conf axfrdns dnslog $service/axfrdns $service/tinydns 127.555.0.2 +supervise $service/axfrdns | supervise $service/axfrdns/log & + +sleep 1 + + +echo '--- cache handles simple example' +cachetest \ +one two three four five \ +one:un one two three four five \ +two:deux one two three four five \ +three:trois one two three four five \ +four:quatre one two three four five \ +five:cinq one two three four five \ +one:een one two three four five \ +two:twee one two three four five \ +three:drie one two three four five \ +four:vier one two three four five \ +five:vijf one two three four five +echo $? + +echo '--- cache handles overwriting' +cachetest \ +one two three four five \ +one:un one two three four five \ +one:een one two three four five \ +two:deux one two three four five \ +two:twee one two three four five \ +three:trois one two three four five \ +three:drie one two three four five \ +four:quatre one two three four five \ +four:vier one two three four five \ +five:cinq one two three four five \ +five:vijf one two three four five +echo $? + +echo '--- cache handles long chains' +cachetest \ +a:1 a \ +a:2 a \ +a:3 a \ +a:4 a \ +a:5 a \ +a:6 a \ +a:7 a \ +a:8 a \ +a:9 a +echo $? + + +echo '--- dnsip finds IP address of network-surveys.cr.yp.to' +dnsip network-surveys.cr.yp.to +echo $? + +echo '--- dnsip does not find nonexistent.cr.yp.to' +dnsip nonexistent.cr.yp.to +echo $? + +echo '--- dnsip rejects overly long domain names' +dnsip x.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789 +echo $? + +echo '--- dnsip handles IP address on input' +dnsip 1.2.3.4 127.0.0.1 10.555.678.901 '[010.0555.0678.0901]' +echo $? + +echo '--- dnsip allows 0 to be omitted' +dnsip 127...1 +echo $? + +echo '--- dnsip handles multiple IP addresses on input' +dnsip 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16 +echo $? + +echo '--- dnsipq handles simple examples' +dnsipq 1.b localhost anything.localhost 5.6.7.8 network-surveys nonexistent +echo $? + +echo '--- dnsmx finds MX record for network-surveys.cr.yp.to' +dnsmx network-surveys.cr.yp.to +echo $? + +echo '--- dnsmx manufactures MX record for nonexistent.cr.yp.to' +dnsmx NONexistent.cr.yp.to +echo $? + +echo '--- dnsmx rejects overly long domain names' +dnsmx 0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789 +echo $? + +echo '--- dnstxt finds TXT record for leap.yp.to' +dnstxt leap.yp.to +echo $? + +echo '--- dnstxt does not find nonexistent.cr.yp.to' +dnstxt nonexistent.cr.yp.to +echo $? + +echo '--- dnstxt rejects overly long domain names' +dnstxt 0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789 +echo $? + +echo '--- dnsname finds host name of 131.193.178.100' +dnsname 131.193.178.100 +echo $? + +echo '--- dnsname does not find 127.5.6.7' +dnsname 127.5.6.7 +echo $? + +echo '--- dnsname rejects misformatted IP addresses' +dnsname 1.2.3 +echo $? + +echo '--- dnsfilter finds some host names' +echo '131.193.178.100+one two three +127.5.6.7+one two three +10+one two three' | dnsfilter +echo $? + + +echo ' +=movie.edu:1.2.3.4 +*star +' > rts-tmp/data + +echo '--- tinydns-data complains about unrecognized initial characters' +( cd rts-tmp; tinydns-data; echo $? ) + +echo ' +.movie.edu:192.249.249.3:a +.movie.edu::wormhole.movie.edu +&fx.movie.edu:192.253.254.2:a +&fx.movie.edu:192.253.254.3:b +.249.249.192.in-addr.arpa:192.249.249.3:a +.249.249.192.in-addr.arpa::wormhole.movie.edu +.253.253.192.in-addr.arpa:192.249.249.3:a +.253.253.192.in-addr.arpa:192.249.249.1:b +.253.253.192.in-addr.arpa:192.253.253.1:c +.254.253.192.in-addr.arpa:192.253.254.2:a +.254.253.192.in-addr.arpa:192.253.254.3:b + ++localhost.movie.edu:127.0.0.1 + +@movie.edu:192.249.249.1:a + +'\''movie.edu:Movie University +:movie.edu:12345:One +:movie.edu:12345:Two +:movie.edu:12346:Three +:movie.edu:12346:Four + +=wormhole.movie.edu:192.249.249.1 ++wh249.movie.edu:192.249.249.1 +=robocop.movie.edu:192.249.249.2 +=terminator.movie.edu:192.249.249.3 ++bigt.movie.edu:192.249.249.3 +=diehard.movie.edu:192.249.294.4 ++dh.movie.edu:192.249.294.4 + +=wormhole.movie.edu:192.253.253.1 ++wh253.movie.edu:192.253.253.1 ++wh.movie.edu:192.253.253.1 ++wh.movie.edu:192.253.253.1 +=misery.movie.edu:192.253.253.2 +=shining.movie.edu:192.253.253.3 +=carrie.movie.edu:192.253.253.4 + +.blah.movie.edu:1.2.3.4:blah.movie.edu +'\''blah.movie.edu:Text +' > rts-tmp/data +utime rts-tmp/data 987654321 + +echo '--- tinydns-data complains if it cannot create data.tmp' +rm -f rts-tmp/data.tmp +ln -s data.tmp rts-tmp/data.tmp +( cd rts-tmp; tinydns-data; echo $? ) +rm -f rts-tmp/data.tmp + +echo '--- tinydns-data handles simple example' +( cd rts-tmp; tinydns-data; echo $? ) + +echo '--- tinydns-data produces A records' +( cd rts-tmp; tinydns-get 1 wormhole.movie.edu | sort; echo $? ) + +echo '--- tinydns-data produces NS records' +( cd rts-tmp; tinydns-get 2 movie.edu; echo $? ) + +echo '--- tinydns-data produces SOA records' +( cd rts-tmp; tinydns-get 6 movie.edu; echo $? ) + +echo '--- tinydns-data produces PTR records' +( cd rts-tmp; tinydns-get 12 1.253.253.192.in-addr.arpa; echo $? ) + +echo '--- tinydns-data produces MX records' +( cd rts-tmp; tinydns-get 15 movie.edu; echo $? ) + +echo '--- tinydns-data produces TXT records' +( cd rts-tmp; tinydns-get 16 movie.edu; echo $? ) + +echo '--- tinydns-data produces AXFR responses' +( cd rts-tmp; tinydns-get 252 movie.edu; echo $? ) + +echo '--- tinydns-data produces ANY responses' +( cd rts-tmp; tinydns-get 255 movie.edu; echo $? ) + +echo '--- tinydns-data produces records of any type' +( cd rts-tmp; tinydns-get 12345 movie.edu; echo $? ) +( cd rts-tmp; tinydns-get 12346 movie.edu; echo $? ) + +echo '--- tinydns-data produces NODATA responses' +( cd rts-tmp; tinydns-get 54321 movie.edu; echo $? ) + +echo '--- tinydns-data produces NXDOMAIN responses' +( cd rts-tmp; tinydns-get 1 this.does.not.exist.movie.edu; echo $? ) + +echo '--- tinydns-data produces NXDOMAIN responses for suffixes' +( cd rts-tmp; tinydns-get 1 ns.movie.edu; echo $? ) + +echo '--- tinydns-data produces NXDOMAIN ANY responses for suffixes' +( cd rts-tmp; tinydns-get 255 ns.movie.edu; echo $? ) + +echo '--- tinydns-data does not produce responses outside its bailiwick' +( cd rts-tmp; tinydns-get 1 edu; echo $? ) + +echo '--- tinydns-data does not include TXT in additional sections' +( cd rts-tmp; tinydns-get 1 blah.movie.edu; echo $? ) + + +echo ' +.test:10.2.3.4:a ++b.ns.test:10.2.3.6:259200 +.test:10.2.3.5:b +'\''127.test:0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456 +'\''128.test:01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567 +'\''254.test:01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123 +'\''255.test:012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234 +'\''387.test:012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456 +'\''388.test:0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567 +'\''400.test:0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +'\''410.test:01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +'\''420.test:012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +'\''430.test:0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +'\''435.test:012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234 +'\''436.test:0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345 +'\''1000.test:0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +=\000\001\177\200\277\.\.\..test:10.5.6.7 +.7.6.5.10.in-addr.arpa:10.5.6.7 + +&x.\0\1\177\200\277\.\.\..test:10.8.9.10 +' > rts-tmp/data +utime rts-tmp/data 0 + +echo '--- tinydns-data handles another example' +( cd rts-tmp; tinydns-data; echo $? ) + +echo '--- tinydns-data uses serial 1 for mtime 0' +( cd rts-tmp; tinydns-get Any test; echo $? ) + +echo '--- tinydns-data does not split size-127 TXT records' +( cd rts-tmp; tinydns-get Txt 127.test; echo $? ) + +echo '--- tinydns-data splits size-128 TXT records' +( cd rts-tmp; tinydns-get 16 128.test; echo $? ) + +echo '--- tinydns-data splits size-254 TXT records' +( cd rts-tmp; tinydns-get 16 254.test; echo $? ) + +echo '--- tinydns-data doubly splits size-255 TXT records' +( cd rts-tmp; tinydns-get 16 255.test; echo $? ) + +echo '--- tinydns-data excludes the additional section if necessary' +( cd rts-tmp; tinydns-get 16 387.test; echo $? ) +( cd rts-tmp; tinydns-get 16 388.test; echo $? ) + +echo '--- tinydns-data excludes the authority section if necessary' +( cd rts-tmp; tinydns-get 16 435.test; echo $? ) +( cd rts-tmp; tinydns-get 16 436.test; echo $? ) + +echo '--- tinydns-data handles size-1000 TXT records' +( cd rts-tmp; tinydns-get 16 1000.test; echo $? ) + +echo '--- tinydns-data handles unusual characters in owner names' +( cd rts-tmp; tinydns-get A '\0\1\177\200\277\56\56\56.test'; echo $? ) + +echo '--- tinydns-data handles unusual characters in PTR results' +( cd rts-tmp; tinydns-get Ptr 7.6.5.10.in-addr.arpa; echo $? ) + +echo '--- tinydns-data handles delegations' +( cd rts-tmp; tinydns-get 1 'x.\0\1\177\200\277\56\56\56.test'; echo $? ) +( cd rts-tmp; tinydns-get 1 'ns.x.\0\1\177\200\277\56\56\56.test'; echo $? ) +( cd rts-tmp; tinydns-get 1 'z.y.x.\0\1\177\200\277\56\56\56.test'; echo $? ) + + +echo ' +Ztest:Primary.Server:Host.Master:1234567:2345678:3456789:4567890:5678901:98765 +&test:1.2.3.4::37 +@*.wild.test:1.2.3.7:mail.wild.test:54321:46 +&child.test:1.2.3.5::38 +@test:1.2.3.4:::41 +=test:1.2.3.4:39 ++www.test:1.2.3.4:40 +'\''test:Text:42 +:test:12345:Binary:43 +Cmail.test:www.test:44 ++*.wild.test:1.2.3.6:45 +=override.wild.test:1.2.3.8:47 ++*.wild.wild.test:1.2.3.9:48 +&child.wild.test:1.2.3.10:49 +C*.alias.wild.test:wild.test:50 +' > rts-tmp/data +utime rts-tmp/data 0 + +echo '--- tinydns-data handles another example' +( cd rts-tmp; tinydns-data; echo $? ) + +echo '--- tinydns-data handles TTLs' +( cd rts-tmp; tinydns-get 255 test; echo $? ) +( cd rts-tmp; tinydns-get 255 www.test; echo $? ) +( cd rts-tmp; tinydns-get 255 child.test; echo $? ) + +echo '--- tinydns-data handles CNAMEs' +( cd rts-tmp; tinydns-get 255 mail.test; echo $? ) +( cd rts-tmp; tinydns-get 5 mail.test; echo $? ) +( cd rts-tmp; tinydns-get 1 mail.test; echo $? ) +( cd rts-tmp; tinydns-get 255 foo.mail.test; echo $? ) + +echo '--- tinydns-data does not apply wildcard A to base name' +( cd rts-tmp; tinydns-get 1 wild.test; echo $? ) + +echo '--- tinydns-data handles wildcard A records' +( cd rts-tmp; tinydns-get 1 x.wild.test; echo $? ) +( cd rts-tmp; tinydns-get 1 xy.wild.test; echo $? ) +( cd rts-tmp; tinydns-get 1 x.z.wild.test; echo $? ) + +echo '--- tinydns-data handles wildcard MX records' +( cd rts-tmp; tinydns-get 255 wild.test; echo $? ) + +echo '--- tinydns-data does not apply wildcard MX to base name' +( cd rts-tmp; tinydns-get 255 x.wild.test; echo $? ) +( cd rts-tmp; tinydns-get 255 xy.wild.test; echo $? ) +( cd rts-tmp; tinydns-get 15 x.z.wild.test; echo $? ) +( cd rts-tmp; tinydns-get 255 x.z.wild.test; echo $? ) +( cd rts-tmp; tinydns-get 255 '*'.wild.test; echo $? ) + +echo '--- tinydns-data uses wildcard under base of sub-wildcard' +( cd rts-tmp; tinydns-get 255 alias.wild.test; echo $? ) + +echo '--- tinydns-data handles wildcard CNAME records' +( cd rts-tmp; tinydns-get 255 xyz.alias.wild.test; echo $? ) +( cd rts-tmp; tinydns-get 255 '*'.alias.wild.test; echo $? ) + +echo '--- tinydns-data lets explicit record override wildcard' +( cd rts-tmp; tinydns-get 255 override.wild.test; echo $? ) + +echo '--- tinydns-data handles overrides sanely' +( cd rts-tmp; tinydns-get 255 x.override.wild.test; echo $? ) + +echo '--- tinydns-data overrides wildcard with subdomain wildcard' +( cd rts-tmp; tinydns-get 255 x.wild.wild.test; echo $? ) + +echo '--- tinydns-data overrides wildcard with delegation' +( cd rts-tmp; tinydns-get 255 child.wild.test; echo $? ) +( cd rts-tmp; tinydns-get 255 x.child.wild.test; echo $? ) + + +echo ' +.four:1.2.3.4::0:30000000fedcba98 ++www.four:1.2.3.4:0:30000000fedcba98 +.five:1.2.3.5:::30000000fedcba98 ++www.five:1.2.3.5::30000000fedcba98 +.six:1.2.3.6::0:50000000fedcba98 ++www.six:1.2.3.6:0:50000000fedcba98 +.seven:1.2.3.7:::50000000fedcba98 ++www.seven:1.2.3.7::50000000fedcba98 +' > rts-tmp/data +utime rts-tmp/data 7654321 + +echo '--- tinydns-data handles another example' +( cd rts-tmp; tinydns-data; echo $? ) + +echo '--- tinydns-data handles ending time' +( cd rts-tmp; tinydns-get 255 www.four; echo $? ) +( cd rts-tmp; tinydns-get 255 www.six; echo $? ) + +echo '--- tinydns-data handles starting time' +( cd rts-tmp; tinydns-get 255 www.five; echo $? ) +( cd rts-tmp; tinydns-get 255 www.seven; echo $? ) + + +echo '--- tinydns-edit handles simple examples' +echo '' > rts-tmp/data +( cd rts-tmp; tinydns-edit data data.new add ns heaven.af.mil 1.2.3.5; echo $? ) +( cd rts-tmp; tinydns-edit data data.new add ns heaven.af.mil 1.2.3.6; echo $? ) +( cd rts-tmp; tinydns-edit data data.new add childns sub.heaven.af.mil 1.2.10.11; echo $? ) +( cd rts-tmp; tinydns-edit data data.new add childns sub.heaven.af.mil 1.2.10.12; echo $? ) +( cd rts-tmp; tinydns-edit data data.new add host lion.heaven.af.mil 1.2.3.4; echo $? ) +( cd rts-tmp; tinydns-edit data data.new add host tiger.heaven.af.mil 1.2.3.5; echo $? ) +( cd rts-tmp; tinydns-edit data data.new add host bear.heaven.af.mil 1.2.3.6; echo $? ) +( cd rts-tmp; tinydns-edit data data.new add alias www.heaven.af.mil 1.2.3.4; echo $? ) +( cd rts-tmp; tinydns-edit data data.new add mx heaven.af.mil 1.2.3.4; echo $? ) +( cd rts-tmp; tinydns-edit data data.new add mx heaven.af.mil 1.2.3.7; echo $? ) +cat rts-tmp/data + +echo '--- tinydns-edit rejects hosts with old names or IP addresses' +( cd rts-tmp; tinydns-edit data data.new add host panda.heaven.af.mil 1.2.3.6; echo $? ) +( cd rts-tmp; tinydns-edit data data.new add host bear.heaven.af.mil 1.2.3.8; echo $? ) +cat rts-tmp/data + +echo '--- tinydns-edit recognizes alternate forms of host names' +( cd rts-tmp; tinydns-edit data data.new add host 'BE\101r.Heaven.AF..Mil.' 1.2.3.8; echo $? ) +cat rts-tmp/data + +echo '--- tinydns-edit copies TTLs from previous NS records' +echo '.test:1.2.3.4:a:3600' > rts-tmp/data +( cd rts-tmp; tinydns-edit data data.new add ns test 1.2.3.5; echo $? ) +cat rts-tmp/data + + + +echo ' +.Test:127.555.0.2 +=Www.Test:127.555.0.100 +=Www.Test:127.555.0.101 +@Test:127.555.0.100:a:1234 +@Test:127.555.0.101:b:45678 +&Pick.Test:127.555.0.3 +&Pick2.Test:127.555.0.3 +&Rbl.Test:127.555.0.5 +.Test2:127.555.0.2 ++*.Test2:127.555.0.102 +C*.Www.Test2:Www.Test2:5000 +=one.Test2:127.555.0.103::300000003456789a +=two.Test2:127.555.0.104:0:500000003456789a +.Test3:127.555.0.2 +=Www.Test3:127.0.0.106 +.Test4:127.555.0.2 +'\''Test4:001234567890123456789012345678901234567890123456789 +'\''Test4:101234567890123456789012345678901234567890123456789 +'\''Test4:201234567890123456789012345678901234567890123456789 +'\''Test4:301234567890123456789012345678901234567890123456789 +'\''Test4:401234567890123456789012345678901234567890123456789 +'\''Test4:501234567890123456789012345678901234567890123456789 +'\''Test4:601234567890123456789012345678901234567890123456789 +'\''Test4:701234567890123456789012345678901234567890123456789 +'\''Test4:801234567890123456789012345678901234567890123456789 +'\''Test4:901234567890123456789012345678901234567890123456789 +'\''Big.Test:0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +%i3:127.555.0.3 +%i4:127.555.0.4 +%i5:127.555.0.5 +%ME:127 +%EX +.Test5:127.555.0.2:ex:::EX +.Test5:127.555.0.2:me:::ME +.Test5:127.555.0.2:i3:::i3 +.Test5:127.555.0.2:i4:::i4 +.Test5:127.555.0.2:i5:::i5 +-Pick.Test5:127.555.0.100:::EX ++Pick.Test5:127.555.0.101:::EX +-Pick2.Test5:127.555.0.102:::ME ++Pick2.Test5:127.555.0.102:::ME ++Pick3.Test5:127.555.0.100 ++Pick3.Test5:127.555.0.101:::EX ++Pick3.Test5:127.555.0.102:::ME ++Pick3.Test5:127.555.0.103:::i3 ++Pick3.Test5:127.555.0.104:::i4 ++Pick3.Test5:127.555.0.105:::i5 ++*.Wild.Test5:127.555.0.100 ++*.Wild.Test5:127.555.0.101:::EX ++*.Wild.Test5:127.555.0.102:::ME ++*.Wild.Test5:127.555.0.103:::i3 ++*.Wild.Test5:127.555.0.104:::i4 ++*.Wild.Test5:127.555.0.105:::i5 +' > $service/tinydns/root/data +utime $service/tinydns/root/data 987654321 +( cd $service/tinydns/root; tinydns-data ) + +echo ' +-Pick.Test:127.555.0.100 ++Pick.Test:127.555.0.101 +-Pick2.Test:127.555.0.102:ME ++Pick2.Test:127.555.0.102:ME +%ME:127 +' > $service/pickdns/root/data +( cd $service/pickdns/root; pickdns-data ) + +echo ' +4.0.0.1 +4.0.0.2/31 +4.0.0.4/30 +4.0.0.8/29 +4.0.0.16/28 +4.0.0.32/27 +4.0.0.64/26 +4.0.0.128/25 +4.0.1.0/24 +4.0.2.0/23 +4.0.4.0/22 +4.0.8.0/21 +4.0.16.0/20 +4.0.32.0/19 +4.0.64.0/18 +4.0.128.0/17 +4.1.0.0/16 +4.2.0.0/15 +4.4.0.0/14 +4.8.0.0/13 +4.16.0.0/12 +4.32.0.0/11 +4.64.0.0/10 +4.128.0.0/9 +5.0.0.0/8 +:127.0.0.3:See http://www.rbl.test/$ +' > $service/rbldns/root/data +( cd $service/rbldns/root; rbldns-data ) + +echo ' +127.:allow,AXFR="tEsT/TeSt2/TEst5" +:deny +' > $service/axfrdns/tcp +( cd $service/axfrdns; tcprules tcp.cdb tcp.tmp < tcp ) + + +echo '--- dnscache handles dotted-decimal names' +dnsqr 255 127.43.123.234 +echo $? + +echo '--- tinydns works' +dnsip WWW.TEST | tr ' ' '\012' | sort +echo $? +dnsmx TEST +echo $? +dnsq 255 WWW.TEST 127.555.0.2 | sort +echo $? +dnsq Any TEST 127.555.0.2 +echo $? + +echo '--- dnscache handles large TXT records' +dnstxt BIG.Test + +echo '--- walldns handles in-addr.arpa names' +dnsname 127.555.6.7 +echo $? +dnsname 127.555.123.234 +echo $? +dnsip 234.123.43.127.IN-ADDR.ARPA +echo $? +dnsq 255 234.123.43.127.IN-ADDR.ARPA 127.555.0.4 +echo $? + +echo '--- walldns handles dotted-decimal names' +dnsq 255 127.43.123.234 127.555.0.4 +echo $? + +echo '--- walldns rejects other names' +dnsq 255 BLAH.TEST 127.555.0.4 +echo $? + +echo '--- rbldns works' +dnsip 2.3.4.5.rbl.test +echo $? +dnstxt 2.3.4.5.rbl.test +echo $? +dnsq 255 2.3.4.5.rbl.test 127.555.0.5 +echo $? +dnsip 200.255.1.4.rbl.test +echo $? +dnstxt 200.255.1.4.rbl.test +echo $? +dnsq 255 200.255.1.4.rbl.test 127.555.0.5 +echo $? +dnsip 200.255.0.4.rbl.test +echo $? +dnstxt 200.255.0.4.rbl.test +echo $? +dnsq 255 200.255.0.4.rbl.test 127.555.0.5 +echo $? +dnsip 1.0.0.4.rbl.test +echo $? +dnstxt 1.0.0.4.rbl.test +echo $? +dnsq 255 1.0.0.4.rbl.test 127.555.0.5 +echo $? +dnsip 0.0.0.4.rbl.test +echo $? +dnstxt 0.0.0.4.rbl.test +echo $? +dnsq 255 0.0.0.4.rbl.test 127.555.0.5 +echo $? + +echo '--- tinydns handles differentiation' +dnsip PICK.TEST5 +echo $? +dnsip PICK2.TEST5 +echo $? +dnsip PICK3.TEST5 | tr ' ' '\012' | sort +echo $? +dnsip REALLY.WILD.TEST5 | tr ' ' '\012' | sort +echo $? +dnsq 255 PICK.TEST5 127.555.0.2 +echo $? +dnsq 255 PICK2.TEST5 127.555.0.2 +echo $? +dnsq 255 PICK3.TEST5 127.555.0.2 | sort +echo $? +dnsq 255 REALLY.WILD.TEST5 127.555.0.2 | sort +echo $? + +echo '--- tinydns-get handles differentiation' +( cd rts-tmp/service/tinydns/root + tinydns-get 255 PICK.TEST5 1.2.3.4; echo $? + tinydns-get 255 PICK2.TEST5 1.2.3.4; echo $? + tinydns-get 255 PICK3.TEST5 1.2.3.4 | sort; echo $? + tinydns-get 255 REALLY.WILD.TEST5 1.2.3.4 | sort; echo $? + tinydns-get 255 PICK.TEST5 127.555.0.4; echo $? + tinydns-get 255 PICK2.TEST5 127.555.0.4; echo $? + tinydns-get 255 PICK3.TEST5 127.555.0.4 | sort; echo $? + tinydns-get 255 REALLY.WILD.TEST5 127.555.0.4 | sort; echo $? +) + +echo '--- pickdns works' +dnsip PICK.TEST +echo $? +dnsip PICK2.TEST +echo $? +dnsq 255 PICK.TEST 127.555.0.3 +echo $? + +echo '--- pickdns answers MX' +dnsmx PICK.TEST +echo $? + +echo '--- pickdns rejects queries for unknown information' +dnsq 255 PICK11.TEST 127.555.0.3 +echo $? +dnsq Txt PICK2.TEST 127.555.0.3 +echo $? + +echo '--- axfrdns rejects unauthorized transfer attempts' +tcpclient -RHl0 127.43.0.2 53 axfr-get TEST3 rts-tmp/zone rts-tmp/zone.tmp +echo $? +tcpclient -RHl0 127.43.0.2 53 axfr-get TEST4 rts-tmp/zone2 rts-tmp/zone2.tmp +echo $? + +echo '--- axfrdns works' +tcpclient -RHl0 127.43.0.2 53 axfr-get TEST rts-tmp/zone rts-tmp/zone.tmp +echo $? +cat rts-tmp/zone + +echo '--- axfrdns handles differentiation' +tcpclient -RHl0 -i 127.43.0.2 127.43.0.2 53 axfr-get TEST5 rts-tmp/zone5 rts-tmp/zone5.tmp +echo $? +cat rts-tmp/zone5 +rm rts-tmp/zone5 +tcpclient -RHl0 -i 127.43.0.3 127.43.0.2 53 axfr-get TEST5 rts-tmp/zone5 rts-tmp/zone5.tmp +echo $? +cat rts-tmp/zone5 +rm rts-tmp/zone5 +tcpclient -RHl0 -i 127.43.0.4 127.43.0.2 53 axfr-get TEST5 rts-tmp/zone5 rts-tmp/zone5.tmp +echo $? +cat rts-tmp/zone5 +rm rts-tmp/zone5 +tcpclient -RHl0 -i 127.43.0.5 127.43.0.2 53 axfr-get TEST5 rts-tmp/zone5 rts-tmp/zone5.tmp +echo $? +cat rts-tmp/zone5 + +echo '--- axfrdns gives authoritative answers' +dnsq any Test4 127.43.0.2 +echo $? + +echo '--- axfrdns handles size-1000 TXT records' +dnsq any BIG.TEST 127.43.0.2 +echo $? + +echo '--- axfr-get handles zones with wildcards' +tcpclient -RHl0 127.43.0.2 53 axfr-get TEST2 rts-tmp/zone2 rts-tmp/zone2.tmp +echo $? +cat rts-tmp/zone2 + + +svc -dx $service/dnscache +svc -dx $service/tinydns +svc -dx $service/pickdns +svc -dx $service/walldns +svc -dx $service/rbldns +svc -dx $service/axfrdns + +svc -dx $service/dnscache/log +svc -dx $service/tinydns/log +svc -dx $service/pickdns/log +svc -dx $service/walldns/log +svc -dx $service/rbldns/log +svc -dx $service/axfrdns/log + +wait +wait +wait +wait +wait +wait + +exit 0 diff --git a/scan.h b/scan.h new file mode 100644 index 0000000..fd383ee --- /dev/null +++ b/scan.h @@ -0,0 +1,28 @@ +#ifndef SCAN_H +#define SCAN_H + +extern unsigned int scan_uint(const char *,unsigned int *); +extern unsigned int scan_xint(const char *,unsigned int *); +extern unsigned int scan_nbbint(const char *,unsigned int,unsigned int,unsigned int,unsigned int *); +extern unsigned int scan_ushort(const char *,unsigned short *); +extern unsigned int scan_xshort(const char *,unsigned short *); +extern unsigned int scan_nbbshort(const char *,unsigned int,unsigned int,unsigned int,unsigned short *); +extern unsigned int scan_ulong(const char *,unsigned long *); +extern unsigned int scan_xlong(const char *,unsigned long *); +extern unsigned int scan_nbblong(const char *,unsigned int,unsigned int,unsigned int,unsigned long *); + +extern unsigned int scan_plusminus(const char *,int *); +extern unsigned int scan_0x(const char *,unsigned int *); + +extern unsigned int scan_whitenskip(const char *,unsigned int); +extern unsigned int scan_nonwhitenskip(const char *,unsigned int); +extern unsigned int scan_charsetnskip(const char *,const char *,unsigned int); +extern unsigned int scan_noncharsetnskip(const char *,const char *,unsigned int); + +extern unsigned int scan_strncmp(const char *,const char *,unsigned int); +extern unsigned int scan_memcmp(const char *,const char *,unsigned int); + +extern unsigned int scan_long(const char *,long *); +extern unsigned int scan_8long(const char *,unsigned long *); + +#endif diff --git a/scan_ulong.c b/scan_ulong.c new file mode 100644 index 0000000..d70b334 --- /dev/null +++ b/scan_ulong.c @@ -0,0 +1,14 @@ +#include "scan.h" + +unsigned int scan_ulong(register const char *s,register unsigned long *u) +{ + register unsigned int pos = 0; + register unsigned long result = 0; + register unsigned long c; + while ((c = (unsigned long) (unsigned char) (s[pos] - '0')) < 10) { + result = result * 10 + c; + ++pos; + } + *u = result; + return pos; +} diff --git a/seek.h b/seek.h new file mode 100644 index 0000000..06aad97 --- /dev/null +++ b/seek.h @@ -0,0 +1,15 @@ +#ifndef SEEK_H +#define SEEK_H + +typedef unsigned long seek_pos; + +extern seek_pos seek_cur(int); + +extern int seek_set(int,seek_pos); +extern int seek_end(int); + +extern int seek_trunc(int,seek_pos); + +#define seek_begin(fd) (seek_set((fd),(seek_pos) 0)) + +#endif diff --git a/seek_set.c b/seek_set.c new file mode 100644 index 0000000..d08d4f3 --- /dev/null +++ b/seek_set.c @@ -0,0 +1,7 @@ +#include +#include "seek.h" + +#define SET 0 /* sigh */ + +int seek_set(int fd,seek_pos pos) +{ if (lseek(fd,(off_t) pos,SET) == -1) return -1; return 0; } diff --git a/select.h1 b/select.h1 new file mode 100644 index 0000000..fe725b6 --- /dev/null +++ b/select.h1 @@ -0,0 +1,10 @@ +#ifndef SELECT_H +#define SELECT_H + +/* sysdep: -sysselect */ + +#include +#include +extern int select(); + +#endif diff --git a/select.h2 b/select.h2 new file mode 100644 index 0000000..2bc2044 --- /dev/null +++ b/select.h2 @@ -0,0 +1,11 @@ +#ifndef SELECT_H +#define SELECT_H + +/* sysdep: +sysselect */ + +#include +#include +#include +extern int select(); + +#endif diff --git a/server.c b/server.c new file mode 100644 index 0000000..e486fe1 --- /dev/null +++ b/server.c @@ -0,0 +1,116 @@ +#include "byte.h" +#include "case.h" +#include "env.h" +#include "buffer.h" +#include "strerr.h" +#include "ip4.h" +#include "uint16.h" +#include "ndelay.h" +#include "socket.h" +#include "droproot.h" +#include "qlog.h" +#include "response.h" +#include "dns.h" + +extern char *fatal; +extern char *starting; +extern int respond(char *,char *,char *); +extern void initialize(void); + +static char ip[4]; +static uint16 port; + +static char buf[513]; +static int len; + +static char *q; + +static int doit(void) +{ + unsigned int pos; + char header[12]; + char qtype[2]; + char qclass[2]; + + if (len >= sizeof buf) goto NOQ; + pos = dns_packet_copy(buf,len,0,header,12); if (!pos) goto NOQ; + if (header[2] & 128) goto NOQ; + if (header[4]) goto NOQ; + if (header[5] != 1) goto NOQ; + + pos = dns_packet_getname(buf,len,pos,&q); if (!pos) goto NOQ; + pos = dns_packet_copy(buf,len,pos,qtype,2); if (!pos) goto NOQ; + pos = dns_packet_copy(buf,len,pos,qclass,2); if (!pos) goto NOQ; + + if (!response_query(q,qtype,qclass)) goto NOQ; + response_id(header); + if (byte_equal(qclass,2,DNS_C_IN)) + response[2] |= 4; + else + if (byte_diff(qclass,2,DNS_C_ANY)) goto WEIRDCLASS; + response[3] &= ~128; + if (!(header[2] & 1)) response[2] &= ~1; + + if (header[2] & 126) goto NOTIMP; + if (byte_equal(qtype,2,DNS_T_AXFR)) goto NOTIMP; + + case_lowerb(q,dns_domain_length(q)); + if (!respond(q,qtype,ip)) { + qlog(ip,port,header,q,qtype," - "); + return 0; + } + qlog(ip,port,header,q,qtype," + "); + return 1; + + NOTIMP: + response[3] &= ~15; + response[3] |= 4; + qlog(ip,port,header,q,qtype," I "); + return 1; + + WEIRDCLASS: + response[3] &= ~15; + response[3] |= 1; + qlog(ip,port,header,q,qtype," C "); + return 1; + + NOQ: + qlog(ip,port,"\0\0","","\0\0"," / "); + return 0; +} + +int main() +{ + char *x; + int udp53; + + x = env_get("IP"); + if (!x) + strerr_die2x(111,fatal,"$IP not set"); + if (!ip4_scan(x,ip)) + strerr_die3x(111,fatal,"unable to parse IP address ",x); + + udp53 = socket_udp(); + if (udp53 == -1) + strerr_die2sys(111,fatal,"unable to create UDP socket: "); + if (socket_bind4_reuse(udp53,ip,53) == -1) + strerr_die2sys(111,fatal,"unable to bind UDP socket: "); + + droproot(fatal); + + initialize(); + + ndelay_off(udp53); + socket_tryreservein(udp53,65536); + + buffer_putsflush(buffer_2,starting); + + for (;;) { + len = socket_recv4(udp53,buf,sizeof buf,ip,&port); + if (len < 0) continue; + if (!doit()) continue; + if (response_len > 512) response_tc(); + socket_send4(udp53,response,response_len,ip,port); + /* may block for buffer space; if it fails, too bad */ + } +} diff --git a/sgetopt.c b/sgetopt.c new file mode 100644 index 0000000..e02d92d --- /dev/null +++ b/sgetopt.c @@ -0,0 +1,51 @@ +/* sgetopt.c, sgetopt.h: (yet another) improved getopt clone, outer layer +D. J. Bernstein, djb@pobox.com. +Depends on subgetopt.h, buffer.h. +No system requirements. +19991219: Switched to buffer.h. +19970208: Cleanups. +931201: Baseline. +No known patent problems. + +Documentation in sgetopt.3. +*/ + +#include "buffer.h" +#define SGETOPTNOSHORT +#include "sgetopt.h" +#define SUBGETOPTNOSHORT +#include "subgetopt.h" + +#define getopt sgetoptmine +#define optind subgetoptind +#define opterr sgetopterr +#define optproblem subgetoptproblem +#define optprogname sgetoptprogname + +int opterr = 1; +const char *optprogname = 0; + +int getopt(int argc,char **argv,const char *opts) +{ + int c; + const char *s; + + if (!optprogname) { + optprogname = *argv; + if (!optprogname) optprogname = ""; + for (s = optprogname;*s;++s) if (*s == '/') optprogname = s + 1; + } + c = subgetopt(argc,argv,opts); + if (opterr) + if (c == '?') { + char chp[2]; chp[0] = optproblem; chp[1] = '\n'; + buffer_puts(buffer_2,optprogname); + if (argv[optind] && (optind < argc)) + buffer_puts(buffer_2,": illegal option -- "); + else + buffer_puts(buffer_2,": option requires an argument -- "); + buffer_put(buffer_2,chp,2); + buffer_flush(buffer_2); + } + return c; +} diff --git a/sgetopt.h b/sgetopt.h new file mode 100644 index 0000000..234a13b --- /dev/null +++ b/sgetopt.h @@ -0,0 +1,21 @@ +#ifndef SGETOPT_H +#define SGETOPT_H + +#ifndef SGETOPTNOSHORT +#define getopt sgetoptmine +#define optarg subgetoptarg +#define optind subgetoptind +#define optpos subgetoptpos +#define opterr sgetopterr +#define optproblem subgetoptproblem +#define optprogname sgetoptprogname +#define opteof subgetoptdone +#endif + +#include "subgetopt.h" + +extern int sgetoptmine(int,char **,const char *); +extern int sgetopterr; +extern const char *sgetoptprogname; + +#endif diff --git a/socket.h b/socket.h new file mode 100644 index 0000000..95e2a7c --- /dev/null +++ b/socket.h @@ -0,0 +1,22 @@ +#ifndef SOCKET_H +#define SOCKET_H + +#include "uint16.h" + +extern int socket_tcp(void); +extern int socket_udp(void); + +extern int socket_connect4(int,const char *,uint16); +extern int socket_connected(int); +extern int socket_bind4(int,char *,uint16); +extern int socket_bind4_reuse(int,char *,uint16); +extern int socket_listen(int,int); +extern int socket_accept4(int,char *,uint16 *); +extern int socket_recv4(int,char *,int,char *,uint16 *); +extern int socket_send4(int,const char *,int,const char *,uint16); +extern int socket_local4(int,char *,uint16 *); +extern int socket_remote4(int,char *,uint16 *); + +extern void socket_tryreservein(int,int); + +#endif diff --git a/socket_accept.c b/socket_accept.c new file mode 100644 index 0000000..22c44d4 --- /dev/null +++ b/socket_accept.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include "byte.h" +#include "socket.h" + +int socket_accept4(int s,char ip[4],uint16 *port) +{ + struct sockaddr_in sa; + int dummy = sizeof sa; + int fd; + + fd = accept(s,(struct sockaddr *) &sa,&dummy); + if (fd == -1) return -1; + + byte_copy(ip,4,(char *) &sa.sin_addr); + uint16_unpack_big((char *) &sa.sin_port,port); + + return fd; +} diff --git a/socket_bind.c b/socket_bind.c new file mode 100644 index 0000000..20830a4 --- /dev/null +++ b/socket_bind.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include "byte.h" +#include "socket.h" + +int socket_bind4(int s,char ip[4],uint16 port) +{ + struct sockaddr_in sa; + + byte_zero(&sa,sizeof sa); + sa.sin_family = AF_INET; + uint16_pack_big((char *) &sa.sin_port,port); + byte_copy((char *) &sa.sin_addr,4,ip); + + return bind(s,(struct sockaddr *) &sa,sizeof sa); +} + +int socket_bind4_reuse(int s,char ip[4],uint16 port) +{ + int opt = 1; + setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof opt); + return socket_bind4(s,ip,port); +} + +void socket_tryreservein(int s,int size) +{ + while (size >= 1024) { + if (setsockopt(s,SOL_SOCKET,SO_RCVBUF,&size,sizeof size) == 0) return; + size -= (size >> 5); + } +} diff --git a/socket_conn.c b/socket_conn.c new file mode 100644 index 0000000..46423cb --- /dev/null +++ b/socket_conn.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include "byte.h" +#include "socket.h" + +int socket_connect4(int s,const char ip[4],uint16 port) +{ + struct sockaddr_in sa; + + byte_zero(&sa,sizeof sa); + sa.sin_family = AF_INET; + uint16_pack_big((char *) &sa.sin_port,port); + byte_copy((char *) &sa.sin_addr,4,ip); + + return connect(s,(struct sockaddr *) &sa,sizeof sa); +} + +int socket_connected(int s) +{ + struct sockaddr_in sa; + int dummy; + char ch; + + dummy = sizeof sa; + if (getpeername(s,(struct sockaddr *) &sa,&dummy) == -1) { + read(s,&ch,1); /* sets errno */ + return 0; + } + return 1; +} diff --git a/socket_listen.c b/socket_listen.c new file mode 100644 index 0000000..abdb483 --- /dev/null +++ b/socket_listen.c @@ -0,0 +1,10 @@ +#include +#include +#include +#include +#include "socket.h" + +int socket_listen(int s,int backlog) +{ + return listen(s,backlog); +} diff --git a/socket_recv.c b/socket_recv.c new file mode 100644 index 0000000..8bc59c5 --- /dev/null +++ b/socket_recv.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include "byte.h" +#include "socket.h" + +int socket_recv4(int s,char *buf,int len,char ip[4],uint16 *port) +{ + struct sockaddr_in sa; + int dummy = sizeof sa; + int r; + + r = recvfrom(s,buf,len,0,(struct sockaddr *) &sa,&dummy); + if (r == -1) return -1; + + byte_copy(ip,4,(char *) &sa.sin_addr); + uint16_unpack_big((char *) &sa.sin_port,port); + + return r; +} diff --git a/socket_send.c b/socket_send.c new file mode 100644 index 0000000..9ffbd5a --- /dev/null +++ b/socket_send.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include "byte.h" +#include "socket.h" + +int socket_send4(int s,const char *buf,int len,const char ip[4],uint16 port) +{ + struct sockaddr_in sa; + + byte_zero(&sa,sizeof sa); + sa.sin_family = AF_INET; + uint16_pack_big((char *) &sa.sin_port,port); + byte_copy((char *) &sa.sin_addr,4,ip); + + return sendto(s,buf,len,0,(struct sockaddr *) &sa,sizeof sa); +} diff --git a/socket_tcp.c b/socket_tcp.c new file mode 100644 index 0000000..c200e2b --- /dev/null +++ b/socket_tcp.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include +#include +#include "ndelay.h" +#include "socket.h" + +int socket_tcp(void) +{ + int s; + + s = socket(AF_INET,SOCK_STREAM,0); + if (s == -1) return -1; + if (ndelay_on(s) == -1) { close(s); return -1; } + return s; +} diff --git a/socket_udp.c b/socket_udp.c new file mode 100644 index 0000000..d71d3e4 --- /dev/null +++ b/socket_udp.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include +#include +#include "ndelay.h" +#include "socket.h" + +int socket_udp(void) +{ + int s; + + s = socket(AF_INET,SOCK_DGRAM,0); + if (s == -1) return -1; + if (ndelay_on(s) == -1) { close(s); return -1; } + return s; +} diff --git a/str.h b/str.h new file mode 100644 index 0000000..a2a4b75 --- /dev/null +++ b/str.h @@ -0,0 +1,14 @@ +#ifndef STR_H +#define STR_H + +extern unsigned int str_copy(char *,const char *); +extern int str_diff(const char *,const char *); +extern int str_diffn(const char *,const char *,unsigned int); +extern unsigned int str_len(const char *); +extern unsigned int str_chr(const char *,int); +extern unsigned int str_rchr(const char *,int); +extern int str_start(const char *,const char *); + +#define str_equal(s,t) (!str_diff((s),(t))) + +#endif diff --git a/str_chr.c b/str_chr.c new file mode 100644 index 0000000..042dfa2 --- /dev/null +++ b/str_chr.c @@ -0,0 +1,17 @@ +#include "str.h" + +unsigned int str_chr(register const char *s,int c) +{ + register char ch; + register const char *t; + + ch = c; + t = s; + for (;;) { + if (!*t) break; if (*t == ch) break; ++t; + if (!*t) break; if (*t == ch) break; ++t; + if (!*t) break; if (*t == ch) break; ++t; + if (!*t) break; if (*t == ch) break; ++t; + } + return t - s; +} diff --git a/str_diff.c b/str_diff.c new file mode 100644 index 0000000..071e7f5 --- /dev/null +++ b/str_diff.c @@ -0,0 +1,15 @@ +#include "str.h" + +int str_diff(register const char *s,register const char *t) +{ + register char x; + + for (;;) { + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + x = *s; if (x != *t) break; if (!x) break; ++s; ++t; + } + return ((int)(unsigned int)(unsigned char) x) + - ((int)(unsigned int)(unsigned char) *t); +} diff --git a/str_len.c b/str_len.c new file mode 100644 index 0000000..8411ebf --- /dev/null +++ b/str_len.c @@ -0,0 +1,14 @@ +#include "str.h" + +unsigned int str_len(const char *s) +{ + register const char *t; + + t = s; + for (;;) { + if (!*t) return t - s; ++t; + if (!*t) return t - s; ++t; + if (!*t) return t - s; ++t; + if (!*t) return t - s; ++t; + } +} diff --git a/str_rchr.c b/str_rchr.c new file mode 100644 index 0000000..b128c4c --- /dev/null +++ b/str_rchr.c @@ -0,0 +1,20 @@ +#include "str.h" + +unsigned int str_rchr(register const char *s,int c) +{ + register char ch; + register const char *t; + register const char *u; + + ch = c; + t = s; + u = 0; + for (;;) { + if (!*t) break; if (*t == ch) u = t; ++t; + if (!*t) break; if (*t == ch) u = t; ++t; + if (!*t) break; if (*t == ch) u = t; ++t; + if (!*t) break; if (*t == ch) u = t; ++t; + } + if (!u) u = t; + return u - s; +} diff --git a/str_start.c b/str_start.c new file mode 100644 index 0000000..757189d --- /dev/null +++ b/str_start.c @@ -0,0 +1,13 @@ +#include "str.h" + +int str_start(register const char *s,register const char *t) +{ + register char x; + + for (;;) { + x = *t++; if (!x) return 1; if (x != *s++) return 0; + x = *t++; if (!x) return 1; if (x != *s++) return 0; + x = *t++; if (!x) return 1; if (x != *s++) return 0; + x = *t++; if (!x) return 1; if (x != *s++) return 0; + } +} diff --git a/stralloc.h b/stralloc.h new file mode 100644 index 0000000..d88f631 --- /dev/null +++ b/stralloc.h @@ -0,0 +1,29 @@ +#ifndef STRALLOC_H +#define STRALLOC_H + +#include "gen_alloc.h" + +GEN_ALLOC_typedef(stralloc,char,s,len,a) + +extern int stralloc_ready(stralloc *,unsigned int); +extern int stralloc_readyplus(stralloc *,unsigned int); +extern int stralloc_copy(stralloc *,const stralloc *); +extern int stralloc_cat(stralloc *,const stralloc *); +extern int stralloc_copys(stralloc *,const char *); +extern int stralloc_cats(stralloc *,const char *); +extern int stralloc_copyb(stralloc *,const char *,unsigned int); +extern int stralloc_catb(stralloc *,const char *,unsigned int); +extern int stralloc_append(stralloc *,const char *); /* beware: this takes a pointer to 1 char */ +extern int stralloc_starts(stralloc *,const char *); + +#define stralloc_0(sa) stralloc_append(sa,"") + +extern int stralloc_catulong0(stralloc *,unsigned long,unsigned int); +extern int stralloc_catlong0(stralloc *,long,unsigned int); + +#define stralloc_catlong(sa,l) (stralloc_catlong0((sa),(l),0)) +#define stralloc_catuint0(sa,i,n) (stralloc_catulong0((sa),(i),(n))) +#define stralloc_catint0(sa,i,n) (stralloc_catlong0((sa),(i),(n))) +#define stralloc_catint(sa,i) (stralloc_catlong0((sa),(i),0)) + +#endif diff --git a/stralloc_cat.c b/stralloc_cat.c new file mode 100644 index 0000000..9bbb119 --- /dev/null +++ b/stralloc_cat.c @@ -0,0 +1,7 @@ +#include "byte.h" +#include "stralloc.h" + +int stralloc_cat(stralloc *sato,const stralloc *safrom) +{ + return stralloc_catb(sato,safrom->s,safrom->len); +} diff --git a/stralloc_catb.c b/stralloc_catb.c new file mode 100644 index 0000000..b606e32 --- /dev/null +++ b/stralloc_catb.c @@ -0,0 +1,12 @@ +#include "stralloc.h" +#include "byte.h" + +int stralloc_catb(stralloc *sa,const char *s,unsigned int n) +{ + if (!sa->s) return stralloc_copyb(sa,s,n); + if (!stralloc_readyplus(sa,n + 1)) return 0; + byte_copy(sa->s + sa->len,n,s); + sa->len += n; + sa->s[sa->len] = 'Z'; /* ``offensive programming'' */ + return 1; +} diff --git a/stralloc_cats.c b/stralloc_cats.c new file mode 100644 index 0000000..92cb66e --- /dev/null +++ b/stralloc_cats.c @@ -0,0 +1,8 @@ +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_cats(stralloc *sa,const char *s) +{ + return stralloc_catb(sa,s,str_len(s)); +} diff --git a/stralloc_copy.c b/stralloc_copy.c new file mode 100644 index 0000000..6b9ae42 --- /dev/null +++ b/stralloc_copy.c @@ -0,0 +1,7 @@ +#include "byte.h" +#include "stralloc.h" + +int stralloc_copy(stralloc *sato,const stralloc *safrom) +{ + return stralloc_copyb(sato,safrom->s,safrom->len); +} diff --git a/stralloc_eady.c b/stralloc_eady.c new file mode 100644 index 0000000..3a31f4b --- /dev/null +++ b/stralloc_eady.c @@ -0,0 +1,6 @@ +#include "alloc.h" +#include "stralloc.h" +#include "gen_allocdefs.h" + +GEN_ALLOC_ready(stralloc,char,s,len,a,i,n,x,30,stralloc_ready) +GEN_ALLOC_readyplus(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus) diff --git a/stralloc_num.c b/stralloc_num.c new file mode 100644 index 0000000..64b25fa --- /dev/null +++ b/stralloc_num.c @@ -0,0 +1,29 @@ +#include "stralloc.h" + +int stralloc_catulong0(stralloc *sa,unsigned long u,unsigned int n) +{ + unsigned int len; + unsigned long q; + char *s; + + len = 1; + q = u; + while (q > 9) { ++len; q /= 10; } + if (len < n) len = n; + + if (!stralloc_readyplus(sa,len)) return 0; + s = sa->s + sa->len; + sa->len += len; + while (len) { s[--len] = '0' + (u % 10); u /= 10; } + + return 1; +} + +int stralloc_catlong0(stralloc *sa,long l,unsigned int n) +{ + if (l < 0) { + if (!stralloc_append(sa,"-")) return 0; + l = -l; + } + return stralloc_catulong0(sa,l,n); +} diff --git a/stralloc_opyb.c b/stralloc_opyb.c new file mode 100644 index 0000000..593029d --- /dev/null +++ b/stralloc_opyb.c @@ -0,0 +1,11 @@ +#include "stralloc.h" +#include "byte.h" + +int stralloc_copyb(stralloc *sa,const char *s,unsigned int n) +{ + if (!stralloc_ready(sa,n + 1)) return 0; + byte_copy(sa->s,n,s); + sa->len = n; + sa->s[n] = 'Z'; /* ``offensive programming'' */ + return 1; +} diff --git a/stralloc_opys.c b/stralloc_opys.c new file mode 100644 index 0000000..860c7e0 --- /dev/null +++ b/stralloc_opys.c @@ -0,0 +1,8 @@ +#include "byte.h" +#include "str.h" +#include "stralloc.h" + +int stralloc_copys(stralloc *sa,const char *s) +{ + return stralloc_copyb(sa,s,str_len(s)); +} diff --git a/stralloc_pend.c b/stralloc_pend.c new file mode 100644 index 0000000..a3443b8 --- /dev/null +++ b/stralloc_pend.c @@ -0,0 +1,5 @@ +#include "alloc.h" +#include "stralloc.h" +#include "gen_allocdefs.h" + +GEN_ALLOC_append(stralloc,char,s,len,a,i,n,x,30,stralloc_readyplus,stralloc_append) diff --git a/strerr.h b/strerr.h new file mode 100644 index 0000000..6c4895a --- /dev/null +++ b/strerr.h @@ -0,0 +1,78 @@ +#ifndef STRERR_H +#define STRERR_H + +struct strerr { + struct strerr *who; + const char *x; + const char *y; + const char *z; +} ; + +extern struct strerr strerr_sys; +extern void strerr_sysinit(void); + +extern const char *strerr(const struct strerr *); +extern void strerr_warn(const char *,const char *,const char *,const char *,const char *,const char *,const struct strerr *); +extern void strerr_die(int,const char *,const char *,const char *,const char *,const char *,const char *,const struct strerr *); + +#define STRERR(r,se,a) \ +{ se.who = 0; se.x = a; se.y = 0; se.z = 0; return r; } + +#define STRERR_SYS(r,se,a) \ +{ se.who = &strerr_sys; se.x = a; se.y = 0; se.z = 0; return r; } +#define STRERR_SYS3(r,se,a,b,c) \ +{ se.who = &strerr_sys; se.x = a; se.y = b; se.z = c; return r; } + +#define strerr_warn6(x1,x2,x3,x4,x5,x6,se) \ +strerr_warn((x1),(x2),(x3),(x4),(x5),(x6),(se)) +#define strerr_warn5(x1,x2,x3,x4,x5,se) \ +strerr_warn((x1),(x2),(x3),(x4),(x5),0,(se)) +#define strerr_warn4(x1,x2,x3,x4,se) \ +strerr_warn((x1),(x2),(x3),(x4),0,0,(se)) +#define strerr_warn3(x1,x2,x3,se) \ +strerr_warn((x1),(x2),(x3),0,0,0,(se)) +#define strerr_warn2(x1,x2,se) \ +strerr_warn((x1),(x2),0,0,0,0,(se)) +#define strerr_warn1(x1,se) \ +strerr_warn((x1),0,0,0,0,0,(se)) + +#define strerr_die6(e,x1,x2,x3,x4,x5,x6,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),(se)) +#define strerr_die5(e,x1,x2,x3,x4,x5,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),0,(se)) +#define strerr_die4(e,x1,x2,x3,x4,se) \ +strerr_die((e),(x1),(x2),(x3),(x4),0,0,(se)) +#define strerr_die3(e,x1,x2,x3,se) \ +strerr_die((e),(x1),(x2),(x3),0,0,0,(se)) +#define strerr_die2(e,x1,x2,se) \ +strerr_die((e),(x1),(x2),0,0,0,0,(se)) +#define strerr_die1(e,x1,se) \ +strerr_die((e),(x1),0,0,0,0,0,(se)) + +#define strerr_die6sys(e,x1,x2,x3,x4,x5,x6) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),&strerr_sys) +#define strerr_die5sys(e,x1,x2,x3,x4,x5) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),0,&strerr_sys) +#define strerr_die4sys(e,x1,x2,x3,x4) \ +strerr_die((e),(x1),(x2),(x3),(x4),0,0,&strerr_sys) +#define strerr_die3sys(e,x1,x2,x3) \ +strerr_die((e),(x1),(x2),(x3),0,0,0,&strerr_sys) +#define strerr_die2sys(e,x1,x2) \ +strerr_die((e),(x1),(x2),0,0,0,0,&strerr_sys) +#define strerr_die1sys(e,x1) \ +strerr_die((e),(x1),0,0,0,0,0,&strerr_sys) + +#define strerr_die6x(e,x1,x2,x3,x4,x5,x6) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),(x6),0) +#define strerr_die5x(e,x1,x2,x3,x4,x5) \ +strerr_die((e),(x1),(x2),(x3),(x4),(x5),0,0) +#define strerr_die4x(e,x1,x2,x3,x4) \ +strerr_die((e),(x1),(x2),(x3),(x4),0,0,0) +#define strerr_die3x(e,x1,x2,x3) \ +strerr_die((e),(x1),(x2),(x3),0,0,0,0) +#define strerr_die2x(e,x1,x2) \ +strerr_die((e),(x1),(x2),0,0,0,0,0) +#define strerr_die1x(e,x1) \ +strerr_die((e),(x1),0,0,0,0,0,0) + +#endif diff --git a/strerr_die.c b/strerr_die.c new file mode 100644 index 0000000..ad93eb4 --- /dev/null +++ b/strerr_die.c @@ -0,0 +1,31 @@ +#include "buffer.h" +#include "exit.h" +#include "strerr.h" + +void strerr_warn(const char *x1,const char *x2,const char *x3,const char *x4,const char *x5,const char *x6,const struct strerr *se) +{ + strerr_sysinit(); + + if (x1) buffer_puts(buffer_2,x1); + if (x2) buffer_puts(buffer_2,x2); + if (x3) buffer_puts(buffer_2,x3); + if (x4) buffer_puts(buffer_2,x4); + if (x5) buffer_puts(buffer_2,x5); + if (x6) buffer_puts(buffer_2,x6); + + while(se) { + if (se->x) buffer_puts(buffer_2,se->x); + if (se->y) buffer_puts(buffer_2,se->y); + if (se->z) buffer_puts(buffer_2,se->z); + se = se->who; + } + + buffer_puts(buffer_2,"\n"); + buffer_flush(buffer_2); +} + +void strerr_die(int e,const char *x1,const char *x2,const char *x3,const char *x4,const char *x5,const char *x6,const struct strerr *se) +{ + strerr_warn(x1,x2,x3,x4,x5,x6,se); + _exit(e); +} diff --git a/strerr_sys.c b/strerr_sys.c new file mode 100644 index 0000000..b484197 --- /dev/null +++ b/strerr_sys.c @@ -0,0 +1,12 @@ +#include "error.h" +#include "strerr.h" + +struct strerr strerr_sys; + +void strerr_sysinit(void) +{ + strerr_sys.who = 0; + strerr_sys.x = error_str(errno); + strerr_sys.y = ""; + strerr_sys.z = ""; +} diff --git a/subgetopt.c b/subgetopt.c new file mode 100644 index 0000000..96c2631 --- /dev/null +++ b/subgetopt.c @@ -0,0 +1,65 @@ +#define SUBGETOPTNOSHORT +#include "subgetopt.h" + +#define sgopt subgetopt +#define optind subgetoptind +#define optpos subgetoptpos +#define optarg subgetoptarg +#define optproblem subgetoptproblem +#define optdone subgetoptdone + +int optind = 1; +int optpos = 0; +char *optarg = 0; +int optproblem = 0; +int optdone = SUBGETOPTDONE; + +int sgopt(int argc,char **argv,const char *opts) +{ + int c; + const char *s; + + optarg = 0; + if (!argv || (optind >= argc) || !argv[optind]) return optdone; + if (optpos && !argv[optind][optpos]) { + ++optind; + optpos = 0; + if ((optind >= argc) || !argv[optind]) return optdone; + } + if (!optpos) { + if (argv[optind][0] != '-') return optdone; + ++optpos; + c = argv[optind][1]; + if ((c == '-') || (c == 0)) { + if (c) ++optind; + optpos = 0; + return optdone; + } + /* otherwise c is reassigned below */ + } + c = argv[optind][optpos]; + ++optpos; + s = opts; + while (*s) { + if (c == *s) { + if (s[1] == ':') { + optarg = argv[optind] + optpos; + ++optind; + optpos = 0; + if (!*optarg) { + optarg = argv[optind]; + if ((optind >= argc) || !optarg) { /* argument past end */ + optproblem = c; + return '?'; + } + ++optind; + } + } + return c; + } + ++s; + if (*s == ':') ++s; + } + optproblem = c; + return '?'; +} diff --git a/subgetopt.h b/subgetopt.h new file mode 100644 index 0000000..65da0fb --- /dev/null +++ b/subgetopt.h @@ -0,0 +1,24 @@ +#ifndef SUBGETOPT_H +#define SUBGETOPT_H + +#ifndef SUBGETOPTNOSHORT +#define sgopt subgetopt +#define sgoptarg subgetoptarg +#define sgoptind subgetoptind +#define sgoptpos subgetoptpos +#define sgoptproblem subgetoptproblem +#define sgoptprogname subgetoptprogname +#define sgoptdone subgetoptdone +#endif + +#define SUBGETOPTDONE -1 + +extern int subgetopt(int,char **,const char *); +extern char *subgetoptarg; +extern int subgetoptind; +extern int subgetoptpos; +extern int subgetoptproblem; +extern char *subgetoptprogname; +extern int subgetoptdone; + +#endif diff --git a/tai.h b/tai.h new file mode 100644 index 0000000..b8db5e5 --- /dev/null +++ b/tai.h @@ -0,0 +1,26 @@ +#ifndef TAI_H +#define TAI_H + +#include "uint64.h" + +struct tai { + uint64 x; +} ; + +#define tai_unix(t,u) ((void) ((t)->x = 4611686018427387914ULL + (uint64) (u))) + +extern void tai_now(struct tai *); + +#define tai_approx(t) ((double) ((t)->x)) + +extern void tai_add(struct tai *,const struct tai *,const struct tai *); +extern void tai_sub(struct tai *,const struct tai *,const struct tai *); +#define tai_less(t,u) ((t)->x < (u)->x) + +#define TAI_PACK 8 +extern void tai_pack(char *,const struct tai *); +extern void tai_unpack(const char *,struct tai *); + +extern void tai_uint(struct tai *,unsigned int); + +#endif diff --git a/tai_add.c b/tai_add.c new file mode 100644 index 0000000..4226ab4 --- /dev/null +++ b/tai_add.c @@ -0,0 +1,6 @@ +#include "tai.h" + +void tai_add(struct tai *t,const struct tai *u,const struct tai *v) +{ + t->x = u->x + v->x; +} diff --git a/tai_now.c b/tai_now.c new file mode 100644 index 0000000..91e84da --- /dev/null +++ b/tai_now.c @@ -0,0 +1,7 @@ +#include +#include "tai.h" + +void tai_now(struct tai *t) +{ + tai_unix(t,time((time_t *) 0)); +} diff --git a/tai_pack.c b/tai_pack.c new file mode 100644 index 0000000..0a2bc06 --- /dev/null +++ b/tai_pack.c @@ -0,0 +1,16 @@ +#include "tai.h" + +void tai_pack(char *s,const struct tai *t) +{ + uint64 x; + + x = t->x; + s[7] = x & 255; x >>= 8; + s[6] = x & 255; x >>= 8; + s[5] = x & 255; x >>= 8; + s[4] = x & 255; x >>= 8; + s[3] = x & 255; x >>= 8; + s[2] = x & 255; x >>= 8; + s[1] = x & 255; x >>= 8; + s[0] = x; +} diff --git a/tai_sub.c b/tai_sub.c new file mode 100644 index 0000000..6ebf7b2 --- /dev/null +++ b/tai_sub.c @@ -0,0 +1,6 @@ +#include "tai.h" + +void tai_sub(struct tai *t,const struct tai *u,const struct tai *v) +{ + t->x = u->x - v->x; +} diff --git a/tai_uint.c b/tai_uint.c new file mode 100644 index 0000000..b01184c --- /dev/null +++ b/tai_uint.c @@ -0,0 +1,6 @@ +#include "tai.h" + +void tai_uint(struct tai *t,unsigned int u) +{ + t->x = u; +} diff --git a/tai_unpack.c b/tai_unpack.c new file mode 100644 index 0000000..b725ae0 --- /dev/null +++ b/tai_unpack.c @@ -0,0 +1,16 @@ +#include "tai.h" + +void tai_unpack(const char *s,struct tai *t) +{ + uint64 x; + + x = (unsigned char) s[0]; + x <<= 8; x += (unsigned char) s[1]; + x <<= 8; x += (unsigned char) s[2]; + x <<= 8; x += (unsigned char) s[3]; + x <<= 8; x += (unsigned char) s[4]; + x <<= 8; x += (unsigned char) s[5]; + x <<= 8; x += (unsigned char) s[6]; + x <<= 8; x += (unsigned char) s[7]; + t->x = x; +} diff --git a/taia.h b/taia.h new file mode 100644 index 0000000..4d37ef2 --- /dev/null +++ b/taia.h @@ -0,0 +1,34 @@ +#ifndef TAIA_H +#define TAIA_H + +#include "tai.h" + +struct taia { + struct tai sec; + unsigned long nano; /* 0...999999999 */ + unsigned long atto; /* 0...999999999 */ +} ; + +extern void taia_tai(const struct taia *,struct tai *); + +extern void taia_now(struct taia *); + +extern double taia_approx(const struct taia *); +extern double taia_frac(const struct taia *); + +extern void taia_add(struct taia *,const struct taia *,const struct taia *); +extern void taia_addsec(struct taia *,const struct taia *,int); +extern void taia_sub(struct taia *,const struct taia *,const struct taia *); +extern void taia_half(struct taia *,const struct taia *); +extern int taia_less(const struct taia *,const struct taia *); + +#define TAIA_PACK 16 +extern void taia_pack(char *,const struct taia *); +extern void taia_unpack(const char *,struct taia *); + +#define TAIA_FMTFRAC 19 +extern unsigned int taia_fmtfrac(char *,const struct taia *); + +extern void taia_uint(struct taia *,unsigned int); + +#endif diff --git a/taia_add.c b/taia_add.c new file mode 100644 index 0000000..3044a26 --- /dev/null +++ b/taia_add.c @@ -0,0 +1,18 @@ +#include "taia.h" + +/* XXX: breaks tai encapsulation */ + +void taia_add(struct taia *t,const struct taia *u,const struct taia *v) +{ + t->sec.x = u->sec.x + v->sec.x; + t->nano = u->nano + v->nano; + t->atto = u->atto + v->atto; + if (t->atto > 999999999UL) { + t->atto -= 1000000000UL; + ++t->nano; + } + if (t->nano > 999999999UL) { + t->nano -= 1000000000UL; + ++t->sec.x; + } +} diff --git a/taia_approx.c b/taia_approx.c new file mode 100644 index 0000000..2a3b429 --- /dev/null +++ b/taia_approx.c @@ -0,0 +1,6 @@ +#include "taia.h" + +double taia_approx(const struct taia *t) +{ + return tai_approx(&t->sec) + taia_frac(t); +} diff --git a/taia_frac.c b/taia_frac.c new file mode 100644 index 0000000..b6b48bc --- /dev/null +++ b/taia_frac.c @@ -0,0 +1,6 @@ +#include "taia.h" + +double taia_frac(const struct taia *t) +{ + return (t->atto * 0.000000001 + t->nano) * 0.000000001; +} diff --git a/taia_less.c b/taia_less.c new file mode 100644 index 0000000..2d889c8 --- /dev/null +++ b/taia_less.c @@ -0,0 +1,12 @@ +#include "taia.h" + +/* XXX: breaks tai encapsulation */ + +int taia_less(const struct taia *t,const struct taia *u) +{ + if (t->sec.x < u->sec.x) return 1; + if (t->sec.x > u->sec.x) return 0; + if (t->nano < u->nano) return 1; + if (t->nano > u->nano) return 0; + return t->atto < u->atto; +} diff --git a/taia_now.c b/taia_now.c new file mode 100644 index 0000000..ccc260d --- /dev/null +++ b/taia_now.c @@ -0,0 +1,12 @@ +#include +#include +#include "taia.h" + +void taia_now(struct taia *t) +{ + struct timeval now; + gettimeofday(&now,(struct timezone *) 0); + tai_unix(&t->sec,now.tv_sec); + t->nano = 1000 * now.tv_usec + 500; + t->atto = 0; +} diff --git a/taia_pack.c b/taia_pack.c new file mode 100644 index 0000000..89e2c16 --- /dev/null +++ b/taia_pack.c @@ -0,0 +1,20 @@ +#include "taia.h" + +void taia_pack(char *s,const struct taia *t) +{ + unsigned long x; + + tai_pack(s,&t->sec); + s += 8; + + x = t->atto; + s[7] = x & 255; x >>= 8; + s[6] = x & 255; x >>= 8; + s[5] = x & 255; x >>= 8; + s[4] = x; + x = t->nano; + s[3] = x & 255; x >>= 8; + s[2] = x & 255; x >>= 8; + s[1] = x & 255; x >>= 8; + s[0] = x; +} diff --git a/taia_sub.c b/taia_sub.c new file mode 100644 index 0000000..6944689 --- /dev/null +++ b/taia_sub.c @@ -0,0 +1,21 @@ +#include "taia.h" + +/* XXX: breaks tai encapsulation */ + +void taia_sub(struct taia *t,const struct taia *u,const struct taia *v) +{ + unsigned long unano = u->nano; + unsigned long uatto = u->atto; + + t->sec.x = u->sec.x - v->sec.x; + t->nano = unano - v->nano; + t->atto = uatto - v->atto; + if (t->atto > uatto) { + t->atto += 1000000000UL; + --t->nano; + } + if (t->nano > unano) { + t->nano += 1000000000UL; + --t->sec.x; + } +} diff --git a/taia_tai.c b/taia_tai.c new file mode 100644 index 0000000..ef4d4fc --- /dev/null +++ b/taia_tai.c @@ -0,0 +1,6 @@ +#include "taia.h" + +void taia_tai(const struct taia *ta,struct tai *t) +{ + *t = ta->sec; +} diff --git a/taia_uint.c b/taia_uint.c new file mode 100644 index 0000000..167936c --- /dev/null +++ b/taia_uint.c @@ -0,0 +1,10 @@ +#include "taia.h" + +/* XXX: breaks tai encapsulation */ + +void taia_uint(struct taia *t,unsigned int s) +{ + t->sec.x = s; + t->nano = 0; + t->atto = 0; +} diff --git a/tdlookup.c b/tdlookup.c new file mode 100644 index 0000000..da7420d --- /dev/null +++ b/tdlookup.c @@ -0,0 +1,310 @@ +#include +#include "uint16.h" +#include "open.h" +#include "tai.h" +#include "cdb.h" +#include "byte.h" +#include "case.h" +#include "dns.h" +#include "seek.h" +#include "response.h" + +static int want(const char *owner,const char type[2]) +{ + unsigned int pos; + static char *d; + char x[10]; + uint16 datalen; + + pos = dns_packet_skipname(response,response_len,12); if (!pos) return 0; + pos += 4; + + while (pos < response_len) { + pos = dns_packet_getname(response,response_len,pos,&d); if (!pos) return 0; + pos = dns_packet_copy(response,response_len,pos,x,10); if (!pos) return 0; + if (dns_domain_equal(d,owner)) + if (byte_equal(type,2,x)) + return 0; + uint16_unpack_big(x + 8,&datalen); + pos += datalen; + } + return 1; +} + +static char *d1; + +static char clientloc[2]; +static struct tai now; +static struct cdb c; + +static char data[32767]; +static uint32 dlen; +static unsigned int dpos; +static char type[2]; +static uint32 ttl; + +static int find(char *d,int flagwild) +{ + int r; + char ch; + struct tai cutoff; + char ttd[8]; + char ttlstr[4]; + char recordloc[2]; + double newttl; + + for (;;) { + r = cdb_findnext(&c,d,dns_domain_length(d)); + if (r <= 0) return r; + dlen = cdb_datalen(&c); + if (dlen > sizeof data) return -1; + if (cdb_read(&c,data,dlen,cdb_datapos(&c)) == -1) return -1; + dpos = dns_packet_copy(data,dlen,0,type,2); if (!dpos) return -1; + dpos = dns_packet_copy(data,dlen,dpos,&ch,1); if (!dpos) return -1; + if ((ch == '=' + 1) || (ch == '*' + 1)) { + --ch; + dpos = dns_packet_copy(data,dlen,dpos,recordloc,2); if (!dpos) return -1; + if (byte_diff(recordloc,2,clientloc)) continue; + } + if (flagwild != (ch == '*')) continue; + dpos = dns_packet_copy(data,dlen,dpos,ttlstr,4); if (!dpos) return -1; + uint32_unpack_big(ttlstr,&ttl); + dpos = dns_packet_copy(data,dlen,dpos,ttd,8); if (!dpos) return -1; + if (byte_diff(ttd,8,"\0\0\0\0\0\0\0\0")) { + tai_unpack(ttd,&cutoff); + if (ttl == 0) { + if (tai_less(&cutoff,&now)) continue; + tai_sub(&cutoff,&cutoff,&now); + newttl = tai_approx(&cutoff); + if (newttl <= 2.0) newttl = 2.0; + if (newttl >= 3600.0) newttl = 3600.0; + ttl = newttl; + } + else + if (!tai_less(&cutoff,&now)) continue; + } + return 1; + } +} + +static int dobytes(unsigned int len) +{ + char buf[20]; + if (len > 20) return 0; + dpos = dns_packet_copy(data,dlen,dpos,buf,len); + if (!dpos) return 0; + return response_addbytes(buf,len); +} + +static int doname(void) +{ + dpos = dns_packet_getname(data,dlen,dpos,&d1); + if (!dpos) return 0; + return response_addname(d1); +} + +static int doit(char *q,char qtype[2]) +{ + unsigned int bpos; + unsigned int anpos; + unsigned int aupos; + unsigned int arpos; + char *control; + char *wild; + int flaggavesoa; + int flagfound; + int r; + int flagns; + int flagauthoritative; + char x[20]; + uint16 u16; + char addr[8][4]; + int addrnum; + uint32 addrttl; + int i; + + anpos = response_len; + + control = q; + for (;;) { + flagns = 0; + flagauthoritative = 0; + cdb_findstart(&c); + while (r = find(control,0)) { + if (r == -1) return 0; + if (byte_equal(type,2,DNS_T_SOA)) flagauthoritative = 1; + if (byte_equal(type,2,DNS_T_NS)) flagns = 1; + } + if (flagns) break; + if (!*control) return 0; /* q is not within our bailiwick */ + control += *control; + control += 1; + } + + if (!flagauthoritative) { + response[2] &= ~4; + goto AUTHORITY; /* q is in a child zone */ + } + + + flaggavesoa = 0; + flagfound = 0; + wild = q; + + for (;;) { + addrnum = 0; + addrttl = 0; + cdb_findstart(&c); + while (r = find(wild,wild != q)) { + if (r == -1) return 0; + flagfound = 1; + if (flaggavesoa && byte_equal(type,2,DNS_T_SOA)) continue; + if (byte_diff(type,2,qtype) && byte_diff(qtype,2,DNS_T_ANY) && byte_diff(type,2,DNS_T_CNAME)) continue; + if (byte_equal(type,2,DNS_T_A) && (dlen - dpos == 4)) { + addrttl = ttl; + i = dns_random(addrnum + 1); + if (i < 8) { + if ((i < addrnum) && (addrnum < 8)) + byte_copy(addr[addrnum],4,addr[i]); + byte_copy(addr[i],4,data + dpos); + } + if (addrnum < 1000000) ++addrnum; + continue; + } + if (!response_rstart(q,type,ttl)) return 0; + if (byte_equal(type,2,DNS_T_NS) || byte_equal(type,2,DNS_T_CNAME) || byte_equal(type,2,DNS_T_PTR)) { + if (!doname()) return 0; + } + else if (byte_equal(type,2,DNS_T_MX)) { + if (!dobytes(2)) return 0; + if (!doname()) return 0; + } + else if (byte_equal(type,2,DNS_T_SOA)) { + if (!doname()) return 0; + if (!doname()) return 0; + if (!dobytes(20)) return 0; + flaggavesoa = 1; + } + else + if (!response_addbytes(data + dpos,dlen - dpos)) return 0; + response_rfinish(RESPONSE_ANSWER); + } + for (i = 0;i < addrnum;++i) + if (i < 8) { + if (!response_rstart(q,DNS_T_A,addrttl)) return 0; + if (!response_addbytes(addr[i],4)) return 0; + response_rfinish(RESPONSE_ANSWER); + } + + if (flagfound) break; + if (wild == control) break; + if (!*wild) break; /* impossible */ + wild += *wild; + wild += 1; + } + + if (!flagfound) + response_nxdomain(); + + + AUTHORITY: + aupos = response_len; + + if (flagauthoritative && (aupos == anpos)) { + cdb_findstart(&c); + while (r = find(control,0)) { + if (r == -1) return 0; + if (byte_equal(type,2,DNS_T_SOA)) { + if (!response_rstart(control,DNS_T_SOA,ttl)) return 0; + if (!doname()) return 0; + if (!doname()) return 0; + if (!dobytes(20)) return 0; + response_rfinish(RESPONSE_AUTHORITY); + break; + } + } + } + else + if (want(control,DNS_T_NS)) { + cdb_findstart(&c); + while (r = find(control,0)) { + if (r == -1) return 0; + if (byte_equal(type,2,DNS_T_NS)) { + if (!response_rstart(control,DNS_T_NS,ttl)) return 0; + if (!doname()) return 0; + response_rfinish(RESPONSE_AUTHORITY); + } + } + } + + arpos = response_len; + + bpos = anpos; + while (bpos < arpos) { + bpos = dns_packet_skipname(response,arpos,bpos); if (!bpos) return 0; + bpos = dns_packet_copy(response,arpos,bpos,x,10); if (!bpos) return 0; + if (byte_equal(x,2,DNS_T_NS) || byte_equal(x,2,DNS_T_MX)) { + if (byte_equal(x,2,DNS_T_NS)) { + if (!dns_packet_getname(response,arpos,bpos,&d1)) return 0; + } + else + if (!dns_packet_getname(response,arpos,bpos + 2,&d1)) return 0; + case_lowerb(d1,dns_domain_length(d1)); + if (want(d1,DNS_T_A)) { + cdb_findstart(&c); + while (r = find(d1,0)) { + if (r == -1) return 0; + if (byte_equal(type,2,DNS_T_A)) { + if (!response_rstart(d1,DNS_T_A,ttl)) return 0; + if (!dobytes(4)) return 0; + response_rfinish(RESPONSE_ADDITIONAL); + } + } + } + } + uint16_unpack_big(x + 8,&u16); + bpos += u16; + } + + if (flagauthoritative && (response_len > 512)) { + byte_zero(response + RESPONSE_ADDITIONAL,2); + response_len = arpos; + if (response_len > 512) { + byte_zero(response + RESPONSE_AUTHORITY,2); + response_len = aupos; + } + } + + return 1; +} + +int respond(char *q,char qtype[2],char ip[4]) +{ + int fd; + int r; + char key[6]; + + tai_now(&now); + fd = open_read("data.cdb"); + if (fd == -1) return 0; + cdb_init(&c,fd); + + byte_zero(clientloc,2); + key[0] = 0; + key[1] = '%'; + byte_copy(key + 2,4,ip); + r = cdb_find(&c,key,6); + if (!r) r = cdb_find(&c,key,5); + if (!r) r = cdb_find(&c,key,4); + if (!r) r = cdb_find(&c,key,3); + if (!r) r = cdb_find(&c,key,2); + if (r == -1) return 0; + if (r && (cdb_datalen(&c) == 2)) + if (cdb_read(&c,clientloc,2,cdb_datapos(&c)) == -1) return 0; + + r = doit(q,qtype); + + cdb_free(&c); + close(fd); + return r; +} diff --git a/timeoutread.c b/timeoutread.c new file mode 100644 index 0000000..85a36e9 --- /dev/null +++ b/timeoutread.c @@ -0,0 +1,28 @@ +#include +#include "error.h" +#include "iopause.h" +#include "timeoutread.h" + +int timeoutread(int t,int fd,char *buf,int len) +{ + struct taia now; + struct taia deadline; + iopause_fd x; + + taia_now(&now); + taia_uint(&deadline,t); + taia_add(&deadline,&now,&deadline); + + x.fd = fd; + x.events = IOPAUSE_READ; + for (;;) { + taia_now(&now); + iopause(&x,1,&deadline,&now); + if (x.revents) break; + if (taia_less(&deadline,&now)) { + errno = error_timeout; + return -1; + } + } + return read(fd,buf,len); +} diff --git a/timeoutread.h b/timeoutread.h new file mode 100644 index 0000000..20d3bfc --- /dev/null +++ b/timeoutread.h @@ -0,0 +1,6 @@ +#ifndef TIMEOUTREAD_H +#define TIMEOUTREAD_H + +extern int timeoutread(); + +#endif diff --git a/timeoutwrite.c b/timeoutwrite.c new file mode 100644 index 0000000..4f665f1 --- /dev/null +++ b/timeoutwrite.c @@ -0,0 +1,28 @@ +#include +#include "error.h" +#include "iopause.h" +#include "timeoutwrite.h" + +int timeoutwrite(int t,int fd,char *buf,int len) +{ + struct taia now; + struct taia deadline; + iopause_fd x; + + taia_now(&now); + taia_uint(&deadline,t); + taia_add(&deadline,&now,&deadline); + + x.fd = fd; + x.events = IOPAUSE_WRITE; + for (;;) { + taia_now(&now); + iopause(&x,1,&deadline,&now); + if (x.revents) break; + if (taia_less(&deadline,&now)) { + errno = error_timeout; + return -1; + } + } + return write(fd,buf,len); +} diff --git a/timeoutwrite.h b/timeoutwrite.h new file mode 100644 index 0000000..4725861 --- /dev/null +++ b/timeoutwrite.h @@ -0,0 +1,6 @@ +#ifndef TIMEOUTWRITE_H +#define TIMEOUTWRITE_H + +extern int timeoutwrite(); + +#endif diff --git a/tinydns-conf.c b/tinydns-conf.c new file mode 100644 index 0000000..d3a4ce5 --- /dev/null +++ b/tinydns-conf.c @@ -0,0 +1,98 @@ +#include +#include +#include "strerr.h" +#include "exit.h" +#include "auto_home.h" +#include "generic-conf.h" + +#define FATAL "tinydns-conf: fatal: " + +void usage(void) +{ + strerr_die1x(100,"tinydns-conf: usage: tinydns-conf acct logacct /tinydns myip"); +} + +char *dir; +char *user; +char *loguser; +struct passwd *pw; +char *myip; + +int main(int argc,char **argv) +{ + user = argv[1]; + if (!user) usage(); + loguser = argv[2]; + if (!loguser) usage(); + dir = argv[3]; + if (!dir) usage(); + if (dir[0] != '/') usage(); + myip = argv[4]; + if (!myip) usage(); + + pw = getpwnam(loguser); + if (!pw) + strerr_die3x(111,FATAL,"unknown account ",loguser); + + init(dir,FATAL); + makelog(loguser,pw->pw_uid,pw->pw_gid); + + makedir("env"); + perm(02755); + start("env/ROOT"); outs(dir); outs("/root\n"); finish(); + perm(0644); + start("env/IP"); outs(myip); outs("\n"); finish(); + perm(0644); + + start("run"); + outs("#!/bin/sh\nexec 2>&1\nexec envuidgid "); outs(user); + outs(" envdir ./env softlimit -d300000 "); + outs(auto_home); outs("/bin/tinydns\n"); + finish(); + perm(0755); + + makedir("root"); + perm(02755); + + start("root/data"); + finish(); + perm(0644); + + start("root/add-ns"); + outs("#!/bin/sh\nexec "); + outs(auto_home); outs("/bin/tinydns-edit data data.new add ns ${1+\"$@\"}\n"); + finish(); + perm(0755); + + start("root/add-childns"); + outs("#!/bin/sh\nexec "); + outs(auto_home); outs("/bin/tinydns-edit data data.new add childns ${1+\"$@\"}\n"); + finish(); + perm(0755); + + start("root/add-host"); + outs("#!/bin/sh\nexec "); + outs(auto_home); outs("/bin/tinydns-edit data data.new add host ${1+\"$@\"}\n"); + finish(); + perm(0755); + + start("root/add-alias"); + outs("#!/bin/sh\nexec "); + outs(auto_home); outs("/bin/tinydns-edit data data.new add alias ${1+\"$@\"}\n"); + finish(); + perm(0755); + + start("root/add-mx"); + outs("#!/bin/sh\nexec "); + outs(auto_home); outs("/bin/tinydns-edit data data.new add mx ${1+\"$@\"}\n"); + finish(); + perm(0755); + + start("root/Makefile"); + outs("data.cdb: data\n"); + outs("\t"); outs(auto_home); outs("/bin/tinydns-data\n"); + finish(); + perm(0644); + + _exit(0); +} diff --git a/tinydns-data.c b/tinydns-data.c new file mode 100644 index 0000000..ba82f84 --- /dev/null +++ b/tinydns-data.c @@ -0,0 +1,456 @@ +#include +#include +#include +#include +#include "uint16.h" +#include "uint32.h" +#include "str.h" +#include "byte.h" +#include "fmt.h" +#include "ip4.h" +#include "exit.h" +#include "case.h" +#include "scan.h" +#include "buffer.h" +#include "strerr.h" +#include "getln.h" +#include "cdb_make.h" +#include "stralloc.h" +#include "open.h" +#include "dns.h" + +#define TTL_NS 259200 +#define TTL_POSITIVE 86400 +#define TTL_NEGATIVE 2560 + +#define FATAL "tinydns-data: fatal: " + +void die_datatmp(void) +{ + strerr_die2sys(111,FATAL,"unable to create data.tmp: "); +} +void nomem(void) +{ + strerr_die1sys(111,FATAL); +} + +void ttdparse(stralloc *sa,char ttd[8]) +{ + unsigned int i; + char ch; + + byte_zero(ttd,8); + for (i = 0;(i < 16) && (i < sa->len);++i) { + ch = sa->s[i]; + if ((ch >= '0') && (ch <= '9')) + ch -= '0'; + else if ((ch >= 'a') && (ch <= 'f')) + ch -= 'a' - 10; + else + ch = 0; + if (!(i & 1)) ch <<= 4; + ttd[i >> 1] |= ch; + } +} + +void locparse(stralloc *sa,char loc[2]) +{ + loc[0] = (sa->len > 0) ? sa->s[0] : 0; + loc[1] = (sa->len > 1) ? sa->s[1] : 0; +} + +void ipprefix_cat(stralloc *out,char *s) +{ + unsigned long u; + char ch; + unsigned int j; + + for (;;) + if (*s == '.') + ++s; + else { + j = scan_ulong(s,&u); + if (!j) return; + s += j; + ch = u; + if (!stralloc_catb(out,&ch,1)) nomem(); + } +} + +void txtparse(stralloc *sa) +{ + char ch; + unsigned int i; + unsigned int j; + + j = 0; + i = 0; + while (i < sa->len) { + ch = sa->s[i++]; + if (ch == '\\') { + if (i >= sa->len) break; + ch = sa->s[i++]; + if ((ch >= '0') && (ch <= '7')) { + ch -= '0'; + if ((i < sa->len) && (sa->s[i] >= '0') && (sa->s[i] <= '7')) { + ch <<= 3; + ch += sa->s[i++] - '0'; + if ((i < sa->len) && (sa->s[i] >= '0') && (sa->s[i] <= '7')) { + ch <<= 3; + ch += sa->s[i++] - '0'; + } + } + } + } + sa->s[j++] = ch; + } + sa->len = j; +} + +char defaultsoa[20]; + +void defaultsoa_init(int fd) +{ + struct stat st; + if (fstat(fd,&st) == -1) + strerr_die2sys(111,FATAL,"unable to stat data: "); + uint32_pack_big(defaultsoa,st.st_mtime); + if (byte_equal(defaultsoa,4,"\0\0\0\0")) + defaultsoa[3] = 1; + byte_copy(defaultsoa + 4,16,"\0\0\100\000\0\0\010\000\0\020\000\000\0\0\012\000"); +} + +int fdcdb; +struct cdb_make cdb; +static stralloc key; +static stralloc result; + +void rr_add(const char *buf,unsigned int len) +{ + if (!stralloc_catb(&result,buf,len)) nomem(); +} +void rr_addname(const char *d) +{ + rr_add(d,dns_domain_length(d)); +} +void rr_start(const char type[2],unsigned long ttl,const char ttd[8],const char loc[2]) +{ + char buf[4]; + if (!stralloc_copyb(&result,type,2)) nomem(); + if (byte_equal(loc,2,"\0\0")) + rr_add("=",1); + else { + rr_add(">",1); + rr_add(loc,2); + } + uint32_pack_big(buf,ttl); + rr_add(buf,4); + rr_add(ttd,8); +} +void rr_finish(const char *owner) +{ + if (byte_equal(owner,2,"\1*")) { + owner += 2; + result.s[2] -= 19; + } + if (!stralloc_copyb(&key,owner,dns_domain_length(owner))) nomem(); + case_lowerb(key.s,key.len); + if (cdb_make_add(&cdb,key.s,key.len,result.s,result.len) == -1) + die_datatmp(); +} + +buffer b; +char bspace[1024]; + +static stralloc line; +int match = 1; +unsigned long linenum = 0; + +#define NUMFIELDS 15 +static stralloc f[NUMFIELDS]; + +static char *d1; +static char *d2; +char dptr[DNS_NAME4_DOMAIN]; + +char strnum[FMT_ULONG]; + +void syntaxerror(const char *why) +{ + strnum[fmt_ulong(strnum,linenum)] = 0; + strerr_die4x(111,FATAL,"unable to parse data line ",strnum,why); +} + +int main() +{ + int fddata; + int i; + int j; + int k; + char ch; + unsigned long ttl; + char ttd[8]; + char loc[2]; + unsigned long u; + char ip[4]; + char type[2]; + char soa[20]; + char buf[4]; + + umask(022); + + fddata = open_read("data"); + if (fddata == -1) + strerr_die2sys(111,FATAL,"unable to open data: "); + defaultsoa_init(fddata); + + buffer_init(&b,buffer_unixread,fddata,bspace,sizeof bspace); + + fdcdb = open_trunc("data.tmp"); + if (fdcdb == -1) die_datatmp(); + if (cdb_make_start(&cdb,fdcdb) == -1) die_datatmp(); + + while (match) { + ++linenum; + if (getln(&b,&line,&match,'\n') == -1) + strerr_die2sys(111,FATAL,"unable to read line: "); + + while (line.len) { + ch = line.s[line.len - 1]; + if ((ch != ' ') && (ch != '\t') && (ch != '\n')) break; + --line.len; + } + if (!line.len) continue; + if (line.s[0] == '#') continue; + if (line.s[0] == '-') continue; + + j = 1; + for (i = 0;i < NUMFIELDS;++i) { + if (j >= line.len) { + if (!stralloc_copys(&f[i],"")) nomem(); + } + else { + k = byte_chr(line.s + j,line.len - j,':'); + if (!stralloc_copyb(&f[i],line.s + j,k)) nomem(); + j += k + 1; + } + } + + switch(line.s[0]) { + + case '%': + locparse(&f[0],loc); + if (!stralloc_copyb(&key,"\0%",2)) nomem(); + if (!stralloc_0(&f[1])) nomem(); + ipprefix_cat(&key,f[1].s); + if (cdb_make_add(&cdb,key.s,key.len,loc,2) == -1) + die_datatmp(); + break; + + case 'Z': + if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem(); + + if (!stralloc_0(&f[3])) nomem(); + if (!scan_ulong(f[3].s,&u)) uint32_unpack_big(defaultsoa,&u); + uint32_pack_big(soa,u); + if (!stralloc_0(&f[4])) nomem(); + if (!scan_ulong(f[4].s,&u)) uint32_unpack_big(defaultsoa + 4,&u); + uint32_pack_big(soa + 4,u); + if (!stralloc_0(&f[5])) nomem(); + if (!scan_ulong(f[5].s,&u)) uint32_unpack_big(defaultsoa + 8,&u); + uint32_pack_big(soa + 8,u); + if (!stralloc_0(&f[6])) nomem(); + if (!scan_ulong(f[6].s,&u)) uint32_unpack_big(defaultsoa + 12,&u); + uint32_pack_big(soa + 12,u); + if (!stralloc_0(&f[7])) nomem(); + if (!scan_ulong(f[7].s,&u)) uint32_unpack_big(defaultsoa + 16,&u); + uint32_pack_big(soa + 16,u); + + if (!stralloc_0(&f[8])) nomem(); + if (!scan_ulong(f[8].s,&ttl)) ttl = TTL_NEGATIVE; + ttdparse(&f[9],ttd); + locparse(&f[10],loc); + + rr_start(DNS_T_SOA,ttl,ttd,loc); + if (!dns_domain_fromdot(&d2,f[1].s,f[1].len)) nomem(); + rr_addname(d2); + if (!dns_domain_fromdot(&d2,f[2].s,f[2].len)) nomem(); + rr_addname(d2); + rr_add(soa,20); + rr_finish(d1); + break; + + case '.': case '&': + if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem(); + if (!stralloc_0(&f[3])) nomem(); + if (!scan_ulong(f[3].s,&ttl)) ttl = TTL_NS; + ttdparse(&f[4],ttd); + locparse(&f[5],loc); + + if (!stralloc_0(&f[1])) nomem(); + + if (byte_chr(f[2].s,f[2].len,'.') >= f[2].len) { + if (!stralloc_cats(&f[2],".ns.")) nomem(); + if (!stralloc_catb(&f[2],f[0].s,f[0].len)) nomem(); + } + if (!dns_domain_fromdot(&d2,f[2].s,f[2].len)) nomem(); + + if (line.s[0] == '.') { + rr_start(DNS_T_SOA,ttl ? TTL_NEGATIVE : 0,ttd,loc); + rr_addname(d2); + rr_add("\12hostmaster",11); + rr_addname(d1); + rr_add(defaultsoa,20); + rr_finish(d1); + } + + rr_start(DNS_T_NS,ttl,ttd,loc); + rr_addname(d2); + rr_finish(d1); + + if (ip4_scan(f[1].s,ip)) { + rr_start(DNS_T_A,ttl,ttd,loc); + rr_add(ip,4); + rr_finish(d2); + } + + break; + + case '+': case '=': + if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem(); + if (!stralloc_0(&f[2])) nomem(); + if (!scan_ulong(f[2].s,&ttl)) ttl = TTL_POSITIVE; + ttdparse(&f[3],ttd); + locparse(&f[4],loc); + + if (!stralloc_0(&f[1])) nomem(); + + if (ip4_scan(f[1].s,ip)) { + rr_start(DNS_T_A,ttl,ttd,loc); + rr_add(ip,4); + rr_finish(d1); + + if (line.s[0] == '=') { + dns_name4_domain(dptr,ip); + rr_start(DNS_T_PTR,ttl,ttd,loc); + rr_addname(d1); + rr_finish(dptr); + } + } + break; + + case '@': + if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem(); + if (!stralloc_0(&f[4])) nomem(); + if (!scan_ulong(f[4].s,&ttl)) ttl = TTL_POSITIVE; + ttdparse(&f[5],ttd); + locparse(&f[6],loc); + + if (!stralloc_0(&f[1])) nomem(); + + if (byte_chr(f[2].s,f[2].len,'.') >= f[2].len) { + if (!stralloc_cats(&f[2],".mx.")) nomem(); + if (!stralloc_catb(&f[2],f[0].s,f[0].len)) nomem(); + } + if (!dns_domain_fromdot(&d2,f[2].s,f[2].len)) nomem(); + + if (!stralloc_0(&f[3])) nomem(); + if (!scan_ulong(f[3].s,&u)) u = 0; + + rr_start(DNS_T_MX,ttl,ttd,loc); + uint16_pack_big(buf,u); + rr_add(buf,2); + rr_addname(d2); + rr_finish(d1); + + if (ip4_scan(f[1].s,ip)) { + rr_start(DNS_T_A,ttl,ttd,loc); + rr_add(ip,4); + rr_finish(d2); + } + break; + + case '^': case 'C': + if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem(); + if (!dns_domain_fromdot(&d2,f[1].s,f[1].len)) nomem(); + if (!stralloc_0(&f[2])) nomem(); + if (!scan_ulong(f[2].s,&ttl)) ttl = TTL_POSITIVE; + ttdparse(&f[3],ttd); + locparse(&f[4],loc); + + if (line.s[0] == 'C') + rr_start(DNS_T_CNAME,ttl,ttd,loc); + else + rr_start(DNS_T_PTR,ttl,ttd,loc); + rr_addname(d2); + rr_finish(d1); + break; + + case '\'': + if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem(); + if (!stralloc_0(&f[2])) nomem(); + if (!scan_ulong(f[2].s,&ttl)) ttl = TTL_POSITIVE; + ttdparse(&f[3],ttd); + locparse(&f[4],loc); + + rr_start(DNS_T_TXT,ttl,ttd,loc); + + txtparse(&f[1]); + i = 0; + while (i < f[1].len) { + k = f[1].len - i; + if (k > 127) k = 127; + ch = k; + rr_add(&ch,1); + rr_add(f[1].s + i,k); + i += k; + } + + rr_finish(d1); + break; + + case ':': + if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem(); + if (!stralloc_0(&f[3])) nomem(); + if (!scan_ulong(f[3].s,&ttl)) ttl = TTL_POSITIVE; + ttdparse(&f[4],ttd); + locparse(&f[5],loc); + + if (!stralloc_0(&f[1])) nomem(); + scan_ulong(f[1].s,&u); + uint16_pack_big(type,u); + if (byte_equal(type,2,DNS_T_AXFR)) + syntaxerror(": type AXFR prohibited"); + if (byte_equal(type,2,"\0\0")) + syntaxerror(": type 0 prohibited"); + if (byte_equal(type,2,DNS_T_SOA)) + syntaxerror(": type SOA prohibited"); + if (byte_equal(type,2,DNS_T_NS)) + syntaxerror(": type NS prohibited"); + if (byte_equal(type,2,DNS_T_CNAME)) + syntaxerror(": type CNAME prohibited"); + if (byte_equal(type,2,DNS_T_PTR)) + syntaxerror(": type PTR prohibited"); + if (byte_equal(type,2,DNS_T_MX)) + syntaxerror(": type MX prohibited"); + + txtparse(&f[2]); + + rr_start(type,ttl,ttd,loc); + rr_add(f[2].s,f[2].len); + rr_finish(d1); + break; + + default: + syntaxerror(": unrecognized leading character"); + } + } + + if (cdb_make_finish(&cdb) == -1) die_datatmp(); + if (fsync(fdcdb) == -1) die_datatmp(); + if (close(fdcdb) == -1) die_datatmp(); /* NFS stupidity */ + if (rename("data.tmp","data.cdb") == -1) + strerr_die2sys(111,FATAL,"unable to move data.tmp to data.cdb: "); + + _exit(0); +} diff --git a/tinydns-edit.c b/tinydns-edit.c new file mode 100644 index 0000000..126a7e0 --- /dev/null +++ b/tinydns-edit.c @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include "stralloc.h" +#include "buffer.h" +#include "exit.h" +#include "open.h" +#include "getln.h" +#include "strerr.h" +#include "scan.h" +#include "byte.h" +#include "str.h" +#include "fmt.h" +#include "ip4.h" +#include "dns.h" + +#define FATAL "tinydns-edit: fatal: " + +#define TTL_NS 259200 +#define TTL_POSITIVE 86400 + +char *fn; +char *fnnew; + +void die_usage() +{ + strerr_die1x(100,"tinydns-edit: usage: tinydns-edit data data.new add [ns|childns|host|alias|mx] domain a.b.c.d"); +} +void nomem() +{ + strerr_die2x(111,FATAL,"out of memory"); +} +void die_read() +{ + strerr_die4sys(100,FATAL,"tinydns-edit: fatal: unable to read ",fn,": "); +} +void die_write() +{ + strerr_die4sys(100,FATAL,"tinydns-edit: fatal: unable to write ",fnnew,": "); +} + +char mode; +static char *target; +char targetip[4]; + +int fd; +buffer b; +char bspace[1024]; + +int fdnew; +buffer bnew; +char bnewspace[1024]; + +static stralloc line; +int match = 1; + +#define NUMFIELDS 10 +static stralloc f[NUMFIELDS]; + +static char *d1; +static char *d2; +char ip[4]; +char ipstr[IP4_FMT]; +char strnum[FMT_ULONG]; + +static char *names[26]; +static int used[26]; + +void put(const char *buf,unsigned int len) +{ + if (buffer_putalign(&bnew,buf,len) == -1) die_write(); +} + +int main(int argc,char **argv) +{ + unsigned long ttl; + struct stat st; + int i; + int j; + int k; + char ch; + + if (!*argv) die_usage(); + + if (!*++argv) die_usage(); + fn = *argv; + + if (!*++argv) die_usage(); + fnnew = *argv; + + if (!*++argv) die_usage(); + if (str_diff(*argv,"add")) die_usage(); + + if (!*++argv) die_usage(); + if (str_equal(*argv,"ns")) mode = '.'; + else if (str_equal(*argv,"childns")) mode = '&'; + else if (str_equal(*argv,"host")) mode = '='; + else if (str_equal(*argv,"alias")) mode = '+'; + else if (str_equal(*argv,"mx")) mode = '@'; + else die_usage(); + + if (!*++argv) die_usage(); + if (!dns_domain_fromdot(&target,*argv,str_len(*argv))) nomem(); + + if (!*++argv) die_usage(); + if (!ip4_scan(*argv,targetip)) die_usage(); + + umask(077); + + fd = open_read(fn); + if (fd == -1) die_read(); + if (fstat(fd,&st) == -1) die_read(); + buffer_init(&b,buffer_unixread,fd,bspace,sizeof bspace); + + fdnew = open_trunc(fnnew); + if (fdnew == -1) die_write(); + if (fchmod(fdnew,st.st_mode & 0644) == -1) die_write(); + buffer_init(&bnew,buffer_unixwrite,fdnew,bnewspace,sizeof bnewspace); + + switch(mode) { + case '.': case '&': + ttl = TTL_NS; + for (i = 0;i < 26;++i) { + ch = 'a' + i; + if (!stralloc_copyb(&f[0],&ch,1)) nomem(); + if (!stralloc_cats(&f[0],".ns.")) nomem(); + if (!dns_domain_todot_cat(&f[0],target)) nomem(); + if (!dns_domain_fromdot(&names[i],f[0].s,f[0].len)) nomem(); + } + break; + case '+': case '=': + ttl = TTL_POSITIVE; + break; + case '@': + ttl = TTL_POSITIVE; + for (i = 0;i < 26;++i) { + ch = 'a' + i; + if (!stralloc_copyb(&f[0],&ch,1)) nomem(); + if (!stralloc_cats(&f[0],".mx.")) nomem(); + if (!dns_domain_todot_cat(&f[0],target)) nomem(); + if (!dns_domain_fromdot(&names[i],f[0].s,f[0].len)) nomem(); + } + break; + } + + while (match) { + if (getln(&b,&line,&match,'\n') == -1) die_read(); + + put(line.s,line.len); + if (line.len && !match) put("\n",1); + + while (line.len) { + ch = line.s[line.len - 1]; + if ((ch != ' ') && (ch != '\t') && (ch != '\n')) break; + --line.len; + } + if (!line.len) continue; + if (line.s[0] == '#') continue; + + j = 1; + for (i = 0;i < NUMFIELDS;++i) { + if (j >= line.len) { + if (!stralloc_copys(&f[i],"")) nomem(); + } + else { + k = byte_chr(line.s + j,line.len - j,':'); + if (!stralloc_copyb(&f[i],line.s + j,k)) nomem(); + j += k + 1; + } + } + + switch(mode) { + case '.': case '&': + if (line.s[0] == mode) { + if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem(); + if (dns_domain_equal(d1,target)) { + if (byte_chr(f[2].s,f[2].len,'.') >= f[2].len) { + if (!stralloc_cats(&f[2],".ns.")) nomem(); + if (!stralloc_catb(&f[2],f[0].s,f[0].len)) nomem(); + } + if (!dns_domain_fromdot(&d2,f[2].s,f[2].len)) nomem(); + if (!stralloc_0(&f[3])) nomem(); + if (!scan_ulong(f[3].s,&ttl)) ttl = TTL_NS; + for (i = 0;i < 26;++i) + if (dns_domain_equal(d2,names[i])) { + used[i] = 1; + break; + } + } + } + break; + + case '=': + if (line.s[0] == '=') { + if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem(); + if (dns_domain_equal(d1,target)) + strerr_die2x(100,FATAL,"host name already used"); + if (!stralloc_0(&f[1])) nomem(); + if (ip4_scan(f[1].s,ip)) + if (byte_equal(ip,4,targetip)) + strerr_die2x(100,FATAL,"IP address already used"); + } + break; + + case '@': + if (line.s[0] == '@') { + if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem(); + if (dns_domain_equal(d1,target)) { + if (byte_chr(f[2].s,f[2].len,'.') >= f[2].len) { + if (!stralloc_cats(&f[2],".mx.")) nomem(); + if (!stralloc_catb(&f[2],f[0].s,f[0].len)) nomem(); + } + if (!dns_domain_fromdot(&d2,f[2].s,f[2].len)) nomem(); + if (!stralloc_0(&f[4])) nomem(); + if (!scan_ulong(f[4].s,&ttl)) ttl = TTL_POSITIVE; + for (i = 0;i < 26;++i) + if (dns_domain_equal(d2,names[i])) { + used[i] = 1; + break; + } + } + } + break; + } + } + + if (!stralloc_copyb(&f[0],&mode,1)) nomem(); + if (!dns_domain_todot_cat(&f[0],target)) nomem(); + if (!stralloc_cats(&f[0],":")) nomem(); + if (!stralloc_catb(&f[0],ipstr,ip4_fmt(ipstr,targetip))) nomem(); + switch(mode) { + case '.': case '&': case '@': + for (i = 0;i < 26;++i) + if (!used[i]) + break; + if (i >= 26) + strerr_die2x(100,FATAL,"too many records for that domain"); + ch = 'a' + i; + if (!stralloc_cats(&f[0],":")) nomem(); + if (!stralloc_catb(&f[0],&ch,1)) nomem(); + if (mode == '@') + if (!stralloc_cats(&f[0],":")) nomem(); + break; + } + if (!stralloc_cats(&f[0],":")) nomem(); + if (!stralloc_catb(&f[0],strnum,fmt_ulong(strnum,ttl))) nomem(); + if (!stralloc_cats(&f[0],"\n")) nomem(); + put(f[0].s,f[0].len); + + if (buffer_flush(&bnew) == -1) die_write(); + if (fsync(fdnew) == -1) die_write(); + if (close(fdnew) == -1) die_write(); /* NFS dorks */ + if (rename(fnnew,fn) == -1) + strerr_die6sys(111,FATAL,"unable to move ",fnnew," to ",fn,": "); + _exit(0); +} diff --git a/tinydns-get.c b/tinydns-get.c new file mode 100644 index 0000000..f7fd67f --- /dev/null +++ b/tinydns-get.c @@ -0,0 +1,76 @@ +#include "str.h" +#include "byte.h" +#include "scan.h" +#include "exit.h" +#include "stralloc.h" +#include "buffer.h" +#include "strerr.h" +#include "uint16.h" +#include "response.h" +#include "case.h" +#include "printpacket.h" +#include "parsetype.h" +#include "ip4.h" +#include "dns.h" + +extern int respond(char *,char *,char *); + +#define FATAL "tinydns-get: fatal: " + +void usage(void) +{ + strerr_die1x(100,"tinydns-get: usage: tinydns-get type name [ip]"); +} +void oops(void) +{ + strerr_die2sys(111,FATAL,"unable to parse: "); +} + +static char ip[4]; +static char type[2]; +static char *q; + +static stralloc out; + +int main(int argc,char **argv) +{ + uint16 u16; + + if (!*argv) usage(); + + if (!*++argv) usage(); + if (!parsetype(*argv,type)) usage(); + + if (!*++argv) usage(); + if (!dns_domain_fromdot(&q,*argv,str_len(*argv))) oops(); + + if (*++argv) { + if (!ip4_scan(*argv,ip)) usage(); + } + + if (!stralloc_copys(&out,"")) oops(); + uint16_unpack_big(type,&u16); + if (!stralloc_catulong0(&out,u16,0)) oops(); + if (!stralloc_cats(&out," ")) oops(); + if (!dns_domain_todot_cat(&out,q)) oops(); + if (!stralloc_cats(&out,":\n")) oops(); + + if (!response_query(q,type,DNS_C_IN)) oops(); + response[3] &= ~128; + response[2] &= ~1; + response[2] |= 4; + case_lowerb(q,dns_domain_length(q)); + + if (byte_equal(type,2,DNS_T_AXFR)) { + response[3] &= ~15; + response[3] |= 4; + } + else + if (!respond(q,type,ip)) goto DONE; + + if (!printpacket_cat(&out,response,response_len)) oops(); + + DONE: + buffer_putflush(buffer_1,out.s,out.len); + _exit(0); +} diff --git a/tinydns.c b/tinydns.c new file mode 100644 index 0000000..2a5b560 --- /dev/null +++ b/tinydns.c @@ -0,0 +1,11 @@ +#include "dns.h" + +const char *fatal = "tinydns: fatal: "; +const char *starting = "starting tinydns\n"; + +static char seed[128]; + +void initialize(void) +{ + dns_random_init(seed); +} diff --git a/trycpp.c b/trycpp.c new file mode 100644 index 0000000..690f2f3 --- /dev/null +++ b/trycpp.c @@ -0,0 +1,7 @@ +int main() +{ +#ifdef NeXT + printf("nextstep\n"); exit(0); +#endif + printf("unknown\n"); exit(0); +} diff --git a/trydrent.c b/trydrent.c new file mode 100644 index 0000000..c778176 --- /dev/null +++ b/trydrent.c @@ -0,0 +1,8 @@ +#include +#include + +void foo() +{ + DIR *dir; + struct dirent *d; +} diff --git a/trylsock.c b/trylsock.c new file mode 100644 index 0000000..c32bd40 --- /dev/null +++ b/trylsock.c @@ -0,0 +1,4 @@ +int main() +{ + ; +} diff --git a/trypoll.c b/trypoll.c new file mode 100644 index 0000000..30bea3d --- /dev/null +++ b/trypoll.c @@ -0,0 +1,18 @@ +#include +#include +#include + +int main() +{ + struct pollfd x; + + x.fd = open("trypoll.c",O_RDONLY); + if (x.fd == -1) _exit(111); + x.events = POLLIN; + if (poll(&x,1,10) == -1) _exit(1); + if (x.revents != POLLIN) _exit(1); + + /* XXX: try to detect and avoid poll() imitation libraries */ + + _exit(0); +} diff --git a/tryshsgr.c b/tryshsgr.c new file mode 100644 index 0000000..81b395c --- /dev/null +++ b/tryshsgr.c @@ -0,0 +1,14 @@ +int main() +{ + short x[4]; + + x[0] = x[1] = 1; + if (getgroups(1,x) == 0) if (setgroups(1,x) == -1) _exit(1); + + if (getgroups(1,x) == -1) _exit(1); + if (x[1] != 1) _exit(1); + x[1] = 2; + if (getgroups(1,x) == -1) _exit(1); + if (x[1] != 2) _exit(1); + _exit(0); +} diff --git a/trysysel.c b/trysysel.c new file mode 100644 index 0000000..f6ed055 --- /dev/null +++ b/trysysel.c @@ -0,0 +1,8 @@ +#include +#include +#include /* SVR4 silliness */ + +void foo() +{ + ; +} diff --git a/tryulong32.c b/tryulong32.c new file mode 100644 index 0000000..20683d6 --- /dev/null +++ b/tryulong32.c @@ -0,0 +1,11 @@ +int main() +{ + unsigned long u; + u = 1; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + if (!u) _exit(0); + _exit(1); +} diff --git a/tryulong64.c b/tryulong64.c new file mode 100644 index 0000000..479e4be --- /dev/null +++ b/tryulong64.c @@ -0,0 +1,11 @@ +int main() +{ + unsigned long u; + u = 1; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + u += u; u += u; u += u; u += u; u += u; u += u; u += u; u += u; + if (!u) _exit(1); + _exit(0); +} diff --git a/uint16.h b/uint16.h new file mode 100644 index 0000000..af314fd --- /dev/null +++ b/uint16.h @@ -0,0 +1,11 @@ +#ifndef UINT16_H +#define UINT16_H + +typedef unsigned short uint16; + +extern void uint16_pack(char *,uint16); +extern void uint16_pack_big(char *,uint16); +extern void uint16_unpack(const char *,uint16 *); +extern void uint16_unpack_big(const char *,uint16 *); + +#endif diff --git a/uint16_pack.c b/uint16_pack.c new file mode 100644 index 0000000..17dbfe6 --- /dev/null +++ b/uint16_pack.c @@ -0,0 +1,13 @@ +#include "uint16.h" + +void uint16_pack(char s[2],uint16 u) +{ + s[0] = u & 255; + s[1] = u >> 8; +} + +void uint16_pack_big(char s[2],uint16 u) +{ + s[1] = u & 255; + s[0] = u >> 8; +} diff --git a/uint16_unpack.c b/uint16_unpack.c new file mode 100644 index 0000000..518b9e3 --- /dev/null +++ b/uint16_unpack.c @@ -0,0 +1,23 @@ +#include "uint16.h" + +void uint16_unpack(const char s[2],uint16 *u) +{ + uint16 result; + + result = (unsigned char) s[1]; + result <<= 8; + result += (unsigned char) s[0]; + + *u = result; +} + +void uint16_unpack_big(const char s[2],uint16 *u) +{ + uint16 result; + + result = (unsigned char) s[0]; + result <<= 8; + result += (unsigned char) s[1]; + + *u = result; +} diff --git a/uint32.h1 b/uint32.h1 new file mode 100644 index 0000000..6ee0172 --- /dev/null +++ b/uint32.h1 @@ -0,0 +1,11 @@ +#ifndef UINT32_H +#define UINT32_H + +typedef unsigned int uint32; + +extern void uint32_pack(char *,uint32); +extern void uint32_pack_big(char *,uint32); +extern void uint32_unpack(const char *,uint32 *); +extern void uint32_unpack_big(const char *,uint32 *); + +#endif diff --git a/uint32.h2 b/uint32.h2 new file mode 100644 index 0000000..7df3ddb --- /dev/null +++ b/uint32.h2 @@ -0,0 +1,11 @@ +#ifndef UINT32_H +#define UINT32_H + +typedef unsigned long uint32; + +extern void uint32_pack(char *,uint32); +extern void uint32_pack_big(char *,uint32); +extern void uint32_unpack(const char *,uint32 *); +extern void uint32_unpack_big(const char *,uint32 *); + +#endif diff --git a/uint32_pack.c b/uint32_pack.c new file mode 100644 index 0000000..76bc670 --- /dev/null +++ b/uint32_pack.c @@ -0,0 +1,21 @@ +#include "uint32.h" + +void uint32_pack(char s[4],uint32 u) +{ + s[0] = u & 255; + u >>= 8; + s[1] = u & 255; + u >>= 8; + s[2] = u & 255; + s[3] = u >> 8; +} + +void uint32_pack_big(char s[4],uint32 u) +{ + s[3] = u & 255; + u >>= 8; + s[2] = u & 255; + u >>= 8; + s[1] = u & 255; + s[0] = u >> 8; +} diff --git a/uint32_unpack.c b/uint32_unpack.c new file mode 100644 index 0000000..f5635d3 --- /dev/null +++ b/uint32_unpack.c @@ -0,0 +1,31 @@ +#include "uint32.h" + +void uint32_unpack(const char s[4],uint32 *u) +{ + uint32 result; + + result = (unsigned char) s[3]; + result <<= 8; + result += (unsigned char) s[2]; + result <<= 8; + result += (unsigned char) s[1]; + result <<= 8; + result += (unsigned char) s[0]; + + *u = result; +} + +void uint32_unpack_big(const char s[4],uint32 *u) +{ + uint32 result; + + result = (unsigned char) s[0]; + result <<= 8; + result += (unsigned char) s[1]; + result <<= 8; + result += (unsigned char) s[2]; + result <<= 8; + result += (unsigned char) s[3]; + + *u = result; +} diff --git a/uint64.h1 b/uint64.h1 new file mode 100644 index 0000000..206fc09 --- /dev/null +++ b/uint64.h1 @@ -0,0 +1,8 @@ +#ifndef UINT64_H +#define UINT64_H + +/* sysdep: -ulong64 */ + +typedef unsigned long long uint64; + +#endif diff --git a/uint64.h2 b/uint64.h2 new file mode 100644 index 0000000..8a0f315 --- /dev/null +++ b/uint64.h2 @@ -0,0 +1,8 @@ +#ifndef UINT64_H +#define UINT64_H + +/* sysdep: +ulong64 */ + +typedef unsigned long uint64; + +#endif diff --git a/utime.c b/utime.c new file mode 100644 index 0000000..4b7984f --- /dev/null +++ b/utime.c @@ -0,0 +1,24 @@ +#include +#include +#include "scan.h" +#include "exit.h" + +char *fn; + +char *ustr; +unsigned long u; +time_t ut[2]; + +int main(int argc,char **argv) +{ + fn = argv[1]; + if (!fn) _exit(100); + + ustr = argv[2]; + if (!ustr) _exit(100); + scan_ulong(ustr,&u); + + ut[0] = ut[1] = u; + if (utime(fn,ut) == -1) _exit(111); + _exit(0); +} diff --git a/walldns-conf.c b/walldns-conf.c new file mode 100644 index 0000000..b46f19a --- /dev/null +++ b/walldns-conf.c @@ -0,0 +1,58 @@ +#include +#include +#include "strerr.h" +#include "exit.h" +#include "auto_home.h" +#include "generic-conf.h" + +#define FATAL "walldns-conf: fatal: " + +void usage(void) +{ + strerr_die1x(100,"walldns-conf: usage: walldns-conf acct logacct /walldns myip"); +} + +char *dir; +char *user; +char *loguser; +struct passwd *pw; +char *myip; + +int main(int argc,char **argv) +{ + user = argv[1]; + if (!user) usage(); + loguser = argv[2]; + if (!loguser) usage(); + dir = argv[3]; + if (!dir) usage(); + if (dir[0] != '/') usage(); + myip = argv[4]; + if (!myip) usage(); + + pw = getpwnam(loguser); + if (!pw) + strerr_die3x(111,FATAL,"unknown account ",loguser); + + init(dir,FATAL); + makelog(loguser,pw->pw_uid,pw->pw_gid); + + makedir("env"); + perm(02755); + start("env/ROOT"); outs(dir); outs("/root\n"); finish(); + perm(0644); + start("env/IP"); outs(myip); outs("\n"); finish(); + perm(0644); + + start("run"); + outs("#!/bin/sh\nexec 2>&1\nexec envuidgid "); outs(user); + outs(" envdir ./env softlimit -d250000 "); + outs(auto_home); outs("/bin/walldns\n"); + finish(); + perm(0755); + + makedir("root"); + perm(02755); + + _exit(0); +} diff --git a/walldns.c b/walldns.c new file mode 100644 index 0000000..3cdaa72 --- /dev/null +++ b/walldns.c @@ -0,0 +1,57 @@ +#include "byte.h" +#include "dns.h" +#include "dd.h" +#include "response.h" + +const char *fatal = "walldns: fatal: "; +const char *starting = "starting walldns\n"; + +void initialize(void) +{ + ; +} + +int respond(char *q,char qtype[2]) +{ + int flaga; + int flagptr; + char ip[4]; + int j; + + flaga = byte_equal(qtype,2,DNS_T_A); + flagptr = byte_equal(qtype,2,DNS_T_PTR); + if (byte_equal(qtype,2,DNS_T_ANY)) flaga = flagptr = 1; + + if (flaga || flagptr) { + if (dd(q,"",ip) == 4) { + if (flaga) { + if (!response_rstart(q,DNS_T_A,655360)) return 0; + if (!response_addbytes(ip,4)) return 0; + response_rfinish(RESPONSE_ANSWER); + } + return 1; + } + j = dd(q,"\7in-addr\4arpa",ip); + if (j >= 0) { + if (flaga && (j == 4)) { + if (!response_rstart(q,DNS_T_A,655360)) return 0; + if (!response_addbytes(ip + 3,1)) return 0; + if (!response_addbytes(ip + 2,1)) return 0; + if (!response_addbytes(ip + 1,1)) return 0; + if (!response_addbytes(ip + 0,1)) return 0; + response_rfinish(RESPONSE_ANSWER); + } + if (flagptr) { + if (!response_rstart(q,DNS_T_PTR,655360)) return 0; + if (!response_addname(q)) return 0; + response_rfinish(RESPONSE_ANSWER); + } + return 1; + } + } + + response[2] &= ~4; + response[3] &= ~15; + response[3] |= 5; + return 1; +} diff --git a/warn-auto.sh b/warn-auto.sh new file mode 100644 index 0000000..36d2313 --- /dev/null +++ b/warn-auto.sh @@ -0,0 +1,2 @@ +#!/bin/sh +# WARNING: This file was auto-generated. Do not edit! diff --git a/warn-shsgr b/warn-shsgr new file mode 100644 index 0000000..37c351e --- /dev/null +++ b/warn-shsgr @@ -0,0 +1,3 @@ +Oops. Your getgroups() returned 0, and setgroups() failed; this means +that I can't reliably do my shsgr test. Please either ``make'' as root +or ``make'' while you're in one or more supplementary groups. diff --git a/x86cpuid.c b/x86cpuid.c new file mode 100644 index 0000000..98e37db --- /dev/null +++ b/x86cpuid.c @@ -0,0 +1,38 @@ +#include + +void nope() +{ + exit(1); +} + +int main() +{ + unsigned long x[4]; + unsigned long y[4]; + int i; + int j; + char c; + + signal(SIGILL,nope); + + x[0] = 0; + x[1] = 0; + x[2] = 0; + x[3] = 0; + + asm volatile(".byte 15;.byte 162" : "=a"(x[0]),"=b"(x[1]),"=c"(x[3]),"=d"(x[2]) : "0"(0) ); + if (!x[0]) return 0; + asm volatile(".byte 15;.byte 162" : "=a"(y[0]),"=b"(y[1]),"=c"(y[2]),"=d"(y[3]) : "0"(1) ); + + for (i = 1;i < 4;++i) + for (j = 0;j < 4;++j) { + c = x[i] >> (8 * j); + if (c < 32) c = 32; + if (c > 126) c = 126; + putchar(c); + } + + printf("-%08x-%08x\n",y[0],y[3]); + + return 0; +} -- cgit v1.2.3