aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile67
-rw-r--r--TARGETS5
-rw-r--r--axfrdns.c4
-rw-r--r--base32hex.c79
-rw-r--r--base32hex.h23
-rw-r--r--dns.h9
-rw-r--r--edns0.c45
-rw-r--r--edns0.h22
-rw-r--r--parsetype.c2
-rw-r--r--printpacket.c4
-rw-r--r--printrecord.c134
-rw-r--r--printtype.c47
-rw-r--r--printtype.h23
-rw-r--r--response.c2
-rw-r--r--response.h2
-rw-r--r--server.c6
-rw-r--r--sha1.c385
-rw-r--r--sha1.h29
-rw-r--r--tdlookup.c308
-rw-r--r--tinydns-data.c2
-rw-r--r--tinydns-get.c10
21 files changed, 1142 insertions, 66 deletions
diff --git a/Makefile b/Makefile
index a141bf8..fe27543 100644
--- a/Makefile
+++ b/Makefile
@@ -53,10 +53,10 @@ iopause.h taia.h tai.h uint64.h taia.h
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 @@ dns.h stralloc.h iopause.h taia.h tai.h taia.h scan.h qlog.h uint16.h \
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 @@ gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h ip6.h
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 @@ gen_alloc.h parsetype.h dns.h stralloc.h iopause.h taia.h
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 @@ gen_alloc.h parsetype.h dns.h stralloc.h iopause.h taia.h
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 @@ droproot.o: \
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 @@ iopause.h taia.h tai.h uint64.h taia.h uint16.h parsetype.h
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 @@ response.h uint32.h
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 @@ gen_alloc.h iopause.h taia.h tai.h uint64.h taia.h
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 @@ server.o: \
compile server.c byte.h case.h env.h buffer.h strerr.h ip4.h uint16.h \
ndelay.h socket.h uint16.h droproot.h qlog.h uint16.h response.h \
uint32.h dns.h stralloc.h gen_alloc.h iopause.h taia.h tai.h uint64.h \
-taia.h iopause.h alloc.h str.h
+taia.h iopause.h alloc.h str.h edns0.h
./compile server.c
setup: \
@@ -931,6 +945,10 @@ tryn2i.c choose compile load socket.lib haven2i.h1 haven2i.h2
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 @@ compile taia_uint.c taia.h tai.h uint64.h
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 @@ timeoutwrite.h
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 @@ dns.h stralloc.h iopause.h taia.h tai.h uint64.h taia.h
./compile tinydns-edit.c
tinydns-get: \
-load tinydns-get.o tdlookup.o response.o printpacket.o printrecord.o \
-parsetype.o 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 @@ compile utime.c scan.h exit.h
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 @@ trysa6.c choose compile sockaddr_in6.h1 sockaddr_in6.h2 haveip6.h
./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 --git a/TARGETS b/TARGETS
index 8e8e457..252d7d2 100644
--- a/TARGETS
+++ b/TARGETS
@@ -240,3 +240,8 @@ scan_xlong.o
socket_accept6.o
socket_connect6.o
socket_tcp6.o
+base32hex.o
+sha1.o
+base32hex.o
+printtype.o
+edns0.o
diff --git a/axfrdns.c b/axfrdns.c
index 85723c9..9fd6f9c 100644
--- a/axfrdns.c
+++ b/axfrdns.c
@@ -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 @@ int main()
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 --git a/base32hex.c b/base32hex.c
new file mode 100644
index 0000000..95826fd
--- /dev/null
+++ b/base32hex.c
@@ -0,0 +1,79 @@
+/* (C) 2012 Peter Conrad <conrad@quisquis.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 --git a/base32hex.h b/base32hex.h
new file mode 100644
index 0000000..8208cdc
--- /dev/null
+++ b/base32hex.h
@@ -0,0 +1,23 @@
+/* (C) 2012 Peter Conrad <conrad@quisquis.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _BASE32_HEX_H
+#define _BASE32_HEX_H
+
+#include <stdint.h>
+
+extern unsigned int base32hex(char *out, uint8_t *in, unsigned int len);
+
+#endif
diff --git a/dns.h b/dns.h
index 5398e2b..c9689a2 100644
--- a/dns.h
+++ b/dns.h
@@ -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 --git a/edns0.c b/edns0.c
new file mode 100644
index 0000000..0487b2b
--- /dev/null
+++ b/edns0.c
@@ -0,0 +1,45 @@
+/* (C) 2012 Peter Conrad <conrad@quisquis.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 --git a/edns0.h b/edns0.h
new file mode 100644
index 0000000..ce41f9f
--- /dev/null
+++ b/edns0.h
@@ -0,0 +1,22 @@
+/* (C) 2012 Peter Conrad <conrad@quisquis.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _EDNS0_H
+
+#define _EDNS0_H
+
+extern unsigned int check_edns0(const char *, const char *, const int, unsigned int);
+
+#endif
diff --git a/parsetype.c b/parsetype.c
index 167aaa4..b3bc332 100644
--- a/parsetype.c
+++ b/parsetype.c
@@ -24,6 +24,8 @@ int parsetype(char *s,char type[2])
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 --git a/printpacket.c b/printpacket.c
index 7571e08..39b303e 100644
--- a/printpacket.c
+++ b/printpacket.c
@@ -5,6 +5,7 @@
#include "dns.h"
#include "printrecord.h"
#include "printpacket.h"
+#include "printtype.h"
static char *d;
@@ -67,8 +68,7 @@ unsigned int printpacket_cat(stralloc *out,char *buf,unsigned int len)
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 --git a/printrecord.c b/printrecord.c
index 4bc7c3e..4cc744d 100644
--- a/printrecord.c
+++ b/printrecord.c
@@ -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 printrecord_cat(stralloc *out,const char *buf,unsigned int len,unsi
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 @@ unsigned int printrecord_cat(stralloc *out,const char *buf,unsigned int len,unsi
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 @@ unsigned int printrecord_cat(stralloc *out,const char *buf,unsigned int len,unsi
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 @@ unsigned int printrecord_cat(stralloc *out,const char *buf,unsigned int len,unsi
if (!stralloc_catb(out,misc,4)) return 0;
}
}
- }
if (!stralloc_cats(out,"\n")) return 0;
if (pos != newpos) { errno = error_proto; return 0; }
diff --git a/printtype.c b/printtype.c
new file mode 100644
index 0000000..ebaa99b
--- /dev/null
+++ b/printtype.c
@@ -0,0 +1,47 @@
+/* (C) 2012 Peter Conrad <conrad@quisquis.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 --git a/printtype.h b/printtype.h
new file mode 100644
index 0000000..d0ce87c
--- /dev/null
+++ b/printtype.h
@@ -0,0 +1,23 @@
+/* (C) 2012 Peter Conrad <conrad@quisquis.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _PRINTTYPE_H
+#define _PRINTTYPE_H
+
+#include "stralloc.h"
+
+extern int printtype(stralloc *, const char *);
+
+#endif
diff --git a/response.c b/response.c
index 33b2fb1..d45843c 100644
--- a/response.c
+++ b/response.c
@@ -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 --git a/response.h b/response.h
index 206b1d4..14a4a1e 100644
--- a/response.h
+++ b/response.h
@@ -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 --git a/server.c b/server.c
index d52ce87..b754265 100644
--- a/server.c
+++ b/server.c
@@ -1,3 +1,4 @@
+#include "edns0.h"
#include "byte.h"
#include "case.h"
#include "env.h"
@@ -63,6 +64,9 @@ static int doit(void)
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 @@ int main()
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 --git a/sha1.c b/sha1.c
new file mode 100644
index 0000000..8a3dfee
--- /dev/null
+++ b/sha1.c
@@ -0,0 +1,385 @@
+/*
+SHA-1 in C
+By Steve Reid <sreid@sea-to-sky.net>
+100% Public Domain
+
+-----------------
+Modified 7/98
+By James H. Brown <jbrown@burgoyne.com>
+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 <process.h> 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 <sreid@sea-to-sky.net>
+Still 100% public domain
+
+1- Removed #include <process.h> 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 <Saul.Kravitz@celera.com>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.
+
+-----------------
+Modified 07/2002
+By Ralph Giles <giles@ghostscript.com>
+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 <conrad@quisquis.de>
+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 <endian.h>
+#include <stdio.h>
+#include <string.h>
+
+#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 <sreid@sea-to-sky.net>");
+ puts("Modified for 16 bit environments 7/98 - by James H. Brown <jbrown@burgoyne.com>"); /* 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 --git a/sha1.h b/sha1.h
new file mode 100644
index 0000000..aff51bc
--- /dev/null
+++ b/sha1.h
@@ -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 <stdint.h>
+
+#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 --git a/tdlookup.c b/tdlookup.c
index b760340..ade5e49 100644
--- a/tdlookup.c
+++ b/tdlookup.c
@@ -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 int want(const char *owner,const char type[2])
}
static char *d1;
-
+static char *wantAddr;
static char clientloc[2];
static struct tai now;
static struct cdb c;
@@ -44,10 +47,18 @@ static uint32 dlen;
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 @@ static int find(char *d,int flagwild)
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 @@ static int find(char *d,int flagwild)
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 @@ static int doname(void)
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 @@ static int doit(char *q,char qtype[2])
int r;
int flagns;
int flagauthoritative;
+ int flagsigned;
+ char *flagcname;
char x[20];
uint16 u16;
char addr[8][4];
@@ -132,18 +265,28 @@ static int doit(char *q,char qtype[2])
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 @@ static int doit(char *q,char qtype[2])
flaggavesoa = 0;
flagfound = 0;
- wild = q;
+ flagcname = 0;
+ if (nsec3) {
+ alloc_free(nsec3);
+ nsec3 = 0;
+ }
for (;;) {
addrnum = addr6num = 0;
@@ -160,10 +307,29 @@ static int doit(char *q,char qtype[2])
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 @@ static int doit(char *q,char qtype[2])
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 @@ static int doit(char *q,char qtype[2])
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 @@ static int doit(char *q,char qtype[2])
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 @@ static int doit(char *q,char qtype[2])
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 @@ static int doit(char *q,char qtype[2])
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 @@ static int doit(char *q,char qtype[2])
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 @@ static int doit(char *q,char qtype[2])
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 @@ static int doit(char *q,char qtype[2])
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 @@ int respond(char *q,char qtype[2],char ip[16])
cdb_init(&c,fd);
r = doit(q,qtype);
+ if (cname) {
+ dns_domain_free(&cname);
+ }
cdb_free(&c);
close(fd);
diff --git a/tinydns-data.c b/tinydns-data.c
index 4d66865..f35fb3b 100644
--- a/tinydns-data.c
+++ b/tinydns-data.c
@@ -436,7 +436,7 @@ int main()
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 --git a/tinydns-get.c b/tinydns-get.c
index 56edb13..d17305d 100644
--- a/tinydns-get.c
+++ b/tinydns-get.c
@@ -20,7 +20,7 @@ extern int respond(char *,char *,char *);
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)
{
@@ -40,6 +40,14 @@ int main(int argc,char **argv)
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();