]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3682. [bug] Correct the behavior of rndc retransfer to allow
authorCurtis Blackburn <ckb@isc.org>
Wed, 4 Dec 2013 18:26:20 +0000 (12:26 -0600)
committerCurtis Blackburn <ckb@isc.org>
Wed, 4 Dec 2013 18:26:20 +0000 (12:26 -0600)
  inline-signing slave zones to retain NSEC3 parameters instead of
reverting to NSEC [RT #34745]

CHANGES
bin/rndc/rndc.docbook
bin/tests/system/inline/clean.sh
bin/tests/system/inline/ns1/root.db.in
bin/tests/system/inline/ns2/named.conf
bin/tests/system/inline/ns3/named.conf
bin/tests/system/inline/ns3/sign.sh [changed mode: 0644->0755]
bin/tests/system/inline/tests.sh [changed mode: 0644->0755]
lib/dns/zone.c

diff --git a/CHANGES b/CHANGES
index de9039a04f4b60d8e555c6bcbe08e32289125fdd..38e3bad85ae49ab6ae5680973d24fae7eb303bb7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+3682.  [bug]           Correct the behavior of rndc retransfer to allow
+                       inline-signing slave zones to retain NSEC3 parameters instead of
+                       reverting to NSEC [RT #34745]
+
 3681.  [port]          Update the Windows build system to support feature
                        selection and WIN64 builds.  This is a work in
                        progress. [RT #34160]
index 60580937a71cd99237e199aed982428bfd61b7d8..6678bc783541844711ad9ee31b28eb85f57bd185 100644 (file)
         <term><userinput>retransfer <replaceable>zone</replaceable> <optional><replaceable>class</replaceable> <optional><replaceable>view</replaceable></optional></optional></userinput></term>
         <listitem>
           <para>
-            Retransfer the given zone from the master.
+            Retransfer the given slave zone from the master server.
+          </para>
+          <para>
+            If the zone is configured to use
+            <command>inline-signing</command>, the signed
+            version of the zone is discarded; after the
+            retransfer of the unsigned version is complete, the
+            signed version will be regenerated with all new
+            signatures.
           </para>
         </listitem>
       </varlistentry>
index 4913c733b39247d99a717b4193bf5e9202bfe667..462bf02c557fc2c7521813899c5326fe6f5b1710 100644 (file)
@@ -60,6 +60,10 @@ rm -f ns3/retransfer.bk
 rm -f ns3/retransfer.bk.jnl
 rm -f ns3/retransfer.bk.signed
 rm -f ns3/retransfer.bk.signed.jnl
+rm -f ns3/retransfer3.bk
+rm -f ns3/retransfer3.bk.jnl
+rm -f ns3/retransfer3.bk.signed
+rm -f ns3/retransfer3.bk.signed.jnl
 rm -f ns3/externalkey.db
 rm -f ns3/externalkey.db.signed
 rm -f ns3/externalkey.db.signed.jnl
index a08db511bcad54c881f117c1b11063c8c1f2837f..e319b37eb04ad396900c652f1447c9c6bd1dc5ea 100644 (file)
@@ -53,3 +53,6 @@ ns3.nsec3.            A       10.53.0.3
 
 externalkey.           NS      ns3.externalkey.
 ns3.externalkey.       A       10.53.0.3
+
+retransfer3.           NS      ns3.retransfer.
+ns3.retransfer3.       A       10.53.0.3
index bafbaf67826bec4ac41d7eceb5dd9b9af6fddd25..c7e8d47bc4af8f4a90be1b8bf0c0ef3baff3c5c6 100644 (file)
@@ -48,3 +48,10 @@ zone "retransfer" {
        allow-update { any; };
        notify no;
 };
+
+zone "retransfer3" {
+       type master;
+       file "retransfer.db";
+       allow-update { any; };
+       notify no;
+};
index 7c23edd1d7cd05383b229301ff05f3bf45e3d629..60635696894132a9a6a6d12a87ecd723bd7d470f 100644 (file)
@@ -111,3 +111,11 @@ zone "externalkey" {
        allow-update { any; };
        file "externalkey.db";
 };
+
+zone "retransfer3" {
+       type slave;
+       masters { 10.53.0.2; };
+       inline-signing yes;
+       auto-dnssec maintain;
+       file "retransfer3.bk";
+};
old mode 100644 (file)
new mode 100755 (executable)
index d606fe7..7e9260b
@@ -80,6 +80,13 @@ rm -f K${zone}.+*+*.private
 keyname=`$KEYGEN -q -r $RANDFILE -a NSEC3RSASHA1 -b 1024 -n zone -f KSK $zone`
 $DSFROMKEY -T 1200 $keyname >> ../ns1/root.db
 
+zone=retransfer3
+rm -f K${zone}.+*+*.key
+rm -f K${zone}.+*+*.private
+keyname=`$KEYGEN -q -r $RANDFILE -a NSEC3RSASHA1 -b 768 -n zone $zone`
+keyname=`$KEYGEN -q -r $RANDFILE -a NSEC3RSASHA1 -b 1024 -n zone -f KSK $zone`
+$DSFROMKEY -T 1200 $keyname >> ../ns1/root.db
+
 for s in a c d h k l m q z
 do
        zone=test-$s
old mode 100644 (file)
new mode 100755 (executable)
index f975c26..c8719f7
@@ -25,7 +25,7 @@ RANDFILE=random.data
 status=0
 n=0
 
-$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -nsec3param 1 0 0 - nsec3
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -nsec3param 1 0 0 - nsec3 > /dev/null 2>&1
 
 for i in 1 2 3 4 5 6 7 8 9 0
 do
@@ -34,6 +34,21 @@ do
        sleep 1
 done
 
+# Loop until retransfer3 has been transferred.
+for i in 1 2 3 4 5 6 7 8 9 0
+do
+        ans=0
+        $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -nsec3param 1 0 0 - retransfer3 > /dev/null 2>&1 || ans=1
+       [ $ans = 0 ] && break
+done
+
+for i in 1 2 3 4 5 6 7 8 9 0
+do
+       nsec3param=`$DIG +short @10.53.0.3 -p 5300 nsec3param retransfer3.`
+       test -n "$nsec3param" && break
+       sleep 1
+done
+
 n=`expr $n + 1`
 echo "I:checking that rrsigs are replaced with ksk only"
 ret=0
@@ -761,6 +776,32 @@ n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
+echo "I:check rndc retransfer of a inline nsec3 slave retains nsec3 ($n)"
+ret=0
+for i in 0 1 2 3 4 5 6 7 8 9
+do
+       ans=0
+       $DIG $DIGOPTS @10.53.0.3 -p 5300 nonexist.retransfer3 A > dig.out.ns3.pre.test$n
+       grep "status: NXDOMAIN" dig.out.ns3.pre.test$n > /dev/null || ans=1
+       grep "NSEC3" dig.out.ns3.pre.test$n > /dev/null || ans=1
+       [ $ans = 0 ] && break
+       sleep 1
+done
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 retransfer retransfer3 2>&1 || ret=1
+for i in 0 1 2 3 4 5 6 7 8 9
+do
+       ans=0
+       $DIG $DIGOPTS @10.53.0.3 -p 5300 nonexist.retransfer3 A > dig.out.ns3.post.test$n
+       grep "status: NXDOMAIN" dig.out.ns3.post.test$n > /dev/null || ans=1
+       grep "NSEC3" dig.out.ns3.post.test$n > /dev/null || ans=1
+       [ $ans = 0 ] && break
+       sleep 1
+done
+[ $ans = 1 ] && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
 n=`expr $n + 1`
 echo "I:stop bump in the wire signer server ($n)"
 ret=0
index 12242660482d6fa25e1e4b2d1ec5cf05b7472d36..d1a94c7a06283498148e671410126d65a7bae410 100644 (file)
@@ -799,6 +799,20 @@ static const char *dbargv_default[] = { "rbt" };
                } \
        } while (0)
 
+typedef struct nsec3param nsec3param_t;
+struct nsec3param {
+       unsigned char data[DNS_NSEC3PARAM_BUFFERSIZE + 1];
+       unsigned int length;
+       isc_boolean_t nsec;
+       isc_boolean_t replace;
+       ISC_LINK(nsec3param_t)  link;
+};
+typedef ISC_LIST(nsec3param_t) nsec3paramlist_t;
+struct np3event {
+       isc_event_t event;
+       nsec3param_t params;
+};
+
 /*%
  * Increment resolver-related statistics counters.  Zone must be locked.
  */
@@ -13407,6 +13421,203 @@ checkandaddsoa(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
                                   0, NULL));
 }
 
+/*
+ * This function should populate an nsec3paramlist_t with the
+ * nsecparam_t data from a zone.
+ */
+static isc_result_t
+save_nsec3param(dns_zone_t *zone, nsec3paramlist_t *nsec3list) {
+       isc_result_t result;
+       dns_dbnode_t *node = NULL;
+       dns_rdataset_t rdataset, prdataset;
+       dns_rdata_t rdata_in, prdata_in, prdata_out;
+       dns_dbversion_t *version = NULL;
+       nsec3param_t *nsec3param = NULL;
+       nsec3param_t *nsec3p = NULL;
+       nsec3param_t *next;
+       dns_db_t *db = NULL;
+       unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
+
+       REQUIRE(DNS_ZONE_VALID(zone));
+       REQUIRE(nsec3list != NULL);
+       REQUIRE(ISC_LIST_EMPTY(*nsec3list));
+
+       dns_db_attach(zone->db, &db);
+       CHECK(dns_db_getoriginnode(db, &node));
+
+       dns_rdataset_init(&rdataset);
+       dns_db_currentversion(db, &version);
+       result = dns_db_findrdataset(db, node, version,
+                                    dns_rdatatype_nsec3param,
+                                    dns_rdatatype_none, 0, &rdataset, NULL);
+
+       if (result != ISC_R_SUCCESS)
+               goto getprivate;
+
+       /*
+        * walk nsec3param rdataset making a list of parameters (note that
+        * multiple simultaneous nsec3 chains are annoyingly legal -- this
+        * is why we use an nsec3list, even tho we will usually only have
+        * one)
+        */
+       for (result = dns_rdataset_first(&rdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&rdataset)) 
+       {
+               dns_rdata_init(&rdata_in);
+               dns_rdataset_current(&rdataset, &rdata_in);
+               isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+                             DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3),
+                             "looping through nsec3param data");
+               nsec3param = isc_mem_get(zone->mctx, sizeof(nsec3param_t));
+               if (nsec3param == NULL)
+                       CHECK(ISC_R_NOMEMORY);
+               ISC_LINK_INIT(nsec3param, link);
+
+               /*
+                * now transfer the data from the rdata to
+                * the nsec3param
+                */
+               dns_rdata_init(&prdata_out);
+               dns_nsec3param_toprivate(&rdata_in, &prdata_out,
+                                        zone->privatetype, nsec3param->data,
+                                        sizeof(nsec3param->data));
+               nsec3param->length = prdata_out.length;
+               ISC_LIST_APPEND(*nsec3list, nsec3param, link);
+       }
+
+ getprivate:
+       dns_rdataset_init(&prdataset);
+       result = dns_db_findrdataset(db, node, version, zone->privatetype,
+                                    dns_rdatatype_none, 0, &prdataset, NULL);
+       if (result != ISC_R_SUCCESS)
+               goto done;
+
+       /*
+        * walk private type records, converting them to nsec3 parameters
+        * using dns_nsec3param_fromprivate(), do the right thing based on
+        * CREATE and REMOVE flags
+        */
+       for (result = dns_rdataset_first(&prdataset);
+            result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&prdataset)) 
+       {
+               dns_rdata_init(&prdata_in);
+               dns_rdataset_current(&prdataset, &prdata_in);
+               isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
+                             DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(3),
+                             "looping through nsec3param private data");
+               
+               if (!dns_nsec3param_fromprivate(&prdata_in, &prdata_out,
+                                               buf, sizeof(buf)))
+                       continue;
+               
+               if ((prdata_out.data[1] & DNS_NSEC3FLAG_REMOVE) !=0) {
+                       prdata_out.data[1] = 0;
+
+                       for (nsec3p = ISC_LIST_HEAD(*nsec3list); 
+                            nsec3p != NULL; 
+                            nsec3p = next) 
+                       {
+                               next = ISC_LIST_NEXT(nsec3p, link);
+                               if (memcmp(prdata_out.data, nsec3p->data, 
+                                   sizeof(nsec3p->data)) == 0) {
+                                       ISC_LIST_UNLINK(*nsec3list,
+                                                       nsec3p, link);
+                                       isc_mem_put(zone->mctx, nsec3p, 
+                                                   sizeof(nsec3param_t));
+                               }
+                       }
+                       continue;
+               }
+
+               nsec3param = isc_mem_get(zone->mctx, sizeof(nsec3param_t));
+               if (nsec3param == NULL)
+                       CHECK(ISC_R_NOMEMORY);
+               ISC_LINK_INIT(nsec3param, link);
+
+               dns_rdata_init(&prdata_out);
+               dns_nsec3param_toprivate(&prdata_in, &prdata_out, 
+                       zone->privatetype, nsec3param->data, 
+                       sizeof(nsec3param->data));
+               nsec3param->length = prdata_out.length;
+               ISC_LIST_APPEND(*nsec3list, nsec3param, link);
+       }
+
+ done:
+       if (result == ISC_R_NOMORE || result == ISC_R_NOTFOUND)
+               result = ISC_R_SUCCESS;
+
+ failure:
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
+       if (version != NULL)
+               dns_db_closeversion(db, &version, ISC_FALSE);
+       if (db != NULL)
+               dns_db_detach(&db);
+       if (dns_rdataset_isassociated(&rdataset))
+               dns_rdataset_disassociate(&rdataset);
+       if (dns_rdataset_isassociated(&prdataset))
+               dns_rdataset_disassociate(&prdataset);
+       return (result);
+}
+
+/* 
+ * Walk the list of the nsec3 chains desired for the zone, converting 
+ * parameters to private type records using dns_nsec3param_toprivate(),
+ * and insert them into the new zone db. 
+ */
+static isc_result_t
+restore_nsec3param(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, 
+                  nsec3paramlist_t *nsec3list)
+{
+       isc_result_t result; 
+       dns_diff_t diff;
+       dns_rdata_t rdata;
+       nsec3param_t *nsec3p = NULL;
+       nsec3param_t *next;
+       
+       REQUIRE(DNS_ZONE_VALID(zone));
+       REQUIRE(!ISC_LIST_EMPTY(*nsec3list));
+       
+       dns_diff_init(zone->mctx, &diff);
+
+       /* 
+        * Loop through the list of private-type records, set the INITIAL
+        * and CREATE flags, and the add the record to the apex of the tree
+        * in db.
+        */
+       for (nsec3p = ISC_LIST_HEAD(*nsec3list);
+            nsec3p != NULL; 
+            nsec3p = next) 
+       {
+               next = ISC_LIST_NEXT(nsec3p, link);
+               dns_rdata_init(&rdata);
+               nsec3p->data[2] = DNS_NSEC3FLAG_CREATE | DNS_NSEC3FLAG_INITIAL;
+               rdata.length = nsec3p->length;
+               rdata.data = nsec3p->data;
+               rdata.type = zone->privatetype;
+               rdata.rdclass = zone->rdclass;
+               CHECK(update_one_rr(db, version, &diff, DNS_DIFFOP_ADD,
+                                   &zone->origin, 0, &rdata));
+       }
+       
+       result = ISC_R_SUCCESS;
+       
+failure:
+       for (nsec3p = ISC_LIST_HEAD(*nsec3list);
+            nsec3p != NULL; 
+            nsec3p = next) 
+       {
+               next = ISC_LIST_NEXT(nsec3p, link);
+               ISC_LIST_UNLINK(*nsec3list, nsec3p, link);
+               isc_mem_put(zone->mctx, nsec3p, sizeof(nsec3param_t));
+       }
+
+       dns_diff_clear(&diff);
+       return (result);
+}
+
 static void
 receive_secure_db(isc_task_t *task, isc_event_t *event) {
        isc_result_t result;
@@ -13422,9 +13633,12 @@ receive_secure_db(isc_task_t *task, isc_event_t *event) {
        isc_time_t loadtime;
        unsigned int oldserial = 0;
        isc_boolean_t have_oldserial = ISC_FALSE;
+       nsec3paramlist_t nsec3list;
 
        UNUSED(task);
 
+       ISC_LIST_INIT(nsec3list);
+               
        zone = event->ev_arg;
        rawdb = ((struct secure_event *)event)->db;
        isc_event_free(&event);
@@ -13445,6 +13659,16 @@ receive_secure_db(isc_task_t *task, isc_event_t *event) {
                result = dns_db_getsoaserial(zone->db, NULL, &oldserial);
                if (result == ISC_R_SUCCESS)
                        have_oldserial = ISC_TRUE;
+
+               /*
+                * assemble nsec3parameters from the old zone, and set a flag 
+                * if any are found
+                */
+               result = save_nsec3param(zone, &nsec3list);
+               if (result != ISC_R_SUCCESS) {
+                       ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+                       goto failure;
+               }
        }
        ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
 
@@ -13506,8 +13730,16 @@ receive_secure_db(isc_task_t *task, isc_event_t *event) {
                dns_db_detachnode(rawdb, &rawnode);
                dns_db_detachnode(db, &node);
        }
-
+       
+       /*
+        * Call restore_nsec3param() to create private-type records from
+        * the old nsec3 parameters and insert them into db
+        */
+       if (!ISC_LIST_EMPTY(nsec3list))
+               restore_nsec3param(zone, db, version, &nsec3list);
+       
        dns_db_closeversion(db, &version, ISC_TRUE);
+
        /*
         * Lock hierarchy: zmgr, zone, raw.
         */
@@ -17202,14 +17434,6 @@ dns_zone_keydone(dns_zone_t *zone, const char *keystr) {
        return (result);
 }
 
-struct nsec3param {
-       isc_event_t event;
-       unsigned char data[DNS_NSEC3PARAM_BUFFERSIZE + 1];
-       unsigned int length;
-       isc_boolean_t nsec;
-       isc_boolean_t replace;
-};
-
 static void
 setnsec3param(isc_task_t *task, isc_event_t *event) {
        const char *me = "setnsec3param";
@@ -17221,7 +17445,8 @@ setnsec3param(isc_task_t *task, isc_event_t *event) {
        dns_dbnode_t *node = NULL;
        dns_rdataset_t prdataset, nrdataset;
        dns_diff_t diff;
-       struct nsec3param *np = (struct nsec3param *)event;
+       struct np3event *npe = (struct np3event *)event;
+       nsec3param_t *np;
        dns_update_log_t log = { update_log_cb, NULL };
        dns_rdata_t rdata;
        isc_boolean_t nseconly;
@@ -17233,6 +17458,8 @@ setnsec3param(isc_task_t *task, isc_event_t *event) {
        INSIST(DNS_ZONE_VALID(zone));
 
        ENTER;
+       
+       np = &npe->params;
 
        dns_rdataset_init(&prdataset);
        dns_rdataset_init(&nrdataset);
@@ -17385,7 +17612,8 @@ dns_zone_setnsec3param(dns_zone_t *zone, isc_uint8_t hash, isc_uint8_t flags,
        dns_rdata_t nrdata = DNS_RDATA_INIT;
        dns_rdata_t prdata = DNS_RDATA_INIT;
        unsigned char nbuf[DNS_NSEC3PARAM_BUFFERSIZE];
-       struct nsec3param *np;
+       struct np3event *npe;
+       nsec3param_t *np;
        dns_zone_t *dummy = NULL;
        isc_buffer_t b;
        isc_event_t *e;
@@ -17396,13 +17624,15 @@ dns_zone_setnsec3param(dns_zone_t *zone, isc_uint8_t hash, isc_uint8_t flags,
        LOCK_ZONE(zone);
 
        e = isc_event_allocate(zone->mctx, zone, DNS_EVENT_SETNSEC3PARAM,
-                              setnsec3param, zone, sizeof(struct nsec3param));
+                              setnsec3param, zone, sizeof(struct np3event));
        if (e == NULL) {
                result = ISC_R_NOMEMORY;
                goto failure;
        }
 
-       np = (struct nsec3param *) e;
+       npe = (struct np3event *) e;
+       np = &npe->params;
+       
        np->replace = replace;
        if (hash == 0) {
                np->length = 0;