diff options
author | Henryk Plötz <henryk@ploetzli.ch> | 2014-10-03 20:19:52 +0200 |
---|---|---|
committer | Henryk Plötz <henryk@ploetzli.ch> | 2014-10-03 20:29:37 +0200 |
commit | eaaa5b4f9301ae2e5a29dd77616d8e29fd3b2c28 (patch) | |
tree | c090b31513b85dfca08b878066faf9d2893c7a7a | |
parent | 898102385f20b06f08dc5fb379e1c9aa261a5700 (diff) | |
download | tinydnssec-eaaa5b4f9301ae2e5a29dd77616d8e29fd3b2c28.tar.gz tinydnssec-eaaa5b4f9301ae2e5a29dd77616d8e29fd3b2c28.tar.bz2 |
Add tinydnssec-1.05-1.3.tar.bz2
Source was http://www.tinydnssec.org/download/tinydnssec-1.05-1.3.tar.bz2, SHA1 b33d5c3e0de67f6427aad8c00a99580b59804075
-rw-r--r-- | INSTALL.tinydnssec | 45 | ||||
-rw-r--r-- | README.tinydnssec | 132 | ||||
-rw-r--r-- | TODO.tinydnssec | 13 | ||||
-rw-r--r-- | djbdns-1.05-dnssec.patch | 1749 | ||||
-rw-r--r-- | gpl-3.0.txt | 674 | ||||
-rwxr-xr-x | run-tests.sh | 104 | ||||
-rw-r--r-- | test/a-01 | 16 | ||||
-rw-r--r-- | test/a-02 | 9 | ||||
-rw-r--r-- | test/a-03 | 11 | ||||
-rw-r--r-- | test/a-04 | 7 | ||||
-rw-r--r-- | test/a-05 | 7 | ||||
-rw-r--r-- | test/a-06 | 9 | ||||
-rw-r--r-- | test/a-07 | 18 | ||||
-rw-r--r-- | test/a-08 | 11 | ||||
-rw-r--r-- | test/a-09 | 7 | ||||
-rw-r--r-- | test/a-10 | 9 | ||||
-rw-r--r-- | test/a-11 | 6 | ||||
-rw-r--r-- | test/a-12 | 3 | ||||
-rw-r--r-- | test/a-13 | 3 | ||||
-rw-r--r-- | test/a-14 | 3 | ||||
-rw-r--r-- | test/a-15 | 9 | ||||
-rw-r--r-- | test/a-16 | 3 | ||||
-rw-r--r-- | test/a-17 | 3 | ||||
-rw-r--r-- | test/a-18 | 3 | ||||
-rw-r--r-- | test/a-19 | 4 | ||||
-rw-r--r-- | test/a-20 | 4 | ||||
-rw-r--r-- | test/a-21 | 7 | ||||
-rw-r--r-- | test/a-22 | 7 | ||||
-rw-r--r-- | test/a-23 | 4 | ||||
-rw-r--r-- | test/a-24 | 6 | ||||
-rw-r--r-- | test/a-25 | 9 | ||||
-rw-r--r-- | test/a-26 | 9 | ||||
-rw-r--r-- | test/a-27 | 12 | ||||
-rw-r--r-- | test/a-28 | 7 | ||||
-rw-r--r-- | test/a-29 | 12 | ||||
-rw-r--r-- | test/a-30 | 3 | ||||
-rw-r--r-- | test/a-31 | 4 | ||||
-rw-r--r-- | test/a-32 | 3 | ||||
-rw-r--r-- | test/a-33 | 4 | ||||
-rw-r--r-- | test/a-34 | 9 | ||||
-rw-r--r-- | test/a-35 | 10 | ||||
-rw-r--r-- | test/a-36 | 3 | ||||
-rw-r--r-- | test/a-37 | 3 | ||||
-rw-r--r-- | test/a-38 | 4 | ||||
-rw-r--r-- | test/a-39 | 5 | ||||
-rw-r--r-- | test/data | 65 | ||||
-rw-r--r-- | test/example.ksk | 53 | ||||
-rw-r--r-- | test/example.zsk | 17 | ||||
-rw-r--r-- | test/q-01 | 2 | ||||
-rw-r--r-- | test/q-02 | 2 | ||||
-rw-r--r-- | test/q-03 | 2 | ||||
-rw-r--r-- | test/q-04 | 2 | ||||
-rw-r--r-- | test/q-05 | 2 | ||||
-rw-r--r-- | test/q-06 | 2 | ||||
-rw-r--r-- | test/q-07 | 2 | ||||
-rw-r--r-- | test/q-08 | 2 | ||||
-rw-r--r-- | test/q-09 | 2 | ||||
-rw-r--r-- | test/q-10 | 1 | ||||
-rw-r--r-- | test/q-11 | 1 | ||||
-rw-r--r-- | test/q-12 | 1 | ||||
-rw-r--r-- | test/q-13 | 1 | ||||
-rw-r--r-- | test/q-14 | 1 | ||||
-rw-r--r-- | test/q-15 | 1 | ||||
-rw-r--r-- | test/q-16 | 1 | ||||
-rw-r--r-- | test/q-17 | 1 | ||||
-rw-r--r-- | test/q-18 | 1 | ||||
-rw-r--r-- | test/q-19 | 1 | ||||
-rw-r--r-- | test/q-20 | 1 | ||||
-rw-r--r-- | test/q-21 | 1 | ||||
-rw-r--r-- | test/q-22 | 1 | ||||
-rw-r--r-- | test/q-23 | 1 | ||||
-rw-r--r-- | test/q-24 | 1 | ||||
-rw-r--r-- | test/q-25 | 1 | ||||
-rw-r--r-- | test/q-26 | 1 | ||||
-rw-r--r-- | test/q-27 | 1 | ||||
-rw-r--r-- | test/q-28 | 1 | ||||
-rw-r--r-- | test/q-29 | 1 | ||||
-rw-r--r-- | test/q-30 | 1 | ||||
-rw-r--r-- | test/q-31 | 1 | ||||
-rw-r--r-- | test/q-32 | 1 | ||||
-rw-r--r-- | test/q-33 | 1 | ||||
-rw-r--r-- | test/q-34 | 1 | ||||
-rw-r--r-- | test/q-35 | 1 | ||||
-rw-r--r-- | test/q-36 | 1 | ||||
-rw-r--r-- | test/q-37 | 1 | ||||
-rw-r--r-- | test/q-38 | 1 | ||||
-rw-r--r-- | test/q-39 | 1 | ||||
-rwxr-xr-x | tinydns-sign.pl | 1025 |
88 files changed, 4191 insertions, 0 deletions
diff --git a/INSTALL.tinydnssec b/INSTALL.tinydnssec new file mode 100644 index 0000000..677d774 --- /dev/null +++ b/INSTALL.tinydnssec @@ -0,0 +1,45 @@ +Installation of the tinydnssec patch +==================================== + +Requirements +------------ + +This patch is *not* against stock djbdns. Here's the minimal set of patches +to install before the tinydnssec patch applies: + +1. http://www.fefe.de/dns/djbdns-1.05-test25.diff.bz2 + Unfortunately, fefe refuses to name a license for this patch, which means + that I cannot redistribute it. + +2. My own fixes to the Makefile (IPv6-related): djbdns-ipv6-make.patch + +Build +----- + +1. Download and unpack the original djbdns sources from + http://cr.yp.to/djbdns/install.html . +2. Download and apply the patches listed above. +3. Download and unpack http://tinydnssec.org/tinydnssec-1.05-1.tar.gz in + the top-level source directory. +4. Apply djbdns-1.05-dnssec.patch. +5. Install as per usual instructions (see http://cr.yp.to/djbdns/install.html ). +6. Optional: run tests (see below). +7. Install djbdns as per original instructions, or whatever your preferred + method is. +8. Install tinydns-sign.pl in your preferred location for system + executables, like e. g. /usr/sbin . +9. Optional: create a manpage for tinydns-sign using e. g. + pod2man -s 8 -c '' "tinydns-sign.pl" >tinydns-sign.8 + then install it in your preferred location for system manpages. + + +Test +---- + +run-tests.sh will sign test/data using keys from test/example*, then issue +some queries using tinydns-get, i. e. without any networking involved. + +As root, start tinydns / axfrdns on a local address (127.0.0.3), then execute +SERVER=127.0.0.3 run-tests.sh -t -u +to test the same queries via tcp and udp. + diff --git a/README.tinydnssec b/README.tinydnssec new file mode 100644 index 0000000..bf15c76 --- /dev/null +++ b/README.tinydnssec @@ -0,0 +1,132 @@ +DNSSEC for tinydns +================== + +This project adds DNSSEC support to D. J. Bernstein's tinydns (see +http://cr.yp.to/djbdns.html ). + +It consists of two parts (mostly): + +- tinydns-sign, a perl script for augmenting a tinydns-data file with + DNSSEC-related RRs, and + +- a patch to tinydns / axfrdns to make them produce DNSSEC-authenticated + answers. + +The patch tries to preserve the behaviour of tinydns/axfrdns wrt non-DNSSEC +queries, with these noteworthy exceptions: + +- The interpretation of wildcard records now matches the description in + RFC-1034 section 4.3.3. Specifically, if there's a wildcard *.x and a + record for a.x, then a query for y.a.x will *not* be answered using the + wildcard (for a label 'a' and series of labels 'x' and 'y'). + This change is required for signed domains, because authentication of + negative responses requires a common understanding between client and + server about the meaning of wildcards. + +- EDNS0 in queries will be honoured also for non-DNSSEC queries, i. e. + tinydns may produce answers exceeding 512 bytes. (There is a hard + limit of 4000 bytes, though.) + This *can* lead to problems on IPv6 networks. + +- TXT records are split into character-strings of 255 bytes, not 127. + This is not really a DNSSEC-related change, but this is kind of a FAQ [5] and + tinydns-data and tinydns-sign must agree on how this is handled or the + generated RRSIG won't match. + +- The patch includes a fix for the broken CNAME handling in tinydns. See [6] + for a description of the problem. The patch referenced by that description + conflicts with fefe's IPv6 patch and requires further modifications for + DNSSEC, so I decided to roll my own solution. + +Be careful with publishing signed zones as a secondary nameserver: the +modified tinydns/axfrdns require certain helper RRs in the database to +simplify locating NSEC3 records. Without these helpers, tinydns cannot +generate valid negative response nor valid wildcard responses. + +Axfrdns *will* publish these helper RRs, other primaries will most +likely *not*. + + +HOWTO +----- + +0. Install tinydns-sign and patched tinydns/axfrdns. + +1. Generate key(s). See the tinydns-sign manpage for details. + + It is common practice to have a "Key signing key" (KSK, with flags=257) + and a "Zone signing key" (ZSK, with flags=256). The KSK is used only for + signing the DNSKEY RRs, the ZSK is used for signing the rest. The KSK is + more difficult to change because it is used in the delegating domain's + referral, therefore it usually has more bits. The ZSK is used for signing + all the other records, and is therefore usually shorter and changed more + frequently. + + You should keep the keys in a safe place (outside the tinydns ROOT), e. g. + in a directory "keys" located above the ROOT. + +2. Add the K pseudo records from the key files to your tinydns-data file. + Also, add a P pseudo record for each signed zone. + +3. Adapt the Makefile to pipe your data file through tinydns-sign before + before running tinydns-data, e. g. + +data.cdb: data update + tinydns-sign ../keys/* <data >data.tmp + mv data.tmp data + tinydns-data + rm -f update + +update: + touch update + +4. Run make. + +5. Set up a cronjob to periodically re-sign your data file before the + signatures expire. + +6. TEST! For example: + + * Use dig axfr <domain> @<server> and validate the result with a dnssec zone + validator, like yazvs [1]. + + * Use an online DNS or DNSSEC test tool. See [2] for a list. + +7. Read RFC-4641 [3] to get a feeling for what is explicitly not called + "Best Current Practices". :-) + + In particular, think about key lifetime and how to do a key rollover. + +8. Sacrifice a few small animals to a deity of your choice. Get yourself a + drink for really tough guys, like prune juice [4]. + +9. If you feel brave, contact your upstream delegator to publish DS records + for your zone. + + Note that this is a really good way to cut yourself off from the rest of the + internet. You've been warned, so don't blame me. + +LICENSE +------- + +(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/>. + + +[1] http://yazvs.verisignlabs.com/ . +[2] http://www.bortzmeyer.org/tests-dns.html +[3] http://tools.ietf.org/html/rfc4641 +[4] http://en.memory-alpha.org/wiki/Prune_juice +[5] http://marc.info/?l=djbdns&m=120848817816960&w=2 +[6] http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/djbdns-problems.html#tinydns-alias-chain-truncation diff --git a/TODO.tinydnssec b/TODO.tinydnssec new file mode 100644 index 0000000..70fe34e --- /dev/null +++ b/TODO.tinydnssec @@ -0,0 +1,13 @@ + +* Make hardcoded limit for EDNS0 response size configurable (environment). + +* Add support for locations + timestamps to tinydns-sign (basically, treat + them as separate zones, with timestamp-dependend SOA serials). + +* Add support for ((semi-)automatic) ZSK rollover using pre-publish method. + +* Refactor tinydns-sign: + - separate generation of helper records + - put some functionality into modules + - make (better) use of existing Net::DNS modules + diff --git a/djbdns-1.05-dnssec.patch b/djbdns-1.05-dnssec.patch new file mode 100644 index 0000000..d2b2323 --- /dev/null +++ b/djbdns-1.05-dnssec.patch @@ -0,0 +1,1749 @@ +(C) 2012 Peter Conrad <conrad@quisquis.de> + +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 <http://www.gnu.org/licenses/>. + +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 <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 -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 <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 -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 <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 -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 <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 -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 <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 -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 <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 -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 <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 -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 <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 -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(); diff --git a/gpl-3.0.txt b/gpl-3.0.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/gpl-3.0.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + 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/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/run-tests.sh b/run-tests.sh new file mode 100755 index 0000000..14d2c88 --- /dev/null +++ b/run-tests.sh @@ -0,0 +1,104 @@ +#!/bin/sh + +# (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/>. + +./tinydns-sign.pl test/example.?sk <test/data >data +./tinydns-data + +for i in test/q-*; do + id="${i#test/q}" + echo -n "$i ... " + read sec type name <"$i" + ./tinydns-get "$sec" "$type" $name | tail +2 >test/"o$id" + sed -s 's/\b[0-9]\{10\}\b/<TIME>/g;/00 RRSIG /s/[^ ]*$/<SIG>/;s/^[0-9]\{1,\}/<SIZE>/' <test/"o$id" >test/"t$id" + if diff "test/t$id" "test/a$id" >/dev/null; then + echo "OK" + else + echo "FAIL: tinydns-get" + fi +done + +function dig2tiny { + awk 'BEGIN { sect = 0; } + /^;; QUESTION SECTION/ { sect = 1; } + /^;; ANSWER SECTION/ { sect = 2; } + /^;; AUTHORITY SECTION/ { sect = 3; } + /^;; ADDITIONAL SECTION/ { sect = 4; } + /^;; OPT PSEUDOSECTION/ { sect = 5; } + /^;; ->>HEADER<<./ { sect = 6; } + { if ($0 !~ /^;;/ && $0 !~ /^$/) { + if (sect == 1) { print "query: " $3 " " substr($1, 2) } + else if (sect == 2) { print "answer: " $0 } + else if (sect == 3) { print "authority: " $0 } + else if (sect == 4) { print "additional: " $0 } + else if (sect == 5) { print "additional: . 0 OPT " $8 " " (0 + $4) " 0 " ($6 == "do;" ? "8000" : "0") } + } else if (sect == 6) { + if ($0 ~ /^;; ...HEADER/ && $5 == "status:") { status = substr($6, 0, length($6) -1); } + else if ($0 ~ /^;; flags: /) { + if ($0 ~ /^;; flags: [ a-z]*aa/) { auth = "authoritative, " } + else { auth = "" } + match($0, /QUERY: ([[:digit:]]+), ANSWER: ([[:digit:]]+), AUTHORITY: ([[:digit:]]+), ADDITIONAL: ([[:digit:]]+)/, rrs); + print "<SIZE> bytes, " rrs[1] "+" rrs[2] "+" rrs[3] "+" rrs[4] " records, response, " auth status; + } + } + }' <"$1" | \ + sed 's=[ ]\{1,\}= =g;s=\(example\|xx\)\. =\1 =g;s=\(example\|xx\)\.$=\1=;s= IN = =g;s=\([0-9a-zA-Z+/]\{40,\}\) =\1=g' >"$2" +} + +if [ "$1" = "-t" ]; then + shift + for i in test/q-*; do + id="${i#test/q}" + echo -n "$i (tcp) ... " + read sec type name <"$i" + if [ "$sec" = "-s" ]; then + sec="+dnssec +bufsize=1220" + elif [ "$sec" = "-S" ]; then + sec="+dnssec +bufsize=2000" + fi + dig +norecurse +tcp $sec "$type" $name @$SERVER >"test/ot$id" + dig2tiny "test/ot$id" "test/ttt$id" + sed -s 's/\b[0-9]\{10\}\b/<TIME>/g;s/\b[0-9]\{14\}\b/<TIME>/g;/00 RRSIG /s/[^ ]*$/<SIG>/' <test/"ttt$id" | \ + sort >test/"tt$id" + if sort <"test/a$id" | diff -i - "test/tt$id" >/dev/null; then + echo "OK" + else + echo "FAIL: dig +tcp" + fi + done +fi + +if [ "$1" = "-u" ]; then + shift + for i in test/q-*; do + id="${i#test/q}" + echo -n "$i (udp) ... " + read sec type name <"$i" + if [ "$sec" = "-s" ]; then + sec="+dnssec +bufsize=1220" + elif [ "$sec" = "-S" ]; then + sec="+dnssec +bufsize=2000" + fi + dig +norecurse +notcp $sec "$type" $name @$SERVER >"test/ou$id" + dig2tiny "test/ou$id" "test/tut$id" + sed -s 's/\b[0-9]\{10\}\b/<TIME>/g;s/\b[0-9]\{14\}\b/<TIME>/g;/00 RRSIG /s/[^ ]*$/<SIG>/' <test/"tut$id" | \ + sort >test/"tu$id" + if sort <"test/a$id" | diff -i - "test/tu$id" >/dev/null; then + echo "OK" + else + echo "FAIL: dig +notcp" + fi + done +fi diff --git a/test/a-01 b/test/a-01 new file mode 100644 index 0000000..edbae15 --- /dev/null +++ b/test/a-01 @@ -0,0 +1,16 @@ +<SIZE> bytes, 1+2+3+9 records, response, authoritative, noerror +query: MX x.w.example +answer: x.w.example 3600 MX 1 xx.example +answer: x.w.example 3600 RRSIG MX 7 3 3600 <TIME> <TIME> 44495 example <SIG> +authority: example 3600 NS ns1.example +authority: example 3600 NS ns2.example +authority: example 3600 RRSIG NS 7 1 3600 <TIME> <TIME> 44495 example <SIG> +additional: . 0 OPT 512 0 0 8000 +additional: xx.example 3600 A 192.0.2.10 +additional: xx.example 3600 AAAA 2001:db8::f00:baaa +additional: xx.example 3600 RRSIG A 7 2 3600 <TIME> <TIME> 44495 example <SIG> +additional: xx.example 3600 RRSIG AAAA 7 2 3600 <TIME> <TIME> 44495 example <SIG> +additional: ns1.example 3600 A 192.0.2.1 +additional: ns1.example 3600 RRSIG A 7 2 3600 <TIME> <TIME> 44495 example <SIG> +additional: ns2.example 3600 A 192.0.2.2 +additional: ns2.example 3600 RRSIG A 7 2 3600 <TIME> <TIME> 44495 example <SIG> diff --git a/test/a-02 b/test/a-02 new file mode 100644 index 0000000..ec13d5d --- /dev/null +++ b/test/a-02 @@ -0,0 +1,9 @@ +<SIZE> bytes, 1+0+4+3 records, response, noerror +query: MX mc.a.example +authority: a.example 3600 NS ns1.a.example +authority: a.example 3600 NS ns2.a.example +authority: a.example 3600 DS 58470 5 1 3079F1593EBAD6DC121E202A8B766A6A4837206C +authority: a.example 3600 RRSIG DS 7 2 3600 <TIME> <TIME> 44495 example <SIG> +additional: . 0 OPT 512 0 0 8000 +additional: ns1.a.example 3600 A 192.0.2.5 +additional: ns2.a.example 3600 A 192.0.2.6 diff --git a/test/a-03 b/test/a-03 new file mode 100644 index 0000000..6b543dc --- /dev/null +++ b/test/a-03 @@ -0,0 +1,11 @@ +<SIZE> bytes, 1+0+8+1 records, response, authoritative, nxdomain +query: A a.c.x.w.example +authority: example 3600 SOA ns1.example bugs.x.w.example <TIME> 3600 300 3600000 3600 +authority: example 3600 RRSIG SOA 7 1 3600 <TIME> <TIME> 44495 example <SIG> +authority: b4um86eghhds6nea196smvmlo4ors995.example 3600 NSEC3 1 0 12 AABBCCDD gjeqe526plbf1g8mklp59enfd789njgi MX RRSIG +authority: b4um86eghhds6nea196smvmlo4ors995.example 3600 RRSIG NSEC3 7 2 3600 <TIME> <TIME> 44495 example <SIG> +authority: 4g6p9u5gvfshp30pqecj98b3maqbn1ck.example 3600 NSEC3 1 0 12 AABBCCDD b4um86eghhds6nea196smvmlo4ors995 NS +authority: 4g6p9u5gvfshp30pqecj98b3maqbn1ck.example 3600 RRSIG NSEC3 7 2 3600 <TIME> <TIME> 44495 example <SIG> +authority: 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example 3600 NSEC3 1 0 12 AABBCCDD 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM +authority: 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example 3600 RRSIG NSEC3 7 2 3600 <TIME> <TIME> 44495 example <SIG> +additional: . 0 OPT 512 0 0 8000 diff --git a/test/a-04 b/test/a-04 new file mode 100644 index 0000000..b23c1ed --- /dev/null +++ b/test/a-04 @@ -0,0 +1,7 @@ +<SIZE> bytes, 1+0+4+1 records, response, authoritative, noerror +query: MX ns1.example +authority: example 3600 SOA ns1.example bugs.x.w.example <TIME> 3600 300 3600000 3600 +authority: example 3600 RRSIG SOA 7 1 3600 <TIME> <TIME> 44495 example <SIG> +authority: 2t7b4g4vsa5smi47k61mv5bv1a22bojr.example 3600 NSEC3 1 0 12 AABBCCDD 2vptu5timamqttgl4luu9kg21e0aor3s A RRSIG +authority: 2t7b4g4vsa5smi47k61mv5bv1a22bojr.example 3600 RRSIG NSEC3 7 2 3600 <TIME> <TIME> 44495 example <SIG> +additional: . 0 OPT 512 0 0 8000 diff --git a/test/a-05 b/test/a-05 new file mode 100644 index 0000000..39dce85 --- /dev/null +++ b/test/a-05 @@ -0,0 +1,7 @@ +<SIZE> bytes, 1+0+4+1 records, response, authoritative, noerror +query: A y.w.example +authority: example 3600 SOA ns1.example bugs.x.w.example <TIME> 3600 300 3600000 3600 +authority: example 3600 RRSIG SOA 7 1 3600 <TIME> <TIME> 44495 example <SIG> +authority: ji6neoaepv8b5o6k4ev33abha8ht9fgc.example 3600 NSEC3 1 0 12 AABBCCDD k8udemvp1j2f7eg6jebps17vp3n8i58h +authority: ji6neoaepv8b5o6k4ev33abha8ht9fgc.example 3600 RRSIG NSEC3 7 2 3600 <TIME> <TIME> 44495 example <SIG> +additional: . 0 OPT 512 0 0 8000 diff --git a/test/a-06 b/test/a-06 new file mode 100644 index 0000000..ea65ded --- /dev/null +++ b/test/a-06 @@ -0,0 +1,9 @@ +<SIZE> bytes, 1+2+5+0 records, response, authoritative, noerror +query: MX a.z.w.example +answer: a.z.w.example 3600 MX 1 ai.example +answer: a.z.w.example 3600 RRSIG MX 7 2 3600 <TIME> <TIME> 44495 example <SIG> +authority: q04jkcevqvmu85r014c7dkba38o0ji5r.example 3600 NSEC3 1 0 12 AABBCCDD r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG +authority: q04jkcevqvmu85r014c7dkba38o0ji5r.example 3600 RRSIG NSEC3 7 2 3600 <TIME> <TIME> 44495 example <SIG> +authority: example 3600 NS ns1.example +authority: example 3600 NS ns2.example +authority: example 3600 RRSIG NS 7 1 3600 <TIME> <TIME> 44495 example <SIG> diff --git a/test/a-07 b/test/a-07 new file mode 100644 index 0000000..3d2e512 --- /dev/null +++ b/test/a-07 @@ -0,0 +1,18 @@ +<SIZE> bytes, 1+2+5+9 records, response, authoritative, noerror +query: MX a.z.w.example +answer: a.z.w.example 3600 MX 1 ai.example +answer: a.z.w.example 3600 RRSIG MX 7 2 3600 <TIME> <TIME> 44495 example <SIG> +authority: q04jkcevqvmu85r014c7dkba38o0ji5r.example 3600 NSEC3 1 0 12 AABBCCDD r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG +authority: q04jkcevqvmu85r014c7dkba38o0ji5r.example 3600 RRSIG NSEC3 7 2 3600 <TIME> <TIME> 44495 example <SIG> +authority: example 3600 NS ns1.example +authority: example 3600 NS ns2.example +authority: example 3600 RRSIG NS 7 1 3600 <TIME> <TIME> 44495 example <SIG> +additional: . 0 OPT 512 0 0 8000 +additional: ai.example 3600 A 192.0.2.9 +additional: ai.example 3600 AAAA 2001:db8::f00:baa9 +additional: ai.example 3600 RRSIG A 7 2 3600 <TIME> <TIME> 44495 example <SIG> +additional: ai.example 3600 RRSIG AAAA 7 2 3600 <TIME> <TIME> 44495 example <SIG> +additional: ns1.example 3600 A 192.0.2.1 +additional: ns1.example 3600 RRSIG A 7 2 3600 <TIME> <TIME> 44495 example <SIG> +additional: ns2.example 3600 A 192.0.2.2 +additional: ns2.example 3600 RRSIG A 7 2 3600 <TIME> <TIME> 44495 example <SIG> diff --git a/test/a-08 b/test/a-08 new file mode 100644 index 0000000..2b64468 --- /dev/null +++ b/test/a-08 @@ -0,0 +1,11 @@ +<SIZE> bytes, 1+0+8+1 records, response, authoritative, noerror +query: AAAA a.z.w.example +authority: example 3600 SOA ns1.example bugs.x.w.example <TIME> 3600 300 3600000 3600 +authority: example 3600 RRSIG SOA 7 1 3600 <TIME> <TIME> 44495 example <SIG> +authority: r53bq7cc2uvmubfu5ocmm6pers9tk9en.example 3600 NSEC3 1 0 12 AABBCCDD t644ebqk9bibcna874givr6joj62mlhv MX RRSIG +authority: r53bq7cc2uvmubfu5ocmm6pers9tk9en.example 3600 RRSIG NSEC3 7 2 3600 <TIME> <TIME> 44495 example <SIG> +authority: k8udemvp1j2f7eg6jebps17vp3n8i58h.example 3600 NSEC3 1 0 12 AABBCCDD kohar7mbb8dc2ce8a9qvl8hon4k53uhi +authority: k8udemvp1j2f7eg6jebps17vp3n8i58h.example 3600 RRSIG NSEC3 7 2 3600 <TIME> <TIME> 44495 example <SIG> +authority: q04jkcevqvmu85r014c7dkba38o0ji5r.example 3600 NSEC3 1 0 12 AABBCCDD r53bq7cc2uvmubfu5ocmm6pers9tk9en A RRSIG +authority: q04jkcevqvmu85r014c7dkba38o0ji5r.example 3600 RRSIG NSEC3 7 2 3600 <TIME> <TIME> 44495 example <SIG> +additional: . 0 OPT 512 0 0 8000 diff --git a/test/a-09 b/test/a-09 new file mode 100644 index 0000000..1cca425 --- /dev/null +++ b/test/a-09 @@ -0,0 +1,7 @@ +<SIZE> bytes, 1+0+4+1 records, response, authoritative, noerror +query: DS example +authority: example 3600 SOA ns1.example bugs.x.w.example <TIME> 3600 300 3600000 3600 +authority: example 3600 RRSIG SOA 7 1 3600 <TIME> <TIME> 44495 example <SIG> +authority: 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example 3600 NSEC3 1 0 12 AABBCCDD 2t7b4g4vsa5smi47k61mv5bv1a22bojr NS SOA MX RRSIG DNSKEY NSEC3PARAM +authority: 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom.example 3600 RRSIG NSEC3 7 2 3600 <TIME> <TIME> 44495 example <SIG> +additional: . 0 OPT 512 0 0 8000 diff --git a/test/a-10 b/test/a-10 new file mode 100644 index 0000000..8388037 --- /dev/null +++ b/test/a-10 @@ -0,0 +1,9 @@ +<SIZE> bytes, 1+1+2+4 records, response, authoritative, noerror +query: MX x.w.example +answer: x.w.example 3600 MX 1 xx.example +authority: example 3600 NS ns1.example +authority: example 3600 NS ns2.example +additional: xx.example 3600 A 192.0.2.10 +additional: xx.example 3600 AAAA 2001:db8::f00:baaa +additional: ns1.example 3600 A 192.0.2.1 +additional: ns2.example 3600 A 192.0.2.2 diff --git a/test/a-11 b/test/a-11 new file mode 100644 index 0000000..a374184 --- /dev/null +++ b/test/a-11 @@ -0,0 +1,6 @@ +<SIZE> bytes, 1+0+2+2 records, response, noerror +query: MX mc.a.example +authority: a.example 3600 NS ns1.a.example +authority: a.example 3600 NS ns2.a.example +additional: ns1.a.example 3600 A 192.0.2.5 +additional: ns2.a.example 3600 A 192.0.2.6 diff --git a/test/a-12 b/test/a-12 new file mode 100644 index 0000000..fd9f2e2 --- /dev/null +++ b/test/a-12 @@ -0,0 +1,3 @@ +<SIZE> bytes, 1+0+1+0 records, response, authoritative, nxdomain +query: A a.c.x.w.example +authority: example 3600 SOA ns1.example bugs.x.w.example <TIME> 3600 300 3600000 3600 diff --git a/test/a-13 b/test/a-13 new file mode 100644 index 0000000..8b8cd29 --- /dev/null +++ b/test/a-13 @@ -0,0 +1,3 @@ +<SIZE> bytes, 1+0+1+0 records, response, authoritative, noerror +query: MX ns1.example +authority: example 3600 SOA ns1.example bugs.x.w.example <TIME> 3600 300 3600000 3600 diff --git a/test/a-14 b/test/a-14 new file mode 100644 index 0000000..b08e678 --- /dev/null +++ b/test/a-14 @@ -0,0 +1,3 @@ +<SIZE> bytes, 1+0+1+0 records, response, authoritative, noerror +query: A y.w.example +authority: example 3600 SOA ns1.example bugs.x.w.example <TIME> 3600 300 3600000 3600 diff --git a/test/a-15 b/test/a-15 new file mode 100644 index 0000000..81c4011 --- /dev/null +++ b/test/a-15 @@ -0,0 +1,9 @@ +<SIZE> bytes, 1+1+2+4 records, response, authoritative, noerror +query: MX a.z.w.example +answer: a.z.w.example 3600 MX 1 ai.example +authority: example 3600 NS ns1.example +authority: example 3600 NS ns2.example +additional: ai.example 3600 A 192.0.2.9 +additional: ai.example 3600 AAAA 2001:db8::f00:baa9 +additional: ns1.example 3600 A 192.0.2.1 +additional: ns2.example 3600 A 192.0.2.2 diff --git a/test/a-16 b/test/a-16 new file mode 100644 index 0000000..563b112 --- /dev/null +++ b/test/a-16 @@ -0,0 +1,3 @@ +<SIZE> bytes, 1+0+1+0 records, response, authoritative, noerror +query: AAAA a.z.w.example +authority: example 3600 SOA ns1.example bugs.x.w.example <TIME> 3600 300 3600000 3600 diff --git a/test/a-17 b/test/a-17 new file mode 100644 index 0000000..f9dd3c4 --- /dev/null +++ b/test/a-17 @@ -0,0 +1,3 @@ +<SIZE> bytes, 1+0+1+0 records, response, authoritative, noerror +query: DS example +authority: example 3600 SOA ns1.example bugs.x.w.example <TIME> 3600 300 3600000 3600 diff --git a/test/a-18 b/test/a-18 new file mode 100644 index 0000000..16f37ad --- /dev/null +++ b/test/a-18 @@ -0,0 +1,3 @@ +<SIZE> bytes, 1+1+0+0 records, response, noerror +query: MX an.example.xx +answer: an.example.xx 86400 CNAME tripple.xx diff --git a/test/a-19 b/test/a-19 new file mode 100644 index 0000000..4bcb58e --- /dev/null +++ b/test/a-19 @@ -0,0 +1,4 @@ +<SIZE> bytes, 1+2+0+0 records, response, noerror +query: MX another.example.xx +answer: another.example.xx 86400 CNAME an.example.xx +answer: an.example.xx 86400 CNAME tripple.xx diff --git a/test/a-20 b/test/a-20 new file mode 100644 index 0000000..9f51657 --- /dev/null +++ b/test/a-20 @@ -0,0 +1,4 @@ +<SIZE> bytes, 1+1+1+0 records, response, authoritative, noerror +query: MX simple.example.xx +answer: simple.example.xx 86400 CNAME ns1.example.xx +authority: example.xx 2500 SOA ns1.example.xx bugs.x.w.example.xx <TIME> 3600 300 3600000 3600 diff --git a/test/a-21 b/test/a-21 new file mode 100644 index 0000000..704ffed --- /dev/null +++ b/test/a-21 @@ -0,0 +1,7 @@ +<SIZE> bytes, 1+1+2+2 records, response, noerror +query: MX sub.example.xx +answer: sub.example.xx 86400 CNAME ns1.a.example.xx +authority: a.example.xx 259200 NS ns1.a.example.xx +authority: a.example.xx 259200 NS ns2.a.example.xx +additional: ns1.a.example.xx 259200 A 192.0.2.5 +additional: ns2.a.example.xx 259200 A 192.0.2.6 diff --git a/test/a-22 b/test/a-22 new file mode 100644 index 0000000..8af935b --- /dev/null +++ b/test/a-22 @@ -0,0 +1,7 @@ +<SIZE> bytes, 1+2+2+1 records, response, authoritative, noerror +query: A simple.example.xx +answer: simple.example.xx 86400 CNAME ns1.example.xx +answer: ns1.example.xx 259200 A 192.0.2.1 +authority: example.xx 259200 NS ns1.example.xx +authority: example.xx 259200 NS ns2.example.xx +additional: ns2.example.xx 259200 A 192.0.2.2 diff --git a/test/a-23 b/test/a-23 new file mode 100644 index 0000000..3d73b24 --- /dev/null +++ b/test/a-23 @@ -0,0 +1,4 @@ +<SIZE> bytes, 1+2+0+0 records, response, noerror +query: MX an.example.xx +answer: an.example.xx 86400 CNAME tripple.xx +answer: an.example.xx 86400 RRSIG CNAME 7 3 86400 <TIME> <TIME> 44495 example.xx <SIG> diff --git a/test/a-24 b/test/a-24 new file mode 100644 index 0000000..d944f1a --- /dev/null +++ b/test/a-24 @@ -0,0 +1,6 @@ +<SIZE> bytes, 1+4+0+0 records, response, noerror +query: MX another.example.xx +answer: another.example.xx 86400 CNAME an.example.xx +answer: another.example.xx 86400 RRSIG CNAME 7 3 86400 <TIME> <TIME> 44495 example.xx <SIG> +answer: an.example.xx 86400 CNAME tripple.xx +answer: an.example.xx 86400 RRSIG CNAME 7 3 86400 <TIME> <TIME> 44495 example.xx <SIG> diff --git a/test/a-25 b/test/a-25 new file mode 100644 index 0000000..e13fdb8 --- /dev/null +++ b/test/a-25 @@ -0,0 +1,9 @@ +<SIZE> bytes, 1+2+4+1 records, response, authoritative, noerror +query: MX simple.example.xx +answer: simple.example.xx 86400 CNAME ns1.example.xx +answer: simple.example.xx 86400 RRSIG CNAME 7 3 86400 <TIME> <TIME> 44495 example.xx <SIG> +authority: example.xx 2500 SOA ns1.example.xx bugs.x.w.example.xx <TIME> 3600 300 3600000 3600 +authority: example.xx 2500 RRSIG SOA 7 2 2500 <TIME> <TIME> 44495 example.xx <SIG> +authority: tmd276tdvbbhrhslmaahlbtn3jvn0pru.example.xx 86400 NSEC3 1 0 12 AABBCCDD ubt957071tgo6dp02qb9j6dp2go2243q A RRSIG +authority: tmd276tdvbbhrhslmaahlbtn3jvn0pru.example.xx 86400 RRSIG NSEC3 7 3 86400 <TIME> <TIME> 44495 example.xx <SIG> +additional: . 0 OPT 512 0 0 8000 diff --git a/test/a-26 b/test/a-26 new file mode 100644 index 0000000..ebc2c64 --- /dev/null +++ b/test/a-26 @@ -0,0 +1,9 @@ +<SIZE> bytes, 1+2+2+3 records, response, noerror +query: MX sub.example.xx +answer: sub.example.xx 86400 CNAME ns1.a.example.xx +answer: sub.example.xx 86400 RRSIG CNAME 7 3 86400 <TIME> <TIME> 44495 example.xx <SIG> +authority: a.example.xx 259200 NS ns1.a.example.xx +authority: a.example.xx 259200 NS ns2.a.example.xx +additional: . 0 OPT 512 0 0 8000 +additional: ns1.a.example.xx 259200 A 192.0.2.5 +additional: ns2.a.example.xx 259200 A 192.0.2.6 diff --git a/test/a-27 b/test/a-27 new file mode 100644 index 0000000..a204012 --- /dev/null +++ b/test/a-27 @@ -0,0 +1,12 @@ +<SIZE> bytes, 1+4+3+3 records, response, authoritative, noerror +query: A simple.example.xx +answer: simple.example.xx 86400 CNAME ns1.example.xx +answer: simple.example.xx 86400 RRSIG CNAME 7 3 86400 <TIME> <TIME> 44495 example.xx <SIG> +answer: ns1.example.xx 259200 RRSIG A 7 3 259200 <TIME> <TIME> 44495 example.xx <SIG> +answer: ns1.example.xx 259200 A 192.0.2.1 +authority: example.xx 259200 NS ns1.example.xx +authority: example.xx 259200 NS ns2.example.xx +authority: example.xx 259200 RRSIG NS 7 2 259200 <TIME> <TIME> 44495 example.xx <SIG> +additional: . 0 OPT 512 0 0 8000 +additional: ns2.example.xx 259200 A 192.0.2.2 +additional: ns2.example.xx 259200 RRSIG A 7 3 259200 <TIME> <TIME> 44495 example.xx <SIG> diff --git a/test/a-28 b/test/a-28 new file mode 100644 index 0000000..ea2d44b --- /dev/null +++ b/test/a-28 @@ -0,0 +1,7 @@ +<SIZE> bytes, 1+1+2+2 records, response, authoritative, noerror +query: CNAME an.example.xx +answer: an.example.xx 86400 CNAME tripple.xx +authority: example.xx 259200 NS ns1.example.xx +authority: example.xx 259200 NS ns2.example.xx +additional: ns1.example.xx 259200 A 192.0.2.1 +additional: ns2.example.xx 259200 A 192.0.2.2 diff --git a/test/a-29 b/test/a-29 new file mode 100644 index 0000000..04b11b8 --- /dev/null +++ b/test/a-29 @@ -0,0 +1,12 @@ +<SIZE> bytes, 1+2+3+5 records, response, authoritative, noerror +query: CNAME an.example.xx +answer: an.example.xx 86400 CNAME tripple.xx +answer: an.example.xx 86400 RRSIG CNAME 7 3 86400 <TIME> <TIME> 44495 example.xx <SIG> +authority: example.xx 259200 NS ns1.example.xx +authority: example.xx 259200 NS ns2.example.xx +authority: example.xx 259200 RRSIG NS 7 2 259200 <TIME> <TIME> 44495 example.xx <SIG> +additional: . 0 OPT 512 0 0 8000 +additional: ns1.example.xx 259200 A 192.0.2.1 +additional: ns1.example.xx 259200 RRSIG A 7 3 259200 <TIME> <TIME> 44495 example.xx <SIG> +additional: ns2.example.xx 259200 A 192.0.2.2 +additional: ns2.example.xx 259200 RRSIG A 7 3 259200 <TIME> <TIME> 44495 example.xx <SIG> diff --git a/test/a-30 b/test/a-30 new file mode 100644 index 0000000..a98f708 --- /dev/null +++ b/test/a-30 @@ -0,0 +1,3 @@ +<SIZE> bytes, 1+0+1+0 records, response, authoritative, noerror +query: AAAA a.ns.unsigned.xx +authority: unsigned.xx 2560 SOA a.ns.unsigned.xx hostmaster.unsigned.xx <TIME> 16384 2048 1048576 2560 diff --git a/test/a-31 b/test/a-31 new file mode 100644 index 0000000..eb8f9d7 --- /dev/null +++ b/test/a-31 @@ -0,0 +1,4 @@ +<SIZE> bytes, 1+0+1+1 records, response, authoritative, noerror +query: AAAA a.ns.unsigned.xx +authority: unsigned.xx 2560 SOA a.ns.unsigned.xx hostmaster.unsigned.xx <TIME> 16384 2048 1048576 2560 +additional: . 0 OPT 512 0 0 8000 diff --git a/test/a-32 b/test/a-32 new file mode 100644 index 0000000..614da90 --- /dev/null +++ b/test/a-32 @@ -0,0 +1,3 @@ +<SIZE> bytes, 1+0+1+0 records, response, authoritative, nxdomain +query: A nx.unsigned.xx +authority: unsigned.xx 2560 SOA a.ns.unsigned.xx hostmaster.unsigned.xx <TIME> 16384 2048 1048576 2560 diff --git a/test/a-33 b/test/a-33 new file mode 100644 index 0000000..f131292 --- /dev/null +++ b/test/a-33 @@ -0,0 +1,4 @@ +<SIZE> bytes, 1+0+1+1 records, response, authoritative, nxdomain +query: A nx.unsigned.xx +authority: unsigned.xx 2560 SOA a.ns.unsigned.xx hostmaster.unsigned.xx <TIME> 16384 2048 1048576 2560 +additional: . 0 OPT 512 0 0 8000 diff --git a/test/a-34 b/test/a-34 new file mode 100644 index 0000000..299ea04 --- /dev/null +++ b/test/a-34 @@ -0,0 +1,9 @@ +<SIZE> bytes, 1+1+2+4 records, response, authoritative, noerror +query: MX wc.w.unsigned.xx +answer: wc.w.unsigned.xx 3600 MX 1 aaaa.unsigned.xx +authority: unsigned.xx 259200 NS a.ns.unsigned.xx +authority: unsigned.xx 259200 NS b.ns.unsigned.xx +additional: aaaa.unsigned.xx 86400 A 10.11.12.13 +additional: aaaa.unsigned.xx 86400 AAAA 2002:a0b:c0d::1 +additional: a.ns.unsigned.xx 259200 A 10.10.10.10 +additional: b.ns.unsigned.xx 259200 A 10.11.11.11 diff --git a/test/a-35 b/test/a-35 new file mode 100644 index 0000000..de21d45 --- /dev/null +++ b/test/a-35 @@ -0,0 +1,10 @@ +<SIZE> bytes, 1+1+2+5 records, response, authoritative, noerror +query: MX wc.w.unsigned.xx +answer: wc.w.unsigned.xx 3600 MX 1 aaaa.unsigned.xx +authority: unsigned.xx 259200 NS a.ns.unsigned.xx +authority: unsigned.xx 259200 NS b.ns.unsigned.xx +additional: . 0 OPT 512 0 0 8000 +additional: aaaa.unsigned.xx 86400 A 10.11.12.13 +additional: aaaa.unsigned.xx 86400 AAAA 2002:a0b:c0d::1 +additional: a.ns.unsigned.xx 259200 A 10.10.10.10 +additional: b.ns.unsigned.xx 259200 A 10.11.11.11 diff --git a/test/a-36 b/test/a-36 new file mode 100644 index 0000000..f77cb70 --- /dev/null +++ b/test/a-36 @@ -0,0 +1,3 @@ +<SIZE> bytes, 1+1+0+0 records, response, noerror +query: MX an.unsigned.xx +answer: an.unsigned.xx 86400 CNAME tripple.xx diff --git a/test/a-37 b/test/a-37 new file mode 100644 index 0000000..f77cb70 --- /dev/null +++ b/test/a-37 @@ -0,0 +1,3 @@ +<SIZE> bytes, 1+1+0+0 records, response, noerror +query: MX an.unsigned.xx +answer: an.unsigned.xx 86400 CNAME tripple.xx diff --git a/test/a-38 b/test/a-38 new file mode 100644 index 0000000..ffb7d58 --- /dev/null +++ b/test/a-38 @@ -0,0 +1,4 @@ +<SIZE> bytes, 1+2+0+0 records, response, noerror +query: MX another.unsigned.xx +answer: another.unsigned.xx 86400 CNAME an.example.xx +answer: an.example.xx 86400 CNAME tripple.xx diff --git a/test/a-39 b/test/a-39 new file mode 100644 index 0000000..9fbea38 --- /dev/null +++ b/test/a-39 @@ -0,0 +1,5 @@ +<SIZE> bytes, 1+3+0+0 records, response, noerror +query: MX another.unsigned.xx +answer: another.unsigned.xx 86400 CNAME an.example.xx +answer: an.example.xx 86400 CNAME tripple.xx +answer: an.example.xx 86400 RRSIG CNAME 7 3 86400 <TIME> <TIME> 44495 example.xx <SIG> diff --git a/test/data b/test/data new file mode 100644 index 0000000..0dd7396 --- /dev/null +++ b/test/data @@ -0,0 +1,65 @@ +# Example zones for testing. + +# This one should match RFC-5155 appendix A with different keys. + +Zexample:ns1.example:bugs.x.w.example:1081539377:3600:300:3600000:3600:3600:: +&example:192.0.2.1:ns1.example:3600 +&example:192.0.2.2:ns2.example:3600 +@example:192.0.2.10:xx.example:1:3600 +#Kexample:256:3:7:AwEAAZvSuWicF6oQ8QarGTQ84GDgYD3c12nrz/K2PQ98eCy0SKOZ+p4662QxkUGTmrxoUSGVlPp2arYXNs5AVf+ggt9zpb+ZSLV18Z152kAA6iHXVrwTbUZX1Eg4IqxzrSX2/jqs2dqQF7dDZcNV7xNpKfKDTW5J5d7vbkhcM8/xxb1p:3600:: +#Kexample:257:3:7:AwEAAdBi/kUytR/v7iW9h9qsgtuj5BSDEvE5djja8UEdFLqThQEJ0bnptExEoS8acYQYhLiufAEfp7no0bV2wcS6jR9cIRS0iZ/NNaPeG04U9HDz1VXiZ9xIsifw6feJlHEUAWMxtq7KF2Kyn3jOz05o08zk5XcIQnBDZiPw96bQfDlxMiM8umPWh8iZa6VmzQJ9bbouyoAppm/9O+ha7lCdMUbvIcKLoYVaVyK+pI2vHH4RaqrGUcposqi4hzJzOZvCU5FtJ+4uWGV+rleTmgR+YWS1gwfbNtaGIQacCAcSDA184TwKuUmHoHdBcrond7eyZGMVbKTbQ/MpiRI56uHd2bxqurBc6NmEsG9r3IZs+TsTvnkQVPksho39gcifpt/NKJ0uN01ZNUUvWQIZREm1UB/uR2hFWJ1hCvPkI08B5AbxIeRc8cb864PJHw2zye0wi6Ey0CHJK04KZLU+f6s80v7TsWmy/1gIMQMrDmiClkJQ/oFddCgisi/SgGbiaIkm5HUgEzBkTnZRluWwgZHVmJHI9I1Vwnyh3NReJo0IIRE90QGrOzA9l/op938f96E1ucFze28OzffhuLCQmmsrMXrKHnqg3K7vV+yk2v7vHec2GoKPuDwg5Lc6O1jOfx2AtoK0OC8Aj3XztynbzjdjJscxZr+C4JeN25pl8ilBT0Zp:3600:: +#Pexample:1:0:12::aabbccdd:3600:: + ++2t7b4g4vsa5smi47k61mv5bv1a22bojr.example:192.0.2.127:3600 + +&a.example:192.0.2.5:ns1.a.example:3600 +&a.example:192.0.2.6:ns2.a.example:3600 +#Da.example:58470:5:1:3079F1593EBAD6DC121E202A8B766A6A4837206C:3600:: + ++ai.example:192.0.2.9:3600 +3ai.example:20010db800000000000000000f00baa9:3600 +:ai.example:13:\006KLH-10\003ITS:3600 + +&c.example:192.0.2.7:ns1.c.example:3600 +&c.example:192.0.2.8:ns2.c.example:3600 + +@*.w.example::ai.example:1:3600 +@x.w.example::xx.example:1:3600 +@x.y.w.example::xx.example:1:3600 + +3xx.example:20010db800000000000000000f00baaa:3600 +:xx.example:13:\006KLH-10\007TOPS-20:3600 + + +# This one is somewhat related to RFC-2308. +Zexample.xx:ns1.example.xx:bugs.x.w.example.xx:1081539377:3600:300:3600000:3600:2500 +&example.xx:192.0.2.1:ns1.example.xx +&example.xx:192.0.2.2:ns2.example.xx +#Kexample.xx:256:3:7:AwEAAZvSuWicF6oQ8QarGTQ84GDgYD3c12nrz/K2PQ98eCy0SKOZ+p4662QxkUGTmrxoUSGVlPp2arYXNs5AVf+ggt9zpb+ZSLV18Z152kAA6iHXVrwTbUZX1Eg4IqxzrSX2/jqs2dqQF7dDZcNV7xNpKfKDTW5J5d7vbkhcM8/xxb1p::: +#Kexample.xx:257:3:7:AwEAAdBi/kUytR/v7iW9h9qsgtuj5BSDEvE5djja8UEdFLqThQEJ0bnptExEoS8acYQYhLiufAEfp7no0bV2wcS6jR9cIRS0iZ/NNaPeG04U9HDz1VXiZ9xIsifw6feJlHEUAWMxtq7KF2Kyn3jOz05o08zk5XcIQnBDZiPw96bQfDlxMiM8umPWh8iZa6VmzQJ9bbouyoAppm/9O+ha7lCdMUbvIcKLoYVaVyK+pI2vHH4RaqrGUcposqi4hzJzOZvCU5FtJ+4uWGV+rleTmgR+YWS1gwfbNtaGIQacCAcSDA184TwKuUmHoHdBcrond7eyZGMVbKTbQ/MpiRI56uHd2bxqurBc6NmEsG9r3IZs+TsTvnkQVPksho39gcifpt/NKJ0uN01ZNUUvWQIZREm1UB/uR2hFWJ1hCvPkI08B5AbxIeRc8cb864PJHw2zye0wi6Ey0CHJK04KZLU+f6s80v7TsWmy/1gIMQMrDmiClkJQ/oFddCgisi/SgGbiaIkm5HUgEzBkTnZRluWwgZHVmJHI9I1Vwnyh3NReJo0IIRE90QGrOzA9l/op938f96E1ucFze28OzffhuLCQmmsrMXrKHnqg3K7vV+yk2v7vHec2GoKPuDwg5Lc6O1jOfx2AtoK0OC8Aj3XztynbzjdjJscxZr+C4JeN25pl8ilBT0Zp::: +#Pexample.xx:1:0:12::aabbccdd::: + +&a.example.xx:192.0.2.5:ns1.a.example.xx +&a.example.xx:192.0.2.6:ns2.a.example.xx + +Can.example.xx:tripple.xx +Canother.example.xx:an.example.xx +Csimple.example.xx:ns1.example.xx +Csub.example.xx:ns1.a.example.xx + + +# Selfmade example for testing an unsigned zone +.unsigned.xx:10.10.10.10:a +.unsigned.xx:10.11.11.11:b + ++aaaa.unsigned.xx:10.11.12.13 +3aaaa.unsigned.xx:20020a0b0c0d00000000000000000001 + +@*.w.unsigned.xx::aaaa.unsigned.xx:1:3600 +@x.w.unsigned.xx::xx.example:1:3600 +@x.y.w.unsigned.xx::xx.example:1:3600 + +Can.unsigned.xx:tripple.xx +Canother.unsigned.xx:an.example.xx +Csimple.unsigned.xx:ns1.example.xx +Csub.unsigned.xx:ns1.a.example.xx diff --git a/test/example.ksk b/test/example.ksk new file mode 100644 index 0000000..691cfe1 --- /dev/null +++ b/test/example.ksk @@ -0,0 +1,53 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIJKgIBAAKCAgEA0GL+RTK1H+/uJb2H2qyC26PkFIMS8Tl2ONrxQR0UupOFAQnR +uem0TEShLxpxhBiEuK58AR+nuejRtXbBxLqNH1whFLSJn801o94bThT0cPPVVeJn +3EiyJ/Dp94mUcRQBYzG2rsoXYrKfeM7PTmjTzOTldwhCcENmI/D3ptB8OXEyIzy6 +Y9aHyJlrpWbNAn1tui7KgCmmb/076FruUJ0xRu8hwouhhVpXIr6kja8cfhFqqsZR +ymiyqLiHMnM5m8JTkW0n7i5YZX6uV5OaBH5hZLWDB9s21oYhBpwIBxIMDXzhPAq5 +SYegd0Fyuid3t7JkYxVspNtD8ymJEjnq4d3ZvGq6sFzo2YSwb2vchmz5OxO+eRBU ++SyGjf2ByJ+m380onS43TVk1RS9ZAhlESbVQH+5HaEVYnWEK8+QjTwHkBvEh5Fzx +xvzrg8kfDbPJ7TCLoTLQIckrTgpktT5/qzzS/tOxabL/WAgxAysOaIKWQlD+gV10 +KCKyL9KAZuJoiSbkdSATMGROdlGW5bCBkdWYkcj0jVXCfKHc1F4mjQghET3RAas7 +MD2X+in3fx/3oTW5wXN7bw7N9+G4sJCaaysxesoeeqDcru9X7KTa/u8d5zYago+4 +PCDktzo7WM5/HYC2grQ4LwCPdfO3KdvON2MmxzFmv4Lgl43bmmXyKUFPRmkCAwEA +AQKCAgEAtUH2I+CYdYAwKHm0arv1UvE6mbDtUA+ISqn+gYG3Hxbj8ORGnayvnEtx +3FPm+1yMTUvQJvYO4YGmr23t253c1LNBPw5OS0am6rNuErvdZ0ZggUTezFgbRuyh +xiPQj480KcD7QwwbzUjLt7xDy9MYr7dF9QSlLZsihA68i0f7VcelMctH4UGgeBci +8Ar8Nbc+M10x3Mrdr7mYW2KEunAQhb/JILxtsV3EPz+OSINRiELEAmlgiWwKQwHG +71YUfOxJ3kwRGHcNgrLvGNQVeuUm9/9+St4d0/l1Tpd30BadjznZfG1jf5bOOA0g +qtVbp9guw5TGHJtwfljZlpX0PaTIFy0c6esj/AEkUGl8lCPxh4ffE/t5vdZhLhET +9F+Y5ktB9dqdcEoUs5FNrb+DKjwrGxkifXGmelKxWAfNfhZIe0ELhp607FIk5TYC +VxrQX90tI4HO3wdceOafCee0xDF3GDisIlCNd7zRwNhHY3pnEYjTxGQum0u7s9q1 +HbrbSlm+D61fAlQ5stKefhk5P51dVmjONt3TMgOg/IzocsgI1pR9RviKOW14Gs8Z +1PiC0tZIG0HDUHs8UEHjMkyXrULEdW+i33dHpjEcsK8GK4+EHWRfsC2NXOJXcjIw +8YwJtIf1BistPz2OGm4zkUB9XFjQrauX4WGofVPvEFp5kTX0CkUCggEBAP5d5VuE +D36K3rVZLdW/Jr1qdE3bTx01L0ktp9K0kjnMQO6xUvn1+Ef/+mKwN0hBRIzYtz4q +TADpXX5d9N7Esw5qYbFWFd5IWTuS+Sl7KTwy9StYL7SaBudPaEhCyYj1yxzKZZ5n +RbzNF4zIv45lxzq4fxLbdm64fAmo/RPG+m1UqrfRXh7qO2By8ykOev5qD9qo1XWe +DkvNHpiPk3rMA+yzumoD5mnC2j7DhNjuC4KaWHxsNu4Ln616KLw3OXJFmQn8FjB3 +BI5B4yUH8S2vXQGjncgOw/0eH09dIDSy5OGhEf6h2clZaD0FMn4RKT6Bp51v8oik +qDArnyW5ZSPE718CggEBANG5hQP7GekwO6cniqb22FQyYgXX7zokcjT6OoRgvNSy +YJVtXTsff3YkR9LQCzCVOwHg1kGlv0ra6XfkwKQ46f5uRoFuq8+raOiYrAmxSWyQ +5OfkS/V3WeLHeykEZFOR//oDB6JUiXiQ3uL3pE1ja63unKHym4RL1R9l3p0mpsTE +2jsjnOV9WOYdL3m5WVslIbbN4c+P1sjnzJhAEvaqnPWOTlsHRcTl6idQgMtdgyyu +TAWxSItCnTD9qN6hlODCx+Mrok7/j1BmD2kY00AbML2nkT2HzdXN7dVOku8ZmaW8 +lqtgsUYvwMQuYNi8NjIz5fRyeVC4HHO44YivqrQzxzcCggEBAPHAre73qX48YAR9 +mIlw3lHiLl2c1SlOVf237avdwKg8D26Mi+9TrkBH8mH/VttOZOd0RVxI+OlY4mnq +xINA8Wj/BJB139zeaCitvC+HhZ5YVBl4/AYq6erH1rXu+/o2mW9okYImZupVBk/g +r+aXpu2RUfzLJll+7yyDNtyoHXTxpjuEOm8pcXtuZNqdj5njlePc2Nurd6zla3HV +63YnFofOHZsKz9+uuJw0WTuPqtLa/MRsWRyPYZiP5M1Vszx/Fz+dHj27sFHAHzEf +xkIETGH1bk0oc29LRLi6KpTLfatP2XlnvESYu/Ba0y1sBAYLVhHUxu7Fh7AYlW5W +MOD5GAMCggEAebJKYkX6AhtP8i36wenpG+pkgPmNQtLVRrKQ9DHiQRYE/5CHkgA0 +CU0CNG0uoRFnPS7HhS51sy0WXtDpjCHOfiplVUPwBMB1TssQwUsTzSDDA2CxRw3r +pbGVYPbAdNH6lIvfiS2+26xM+a0ztQhk+nfEgiDyZzFNyTtmkxBTo0iLTdfbejtj +M5xp6RtJo58HUjljt/rCarA/Q3Wiy2mzTLY395BfxuKXHhsTsW5g6LN3P7Jg4xZT +epMmw5FFf6rnLIYsV+Tpt4CRnq2eH8vnW5X5rJe6ND+bq7Q9hOr5AnhNgcLI+25I +UE6NOhb05+q/nDo09Ubwk6ILlTJCPvDwvwKCAQEAwIE3UchyTPqpxQhwM4pskzp5 +4d22lESv0+hkmxUIoHOABuHPF3USJ+UmptPBlvU9ii9TPh3M3PZmH0e5K/Tuon6Y +U3F5P5kP2tHv0uChAhlFLgn8ibQu7j77s2F7YnkdGPldahML3s6O/hrbcqWh87t9 +nHYPu9cfipNKvxtyLBqeqAi36ysSngKeg/G6zoRVXKNAxvfVW18ndloopnmJYpUH +SYpsYHj/Ob9YfXFeCvbsMsXy8384EGA+kt59OBnMn4NPy4uiQXaGEcQWmE+obKZa +hYZLSp/LT3kPmKedkNkitLonghDLsgcTwL9TPo+OMRZ8GynOI+7Lp9JzMrm55w== +-----END RSA PRIVATE KEY----- +#Kexample:257:3:8:AwEAAdBi/kUytR/v7iW9h9qsgtuj5BSDEvE5djja8UEdFLqThQEJ0bnptExEoS8acYQYhLiufAEfp7no0bV2wcS6jR9cIRS0iZ/NNaPeG04U9HDz1VXiZ9xIsifw6feJlHEUAWMxtq7KF2Kyn3jOz05o08zk5XcIQnBDZiPw96bQfDlxMiM8umPWh8iZa6VmzQJ9bbouyoAppm/9O+ha7lCdMUbvIcKLoYVaVyK+pI2vHH4RaqrGUcposqi4hzJzOZvCU5FtJ+4uWGV+rleTmgR+YWS1gwfbNtaGIQacCAcSDA184TwKuUmHoHdBcrond7eyZGMVbKTbQ/MpiRI56uHd2bxqurBc6NmEsG9r3IZs+TsTvnkQVPksho39gcifpt/NKJ0uN01ZNUUvWQIZREm1UB/uR2hFWJ1hCvPkI08B5AbxIeRc8cb864PJHw2zye0wi6Ey0CHJK04KZLU+f6s80v7TsWmy/1gIMQMrDmiClkJQ/oFddCgisi/SgGbiaIkm5HUgEzBkTnZRluWwgZHVmJHI9I1Vwnyh3NReJo0IIRE90QGrOzA9l/op938f96E1ucFze28OzffhuLCQmmsrMXrKHnqg3K7vV+yk2v7vHec2GoKPuDwg5Lc6O1jOfx2AtoK0OC8Aj3XztynbzjdjJscxZr+C4JeN25pl8ilBT0Zp::: +#Dexample:44062:8:1:e95469a449a82fc0c0ccb257b8a546edcdeb564d::: diff --git a/test/example.zsk b/test/example.zsk new file mode 100644 index 0000000..4d5952b --- /dev/null +++ b/test/example.zsk @@ -0,0 +1,17 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCb0rlonBeqEPEGqxk0POBg4GA93Ndp68/ytj0PfHgstEijmfqe +OutkMZFBk5q8aFEhlZT6dmq2FzbOQFX/oILfc6W/mUi1dfGdedpAAOoh11a8E21G +V9RIOCKsc60l9v46rNnakBe3Q2XDVe8TaSnyg01uSeXe725IXDPP8cW9aQIDAQAB +AoGAeZeh3qOPQ8IckpuI+15VqMLt1tgxsBG3Hypd02vJSvkThbZt/nLzpCeZtZY8 +tLCiPpa+vgMRmi3bMm65rNPPyt5pFzJ3sEVSgP98zoN9MmpDBKRe93poMyOiWdKL +JagmHiBURi9LRk3SG9M7w/HyQn9TUtuLXjgeNlz/zdeLSgECQQDL8PLijCrqeeGL +9OYBjs63Db2V6dMx3BrI3y3KstM0/aEBH+9mzkZD9IrgqrTn/PtIpPYuIhtWWwos +i4bpnuu5AkEAw5lhJmSVnNqtrsC9F5YqBUlMyPvfJeQWEW0dwxVk3NCc16AtBUcC +s/3lrKJNqAKYB5bRTHNca2tk0Lw8BRUXMQJATXQzKqtFWUv0xyy5dfoAtDD5wcfO +N+96FLP+Ni94W3XAAidYytiogwKLBAyRLFI+NTbBcH/vlfp5gLV1BaEfsQJAc8AN +pMm7XAJw68x1WkLsBQrWnM2oxWSPxqo7BZpggOgXGOdaHRhjuh5TT3EQ4Y7/ZuZS +X5qZI5x/IaNzJVLQ0QJBALSHOwr6CA+PH0g6qeTAewMMA5M95/4hCl2JHL9jTvbr +5JdKq1+NP/0ZY8YeyAJLqgbWZvrvac3h4sKE4e/ey2k= +-----END RSA PRIVATE KEY----- +#Kexample:256:3:7:AwEAAZvSuWicF6oQ8QarGTQ84GDgYD3c12nrz/K2PQ98eCy0SKOZ+p4662QxkUGTmrxoUSGVlPp2arYXNs5AVf+ggt9zpb+ZSLV18Z152kAA6iHXVrwTbUZX1Eg4IqxzrSX2/jqs2dqQF7dDZcNV7xNpKfKDTW5J5d7vbkhcM8/xxb1p::: +#Dexample:44495:7:1:e4c565a032c3709f54b72541ef13e647c9c19e1d::: diff --git a/test/q-01 b/test/q-01 new file mode 100644 index 0000000..bef04de --- /dev/null +++ b/test/q-01 @@ -0,0 +1,2 @@ +-s mx x.w.example +# RFC-4035 Appendix B.1 diff --git a/test/q-02 b/test/q-02 new file mode 100644 index 0000000..b5cfc62 --- /dev/null +++ b/test/q-02 @@ -0,0 +1,2 @@ +-s mx mc.a.example +# RFC-4035 Appendix B.4 diff --git a/test/q-03 b/test/q-03 new file mode 100644 index 0000000..ec55a89 --- /dev/null +++ b/test/q-03 @@ -0,0 +1,2 @@ +-s a a.c.x.w.example +# RFC-5155 Appendix B.1 diff --git a/test/q-04 b/test/q-04 new file mode 100644 index 0000000..72ff808 --- /dev/null +++ b/test/q-04 @@ -0,0 +1,2 @@ +-s mx ns1.example +# RFC-5155 Appendix B.2 diff --git a/test/q-05 b/test/q-05 new file mode 100644 index 0000000..da2d679 --- /dev/null +++ b/test/q-05 @@ -0,0 +1,2 @@ +-s a y.w.example +# RFC-5155 Appendix B.2.1 diff --git a/test/q-06 b/test/q-06 new file mode 100644 index 0000000..c08772a --- /dev/null +++ b/test/q-06 @@ -0,0 +1,2 @@ +-s mx a.z.w.example +# RFC-5155 Appendix B.4 diff --git a/test/q-07 b/test/q-07 new file mode 100644 index 0000000..3079f01 --- /dev/null +++ b/test/q-07 @@ -0,0 +1,2 @@ +-S mx a.z.w.example +# RFC-5155 Appendix B.4 diff --git a/test/q-08 b/test/q-08 new file mode 100644 index 0000000..1123888 --- /dev/null +++ b/test/q-08 @@ -0,0 +1,2 @@ +-s aaaa a.z.w.example +# RFC-5155 Appendix B.5 diff --git a/test/q-09 b/test/q-09 new file mode 100644 index 0000000..30ed504 --- /dev/null +++ b/test/q-09 @@ -0,0 +1,2 @@ +-s ds example +# RFC-5155 Appendix B.6 diff --git a/test/q-10 b/test/q-10 new file mode 100644 index 0000000..3947108 --- /dev/null +++ b/test/q-10 @@ -0,0 +1 @@ +mx x.w.example diff --git a/test/q-11 b/test/q-11 new file mode 100644 index 0000000..075e5e6 --- /dev/null +++ b/test/q-11 @@ -0,0 +1 @@ +mx mc.a.example diff --git a/test/q-12 b/test/q-12 new file mode 100644 index 0000000..333e0bd --- /dev/null +++ b/test/q-12 @@ -0,0 +1 @@ +a a.c.x.w.example diff --git a/test/q-13 b/test/q-13 new file mode 100644 index 0000000..f98714e --- /dev/null +++ b/test/q-13 @@ -0,0 +1 @@ +mx ns1.example diff --git a/test/q-14 b/test/q-14 new file mode 100644 index 0000000..f442db7 --- /dev/null +++ b/test/q-14 @@ -0,0 +1 @@ +a y.w.example diff --git a/test/q-15 b/test/q-15 new file mode 100644 index 0000000..8aeba48 --- /dev/null +++ b/test/q-15 @@ -0,0 +1 @@ +mx a.z.w.example diff --git a/test/q-16 b/test/q-16 new file mode 100644 index 0000000..15de40d --- /dev/null +++ b/test/q-16 @@ -0,0 +1 @@ +aaaa a.z.w.example diff --git a/test/q-17 b/test/q-17 new file mode 100644 index 0000000..0362480 --- /dev/null +++ b/test/q-17 @@ -0,0 +1 @@ +ds example diff --git a/test/q-18 b/test/q-18 new file mode 100644 index 0000000..18e7a2b --- /dev/null +++ b/test/q-18 @@ -0,0 +1 @@ +mx an.example.xx diff --git a/test/q-19 b/test/q-19 new file mode 100644 index 0000000..195f284 --- /dev/null +++ b/test/q-19 @@ -0,0 +1 @@ +mx another.example.xx diff --git a/test/q-20 b/test/q-20 new file mode 100644 index 0000000..fed41b4 --- /dev/null +++ b/test/q-20 @@ -0,0 +1 @@ +mx simple.example.xx diff --git a/test/q-21 b/test/q-21 new file mode 100644 index 0000000..d0c8d6a --- /dev/null +++ b/test/q-21 @@ -0,0 +1 @@ +mx sub.example.xx diff --git a/test/q-22 b/test/q-22 new file mode 100644 index 0000000..2bafbd8 --- /dev/null +++ b/test/q-22 @@ -0,0 +1 @@ +a simple.example.xx diff --git a/test/q-23 b/test/q-23 new file mode 100644 index 0000000..274715c --- /dev/null +++ b/test/q-23 @@ -0,0 +1 @@ +-s mx an.example.xx diff --git a/test/q-24 b/test/q-24 new file mode 100644 index 0000000..71c8006 --- /dev/null +++ b/test/q-24 @@ -0,0 +1 @@ +-s mx another.example.xx diff --git a/test/q-25 b/test/q-25 new file mode 100644 index 0000000..20d96e9 --- /dev/null +++ b/test/q-25 @@ -0,0 +1 @@ +-s mx simple.example.xx diff --git a/test/q-26 b/test/q-26 new file mode 100644 index 0000000..626d4b4 --- /dev/null +++ b/test/q-26 @@ -0,0 +1 @@ +-s mx sub.example.xx diff --git a/test/q-27 b/test/q-27 new file mode 100644 index 0000000..1030c51 --- /dev/null +++ b/test/q-27 @@ -0,0 +1 @@ +-s a simple.example.xx diff --git a/test/q-28 b/test/q-28 new file mode 100644 index 0000000..b53f963 --- /dev/null +++ b/test/q-28 @@ -0,0 +1 @@ +cname an.example.xx diff --git a/test/q-29 b/test/q-29 new file mode 100644 index 0000000..9d31260 --- /dev/null +++ b/test/q-29 @@ -0,0 +1 @@ +-s cname an.example.xx diff --git a/test/q-30 b/test/q-30 new file mode 100644 index 0000000..15d5ee6 --- /dev/null +++ b/test/q-30 @@ -0,0 +1 @@ +aaaa a.ns.unsigned.xx diff --git a/test/q-31 b/test/q-31 new file mode 100644 index 0000000..23d7d82 --- /dev/null +++ b/test/q-31 @@ -0,0 +1 @@ +-s aaaa a.ns.unsigned.xx diff --git a/test/q-32 b/test/q-32 new file mode 100644 index 0000000..68769ec --- /dev/null +++ b/test/q-32 @@ -0,0 +1 @@ +a nx.unsigned.xx diff --git a/test/q-33 b/test/q-33 new file mode 100644 index 0000000..bfd510e --- /dev/null +++ b/test/q-33 @@ -0,0 +1 @@ +-s a nx.unsigned.xx diff --git a/test/q-34 b/test/q-34 new file mode 100644 index 0000000..d04f65e --- /dev/null +++ b/test/q-34 @@ -0,0 +1 @@ +mx wc.w.unsigned.xx diff --git a/test/q-35 b/test/q-35 new file mode 100644 index 0000000..15b6fd3 --- /dev/null +++ b/test/q-35 @@ -0,0 +1 @@ +-s mx wc.w.unsigned.xx diff --git a/test/q-36 b/test/q-36 new file mode 100644 index 0000000..6c7aec9 --- /dev/null +++ b/test/q-36 @@ -0,0 +1 @@ +mx an.unsigned.xx diff --git a/test/q-37 b/test/q-37 new file mode 100644 index 0000000..52a2dec --- /dev/null +++ b/test/q-37 @@ -0,0 +1 @@ +-s mx an.unsigned.xx diff --git a/test/q-38 b/test/q-38 new file mode 100644 index 0000000..b8778b8 --- /dev/null +++ b/test/q-38 @@ -0,0 +1 @@ +mx another.unsigned.xx diff --git a/test/q-39 b/test/q-39 new file mode 100644 index 0000000..a79f33f --- /dev/null +++ b/test/q-39 @@ -0,0 +1 @@ +-s mx another.unsigned.xx diff --git a/tinydns-sign.pl b/tinydns-sign.pl new file mode 100755 index 0000000..fd72033 --- /dev/null +++ b/tinydns-sign.pl @@ -0,0 +1,1025 @@ +#!/usr/bin/perl -w + +# (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/>. + +use strict; +use Fcntl; +use Digest::SHA1 qw(sha1 sha1_hex); +use Crypt::OpenSSL::RSA; +use MIME::Base64; + +$main::ttl = 432000; +%main::keys = (); +%main::names = (); +@main::zones = (); +%main::locs = (); +$main::catchAllLoc = undef; + +while ($#ARGV >= 0) { + if ($ARGV[0] eq '-h' || $ARGV[0] eq '--help') { + &usage(); + # usage does not return + } elsif ($ARGV[0] eq '-t') { + if ($#ARGV < 1) { &usage(); } + $main::ttl = $ARGV[1]; + shift @ARGV; + } elsif ($ARGV[0] eq '-g') { + if ($#ARGV != 5) { &usage(); } + &genkey($ARGV[1], $ARGV[2], $ARGV[3], $ARGV[4], $ARGV[5]); + # genkey does not return + exit(0); + } else { # keyfile + &addKey($ARGV[0]); + } + shift @ARGV; +} + +my $now = time(); +while ($_ = <STDIN>) { + s/\s+$//s; + if (/^:[^:]*:(43|46|48|50|51|6528[12]):/) { next; } + if (/^$/ || /^-/ || /^#[^KDP]/) { + print "$_\n"; + next; + } + if (/^\./) { + print "# Was: $_\n"; + while (! /^\.([^:]*):([0-9.]*):([^:]+):(\d*):(\d*):([^:]*)$/) { $_ .= ':'; } + my ($dom,$ip,$ns,$ttl,$ts,$lo) = /^\.([^:]*):([0-9.]*):([^:]+):(\d*):(\d*):([^:]*)$/; + # &fqdn:ip:x:ttl:timestamp:lo + print "\&$dom:$ip:$ns:$ttl:$ts:$lo\n"; + $dom =~ tr/A-Z/a-z/; + $ns =~ tr/A-Z/a-z/; + if ($ns !~ /\./) { $ns .= ".ns.$dom"; } + my $rec = &getOrCreateRRs($dom); + $rec->addNS($ns, $ttl, $ts, $lo); + &addA($ns, $ip, $ttl || 259200, $ts, $lo); + if (exists($rec->{byType}->{6})) { next; } # don't create more than one SOA per zone + # Zfqdn:mname:rname:ser:ref:ret:exp:min:ttl:timestamp:lo + $_ = "Z$dom:$ns:hostmaster.${dom}:::::$ttl:$ts:$lo\n"; + } + if (/^Z/) { + my @fields = split /:/; + if ($#fields < 3 || $fields[3] !~ /^00/) { + $fields[3] = $now; + $_ = join(":", @fields); + } + } + print "$_\n"; + if (/^%(\w\w?):?/) { + $main::locs{$1} = $'; + if ($' eq "") { + $main::catchAllLoc = $1; + } + } elsif (/^#[KDP]/) { + if (/^#K([^:]*):(\d+):(\d*):(\d+):([^:]*):(\d*):(\d*):([^:]*)$/) { + # C<#Kname:flags:proto:algorithm:key:ttl:timestamp:lo> + my ($dom,$flags,$proto,$alg,$key,$ttl,$ts,$lo) = ($1, $2, $3, $4, $5, $6, $7, $8); + $dom =~ tr/A-Z/a-z/; + my $pubkey = decode_base64($key); + my $rdata = &htons($flags).chr($proto).chr($alg).$pubkey; + &makeGenericRecord($dom, 48, $rdata, $ttl, $ts, $lo); + my $rrs = &getOrCreateRRs($dom); + $rrs->addKey($flags, $alg, $pubkey); + $rrs->addRecord(48, $rdata, $ttl, $ts, $lo); + } elsif (/^#D([^:]*):(\d+):(\d+):(\d+):([0-9a-fA-F]*):(\d*):(\d*):([^:]*)$/) { + # C<#Dname:tag:algorithm:digest:fingerprint:ttl:timestamp:lo> + my ($dom,$tag,$alg,$dig,$fp,$ttl,$ts,$lo) = ($1, $2, $3, $4, $5, $6, $7, $8); + $dom =~ tr/A-Z/a-z/; + my $rdata = &htons($tag).chr($alg).chr($dig).pack("H*", $fp); + &makeGenericRecord($dom, 43, $rdata, $ttl, $ts, $lo); + &getOrCreateRRs($dom)->addRecord(43, $rdata, $ttl, $ts, $lo); + } elsif (/^#P([^:]*):(\d+):(\d+):(\d+):(\d*):([0-9a-fA-F]*):(\d*):(\d*):([^:]*)$/) { + # C<#Pname:algorithm:flags:iter:len:salt:ttl:timestamp:lo> + my ($dom,$alg,$flag,$iter,$len,$salt,$ttl,$ts,$lo) = ($1, $2, $3, $4, $5, $6, $7, $8, $9); + $dom =~ tr/A-Z/a-z/; + if ($salt eq "") { + if ($len eq "") { $len = 4; } + open(RANDOM, "</dev/urandom") or die("Failed to open /dev/urandom"); + sysread(RANDOM, $salt, $len); + close(RANDOM); + $salt = unpack("H*", $salt); + } else { + $len = length(pack("H*", $salt)); + } + my $rdata = chr($alg).chr($flag).&htons($iter) + .chr($len).pack("H*", $salt); + &makeGenericRecord($dom, 51, $rdata, $ttl, $ts, $lo); + my $rrs = &getOrCreateRRs($dom); + $rrs->addNS3P($alg, $flag, $iter, $salt, $ttl, $ts, $lo); + $rrs->addRecord(51, $rdata, $ttl, $ts, $lo); + } else { + print STDERR "Warning: ignored incomplete pseudo record '$_'!\n"; + } + next; + } + my $type = substr($_, 0, 1); + if ($type !~ /^[.\&=+\@'^CZ:36]/) { + print STDERR "Warning: ignored unknown record type '$type'\n"; + next; + } + my @stuff = split(/:/, substr($_, 1)); + if ($#stuff < 0) { + print STDERR "Warning: ignored empty record '$_'\n"; + next; + } + my $dom = shift @stuff; + $dom =~ tr/A-Z/a-z/; + my $rec = &getOrCreateRRs($dom); + if ($type eq '&') { + # &fqdn:ip:x:ttl:timestamp:lo + my $ns = $stuff[1]; + if ($ns !~ /\./) { $ns .= ".ns.$dom"; } + $rec->addNS($ns, $stuff[2], $stuff[3], $stuff[4]); + &addA($ns, $stuff[0], $stuff[2] || 259200, $stuff[3], $stuff[4]); + } elsif ($type eq '=') { + # =fqdn:ip:ttl:timestamp:lo + $rec->addA($stuff[0], $stuff[1], $stuff[2], $stuff[3]); + &addPTR($stuff[0], $dom, $stuff[1], $stuff[2], $stuff[3]); + } elsif ($type eq '+') { + # +fqdn:ip:ttl:timestamp:lo + $rec->addA($stuff[0], $stuff[1], $stuff[2], $stuff[3]); + } elsif ($type eq '6') { + # =fqdn:ip6:ttl:timestamp:lo + $rec->addAAAA($stuff[0], $stuff[1], $stuff[2], $stuff[3]); + &addPTR($stuff[0], $dom, $stuff[1], $stuff[2], $stuff[3]); + } elsif ($type eq '3') { + # +fqdn:ip6:ttl:timestamp:lo + $rec->addAAAA($stuff[0], $stuff[1], $stuff[2], $stuff[3]); + } elsif ($type eq '@') { + # @fqdn:ip:x:dist:ttl:timestamp:lo + my $mx = $stuff[1]; + if ($mx !~ /\./) { $mx .= ".mx.$dom"; } + $rec->addMX($mx, $stuff[2], $stuff[3], $stuff[4], $stuff[5]); + &addA($mx, $stuff[0], $stuff[3], $stuff[4], $stuff[5]); + } elsif ($type eq "'") { + # 'fqdn:s:ttl:timestamp:lo + $rec->addTXT(&parseData($stuff[0]), $stuff[1], $stuff[2], $stuff[3]); + } elsif ($type eq '^') { + # ^fqdn:p:ttl:timestamp:lo + $rec->addPTR($stuff[0], $stuff[1], $stuff[2], $stuff[3]); + } elsif ($type eq 'C') { + # Cfqdn:p:ttl:timestamp:lo + $rec->addCNAME($stuff[0], $stuff[1], $stuff[2], $stuff[3]); + } elsif ($type eq 'Z') { + # Zfqdn:mname:rname:ser:ref:ret:exp:min:ttl:timestamp:lo + $rec->addSOA($stuff[0], $stuff[1], $stuff[2], $stuff[3], $stuff[4], $stuff[5], $stuff[6], $stuff[7], $stuff[8], $stuff[9]); + } elsif ($type eq ':') { + # :fqdn:n:rdata:ttl:timestamp:lo + $rec->addRecord($stuff[0], &parseData($stuff[1]), $stuff[2], $stuff[3], $stuff[4]); + } +} + +foreach my $rec (values %main::names) { + my $dom = $rec->{name}; + if (exists($rec->{byType}->{48})) { + if (!exists($rec->{byType}->{6})) { + print STDERR "Warning: useless DNSKEY for $dom without SOA!\n"; + } elsif (!exists($rec->{byType}->{51})) { + print STDERR "ERROR: DNSKEY for $dom without NSEC3PARAM!\n"; + exit(1); + } + } elsif (exists($rec->{byType}->{51})) { + print STDERR "Warning: useless NSEC3PARAM for $dom without DNSKEY!\n"; + } + &findControl($rec); +} + +foreach my $zone (@main::zones) { + my $rec = $main::names{$zone}; + if (!exists($rec->{keys})) { + print STDERR "Info: ignore unsigned zone $zone\n"; + foreach my $dom (keys %{$rec->{zone}}) { + delete $main::names{$dom}; + } + next; + } + if (!exists($rec->{nsec3p})) { + next; + } + + # + # Add NSEC3 RRs to zone + my %hashes = (); + my $n3p = $rec->{nsec3p}->[0]; + # Generate hashes + foreach my $name (keys %{$rec->{zone}}) { + my $rr; + LOOP: { do { + $rr = &getOrCreateRRs($name); + if (exists($rr->{hash})) { last; } + $rec->{zone}->{$name} = $rr; + my $hash = &nsec3hash($name, $n3p->{iterations}, $n3p->{salt}); + if (exists($hashes{$hash})) { + print STDERR "ERROR: hash collision on $name!?\n"; + exit(1); + } + $hashes{$hash} = { hash => $hash, name => &base32hex($hash).".".$zone, + generator => $name, zone => $zone }; + $rr->{hash} = $hash; + if ($name eq $zone) { last; } + if ($name =~ /^[^.]*\./) { $name = $'; } + } while ($rr->{name} ne $zone); } + } + # Find next hash in hash sort order + my ($first, $prev); + my @byNibble = (); + my $prevNib = -1; + foreach my $hash (sort keys %hashes) { + my $nib = ord($hash) >> 4; + if (!defined($byNibble[$nib])) { + while ($prevNib < $nib) { + $byNibble[++$prevNib] = defined($prev) ? [$prev->{hash}] : []; + } + } + push @{$byNibble[$nib]}, $hash; + if (!$first) { + $first = $prev = $hashes{$hash}; + next; + } + $prev->{next} = $hash; + $prev = $hashes{$hash}; + } + $prev->{next} = $first->{hash}; + unshift @{$byNibble[0]}, $prev->{hash}; + for (my $nib = 1; $#{$byNibble[$nib]} < 0; $nib++) { + unshift @{$byNibble[$nib]}, $prev->{hash}; + } + for (my $nib = $#byNibble + 1; $nib < 16; $nib++) { + $byNibble[$nib] = [$prev->{hash}]; + } + # Generate records + foreach my $hash (values %hashes) { + my $rRec = &getOrCreateRRs($hash->{name}); + my $gRec = &getOrCreateRRs($hash->{generator}); + $rec->{zone}->{$hash->{name}} = $rRec; + my $rdata = chr($n3p->{alg}).chr($n3p->{flags}) + .&htons($n3p->{iterations}) + .chr(length($n3p->{salt})).$n3p->{salt} + .chr(length($hash->{next})).$hash->{next} + .&genTypeBitmaps(keys %{$gRec->{byType}}); + print "# NSEC3: ".$hash->{name}." - ".&base32hex($hash->{next})." (" + .join(" ", sort keys %{$gRec->{byType}}).")\n"; + $rRec->addRecord(50, $rdata, $n3p->{ttl}, $n3p->{ts}, $n3p->{lo}); + &makeGenericRecord($hash->{name}, 50, $rdata, $n3p->{ttl}, $n3p->{ts}, $n3p->{lo}); + print "# H(".$hash->{generator}.") -> ".$hash->{name}."\n"; + #$gRec->addRecord(65281, &wireName($hash->{name}), $n3p->{ttl}, $n3p->{ts}, $n3p->{lo}); + &makeGenericRecord($hash->{generator}, 65281, &wireName($hash->{name}), $n3p->{ttl}, $n3p->{ts}, $n3p->{lo}); + } + for (my $nib = 0; $nib < 16; $nib++) { + my $name = sprintf("%x", $nib).".$zone"; + my $rec = &getOrCreateRRs($name); + $rec->addRecord(65282, join("", @{$byNibble[$nib]}), $n3p->{ttl}, $n3p->{ts}, $n3p->{lo}); + &makeGenericRecord($name, 65282, join("", @{$byNibble[$nib]}), $n3p->{ttl}, $n3p->{ts}, $n3p->{lo}); + } + + # Add RRSIGs to zone + my (@zsks, @ksks); + if (!$rec->{haveSEP} || !$rec->{haveZSK}) { + @zsks = @ksks = @{$rec->{keys}}; + } else { + @ksks = grep { $_->{flags} & 1 } @{$rec->{keys}}; + @zsks = grep { !($_->{flags} & 1) } @{$rec->{keys}}; + } + my $validFrom = $now - 3600; + my $validUntil = $now + $main::ttl; + foreach my $owner (values %{$rec->{zone}}) { + my $name = $owner->{name}; + my $isCutpoint = exists($owner->{byType}->{2}) && $name ne $zone; + foreach my $type (keys %{$owner->{byType}}) { + if ($isCutpoint && $type != 43 && $type != 50) { next; } + my $labels = $name; + $labels =~ s/^\*\.//; + $labels =~ s/[^.]+//g; + $labels = length($labels) + 1; + my $ttl = $owner->{byType}->{$type}->[0]->{ttl} || 86400; + foreach my $key ($type == 48 ? @ksks : @zsks) { + my $keytag = $key->{key}->{basetag} + $key->{alg} + $key->{flags}; + $keytag = ($keytag + ($keytag >> 16)) & 0xffff; + my $rdata = &htons($type).chr($key->{alg}).chr($labels) + .&htonl($ttl).&htonl($validUntil) + .&htonl($validFrom) + .&htons($keytag).&wireName($zone); + my $toSign = $rdata; + foreach my $rr (sort { $a->{rdata} cmp $b->{rdata} } @{$owner->{byType}->{$type}}) { + $toSign .= &wireName($name).&htons($type)."\0\1".&htonl($ttl) + .&htons(length($rr->{rdata})).$rr->{rdata}; + } + $key->{key}->{key}->use_pkcs1_padding(); + if ($key->{alg} == 7) { + $key->{key}->{key}->use_sha1_hash(); + } elsif ($key->{alg} == 8) { + $key->{key}->{key}->use_sha256_hash(); + } elsif ($key->{alg} == 10) { + $key->{key}->{key}->use_sha512_hash(); + } else { + print STDERR "Unsupported key type ".$key->{alg}."\n"; + exit 1; + } + my $sig = $key->{key}->{key}->sign($toSign); + if (!$sig || !$key->{key}->{key}->verify($toSign, $sig)) { + print STDERR "Failed to sign $name ($type)!?\n"; + exit 1; + } + #$key->{key}->{key}->use_no_padding(); + #print "# ".unpack("H*", $key->{key}->{key}->public_decrypt($sig))."\n"; + $rdata .= $sig; + print "# RRSIG $type ".$key->{alg}." $labels $ttl $validUntil $validFrom " + ."$keytag $name\n"; + &makeGenericRecord($name, 46, $rdata, $ttl, "", ""); + } + } + } +} + +exit(0); + +package Records; + +sub new { + my ($class, $dom) = @_; + $dom =~ tr/A-Z/a-z/; + my $self = { name => $dom, byType => {}, haveSEP => 0, haveZSK => 0, + locs => {}, zone => {} }; + $self->{zone}->{$dom} = $self; + bless $self, $class; + return $self; +} + +sub addKey { +my ($self, $flags, $alg, $key) = @_; + + if (!($flags & 0x100)) { return; } + if (!exists($main::keys{$key})) { + print STDERR "ERROR: encountered DNSKEY pseudo record without a matching key:\n"; + print STDERR "$_\n"; + exit 1; + } + if ($alg != 7 && $alg != 8 && $alg != 10) { + print STDERR "Warning: ignoring DNSKEY with unsupported algorithm $alg\n"; + return; + } + my $entry = { flags => $flags, alg => $alg, pubkey => $key, + key => $main::keys{$key} }; + if (exists($self->{keys})) { + foreach my $other (@{$self->{keys}}) { + if ($other->{flags} == $flags && $other->{alg} == $alg + && $other->{pubkey} eq $key) { + return; + } + } + push @{$self->{keys}}, $entry; + } else { + $self->{keys} = [$entry]; + } + if ($flags & 1) { + $self->{haveSEP} = 1; + } else { + $self->{haveZSK} = 1; + } +} + +sub addNS3P { +my ($self, $alg, $flag, $iter, $salt, $ttl, $ts, $lo) = @_; + + if ($flag ne "0") { + print STDERR "Warning: don't know about NSEC3 flags values != 0, ignoring\n"; + } + if ($iter > 150) { + print STDERR "Warning: large iteration count $iter may lead to problems\n"; + } + if ($alg ne "1") { + print STDERR "ERROR: NSEC3 algorithm $alg unknown. Please use algorithm 1.\n"; + exit 1; + } + + my $entry = { flags => $flag, alg => $alg, iterations => $iter, + salt => pack("H*", $salt), ttl => $ttl, ts => $ts, lo => $lo }; + if (exists($self->{nsec3p})) { + print STDERR "Warning: ignoring additional NSEC3PARAM for ".$self->{name}."\n"; +# foreach my $other (@$self->{nsec3p}) { +# if ($other->{flags} == $flag && $other->{alg} == $alg +# && $other->{iterations} == $iter +# && $other->{salt} eq $entry->{salt}) { +# return; +# } +# } +# push @$self->{nsec3p}, $entry; + } else { + $self->{nsec3p} = [$entry]; + } +} + +sub addRecord { +my ($self, $type, $data, $ttl, $ts, $lo) = @_; + + if (!defined($lo)) { $lo = ""; } + if (!defined($ttl) || $ttl eq "") { $ttl = 86400; } + $self->{locs}->{$lo} = 1; + my $entry = { type => $type, rdata => $data, ttl => $ttl, ts => $ts, lo => $lo }; + if (!exists($self->{byType}->{$type})) { + $self->{byType}->{$type} = [$entry]; + return; + } + foreach my $other (@{$self->{byType}->{$type}}) { + if ($other->{rdata} eq $data + && ($other->{lo} eq $lo || $lo eq "" || $other->{lo} eq "") + && (($other->{ttl} eq "0") != ($ttl eq "0"))) { + print STDERR "Warning: duplicate record ".$self->{name}.":$type:...\n"; + return; + } + if (($other->{lo} eq $lo || $lo eq "" || $other->{lo} eq "") + && (($other->{ttl} eq "0") == ($ttl eq "0")) + && $other->{ttl} ne $ttl) { + print STDERR "Warning: ttl mismatch for ".$self->{name}.":$type:...\n"; + return; + } + } + push @{$self->{byType}->{$type}}, $entry; +} + +sub addA { +my ($self, $ip, $ttl, $ts, $lo) = @_; + + if ($ip !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) { + print STDERR "Warning: ignoring unparsable IPv4 address '$ip'\n"; + return; + } + $self->addRecord(1, pack("C*", $1, $2, $3, $4), $ttl, $ts, $lo); +} + +sub addNS { +my ($self, $ns, $ttl, $ts, $lo) = @_; + + $self->addRecord(2, &toDomain($ns), $ttl || 259200, $ts, $lo); +} + +sub addCNAME { +my ($self, $nm, $ttl, $ts, $lo) = @_; + + $self->addRecord(5, &toDomain($nm), $ttl, $ts, $lo); +} + +sub addSOA { +my ($self, $ns, $hm, $ser, $ref, $ret, $exp, $min, $ttl, $ts, $lo) = @_; + + $self->addRecord(6, &toDomain($ns).&toDomain($hm) + .pack("N*", $ser || 1, $ref || 16384, $ret || 2048, + $exp || 1048576, $min || 2560), + $ttl || 2560, $ts, $lo); +} + +sub addPTR { +my ($self, $nm, $ttl, $ts, $lo) = @_; + + $self->addRecord(12, &toDomain($nm), $ttl, $ts, $lo); +} + +sub addMX { +my ($self, $mx, $dist, $ttl, $ts, $lo) = @_; + + $self->addRecord(15, pack("n", $dist || 0).&toDomain($mx), $ttl, $ts, $lo); +} + +sub addTXT { +my ($self, $txt, $ttl, $ts, $lo) = @_; + + my $cstr = ""; + while ((my $l = length($txt)) > 0) { + if ($l > 255) { $l = 255; } + $cstr .= chr($l).substr($txt, 0, $l); + $txt = substr($txt, $l); + } + $self->addRecord(16, $cstr, $ttl, $ts, $lo); +} + +sub addAAAA { +my ($self, $ip, $ttl, $ts, $lo) = @_; + + if ($ip !~ /^[0-9a-f]{32}$/i) { + print STDERR "Warning: ignoring unparsable IPv6 address '$ip'\n"; + return; + } + $self->addRecord(28, pack("H*", $ip), $ttl, $ts, $lo); +} + +sub toDomain { +my $name = shift; + + $name =~ tr/A-Z/a-z/; + my $res = ""; + while ($name =~ /^([^.]*)\./) { + $name = $'; + $res .= chr(length($1)).$1; + } + return $res.chr(length($name)).$name."\0"; +} + +package main; + +sub usage { + print STDERR "$0 -g <bits> <flags> <algorithm> <domain> <keyfile>\n"; + print STDERR " or\n"; + print STDERR "$0 [-t <ttl>] [<keyfile> ...] <input >output\n"; + exit(1); +} + +sub findControl { +my $rec = shift; + + if (exists($rec->{control})) { return; } + + my $dom = $rec->{name}; + my $soa = exists($rec->{byType}->{6}); + if ($soa) { + $rec->{control} = $dom; + $rec->{zone}->{$dom} = $rec; + push @main::zones, $dom; + return; + } + + my $anc = $dom; + while ($anc =~ /^[^.]*\./) { + $anc = $'; + if ($dom !~ /^\*\./ && exists($main::names{"*.$anc"}) + && !exists($main::names{"*.$dom"})) { + print STDERR "Warning: wildcard *.$anc shadowed by $dom (see RFC-1034 sect. 4.3.3)!\n"; + } + if (exists($main::names{$anc})) { + my $ctl_rec = $main::names{$anc}; + &findControl($ctl_rec); + if (!exists($ctl_rec->{control})) { + if (!$soa) { print STDERR "Warning: Out-of-bailiwick name '$dom' (oob parent)\n"; } + return; + } + my $control = $ctl_rec->{control}; + if ($ctl_rec->{byType}->{2}) { $control = $anc; } + $ctl_rec = $main::names{$control}; + if (!$ctl_rec->{byType}->{6}) { + # Most likely glue... + if (!exists($rec->{byType}->{1}) + && !exists($rec->{byType}->{28})) { + print STDERR "Warning: Out-of-bailiwick name '$dom' (below subdelegation)\n"; + } + } else { + $rec->{control} = $control; + $ctl_rec->{zone}->{$dom} = $rec; + } + return; + } + } + print STDERR "Warning: Out-of-bailiwick name '$dom' (no parent)\n"; +} + +sub parseData { +my $in = shift; + + my $res = ""; + while ($in =~ /^(.*?)\\(\d\d\d)/) { + $in = $'; + $res .= $1.chr(oct($2)); + } + return $res.$in; +} + +sub makeGenericRecord { +my ($dom, $type, $rdata, $ttl, $ts, $lo) = @_; + + print ":$dom:$type:"; + while (length($rdata)) { + my $char = substr($rdata, 0, 1); + $rdata = substr($rdata, 1); + if ($char =~ /[0-9a-zA-Z +*.,\/=<>\@\$-]/) { + print $char; + } else { + printf "\\%03o", ord($char); + } + } + print ":$ttl:$ts:$lo\n"; +} + +sub getOrCreateRRs { +my $dom = shift; + + $dom =~ tr/A-Z/a-z/; + if (!exists($main::names{$dom})) { + $main::names{$dom} = new Records($dom); + } + return $main::names{$dom}; +} + +sub htons { +my $n = shift; + + return chr($n >> 8).chr($n & 0xff); +} + +sub htonl { +my $n = shift; + + return &htons($n >> 16).&htons($n & 0xffff); +} + +sub wireName { +my $name = shift; + + my $wire = ""; + while ($name =~ /^([^.]+)/) { + $wire .= chr(length($1)).$1; + $name = ($name eq $1) ? "" : substr($name, length($1) + 1); + } + return $wire."\0"; +} + +sub nsec3hash { +my ($name, $iter, $salt) = @_; + + my $dig = &wireName($name); + while ($iter-- >= 0) { + $dig = sha1($dig.$salt); + } + return $dig; +} + +sub base32hex { +my $data = shift; + + my $buf = 0; + my $bits = 0; + my $res = ""; + while (length($data) > 0) { + $buf = ($buf << 8) | ord($data); + $data = substr($data, 1); + $bits += 8; + while ($bits >= 5) { + my $dig = ($buf >> ($bits-5)) & 0x1f; + $bits -= 5; + if ($dig < 10) { + $res .= $dig; + } else { + $res .= chr($dig + 87); + } + } + } + if ($bits > 0) { + $buf <<= (5 - $bits); + $buf &= 0x1f; + if ($buf < 10) { + $res .= $buf; + } else { + $res .= chr($buf + 87); + } + $bits += 3; + while ($bits > 0) { + if ($bits < 5) { $bits += 8; } + else { $res .= "="; $bits -= 5; } + } + } + return $res; +} + +sub tai2unix { +my $ts = shift; + + $ts =~ s/^40*//; + return "0x$ts" - 10; +} + +sub genTypeBitmaps { + my %windows = (); + if ($#_ > 0 || $#_ == 0 && $_[0] != 2) { + # The type bitmaps includes all types except those contributed by NSEC3 + # itself, including the signature for the NSEC3. I. e. if there's at + # least one record here (except for a single NS delegation), there'll + # also be an RRSIG here, eventually. + push @_, 46; + @_ = sort @_; + } + foreach my $type (@_) { + my $window = $type >> 8; + $type &= 0xff; + if (exists($windows{$window})) { + push @{$windows{$window}}, $type; + } else { + $windows{$window} = [$type]; + } + } + my $tbm = ""; + foreach my $window (sort keys %windows) { + my $wbm = "\0" x 32; + foreach my $type (@{$windows{$window}}) { + substr($wbm, $type >> 3, 1) = chr(ord(substr($wbm, $type >> 3, 1)) | 1 << (7 - ($type & 7))); + } + $wbm =~ s/\0+$//; + $tbm .= chr($window).chr(length($wbm)).$wbm; + } + return $tbm; +} + +sub gen_pubkey_data { +my ($n, $e, $flags, $alg, $dom) = @_; + + my $e_bin = $e->to_bin(); + $e_bin =~ s/^\0+//; + my $n_bin = $n->to_bin(); + $n_bin =~ s/^\0+//; + + my $pubkey = chr(length($e_bin)).$e_bin.$n_bin; + my $keytag = $flags + $alg + 3 * 256; # protocol is always 3 + for (my $i = length($pubkey) - 1; $i >= 0; $i--) { + $keytag += ord(substr($pubkey, $i)) * (($i & 1) ? 1 : 256); + } + if ($alg > 0) { + $keytag += $keytag >> 16; + $keytag &= 0xffff; + } + $dom =~ tr/A-Z/a-z/; + my $digest = sha1_hex(&wireName($dom).&htons($flags).chr(3).chr($alg).$pubkey); + return ($keytag, $pubkey, $digest); +} + +sub addA { +my ($dom, $ip, $ttl, $ts, $lo) = @_; + + if ($ip eq "") { return; } + my $rec = &getOrCreateRRs($dom); + $rec->addA($ip, $ttl, $ts, $lo); +} + +sub addPTR { +my ($ip, $dom, $ttl, $ts, $lo) = @_; + + my $arpa; + if ($ip =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) { + $arpa = "$4.$3.$2.$1.in-addr.arpa"; + } elsif ($ip =~ /^[0-9a-f]{32}$/i) { + $ip =~ tr/A-Z/a-z/; + $arpa = "ip6.arpa"; + while ($ip =~ /^./) { + $ip = $'; + $arpa = "$&.$arpa"; + } + } else { + print STDERR "Warning: ignoring unparsable IP address '$ip'\n"; + return; + } + my $rec = getOrCreateRRs($arpa); + $rec->addPTR($dom, $ttl, $ts, $lo); +} + +sub addKey { +my ($file) = @_; + + open(KEYFILE, "<$file") or die("Can't read $file either:"); + my $rsa = Crypt::OpenSSL::RSA->new_private_key(join("", <KEYFILE>)); + close KEYFILE; + if (!$rsa) { + print STDERR "Failed to read key from $file!\n"; + exit(1); + } + my ($n, $e, $x1, $x2, $x3, $x4, $x5, $x6) = $rsa->get_key_parameters(); + $x1 = $x2 = $x3 = $x4 = $x5 = $x6 = 0; # get rid of private stuff + my ($keytag, $keydata, $fp) = &gen_pubkey_data($n, $e, 0, 0, ""); + $main::keys{$keydata} = { key => $rsa, basetag => $keytag }; +} + +sub genkey { +my ($bits, $flags, $alg, $dom, $file) = @_; + + if ($bits < 1024 || $bits > 4096) { + print STDERR "ERROR: Keys of less than 1024 or more than 4096 bits are not supported!\n"; + exit 1; + } + + if ($alg != 7 && $alg != 8 && $alg != 10) { + print STDERR "ERROR: $0 only supports algorithms 7 (RSA-SHA1), 8 (RSA-SHA256)\nand 10 (RSA-SHA512).\n"; + exit 1; + } + + if (sysopen(KEYFILE, $file, O_CREAT|O_EXCL|O_WRONLY, 0600)) { + my $rsa = Crypt::OpenSSL::RSA->generate_key($bits); + print KEYFILE $rsa->get_private_key_string(); + my ($n, $e, $x1, $x2, $x3, $x4, $x5, $x6) = $rsa->get_key_parameters(); + $x1 = $x2 = $x3 = $x4 = $x5 = $x6 = 0; # get rid of private stuff + my ($keytag, $keydata, $fp) = &gen_pubkey_data($n, $e, $flags, $alg, $dom); + print KEYFILE "#K$dom:$flags:3:$alg:".encode_base64($keydata, "").":::\n"; + print KEYFILE "#D$dom:$keytag:$alg:1:${fp}:::\n"; + close KEYFILE; + } else { + print STDERR "Warning: couldn't create $file: $!\n"; + print STDERR "Attempting to read key...\n"; + open(KEYFILE, "<$file") or die("Can't read $file either:"); + my $rsa = Crypt::OpenSSL::RSA->new_private_key(join("", <KEYFILE>)); + close KEYFILE; + if (!$rsa) { + print STDERR "Failed to read key from $file!\n"; + exit(1); + } + my ($n, $e, $x1, $x2, $x3, $x4, $x5, $x6) = $rsa->get_key_parameters(); + $x1 = $x2 = $x3 = $x4 = $x5 = $x6 = 0; # get rid of private stuff + my ($keytag, $keydata, $fp) = &gen_pubkey_data($n, $e, $flags, $alg, $dom); + print "#K$dom:$flags:3:$alg:".encode_base64($keydata, "").":::\n"; + print "#D$dom:$keytag:$alg:1:${fp}:::\n"; + } + exit 0; +} + +=pod + +=head1 NAME + +tinydns-sign - Signs records in L<tinydns-data(8)> files + +=head1 SYNOPSIS + + tinydns-sign -g bits flags algorithm domain keyfile + + tinydns-sign [-t ttl] [keyfile ...] <infile >outfile + +=head1 DESCRIPTION + +The first form is used to generate a public/private RSA key pair with a +modulus of length I<bits>. If F<keyfile> exists, tinydns-sign will try to +read a private key from the file and print DS and DNSKEY pseudo-records for +the corresponding public key on stdout. If F<keyfile> does not exist, +tinydns-sign will generate a new key pair and write the key plus the +corresponding pseudo-records to F<keyfile>. + +In the second form, tinydns-sign reads key pairs from each given F<keyfile>. +It then reads a L<tinydns-data(8)> file from STDIN and writes the same +file to STDOUT, with the following modifications: + +=over + +=item * It will delete all generic records with RRTYPE DS (43), RRSIG (46), +DNSKEY (48), NSEC3(50), NSEC3PARAM(51) and private types 65281 and 65282. + +=item * It will turn each . record into a Z record and a & record. + +=item * It will adjust the serial number of all Z records to the current time, +unless the serial number begins with two zeroes. Note that an SOA must have a +fixed serial for generating a matching RRSIG record. + +=item * It will create new DS, DNSKEY and NSEC3PARAM records from each +corresponding pseudo record (see below) present in the file. + +=item * It will create NSEC3 records for all names in all zones that have at +least one DNSKEY and NSEC3PARAM in the file. + +=item * It will create a generic record with type 65281 for each name +(including empty non-terminals) containing the owner of its matching NSEC3 RR. + +=item * It will create generic records with type 65282 for each hex digit (i. +e. 0-9a-f) below the zone apex containing all NSEC3 hashes starting with that +digit. + +=item * It will create RRSIG records for all RR-sets in all zones that have at +least one DNSKEY in the file. If both DNSKEYS with and without the SEP flag set +are present, then those with the SEP flag will be used only for RRSIGs on +DNSKEY RRs and those without the SEP flag will be used for the remaining +RR-sets. Otherwise, RRSIGs will be created using all DNSKEYs. + +RRSIGs will be valid beginning one hour in the past and ending at (now + I<ttl>) +seconds. I<ttl> defaults to 432000 (5 days). + +=back + +=head2 Pseudo-Records + +Pseudo-records are records defined in a syntax that's only understood by +tinydns-sign. To L<tinydns-data(8)> they look like comments, i. e. they are +ignored. + +tinydns-sign will create one or more generic records for each pseudo-record. +All generic records with an RR-type for which a pseudo-record can be defined +are deleted from the input. (Otherwise, removing a pseudo-record would not +result in removal of the corresponding generic record.) + +In contrast to standard tinydns-data behaviour, trailing colons in +pseudo-records are B<not> optional. + +Currently, pseudo-records are defined for the following RR-types: + +=over + +=item * #Kname:flags:proto:algorithm:key:ttl:timestamp:lo + +This generates a DNSKEY record for I<name>. I<flags>. I<proto> and I<algorithm> +are decimal numbers. At the time of writing, I<proto> must be 3. tinydns-sign +only supports I<algorithm>s 7 (RSA-SHA1), 8 (RSA-SHA256) and 10 (RSA-SHA512). +I<key> is base-64 encoded key material, depending on the selected +I<algorithm>. I<ttl>, I<timestamp> and I<lo> are as usual. + +It is an error to have a DNSKEY pseudo-record in the input without a +corresponding F<keyfile> containing the matching private key. + +=item * #Dname:tag:algorithm:digest:fingerprint:ttl:timestamp:lo + +This generates a DS record for I<name>. I<tag> is the key tag, I<algorithm> +specifies the algorithm of the referenced key and I<digest> is the digest type +(all in decimal). I<fingerprint> is the hex-encoded actual digest value +(omitting leading/trailing zeroes is not permitted!). I<ttl>, I<timestamp> and +I<lo> are as usual. + +=item * #Pname:algorithm:flags:iter:len:salt:ttl:timestamp:lo + +This generates an NSEC3PARAM record for I<name> with the given I<algorithm>, +I<flags>, I<iter>ation count, salt I<len>gth and I<salt>. If I<salt> is empty, +a new random salt with the given salt I<len>gth (4 bytes if I<len> is empty) +will be generated. If I<salt> is non-empty, it must be a string of hex digits +with even length. The salt length is derived from the given salt value, i. e. +I<len> is ignored in that case. I<ttl>, I<timestamp> and I<lo> are as usual. + +tinydns-sign currently only supports I<algorithm> 1 (SHA-1). At the time of +writing, I<flags> is defined to be 0, and the I<iter>ation count is limited +depending on the key length (see L<RFC-5155>). + +=back + +=head1 EXIT STATUS + +tinydns-sign will exit with status 0 if it thinks all went well. Warning +messages will not trigger a nonzero exit status. + +tinydns-sign will exit with nonzero status if an error occurred. In this case, +the output is most likely incomplete and should not be used to replace an +input file. + +=head1 SEE ALSO + +L<tinydns-data(8)>, +L<RFC-4034|http://tools.ietf.org/html/rfc4034>, +L<RFC-4035|http://tools.ietf.org/html/rfc4035>, +L<RFC-5155|http://tools.ietf.org/html/rfc5155> + +=head1 LIMITATIONS + +=over + +=item * Location code handling is incomplete in that location codes must be +present for all RRs in a zone, or for none at all. + +=item * Timestamps are currently mostly ignored, i. e. signatures will happily +outlive the RR-sets which they sign. + +=item * It is currently not possible to protect the private keys with a +passphrase. + +=item * It is not possible to have a signed zone and a signed child zone in +the same data file. + +=item * NSEC3 RRs with Opt-Out child zones are not supported. + +=item * The pseudo-RRs with type 65282 contain a list of hash values. The list +cannot grow bigger than 65kBytes (about 3270 hashes). This is not a problem +for a typical domain, but it would be a problem if tinydns were to serve the +.de zone, for example. Also, the list is searched sequentially, which can +cause a performance impact long before this limit is reached. + +=back + +=head1 CAVEATS + +=over + +=item * The system clock should be reasonably close to UTC (i. e. within a few minutes). + +=item * Stock tinydns/axfrdns will happily work with signed data.cdb files, +but they will not produce correct DNSSEC responses! + +=item * If a zone contains both keys with and without the SEP flag, you must +make sure that both key sets cover the same set of algorithms. This is due to +a requirement in RFC-4035 section 2.2. + +=back + +=head1 AUTHOR + +(C) 2012 Peter Conrad L<mailto: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/>. + +=cut + |