--- /dev/null
+### -*-makefile-*-
+
+BASE = distorted.org.uk
+ZONE = dnserr.$(BASE)
+
+KEYGEN = dnssec-keygen -aRSASHA256 -b1024 -Kkey/
+SIGNZONE = dnssec-signzone -S -Kkey/ -dds/
+SIGVALID = -s20000101000000 -e20500101000000
+SIGOLD = -s20000101000000 -e20010101000000
+
+all:
+
+DUMMY = refused wrong-ds
+DUMMYZONES = $(addsuffix .zone,$(DUMMY))
+TARGETS += $(DUMMYZONES)
+$(DUMMYZONES): %.zone: utils.m4 dummy.in
+ m4 -P -DBASE=$(BASE) >$@.new utils.m4 dummy.in
+ mv $@.new $@
+
+TARGETS += dnserr.zone
+dnserr.zone: utils.m4 config.m4 dnserr.in
+ m4 -P -DBASE=$(BASE) >$@.new utils.m4 dnserr.in
+ mv $@.new $@
+
+KEYSTAMP = $(patsubst %,key/%.stamp, \
+ $(ZONE) \
+ $(addsuffix .$(ZONE),$(DUMMY)))
+$(KEYSTAMP): key/%.stamp:
+ mkdir -p key
+ $(KEYGEN) -fKSK $*
+ $(KEYGEN) $*
+ touch $@
+all: $(KEYSTAMP)
+realclean::; rm -rf key/
+
+DUMMYSIG = $(addsuffix .zone.sig,$(DUMMY))
+TARGETS += $(DUMMYSIG)
+$(DUMMYSIG): %.zone.sig: %.zone
+wrong-ds.zone.sig: wrong-ds.zone key/wrong-ds.$(ZONE).stamp
+ mkdir -p ds/
+ $(SIGNZONE) $(SIGVALID) -owrong-ds.$(ZONE) -f$@ $<
+clean::; rm -rf ds/
+
+TARGETS += dnserr.zone.signew
+dnserr.zone.signew: dnserr.zone key/$(ZONE).stamp
+ $(SIGNZONE) $(SIGVALID) -o$(ZONE) -f$@.bind $<
+ ldns-read-zone $@.bind >$@.new
+ rm $@.bind
+ mv $@.new $@
+
+TARGETS += dnserr.zone.sigold
+dnserr.zone.sigold: dnserr.zone key/$(ZONE).stamp
+ $(SIGNZONE) $(SIGOLD) -P -o$(ZONE) -f$@.bind $<
+ ldns-read-zone $@.bind >$@.new
+ rm $@.bind
+ mv $@.new $@
+
+TARGETS += dnserr.zone.sig
+OLDSIGMATCH = $$1 == "expired-rrsig.$(ZONE)." && \
+ $$4 == "RRSIG" && $$5 == "A"
+BADSIGMATCH = $$1 == "invalid-rrsig.$(ZONE)." && \
+ $$4 == "RRSIG" && $$5 == "A"
+CLEAN += t.oldsig
+dnserr.zone.sig: dnserr.zone.sigold dnserr.zone.signew
+ awk '$(OLDSIGMATCH) { print; }' \
+ dnserr.zone.sigold >t.oldsig
+ awk '$(OLDSIGMATCH) { system("cat t.oldsig"); next; } \
+ { gsub(/invalid-rrsigx/, "invalid-rrsig"); print; }' \
+ dnserr.zone.signew >$@.new
+ mv $@.new $@
+
+CLEAN += $(TARGETS)
+all: $(TARGETS)
+.PHONY: all
+
+clean::; rm -f $(CLEAN)
+realclean:: clean; rm -f $(REALCLEAN)
+.PHONY: clean realclean
--- /dev/null
+### -*-m4-*-
+###
+### Configuration for `distorted.org.uk'.
+
+m4_define([MASTER], [radius.BASE])
+m4_define([NAMESERVERS], [
+ [ns0, 62.49.204.146],
+ [ns1, 62.49.204.150]])
--- /dev/null
+;;; -*-dns-*-
+;;;
+;;; A zone filled with interestingly wrong things.
+
+$TTL 14400
+
+;;;--------------------------------------------------------------------------
+;;; Standard zone scaffolding.
+
+@ IN SOA MASTER. (
+ CONTACT.
+ 2012033109 ;serial
+ 86400 ;refresh
+ 3600 ;retry
+ 1209600 ;expire
+ 14400 ) ;min-ttl
+
+SUBZONE([@])
+
+;;;--------------------------------------------------------------------------
+;;; Some wrong things.
+
+;; Some perfectly sensible records.
+a IN A 127.0.0.1
+mx IN MX 69 a
+_http._tcp.srv IN SRV 69 0 80 a
+
+;; Various stupid indirection games.
+cname IN CNAME a
+cname-2 IN CNAME cname
+cname-3 IN CNAME cname-2
+cname-mx IN CNAME mx
+mx-cname IN MX 69 cname
+cname-srv IN CNAME srv
+srv-cname IN SRV 69 0 80 cname
+
+;; I promise never to define RRs for this name.
+;nxdomain IN ANY
+
+;; A CNAME which doesn't point to anything.
+dangling-cname IN CNAME nxdomain
+
+;; A CNAME which points to itself.
+loop IN CNAME loop
+
+;; I promise never to define A or AAAA records for this name.
+no-address IN TXT "This name has no address records."
+
+;; A name -- in fact, an entire DNS subtree -- for which no authoritative
+;; server will ever return a answer. The address is
+;; blackhole.distorted.org.uk, which drops all packets.
+ns.blackhole IN A BLACKHOLE
+blackhole IN NS ns.blackhole
+ IN DS 18693 8 1 f2ade1384e3cf158372ba16aa3a934a16104066d
+ IN DS 18693 8 2 061929cdc2de9ba7728d4e011f796d0abb54c4a5e4681469d5f1d32d78e142f0
+
+;; A subtree for which authoritative servers will always answer REFUSED.
+;; Recursive resolvers tend to turn this into SERVFAIL.
+SUBZONE([refused])
+ IN DS 63860 8 1 612896152445f6f9134ba5c85a98dd62f527ec4a
+ IN DS 63860 8 2 afb31601378c19d394997f7ee2f5c59f47d1ceb4d181a559053d680f1836b31e
+
+;; A subzone delegated to a server which doesn't think it's
+;; authoritative.
+SUBZONE([lame])
+ IN DS 54525 8 1 d6b4f044da02963de9d60180871b94975a001f55
+ IN DS 54525 8 2 88ab5ce80505eceba195de90e93d53fecf388aff292694f80c4ee24ab77796b9
+
+;; I want some way of reliably provoking a SERVFAIL response from the
+;; server, but I can't think of one right now.
+;servfail IN ???
+
+;;;--------------------------------------------------------------------------
+;;; DNSsec wrongness.
+
+;; An RRset whose DNSsec signature has expired.
+expired-rrsig IN A 127.0.0.1
+; IN RRSIG ?
+
+;; An RRset whose signature is incorrect.
+invalid-rrsigx IN A 127.0.0.1
+; IN RRSIG ?
+
+;; A delegation with an incorrect DS record.
+SUBZONE([wrong-ds])
+wrong-ds IN DS 8224 8 1 c12019d5604e3e4b0e0efb7c62c00021b5943e95
+wrong-ds IN DS 8224 8 2 1541dfc4f64f26f5685a27bd0bdaac1ecb24b36f49e2d573d62646185978b78b
+
+
+;;;----- That's all, folks --------------------------------------------------
--- /dev/null
+;;; -*-dns-*-
+;;;
+;;; An empty zone which might be useful for something.
+
+$TTL 14400
+
+@ IN SOA MASTER. (
+ CONTACT.
+ 2012033100 ;serial
+ 86400 ;refresh
+ 3600 ;retry
+ 1209600 ;expire
+ 14400 ) ;min-ttl
+
+SUBZONE([@])
+
+ ;; A dummy address record just for form's sake.
+@ IN A 127.0.0.1
--- /dev/null
+m4_divert(-1) ### -*-m4-*-
+###
+### Definitions for generating zone files.
+
+m4_changequote([, ])
+
+###--------------------------------------------------------------------------
+### Utilities.
+
+## FOREACH(what, list)
+##
+## The LIST is a comma-separated list of things, like an m4 argument list.
+## For each item in the list, expand WHAT as if it's the body of a macro with
+## the list item as its arguments. In other words, the list item itself can
+## be a list of comma-separated items, which are available as $1, $2, ...,
+## within WHAT.
+m4_define([_FOREACH], [m4_dnl
+m4_ifelse([$#], [1], [_foreach_func($1)],
+ [_foreach_func($1)[]_FOREACH(m4_shift($@))])])
+m4_define([FOREACH], [m4_dnl
+m4_pushdef([_foreach_func], [$1])m4_dnl
+_FOREACH($2)[]m4_dnl
+m4_popdef([_foreach_func])])
+
+## SUBZONE(name)
+##
+## Delegate NAME to the NAMESERVERS.
+m4_define([SUBZONE], [m4_dnl
+FOREACH([m4_dnl
+m4_ifelse($1,@,$][1,$][1.$1) IN A $][2
+], [NAMESERVERS])
+FOREACH([m4_dnl
+$1 IN NS m4_ifelse($1,@,$][1,$][1.$1)
+], [NAMESERVERS])])
+
+###--------------------------------------------------------------------------
+### Configuration.
+
+m4_define([CONTACT], [hostmaster.BASE])
+m4_define([BLACKHOLE], [212.13.198.78])
+m4_include([config.m4])
+
+###----- That's all, folks --------------------------------------------------
+m4_divert(0)m4_dnl