From 60f63ce097c515a45400464cde774844bdc21601 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Fri, 13 Mar 2026 11:13:35 +0100 Subject: [PATCH 1/4] Test showzone and modzone on configured zone Add test cases for 'rndc showzone' and 'rndc modzone' on a zone that was configured in named.conf. This should not crash. (cherry picked from commit 900127c4601382d028af1042db44c36aae54d9fa) --- bin/tests/system/addzone/tests.sh | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/bin/tests/system/addzone/tests.sh b/bin/tests/system/addzone/tests.sh index 45f61d13b2..36426cc23c 100755 --- a/bin/tests/system/addzone/tests.sh +++ b/bin/tests/system/addzone/tests.sh @@ -36,6 +36,26 @@ n=$((n + 1)) if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) +# showzone +echo_i "showzone normally loaded zone ($n)" +ret=0 +$RNDCCMD 10.53.0.2 showzone normal.example >rndc.out.ns2.$n +expected='zone "normal.example" { type primary; file "normal.db"; };' +[ "$(cat rndc.out.ns2.$n)" = "$expected" ] || ret=1 +n=$((n + 1)) +if [ $ret != 0 ]; then echo_i "failed"; fi +status=$((status + ret)) +# modzone +echo_i "modzone normally loaded zone ($n)" +ret=0 +$RNDCCMD 10.53.0.2 modzone normal.example '{ type primary; file "normal.db"; };' >rndc.out.ns2.$n +grep "" rndc.out.ns2.$n >/dev/null || ret=1 +grep "zone 'normal.example' must also be reconfigured in" rndc.out.ns2.$n >/dev/null || ret=1 +grep "named.conf to make changes permanent." rndc.out.ns2.$n >/dev/null || ret=1 +n=$((n + 1)) +if [ $ret != 0 ]; then echo_i "failed"; fi +status=$((status + ret)) + # When LMDB support is compiled in, this tests that migration from # NZF to NZD occurs during named startup echo_i "checking previously added zone ($n)" @@ -263,7 +283,7 @@ status=$((status + ret)) echo_i "delete a normally-loaded zone ($n)" ret=0 $RNDCCMD 10.53.0.2 delzone normal.example >rndc.out.ns2.$n 2>&1 -grep "is no longer active and will be deleted" rndc.out.ns2.$n >/dev/null || ret=11 +grep "is no longer active and will be deleted" rndc.out.ns2.$n >/dev/null || ret=1 grep "To keep it from returning when the server is restarted" rndc.out.ns2.$n >/dev/null || ret=1 grep "must also be removed from named.conf." rndc.out.ns2.$n >/dev/null || ret=1 _check_delete_normally_loaded_zone() ( @@ -271,7 +291,6 @@ _check_delete_normally_loaded_zone() ( && grep 'status: REFUSED' dig.out.ns2.$n >/dev/null ) retry_quiet 5 _check_delete_normally_loaded_zone || ret=1 - n=$((n + 1)) if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) From 4a6509582320916b4d3e538dbdbabfba9f98acbb Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Fri, 13 Mar 2026 11:52:47 +0100 Subject: [PATCH 2/4] Only lock view->newzone.lock if not already locked Some code paths try to lock an already locked view->newzone.lock. For example, do_modzone() aqcuires the lock and then calls delete_zoneconf(), that wants to acquire the same lock. Add a parameter to delete_zoneconf() that informs the function if the lock has already been acquired. (cherry picked from commit 71587b0816a9458895aaa14a85539acd91afda38) --- bin/named/server.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index 796b4cc97e..d2ac553ffc 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -13863,7 +13863,7 @@ cleanup: static isc_result_t delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx, const cfg_obj_t *config, - const dns_name_t *zname, nzfwriter_t nzfwriter) { + const dns_name_t *zname, nzfwriter_t nzfwriter, bool locked) { isc_result_t result = ISC_R_NOTFOUND; const cfg_listelt_t *elt = NULL; const cfg_obj_t *zl = NULL; @@ -13876,7 +13876,9 @@ delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx, const cfg_obj_t *config, REQUIRE(config != NULL); REQUIRE(zname != NULL); - LOCK(&view->new_zone_lock); + if (!locked) { + LOCK(&view->new_zone_lock); + } cfg_map_get(config, "zone", &zl); @@ -13917,7 +13919,9 @@ delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx, const cfg_obj_t *config, } cleanup: - UNLOCK(&view->new_zone_lock); + if (!locked) { + UNLOCK(&view->new_zone_lock); + } return result; } @@ -13927,13 +13931,13 @@ do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view, bool redirect, isc_buffer_t **text) { isc_result_t result, tresult; dns_zone_t *zone = NULL; + bool locked = false; #ifndef HAVE_LMDB FILE *fp = NULL; bool cleanup_config = false; #else /* HAVE_LMDB */ MDB_txn *txn = NULL; MDB_dbi dbi; - bool locked = false; UNUSED(zoneconf); #endif @@ -14080,7 +14084,7 @@ cleanup: } if (result != ISC_R_SUCCESS && cleanup_config) { tresult = delete_zoneconf(view, cfg->add_parser, - cfg->nzf_config, name, NULL); + cfg->nzf_config, name, NULL, locked); RUNTIME_CHECK(tresult == ISC_R_SUCCESS); } #else /* HAVE_LMDB */ @@ -14106,13 +14110,13 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view, isc_result_t result, tresult; dns_zone_t *zone = NULL; bool added; + bool locked = false; #ifndef HAVE_LMDB FILE *fp = NULL; cfg_obj_t *z; #else /* HAVE_LMDB */ MDB_txn *txn = NULL; MDB_dbi dbi; - bool locked = false; #endif /* HAVE_LMDB */ /* Zone must already exist */ @@ -14202,7 +14206,7 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view, if (added) { result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config, dns_zone_getorigin(zone), - nzf_writeconf); + nzf_writeconf, locked); if (result != ISC_R_SUCCESS) { TCHECK(putstr(text, "former zone configuration " "not deleted: ")); @@ -14216,13 +14220,13 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view, if (cfg->vconfig == NULL) { result = delete_zoneconf( view, cfg->conf_parser, cfg->config, - dns_zone_getorigin(zone), NULL); + dns_zone_getorigin(zone), NULL, locked); } else { const cfg_obj_t *voptions = cfg_tuple_get(cfg->vconfig, "options"); result = delete_zoneconf( view, cfg->conf_parser, voptions, - dns_zone_getorigin(zone), NULL); + dns_zone_getorigin(zone), NULL, locked); } if (result != ISC_R_SUCCESS) { @@ -14504,7 +14508,7 @@ rmzone(void *arg) { #else /* ifdef HAVE_LMDB */ result = delete_zoneconf(view, cfg->add_parser, cfg->nzf_config, dns_zone_getorigin(zone), - nzf_writeconf); + nzf_writeconf, false); if (result != ISC_R_SUCCESS) { isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, @@ -14520,11 +14524,11 @@ rmzone(void *arg) { "options"); result = delete_zoneconf( view, cfg->conf_parser, voptions, - dns_zone_getorigin(zone), NULL); + dns_zone_getorigin(zone), NULL, false); } else { result = delete_zoneconf( view, cfg->conf_parser, cfg->config, - dns_zone_getorigin(zone), NULL); + dns_zone_getorigin(zone), NULL, false); } if (result != ISC_R_SUCCESS) { isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, From 7e30d16e9345026227a0d29af3cefc7d0e082de1 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Fri, 13 Mar 2026 11:56:31 +0100 Subject: [PATCH 3/4] Don't call dns_zone_setadded() on modify If we are modifiying the zone, the zone must have been added before. Don't overwrite this value on modifications. Also it feels cleaner to pass added=false to configure_zone() in do_modzone(). (cherry picked from commit 780872e07eaa735c215765da570d2f1f78bfade7) --- bin/named/server.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index d2ac553ffc..09cf436627 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -7026,7 +7026,9 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, /* * Mark whether the zone was originally added at runtime or not */ - dns_zone_setadded(zone, added); + if (!modify) { + dns_zone_setadded(zone, added); + } /* * Determine if we need to set up inline signing. @@ -14179,7 +14181,7 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view, dns_view_thaw(view); result = configure_zone(cfg->config, zoneobj, cfg->vconfig, view, &server->viewlist, &server->kasplist, - &server->keystorelist, cfg->actx, true, false, + &server->keystorelist, cfg->actx, false, false, false, true); dns_view_freeze(view); From 85453d393d1b591ae1108603308c79dd63acca85 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Tue, 17 Mar 2026 09:29:10 +0100 Subject: [PATCH 4/4] Store zone config also on modzone 'rndc modzone' deletes the old configuration. If we don't store the new zone config, when we do a 'rndc showzone' it will be a failure. This is not an issue in the 9.21 version, because of the effective config behavior. --- bin/named/server.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bin/named/server.c b/bin/named/server.c index 09cf436627..37d4ba92e8 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -14298,6 +14298,18 @@ do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view, TCHECK(putstr(text, zname)); TCHECK(putstr(text, "' reconfigured.")); } else { +#ifdef HAVE_LMDB + CHECK(nzd_open(view, 0, &txn, &dbi)); + CHECK(nzd_save(&txn, dbi, zone, zoneobj)); +#else /* ifdef HAVE_LMDB */ + result = nzf_append(view, zoneobj); + if (result != ISC_R_SUCCESS) { + TCHECK(putstr(text, "\nNew zone config not saved: ")); + TCHECK(putstr(text, isc_result_totext(result))); + goto cleanup; + } +#endif /* HAVE_LMDB */ + TCHECK(putstr(text, "zone '")); TCHECK(putstr(text, zname)); TCHECK(putstr(text, "' must also be reconfigured in\n"));