diff --git a/CHANGES b/CHANGES index aa9fc86af4..77c1bf6de2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +3252. [bug] When master zones using inline-signing were + updated while the server was offline, the source + zone could fall out of sync with the signed + copy. They can now resynchronize. [RT #26676] + 3251. [bug] Enforce a upper bound (65535 bytes) on the amount of memory dns_sdlz_putrr() can allocate per record to prevent run away memory consumption on ISC_R_NOSPACE. diff --git a/bin/check/check-tool.c b/bin/check/check-tool.c index 3b5e9b117a..445c0cc029 100644 --- a/bin/check/check-tool.c +++ b/bin/check/check-tool.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: check-tool.c,v 1.43 2011/12/09 23:47:02 tbox Exp $ */ +/* $Id: check-tool.c,v 1.44 2011/12/22 07:32:39 each Exp $ */ /*! \file */ @@ -661,7 +661,6 @@ dump_zone(const char *zonename, dns_zone_t *zone, const char *filename, result = dns_zone_dumptostream3(zone, output, fileformat, style, rawversion); - if (output != stdout) (void)isc_stdio_close(output); diff --git a/bin/check/named-checkzone.c b/bin/check/named-checkzone.c index 073cd49302..c5ababdd47 100644 --- a/bin/check/named-checkzone.c +++ b/bin/check/named-checkzone.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: named-checkzone.c,v 1.63 2011/12/09 23:47:02 tbox Exp $ */ +/* $Id: named-checkzone.c,v 1.64 2011/12/22 07:32:39 each Exp $ */ /*! \file */ @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -112,8 +113,11 @@ main(int argc, char **argv) { const char *outputformatstr = NULL; dns_masterformat_t inputformat = dns_masterformat_text; dns_masterformat_t outputformat = dns_masterformat_text; - isc_uint32_t rawversion = 1; + dns_masterrawheader_t header; + isc_uint32_t rawversion = 1, serialnum = 0; + isc_boolean_t snset = ISC_FALSE; FILE *errout = stdout; + char *endp; outputstyle = &dns_master_style_full; @@ -157,7 +161,7 @@ main(int argc, char **argv) { isc_commandline_errprint = ISC_FALSE; while ((c = isc_commandline_parse(argc, argv, - "c:df:hi:jk:m:n:qr:s:t:o:vw:DF:M:S:W:")) + "c:df:hi:jk:L:m:n:qr:s:t:o:vw:DF:M:S:W:")) != EOF) { switch (c) { case 'c': @@ -235,6 +239,17 @@ main(int argc, char **argv) { } break; + case 'L': + snset = ISC_TRUE; + endp = NULL; + serialnum = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fprintf(stderr, "source serial number " + "must be numeric"); + exit(1); + } + break; + case 'n': if (ARGCMP("ignore")) { zone_options &= ~(DNS_ZONEOPT_CHECKNS| @@ -477,6 +492,13 @@ main(int argc, char **argv) { result = load_zone(mctx, origin, filename, inputformat, classname, &zone); + if (snset) { + dns_master_initrawheader(&header); + header.flags = DNS_MASTERRAW_SOURCESERIALSET; + header.sourceserial = serialnum; + dns_zone_setrawdata(zone, &header); + } + if (result == ISC_R_SUCCESS && dumpzone) { if (!quiet && progmode == progmode_compile) { fprintf(errout, "dump zone to %s...", output_filename); diff --git a/bin/check/named-checkzone.docbook b/bin/check/named-checkzone.docbook index 22101997b0..85479e7d90 100644 --- a/bin/check/named-checkzone.docbook +++ b/bin/check/named-checkzone.docbook @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + June 13, 2000 @@ -71,6 +71,7 @@ + @@ -96,6 +97,7 @@ + @@ -280,6 +282,17 @@ + + -L serial + + + When compiling a zone to 'raw' format, set the "source serial" + value in the header to the specified serial number. (This is + expected to be used primarily for testing purposes.) + + + + -m mode diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index c8b2abfa58..8335195ddb 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -29,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-signzone.c,v 1.284 2011/12/08 23:45:02 marka Exp $ */ +/* $Id: dnssec-signzone.c,v 1.285 2011/12/22 07:32:39 each Exp $ */ /*! \file */ @@ -139,7 +139,8 @@ static char *tempfile = NULL; static const dns_master_style_t *masterstyle; static dns_masterformat_t inputformat = dns_masterformat_text; static dns_masterformat_t outputformat = dns_masterformat_text; -static unsigned int rawversion = 1; +static isc_uint32_t rawversion = 1, serialnum = 0; +static isc_boolean_t snset = ISC_FALSE; static unsigned int nsigned = 0, nretained = 0, ndropped = 0; static unsigned int nverified = 0, nverifyfailed = 0; static const char *directory = NULL, *dsdir = NULL; @@ -3470,7 +3471,7 @@ main(int argc, char *argv[]) { isc_boolean_t set_iter = ISC_FALSE; #define CMDLINE_FLAGS \ - "3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:l:m:n:N:o:O:PpRr:s:ST:tuUv:X:xz" + "3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:L:l:m:n:N:o:O:PpRr:s:ST:tuUv:X:xz" /* * Process memory debugging argument first. @@ -3620,6 +3621,17 @@ main(int argc, char *argv[]) { dskeyfile[ndskeys++] = isc_commandline_argument; break; + case 'L': + snset = ISC_TRUE; + endp = NULL; + serialnum = strtol(isc_commandline_argument, &endp, 0); + if (*endp != '\0') { + fprintf(stderr, "source serial number " + "must be numeric"); + exit(1); + } + break; + case 'l': len = strlen(isc_commandline_argument); isc_buffer_init(&b, isc_commandline_argument, len); @@ -4077,6 +4089,10 @@ main(int argc, char *argv[]) { dns_master_initrawheader(&header); if (rawversion == 0U) header.flags = DNS_MASTERRAW_COMPAT; + else if (snset) { + header.flags = DNS_MASTERRAW_SOURCESERIALSET; + header.sourceserial = serialnum; + } result = dns_master_dumptostream3(mctx, gdb, gversion, masterstyle, outputformat, &header, fp); diff --git a/bin/dnssec/dnssec-signzone.docbook b/bin/dnssec/dnssec-signzone.docbook index 2517d199bc..e427fc1266 100644 --- a/bin/dnssec/dnssec-signzone.docbook +++ b/bin/dnssec/dnssec-signzone.docbook @@ -18,7 +18,7 @@ - PERFORMANCE OF THIS SOFTWARE. --> - + June 05, 2009 @@ -69,6 +69,7 @@ + @@ -371,6 +372,17 @@ + + -L serial + + + When writing a signed zone to 'raw' format, set the "source serial" + value in the header to the specified serial number. (This is + expected to be used primarily for testing purposes.) + + + + -n ncpus diff --git a/bin/named/update.c b/bin/named/update.c index d83fcbae35..bfffc73bcc 100644 --- a/bin/named/update.c +++ b/bin/named/update.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: update.c,v 1.198 2011/10/28 06:20:04 each Exp $ */ +/* $Id: update.c,v 1.199 2011/12/22 07:32:40 each Exp $ */ #include @@ -3095,7 +3095,7 @@ update_action(isc_task_t *task, isc_event_t *event) { journal = NULL; result = dns_journal_open(mctx, journalfile, - ISC_TRUE, &journal); + DNS_JOURNAL_CREATE, &journal); if (result != ISC_R_SUCCESS) FAILS(result, "journal open failed"); diff --git a/bin/named/xfrout.c b/bin/named/xfrout.c index 43eec8e899..70b7830541 100644 --- a/bin/named/xfrout.c +++ b/bin/named/xfrout.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: xfrout.c,v 1.143 2011/12/01 00:53:58 marka Exp $ */ +/* $Id: xfrout.c,v 1.144 2011/12/22 07:32:40 each Exp $ */ #include @@ -252,7 +252,7 @@ ixfr_rrstream_create(isc_mem_t *mctx, s->journal = NULL; CHECK(dns_journal_open(mctx, journal_filename, - ISC_FALSE, &s->journal)); + DNS_JOURNAL_READ, &s->journal)); CHECK(dns_journal_iter_init(s->journal, begin_serial, end_serial)); *sp = (rrstream_t *) s; diff --git a/bin/tests/system/inline/clean.sh b/bin/tests/system/inline/clean.sh index 12ccefcea8..8fefba08b6 100644 --- a/bin/tests/system/inline/clean.sh +++ b/bin/tests/system/inline/clean.sh @@ -12,13 +12,14 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: clean.sh,v 1.7 2011/12/02 02:44:01 marka Exp $ +# $Id: clean.sh,v 1.8 2011/12/22 07:32:40 each Exp $ rm -f */named.memstats rm -f */named.run rm -f */trusted.conf rm -f ns1/K* rm -f ns1/dsset-* +rm -f ns3/dsset-* rm -f ns1/root.db rm -f ns1/root.db.signed rm -f ns2/bits.db @@ -40,6 +41,10 @@ rm -f ns3/dynamic.db rm -f ns3/dynamic.db.jnl rm -f ns3/dynamic.db.signed rm -f ns3/dynamic.db.signed.jnl +rm -f ns3/updated.db +rm -f ns3/updated.db.jnl +rm -f ns3/updated.db.signed +rm -f ns3/updated.db.signed.jnl rm -f ns4/K* rm -f ns4/noixfr.db rm -f ns4/noixfr.db.jnl diff --git a/bin/tests/system/inline/ns1/root.db.in b/bin/tests/system/inline/ns1/root.db.in index b3e756dd7c..8f4cb6d536 100644 --- a/bin/tests/system/inline/ns1/root.db.in +++ b/bin/tests/system/inline/ns1/root.db.in @@ -12,7 +12,7 @@ ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ; PERFORMANCE OF THIS SOFTWARE. -; $Id: root.db.in,v 1.4 2011/10/26 20:56:45 marka Exp $ +; $Id: root.db.in,v 1.5 2011/12/22 07:32:40 each Exp $ $TTL 300 . IN SOA gson.nominum.com. a.root.servers.nil. ( @@ -38,3 +38,6 @@ ns3.master. A 10.53.0.3 dynamic. NS ns3.dynamic. ns3.dynamic. A 10.53.0.3 + +updated. NS ns3.updated. +ns3.updated. A 10.53.0.3 diff --git a/bin/tests/system/inline/ns1/sign.sh b/bin/tests/system/inline/ns1/sign.sh index 3f25d618af..b2688ea2b8 100644 --- a/bin/tests/system/inline/ns1/sign.sh +++ b/bin/tests/system/inline/ns1/sign.sh @@ -14,7 +14,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: sign.sh,v 1.2 2011/10/25 01:54:20 marka Exp $ +# $Id: sign.sh,v 1.3 2011/12/22 07:32:40 each Exp $ SYSTEMTESTTOP=../.. . $SYSTEMTESTTOP/conf.sh @@ -26,7 +26,7 @@ rm -f K.+*+*.key rm -f K.+*+*.private keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone` keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone -f KSK $zone` -$SIGNER -S -x -T 1200 -o ${zone} root.db +$SIGNER -S -x -T 1200 -o ${zone} root.db > /dev/null 2>&1 cat ${keyname}.key | grep -v '^; ' | $PERL -n -e ' local ($dn, $class, $type, $flags, $proto, $alg, @rest) = split; diff --git a/bin/tests/system/inline/ns3/named.conf b/bin/tests/system/inline/ns3/named.conf index 1c9483bb7c..970fe1683a 100644 --- a/bin/tests/system/inline/ns3/named.conf +++ b/bin/tests/system/inline/ns3/named.conf @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: named.conf,v 1.4 2011/10/26 20:56:45 marka Exp $ */ +/* $Id: named.conf,v 1.5 2011/12/22 07:32:40 each Exp $ */ // NS3 @@ -70,3 +70,11 @@ zone "dynamic" { allow-update { any; }; file "dynamic.db"; }; + +zone "updated" { + type master; + inline-signing yes; + auto-dnssec maintain; + allow-update { none; }; + file "updated.db"; +}; diff --git a/bin/tests/system/inline/ns3/sign.sh b/bin/tests/system/inline/ns3/sign.sh index 913e64bd5f..3a58fd8f5d 100644 --- a/bin/tests/system/inline/ns3/sign.sh +++ b/bin/tests/system/inline/ns3/sign.sh @@ -14,7 +14,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: sign.sh,v 1.4 2011/10/26 20:56:45 marka Exp $ +# $Id: sign.sh,v 1.5 2011/12/22 07:32:40 each Exp $ SYSTEMTESTTOP=../.. . $SYSTEMTESTTOP/conf.sh @@ -48,3 +48,12 @@ rm -f K${zone}.+*+*.private keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone` keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone -f KSK $zone` $DSFROMKEY -T 1200 $keyname >> ../ns1/root.db + +zone=updated +rm -f K${zone}.+*+*.key +rm -f K${zone}.+*+*.private +keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone` +keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone -f KSK $zone` +$DSFROMKEY -T 1200 $keyname >> ../ns1/root.db +$SIGNER -S -O raw -L 2000042407 -o ${zone} ${zone}.db > /dev/null 2>&1 +cp master2.db.in updated.db diff --git a/bin/tests/system/inline/setup.sh b/bin/tests/system/inline/setup.sh index dd0a19a0c9..d7bb722f0f 100644 --- a/bin/tests/system/inline/setup.sh +++ b/bin/tests/system/inline/setup.sh @@ -12,7 +12,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: setup.sh,v 1.7 2011/12/09 22:09:25 marka Exp $ +# $Id: setup.sh,v 1.8 2011/12/22 07:32:40 each Exp $ sh clean.sh @@ -45,6 +45,7 @@ rm -f ns3/dynamic.db.signed.jnl cp ns3/master.db.in ns3/master.db cp ns3/master.db.in ns3/dynamic.db +cp ns3/master.db.in ns3/updated.db touch ns4/trusted.conf cp ns4/noixfr.db.in ns4/noixfr.db diff --git a/bin/tests/system/inline/tests.sh b/bin/tests/system/inline/tests.sh index 836e9d0a2a..015c208d60 100644 --- a/bin/tests/system/inline/tests.sh +++ b/bin/tests/system/inline/tests.sh @@ -14,7 +14,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: tests.sh,v 1.10 2011/12/19 23:46:13 marka Exp $ +# $Id: tests.sh,v 1.11 2011/12/22 07:32:40 each Exp $ SYSTEMTESTTOP=.. . $SYSTEMTESTTOP/conf.sh @@ -353,6 +353,27 @@ do done if [ $ret != 0 ]; then echo "I:failed"; fi +n=`expr $n + 1` +echo "I:checking master zone that was updated while offline is correct ($n)" +ret=0 +serial=`$DIG $DIGOPTS +short @10.53.0.3 -p 5300 updated SOA | awk '{print $3}'` +# serial should have changed +[ "$serial" = "2000042407" ] && ret=1 +# e.updated should exist and should be signed +$DIG $DIGOPTS @10.53.0.3 -p 5300 e.updated A > dig.out.ns3.test$n +grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1 +grep "ANSWER: 2," dig.out.ns3.test$n > /dev/null || ret=1 +# updated.db.signed.jnl should exist, should have the source serial +# of master2.db, and should show a minimal diff: no more than 8 added +# records (SOA/RRSIG, 2 x NSEC/RRSIG, A/RRSIG), and 4 removed records +# (SOA/RRSIG, NSEC/RRSIG). +serial=`$JOURNALPRINT ns3/updated.db.signed.jnl | head -1 | awk '{print $4}'` +[ "$serial" = "2000042408" ] || ret=1 +diffsize=`$JOURNALPRINT ns3/updated.db.signed.jnl | wc -l` +[ "$diffsize" -le 13 ] || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + n=`expr $n + 1` echo "I:checking adding of record to unsigned master using UPDATE ($n)" ret=0 diff --git a/bin/tests/system/masterformat/clean.sh b/bin/tests/system/masterformat/clean.sh index be50b22189..5c2f13d939 100755 --- a/bin/tests/system/masterformat/clean.sh +++ b/bin/tests/system/masterformat/clean.sh @@ -14,11 +14,12 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: clean.sh,v 1.9 2011/12/08 16:07:20 each Exp $ +# $Id: clean.sh,v 1.10 2011/12/22 07:32:40 each Exp $ rm -f named-compilezone rm -f ns1/example.db.raw* rm -f ns1/example.db.compat +rm -f ns1/example.db.serial.raw rm -f ns2/example.db rm -f dig.out.* rm -f */named.memstats diff --git a/bin/tests/system/masterformat/ns1/compile.sh b/bin/tests/system/masterformat/ns1/compile.sh index 0edffec091..e778997b21 100755 --- a/bin/tests/system/masterformat/ns1/compile.sh +++ b/bin/tests/system/masterformat/ns1/compile.sh @@ -12,7 +12,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: compile.sh,v 1.8 2011/12/09 23:47:03 tbox Exp $ +# $Id: compile.sh,v 1.9 2011/12/22 07:32:40 each Exp $ ../named-compilezone -D -F raw -o example.db.raw example \ example.db > /dev/null 2>&1 @@ -20,3 +20,5 @@ example.db > /dev/null 2>&1 ../named-compilezone -D -F raw=0 -o example.db.compat example-compat \ example.db > /dev/null 2>&1 +../named-compilezone -D -F raw -L 3333 -o example.db.serial.raw example \ + example.db > /dev/null 2>&1 diff --git a/bin/tests/system/masterformat/tests.sh b/bin/tests/system/masterformat/tests.sh index 74678ecc5b..7066714d5c 100755 --- a/bin/tests/system/masterformat/tests.sh +++ b/bin/tests/system/masterformat/tests.sh @@ -14,7 +14,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -# $Id: tests.sh,v 1.8 2011/12/08 16:07:20 each Exp $ +# $Id: tests.sh,v 1.9 2011/12/22 07:32:40 each Exp $ SYSTEMTESTTOP=.. . $SYSTEMTESTTOP/conf.sh @@ -28,11 +28,24 @@ israw () { rawversion () { perl -e '$input = ; - if (length($input) < 2) { print "not raw\n"; exit 0; }; + if (length($input) < 8) { print "not raw\n"; exit 0; }; ($style, $version) = unpack("NN", $input); print ($style == 2 ? "$version\n" : "not raw\n");' < $1 } +sourceserial () { + perl -e '$input = ; + if (length($input) < 20) { print "UNSET\n"; exit; }; + ($format, $version, $dumptime, $flags, $sourceserial) = + unpack("NNNNN", $input); + if ($format != 2 || $version < 1) { print "UNSET\n"; exit; }; + if ($flags & 02) { + print $sourceserial . "\n"; + } else { + print "UNSET\n"; + }' < $1 +} + DIGOPTS="+tcp +noauth +noadd +nosea +nostat +noquest +nocomm +nocmd" status=0 @@ -62,6 +75,13 @@ israw ns1/example.db.compat || ret=1 [ $ret -eq 0 ] || echo "I:failed" status=`expr $status + $ret` +echo "I:checking source serial numbers" +ret=0 +[ "`sourceserial ns1/example.db.raw`" = "UNSET" ] || ret=1 +[ "`sourceserial ns1/example.db.serial.raw`" = "3333" ] || ret=1 +[ $ret -eq 0 ] || echo "I:failed" +status=`expr $status + $ret` + echo "I:waiting for transfers to complete" sleep 1 diff --git a/lib/dns/include/dns/journal.h b/lib/dns/include/dns/journal.h index b615589de4..68ba8b35ae 100644 --- a/lib/dns/include/dns/journal.h +++ b/lib/dns/include/dns/journal.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: journal.h,v 1.42 2011/12/05 23:46:35 tbox Exp $ */ +/* $Id: journal.h,v 1.43 2011/12/22 07:32:41 each Exp $ */ #ifndef DNS_JOURNAL_H #define DNS_JOURNAL_H 1 @@ -106,7 +106,7 @@ dns_journal_open(isc_mem_t *mctx, const char *filename, unsigned int mode, * * DNS_JOURNAL_CREATE open the journal for reading and writing and create * the journal if it does not exist. - * DNS_JOURNAL_WRITE open the journal for readinge and writing. + * DNS_JOURNAL_WRITE open the journal for reading and writing. * DNS_JOURNAL_READ open the journal for reading only. */ @@ -293,12 +293,15 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial, * exists and is non-empty 'serial' must exist in the journal. */ -isc_uint32_t -dns_journal_get_sourceserial(dns_journal_t *j); +isc_boolean_t +dns_journal_get_sourceserial(dns_journal_t *j, isc_uint32_t *sourceserial); void dns_journal_set_sourceserial(dns_journal_t *j, isc_uint32_t sourceserial); /*%< * Get and set source serial. + * + * Returns: + * ISC_TRUE if sourceserial has previously been set. */ ISC_LANG_ENDDECLS diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 9f8ed39e56..e5d1d92a12 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.h,v 1.198 2011/12/08 16:07:21 each Exp $ */ +/* $Id: zone.h,v 1.199 2011/12/22 07:32:41 each Exp $ */ #ifndef DNS_ZONE_H #define DNS_ZONE_H 1 @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -2029,6 +2030,13 @@ dns_zone_setnsec3param(dns_zone_t *zone, isc_uint8_t hash, isc_uint8_t flags, * Requires: * \li 'zone' to be valid. */ + +void +dns_zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header); +/*% + * Set the data to be included in the header when the zone is dumped in + * binary format. + */ ISC_LANG_ENDDECLS #endif /* DNS_ZONE_H */ diff --git a/lib/dns/journal.c b/lib/dns/journal.c index a6a40aab82..f8f1a9794c 100644 --- a/lib/dns/journal.c +++ b/lib/dns/journal.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: journal.c,v 1.119 2011/12/05 23:46:35 tbox Exp $ */ +/* $Id: journal.c,v 1.120 2011/12/22 07:32:41 each Exp $ */ #include @@ -111,6 +111,8 @@ static isc_boolean_t bind8_compat = ISC_TRUE; /* XXX config */ if (result != ISC_R_SUCCESS) goto failure; \ } while (0) +#define JOURNAL_SERIALSET 0x01U + static isc_result_t index_to_disk(dns_journal_t *); static inline isc_uint32_t @@ -215,6 +217,7 @@ typedef union { unsigned char index_size[4]; /*% Source serial number. */ unsigned char sourceserial[4]; + unsigned char flags; } h; /* Pad the header to a fixed size. */ unsigned char pad[JOURNAL_HEADER_SIZE]; @@ -255,6 +258,7 @@ typedef struct { journal_pos_t end; isc_uint32_t index_size; isc_uint32_t sourceserial; + isc_boolean_t serialset; } journal_header_t; /*% @@ -287,7 +291,7 @@ typedef struct { */ static journal_header_t -initial_journal_header = { ";BIND LOG V9\n", { 0, 0 }, { 0, 0 }, 0, 0 }; +initial_journal_header = { ";BIND LOG V9\n", { 0, 0 }, { 0, 0 }, 0, 0, 0 }; #define JOURNAL_EMPTY(h) ((h)->begin.offset == (h)->end.offset) @@ -358,10 +362,13 @@ journal_header_decode(journal_rawheader_t *raw, journal_header_t *cooked) { journal_pos_decode(&raw->h.end, &cooked->end); cooked->index_size = decode_uint32(raw->h.index_size); cooked->sourceserial = decode_uint32(raw->h.sourceserial); + cooked->serialset = ISC_TF(raw->h.flags & JOURNAL_SERIALSET); } static void journal_header_encode(journal_header_t *cooked, journal_rawheader_t *raw) { + unsigned char flags = 0; + INSIST(sizeof(cooked->format) == sizeof(raw->h.format)); memset(raw->pad, 0, sizeof(raw->pad)); memcpy(raw->h.format, cooked->format, sizeof(raw->h.format)); @@ -369,6 +376,9 @@ journal_header_encode(journal_header_t *cooked, journal_rawheader_t *raw) { journal_pos_encode(&raw->h.end, &cooked->end); encode_uint32(cooked->index_size, raw->h.index_size); encode_uint32(cooked->sourceserial, raw->h.sourceserial); + if (cooked->serialset) + flags |= JOURNAL_SERIALSET; + raw->h.flags = flags; } /* @@ -546,7 +556,8 @@ journal_file_create(isc_mem_t *mctx, const char *filename) { static isc_result_t journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, - isc_boolean_t create, dns_journal_t **journalp) { + isc_boolean_t create, dns_journal_t **journalp) +{ FILE *fp = NULL; isc_result_t result; journal_rawheader_t rawheader; @@ -674,7 +685,8 @@ journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, isc_result_t dns_journal_open(isc_mem_t *mctx, const char *filename, unsigned int mode, - dns_journal_t **journalp) { + dns_journal_t **journalp) +{ isc_result_t result; int namelen; char backup[1024]; @@ -1164,10 +1176,8 @@ dns_journal_commit(dns_journal_t *j) { /* * Update the journal header. */ - if (JOURNAL_EMPTY(&j->header)) { + if (JOURNAL_EMPTY(&j->header)) j->header.begin = j->x.pos[0]; - j->header.sourceserial = j->header.begin.serial; - } j->header.end = j->x.pos[1]; journal_header_encode(&j->header, &rawheader); CHECK(journal_seek(j, 0)); @@ -1399,7 +1409,7 @@ dns_journal_rollforward2(isc_mem_t *mctx, dns_db_t *db, unsigned int options, REQUIRE(filename != NULL); j = NULL; - result = dns_journal_open(mctx, filename, ISC_FALSE, &j); + result = dns_journal_open(mctx, filename, DNS_JOURNAL_READ, &j); if (result == ISC_R_NOTFOUND) { isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no journal file, but that's OK"); @@ -1432,7 +1442,7 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) { REQUIRE(filename != NULL); j = NULL; - result = dns_journal_open(mctx, filename, ISC_FALSE, &j); + result = dns_journal_open(mctx, filename, DNS_JOURNAL_READ, &j); if (result == ISC_R_NOTFOUND) { isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no journal file"); return (DNS_R_NOJOURNAL); @@ -1445,7 +1455,8 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) { return (result); } - fprintf(file, "Source serial = %u\n", j->header.sourceserial); + if (j->header.serialset) + fprintf(file, "Source serial = %u\n", j->header.sourceserial); dns_diff_init(j->mctx, &diff); /* @@ -1546,13 +1557,19 @@ dns_journal_set_sourceserial(dns_journal_t *j, isc_uint32_t sourceserial) { j->state == JOURNAL_STATE_TRANSACTION); j->header.sourceserial = sourceserial; + j->header.serialset = ISC_TRUE; if (j->state == JOURNAL_STATE_WRITE) j->state = JOURNAL_STATE_INLINE; } -isc_uint32_t -dns_journal_get_sourceserial(dns_journal_t *j) { - return (j->header.sourceserial); +isc_boolean_t +dns_journal_get_sourceserial(dns_journal_t *j, isc_uint32_t *sourceserial) { + REQUIRE(sourceserial != NULL); + + if (!j->header.serialset) + return (ISC_FALSE); + *sourceserial = j->header.sourceserial; + return (ISC_TRUE); } /**************************************************************************/ @@ -2043,8 +2060,8 @@ dns_db_diffx(dns_diff_t *diff, dns_db_t *dba, dns_dbversion_t *dbvera, dns_journal_t *journal = NULL; if (filename != NULL) { - result = dns_journal_open(diff->mctx, filename, ISC_TRUE, - &journal); + result = dns_journal_open(diff->mctx, filename, + DNS_JOURNAL_CREATE, &journal); if (result != ISC_R_SUCCESS) return (result); } @@ -2213,6 +2230,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial, new->header.end.serial = j->header.end.serial; new->header.end.offset = indexend + copy_length; new->header.sourceserial = j->header.sourceserial; + new->header.serialset = j->header.serialset; /* * Update the journal header. diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c index ad11414c4c..b53e720e98 100644 --- a/lib/dns/xfrin.c +++ b/lib/dns/xfrin.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: xfrin.c,v 1.171 2011/08/30 05:16:14 marka Exp $ */ +/* $Id: xfrin.c,v 1.172 2011/12/22 07:32:41 each Exp $ */ /*! \file */ @@ -360,7 +360,7 @@ ixfr_init(dns_xfrin_ctx_t *xfr) { journalfile = dns_zone_getjournal(xfr->zone); if (journalfile != NULL) CHECK(dns_journal_open(xfr->mctx, journalfile, - ISC_TRUE, &xfr->ixfr.journal)); + DNS_JOURNAL_CREATE, &xfr->ixfr.journal)); result = ISC_R_SUCCESS; failure: diff --git a/lib/dns/zone.c b/lib/dns/zone.c index bf4d3f50c8..132d494610 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: zone.c,v 1.657 2011/12/20 00:26:52 marka Exp $ */ +/* $Id: zone.c,v 1.658 2011/12/22 07:32:41 each Exp $ */ /*! \file */ @@ -364,8 +364,8 @@ struct dns_zone { dns_zone_t *raw; dns_zone_t *secure; - isc_boolean_t rawserialset; - isc_uint32_t rawserial; + isc_boolean_t sourceserialset; + isc_uint32_t sourceserial; }; #define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0)) @@ -655,6 +655,7 @@ static void zone_name_tostr(dns_zone_t *zone, char *buf, size_t length); static void zone_rdclass_tostr(dns_zone_t *zone, char *buf, size_t length); static void zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length); static isc_result_t zone_send_secureserial(dns_zone_t *zone, + isc_boolean_t locked, isc_uint32_t serial); #if 0 @@ -712,7 +713,8 @@ static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver, static void zone_rekey(dns_zone_t *zone); static isc_boolean_t delsig_ok(dns_rdata_rrsig_t *rrsig_ptr, dst_key_t **keys, unsigned int nkeys); -static isc_result_t zone_send_securedb(dns_zone_t *zone, dns_db_t *db); +static isc_result_t zone_send_securedb(dns_zone_t *zone, isc_boolean_t locked, + dns_db_t *db); #define ENTER zone_debuglog(zone, me, 1, "enter") @@ -899,8 +901,8 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) { ISC_LIST_INIT(zone->forwards); zone->raw = NULL; zone->secure = NULL; - zone->rawserial = 0; - zone->rawserialset = ISC_FALSE; + zone->sourceserial = 0; + zone->sourceserialset = ISC_FALSE; zone->magic = ZONE_MAGIC; @@ -1038,6 +1040,28 @@ zone_free(dns_zone_t *zone) { isc_mem_detach(&mctx); } +/* + * Returns ISC_TRUE iff this the signed side of an inline-signing zone + */ +static inline isc_boolean_t +inline_secure(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + if (zone->raw != NULL) + return (ISC_TRUE); + return (ISC_FALSE); +} + +/* + * Returns ISC_TRUE iff this the unsigned side of an inline-signing zone + */ +static inline isc_boolean_t +inline_raw(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + if (zone->secure != NULL) + return (ISC_TRUE); + return (ISC_FALSE); +} + /* * Single shot. */ @@ -1066,7 +1090,7 @@ dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) { zone_rdclass_tostr(zone, namebuf, sizeof namebuf); zone->strrdclass = isc_mem_strdup(zone->mctx, namebuf); - if (zone->raw != NULL) + if (inline_secure(zone)) dns_zone_setclass(zone->raw, rdclass); UNLOCK_ZONE(zone); } @@ -1259,7 +1283,7 @@ dns_zone_setview(dns_zone_t *zone, dns_view_t *view) { zone_viewname_tostr(zone, namebuf, sizeof namebuf); zone->strviewname = isc_mem_strdup(zone->mctx, namebuf); - if (zone->raw != NULL) + if (inline_secure(zone)) dns_zone_setview(zone->raw, view); UNLOCK_ZONE(zone); @@ -1298,7 +1322,7 @@ dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin) { zone_name_tostr(zone, namebuf, sizeof namebuf); zone->strname = isc_mem_strdup(zone->mctx, namebuf); - if (result == ISC_R_SUCCESS && zone->raw != NULL) + if (result == ISC_R_SUCCESS && inline_secure(zone)) result = dns_zone_setorigin(zone->raw, origin); UNLOCK_ZONE(zone); return (result); @@ -1470,7 +1494,7 @@ zone_load(dns_zone_t *zone, unsigned int flags) { LOCK_ZONE(zone); TIME_NOW(&now); - if (zone->raw != NULL) { + if (inline_secure(zone)) { result = zone_load(zone->raw, flags); if (result != ISC_R_SUCCESS) goto cleanup; @@ -1723,7 +1747,11 @@ isc_result_t dns_zone_loadandthaw(dns_zone_t *zone) { isc_result_t result; - result = zone_load(zone, DNS_ZONELOADFLAG_THAW); + if (inline_raw(zone)) + result = zone_load(zone->secure, DNS_ZONELOADFLAG_THAW); + else + result = zone_load(zone, DNS_ZONELOADFLAG_THAW); + switch (result) { case DNS_R_CONTINUE: /* Deferred thaw. */ @@ -1846,7 +1874,7 @@ zone_gotwritehandle(isc_task_t *task, isc_event_t *event) { ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); dns_db_currentversion(zone->db, &version); dns_master_initrawheader(&rawdata); - if (zone->raw != NULL) + if (inline_secure(zone)) get_raw_serial(zone->raw, &rawdata); result = dns_master_dumpinc3(zone->mctx, zone->db, version, &dns_master_style_default, @@ -1864,24 +1892,28 @@ zone_gotwritehandle(isc_task_t *task, isc_event_t *event) { dump_done(zone, result); } +/* + * Save the raw serial number for inline-signing zones. + * (XXX: Other information from the header will be used + * for other purposes in the future, but for now this is + * all we're interested in.) + */ static void zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header) { + if ((header->flags & DNS_MASTERRAW_SOURCESERIALSET) == 0) + return; + + zone->sourceserial = header->sourceserial; + zone->sourceserialset = ISC_TRUE; +} + +void +dns_zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header) { if (zone == NULL) return; - /* - * Save the raw serial number for inline-signing zones. - * (XXX: Other information from the header will be used - * for other purposes in the future, but for now this is - * all we're interested in.) - */ - if (zone->raw != NULL || - ((header->flags & DNS_MASTERRAW_SOURCESERIALSET) == 0)) - return; - LOCK_ZONE(zone); - zone->rawserial = header->sourceserial; - zone->rawserialset = ISC_TRUE; + zone_setrawdata(zone, header); UNLOCK_ZONE(zone); } @@ -3289,30 +3321,32 @@ zone_journal(dns_zone_t *zone, dns_diff_t *diff, isc_uint32_t *sourceserial, const char *journalfile; isc_result_t result = ISC_R_SUCCESS; dns_journal_t *journal = NULL; + unsigned int mode = DNS_JOURNAL_CREATE|DNS_JOURNAL_WRITE; ENTER; journalfile = dns_zone_getjournal(zone); if (journalfile != NULL) { - result = dns_journal_open(zone->mctx, journalfile, - DNS_JOURNAL_CREATE, &journal); + result = dns_journal_open(zone->mctx, journalfile, mode, + &journal); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "%s:dns_journal_open -> %s\n", caller, dns_result_totext(result)); return (result); } + if (sourceserial != NULL) dns_journal_set_sourceserial(journal, *sourceserial); result = dns_journal_write_transaction(journal, diff); - dns_journal_destroy(&journal); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "%s:dns_journal_write_transaction -> %s\n", caller, dns_result_totext(result)); - return (result); } + dns_journal_destroy(&journal); } + return (result); } @@ -3515,12 +3549,34 @@ sync_keyzone(dns_zone_t *zone, dns_db_t *db) { } static void -maybe_send_securedb(dns_zone_t *zone) { +maybe_send_secure(dns_zone_t *zone) { + isc_result_t result; + + /* + * We've finished loading, or else failed to load, an inline-signing + * 'secure' zone. We now need information about the status of the + * 'raw' zone. If we failed to load, then we need it to send a + * copy of its database; if we succeeded, we need it to send its + * serial number so that we can sync with it. If it has not yet + * loaded, we set a flag so that it will send the necessary + * information when it has finished loading. + */ LOCK_ZONE(zone->raw); - if (zone->raw->db != NULL) - zone_send_securedb(zone->raw, zone->raw->db); - else + if (zone->raw->db != NULL) { + if (zone->db != NULL) { + isc_uint32_t serial; + result = zone_get_from_db(zone->raw, zone->raw->db, + NULL, NULL, &serial, NULL, + NULL, NULL, NULL, NULL); + if (result == ISC_R_SUCCESS) + zone_send_secureserial(zone->raw, ISC_TRUE, + serial); + } else + zone_send_securedb(zone->raw, ISC_TRUE, zone->raw->db); + + } else DNS_ZONE_SETFLAG(zone->raw, DNS_ZONEFLG_SENDSECURE); + UNLOCK_ZONE(zone->raw); } @@ -3538,6 +3594,9 @@ zone_unchanged(dns_db_t *db1, dns_db_t *db2, isc_mem_t *mctx) { return (answer); } +/* + * The zone is presumed to be locked. + */ static isc_result_t zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, isc_result_t result) @@ -3574,10 +3633,11 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, zone->masterfile, dns_result_totext(result)); } else if (zone->type == dns_zone_master && - zone->raw != NULL && result == ISC_R_FILENOTFOUND) { + inline_secure(zone) && result == ISC_R_FILENOTFOUND) + { dns_zone_log(zone, ISC_LOG_DEBUG(1), "no master file, requesting db"); - maybe_send_securedb(zone); + maybe_send_secure(zone); } else { int level = ISC_LOG_ERROR; if (zone->type == dns_zone_key && @@ -3677,7 +3737,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, dns_journal_t *journal = NULL; result = dns_journal_open(zone->mctx, zone->journal, - ISC_FALSE, &journal); + DNS_JOURNAL_READ, &journal); if (result == ISC_R_SUCCESS) { jserial = dns_journal_last_serial(journal); dns_journal_destroy(&journal); @@ -3843,6 +3903,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, &zone->expiretime) >= 0) zone->refreshtime = now; } + break; case dns_zone_key: @@ -3895,10 +3956,23 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY); if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SENDSECURE) && - zone->secure != NULL) - zone_send_securedb(zone, db); + inline_raw(zone)) + { + if (zone->secure->db == NULL) + zone_send_securedb(zone, ISC_FALSE, db); + else + zone_send_secureserial(zone, ISC_FALSE, serial); + } } + /* + * Finished loading inline-signing zone; need to get status + * from the raw side now. + */ + if (zone->type == dns_zone_master && inline_secure(zone)) + maybe_send_secure(zone); + + result = ISC_R_SUCCESS; if (needdump) { @@ -8491,7 +8565,7 @@ dns_zone_markdirty(dns_zone_t *zone) { LOCK_ZONE(zone); if (zone->type == dns_zone_master) { - if (zone->secure != NULL) { + if (inline_raw(zone)) { ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); if (zone->db != NULL) { result = zone_get_from_db(zone, zone->db, NULL, @@ -8502,7 +8576,7 @@ dns_zone_markdirty(dns_zone_t *zone) { result = DNS_R_NOTLOADED; ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); if (result == ISC_R_SUCCESS) - zone_send_secureserial(zone, serial); + zone_send_secureserial(zone, ISC_FALSE, serial); } set_resigntime(zone); /* XXXMPA make separate call back */ } @@ -8694,8 +8768,9 @@ dump_done(void *arg, isc_result_t result) { * If there is a secure version of this zone * use its serial if it is less than ours. */ - if (tresult == ISC_R_SUCCESS && - zone->secure != NULL && zone->secure->db != NULL) { + if (tresult == ISC_R_SUCCESS && inline_raw(zone) && + zone->secure->db != NULL) + { isc_uint32_t sserial; isc_result_t mresult; @@ -8816,7 +8891,7 @@ zone_dump(dns_zone_t *zone, isc_boolean_t compact) { dns_masterrawheader_t rawdata; dns_db_currentversion(db, &version); dns_master_initrawheader(&rawdata); - if (zone->raw != NULL) + if (inline_secure(zone)) get_raw_serial(zone->raw, &rawdata); result = dns_master_dump3(zone->mctx, db, version, &dns_master_style_default, @@ -8880,8 +8955,12 @@ dumptostream(dns_zone_t *zone, FILE *fd, const dns_master_style_t *style, dns_master_initrawheader(&rawdata); if (rawversion == 0) rawdata.flags |= DNS_MASTERRAW_COMPAT; - if (zone->raw != NULL && rawversion > 0) + else if (inline_secure(zone)) get_raw_serial(zone->raw, &rawdata); + else if (zone->sourceserialset) { + rawdata.flags = DNS_MASTERRAW_SOURCESERIALSET; + rawdata.sourceserial = zone->sourceserial; + } result = dns_master_dumptostream3(zone->mctx, db, version, style, format, &rawdata, fd); dns_db_closeversion(db, &version, ISC_FALSE); @@ -10984,11 +11063,11 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) { */ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SHUTDOWN); free_needed = exit_check(zone); - if (zone->raw != NULL) { + if (inline_secure(zone)) { raw = zone->raw; zone->raw = NULL; } - if (zone->secure != NULL) { + if (inline_raw(zone)) { secure = zone->secure; zone->secure = NULL; } @@ -11360,7 +11439,7 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, * Notify messages are processed by the raw zone. */ LOCK_ZONE(zone); - if (zone->raw != NULL) { + if (inline_secure(zone)) { result = dns_zone_notifyreceive(zone->raw, from, msg); UNLOCK_ZONE(zone); return (result); @@ -11771,9 +11850,9 @@ zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length) { isc_buffer_putstr(&buffer, "/"); isc_buffer_putstr(&buffer, zone->view->name); } - if (zone->raw != NULL && 9U < isc_buffer_availablelength(&buffer)) + if (inline_secure(zone) && 9U < isc_buffer_availablelength(&buffer)) isc_buffer_putstr(&buffer, " (signed)"); - if (zone->secure != NULL && 11U < isc_buffer_availablelength(&buffer)) + if (inline_raw(zone) && 11U < isc_buffer_availablelength(&buffer)) isc_buffer_putstr(&buffer, " (unsigned)"); buf[isc_buffer_usedlength(&buffer)] = '\0'; @@ -12092,8 +12171,9 @@ notify_done(isc_task_t *task, isc_event_t *event) { dns_message_destroy(&message); } -struct secure_serial { +struct secure_event { isc_event_t e; + dns_db_t *db; isc_uint32_t serial; }; @@ -12103,89 +12183,55 @@ update_log_cb(void *arg, dns_zone_t *zone, int level, const char *message) { dns_zone_log(zone, level, "%s", message); } -static void -receive_secure_serial(isc_task_t *task, isc_event_t *event) { - isc_result_t result; - dns_journal_t *rjournal = NULL, *sjournal = NULL; - isc_uint32_t start, end; - dns_zone_t *zone; - int n_soa = 0; - dns_db_t *db = NULL; - dns_dbnode_t *node = NULL; - dns_dbversion_t *newver = NULL, *oldver = NULL; - isc_uint32_t oldserial, newserial; +static isc_result_t +sync_secure_journal(dns_zone_t *zone, dns_journal_t *journal, + isc_uint32_t start, isc_uint32_t end, + dns_difftuple_t **soatuplep, dns_diff_t *diff) +{ + isc_result_t result; + dns_difftuple_t *tuple = NULL; dns_diffop_t op = DNS_DIFFOP_ADD; - dns_diff_t diff; - dns_difftuple_t *tuple = NULL, *soatuple = NULL; - dns_update_log_t log = { update_log_cb, NULL }; - isc_time_t timenow; + int n_soa = 0; - zone = event->ev_arg; - end = ((struct secure_serial *)event)->serial; + REQUIRE(soatuplep != NULL); - dns_diff_init(zone->mctx, &diff); + if (start == end) + return (DNS_R_UNCHANGED); - UNUSED(task); - CHECK(dns_journal_open(zone->raw->mctx, zone->raw->journal, - DNS_JOURNAL_WRITE, &rjournal)); - result = dns_journal_open(zone->raw->mctx, zone->journal, - DNS_JOURNAL_READ, &sjournal); - if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) - goto failure; - - start = dns_journal_get_sourceserial(rjournal); - if (sjournal != NULL) { - isc_uint32_t serial = dns_journal_get_sourceserial(sjournal); - /* - * We write the secure journal first so if that exists - * use its value provided it is greater that from the - * raw journal. - */ - if (isc_serial_gt(serial, start)) - start = serial; - dns_journal_destroy(&sjournal); - } - - if (start == end) - goto failure; - CHECK(dns_journal_iter_init(rjournal, start, end)); - - dns_db_attach(zone->db, &db); - dns_db_currentversion(db, &oldver); - CHECK(dns_db_newversion(db, &newver)); - - for (result = dns_journal_first_rr(rjournal); - result == ISC_R_SUCCESS; - result = dns_journal_next_rr(rjournal)) { - dns_name_t *name = NULL; - isc_uint32_t ttl; - dns_rdata_t *rdata = NULL; - dns_journal_current_rr(rjournal, &name, &ttl, &rdata); - - if (rdata->type == dns_rdatatype_soa) { - n_soa++; - if (n_soa == 2) { - /* - * Save the lastest raw SOA record. - */ - if (soatuple != NULL) - dns_difftuple_free(&soatuple); - CHECK(dns_difftuple_create(diff.mctx, - DNS_DIFFOP_ADD, - name, ttl, rdata, - &soatuple)); - } - if (n_soa == 3) - n_soa = 1; + CHECK(dns_journal_iter_init(journal, start, end)); + for (result = dns_journal_first_rr(journal); + result == ISC_R_SUCCESS; + result = dns_journal_next_rr(journal)) + { + dns_name_t *name = NULL; + isc_uint32_t ttl; + dns_rdata_t *rdata = NULL; + dns_journal_current_rr(journal, &name, &ttl, &rdata); + + if (rdata->type == dns_rdatatype_soa) { + n_soa++; + if (n_soa == 2) { + /* + * Save the latest raw SOA record. + */ + if (*soatuplep != NULL) + dns_difftuple_free(soatuplep); + CHECK(dns_difftuple_create(diff->mctx, + DNS_DIFFOP_ADD, + name, ttl, rdata, + soatuplep)); + } + if (n_soa == 3) + n_soa = 1; continue; } - /* Sanity. */ + /* Sanity. */ if (n_soa == 0) { dns_zone_log(zone->raw, ISC_LOG_ERROR, "corrupt journal file: '%s'\n", zone->raw->journal); - goto failure; + return (ISC_R_FAILURE); } if (zone->privatetype != 0 && @@ -12201,18 +12247,149 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) { op = (n_soa == 1) ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD; - CHECK(dns_difftuple_create(diff.mctx, op, name, ttl, rdata, + CHECK(dns_difftuple_create(diff->mctx, op, name, ttl, rdata, &tuple)); - dns_diff_appendminimal(&diff, &tuple); + dns_diff_appendminimal(diff, &tuple); + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + + failure: + return(result); +} + +static isc_result_t +sync_secure_db(dns_zone_t *seczone, dns_db_t *secdb, + dns_dbversion_t *secver, dns_diff_t *diff) +{ + isc_result_t result; + dns_db_t *rawdb = NULL; + dns_dbversion_t *rawver = NULL; + dns_difftuple_t *tuple = NULL, *next; + + REQUIRE(DNS_ZONE_VALID(seczone)); + REQUIRE(inline_secure(seczone)); + + if (!seczone->sourceserialset) + return (DNS_R_UNCHANGED); + + dns_db_attach(seczone->raw->db, &rawdb); + dns_db_currentversion(rawdb, &rawver); + result = dns_db_diffx(diff, rawdb, rawver, secdb, secver, NULL); + dns_db_closeversion(rawdb, &rawver, ISC_FALSE); + dns_db_detach(&rawdb); + + if (result != ISC_R_SUCCESS) + return (result); + + for (tuple = ISC_LIST_HEAD(diff->tuples); + tuple != NULL; + tuple = next) + { + next = ISC_LIST_NEXT(tuple, link); + if (tuple->rdata.type == dns_rdatatype_nsec || + tuple->rdata.type == dns_rdatatype_rrsig || + tuple->rdata.type == dns_rdatatype_dnskey || + tuple->rdata.type == dns_rdatatype_nsec3 || + tuple->rdata.type == dns_rdatatype_soa || + tuple->rdata.type == dns_rdatatype_nsec3param) + { + ISC_LIST_UNLINK(diff->tuples, tuple, link); + dns_difftuple_free(&tuple); + } + } + + if (ISC_LIST_EMPTY(diff->tuples)) + return (DNS_R_UNCHANGED); + + return (ISC_R_SUCCESS); +} + +static void +receive_secure_serial(isc_task_t *task, isc_event_t *event) { + isc_result_t result; + dns_journal_t *rjournal = NULL; + isc_uint32_t start, end; + dns_zone_t *zone; + dns_db_t *db = NULL; + dns_dbnode_t *node = NULL; + dns_dbversion_t *newver = NULL, *oldver = NULL; + dns_diff_t diff; + dns_difftuple_t *tuple = NULL, *soatuple = NULL; + dns_update_log_t log = { update_log_cb, NULL }; + isc_time_t timenow; + + zone = event->ev_arg; + end = ((struct secure_event *)event)->serial; + isc_event_free(&event); + + REQUIRE(inline_secure(zone)); + + dns_diff_init(zone->mctx, &diff); + + UNUSED(task); + + /* + * We first attempt to sync the raw zone to the secure zone + * by using the raw zone's journal, applying all the deltas + * from the latest source-serial of the secure zone up to + * the current serial number of the raw zone. + * + * If that fails, then we'll fall back to a direct comparison + * between raw and secure zones. + */ + result = dns_journal_open(zone->raw->mctx, zone->raw->journal, + DNS_JOURNAL_WRITE, &rjournal); + if (result != ISC_R_SUCCESS) + goto failure; + else { + dns_journal_t *sjournal = NULL; + + result = dns_journal_open(zone->raw->mctx, zone->journal, + DNS_JOURNAL_READ, &sjournal); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) + goto failure; + + if (!dns_journal_get_sourceserial(rjournal, &start)) { + start = dns_journal_first_serial(rjournal); + dns_journal_set_sourceserial(rjournal, start); + } + if (sjournal != NULL) { + isc_uint32_t serial; + /* + * We read the secure journal first, if that exists + * use its value provided it is greater that from the + * raw journal. + */ + if (dns_journal_get_sourceserial(sjournal, &serial)) { + if (isc_serial_gt(serial, start)) + start = serial; + } + dns_journal_destroy(&sjournal); + } + } + + dns_db_attach(zone->db, &db); + dns_db_currentversion(db, &oldver); + CHECK(dns_db_newversion(db, &newver)); + + /* + * Try to apply diffs from the raw zone's journal to the secure + * zone. If that fails, we recover by syncing up the databases + * directly. + */ + result = sync_secure_journal(zone, rjournal, start, end, + &soatuple, &diff); + if (result == DNS_R_UNCHANGED) + goto failure; + else if (result != ISC_R_SUCCESS) { + CHECK(sync_secure_db(zone, db, oldver, &diff)); } - if (result == ISC_R_NOMORE) - result = ISC_R_SUCCESS; - CHECK(result); CHECK(dns_diff_apply(&diff, db, newver)); if (soatuple != NULL) { - isc_uint32_t desired; + isc_uint32_t oldserial, newserial, desired; CHECK(dns_db_createsoatuple(db, oldver, diff.mctx, DNS_DIFFOP_DEL, &tuple)); @@ -12243,8 +12420,8 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) { LOCK_ZONE(zone); DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY); - zone->rawserial = start; - zone->rawserialset = ISC_TRUE; + zone->sourceserial = end; + zone->sourceserialset = ISC_TRUE; zone_needdump(zone, DNS_DUMP_DELAY); TIME_NOW(&timenow); @@ -12256,6 +12433,9 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) { dns_db_closeversion(db, &newver, ISC_TRUE); failure: + if (result != ISC_R_SUCCESS) + dns_zone_log(zone, ISC_LOG_ERROR, "receive_secure_serial: %s", + dns_result_totext(result)); if (tuple != NULL) dns_difftuple_free(&tuple); if (soatuple != NULL) @@ -12271,33 +12451,33 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) { } if (rjournal != NULL) dns_journal_destroy(&rjournal); - if (sjournal != NULL) - dns_journal_destroy(&sjournal); dns_diff_clear(&diff); - isc_event_free(&event); + dns_zone_idetach(&zone); } static isc_result_t -zone_send_secureserial(dns_zone_t *zone, isc_uint32_t serial) { +zone_send_secureserial(dns_zone_t *zone, isc_boolean_t locked, + isc_uint32_t serial) +{ isc_event_t *e; + dns_zone_t *dummy = NULL; e = isc_event_allocate(zone->secure->mctx, zone, DNS_EVENT_ZONESECURESERIAL, receive_secure_serial, zone->secure, - sizeof(struct secure_serial)); + sizeof(struct secure_event)); if (e == NULL) return (ISC_R_NOMEMORY); - ((struct secure_serial *)e)->serial = serial; - + ((struct secure_event *)e)->serial = serial; + if (locked) + zone_iattach(zone->secure, &dummy); + else + dns_zone_iattach(zone->secure, &dummy); isc_task_send(zone->secure->task, &e); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SENDSECURE); return (ISC_R_SUCCESS); } -struct secure_db { - isc_event_t e; - dns_db_t *db; -}; - static void receive_secure_db(isc_task_t *task, isc_event_t *event) { isc_result_t result; @@ -12315,7 +12495,11 @@ receive_secure_db(isc_task_t *task, isc_event_t *event) { UNUSED(task); zone = event->ev_arg; - rawdb = ((struct secure_db *)event)->db; + rawdb = ((struct secure_event *)event)->db; + isc_event_free(&event); + + REQUIRE(inline_secure(zone)); + dns_fixedname_init(&fname); name = dns_fixedname_name(&fname); dns_rdataset_init(&rdataset); @@ -12400,22 +12584,27 @@ receive_secure_db(isc_task_t *task, isc_event_t *event) { dns_db_detach(&rawdb); if (dbiterator != NULL) dns_dbiterator_destroy(&dbiterator); - isc_event_free(&event); + dns_zone_idetach(&zone); } static isc_result_t -zone_send_securedb(dns_zone_t *zone, dns_db_t *db) { +zone_send_securedb(dns_zone_t *zone, isc_boolean_t locked, dns_db_t *db) { isc_event_t *e; dns_db_t *dummy = NULL; + dns_zone_t *secure = NULL; e = isc_event_allocate(zone->secure->mctx, zone, DNS_EVENT_ZONESECUREDB, receive_secure_db, zone->secure, - sizeof(struct secure_db)); + sizeof(struct secure_event)); if (e == NULL) return (ISC_R_NOMEMORY); dns_db_attach(db, &dummy); - ((struct secure_db *)e)->db = dummy; + ((struct secure_event *)e)->db = dummy; + if (locked) + zone_iattach(zone->secure, &secure); + else + dns_zone_iattach(zone->secure, &secure); isc_task_send(zone->secure->task, &e); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_SENDSECURE); @@ -12483,7 +12672,8 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { */ if (zone->db != NULL && zone->journal != NULL && DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS) && - !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) { + !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) + { isc_uint32_t serial, oldserial; dns_zone_log(zone, ISC_LOG_DEBUG(3), "generating diffs"); @@ -12542,8 +12732,8 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { break; } } - if (zone->type == dns_zone_master && zone->secure != NULL) - zone_send_secureserial(zone, serial); + if (zone->type == dns_zone_master && inline_raw(zone)) + zone_send_secureserial(zone, ISC_FALSE, serial); } else { if (dump && zone->masterfile != NULL) { /* @@ -12594,8 +12784,9 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) { zone->journal, strbuf); } } - if (zone->secure != NULL) - zone_send_securedb(zone, db); + + if (inline_raw(zone)) + zone_send_securedb(zone, ISC_FALSE, db); } dns_db_closeversion(db, &ver, ISC_FALSE); @@ -12747,8 +12938,8 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) { dns_zone_log(zone, ISC_LOG_INFO, "transferred serial %u%s", serial, buf); - if (zone->secure != NULL) - zone_send_secureserial(zone, serial); + if (inline_raw(zone)) + zone_send_secureserial(zone, ISC_FALSE, serial); } /*