diff options
author | Henryk Plötz <henryk@ploetzli.ch> | 2014-10-03 19:58:52 +0200 |
---|---|---|
committer | Henryk Plötz <henryk@ploetzli.ch> | 2014-10-03 19:58:52 +0200 |
commit | 0e5b2871ca6456b01d4bf037a6e68badf1ff1a41 (patch) | |
tree | 97b95b74c9618d85da9aa9451a55a819cd7b1c2e | |
download | tinydnssec-0e5b2871ca6456b01d4bf037a6e68badf1ff1a41.tar.gz tinydnssec-0e5b2871ca6456b01d4bf037a6e68badf1ff1a41.tar.bz2 |
Initial commit of djbdns-1.05.tar.gz
Source was http://cr.yp.to/djbdns/djbdns-1.05.tar.gz, SHA1 2efdb3a039d0c548f40936aa9cb30829e0ce8c3d
-rw-r--r-- | CHANGES | 376 | ||||
-rw-r--r-- | FILES | 243 | ||||
-rw-r--r-- | Makefile | 1106 | ||||
-rw-r--r-- | README | 7 | ||||
-rw-r--r-- | SYSDEPS | 10 | ||||
-rw-r--r-- | TARGETS | 216 | ||||
-rw-r--r-- | TINYDNS | 25 | ||||
-rw-r--r-- | TODO | 12 | ||||
-rw-r--r-- | VERSION | 1 | ||||
-rw-r--r-- | alloc.c | 31 | ||||
-rw-r--r-- | alloc.h | 8 | ||||
-rw-r--r-- | alloc_re.c | 17 | ||||
-rw-r--r-- | auto-str.c | 40 | ||||
-rw-r--r-- | auto_home.h | 6 | ||||
-rw-r--r-- | axfr-get.c | 373 | ||||
-rw-r--r-- | axfrdns-conf.c | 71 | ||||
-rw-r--r-- | axfrdns.c | 378 | ||||
-rw-r--r-- | buffer.c | 10 | ||||
-rw-r--r-- | buffer.h | 59 | ||||
-rw-r--r-- | buffer_1.c | 5 | ||||
-rw-r--r-- | buffer_2.c | 5 | ||||
-rw-r--r-- | buffer_copy.c | 16 | ||||
-rw-r--r-- | buffer_get.c | 67 | ||||
-rw-r--r-- | buffer_put.c | 88 | ||||
-rw-r--r-- | buffer_read.c | 7 | ||||
-rw-r--r-- | buffer_write.c | 7 | ||||
-rw-r--r-- | byte.h | 13 | ||||
-rw-r--r-- | byte_chr.c | 20 | ||||
-rw-r--r-- | byte_copy.c | 14 | ||||
-rw-r--r-- | byte_cr.c | 16 | ||||
-rw-r--r-- | byte_diff.c | 16 | ||||
-rw-r--r-- | byte_zero.c | 13 | ||||
-rw-r--r-- | cache.c | 207 | ||||
-rw-r--r-- | cache.h | 12 | ||||
-rw-r--r-- | cachetest.c | 32 | ||||
-rw-r--r-- | case.h | 13 | ||||
-rw-r--r-- | case_diffb.c | 18 | ||||
-rw-r--r-- | case_diffs.c | 17 | ||||
-rw-r--r-- | case_lowerb.c | 12 | ||||
-rw-r--r-- | cdb.c | 136 | ||||
-rw-r--r-- | cdb.h | 37 | ||||
-rw-r--r-- | cdb_hash.c | 21 | ||||
-rw-r--r-- | cdb_make.c | 152 | ||||
-rw-r--r-- | cdb_make.h | 39 | ||||
-rw-r--r-- | chkshsgr.c | 10 | ||||
-rw-r--r-- | choose.sh | 18 | ||||
-rw-r--r-- | conf-cc | 3 | ||||
-rw-r--r-- | conf-home | 4 | ||||
-rw-r--r-- | conf-ld | 3 | ||||
-rw-r--r-- | dd.c | 36 | ||||
-rw-r--r-- | dd.h | 6 | ||||
-rw-r--r-- | direntry.h1 | 10 | ||||
-rw-r--r-- | direntry.h2 | 10 | ||||
-rw-r--r-- | dns.h | 84 | ||||
-rw-r--r-- | dns_dfd.c | 69 | ||||
-rw-r--r-- | dns_domain.c | 74 | ||||
-rw-r--r-- | dns_dtda.c | 35 | ||||
-rw-r--r-- | dns_ip.c | 75 | ||||
-rw-r--r-- | dns_ipq.c | 71 | ||||
-rw-r--r-- | dns_mx.c | 49 | ||||
-rw-r--r-- | dns_name.c | 48 | ||||
-rw-r--r-- | dns_nd.c | 24 | ||||
-rw-r--r-- | dns_packet.c | 77 | ||||
-rw-r--r-- | dns_random.c | 63 | ||||
-rw-r--r-- | dns_rcip.c | 86 | ||||
-rw-r--r-- | dns_rcrw.c | 131 | ||||
-rw-r--r-- | dns_resolve.c | 29 | ||||
-rw-r--r-- | dns_sortip.c | 20 | ||||
-rw-r--r-- | dns_transmit.c | 366 | ||||
-rw-r--r-- | dns_txt.c | 59 | ||||
-rw-r--r-- | dnscache-conf.c | 169 | ||||
-rw-r--r-- | dnscache.c | 447 | ||||
-rw-r--r-- | dnsfilter.c | 214 | ||||
-rw-r--r-- | dnsip.c | 40 | ||||
-rw-r--r-- | dnsipq.c | 43 | ||||
-rw-r--r-- | dnsmx.c | 64 | ||||
-rw-r--r-- | dnsname.c | 34 | ||||
-rw-r--r-- | dnsq.c | 98 | ||||
-rw-r--r-- | dnsqr.c | 66 | ||||
-rw-r--r-- | dnsroots.global | 13 | ||||
-rw-r--r-- | dnstrace.c | 474 | ||||
-rw-r--r-- | dnstracesort.sh | 51 | ||||
-rw-r--r-- | dnstxt.c | 33 | ||||
-rw-r--r-- | droproot.c | 33 | ||||
-rw-r--r-- | droproot.h | 6 | ||||
-rw-r--r-- | env.c | 15 | ||||
-rw-r--r-- | env.h | 8 | ||||
-rw-r--r-- | error.c | 123 | ||||
-rw-r--r-- | error.h | 27 | ||||
-rw-r--r-- | error_str.c | 267 | ||||
-rw-r--r-- | exit.h | 6 | ||||
-rw-r--r-- | find-systype.sh | 143 | ||||
-rw-r--r-- | fmt.h | 25 | ||||
-rw-r--r-- | fmt_ulong.c | 13 | ||||
-rw-r--r-- | gen_alloc.h | 7 | ||||
-rw-r--r-- | gen_allocdefs.h | 34 | ||||
-rw-r--r-- | generic-conf.c | 99 | ||||
-rw-r--r-- | generic-conf.h | 20 | ||||
-rw-r--r-- | getln.c | 14 | ||||
-rw-r--r-- | getln.h | 10 | ||||
-rw-r--r-- | getln2.c | 24 | ||||
-rw-r--r-- | hasdevtcp.h1 | 1 | ||||
-rw-r--r-- | hasdevtcp.h2 | 2 | ||||
-rw-r--r-- | hasshsgr.h1 | 1 | ||||
-rw-r--r-- | hasshsgr.h2 | 2 | ||||
-rw-r--r-- | hier.c | 42 | ||||
-rw-r--r-- | install.c | 151 | ||||
-rw-r--r-- | instcheck.c | 108 | ||||
-rw-r--r-- | iopause.c | 76 | ||||
-rw-r--r-- | iopause.h1 | 19 | ||||
-rw-r--r-- | iopause.h2 | 18 | ||||
-rw-r--r-- | ip4.h | 9 | ||||
-rw-r--r-- | ip4_fmt.c | 18 | ||||
-rw-r--r-- | ip4_scan.c | 19 | ||||
-rw-r--r-- | log.c | 288 | ||||
-rw-r--r-- | log.h | 36 | ||||
-rw-r--r-- | ndelay.h | 7 | ||||
-rw-r--r-- | ndelay_off.c | 12 | ||||
-rw-r--r-- | ndelay_on.c | 12 | ||||
-rw-r--r-- | okclient.c | 26 | ||||
-rw-r--r-- | okclient.h | 6 | ||||
-rw-r--r-- | open.h | 10 | ||||
-rw-r--r-- | open_read.c | 6 | ||||
-rw-r--r-- | open_trunc.c | 6 | ||||
-rw-r--r-- | openreadclose.c | 16 | ||||
-rw-r--r-- | openreadclose.h | 8 | ||||
-rw-r--r-- | parsetype.c | 31 | ||||
-rw-r--r-- | parsetype.h | 6 | ||||
-rw-r--r-- | pickdns-conf.c | 66 | ||||
-rw-r--r-- | pickdns-data.c | 230 | ||||
-rw-r--r-- | pickdns.c | 101 | ||||
-rw-r--r-- | printpacket.c | 90 | ||||
-rw-r--r-- | printpacket.h | 8 | ||||
-rw-r--r-- | printrecord.c | 115 | ||||
-rw-r--r-- | printrecord.h | 9 | ||||
-rw-r--r-- | prot.c | 19 | ||||
-rw-r--r-- | prot.h | 7 | ||||
-rw-r--r-- | qlog.c | 63 | ||||
-rw-r--r-- | qlog.h | 8 | ||||
-rw-r--r-- | query.c | 851 | ||||
-rw-r--r-- | query.h | 32 | ||||
-rw-r--r-- | random-ip.c | 80 | ||||
-rw-r--r-- | rbldns-conf.c | 71 | ||||
-rw-r--r-- | rbldns-data.c | 128 | ||||
-rw-r--r-- | rbldns.c | 116 | ||||
-rw-r--r-- | readclose.c | 21 | ||||
-rw-r--r-- | readclose.h | 9 | ||||
-rw-r--r-- | response.c | 121 | ||||
-rw-r--r-- | response.h | 27 | ||||
-rw-r--r-- | roots.c | 127 | ||||
-rw-r--r-- | roots.h | 8 | ||||
-rw-r--r-- | rts.exp | 1072 | ||||
-rw-r--r-- | rts.sh | 1 | ||||
-rw-r--r-- | rts.tests | 767 | ||||
-rw-r--r-- | scan.h | 28 | ||||
-rw-r--r-- | scan_ulong.c | 14 | ||||
-rw-r--r-- | seek.h | 15 | ||||
-rw-r--r-- | seek_set.c | 7 | ||||
-rw-r--r-- | select.h1 | 10 | ||||
-rw-r--r-- | select.h2 | 11 | ||||
-rw-r--r-- | server.c | 116 | ||||
-rw-r--r-- | sgetopt.c | 51 | ||||
-rw-r--r-- | sgetopt.h | 21 | ||||
-rw-r--r-- | socket.h | 22 | ||||
-rw-r--r-- | socket_accept.c | 21 | ||||
-rw-r--r-- | socket_bind.c | 33 | ||||
-rw-r--r-- | socket_conn.c | 33 | ||||
-rw-r--r-- | socket_listen.c | 10 | ||||
-rw-r--r-- | socket_recv.c | 21 | ||||
-rw-r--r-- | socket_send.c | 18 | ||||
-rw-r--r-- | socket_tcp.c | 17 | ||||
-rw-r--r-- | socket_udp.c | 17 | ||||
-rw-r--r-- | str.h | 14 | ||||
-rw-r--r-- | str_chr.c | 17 | ||||
-rw-r--r-- | str_diff.c | 15 | ||||
-rw-r--r-- | str_len.c | 14 | ||||
-rw-r--r-- | str_rchr.c | 20 | ||||
-rw-r--r-- | str_start.c | 13 | ||||
-rw-r--r-- | stralloc.h | 29 | ||||
-rw-r--r-- | stralloc_cat.c | 7 | ||||
-rw-r--r-- | stralloc_catb.c | 12 | ||||
-rw-r--r-- | stralloc_cats.c | 8 | ||||
-rw-r--r-- | stralloc_copy.c | 7 | ||||
-rw-r--r-- | stralloc_eady.c | 6 | ||||
-rw-r--r-- | stralloc_num.c | 29 | ||||
-rw-r--r-- | stralloc_opyb.c | 11 | ||||
-rw-r--r-- | stralloc_opys.c | 8 | ||||
-rw-r--r-- | stralloc_pend.c | 5 | ||||
-rw-r--r-- | strerr.h | 78 | ||||
-rw-r--r-- | strerr_die.c | 31 | ||||
-rw-r--r-- | strerr_sys.c | 12 | ||||
-rw-r--r-- | subgetopt.c | 65 | ||||
-rw-r--r-- | subgetopt.h | 24 | ||||
-rw-r--r-- | tai.h | 26 | ||||
-rw-r--r-- | tai_add.c | 6 | ||||
-rw-r--r-- | tai_now.c | 7 | ||||
-rw-r--r-- | tai_pack.c | 16 | ||||
-rw-r--r-- | tai_sub.c | 6 | ||||
-rw-r--r-- | tai_uint.c | 6 | ||||
-rw-r--r-- | tai_unpack.c | 16 | ||||
-rw-r--r-- | taia.h | 34 | ||||
-rw-r--r-- | taia_add.c | 18 | ||||
-rw-r--r-- | taia_approx.c | 6 | ||||
-rw-r--r-- | taia_frac.c | 6 | ||||
-rw-r--r-- | taia_less.c | 12 | ||||
-rw-r--r-- | taia_now.c | 12 | ||||
-rw-r--r-- | taia_pack.c | 20 | ||||
-rw-r--r-- | taia_sub.c | 21 | ||||
-rw-r--r-- | taia_tai.c | 6 | ||||
-rw-r--r-- | taia_uint.c | 10 | ||||
-rw-r--r-- | tdlookup.c | 310 | ||||
-rw-r--r-- | timeoutread.c | 28 | ||||
-rw-r--r-- | timeoutread.h | 6 | ||||
-rw-r--r-- | timeoutwrite.c | 28 | ||||
-rw-r--r-- | timeoutwrite.h | 6 | ||||
-rw-r--r-- | tinydns-conf.c | 98 | ||||
-rw-r--r-- | tinydns-data.c | 456 | ||||
-rw-r--r-- | tinydns-edit.c | 257 | ||||
-rw-r--r-- | tinydns-get.c | 76 | ||||
-rw-r--r-- | tinydns.c | 11 | ||||
-rw-r--r-- | trycpp.c | 7 | ||||
-rw-r--r-- | trydrent.c | 8 | ||||
-rw-r--r-- | trylsock.c | 4 | ||||
-rw-r--r-- | trypoll.c | 18 | ||||
-rw-r--r-- | tryshsgr.c | 14 | ||||
-rw-r--r-- | trysysel.c | 8 | ||||
-rw-r--r-- | tryulong32.c | 11 | ||||
-rw-r--r-- | tryulong64.c | 11 | ||||
-rw-r--r-- | uint16.h | 11 | ||||
-rw-r--r-- | uint16_pack.c | 13 | ||||
-rw-r--r-- | uint16_unpack.c | 23 | ||||
-rw-r--r-- | uint32.h1 | 11 | ||||
-rw-r--r-- | uint32.h2 | 11 | ||||
-rw-r--r-- | uint32_pack.c | 21 | ||||
-rw-r--r-- | uint32_unpack.c | 31 | ||||
-rw-r--r-- | uint64.h1 | 8 | ||||
-rw-r--r-- | uint64.h2 | 8 | ||||
-rw-r--r-- | utime.c | 24 | ||||
-rw-r--r-- | walldns-conf.c | 58 | ||||
-rw-r--r-- | walldns.c | 57 | ||||
-rw-r--r-- | warn-auto.sh | 2 | ||||
-rw-r--r-- | warn-shsgr | 3 | ||||
-rw-r--r-- | x86cpuid.c | 38 |
243 files changed, 15929 insertions, 0 deletions
@@ -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. @@ -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 @@ -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 @@ -0,0 +1,10 @@ +VERSION +systype +uint32.h +uint64.h +select.h +iopause.h +direntry.h +hasshsgr.h +hasdevtcp.h +socket.lib @@ -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 @@ -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. @@ -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 @@ -0,0 +1 @@ +djbdns 1.05 @@ -0,0 +1,31 @@ +#include <stdlib.h> +#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); +} @@ -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 <stdio.h> +#include <unistd.h> +#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 <unistd.h> +#include <pwd.h> +#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 <unistd.h> +#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 <unistd.h> +#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 <unistd.h> +#include "buffer.h" + +int buffer_unixwrite(int fd,const char *buf,unsigned int len) +{ + return write(fd,buf,len); +} @@ -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; + } +} @@ -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; +} @@ -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); +} @@ -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; + } +} @@ -0,0 +1,136 @@ +/* Public domain. */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <unistd.h> +#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); +} @@ -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" @@ -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. @@ -0,0 +1,3 @@ +gcc -s + +This will be used to link .o files into an executable. @@ -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; + } +} @@ -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 <sys/types.h> +#include <sys/dir.h> +#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 <sys/types.h> +#include <dirent.h> +#define direntry struct dirent + +#endif @@ -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 <unistd.h> +#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 <unistd.h> +#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 <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#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 <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "hasdevtcp.h" +#ifdef HASDEVTCP +#include <sys/mkdev.h> +#endif +#include <pwd.h> +#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 <seed\nexec envdir ./env sh -c '\n exec envuidgid "); outs(user); + outs(" softlimit -o250 -d \"$DATALIMIT\" "); + outs(auto_home); outs("/bin/dnscache\n'\n"); finish(); + seed_addtime(); perm(0755); + seed_addtime(); start("log/run"); + outs("#!/bin/sh\nexec setuidgid "); outs(loguser); + outs(" multilog t ./main\n"); finish(); + seed_addtime(); perm(0755); + seed_addtime(); makedir("root"); + seed_addtime(); perm(02755); + seed_addtime(); makedir("root/ip"); + seed_addtime(); perm(02755); + seed_addtime(); start("root/ip/127.0.0.1"); finish(); + seed_addtime(); perm(0600); + seed_addtime(); makedir("root/servers"); + seed_addtime(); perm(02755); + seed_addtime(); start("root/servers/@"); + buffer_init(&ssrootservers,buffer_unixread,fdrootservers,rootserversbuf,sizeof rootserversbuf); + copyfrom(&ssrootservers); + finish(); + seed_addtime(); perm(0644); + seed_addtime(); + + start("seed"); out((char *) seed,128); finish(); + perm(0600); + +#ifdef HASDEVTCP + makedir("root/etc"); + perm(02755); + makedir("root/dev"); + perm(02755); + start("root/etc/netconfig"); + outs("tcp tpi_cots_ord v inet tcp /dev/tcp -\n"); + outs("udp tpi_clts v inet udp /dev/udp -\n"); + finish(); + perm(0645); + umask(000); + if (mknod("root/dev/tcp",S_IFCHR | 0667,makedev(11,42)) == -1) + strerr_die4sys(111,FATAL,"unable to create device ",dir,"/root/dev/tcp: "); + if (mknod("root/dev/udp",S_IFCHR | 0667,makedev(11,41)) == -1) + strerr_die4sys(111,FATAL,"unable to create device ",dir,"/root/dev/udp: "); + umask(022); +#endif + + _exit(0); +} diff --git a/dnscache.c b/dnscache.c new file mode 100644 index 0000000..8c899a3 --- /dev/null +++ b/dnscache.c @@ -0,0 +1,447 @@ +#include <unistd.h> +#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 <unistd.h> +#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); +} @@ -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); +} @@ -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); +} @@ -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); +} @@ -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 <unistd.h> +#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 @@ -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; +} @@ -0,0 +1,8 @@ +#ifndef ENV_H +#define ENV_H + +extern char **environ; + +extern /*@null@*/char *env_get(const char *); + +#endif @@ -0,0 +1,123 @@ +#include <errno.h> +#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 @@ -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 <errno.h> +#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"; +} @@ -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]' @@ -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 <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#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 @@ -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; +} @@ -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 @@ -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 <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#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 <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#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 <sys/types.h> +#include <poll.h> + +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 @@ -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; +} @@ -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(); +} @@ -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 <sys/types.h> +#include <fcntl.h> +#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 <sys/types.h> +#include <fcntl.h> +#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 <sys/types.h> +#include <sys/stat.h> +#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 @@ -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 <sys/types.h> +#include <fcntl.h> +#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 <sys/types.h> +#include <fcntl.h> +#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 <unistd.h> +#include <pwd.h> +#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 <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#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 <unistd.h> +#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 @@ -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); +} @@ -0,0 +1,7 @@ +#ifndef PROT_H +#define PROT_H + +extern int prot_gid(int); +extern int prot_uid(int); + +#endif @@ -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); +} @@ -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 @@ -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); +} @@ -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 <unistd.h> +#include <pwd.h> +#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 <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#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 <unistd.h> +#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 <unistd.h> +#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 @@ -0,0 +1,127 @@ +#include <unistd.h> +#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; +} @@ -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 @@ -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 @@ -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 @@ -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; +} @@ -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 <sys/types.h> +#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 <sys/types.h> +#include <sys/time.h> +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 <sys/types.h> +#include <sys/time.h> +#include <sys/select.h> +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 <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#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 <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#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 <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <unistd.h> +#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 <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#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 <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#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 <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#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 <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <unistd.h> +#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 <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <unistd.h> +#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; +} @@ -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 @@ -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 <time.h> +#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; +} @@ -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 <sys/types.h> +#include <sys/time.h> +#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 <unistd.h> +#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 <unistd.h> +#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 <unistd.h> +#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 <unistd.h> +#include <pwd.h> +#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 <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#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 <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#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 <sys/types.h> +#include <dirent.h> + +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 <sys/types.h> +#include <fcntl.h> +#include <poll.h> + +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 <sys/types.h> +#include <sys/time.h> +#include <sys/select.h> /* 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 @@ -0,0 +1,24 @@ +#include <sys/types.h> +#include <sys/time.h> +#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 <unistd.h> +#include <pwd.h> +#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 <signal.h> + +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; +} |