]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Don't crash when rndc delzone encounters a catz member
authorTony Finch <fanf@isc.org>
Wed, 14 Dec 2022 16:24:19 +0000 (16:24 +0000)
committerTony Finch <dot@dotat.at>
Wed, 4 Jan 2023 17:50:44 +0000 (17:50 +0000)
This bug was masked in the tests because the `catz` test script did an
`rndc addzone` before an `rndc delzone`. The `addzone` autovivified
the NZF config, so `delzone` worked OK.

This commit swaps the order of two sections of the `catz` test script
so that it uses `delzone` before `addzone`, which provokes a crash
when `delzone` requires a non-NULL NZF config.

To fix the crash, we now try to remove the zone from the NZF config
only if it was dynamically added but not by a catalog zone.

(cherry picked from commit 9fa20d6f6c1d978fa6a8f79fa19d0dd71c0ca4eb)

CHANGES
bin/named/server.c
bin/tests/system/catz/tests.sh

diff --git a/CHANGES b/CHANGES
index 55e36d23967ec22d0ba7b6c44bafe90757593ecc..0e7eeab1b51ba5c3270ae4f47677ea9ba78f5f56 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+6058.  [bug]           Prevent named from crashing when "rndc delzone"
+                       attempts to delete a zone added by a catalog zone.
+                       [GL #3745]
+
 6053.  [bug]           Fix an ADB quota management bug in resolver. [GL #3752]
 
 6051.  [bug]           Improve thread safety in the dns_dispatch unit.
index 464a1708e59dd67226f1f1c337b0ecbfa077f831..a18395550eeadddb05230042f1a7de51b4fecc9e 100644 (file)
@@ -14419,10 +14419,11 @@ typedef struct {
 static void
 rmzone(isc_task_t *task, isc_event_t *event) {
        ns_dzctx_t *dz = (ns_dzctx_t *)event->ev_arg;
-       dns_zone_t *zone, *raw = NULL, *mayberaw;
+       dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
+       dns_catz_zone_t *catz = NULL;
        char zonename[DNS_NAME_FORMATSIZE];
-       dns_view_t *view;
-       ns_cfgctx_t *cfg;
+       dns_view_t *view = NULL;
+       ns_cfgctx_t *cfg = NULL;
        dns_db_t *dbp = NULL;
        bool added;
        isc_result_t result;
@@ -14446,10 +14447,14 @@ rmzone(isc_task_t *task, isc_event_t *event) {
                      "deleting zone %s in view %s via delzone", zonename,
                      view->name);
 
-       /* Remove the zone from configuration (and NZF file if applicable) */
+       /*
+        * Remove the zone from configuration (and NZF file if applicable)
+        * (If this is a catalog zone member then nzf_config can be NULL)
+        */
        added = dns_zone_getadded(zone);
+       catz = dns_zone_get_parentcatz(zone);
 
-       if (added && cfg != NULL) {
+       if (added && catz == NULL && cfg != NULL) {
 #ifdef HAVE_LMDB
                /* Make sure we can open the NZD database */
                LOCK(&view->new_zone_lock);
@@ -14466,8 +14471,7 @@ rmzone(isc_task_t *task, isc_event_t *event) {
                if (result != ISC_R_SUCCESS) {
                        isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
                                      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
-                                     "unable to "
-                                     "delete zone configuration: %s",
+                                     "unable to delete zone configuration: %s",
                                      isc_result_totext(result));
                }
 
@@ -14482,8 +14486,7 @@ rmzone(isc_task_t *task, isc_event_t *event) {
                if (result != ISC_R_SUCCESS) {
                        isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
                                      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
-                                     "unable to "
-                                     "delete zone configuration: %s",
+                                     "unable to delete zone configuration: %s",
                                      isc_result_totext(result));
                }
 #endif /* HAVE_LMDB */
@@ -14504,8 +14507,7 @@ rmzone(isc_task_t *task, isc_event_t *event) {
                if (result != ISC_R_SUCCESS) {
                        isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
                                      NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
-                                     "unable to "
-                                     "delete zone configuration: %s",
+                                     "unable to delete zone configuration: %s",
                                      isc_result_totext(result));
                }
        }
@@ -14622,8 +14624,8 @@ named_server_delzone(named_server_t *server, isc_lex_t *lex,
        if (dns_zone_get_rpz_num(zone) != DNS_RPZ_INVALID_NUM) {
                TCHECK(putstr(text, "zone '"));
                TCHECK(putstr(text, zonename));
-               TCHECK(putstr(text, "' cannot be deleted: response-policy "
-                                   "zone."));
+               TCHECK(putstr(text,
+                             "' cannot be deleted: response-policy zone."));
                result = ISC_R_FAILURE;
                goto cleanup;
        }
index 09c7ba5d046cb0d9f978812bf331e3da7bc30db3..796786366b8a61a290dc6f83dcd250c7d46b07f7 100644 (file)
@@ -1904,83 +1904,83 @@ if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 ##########################################################################
-echo_i "Testing having a regular zone and a zone in catalog zone of the same name"
+echo_i "Testing recreation of a manually deleted zone after a reload"
 n=$((n+1))
-echo_i "checking that dom14.example. is not served by primary ($n)"
+echo_i "checking that dom16.example. is not served by primary ($n)"
 ret=0
-wait_for_no_soa @10.53.0.1 dom14.example. dig.out.test$n || ret=1
+wait_for_no_soa @10.53.0.1 dom16.example. dig.out.test$n || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
-echo_i "Adding a domain dom14.example. to primary ns1 via RNDC ($n)"
+echo_i "Adding a domain dom16.example. to primary ns1 via RNDC ($n)"
 ret=0
-echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns1/dom14.example.db
-echo "@ IN NS invalid." >> ns1/dom14.example.db
-echo "@ IN A 192.0.2.1" >> ns1/dom14.example.db
-rndccmd 10.53.0.1 addzone dom14.example. in default '{type primary; file "dom14.example.db";};' || ret=1
+echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns1/dom16.example.db
+echo "@ IN NS invalid." >> ns1/dom16.example.db
+echo "@ IN A 192.0.2.1" >> ns1/dom16.example.db
+rndccmd 10.53.0.1 addzone dom16.example. in default '{type primary; file "dom16.example.db";};' || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
-echo_i "checking that dom14.example. is now served by primary ns1 ($n)"
+echo_i "checking that dom16.example. is now served by primary ns1 ($n)"
 ret=0
-wait_for_soa @10.53.0.1 dom14.example. dig.out.test$n || ret=1
+wait_for_soa @10.53.0.1 dom16.example. dig.out.test$n || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
+nextpart ns2/named.run >/dev/null
+
 n=$((n+1))
-echo_i "Adding a domain dom14.example. to primary ns3 via RNDC ($n)"
+echo_i "Adding domain dom16.example. to catalog1 zone with ns1 as primary ($n)"
 ret=0
-echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns3/dom14.example.db
-echo "@ IN NS invalid." >> ns3/dom14.example.db
-echo "@ IN A 192.0.2.2" >> ns3/dom14.example.db
-rndccmd 10.53.0.3 addzone dom14.example. '{type primary; file "dom14.example.db";};' || ret=1
+$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
+    server 10.53.0.1 ${PORT}
+    update add efe725d0cf430ffb113b9bcf59266f066a21216b.zones.catalog1.example. 3600 IN PTR dom16.example.
+    update add masters.efe725d0cf430ffb113b9bcf59266f066a21216b.zones.catalog1.example. 3600 IN A 10.53.0.1
+    send
+END
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
-echo_i "checking that dom14.example. is now served by primary ns3 ($n)"
+echo_i "waiting for secondary to sync up ($n)"
 ret=0
-wait_for_soa @10.53.0.3 dom14.example. dig.out.test$n || ret=1
+wait_for_message ns2/named.run  "catz: adding zone 'dom16.example' from catalog 'catalog1.example'" &&
+wait_for_message ns2/named.run  "transfer of 'dom16.example/IN/default' from 10.53.0.1#${PORT}: Transfer status: success" || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 nextpart ns2/named.run >/dev/null
 
 n=$((n+1))
-echo_i "Adding domain dom14.example. with rndc with ns1 as primary ($n)"
+echo_i "checking that dom16.example. is served by secondary and that it's the one from ns1 ($n)"
 ret=0
-rndccmd 10.53.0.2 addzone dom14.example. in default '{type secondary; primaries {10.53.0.1;};};' || ret=1
+wait_for_a @10.53.0.2 dom16.example. dig.out.test$n || ret=1
+grep "192.0.2.1" dig.out.test$n > /dev/null || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
-n=$((n+1))
-echo_i "waiting for secondary to sync up ($n)"
+nextpart ns2/named.run >/dev/null
+
+echo_i "Deleting dom16.example. from secondary ns2 via RNDC ($n)"
 ret=0
-wait_for_message ns2/named.run  "transfer of 'dom14.example/IN/default' from 10.53.0.1#${PORT}: Transfer status: success" || ret=1
+rndccmd 10.53.0.2 delzone dom16.example. in default >/dev/null 2>&1 || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
-nextpart ns2/named.run >/dev/null
-
 n=$((n+1))
-echo_i "checking that dom14.example. is served by secondary and that it's the one from ns1 ($n)"
+echo_i "checking that dom16.example. is no longer served by secondary ($n)"
 ret=0
-wait_for_a @10.53.0.2 dom14.example. dig.out.test$n || ret=1
-grep "192.0.2.1" dig.out.test$n > /dev/null || ret=1
+wait_for_no_soa @10.53.0.2 dom16.example. dig.out.test$n || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
-n=$((n+1))
-echo_i "Adding domain dom14.example. to catalog2 zone with ns3 as primary ($n)"
+nextpart ns2/named.run >/dev/null
+
+echo_i "Reloading secondary ns2 via RNDC ($n)"
 ret=0
-$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
-    server 10.53.0.3 ${PORT}
-    update add 45e3d45ea5f7bd01c395ccbde6ae2e750a3ee8ab.zones.catalog2.example. 3600 IN PTR dom14.example.
-    update add primaries.45e3d45ea5f7bd01c395ccbde6ae2e750a3ee8ab.zones.catalog2.example. 3600 IN A 10.53.0.3
-    send
-END
+rndccmd 10.53.0.2 reload >/dev/null 2>&1 || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
@@ -1992,9 +1992,9 @@ if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
-echo_i "checking that dom14.example. is served by secondary and that it's still the one from ns1 ($n)"
+echo_i "checking that dom16.example. is served by secondary and that it's the one from ns1 ($n)"
 ret=0
-wait_for_a @10.53.0.2 dom14.example. dig.out.test$n || ret=1
+wait_for_a @10.53.0.2 dom16.example. dig.out.test$n || ret=1
 grep "192.0.2.1" dig.out.test$n > /dev/null || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
@@ -2002,12 +2002,12 @@ status=$((status+ret))
 nextpart ns2/named.run >/dev/null
 
 n=$((n+1))
-echo_i "Deleting domain dom14.example. from catalog2 ($n)"
+echo_i "Deleting domain dom16.example. from catalog1 ($n)"
 ret=0
 $NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
-    server 10.53.0.3 ${PORT}
-    update delete 45e3d45ea5f7bd01c395ccbde6ae2e750a3ee8ab.zones.catalog2.example. 3600 IN PTR dom14.example.
-    update delete primaries.45e3d45ea5f7bd01c395ccbde6ae2e750a3ee8ab.zones.catalog2.example. 3600 IN A 10.53.0.3
+    server 10.53.0.1 ${PORT}
+    update delete efe725d0cf430ffb113b9bcf59266f066a21216b.zones.catalog1.example. 3600 IN PTR dom16.example.
+    update delete masters.efe725d0cf430ffb113b9bcf59266f066a21216b.zones.catalog1.example. 3600 IN A 10.53.0.1
     send
 END
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
@@ -2021,129 +2021,117 @@ if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
-echo_i "checking that dom14.example. is served by secondary and that it's still the one from ns1 ($n)"
+echo_i "checking that dom16.example. is no longer served by secondary ($n)"
 ret=0
-wait_for_a @10.53.0.2 dom14.example. dig.out.test$n || ret=1
-grep "192.0.2.1" dig.out.test$n > /dev/null || ret=1
+wait_for_no_soa @10.53.0.2 dom16.example. dig.out.test$n || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 ##########################################################################
-echo_i "Testing changing label for a member zone"
+echo_i "Testing having a regular zone and a zone in catalog zone of the same name"
 n=$((n+1))
-echo_i "checking that dom15.example. is not served by primary ($n)"
+echo_i "checking that dom14.example. is not served by primary ($n)"
 ret=0
-wait_for_no_soa @10.53.0.1 dom15.example. dig.out.test$n || ret=1
+wait_for_no_soa @10.53.0.1 dom14.example. dig.out.test$n || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
-echo_i "Adding a domain dom15.example. to primary ns1 via RNDC ($n)"
+echo_i "Adding a domain dom14.example. to primary ns1 via RNDC ($n)"
 ret=0
-echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns1/dom15.example.db
-echo "@ IN NS invalid." >> ns1/dom15.example.db
-rndccmd 10.53.0.1 addzone dom15.example. in default '{type primary; file "dom15.example.db";};' || ret=1
+echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns1/dom14.example.db
+echo "@ IN NS invalid." >> ns1/dom14.example.db
+echo "@ IN A 192.0.2.1" >> ns1/dom14.example.db
+rndccmd 10.53.0.1 addzone dom14.example. in default '{type primary; file "dom14.example.db";};' || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
-echo_i "checking that dom15.example. is now served by primary ns1 ($n)"
-ret=0
-wait_for_soa @10.53.0.1 dom15.example. dig.out.test$n || ret=1
-if [ $ret -ne 0 ]; then echo_i "failed"; fi
-status=$((status+ret))
-
-nextpart ns2/named.run >/dev/null
-
-echo_i "Adding domain dom15.example. to catalog1 zone with 'dom15label1' label ($n)"
+echo_i "checking that dom14.example. is now served by primary ns1 ($n)"
 ret=0
-$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
-    server 10.53.0.1 ${PORT}
-    update add dom15label1.zones.catalog1.example. 3600 IN PTR dom15.example.
-    send
-END
+wait_for_soa @10.53.0.1 dom14.example. dig.out.test$n || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
-echo_i "waiting for secondary to sync up ($n)"
+echo_i "Adding a domain dom14.example. to primary ns3 via RNDC ($n)"
 ret=0
-wait_for_message ns2/named.run  "catz: update_from_db: new zone merged" || ret=1
+echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns3/dom14.example.db
+echo "@ IN NS invalid." >> ns3/dom14.example.db
+echo "@ IN A 192.0.2.2" >> ns3/dom14.example.db
+rndccmd 10.53.0.3 addzone dom14.example. '{type primary; file "dom14.example.db";};' || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
-sleep 3
-
 n=$((n+1))
-echo_i "checking that dom15.example. is served by secondary ($n)"
+echo_i "checking that dom14.example. is now served by primary ns3 ($n)"
 ret=0
-wait_for_soa @10.53.0.2 dom15.example. dig.out.test$n || ret=1
+wait_for_soa @10.53.0.3 dom14.example. dig.out.test$n || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 nextpart ns2/named.run >/dev/null
 
 n=$((n+1))
-echo_i "Changing label of domain dom15.example. from 'dom15label1' to 'dom15label2' ($n)"
+echo_i "Adding domain dom14.example. with rndc with ns1 as primary ($n)"
 ret=0
-$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
-    server 10.53.0.1 ${PORT}
-    update delete dom15label1.zones.catalog1.example. 3600 IN PTR dom15.example.
-    update add dom15label2.zones.catalog1.example. 3600 IN PTR dom15.example.
-    send
-END
+rndccmd 10.53.0.2 addzone dom14.example. in default '{type secondary; primaries {10.53.0.1;};};' || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
 echo_i "waiting for secondary to sync up ($n)"
 ret=0
-wait_for_message ns2/named.run  "catz: update_from_db: new zone merged" || ret=1
+wait_for_message ns2/named.run  "transfer of 'dom14.example/IN/default' from 10.53.0.1#${PORT}: Transfer status: success" || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
+nextpart ns2/named.run >/dev/null
+
 n=$((n+1))
-echo_i "checking that dom15.example. is served by secondary ($n)"
+echo_i "checking that dom14.example. is served by secondary and that it's the one from ns1 ($n)"
 ret=0
-wait_for_soa @10.53.0.2 dom15.example. dig.out.test$n || ret=1
+wait_for_a @10.53.0.2 dom14.example. dig.out.test$n || ret=1
+grep "192.0.2.1" dig.out.test$n > /dev/null || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
-##########################################################################
-echo_i "Testing recreation of a manually deleted zone after a reload"
 n=$((n+1))
-echo_i "checking that dom16.example. is not served by primary ($n)"
+echo_i "Adding domain dom14.example. to catalog2 zone with ns3 as primary ($n)"
 ret=0
-wait_for_no_soa @10.53.0.1 dom16.example. dig.out.test$n || ret=1
+$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
+    server 10.53.0.3 ${PORT}
+    update add 45e3d45ea5f7bd01c395ccbde6ae2e750a3ee8ab.zones.catalog2.example. 3600 IN PTR dom14.example.
+    update add primaries.45e3d45ea5f7bd01c395ccbde6ae2e750a3ee8ab.zones.catalog2.example. 3600 IN A 10.53.0.3
+    send
+END
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
-echo_i "Adding a domain dom16.example. to primary ns1 via RNDC ($n)"
+echo_i "waiting for secondary to sync up ($n)"
 ret=0
-echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns1/dom16.example.db
-echo "@ IN NS invalid." >> ns1/dom16.example.db
-echo "@ IN A 192.0.2.1" >> ns1/dom16.example.db
-rndccmd 10.53.0.1 addzone dom16.example. in default '{type primary; file "dom16.example.db";};' || ret=1
+wait_for_message ns2/named.run  "catz: update_from_db: new zone merged" || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
-echo_i "checking that dom16.example. is now served by primary ns1 ($n)"
+echo_i "checking that dom14.example. is served by secondary and that it's still the one from ns1 ($n)"
 ret=0
-wait_for_soa @10.53.0.1 dom16.example. dig.out.test$n || ret=1
+wait_for_a @10.53.0.2 dom14.example. dig.out.test$n || ret=1
+grep "192.0.2.1" dig.out.test$n > /dev/null || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 nextpart ns2/named.run >/dev/null
 
 n=$((n+1))
-echo_i "Adding domain dom16.example. to catalog1 zone with ns1 as primary ($n)"
+echo_i "Deleting domain dom14.example. from catalog2 ($n)"
 ret=0
 $NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
-    server 10.53.0.1 ${PORT}
-    update add efe725d0cf430ffb113b9bcf59266f066a21216b.zones.catalog1.example. 3600 IN PTR dom16.example.
-    update add masters.efe725d0cf430ffb113b9bcf59266f066a21216b.zones.catalog1.example. 3600 IN A 10.53.0.1
+    server 10.53.0.3 ${PORT}
+    update delete 45e3d45ea5f7bd01c395ccbde6ae2e750a3ee8ab.zones.catalog2.example. 3600 IN PTR dom14.example.
+    update delete primaries.45e3d45ea5f7bd01c395ccbde6ae2e750a3ee8ab.zones.catalog2.example. 3600 IN A 10.53.0.3
     send
 END
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
@@ -2152,41 +2140,52 @@ status=$((status+ret))
 n=$((n+1))
 echo_i "waiting for secondary to sync up ($n)"
 ret=0
-wait_for_message ns2/named.run  "catz: adding zone 'dom16.example' from catalog 'catalog1.example'" &&
-wait_for_message ns2/named.run  "transfer of 'dom16.example/IN/default' from 10.53.0.1#${PORT}: Transfer status: success" || ret=1
+wait_for_message ns2/named.run  "catz: update_from_db: new zone merged" || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
-nextpart ns2/named.run >/dev/null
-
 n=$((n+1))
-echo_i "checking that dom16.example. is served by secondary and that it's the one from ns1 ($n)"
+echo_i "checking that dom14.example. is served by secondary and that it's still the one from ns1 ($n)"
 ret=0
-wait_for_a @10.53.0.2 dom16.example. dig.out.test$n || ret=1
+wait_for_a @10.53.0.2 dom14.example. dig.out.test$n || ret=1
 grep "192.0.2.1" dig.out.test$n > /dev/null || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
-nextpart ns2/named.run >/dev/null
+##########################################################################
+echo_i "Testing changing label for a member zone"
+n=$((n+1))
+echo_i "checking that dom15.example. is not served by primary ($n)"
+ret=0
+wait_for_no_soa @10.53.0.1 dom15.example. dig.out.test$n || ret=1
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
 
-echo_i "Deleting dom16.example. from secondary ns2 via RNDC ($n)"
+n=$((n+1))
+echo_i "Adding a domain dom15.example. to primary ns1 via RNDC ($n)"
 ret=0
-rndccmd 10.53.0.2 delzone dom16.example. in default >/dev/null 2>&1 || ret=1
+echo "@ 3600 IN SOA . . 1 3600 3600 3600 3600" > ns1/dom15.example.db
+echo "@ IN NS invalid." >> ns1/dom15.example.db
+rndccmd 10.53.0.1 addzone dom15.example. in default '{type primary; file "dom15.example.db";};' || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
-echo_i "checking that dom16.example. is no longer served by secondary ($n)"
+echo_i "checking that dom15.example. is now served by primary ns1 ($n)"
 ret=0
-wait_for_no_soa @10.53.0.2 dom16.example. dig.out.test$n || ret=1
+wait_for_soa @10.53.0.1 dom15.example. dig.out.test$n || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 nextpart ns2/named.run >/dev/null
 
-echo_i "Reloading secondary ns2 via RNDC ($n)"
+echo_i "Adding domain dom15.example. to catalog1 zone with 'dom15label1' label ($n)"
 ret=0
-rndccmd 10.53.0.2 reload >/dev/null 2>&1 || ret=1
+$NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
+    server 10.53.0.1 ${PORT}
+    update add dom15label1.zones.catalog1.example. 3600 IN PTR dom15.example.
+    send
+END
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
@@ -2197,23 +2196,24 @@ wait_for_message ns2/named.run  "catz: update_from_db: new zone merged" || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
+sleep 3
+
 n=$((n+1))
-echo_i "checking that dom16.example. is served by secondary and that it's the one from ns1 ($n)"
+echo_i "checking that dom15.example. is served by secondary ($n)"
 ret=0
-wait_for_a @10.53.0.2 dom16.example. dig.out.test$n || ret=1
-grep "192.0.2.1" dig.out.test$n > /dev/null || ret=1
+wait_for_soa @10.53.0.2 dom15.example. dig.out.test$n || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 nextpart ns2/named.run >/dev/null
 
 n=$((n+1))
-echo_i "Deleting domain dom16.example. from catalog1 ($n)"
+echo_i "Changing label of domain dom15.example. from 'dom15label1' to 'dom15label2' ($n)"
 ret=0
 $NSUPDATE -d <<END >> nsupdate.out.test$n 2>&1 || ret=1
     server 10.53.0.1 ${PORT}
-    update delete efe725d0cf430ffb113b9bcf59266f066a21216b.zones.catalog1.example. 3600 IN PTR dom16.example.
-    update delete masters.efe725d0cf430ffb113b9bcf59266f066a21216b.zones.catalog1.example. 3600 IN A 10.53.0.1
+    update delete dom15label1.zones.catalog1.example. 3600 IN PTR dom15.example.
+    update add dom15label2.zones.catalog1.example. 3600 IN PTR dom15.example.
     send
 END
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
@@ -2227,9 +2227,9 @@ if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
 n=$((n+1))
-echo_i "checking that dom16.example. is no longer served by secondary ($n)"
+echo_i "checking that dom15.example. is served by secondary ($n)"
 ret=0
-wait_for_no_soa @10.53.0.2 dom16.example. dig.out.test$n || ret=1
+wait_for_soa @10.53.0.2 dom15.example. dig.out.test$n || ret=1
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status+ret))