]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3252. [bug] When master zones using inline-signing were
authorEvan Hunt <each@isc.org>
Thu, 22 Dec 2011 07:32:41 +0000 (07:32 +0000)
committerEvan Hunt <each@isc.org>
Thu, 22 Dec 2011 07:32:41 +0000 (07:32 +0000)
updated while the server was offline, the source
zone could fall out of sync with the signed
copy. They can now resynchronize. [RT #26676]

23 files changed:
CHANGES
bin/check/check-tool.c
bin/check/named-checkzone.c
bin/check/named-checkzone.docbook
bin/dnssec/dnssec-signzone.c
bin/dnssec/dnssec-signzone.docbook
bin/named/update.c
bin/named/xfrout.c
bin/tests/system/inline/clean.sh
bin/tests/system/inline/ns1/root.db.in
bin/tests/system/inline/ns1/sign.sh
bin/tests/system/inline/ns3/named.conf
bin/tests/system/inline/ns3/sign.sh
bin/tests/system/inline/setup.sh
bin/tests/system/inline/tests.sh
bin/tests/system/masterformat/clean.sh
bin/tests/system/masterformat/ns1/compile.sh
bin/tests/system/masterformat/tests.sh
lib/dns/include/dns/journal.h
lib/dns/include/dns/zone.h
lib/dns/journal.c
lib/dns/xfrin.c
lib/dns/zone.c

diff --git a/CHANGES b/CHANGES
index aa9fc86af41a8f6eafeb79e478579108e094c917..77c1bf6de26b1ba131667a50ba8cd0b81065019e 100644 (file)
--- 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.
index 3b5e9b117af2dc1136d6d8955df6f4c1b94356ee..445c0cc029d1043866d0f62bcb6df4dc1aa3cbe3 100644 (file)
@@ -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);
 
index 073cd493025bd64cda4311ee8dff4bcdeb62b521..c5ababdd47af35a0f0c98cd5df2a02a07b8d1d43 100644 (file)
@@ -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 <dns/db.h>
 #include <dns/fixedname.h>
 #include <dns/log.h>
+#include <dns/master.h>
 #include <dns/masterdump.h>
 #include <dns/name.h>
 #include <dns/rdataclass.h>
@@ -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);
index 22101997b0ed6fb5101db781a0bce8035c12a546..85479e7d90169d99bbb58659c18bbca1cbe61b07 100644 (file)
@@ -18,7 +18,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- $Id: named-checkzone.docbook,v 1.43 2011/12/09 23:47:02 tbox Exp $ -->
+<!-- $Id: named-checkzone.docbook,v 1.44 2011/12/22 07:32:39 each Exp $ -->
 <refentry id="man.named-checkzone">
   <refentryinfo>
     <date>June 13, 2000</date>
@@ -71,6 +71,7 @@
       <arg><option>-m <replaceable class="parameter">mode</replaceable></option></arg>
       <arg><option>-M <replaceable class="parameter">mode</replaceable></option></arg>
       <arg><option>-n <replaceable class="parameter">mode</replaceable></option></arg>
+      <arg><option>-L <replaceable class="parameter">serial</replaceable></option></arg>
       <arg><option>-o <replaceable class="parameter">filename</replaceable></option></arg>
       <arg><option>-r <replaceable class="parameter">mode</replaceable></option></arg>
       <arg><option>-s <replaceable class="parameter">style</replaceable></option></arg>
@@ -96,6 +97,7 @@
       <arg><option>-k <replaceable class="parameter">mode</replaceable></option></arg>
       <arg><option>-m <replaceable class="parameter">mode</replaceable></option></arg>
       <arg><option>-n <replaceable class="parameter">mode</replaceable></option></arg>
+      <arg><option>-L <replaceable class="parameter">serial</replaceable></option></arg>
       <arg><option>-r <replaceable class="parameter">mode</replaceable></option></arg>
       <arg><option>-s <replaceable class="parameter">style</replaceable></option></arg>
       <arg><option>-t <replaceable class="parameter">directory</replaceable></option></arg>
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term>-L <replaceable class="parameter">serial</replaceable></term>
+        <listitem>
+          <para>
+            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.)
+          </para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term>-m <replaceable class="parameter">mode</replaceable></term>
         <listitem>
index c8b2abfa58b8ee0592669ffafbc7af13eb762173..8335195ddb1bf158b01d9a6553a8eecc696bbbda 100644 (file)
@@ -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);
index 2517d199bc3a120df3d4df2d24690a4726bac2ed..e427fc1266bc0f98af55edf0d83726241907ec60 100644 (file)
@@ -18,7 +18,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- $Id: dnssec-signzone.docbook,v 1.51 2011/12/08 16:07:20 each Exp $ -->
+<!-- $Id: dnssec-signzone.docbook,v 1.52 2011/12/22 07:32:40 each Exp $ -->
 <refentry id="man.dnssec-signzone">
   <refentryinfo>
     <date>June 05, 2009</date>
@@ -69,6 +69,7 @@
       <arg><option>-h</option></arg>
       <arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg>
       <arg><option>-k <replaceable class="parameter">key</replaceable></option></arg>
+      <arg><option>-L <replaceable class="parameter">serial</replaceable></option></arg>
       <arg><option>-l <replaceable class="parameter">domain</replaceable></option></arg>
       <arg><option>-i <replaceable class="parameter">interval</replaceable></option></arg>
       <arg><option>-I <replaceable class="parameter">input-format</replaceable></option></arg>
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term>-L <replaceable class="parameter">serial</replaceable></term>
+        <listitem>
+          <para>
+            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.)
+          </para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term>-n <replaceable class="parameter">ncpus</replaceable></term>
         <listitem>
index d83fcbae35e725437500b935118f213b5ba047f4..bfffc73bcc06786332144c1e817df8535751e28d 100644 (file)
@@ -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 <config.h>
 
@@ -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");
 
index 43eec8e899bc28997a3fcd97f5c22ab46bd88c7b..70b7830541de4ca3fd4cc586153ff9fbb32784a2 100644 (file)
@@ -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 <config.h>
 
@@ -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;
index 12ccefcea86633bae4ef1dbd2e603e7d6d9fb7c0..8fefba08b61d2274a27c3aaf6db683caff8a1317 100644 (file)
 # 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
index b3e756dd7c37d17e8a0ffe0916d594f5d6b6d1be..8f4cb6d536fc51d08a4a4737bbc4d538d6cccaa0 100644 (file)
@@ -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
index 3f25d618aff74411f17843363f4dde26c0289acb..b2688ea2b8c6fb0c14dee51dc625360f9aa40c7e 100644 (file)
@@ -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;
index 1c9483bb7c0daa9f59e454f12e65023359ff7b0b..970fe1683a284c866575bcc17669568ed7ef87df 100644 (file)
@@ -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";
+};
index 913e64bd5f4f4ee86e484e2602df87fd0cdf5830..3a58fd8f5d7d9ccdb829166bfdf68bfbe1bb4e6b 100644 (file)
@@ -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
index dd0a19a0c9465d965c26a39a1c61b943c8072a2f..d7bb722f0fb49fd771949b60baf7f646f19b1a49 100644 (file)
@@ -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
index 836e9d0a2a8718fae339ed244d86cf7e48cdf0fe..015c208d604c1a03d26aa47e8969a8922897a683 100644 (file)
@@ -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
index be50b22189c99109c801cf6d862e93a54021c076..5c2f13d939ce7a9574d6f3d6393d2b0445642ef5 100755 (executable)
 # 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
index 0edffec0914914494c15c7a00b8245a3e0059bfc..e778997b21a7fa194643a435a94e86fedb0304a3 100755 (executable)
@@ -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
index 74678ecc5b8e0c595d517620f0d36ee699395265..7066714d5c868befa9d3a0331919c0b85aba13b5 100755 (executable)
@@ -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 = <STDIN>;
-             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 = <STDIN>;
+             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
 
index b615589de4bfdb1be4fdedd59ef30054b682afda..68ba8b35ae91d98b16bd24176eeafb02acaef97f 100644 (file)
@@ -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
index 9f8ed39e56759204abb55a85aa16391d68a526d9..e5d1d92a12926b70c1ec5abbb2a94b87addc5a1e 100644 (file)
@@ -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 <isc/lang.h>
 #include <isc/rwlock.h>
 
+#include <dns/master.h>
 #include <dns/masterdump.h>
 #include <dns/rdatastruct.h>
 #include <dns/types.h>
@@ -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 */
index a6a40aab82e758cf9879c4d0ab3c7b717059e2ff..f8f1a9794cfd2b4ca8ad965eedd24648532bf6ff 100644 (file)
@@ -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 <config.h>
 
@@ -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.
index ad11414c4c18aa9f8db4ba2cb02d746eeb7200a4..b53e720e980223f34fd51303108644d5d329f0b7 100644 (file)
@@ -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:
index bf4d3f50c88464de5a365b0ce66a680625e910c7..132d49461092db734e1aa9ac62ec2297e4cfb638 100644 (file)
@@ -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 (zone == NULL)
+       if ((header->flags & DNS_MASTERRAW_SOURCESERIALSET) == 0)
                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))
+       zone->sourceserial = header->sourceserial;
+       zone->sourceserialset = ISC_TRUE;
+}
+
+void
+dns_zone_setrawdata(dns_zone_t *zone, dns_masterrawheader_t *header) {
+       if (zone == NULL)
                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;
-
-       zone = event->ev_arg;
-       end = ((struct secure_serial *)event)->serial;
-
-       dns_diff_init(zone->mctx, &diff);
-
-       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));
+       int n_soa = 0;
 
-       dns_db_attach(zone->db, &db);
-       dns_db_currentversion(db, &oldver);
-       CHECK(dns_db_newversion(db, &newver));
+       REQUIRE(soatuplep != NULL);
 
-       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 (start == end)
+               return (DNS_R_UNCHANGED);
 
-               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);
                }
 
                /*