--- djbdns-1.05.old/axfr-get.c +++ djbdns-1.05/axfr-get.c @@ -209,6 +209,26 @@ if (!stralloc_cats(&line,".:")) return 0; if (!stralloc_catulong0(&line,dist,0)) return 0; } + else if (byte_equal(data,2,DNS_T_SRV)) { + uint16 dist, weight, port; + if (!stralloc_copys(&line,"S")) 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); + pos = x_copy(buf,len,pos,data,2); + uint16_unpack_big(data,&weight); + pos = x_copy(buf,len,pos,data,2); + uint16_unpack_big(data,&port); + 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; + if (!stralloc_cats(&line,":")) return 0; + if (!stralloc_catulong0(&line,weight,0)) return 0; + if (!stralloc_cats(&line,":")) return 0; + if (!stralloc_catulong0(&line,port,0)) return 0; + } else if (byte_equal(data,2,DNS_T_A) && (dlen == 4)) { char ipstr[IP4_FMT]; if (!stralloc_copys(&line,"+")) return 0; @@ -217,6 +237,14 @@ x_copy(buf,len,pos,data,4); if (!stralloc_catb(&line,ipstr,ip4_fmt(ipstr,data))) return 0; } + else if (byte_equal(data,2,DNS_T_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 { unsigned char ch; unsigned char ch2; --- djbdns-1.05.old/axfrdns-conf.c +++ djbdns-1.05/axfrdns-conf.c @@ -51,7 +51,7 @@ 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"); + outs(auto_home); outs("/sbin/axfrdns\n'\n"); finish(); perm(0755); --- djbdns-1.05.old/clients.h +++ djbdns-1.05/clients.h @@ -0,0 +1,7 @@ +#ifndef CLIENTS_H +#define CLIENTS_H + +#define MAXUDP 200 +#define MAXTCP 20 + +#endif /* CLIENTS_H */ --- djbdns-1.05.old/dns.h +++ djbdns-1.05/dns.h @@ -4,6 +4,7 @@ #include "stralloc.h" #include "iopause.h" #include "taia.h" +#include "clients.h" #define DNS_C_IN "\0\1" #define DNS_C_ANY "\0\377" @@ -20,6 +21,7 @@ #define DNS_T_SIG "\0\30" #define DNS_T_KEY "\0\31" #define DNS_T_AAAA "\0\34" +#define DNS_T_SRV "\0\41" #define DNS_T_AXFR "\0\374" #define DNS_T_ANY "\0\377" @@ -37,8 +39,14 @@ const char *servers; char localip[4]; char qtype[2]; + struct dns_transmit *master; + struct dns_transmit *slaves[MAXUDP]; + int nslaves; } ; +extern void dns_enable_merge(void (*logger)(const char *, const char *, + const char *)); + extern void dns_random_init(const char *); extern unsigned int dns_random(unsigned int); --- djbdns-1.05.old/dns_transmit.c +++ djbdns-1.05/dns_transmit.c @@ -7,6 +7,61 @@ #include "byte.h" #include "uint16.h" #include "dns.h" +#include "strerr.h" + +static int merge_enable; +static void (*merge_logger)(const char *, const char *, const char *); +void dns_enable_merge(void (*f)(const char *, const char *, const char *)) +{ + merge_enable = 1; + merge_logger = f; +} + +static int merge_equal(struct dns_transmit *a, struct dns_transmit *b) +{ + const char *ip1 = a->servers + 4 * a->curserver; + const char *ip2 = b->servers + 4 * b->curserver; + return + byte_equal(ip1, 4, ip2) && + byte_equal(a->qtype, 2, b->qtype) && + dns_domain_equal(a->query + 14, b->query + 14); +} + +struct dns_transmit *inprogress[MAXUDP]; + +static int try_merge(struct dns_transmit *d) +{ + int i; + for (i = 0; i < MAXUDP; i++) { + if (!inprogress[i]) continue; + if (!merge_equal(d, inprogress[i])) continue; + d->master = inprogress[i]; + inprogress[i]->slaves[inprogress[i]->nslaves++] = d; + return 1; + } + return 0; +} + +static void register_inprogress(struct dns_transmit *d) +{ + int i; + for (i = 0; i < MAXUDP; i++) { + if (!inprogress[i]) { + inprogress[i] = d; + return; + } + } + strerr_die1x(100, "BUG: out of inprogress slots"); +} + +static void unregister_inprogress(struct dns_transmit *d) +{ + int i; + for (i = 0; i < MAXUDP; i++) { + if (inprogress[i] == d) + inprogress[i] = 0; + } +} static int serverwantstcp(const char *buf,unsigned int len) { @@ -59,8 +114,28 @@ d->packet = 0; } +static void mergefree(struct dns_transmit *d) +{ + int i; + if (merge_enable) + unregister_inprogress(d); + /* unregister us from our master */ + if (d->master) { + for (i = 0; i < d->master->nslaves; i++) + if (d->master->slaves[i] == d) + d->master->slaves[i] = 0; + } + /* and unregister all of our slaves from us */ + for (i = 0; i < d->nslaves; i++) { + if (d->slaves[i]) + d->slaves[i]->master = NULL; + } + d->nslaves = 0; +} + static void queryfree(struct dns_transmit *d) { + mergefree(d); if (!d->query) return; alloc_free(d->query); d->query = 0; @@ -99,11 +174,18 @@ const char *ip; socketfree(d); + mergefree(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")) { + if (merge_enable && try_merge(d)) { + if (merge_logger) + merge_logger(ip, d->qtype, d->query + 14); + return 0; + } + d->query[2] = dns_random(256); d->query[3] = dns_random(256); @@ -118,6 +200,8 @@ taia_uint(&d->deadline,timeouts[d->udploop]); taia_add(&d->deadline,&d->deadline,&now); d->tcpstate = 0; + if (merge_enable) + register_inprogress(d); return 0; } @@ -226,7 +310,11 @@ x->fd = d->s1 - 1; switch(d->tcpstate) { - case 0: case 3: case 4: case 5: + case 0: + if (d->master) return; + if (d->packet) { taia_now(deadline); return; } + /* otherwise, fall through */ + case 3: case 4: case 5: x->events = IOPAUSE_READ; break; case 1: case 2: @@ -244,10 +332,14 @@ unsigned char ch; int r; int fd; + int i; errno = error_io; fd = d->s1 - 1; + if (d->tcpstate == 0 && d->master) return 0; + if (d->tcpstate == 0 && d->packet) return 1; + if (!x->revents) { if (taia_less(when,&d->deadline)) return 0; errno = error_timeout; @@ -279,6 +371,15 @@ d->packet = alloc(d->packetlen); if (!d->packet) { dns_transmit_free(d); return -1; } byte_copy(d->packet,d->packetlen,udpbuf); + + for (i = 0; i < d->nslaves; i++) { + if (!d->slaves[i]) continue; + d->slaves[i]->packetlen = d->packetlen; + d->slaves[i]->packet = alloc(d->packetlen); + if (!d->slaves[i]->packet) { dns_transmit_free(d->slaves[i]); continue; } + byte_copy(d->slaves[i]->packet,d->packetlen,udpbuf); + } + queryfree(d); return 1; } --- djbdns-1.05.old/dnscache-conf.c +++ djbdns-1.05/dnscache-conf.c @@ -123,7 +123,7 @@ seed_addtime(); start("run"); outs("#!/bin/sh\nexec 2>&1\nexec loop == 100) goto DIE; + if (++z->loop == 200) goto DIE; d = z->name[z->level]; dtype = z->level ? DNS_T_A : z->type; dlen = dns_domain_length(d); @@ -319,6 +319,29 @@ } } + if (typematch(DNS_T_SOA,dtype)) { + byte_copy(key,2,DNS_T_SOA); + cached = cache_get(key,dlen + 2,&cachedlen,&ttl); + if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) { + log_cachedanswer(d,DNS_T_SOA); + if (!rqa(z)) goto DIE; + pos = 0; + while (pos = dns_packet_copy(cached,cachedlen,pos,misc,20)) { + pos = dns_packet_getname(cached,cachedlen,pos,&t2); + if (!pos) break; + pos = dns_packet_getname(cached,cachedlen,pos,&t3); + if (!pos) break; + if (!response_rstart(d,DNS_T_SOA,ttl)) goto DIE; + if (!response_addname(t2)) goto DIE; + if (!response_addname(t3)) goto DIE; + if (!response_addbytes(misc,20)) 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); @@ -351,7 +374,7 @@ } } - if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_CNAME,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype)) { + if (!typematch(DNS_T_ANY,dtype) && !typematch(DNS_T_AXFR,dtype) && !typematch(DNS_T_CNAME,dtype) && !typematch(DNS_T_NS,dtype) && !typematch(DNS_T_PTR,dtype) && !typematch(DNS_T_A,dtype) && !typematch(DNS_T_MX,dtype) && !typematch(DNS_T_SOA,dtype)) { byte_copy(key,2,dtype); cached = cache_get(key,dlen + 2,&cachedlen,&ttl); if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) { @@ -449,7 +472,7 @@ HAVEPACKET: - if (++z->loop == 100) goto DIE; + if (++z->loop == 200) goto DIE; buf = z->dt.packet; len = z->dt.packetlen; @@ -578,6 +601,12 @@ } if (!dns_domain_suffix(t1,control)) { i = j; continue; } + + if (!flagforwardonly && byte_equal(type,2,DNS_T_NS) && dns_domain_equal(t1,control)) { + char dummy[256]; + if (!roots(dummy,control)) { i = j; continue; } + } + if (!roots_same(t1,control)) { i = j; continue; } if (byte_equal(type,2,DNS_T_ANY)) @@ -585,15 +614,24 @@ else if (byte_equal(type,2,DNS_T_AXFR)) ; else if (byte_equal(type,2,DNS_T_SOA)) { + int non_authority = 0; + 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; 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) + if (records[i] < posauthority) { log_rrsoa(whichserver,t1,t2,t3,misc,ttl); + save_data(misc,20); + save_data(t2,dns_domain_length(t2)); + save_data(t3,dns_domain_length(t3)); + non_authority++; + } ++i; } + if (non_authority) + save_finish(DNS_T_SOA,t1,ttl); } else if (byte_equal(type,2,DNS_T_CNAME)) { pos = dns_packet_skipname(buf,len,records[j - 1]); if (!pos) goto DIE; --- djbdns-1.05.old/rbldns-conf.c +++ djbdns-1.05/rbldns-conf.c @@ -52,7 +52,7 @@ start("run"); outs("#!/bin/sh\nexec 2>&1\nexec envuidgid "); outs(user); outs(" envdir ./env softlimit -d250000 "); - outs(auto_home); outs("/bin/rbldns\n"); + outs(auto_home); outs("/sbin/rbldns\n"); finish(); perm(0755); @@ -63,7 +63,7 @@ perm(0644); start("root/Makefile"); outs("data.cdb: data\n"); - outs("\t"); outs(auto_home); outs("/bin/rbldns-data\n"); + outs("\t"); outs(auto_home); outs("/sbin/rbldns-data\n"); finish(); perm(0644); --- djbdns-1.05.old/response.c +++ djbdns-1.05/response.c @@ -34,7 +34,7 @@ uint16_pack_big(buf,49152 + name_ptr[i]); return response_addbytes(buf,2); } - if (dlen <= 128) + if ((dlen <= 128) && (response_len < 16384)) if (name_num < NAMES) { byte_copy(name[name_num],dlen,d); name_ptr[name_num] = response_len; --- djbdns-1.05.old/tinydns-conf.c +++ djbdns-1.05/tinydns-conf.c @@ -47,7 +47,7 @@ start("run"); outs("#!/bin/sh\nexec 2>&1\nexec envuidgid "); outs(user); outs(" envdir ./env softlimit -d300000 "); - outs(auto_home); outs("/bin/tinydns\n"); + outs(auto_home); outs("/sbin/tinydns\n"); finish(); perm(0755); @@ -60,37 +60,37 @@ start("root/add-ns"); outs("#!/bin/sh\nexec "); - outs(auto_home); outs("/bin/tinydns-edit data data.new add ns ${1+\"$@\"}\n"); + outs(auto_home); outs("/sbin/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"); + outs(auto_home); outs("/sbin/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"); + outs(auto_home); outs("/sbin/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"); + outs(auto_home); outs("/sbin/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"); + outs(auto_home); outs("/sbin/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"); + outs("\t"); outs(auto_home); outs("/sbin/tinydns-data\n"); finish(); perm(0644); --- djbdns-1.05.old/tinydns-data.c +++ djbdns-1.05/tinydns-data.c @@ -196,6 +196,7 @@ char type[2]; char soa[20]; char buf[4]; + char srv[6]; umask(022); @@ -363,6 +364,43 @@ 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 'S': + if (!dns_domain_fromdot(&d1,f[0].s,f[0].len)) nomem(); + if (!stralloc_0(&f[6])) nomem(); + if (!scan_ulong(f[6].s,&ttl)) ttl = TTL_POSITIVE; + ttdparse(&f[7],ttd); + locparse(&f[8],loc); + + if (!stralloc_0(&f[1])) nomem(); + + if (byte_chr(f[2].s,f[2].len,'.') >= f[2].len) { + if (!stralloc_cats(&f[2],".srv.")) 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,&u)) u = 0; + uint16_pack_big(srv,u); + if (!stralloc_0(&f[5])) nomem(); + if (!scan_ulong(f[5].s,&u)) u = 0; + uint16_pack_big(srv + 2,u); + if (!stralloc_0(&f[3])) nomem(); + if (!scan_ulong(f[3].s,&u)) nomem(); + uint16_pack_big(srv + 4,u); + + rr_start(DNS_T_SRV,ttl,ttd,loc); + rr_add(srv,6); + 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); --- djbdns-1.05.old/walldns-conf.c +++ djbdns-1.05/walldns-conf.c @@ -47,7 +47,7 @@ start("run"); outs("#!/bin/sh\nexec 2>&1\nexec envuidgid "); outs(user); outs(" envdir ./env softlimit -d250000 "); - outs(auto_home); outs("/bin/walldns\n"); + outs(auto_home); outs("/sbin/walldns\n"); finish(); perm(0755);