version 20090602 Matthew Dempsky Public domain. This patch adds basic DNSCurve support to dnscache. To compile, you have to first build NaCl (http://nacl.cace-project.eu/install.html). Once you have built NaCl, apply this patch to djbdns-1.05, add -I/path/to/nacl/build/host/include/arch/ to conf-cc, add -L/path/to/nacl/build/host/lib/arch/ to conf-ld (substituting "path/to/nacl", "host", and "arch" as appropriate), and build/install as normal. dnscache will now automatically start using DNSCurve whenever possible. However, two notes for administrators installing this patch: 1. The log format for "tx" entries is changed slightly. There is now an additional field between the control field and the server address fields. A "+" indicates the query used DNSCurve, and a "-" indicates it did not. 2. By default, dnscache will send DNSCurve queries using the "streamlined" format. This format is smaller and more efficient to generate and parse and is therefore recommended for use when possible, but may have interoperability problems with some firewalls. By setting the USETXTFORMAT environment variable (i.e., "echo 1 > /service/dnscache/env/USETXTFORMAT"), dnscache will instead send DNSCurve queries using the "TXT" format. diff -pru djbdns-1.05.orig/Makefile djbdns-1.05/Makefile --- djbdns-1.05.orig/Makefile 2001-02-11 13:11:45.000000000 -0800 +++ djbdns-1.05/Makefile 2009-05-29 21:01:00.000000000 -0700 @@ -567,7 +567,7 @@ warn-auto.sh conf-ld ( cat warn-auto.sh; \ echo 'main="$$1"; shift'; \ echo exec "`head -1 conf-ld`" \ - '-o "$$main" "$$main".o $${1+"$$@"}' \ + '-o "$$main" "$$main".o $${1+"$$@"} -lnacl' \ ) > load chmod 755 load diff -pru djbdns-1.05.orig/dns.h djbdns-1.05/dns.h --- djbdns-1.05.orig/dns.h 2001-02-11 13:11:45.000000000 -0800 +++ djbdns-1.05/dns.h 2009-05-30 15:13:42.000000000 -0700 @@ -30,11 +30,17 @@ struct dns_transmit { unsigned int packetlen; int s1; /* 0, or 1 + an open file descriptor */ int tcpstate; + int flagrecursive; unsigned int udploop; unsigned int curserver; struct taia deadline; unsigned int pos; + const char *name; const char *servers; + const char *keys; + const char *pubkey; + const char *suffix; + char nonce[12]; char localip[4]; char qtype[2]; } ; @@ -43,6 +49,7 @@ extern void dns_random_init(const char * extern unsigned int dns_random(unsigned int); extern void dns_sortip(char *,unsigned int); +extern void dns_sortip2(char *,char *,unsigned int); extern void dns_domain_free(char **); extern int dns_domain_copy(char **,const char *); @@ -58,6 +65,7 @@ extern unsigned int dns_packet_getname(c 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 int dns_transmit_start2(struct dns_transmit *,const char *,int,const char *,const char *,const char *,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 *); diff -pru djbdns-1.05.orig/dns_sortip.c djbdns-1.05/dns_sortip.c --- djbdns-1.05.orig/dns_sortip.c 2001-02-11 13:11:45.000000000 -0800 +++ djbdns-1.05/dns_sortip.c 2009-05-29 11:55:38.000000000 -0700 @@ -18,3 +18,20 @@ void dns_sortip(char *s,unsigned int n) byte_copy(s + (n << 2),4,tmp); } } + +void dns_sortip2(char *s,char *t,unsigned int n) +{ + unsigned int i; + char tmp[32]; + + 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); + byte_copy(tmp,32,t + (i << 5)); + byte_copy(t + (i << 5),32,t + (n << 5)); + byte_copy(t + (n << 5),32,tmp); + } +} diff -pru djbdns-1.05.orig/dns_transmit.c djbdns-1.05/dns_transmit.c --- djbdns-1.05.orig/dns_transmit.c 2001-02-11 13:11:45.000000000 -0800 +++ djbdns-1.05/dns_transmit.c 2009-06-01 20:54:39.000000000 -0700 @@ -6,8 +6,229 @@ #include "error.h" #include "byte.h" #include "uint16.h" +#include "uint64.h" +#include "case.h" #include "dns.h" +#include "crypto_box_curve25519xsalsa20poly1305.h" + +#define crypto_box_afternm crypto_box_curve25519xsalsa20poly1305_afternm +#define crypto_box_open_afternm crypto_box_curve25519xsalsa20poly1305_open_afternm + +/* XXX: put in uint64_pack.c */ +static void uint64_pack(char s[8],uint64 u) +{ + s[0] = u & 255; u >>= 8; + s[1] = u & 255; u >>= 8; + s[2] = u & 255; u >>= 8; + s[3] = u & 255; u >>= 8; + s[4] = u & 255; u >>= 8; + s[5] = u & 255; u >>= 8; + s[6] = u & 255; u >>= 8; + s[7] = u & 255; +} + +/* XXX: put in dns_nonce.c */ +static void dns_nonce(char nonce[12]) +{ + /* XXX: use nanoseconds */ + static uint64 x; + + uint64_pack(nonce,++x); + nonce[8] = dns_random(256); + nonce[9] = dns_random(256); + nonce[10] = dns_random(256); + nonce[11] = dns_random(256); +} + + +/* XXX: put in base32.c */ +static const char base32_digits[32] = "0123456789bcdfghjklmnpqrstuvwxyz"; + +static unsigned int base32_bytessize(unsigned int len) +{ + len = (8 * len + 4) / 5; + return len + (len + 49) / 50; +} + +static void base32_encodebytes(char *out,const char *in,unsigned int len) +{ + unsigned int i, x, v, vbits; + + x = v = vbits = 0; + for (i = 0;i < len;++i) { + v |= ((unsigned int) (unsigned char) in[i]) << vbits; + vbits += 8; + do { + out[++x] = base32_digits[v & 31]; + v >>= 5; + vbits -= 5; + if (x == 50) { + *out = x; + out += 1 + x; + x = 0; + } + } while (vbits >= 5); + } + + if (vbits) out[++x] = base32_digits[v & 31]; + if (x) *out = x; +} + +static void base32_encodekey(char *out,const char *key) +{ + unsigned int i, v, vbits; + + byte_copy(out,4,"\66x1a"); + out += 4; + + v = vbits = 0; + for (i = 0;i < 32;++i) { + v |= ((unsigned int) (unsigned char) key[i]) << vbits; + vbits += 8; + do { + *out++ = base32_digits[v & 31]; + v >>= 5; + vbits -= 5; + } while (vbits >= 5); + } +} + + +static void makebasequery(struct dns_transmit *d,char *query) +{ + unsigned int len; + + len = dns_domain_length(d->name); + + byte_copy(query,2,d->nonce + 8); + byte_copy(query + 2,10,d->flagrecursive ? "\1\0\0\1\0\0\0\0\0\0" : "\0\0\0\1\0\0\0\0\0\0gcc-bug-workaround"); + byte_copy(query + 12,len,d->name); + byte_copy(query + 12 + len,2,d->qtype); + byte_copy(query + 14 + len,2,DNS_C_IN); +} + +static void prepquery(struct dns_transmit *d) +{ + unsigned int len; + char nonce[24]; + const char *key; + unsigned int m; + unsigned int suffixlen; + + dns_nonce(d->nonce); + + if (!d->keys) { + byte_copy(d->query + 2,2,d->nonce + 8); + return; + } + + len = dns_domain_length(d->name); + + byte_copy(nonce,12,d->nonce); + byte_zero(nonce + 12,12); + key = d->keys + 32 * d->curserver; + + byte_zero(d->query,32); + makebasequery(d,d->query + 32); + crypto_box_afternm((unsigned char *) d->query,(const unsigned char *) d->query,len + 48,(const unsigned char *) nonce,(const unsigned char *) key); + + if (!d->suffix) { + byte_copyr(d->query + 54,len + 32,d->query + 16); + uint16_pack_big(d->query,len + 84); + byte_copy(d->query + 2,8,"Q6fnvWj8"); + byte_copy(d->query + 10,32,d->pubkey); + byte_copy(d->query + 42,12,nonce); + return; + } + + byte_copyr(d->query + d->querylen - len - 32,len + 32,d->query + 16); + byte_copy(d->query + d->querylen - len - 44,12,nonce); + + suffixlen = dns_domain_length(d->suffix); + m = base32_bytessize(len + 44); + + uint16_pack_big(d->query,d->querylen - 2); + d->query[2] = dns_random(256); + d->query[3] = dns_random(256); + byte_copy(d->query + 4,10,"\0\0\0\1\0\0\0\0\0\0"); + base32_encodebytes(d->query + 14,d->query + d->querylen - len - 44,len + 44); + base32_encodekey(d->query + 14 + m,d->pubkey); + byte_copy(d->query + 69 + m,suffixlen,d->suffix); + byte_copy(d->query + 69 + m + suffixlen,4,DNS_T_TXT DNS_C_IN); +} + +static int uncurve(const struct dns_transmit *d,char *buf,unsigned int *lenp) +{ + const char *key; + char nonce[24]; + unsigned int len; + char out[16]; + unsigned int pos; + uint16 datalen; + unsigned int i; + unsigned int j; + char ch; + unsigned int txtlen; + unsigned int namelen; + + if (!d->keys) return 0; + + key = d->keys + 32 * d->curserver; + len = *lenp; + + if (!d->suffix) { + if (len < 48) return 1; + if (byte_diff(buf,8,"R6fnvWJ8")) return 1; + if (byte_diff(buf + 8,12,d->nonce)) return 1; + byte_copy(nonce,24,buf + 8); + byte_zero(buf + 16,16); + if (crypto_box_open_afternm((unsigned char *) buf + 16,(const unsigned char *) buf + 16,len - 16,(const unsigned char *) nonce,(const unsigned char *) key)) return 1; + byte_copy(buf,len - 48,buf + 48); + *lenp = len - 48; + return 0; + } + + /* XXX: be more leniant? */ + + pos = dns_packet_copy(buf,len,0,out,12); if (!pos) return 1; + if (byte_diff(out,2,d->query + 2)) return 1; + if (byte_diff(out + 2,10,"\204\0\0\1\0\1\0\0\0\0")) return 1; + + /* query name might be >255 bytes, so can't use dns_packet_getname */ + namelen = dns_domain_length(d->query + 14); + if (namelen > len - pos) return 1; + if (case_diffb(buf + pos,namelen,d->query + 14)) return 1; + pos += namelen; + + pos = dns_packet_copy(buf,len,pos,out,16); if (!pos) return 1; + if (byte_diff(out,14,"\0\20\0\1\300\14\0\20\0\1\0\0\0\0")) return 1; + uint16_unpack_big(out + 14,&datalen); + if (datalen > len - pos) return 1; + + j = 4; + txtlen = 0; + for (i = 0;i < datalen;++i) { + ch = buf[pos + i]; + if (!txtlen) + txtlen = (unsigned char) ch; + else { + --txtlen; + buf[j++] = ch; + } + } + if (txtlen) return 1; + + if (j < 32) return 1; + byte_copy(nonce,12,d->nonce); + byte_copy(nonce + 12,12,buf + 4); + byte_zero(buf,16); + if (crypto_box_open_afternm((unsigned char *) buf,(const unsigned char *) buf,j,(const unsigned char *) nonce,(const unsigned char *) key)) return 1; + byte_copy(buf,j - 32,buf + 32); + *lenp = j - 32; + return 0; +} + static int serverwantstcp(const char *buf,unsigned int len) { char out[12]; @@ -36,13 +257,13 @@ static int irrelevant(const struct dns_t 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 (byte_diff(out,2,d->nonce + 8)) 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; } + if (!dns_domain_equal(dn,d->name)) { alloc_free(dn); return 1; } alloc_free(dn); pos = dns_packet_copy(buf,len,pos,out,4); if (!pos) return 1; @@ -104,8 +325,7 @@ static int thisudp(struct dns_transmit * 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); + prepquery(d); d->s1 = 1 + socket_udp(); if (!d->s1) { dns_transmit_free(d); return -1; } @@ -155,8 +375,7 @@ static int thistcp(struct dns_transmit * 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); + prepquery(d); d->s1 = 1 + socket_tcp(); if (!d->s1) { dns_transmit_free(d); return -1; } @@ -195,25 +414,47 @@ static int nexttcp(struct dns_transmit * 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]) { + return dns_transmit_start2(d,servers,flagrecursive,q,qtype,localip,0,0,0); +} + +int dns_transmit_start2(struct dns_transmit *d,const char servers[64],int flagrecursive,const char *q,const char qtype[2],const char localip[4],const char keys[512],const char pubkey[32],const char *suffix) +{ unsigned int len; + unsigned int suffixlen; + unsigned int m; dns_transmit_free(d); errno = error_io; len = dns_domain_length(q); - d->querylen = len + 18; + + if (!keys) + d->querylen = len + 18; + else if (!suffix) + d->querylen = len + 86; + else { + suffixlen = dns_domain_length(suffix); + m = base32_bytessize(len + 44); + d->querylen = m + suffixlen + 73; + } + 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); - + d->name = q; byte_copy(d->qtype,2,qtype); d->servers = servers; byte_copy(d->localip,4,localip); + d->flagrecursive = flagrecursive; + d->keys = keys; + d->pubkey = pubkey; + d->suffix = suffix; + + if (!d->keys) { + uint16_pack_big(d->query,len + 16); + makebasequery(d,d->query + 2); + d->name = d->query + 14; /* keeps dns_transmit_start backwards compatible */ + } d->udploop = flagrecursive ? 1 : 0; @@ -240,10 +481,11 @@ void dns_transmit_io(struct dns_transmit int dns_transmit_get(struct dns_transmit *d,const iopause_fd *x,const struct taia *when) { - char udpbuf[513]; + char udpbuf[4097]; unsigned char ch; int r; int fd; + unsigned int len; errno = error_io; fd = d->s1 - 1; @@ -267,15 +509,17 @@ have sent query to curserver on UDP sock } 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)) { + len = r; + if (uncurve(d,udpbuf,&len)) return 0; + if (irrelevant(d,udpbuf,len)) return 0; + if (serverwantstcp(udpbuf,len)) return firsttcp(d); + if (serverfailed(udpbuf,len)) { if (d->udploop == 2) return 0; return nextudp(d); } socketfree(d); - d->packetlen = r; + d->packetlen = len; d->packet = alloc(d->packetlen); if (!d->packet) { dns_transmit_free(d); return -1; } byte_copy(d->packet,d->packetlen,udpbuf); @@ -354,6 +598,7 @@ have received pos bytes of packet if (d->pos < d->packetlen) return 0; socketfree(d); + if (uncurve(d,d->packet,&d->packetlen)) return nexttcp(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); diff -pru djbdns-1.05.orig/dnscache.c djbdns-1.05/dnscache.c --- djbdns-1.05.orig/dnscache.c 2001-02-11 13:11:45.000000000 -0800 +++ djbdns-1.05/dnscache.c 2009-04-22 08:31:47.000000000 -0700 @@ -418,6 +418,8 @@ int main() dns_random_init(seed); close(0); + query_init(); + x = env_get("IPSEND"); if (!x) strerr_die2x(111,FATAL,"$IPSEND not set"); @@ -435,6 +437,8 @@ int main() response_hidettl(); if (env_get("FORWARDONLY")) query_forwardonly(); + if (env_get("USETXTFORMAT")) + query_usetxtformat(); if (!roots_init()) strerr_die2sys(111,FATAL,"unable to read servers: "); diff -pru djbdns-1.05.orig/log.c djbdns-1.05/log.c --- djbdns-1.05.orig/log.c 2001-02-11 13:11:45.000000000 -0800 +++ djbdns-1.05/log.c 2009-05-30 15:00:04.000000000 -0700 @@ -135,13 +135,14 @@ void log_tcpclose(const char client[4],u line(); } -void log_tx(const char *q,const char qtype[2],const char *control,const char servers[64],unsigned int gluelessness) +void log_tx(const char *q,const char qtype[2],const char *control,const char servers[64],unsigned int flaghavekeys,unsigned int gluelessness) { int i; string("tx "); number(gluelessness); space(); logtype(qtype); space(); name(q); space(); name(control); + string(flaghavekeys ? " +" : " -"); for (i = 0;i < 64;i += 4) if (byte_diff(servers + i,4,"\0\0\0\0")) { space(); diff -pru djbdns-1.05.orig/log.h djbdns-1.05/log.h --- djbdns-1.05.orig/log.h 2001-02-11 13:11:45.000000000 -0800 +++ djbdns-1.05/log.h 2009-04-21 12:55:50.000000000 -0700 @@ -17,7 +17,7 @@ extern void log_cachedcname(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_tx(const char *,const char *,const char *,const char *,unsigned int,unsigned int); extern void log_nxdomain(const char *,const char *,unsigned int); extern void log_nodata(const char *,const char *,const char *,unsigned int); diff -pru djbdns-1.05.orig/query.c djbdns-1.05/query.c --- djbdns-1.05.orig/query.c 2001-02-11 13:11:45.000000000 -0800 +++ djbdns-1.05/query.c 2009-06-02 12:38:33.000000000 -0700 @@ -13,6 +13,24 @@ #include "response.h" #include "query.h" +#include "crypto_scalarmult_curve25519.h" +#include "crypto_box_curve25519xsalsa20poly1305.h" + +#define crypto_scalarmult_base crypto_scalarmult_curve25519_base +#define crypto_box_beforenm crypto_box_curve25519xsalsa20poly1305_beforenm + +static char secretkey[32]; +static char publickey[32]; + +void query_init(void) +{ + int k; + + /* called after droproot(), can't use crypto_box_keypair (depends on /dev/urandom) */ + for (k = 0;k < 32;++k) secretkey[k] = dns_random(256); + crypto_scalarmult_base((unsigned char *) publickey,(unsigned char *) secretkey); +} + static int flagforwardonly = 0; void query_forwardonly(void) @@ -20,6 +38,13 @@ void query_forwardonly(void) flagforwardonly = 1; } +static int flagusetxtformat = 0; + +void query_usetxtformat(void) +{ + flagusetxtformat = 1; +} + static void cachegeneric(const char type[2],const char *d,const char *data,unsigned int datalen,uint32 ttl) { unsigned int len; @@ -120,6 +145,74 @@ static int globalip(char *d,char ip[4]) return 0; } +/* XXX: move to base32.c */ +static unsigned int base32_decode(char *out,const char *in,unsigned int len,int mode) +{ + /* + * digits = '0123456789bcdfghjklmnpqrstuvwxyz' + * ','.join('%2d' % digits.find(chr(x).lower()) for x in xrange(256)) + */ + static const char val[256] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, + -1,-1,10,11,12,-1,13,14,15,-1,16,17,18,19,20,-1, + 21,22,23,24,25,26,27,28,29,30,31,-1,-1,-1,-1,-1, + -1,-1,10,11,12,-1,13,14,15,-1,16,17,18,19,20,-1, + 21,22,23,24,25,26,27,28,29,30,31,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + }; + + unsigned int i; + unsigned int x, v, vbits; + char *out0 = out; + + v = vbits = 0; + for (i = 0;i < len;++i) { + x = (unsigned char) val[(unsigned char) in[i]]; + if (x >= 32) return 0; + v |= x << vbits; + vbits += 5; + if (vbits >= 8) { + *out++ = v; + v >>= 8; + vbits -= 8; + } + } + + if (mode) { + if (vbits) + *out++ = v; + } + else if (vbits >= 5 || v) + return 0; + + return out - out0; +} + +static int findkey(const char *dn,char key[32]) +{ + unsigned char c; + + while (c = *dn++) { + if (c == 54) + if (!case_diffb(dn,3,"uz5")) + if (base32_decode(key,dn + 3,51,1) == 32) + return 1; + dn += (unsigned int) c; + } + + return 0; +} + static char *t1 = 0; static char *t2 = 0; static char *t3 = 0; @@ -157,6 +250,27 @@ static int smaller(char *buf,unsigned in return 0; } +static void addserver(struct query *z,const char *addr,int flaghaskey,const char *key) +{ + int k; + + if (z->flaghavekeys[z->level - 1]) { + if (!flaghaskey) return; + } else if (flaghaskey) { + byte_zero(z->servers[z->level - 1],64); + byte_zero(z->keys[z->level - 1],512); + z->flaghavekeys[z->level - 1] = 1; + } + + 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,addr); + if (flaghaskey) + byte_copy(z->keys[z->level - 1] + 8 * k,32,key); + break; + } +} + static int doit(struct query *z,int state) { char key[257]; @@ -165,8 +279,11 @@ static int doit(struct query *z,int stat char *buf; unsigned int len; const char *whichserver; + char *whichkey; char header[12]; char misc[20]; + char pubkey[32]; + int flaghaskey; unsigned int rcode; unsigned int posanswers; uint16 numanswers; @@ -210,11 +327,7 @@ static int doit(struct query *z,int stat 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; - } + addserver(z,misc,0,0); goto LOWERLEVEL; } if (!rqa(z)) goto DIE; @@ -324,13 +437,10 @@ static int doit(struct query *z,int stat cached = cache_get(key,dlen + 2,&cachedlen,&ttl); if (cached && (cachedlen || byte_diff(dtype,2,DNS_T_ANY))) { if (z->level) { + flaghaskey = findkey(d,pubkey); 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; - } + addserver(z,cached,flaghaskey,pubkey); cached += 4; cachedlen -= 4; } @@ -375,7 +485,8 @@ static int doit(struct query *z,int stat } for (;;) { - if (roots(z->servers[z->level],d)) { + if (roots(z->servers[z->level],d)) { /* XXX: allow roots() to provide keys */ + z->flaghavekeys[z->level] = 0; for (j = 0;j < QUERY_MAXNS;++j) dns_domain_free(&z->ns[z->level][j]); z->control[z->level] = d; @@ -391,6 +502,7 @@ static int doit(struct query *z,int stat if (cached && cachedlen) { z->control[z->level] = d; byte_zero(z->servers[z->level],64); + z->flaghavekeys[z->level] = 0; for (j = 0;j < QUERY_MAXNS;++j) dns_domain_free(&z->ns[z->level][j]); pos = 0; @@ -428,15 +540,27 @@ static int doit(struct query *z,int stat 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; + if (z->flaghavekeys[z->level]) { + byte_copy(key,2,DNS_T_AXFR); + for (j = 0;j < 64;j += 4) + if (byte_diff(z->servers[z->level] + j,4,"\0\0\0\0")) { + whichkey = z->keys[z->level] + 8 * j; + byte_copy(key + 2,32,whichkey); + cached = cache_get(key,34,&cachedlen,&ttl); + if (cached && (cachedlen == 32)) { + byte_copy(whichkey,32,cached); + continue; + } + crypto_box_beforenm((unsigned char *) whichkey,(const unsigned char *) whichkey,(const unsigned char *) secretkey); + cache_set(key,34,whichkey,32,655360); + } } + + dns_sortip2(z->servers[z->level],z->keys[z->level],16); + dtype = z->level ? DNS_T_A : z->type; + log_tx(z->name[z->level],dtype,z->control[z->level],z->servers[z->level],z->flaghavekeys[z->level],z->level); + control = flagusetxtformat ? z->control[z->level] : 0; + if (dns_transmit_start2(&z->dt,z->servers[z->level],flagforwardonly,z->name[z->level],dtype,z->localip,z->flaghavekeys[z->level] ? z->keys[z->level] : 0,publickey,control) == -1) goto DIE; return 0; @@ -714,6 +838,7 @@ static int doit(struct query *z,int stat if (flagout || flagsoa || !flagreferral) { if (z->level) { + flaghaskey = findkey(d,pubkey); pos = posanswers; for (j = 0;j < numanswers;++j) { pos = dns_packet_getname(buf,len,pos,&t1); if (!pos) goto DIE; @@ -722,12 +847,10 @@ static int doit(struct query *z,int stat 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; - } + if (datalen == 4) { + if (!dns_packet_copy(buf,len,pos,misc,4)) goto DIE; + addserver(z,misc,flaghaskey,pubkey); + } pos += datalen; } goto LOWERLEVEL; @@ -784,6 +907,7 @@ static int doit(struct query *z,int stat control = d + dns_domain_suffixpos(d,referral); z->control[z->level] = control; byte_zero(z->servers[z->level],64); + z->flaghavekeys[z->level] = 0; for (j = 0;j < QUERY_MAXNS;++j) dns_domain_free(&z->ns[z->level][j]); k = 0; diff -pru djbdns-1.05.orig/query.h djbdns-1.05/query.h --- djbdns-1.05.orig/query.h 2001-02-11 13:11:45.000000000 -0800 +++ djbdns-1.05/query.h 2009-05-29 18:32:16.000000000 -0700 @@ -15,6 +15,8 @@ struct query { char *control[QUERY_MAXLEVEL]; /* pointing inside name */ char *ns[QUERY_MAXLEVEL][QUERY_MAXNS]; char servers[QUERY_MAXLEVEL][64]; + char keys[QUERY_MAXLEVEL][512]; + int flaghavekeys[QUERY_MAXLEVEL]; char *alias[QUERY_MAXALIAS]; uint32 aliasttl[QUERY_MAXALIAS]; char localip[4]; @@ -27,6 +29,8 @@ extern int query_start(struct query *,ch extern void query_io(struct query *,iopause_fd *,struct taia *); extern int query_get(struct query *,iopause_fd *,struct taia *); +extern void query_init(void); extern void query_forwardonly(void); +extern void query_usetxtformat(void); #endif