(C) 2012 Peter Conrad This patch is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . diff -rNU3 djbdns-1.05.tds-base/axfrdns.c djbdns-1.05.tinydnssec/axfrdns.c --- djbdns-1.05.tds-base/axfrdns.c 2012-12-06 22:45:38.000000000 +0100 +++ djbdns-1.05.tinydnssec/axfrdns.c 2012-12-06 22:39:13.000000000 +0100 @@ -23,6 +23,7 @@ #include "response.h" #include "ip6.h" #include "clientloc.h" +#include "edns0.h" extern int respond(char *,char *,char *); @@ -346,6 +347,9 @@ if (byte_diff(qclass,2,DNS_C_IN) && byte_diff(qclass,2,DNS_C_ANY)) strerr_die2x(111,FATAL,"bogus query: bad class"); + pos = check_edns0(header, buf, len, pos); + if (!pos) die_truncated(); + qlog(ip,port,header,zone,qtype," "); if (byte_equal(qtype,2,DNS_T_AXFR)) { diff -rNU3 djbdns-1.05.tds-base/base32hex.c djbdns-1.05.tinydnssec/base32hex.c --- djbdns-1.05.tds-base/base32hex.c 1970-01-01 01:00:00.000000000 +0100 +++ djbdns-1.05.tinydnssec/base32hex.c 2012-12-06 22:39:13.000000000 +0100 @@ -0,0 +1,79 @@ +/* (C) 2012 Peter Conrad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "base32hex.h" + +#define to_32hex(c) ((c) < 10 ? (c) + '0' : (c) + 'a' - 10) + +/* out must point to a buffer of at least (len * 8 / 5) + 1 bytes. + * Encoded string is *not* padded. + * See RFC-4648. This implementation produces lowercase hex characters. + * Returns length of encoded string. + */ +unsigned int base32hex(char *out, uint8_t *in, unsigned int len) { +int buf = 0, bits = 0; +char *x = out; + + while (len-- > 0) { + buf <<= 8; + buf |= *in++; + bits += 8; + while (bits >= 5) { + char c = (buf >> (bits - 5)) & 0x1f; + *x++ = to_32hex(c); + bits -= 5; + } + } + if (bits > 0) { + char c = (buf << (5 - bits)) & 0x1f; + *x++ = to_32hex(c); + } + return x - out; +} + +#ifdef TEST +#include +#include +#include + +static void test(char *in, char *expected, int explen) { +char buf[255]; +int r; + + if ((r = base32hex(buf, in, strlen(in))) != explen) { + printf("Failed: b32h('%s') yields %d chars (expected %d)\n", + in, r, explen); + exit(1); + } + if (strncmp(buf, expected, r)) { + buf[r] = 0; + printf("Failed: b32h('%s') = '%s' (expected %s)\n", + in, buf, expected); + exit(1); + } +} + +int main(int argc, char **argv) { + test("", "", 0); + test("f", "co", 2); + test("fo", "cpng", 4); + test("foo", "cpnmu", 5); + test("foob", "cpnmuog", 7); + test("fooba", "cpnmuoj1", 8); + test("foobar", "cpnmuoj1e8", 10); + printf("Success!\n"); +} + +#endif diff -rNU3 djbdns-1.05.tds-base/base32hex.h djbdns-1.05.tinydnssec/base32hex.h --- djbdns-1.05.tds-base/base32hex.h 1970-01-01 01:00:00.000000000 +0100 +++ djbdns-1.05.tinydnssec/base32hex.h 2012-12-06 22:39:13.000000000 +0100 @@ -0,0 +1,23 @@ +/* (C) 2012 Peter Conrad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _BASE32_HEX_H +#define _BASE32_HEX_H + +#include + +extern unsigned int base32hex(char *out, uint8_t *in, unsigned int len); + +#endif diff -rNU3 djbdns-1.05.tds-base/dns.h djbdns-1.05.tinydnssec/dns.h --- djbdns-1.05.tds-base/dns.h 2012-12-06 22:45:38.000000000 +0100 +++ djbdns-1.05.tinydnssec/dns.h 2012-12-06 22:39:13.000000000 +0100 @@ -20,8 +20,17 @@ #define DNS_T_SIG "\0\30" #define DNS_T_KEY "\0\31" #define DNS_T_AAAA "\0\34" +#define DNS_T_OPT "\0\51" +#define DNS_T_DS "\0\53" +#define DNS_T_RRSIG "\0\56" +#define DNS_T_DNSKEY "\0\60" +#define DNS_T_NSEC3 "\0\62" +#define DNS_T_NSEC3PARAM "\0\63" #define DNS_T_AXFR "\0\374" #define DNS_T_ANY "\0\377" +/* Pseudo-RRs for DNSSEC */ +#define DNS_T_HASHREF "\377\1" +#define DNS_T_HASHLIST "\377\2" struct dns_transmit { char *query; /* 0, or dynamically allocated */ diff -rNU3 djbdns-1.05.tds-base/edns0.c djbdns-1.05.tinydnssec/edns0.c --- djbdns-1.05.tds-base/edns0.c 1970-01-01 01:00:00.000000000 +0100 +++ djbdns-1.05.tinydnssec/edns0.c 2012-12-06 22:39:13.000000000 +0100 @@ -0,0 +1,45 @@ +/* (C) 2012 Peter Conrad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dns.h" +#include "edns0.h" +#include "response.h" +#include "uint16.h" + +unsigned int check_edns0(const char header[12], const char *buf, const int len, unsigned int pos) +{ +char opt_class[2]; +char opt_ttl[4]; + + max_response_len = 512; + do_dnssec = 0; + if (!header[6] && !header[7] && !header[8] && !header[9] + && !header[10] && header[11] == 1) { + char nametype[3]; + uint16 size, min_len; + pos = dns_packet_copy(buf,len,pos,nametype,3); if (!pos) return pos; + if (nametype[0] || nametype[1] || nametype[2] != DNS_T_OPT[1]) return pos; + pos = dns_packet_copy(buf,len,pos,opt_class,2); if (!pos) return pos; + pos = dns_packet_copy(buf,len,pos,opt_ttl,4); if (!pos) return pos; + if (opt_ttl[0]) return pos; // unsupported RCODE in query + if (opt_ttl[1]) return pos; // unsupported version + do_dnssec = opt_ttl[2] & 0x80; + uint16_unpack_big(opt_class, &size); + min_len = do_dnssec ? 1220 : 512; + max_response_len = size > 4000 ? 4000 : size; + if (max_response_len < min_len) { max_response_len = min_len; } + } + return pos; +} diff -rNU3 djbdns-1.05.tds-base/edns0.h djbdns-1.05.tinydnssec/edns0.h --- djbdns-1.05.tds-base/edns0.h 1970-01-01 01:00:00.000000000 +0100 +++ djbdns-1.05.tinydnssec/edns0.h 2012-12-06 22:39:13.000000000 +0100 @@ -0,0 +1,22 @@ +/* (C) 2012 Peter Conrad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _EDNS0_H + +#define _EDNS0_H + +extern unsigned int check_edns0(const char *, const char *, const int, unsigned int); + +#endif diff -rNU3 djbdns-1.05.tds-base/Makefile djbdns-1.05.tinydnssec/Makefile --- djbdns-1.05.tds-base/Makefile 2012-12-06 22:45:45.000000000 +0100 +++ djbdns-1.05.tinydnssec/Makefile 2012-12-07 11:07:23.000000000 +0100 @@ -53,10 +53,10 @@ axfrdns: \ load axfrdns.o iopause.o droproot.o tdlookup.o response.o qlog.o \ prot.o timeoutread.o timeoutwrite.o clientloc.o dns.a libtai.a alloc.a env.a \ -cdb.a buffer.a unix.a byte.a +cdb.a buffer.a unix.a byte.a sha1.o base32hex.o edns0.o ./load axfrdns iopause.o droproot.o tdlookup.o response.o \ qlog.o prot.o timeoutread.o timeoutwrite.o clientloc.o dns.a libtai.a \ - alloc.a env.a cdb.a buffer.a unix.a byte.a + alloc.a env.a cdb.a buffer.a unix.a byte.a sha1.o base32hex.o edns0.o axfrdns-conf: \ load axfrdns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a @@ -76,6 +76,10 @@ response.h uint32.h clientloc.h ./compile axfrdns.c +base32hex.o: \ +compile base32hex.c base32hex.h + ./compile base32hex.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 @@ -454,10 +458,11 @@ 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 +env.a libtai.a buffer.a alloc.a unix.a byte.a socket.lib printtype.o \ +base32hex.o ./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` + byte.a `cat socket.lib` printtype.o base32hex.o dnsq.o: \ compile dnsq.c uint16.h strerr.h buffer.h scan.h str.h byte.h error.h \ @@ -467,10 +472,11 @@ 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 +env.a libtai.a buffer.a alloc.a unix.a byte.a socket.lib printtype.o \ +base32hex.o ./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` + byte.a `cat socket.lib` printtype.o base32hex.o dnsqr.o: \ compile dnsqr.c uint16.h strerr.h buffer.h scan.h str.h byte.h \ @@ -480,10 +486,10 @@ 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 +libtai.a alloc.a buffer.a unix.a byte.a socket.lib printtype.o base32hex.o ./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` + socket.lib` printtype.o base32hex.o dnstrace.o: \ compile dnstrace.c uint16.h uint32.h fmt.h str.h byte.h ip4.h \ @@ -514,6 +520,10 @@ compile droproot.c env.h scan.h prot.h strerr.h ./compile droproot.c +edns0.o: \ +compile edns0.c edns0.h uint16.h dns.h response.h iopause.h taia.h uint64.h + ./compile edns0.c + env.a: \ makelib env.o ./makelib env.a env.o @@ -689,10 +699,10 @@ pickdns: \ load pickdns.o server.o iopause.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 +env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib edns0.o ./load pickdns server.o iopause.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` + byte.a `cat socket.lib` edns0.o pickdns-conf: \ load pickdns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a @@ -725,15 +735,19 @@ 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 +printrecord.h stralloc.h printpacket.h stralloc.h printtype.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 +printrecord.h stralloc.h printtype.h ./compile printrecord.c +printtype.o: \ +compile printtype.c printtype.h dns.h stralloc.h byte.h uint16.h iopause.h taia.h uint64.h + ./compile printtype.c + prog: \ dnscache-conf dnscache walldns-conf walldns rbldns-conf rbldns \ rbldns-data pickdns-conf pickdns pickdns-data tinydns-conf tinydns \ @@ -767,10 +781,10 @@ rbldns: \ load rbldns.o server.o iopause.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 +env.a libtai.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib edns0.o ./load rbldns server.o iopause.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` + byte.a `cat socket.lib` edns0.o rbldns-conf: \ load rbldns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a @@ -840,7 +854,7 @@ 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 iopause.h alloc.h str.h +taia.h iopause.h alloc.h str.h edns0.h ./compile server.c setup: \ @@ -931,6 +945,10 @@ cp /dev/null haven2i.h ./choose cL tryn2i haven2i.h1 haven2i.h2 socket > haven2i.h +sha1.o: \ +compile sha1.c sha1.h + ./compile sha1.c + str_chr.o: \ compile str_chr.c str.h ./compile str_chr.c @@ -1072,7 +1090,7 @@ 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 ip6.h clientloc.h +taia.h seek.h response.h uint32.h ip6.h clientloc.h sha1.h base32hex.h ./compile tdlookup.c timeoutread.o: \ @@ -1088,10 +1106,10 @@ tinydns: \ load tinydns.o server.o iopause.o droproot.o tdlookup.o response.o qlog.o \ prot.o clientloc.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a byte.a \ -socket.lib +socket.lib sha1.o base32hex.o edns0.o ./load tinydns server.o iopause.o droproot.o tdlookup.o response.o \ qlog.o prot.o clientloc.o dns.a libtai.a env.a cdb.a alloc.a buffer.a \ - unix.a byte.a `cat socket.lib` + unix.a byte.a `cat socket.lib` sha1.o base32hex.o edns0.o tinydns-conf: \ load tinydns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a @@ -1126,11 +1144,12 @@ ./compile tinydns-edit.c tinydns-get: \ -load tinydns-get.o tdlookup.o response.o printpacket.o printrecord.o \ -parsetype.o clientloc.o dns.a libtai.a cdb.a buffer.a alloc.a unix.a byte.a +load tinydns-get.o tdlookup.o sha1.o response.o printpacket.o printrecord.o \ +parsetype.o clientloc.o dns.a libtai.a cdb.a buffer.a alloc.a unix.a byte.a \ +base32hex.o printtype.o ./load tinydns-get tdlookup.o response.o printpacket.o \ printrecord.o parsetype.o clientloc.o dns.a libtai.a cdb.a buffer.a \ - alloc.a unix.a byte.a + alloc.a unix.a byte.a sha1.o base32hex.o printtype.o tinydns-get.o: \ compile tinydns-get.c str.h byte.h scan.h exit.h stralloc.h \ @@ -1198,10 +1217,10 @@ walldns: \ load walldns.o server.o iopause.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 +dns.a env.a cdb.a alloc.a buffer.a unix.a byte.a socket.lib edns0.o ./load walldns server.o iopause.o response.o droproot.o qlog.o \ prot.o dd.o dns.a libtai.a env.a cdb.a alloc.a buffer.a unix.a \ - byte.a `cat socket.lib` + byte.a `cat socket.lib` edns0.o walldns-conf: \ load walldns-conf.o generic-conf.o auto_home.o buffer.a unix.a byte.a @@ -1227,4 +1246,4 @@ ./choose c trysa6 sockaddr_in6.h1 sockaddr_in6.h2 > sockaddr_in6.h clean: - rm -f `cat TARGETS` + rm -f `cat TARGETS` data data.cdb test/[ot]* diff -rNU3 djbdns-1.05.tds-base/parsetype.c djbdns-1.05.tinydnssec/parsetype.c --- djbdns-1.05.tds-base/parsetype.c 2001-02-11 22:11:45.000000000 +0100 +++ djbdns-1.05.tinydnssec/parsetype.c 2012-12-06 22:39:13.000000000 +0100 @@ -24,6 +24,8 @@ 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 if (case_equals(s,"dnskey")) byte_copy(type,2,DNS_T_DNSKEY); + else if (case_equals(s,"ds")) byte_copy(type,2,DNS_T_DS); else return 0; diff -rNU3 djbdns-1.05.tds-base/printpacket.c djbdns-1.05.tinydnssec/printpacket.c --- djbdns-1.05.tds-base/printpacket.c 2001-02-11 22:11:45.000000000 +0100 +++ djbdns-1.05.tinydnssec/printpacket.c 2012-12-06 22:39:13.000000000 +0100 @@ -5,6 +5,7 @@ #include "dns.h" #include "printrecord.h" #include "printpacket.h" +#include "printtype.h" static char *d; @@ -67,8 +68,7 @@ X("weird class") } else { - uint16_unpack_big(data,&type); - NUM(type) + if (!printtype(out,data)) return 0; X(" ") if (!dns_domain_todot_cat(out,d)) return 0; } diff -rNU3 djbdns-1.05.tds-base/printrecord.c djbdns-1.05.tinydnssec/printrecord.c --- djbdns-1.05.tds-base/printrecord.c 2012-12-06 22:45:38.000000000 +0100 +++ djbdns-1.05.tinydnssec/printrecord.c 2012-12-06 22:39:13.000000000 +0100 @@ -5,9 +5,25 @@ #include "dns.h" #include "printrecord.h" #include "ip6.h" +#include "base32hex.h" +#include "printtype.h" static char *d; +static const char *HEX = "0123456789ABCDEF"; + +static int hexout(stralloc *out,const char *buf,unsigned int len,unsigned int pos,unsigned int n) { + unsigned char c; + int i; + + for (i = 0; i < n; i++) { + pos = dns_packet_copy(buf,len,pos,&c,1); if (!pos) return 0; + if (!stralloc_catb(out,&HEX[(c>>4)&0xf],1)) return 0; + if (!stralloc_catb(out,&HEX[c&0xf],1)) return 0; + } + return pos; +} + 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; @@ -18,6 +34,7 @@ unsigned int newpos; int i; unsigned char ch; + int rawlen; 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; @@ -33,15 +50,20 @@ 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,DNS_T_OPT)) { + 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; + if (byte_diff(misc + 2,2,DNS_C_IN)) { + if (!stralloc_cats(out," weird class\n")) return 0; + return newpos; + } + } else { + if (!stralloc_cats(out,"0")) return 0; } x = 0; + rawlen = 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 "; @@ -92,12 +114,111 @@ stringlen=ip6_fmt(ip6str,misc); if (!stralloc_catb(out,ip6str,stringlen)) return 0; } + else if (byte_equal(misc,2,DNS_T_DNSKEY)) { + pos = dns_packet_copy(buf,len,pos,misc,4); if (!pos) return 0; + if (!stralloc_cats(out," DNSKEY ")) return 0; + uint16_unpack_big(misc,&u16); + if (!stralloc_catulong0(out,u16,0)) return 0; + if (!stralloc_cats(out," ")) return 0; + if (!stralloc_catulong0(out,misc[2],0)) return 0; + if (!stralloc_cats(out," ")) return 0; + if (!stralloc_catulong0(out,misc[3],0)) return 0; + if (!stralloc_cats(out," ")) return 0; + rawlen = datalen - 4; + } + else if (byte_equal(misc,2,DNS_T_DS)) { + pos = dns_packet_copy(buf,len,pos,misc,4); if (!pos) return 0; + if (!stralloc_cats(out," DS ")) return 0; + uint16_unpack_big(misc,&u16); + if (!stralloc_catulong0(out,u16,0)) return 0; + if (!stralloc_cats(out," ")) return 0; + if (!stralloc_catulong0(out,misc[2],0)) return 0; + if (!stralloc_cats(out," ")) return 0; + if (!stralloc_catulong0(out,misc[3],0)) return 0; + if (!stralloc_cats(out," ")) return 0; + pos = hexout(out,buf,len,pos,datalen - 4); if (!pos) return 0; + } + else if (byte_equal(misc,2,DNS_T_RRSIG)) { + pos = dns_packet_copy(buf,len,pos,misc,18); if (!pos) return 0; + if (!stralloc_cats(out," RRSIG ")) return 0; + if (!printtype(out,misc)) return 0; + if (!stralloc_cats(out," ")) return 0; + if (!stralloc_catulong0(out,misc[2],0)) return 0; + if (!stralloc_cats(out," ")) return 0; + if (!stralloc_catulong0(out,misc[3],0)) return 0; + if (!stralloc_cats(out," ")) return 0; + uint32_unpack_big(misc + 4,&u32); + if (!stralloc_catulong0(out,u32,0)) return 0; + if (!stralloc_cats(out," ")) return 0; + uint32_unpack_big(misc + 8,&u32); + if (!stralloc_catulong0(out,u32,0)) return 0; + if (!stralloc_cats(out," ")) return 0; + uint32_unpack_big(misc + 12,&u32); + if (!stralloc_catulong0(out,u32,0)) return 0; + if (!stralloc_cats(out," ")) return 0; + uint16_unpack_big(misc + 16,&u16); + if (!stralloc_catulong0(out,u16,0)) return 0; + if (!stralloc_cats(out," ")) return 0; + rawlen = dns_packet_getname(buf,len,pos,&d); if (!pos) return 0; + rawlen = datalen - 18 - (rawlen - pos); + pos += datalen - 18 - rawlen; + if (!dns_domain_todot_cat(out,d)) return 0; + if (!stralloc_cats(out," ")) return 0; + } + else if (byte_equal(misc,2,DNS_T_NSEC3)) { + char nextHash[255]; + char nextOwner[255*8/5]; + int j; + pos = dns_packet_copy(buf,len,pos,misc,5); if (!pos) return 0; + if (!stralloc_cats(out," NSEC3 ")) return 0; + if (!stralloc_catulong0(out,misc[0],0)) return 0; + if (!stralloc_cats(out," ")) return 0; + if (!stralloc_catulong0(out,misc[1],0)) return 0; + if (!stralloc_cats(out," ")) return 0; + uint16_unpack_big(misc+2,&u16); + if (!stralloc_catulong0(out,u16,0)) return 0; + if (!stralloc_cats(out," ")) return 0; + if (!misc[4]) + if (!stralloc_cats(out,"-")) return 0; + pos = hexout(out,buf,len,pos,misc[4]); if (!pos) return 0; + if (!stralloc_cats(out," ")) return 0; + pos = dns_packet_copy(buf,len,pos,misc,1); if (!pos) return 0; + pos = dns_packet_copy(buf,len,pos,nextHash,misc[0]); if (!pos) return 0; + i = base32hex(nextOwner, nextHash, misc[0]); + if (!stralloc_catb(out,nextOwner,i)) return 0; + while (pos < newpos) { + pos = dns_packet_copy(buf,len,pos,misc,2); if (!pos) return 0; + pos = dns_packet_copy(buf,len,pos,nextHash,misc[1]); if (!pos) return 0; + j = 8 * misc[1]; + for (i = 0; i < j; i++) { + if (nextHash[i/8] & (1 << (7 - (i%8)))) { + misc[1] = i; + if (!stralloc_cats(out," ")) return 0; + if (!printtype(out,misc)) return 0; + } + } + } + } + else if (byte_equal(misc,2,DNS_T_OPT)) { + if (!stralloc_cats(out," OPT ")) return 0; + uint16_unpack_big(misc+2, &u16); + if (!stralloc_catulong0(out,u16,0)) return 0; + if (!stralloc_cats(out," ")) return 0; + if (!stralloc_catulong0(out,misc[4],0)) return 0; + if (!stralloc_cats(out," ")) return 0; + if (!stralloc_catulong0(out,misc[5],0)) return 0; + if (!stralloc_cats(out," ")) return 0; + if (!hexout(out,misc,8,6,2)) return 0; + rawlen = datalen; + } 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--) { + rawlen = datalen; + } + while (rawlen--) { 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; @@ -111,7 +232,6 @@ if (!stralloc_catb(out,misc,4)) return 0; } } - } if (!stralloc_cats(out,"\n")) return 0; if (pos != newpos) { errno = error_proto; return 0; } diff -rNU3 djbdns-1.05.tds-base/printtype.c djbdns-1.05.tinydnssec/printtype.c --- djbdns-1.05.tds-base/printtype.c 1970-01-01 01:00:00.000000000 +0100 +++ djbdns-1.05.tinydnssec/printtype.c 2012-12-06 22:39:13.000000000 +0100 @@ -0,0 +1,47 @@ +/* (C) 2012 Peter Conrad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "byte.h" +#include "dns.h" +#include "uint16.h" +#include "printtype.h" + +int printtype(stralloc *out, const char type[2]) { +uint16 u16; + + if (byte_equal(type,2,DNS_T_A)) return stralloc_cats(out,"A"); + if (byte_equal(type,2,DNS_T_NS)) return stralloc_cats(out,"NS"); + if (byte_equal(type,2,DNS_T_CNAME)) return stralloc_cats(out,"CNAME"); + if (byte_equal(type,2,DNS_T_SOA)) return stralloc_cats(out,"SOA"); + if (byte_equal(type,2,DNS_T_PTR)) return stralloc_cats(out,"PTR"); + if (byte_equal(type,2,DNS_T_HINFO)) return stralloc_cats(out,"HINFO"); + if (byte_equal(type,2,DNS_T_MX)) return stralloc_cats(out,"MX"); + if (byte_equal(type,2,DNS_T_TXT)) return stralloc_cats(out,"TXT"); + if (byte_equal(type,2,DNS_T_RP)) return stralloc_cats(out,"RP"); + if (byte_equal(type,2,DNS_T_SIG)) return stralloc_cats(out,"SIG"); + if (byte_equal(type,2,DNS_T_KEY)) return stralloc_cats(out,"KEY"); + if (byte_equal(type,2,DNS_T_AAAA)) return stralloc_cats(out,"AAAA"); + if (byte_equal(type,2,DNS_T_OPT)) return stralloc_cats(out,"OPT"); + if (byte_equal(type,2,DNS_T_DS)) return stralloc_cats(out,"DS"); + if (byte_equal(type,2,DNS_T_RRSIG)) return stralloc_cats(out,"RRSIG"); + if (byte_equal(type,2,DNS_T_DNSKEY)) return stralloc_cats(out,"DNSKEY"); + if (byte_equal(type,2,DNS_T_NSEC3)) return stralloc_cats(out,"NSEC3"); + if (byte_equal(type,2,DNS_T_NSEC3PARAM)) return stralloc_cats(out,"NSEC3PARAM"); + if (byte_equal(type,2,DNS_T_AXFR)) return stralloc_cats(out,"AXFR"); + if (byte_equal(type,2,DNS_T_ANY)) return stralloc_cats(out,"*"); + + uint16_unpack_big(type,&u16); + return stralloc_catulong0(out,u16,0); +} diff -rNU3 djbdns-1.05.tds-base/printtype.h djbdns-1.05.tinydnssec/printtype.h --- djbdns-1.05.tds-base/printtype.h 1970-01-01 01:00:00.000000000 +0100 +++ djbdns-1.05.tinydnssec/printtype.h 2012-12-06 22:39:13.000000000 +0100 @@ -0,0 +1,23 @@ +/* (C) 2012 Peter Conrad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _PRINTTYPE_H +#define _PRINTTYPE_H + +#include "stralloc.h" + +extern int printtype(stralloc *, const char *); + +#endif diff -rNU3 djbdns-1.05.tds-base/response.c djbdns-1.05.tinydnssec/response.c --- djbdns-1.05.tds-base/response.c 2001-02-11 22:11:45.000000000 +0100 +++ djbdns-1.05.tinydnssec/response.c 2012-12-06 22:39:13.000000000 +0100 @@ -5,6 +5,8 @@ char response[65535]; unsigned int response_len = 0; /* <= 65535 */ +unsigned int max_response_len = 0; /* <= 65535 */ +unsigned int do_dnssec = 0; static unsigned int tctarget; #define NAMES 100 diff -rNU3 djbdns-1.05.tds-base/response.h djbdns-1.05.tinydnssec/response.h --- djbdns-1.05.tds-base/response.h 2001-02-11 22:11:45.000000000 +0100 +++ djbdns-1.05.tinydnssec/response.h 2012-12-06 22:39:13.000000000 +0100 @@ -5,6 +5,8 @@ extern char response[]; extern unsigned int response_len; +extern unsigned int max_response_len; +extern unsigned int do_dnssec; extern int response_query(const char *,const char *,const char *); extern void response_nxdomain(void); diff -rNU3 djbdns-1.05.tds-base/server.c djbdns-1.05.tinydnssec/server.c --- djbdns-1.05.tds-base/server.c 2012-12-06 22:45:38.000000000 +0100 +++ djbdns-1.05.tinydnssec/server.c 2012-12-06 22:39:13.000000000 +0100 @@ -1,3 +1,4 @@ +#include "edns0.h" #include "byte.h" #include "case.h" #include "env.h" @@ -63,6 +64,9 @@ if (header[2] & 126) goto NOTIMP; if (byte_equal(qtype,2,DNS_T_AXFR)) goto NOTIMP; + pos = check_edns0(header, buf, len, pos); + if (!pos) goto NOQ; + case_lowerb(q,dns_domain_length(q)); if (!respond(q,qtype,ip)) { qlog(ip,port,header,q,qtype," - "); @@ -168,7 +172,7 @@ len = socket_recv6(udp53[i],buf,sizeof buf,ip,&port,&ifid); if (len < 0) continue; if (!doit()) continue; - if (response_len > 512) response_tc(); + if (response_len > max_response_len) response_tc(); socket_send6(udp53[i],response,response_len,ip,port,ifid); /* may block for buffer space; if it fails, too bad */ } diff -rNU3 djbdns-1.05.tds-base/sha1.c djbdns-1.05.tinydnssec/sha1.c --- djbdns-1.05.tds-base/sha1.c 1970-01-01 01:00:00.000000000 +0100 +++ djbdns-1.05.tinydnssec/sha1.c 2012-12-06 22:39:13.000000000 +0100 @@ -0,0 +1,385 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +----------------- +Modified 7/98 +By James H. Brown +Still 100% Public Domain + +Corrected a problem which generated improper hash values on 16 bit machines +Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int +len) +to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned +long len) + +The 'len' parameter was declared an int which works fine on 32 bit machines. +However, on 16 bit machines an int is too small for the shifts being done +against +it. This caused the hash function to generate incorrect values if len was +greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + +Since the file IO in main() reads 16K at a time, any file 8K or larger would +be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million +"a"s). + +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. + +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. + +-- +I also corrected a few compiler warnings generated by Borland C. +1. Added #include for exit() prototype +2. Removed unused variable 'j' in SHA1Final +3. Changed exit(0) to return(0) at end of main. + +ALL changes I made can be located by searching for comments containing 'JHB' +----------------- +Modified 8/98 +By Steve Reid +Still 100% public domain + +1- Removed #include and used return() instead of exit() +2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) +3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + +----------------- +Modified 4/01 +By Saul Kravitz +Still 100% PD +Modified to run on Compaq Alpha hardware. + +----------------- +Modified 07/2002 +By Ralph Giles +Still 100% public domain +modified for use with stdint types, autoconf +code cleanup, removed attribution comments +switched SHA1Final() argument order for consistency +use SHA1_ prefix for public api +move public api to sha1.h + +----------------- +Modified 08/2012 +By Peter Conrad +Still 100% public domain + +Taken from http://svn.ghostscript.com/jbig2dec/trunk/ for inclusion in tinydns +Added/removed some includes +Replaced WORDS_BIGENDIAN with BYTE_ORDER == BIG_ENDIAN check +Test succeeds on x86_64 +*/ + +/* +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define SHA1HANDSOFF */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "sha1.h" + +void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +/* FIXME: can we do this in an endian-proof way? */ +#if BYTE_ORDER == BIG_ENDIAN +#define blk0(i) block->l[i] +#else +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +#ifdef VERBOSE /* SAK */ +void SHAPrintContext(SHA1_CTX *context, char *msg){ + printf("%s (%d,%d) %x %x %x %x %x\n", + msg, + context->count[0], context->count[1], + context->state[0], + context->state[1], + context->state[2], + context->state[3], + context->state[4]); +} +#endif /* VERBOSE */ + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e; + typedef union { + uint8_t c[64]; + uint32_t l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; + +#ifdef SHA1HANDSOFF + static uint8_t workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ +void SHA1_Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ +void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len) +{ + size_t i, j; + +#ifdef VERBOSE + SHAPrintContext(context, "before"); +#endif + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1_Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1_Transform(context->state, data + i); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); + +#ifdef VERBOSE + SHAPrintContext(context, "after "); +#endif +} + + +/* Add padding and return the message digest. */ +void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]) +{ + uint32_t i; + uint8_t finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1_Update(context, (uint8_t *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1_Update(context, (uint8_t *)"\0", 1); + } + SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ + for (i = 0; i < SHA1_DIGEST_SIZE; i++) { + digest[i] = (uint8_t) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + + /* Wipe variables */ + i = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(finalcount, 0, 8); /* SWR */ + +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */ + SHA1_Transform(context->state, context->buffer); +#endif +} + +/*************************************************************/ + +#if 0 +int main(int argc, char** argv) +{ +int i, j; +SHA1_CTX context; +unsigned char digest[SHA1_DIGEST_SIZE], buffer[16384]; +FILE* file; + + if (argc > 2) { + puts("Public domain SHA-1 implementation - by Steve Reid "); + puts("Modified for 16 bit environments 7/98 - by James H. Brown "); /* JHB */ + puts("Produces the SHA-1 hash of a file, or stdin if no file is specified."); + return(0); + } + if (argc < 2) { + file = stdin; + } + else { + if (!(file = fopen(argv[1], "rb"))) { + fputs("Unable to open file.", stderr); + return(-1); + } + } + SHA1_Init(&context); + while (!feof(file)) { /* note: what if ferror(file) */ + i = fread(buffer, 1, 16384, file); + SHA1_Update(&context, buffer, i); + } + SHA1_Final(&context, digest); + fclose(file); + for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) { + for (j = 0; j < 4; j++) { + printf("%02X", digest[i*4+j]); + } + putchar(' '); + } + putchar('\n'); + return(0); /* JHB */ +} +#endif + +/* self test */ + +#ifdef TEST + +static char *test_data[] = { + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "A million repetitions of 'a'"}; +static char *test_results[] = { + "A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D", + "84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1", + "34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F"}; + + +void digest_to_hex(const uint8_t digest[SHA1_DIGEST_SIZE], char *output) +{ + int i,j; + char *c = output; + + for (i = 0; i < SHA1_DIGEST_SIZE/4; i++) { + for (j = 0; j < 4; j++) { + sprintf(c,"%02X", digest[i*4+j]); + c += 2; + } + sprintf(c, " "); + c += 1; + } + *(c - 1) = '\0'; +} + +int main(int argc, char** argv) +{ + int k; + SHA1_CTX context; + uint8_t digest[20]; + char output[80]; + + fprintf(stdout, "verifying SHA-1 implementation... "); + + for (k = 0; k < 2; k++){ + SHA1_Init(&context); + SHA1_Update(&context, (uint8_t*)test_data[k], strlen(test_data[k])); + SHA1_Final(&context, digest); + digest_to_hex(digest, output); + + if (strcmp(output, test_results[k])) { + fprintf(stdout, "FAIL\n"); + fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[k]); + fprintf(stderr,"\t%s returned\n", output); + fprintf(stderr,"\t%s is correct\n", test_results[k]); + return (1); + } + } + /* million 'a' vector we feed separately */ + SHA1_Init(&context); + for (k = 0; k < 1000000; k++) + SHA1_Update(&context, (uint8_t*)"a", 1); + SHA1_Final(&context, digest); + digest_to_hex(digest, output); + if (strcmp(output, test_results[2])) { + fprintf(stdout, "FAIL\n"); + fprintf(stderr,"* hash of \"%s\" incorrect:\n", test_data[2]); + fprintf(stderr,"\t%s returned\n", output); + fprintf(stderr,"\t%s is correct\n", test_results[2]); + return (1); + } + + /* success */ + fprintf(stdout, "ok\n"); + return(0); +} +#endif /* TEST */ diff -rNU3 djbdns-1.05.tds-base/sha1.h djbdns-1.05.tinydnssec/sha1.h --- djbdns-1.05.tds-base/sha1.h 1970-01-01 01:00:00.000000000 +0100 +++ djbdns-1.05.tinydnssec/sha1.h 2012-12-06 22:39:13.000000000 +0100 @@ -0,0 +1,29 @@ +/* public api for steve reid's public domain SHA-1 implementation */ +/* this file is in the public domain */ + +#ifndef __SHA1_H +#define __SHA1_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint32_t state[5]; + uint32_t count[2]; + uint8_t buffer[64]; +} SHA1_CTX; + +#define SHA1_DIGEST_SIZE 20 + +void SHA1_Init(SHA1_CTX* context); +void SHA1_Update(SHA1_CTX* context, const uint8_t* data, const size_t len); +void SHA1_Final(SHA1_CTX* context, uint8_t digest[SHA1_DIGEST_SIZE]); + +#ifdef __cplusplus +} +#endif + +#endif /* __SHA1_H */ diff -rNU3 djbdns-1.05.tds-base/TARGETS djbdns-1.05.tinydnssec/TARGETS --- djbdns-1.05.tds-base/TARGETS 2012-12-06 22:45:38.000000000 +0100 +++ djbdns-1.05.tinydnssec/TARGETS 2012-12-06 22:39:13.000000000 +0100 @@ -240,3 +240,8 @@ socket_accept6.o socket_connect6.o socket_tcp6.o +base32hex.o +sha1.o +base32hex.o +printtype.o +edns0.o diff -rNU3 djbdns-1.05.tds-base/tdlookup.c djbdns-1.05.tinydnssec/tdlookup.c --- djbdns-1.05.tds-base/tdlookup.c 2012-12-06 22:45:38.000000000 +0100 +++ djbdns-1.05.tinydnssec/tdlookup.c 2012-12-07 11:01:39.000000000 +0100 @@ -10,6 +10,9 @@ #include "response.h" #include "ip6.h" #include "clientloc.h" +#include "alloc.h" +#include "sha1.h" +#include "base32hex.h" static int want(const char *owner,const char type[2]) { @@ -34,7 +37,7 @@ } static char *d1; - +static char *wantAddr; static char clientloc[2]; static struct tai now; static struct cdb c; @@ -44,10 +47,18 @@ static unsigned int dpos; static char type[2]; static uint32 ttl; +static char *nsec3; +static char *cname = 0; +/* returns -1 on failure, + * returns 0 on not found + * returns 1 when found + * returns 2 when flagwild is true and no wildcard match has been found but + * a direct match exists. This is for RFC-1034 section 4.3.3 compatibility. + */ static int find(char *d,int flagwild) { - int r; + int r, direct=0; char ch; struct tai cutoff; char ttd[8]; @@ -57,7 +68,9 @@ for (;;) { r = cdb_findnext(&c,d,dns_domain_length(d)); - if (r <= 0) return r; + if (r < 0) return r; /* -1 */ + if (r == 0) { return flagwild ? direct ? 2 : 0 + : 0; } dlen = cdb_datalen(&c); if (dlen > sizeof data) return -1; if (cdb_read(&c,data,dlen,cdb_datapos(&c)) == -1) return -1; @@ -68,6 +81,7 @@ dpos = dns_packet_copy(data,dlen,dpos,recordloc,2); if (!dpos) return -1; if (byte_diff(recordloc,2,clientloc)) continue; } + direct = direct || (ch != '*'); if (flagwild != (ch == '*')) continue; dpos = dns_packet_copy(data,dlen,dpos,ttlstr,4); if (!dpos) return -1; uint32_unpack_big(ttlstr,&ttl); @@ -105,6 +119,123 @@ return response_addname(d1); } +static int addNSEC3(char *hashName) +{ +int r; + + cdb_findstart(&c); + while (r = find(hashName,0)) { + if (r == -1) return 0; + if (byte_equal(type,2,DNS_T_NSEC3)) { + if (!response_rstart(hashName,DNS_T_NSEC3,ttl)) return 0; + if (!response_addbytes(data + dpos,dlen - dpos)) return 0; + response_rfinish(RESPONSE_AUTHORITY); + } + else if (do_dnssec && byte_equal(type,2,DNS_T_RRSIG) && dlen > dpos+18 + && byte_equal(data+dpos,2,DNS_T_NSEC3)) { + if (!response_rstart(hashName,DNS_T_RRSIG,ttl)) return 0; + if (!dobytes(18)) return 0; + if (!doname()) return 0; + if (!response_addbytes(data + dpos,dlen - dpos)) return 0; + response_rfinish(RESPONSE_AUTHORITY); + } + } + return 1; +} + +static int addNSEC3Cover(char *name, char *control, int wild) +{ +SHA1_CTX ctx; +int algo = 0, flags = 0, saltlen = 0, r; +uint16 iterations = 0; +char salt[255]; +uint8_t digest[SHA1_DIGEST_SIZE]; + + /* Search NSEC3PARAM to find hash parameters */ + cdb_findstart(&c); + while (r = find(control,0)) { + if (r == -1) return 0; + if (byte_equal(type,2,DNS_T_NSEC3PARAM) && dlen - dpos > 5) { + algo = data[dpos]; + flags = data[dpos+1]; + uint16_unpack_big(data + dpos + 2, &iterations); + saltlen = data[dpos+4]; + if (algo != 1 || flags || dlen - dpos - 5 < saltlen) { + algo = 0; + } else { + byte_copy(salt,saltlen, data + dpos + 5); + break; + } + } + } + if (algo != 1) return 0; /* not found or unsupported algorithm / flags */ + + /* Compute hash value */ + case_lowerb(name,dns_domain_length(name)); + SHA1_Init(&ctx); + if (wild) SHA1_Update(&ctx, "\1*", 2); + SHA1_Update(&ctx, name, dns_domain_length(name)); + SHA1_Update(&ctx, salt, saltlen); + SHA1_Final(&ctx, digest); + while (iterations-- > 0) { + SHA1_Init(&ctx); + SHA1_Update(&ctx, digest, SHA1_DIGEST_SIZE); + SHA1_Update(&ctx, salt, saltlen); + SHA1_Final(&ctx, digest); + } + + /* Find covering hash */ + char nibble = ((digest[0] >> 4) & 0xf) + '0'; + if (nibble > '9') { nibble += 'a' - '9' - 1; } + salt[0] = 1; + salt[1] = nibble; + byte_copy(salt+2, dns_domain_length(control), control); + cdb_findstart(&c); + while (r = find(salt,0)) { + if (r == -1) return 0; + if (byte_equal(type,2,DNS_T_HASHLIST) && dlen - dpos >= SHA1_DIGEST_SIZE) { + int hpos = dpos + SHA1_DIGEST_SIZE; + while (byte_diff(digest,SHA1_DIGEST_SIZE,data+hpos) > 0 && hpos < dlen) hpos += SHA1_DIGEST_SIZE; + hpos -= SHA1_DIGEST_SIZE; + *salt = base32hex(salt+1,data+hpos,SHA1_DIGEST_SIZE); + byte_copy(salt + *salt + 1, dns_domain_length(control), control); + break; + } + } + if (*salt == 1) return 0; /* not found */ + return addNSEC3(salt); +} + +static int addClosestEncloserProof(char *name, char *control, int includeWild) +{ +char *q = name; +char *hashName = 0; +int r; + + while (*q) { + cdb_findstart(&c); + while (r = find(q,0)) { + if (r == -1) return 0; + if (byte_equal(type,2,DNS_T_HASHREF) && dlen > dpos) { + if (!dns_packet_getname(data,dlen,dpos,&hashName)) return 0; + break; + } + } + if (hashName) { + int rc = addNSEC3(hashName); + alloc_free(hashName); + if (!rc) return 0; + hashName = 0; + break; + } + name = q; + q += *q + 1; + } + if (!*q) return 0; + if (includeWild && !addNSEC3Cover(q, control, 1)) return 0; + return addNSEC3Cover(name, control, 0); +} + static int doit(char *q,char qtype[2]) { unsigned int bpos; @@ -118,6 +249,8 @@ int r; int flagns; int flagauthoritative; + int flagsigned; + char *flagcname; char x[20]; uint16 u16; char addr[8][4]; @@ -132,18 +265,28 @@ for (;;) { flagns = 0; flagauthoritative = 0; + flagsigned = 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; + else if (byte_equal(type,2,DNS_T_NS)) flagns = 1; + else if (byte_equal(type,2,DNS_T_DNSKEY)) flagsigned |= 1; + else if (byte_equal(type,2,DNS_T_RRSIG)) flagsigned |= 2; + else if (byte_equal(type,2,DNS_T_NSEC3PARAM)) flagsigned |= 4; } + flagsigned = (flagsigned == 7); if (flagns) break; - if (!*control) return 0; /* q is not within our bailiwick */ + if (!*control) { + if (!cname) return 0; /* q is not within our bailiwick */ + response[2] &= ~4; /* CNAME chain ends in external reference */ + return 1; + } control += *control; control += 1; } + wild = q; if (!flagauthoritative) { response[2] &= ~4; goto AUTHORITY; /* q is in a child zone */ @@ -152,7 +295,11 @@ flaggavesoa = 0; flagfound = 0; - wild = q; + flagcname = 0; + if (nsec3) { + alloc_free(nsec3); + nsec3 = 0; + } for (;;) { addrnum = addr6num = 0; @@ -160,10 +307,29 @@ cdb_findstart(&c); while (r = find(wild,wild != q)) { if (r == -1) return 0; + if (r == 2) break; 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)) { + if (do_dnssec && byte_equal(type,2,DNS_T_HASHREF) && dlen > dpos) { + if (!dns_packet_getname(data,dlen,dpos,&nsec3)) return 0; + } + if (byte_diff(type,2,qtype) && byte_diff(qtype,2,DNS_T_ANY) && byte_diff(type,2,DNS_T_CNAME) + && (!do_dnssec || byte_diff(type,2,DNS_T_RRSIG))) continue; + if (byte_equal(type,2,DNS_T_HASHREF) || byte_equal(type,2,DNS_T_HASHLIST)) continue; + if (do_dnssec && byte_equal(type,2,DNS_T_RRSIG) && dlen - dpos > 18) { + char sigtype[2]; + struct tai valid; + uint32 validFrom, validUntil; + byte_copy(sigtype,2,data + dpos); + if (byte_diff(sigtype,2,qtype) && byte_diff(qtype,2,DNS_T_ANY) && byte_diff(sigtype,2,DNS_T_CNAME)) continue; + uint32_unpack_big(data + dpos + 12, &validFrom); + tai_unix(&valid, validFrom); + if (tai_less(&now, &valid)) continue; + uint32_unpack_big(data + dpos + 8, &validUntil); + tai_unix(&valid, validUntil); + if (tai_less(&valid, &now)) continue; + } + if (byte_equal(type,2,DNS_T_A) && (dlen - dpos == 4) && (!do_dnssec || addrnum < 8)) { addrttl = ttl; i = dns_random(addrnum + 1); if (i < 8) { @@ -174,7 +340,7 @@ if (addrnum < 1000000) ++addrnum; continue; } - if (byte_equal(type,2,DNS_T_AAAA) && (dlen - dpos == 16)) { + if (byte_equal(type,2,DNS_T_AAAA) && (dlen - dpos == 16) && (!do_dnssec || addr6num < 8)) { addr6ttl = ttl; i = dns_random(addr6num + 1); if (i < 8) { @@ -188,6 +354,9 @@ 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; + if (byte_equal(type,2,DNS_T_CNAME) && byte_diff(qtype,2,DNS_T_CNAME)) { + if (!dns_domain_copy(&flagcname,d1)) return 0; + } } else if (byte_equal(type,2,DNS_T_MX)) { if (!dobytes(2)) return 0; @@ -199,10 +368,18 @@ if (!dobytes(20)) return 0; flaggavesoa = 1; } + else if (byte_equal(type,2,DNS_T_RRSIG) && dlen - dpos > 18) { + char sigtype[2]; + byte_copy(sigtype,2,data + dpos); + if (!dobytes(18)) return 0; + if (!doname()) return 0; + if (!response_addbytes(data + dpos,dlen - dpos)) return 0; + } else if (!response_addbytes(data + dpos,dlen - dpos)) return 0; response_rfinish(RESPONSE_ANSWER); } + if (r == 2) break; for (i = 0;i < addrnum;++i) if (i < 8) { if (!response_rstart(q,DNS_T_A,addrttl)) return 0; @@ -223,6 +400,16 @@ wild += 1; } + if (flagcname) { + if (response[RESPONSE_ANSWER+1] >= 100) { + dns_domain_free(&flagcname); /* most likely a loop */ + return 0; + } + if (cname) dns_domain_free(&cname); + cname = flagcname; + return doit(cname, qtype); + } + if (!flagfound) response_nxdomain(); @@ -230,22 +417,49 @@ 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; + if (flagauthoritative && (aupos == anpos)) { /* NODATA or NXDOMAIN */ + if (!flaggavesoa) { + cdb_findstart(&c); + while (r = find(control,0)) { + if (r == -1) return 0; + if (!flaggavesoa && 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); + flaggavesoa = 1; + } + else if (do_dnssec && byte_equal(type,2,DNS_T_RRSIG) && dlen > dpos+18 + && byte_equal(data+dpos,2,DNS_T_SOA)) { + if (!response_rstart(control,DNS_T_RRSIG,ttl)) return 0; + if (!dobytes(18)) return 0; + if (!doname()) return 0; + if (!response_addbytes(data + dpos,dlen - dpos)) return 0; + response_rfinish(RESPONSE_AUTHORITY); + } + } + } + if (do_dnssec && flagsigned) { + if (flagfound && nsec3) { /* NODATA */ + if (!addNSEC3(nsec3)) return 0; + if (wild != q) { /* Wildcard NODATA */ + if (!addClosestEncloserProof(q, control, 0)) return 0; + } + } + else { /* NXDOMAIN, or query for NSEC3 owner name */ + if (!addClosestEncloserProof(q, control, 1)) return 0; } } } - else + else { + if (do_dnssec && wild != q && flagsigned) { /* Wildcard answer */ + char *nextCloser = q; + while (nextCloser + *nextCloser + 1 < wild) { nextCloser += *nextCloser + 1; } + if (!addNSEC3Cover(nextCloser, control, 0)) return 0; + } if (want(control,DNS_T_NS)) { + int have_ds = 0; cdb_findstart(&c); while (r = find(control,0)) { if (r == -1) return 0; @@ -254,10 +468,33 @@ if (!doname()) return 0; response_rfinish(RESPONSE_AUTHORITY); } + else if (do_dnssec && byte_equal(type,2,DNS_T_DS)) { + if (!response_rstart(control,DNS_T_DS,ttl)) return 0; + if (!response_addbytes(data + dpos,dlen - dpos)) return 0; + response_rfinish(RESPONSE_AUTHORITY); + have_ds = 1; + } + else if (do_dnssec && byte_equal(type,2,DNS_T_RRSIG) && dlen > dpos+18 + && (byte_equal(data+dpos,2,DNS_T_NS) + || byte_equal(data+dpos,2,DNS_T_DS))) { + if (!response_rstart(control,DNS_T_RRSIG,ttl)) return 0; + if (!dobytes(18)) return 0; + if (!doname()) return 0; + if (!response_addbytes(data + dpos,dlen - dpos)) return 0; + response_rfinish(RESPONSE_AUTHORITY); + } } + if (do_dnssec && !flagauthoritative && !have_ds) { addNSEC3(control); } } + } arpos = response_len; + if (do_dnssec) { + /* Add EDNS0 OPT RR */ + if (!response_rstart("",DNS_T_OPT,1 << 15)) return 0; + uint16_pack_big(response+arpos+3, 512); + response_rfinish(RESPONSE_ADDITIONAL); + } bpos = anpos; while (bpos < arpos) { @@ -265,25 +502,33 @@ 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; + if (!dns_packet_getname(response,arpos,bpos,&wantAddr)) 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)) { + if (!dns_packet_getname(response,arpos,bpos + 2,&wantAddr)) return 0; + case_lowerb(wantAddr,dns_domain_length(wantAddr)); + if (want(wantAddr,DNS_T_A)) { cdb_findstart(&c); - while (r = find(d1,0)) { + while (r = find(wantAddr,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 (!response_rstart(wantAddr,DNS_T_A,ttl)) return 0; if (!dobytes(4)) return 0; response_rfinish(RESPONSE_ADDITIONAL); } else if (byte_equal(type,2,DNS_T_AAAA)) { - if (!response_rstart(d1,DNS_T_AAAA,ttl)) return 0; + if (!response_rstart(wantAddr,DNS_T_AAAA,ttl)) return 0; if (!dobytes(16)) return 0; response_rfinish(RESPONSE_ADDITIONAL); } + else if (do_dnssec && byte_equal(type,2,DNS_T_RRSIG) && dlen > dpos+18 + && (byte_equal(data+dpos,2,DNS_T_A) || byte_equal(data+dpos,2,DNS_T_AAAA))) { + if (!response_rstart(wantAddr,DNS_T_RRSIG,ttl)) return 0; + if (!dobytes(18)) return 0; + if (!doname()) return 0; + if (!response_addbytes(data + dpos,dlen - dpos)) return 0; + response_rfinish(RESPONSE_ADDITIONAL); + } } } } @@ -291,10 +536,10 @@ bpos += u16; } - if (flagauthoritative && (response_len > 512)) { + if (flagauthoritative && (response_len > max_response_len)) { byte_zero(response + RESPONSE_ADDITIONAL,2); response_len = arpos; - if (response_len > 512) { + if (!do_dnssec && response_len > max_response_len) { byte_zero(response + RESPONSE_AUTHORITY,2); response_len = aupos; } @@ -316,6 +561,9 @@ cdb_init(&c,fd); r = doit(q,qtype); + if (cname) { + dns_domain_free(&cname); + } cdb_free(&c); close(fd); diff -rNU3 djbdns-1.05.tds-base/tinydns-data.c djbdns-1.05.tinydnssec/tinydns-data.c --- djbdns-1.05.tds-base/tinydns-data.c 2012-12-06 22:45:38.000000000 +0100 +++ djbdns-1.05.tinydnssec/tinydns-data.c 2012-12-06 22:39:13.000000000 +0100 @@ -436,7 +436,7 @@ i = 0; while (i < f[1].len) { k = f[1].len - i; - if (k > 127) k = 127; + if (k > 255) k = 255; ch = k; rr_add(&ch,1); rr_add(f[1].s + i,k); diff -rNU3 djbdns-1.05.tds-base/tinydns-get.c djbdns-1.05.tinydnssec/tinydns-get.c --- djbdns-1.05.tds-base/tinydns-get.c 2001-02-11 22:11:45.000000000 +0100 +++ djbdns-1.05.tinydnssec/tinydns-get.c 2012-12-06 22:39:13.000000000 +0100 @@ -19,7 +19,7 @@ void usage(void) { - strerr_die1x(100,"tinydns-get: usage: tinydns-get type name [ip]"); + strerr_die1x(100,"tinydns-get: usage: tinydns-get [-s | -S] type name [ip]"); } void oops(void) { @@ -39,6 +39,14 @@ if (!*argv) usage(); if (!*++argv) usage(); + + max_response_len = 512; + if ((*argv)[0] == '-') { + if ((*argv)[1] != 's' && (*argv)[1] != 'S' || (*argv)[2]) usage(); + do_dnssec = 1; + max_response_len = (*argv)[1] == 's' ? 1220 : 4000; + if (!*++argv) usage(); + } if (!parsetype(*argv,type)) usage(); if (!*++argv) usage();