PKG_NAME:=bind
PKG_VERSION:=9.20.18
-PKG_RELEASE:=1
+PKG_RELEASE:=2
USERID:=bind=57:bind=57
PKG_MAINTAINER:=Noah Meyerhans <frodo@morgul.net>
--- /dev/null
+From 6e1450ef0f9d66679587092cef2e83e6deb1575f Mon Sep 17 00:00:00 2001
+From: Mark Andrews <marka@isc.org>
+Date: Tue, 2 Dec 2025 11:02:34 +1100
+Subject: [PATCH 1/4] Allow rndc addzone to replace automatic empty zones
+
+Check if the found zone is an automatic zone and if so remove it
+from the view prior to adding the new zone. If the addzone fails
+restore the automatic zone to the view.
+---
+ bin/named/server.c | 34 +++++++++++++++++++++++++++++++++-
+ lib/dns/view.c | 4 +++-
+ 2 files changed, 36 insertions(+), 2 deletions(-)
+
+--- a/bin/named/server.c
++++ b/bin/named/server.c
+@@ -13946,6 +13946,7 @@ do_addzone(named_server_t *server, ns_cf
+ bool redirect, isc_buffer_t **text) {
+ isc_result_t result, tresult;
+ dns_zone_t *zone = NULL;
++ dns_zone_t *oldzone = NULL;
+ #ifndef HAVE_LMDB
+ FILE *fp = NULL;
+ bool cleanup_config = false;
+@@ -13964,7 +13965,13 @@ do_addzone(named_server_t *server, ns_cf
+ } else {
+ result = dns_view_findzone(view, name, DNS_ZTFIND_EXACT, &zone);
+ if (result == ISC_R_SUCCESS) {
+- result = ISC_R_EXISTS;
++ if (dns_zone_getautomatic(zone)) {
++ oldzone = zone;
++ zone = NULL;
++ result = ISC_R_NOTFOUND;
++ } else {
++ result = ISC_R_EXISTS;
++ }
+ }
+ }
+ if (result != ISC_R_NOTFOUND) {
+@@ -13973,6 +13980,10 @@ do_addzone(named_server_t *server, ns_cf
+
+ isc_loopmgr_pause(named_g_loopmgr);
+
++ if (oldzone != NULL) {
++ dns_view_delzone(view, oldzone);
++ }
++
+ #ifndef HAVE_LMDB
+ /*
+ * Make sure we can open the configuration save file
+@@ -14077,6 +14088,11 @@ do_addzone(named_server_t *server, ns_cf
+ /* Remove the zone from the zone table */
+ dns_view_delzone(view, zone);
+ goto cleanup;
++ } else if (oldzone != NULL) {
++ /*
++ * We no longer need to keep the old zone around.
++ */
++ dns_zone_detach(&oldzone);
+ }
+
+ /* Flag the zone as having been added at runtime */
+@@ -14093,6 +14109,22 @@ do_addzone(named_server_t *server, ns_cf
+
+ cleanup:
+
++ if (oldzone != NULL) {
++ /*
++ * Restore the old zone.
++ */
++ dns_view_thaw(view);
++ tresult = dns_view_addzone(view, oldzone);
++ dns_view_freeze(view);
++ dns_zone_detach(&oldzone);
++
++ if (tresult != ISC_R_SUCCESS && tresult != ISC_R_SHUTTINGDOWN) {
++ TCHECK(putstr(text, "\nUnable to restore automatic "
++ "empty zone: "));
++ TCHECK(putstr(text, isc_result_totext(result)));
++ }
++ }
++
+ #ifndef HAVE_LMDB
+ if (fp != NULL) {
+ (void)isc_stdio_close(fp);
+--- a/lib/dns/view.c
++++ b/lib/dns/view.c
+@@ -778,7 +778,9 @@ dns_view_delzone(dns_view_t *view, dns_z
+
+ REQUIRE(DNS_VIEW_VALID(view));
+
+- dns_zone_prepare_shutdown(zone);
++ if (!dns_zone_getautomatic(zone)) {
++ dns_zone_prepare_shutdown(zone);
++ }
+
+ rcu_read_lock();
+ zonetable = rcu_dereference(view->zonetable);
--- /dev/null
+From cb9cb3c8d9f1c8e5e6a0fb55fea8dba43ea5d529 Mon Sep 17 00:00:00 2001
+From: Mark Andrews <marka@isc.org>
+Date: Tue, 2 Dec 2025 11:05:51 +1100
+Subject: [PATCH 2/4] Check if adding new zone can replace an automatic empty
+ zone
+
+---
+ bin/tests/system/addzone/ns6/added.db | 25 ++++++++++++++
+ bin/tests/system/addzone/ns6/named.conf.j2 | 40 ++++++++++++++++++++++
+ bin/tests/system/addzone/tests.sh | 29 ++++++++++++++++
+ 3 files changed, 94 insertions(+)
+ create mode 100644 bin/tests/system/addzone/ns6/added.db
+ create mode 100644 bin/tests/system/addzone/ns6/named.conf.j2
+
+--- /dev/null
++++ b/bin/tests/system/addzone/ns6/added.db
+@@ -0,0 +1,25 @@
++; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
++;
++; SPDX-License-Identifier: MPL-2.0
++;
++; This Source Code Form is subject to the terms of the Mozilla Public
++; License, v. 2.0. If a copy of the MPL was not distributed with this
++; file, you can obtain one at https://mozilla.org/MPL/2.0/.
++;
++; See the COPYRIGHT file distributed with this work for additional
++; information regarding copyright ownership.
++
++$TTL 300 ; 5 minutes
++@ IN SOA mname1. . (
++ 1 ; serial
++ 20 ; refresh (20 seconds)
++ 20 ; retry (20 seconds)
++ 1814400 ; expire (3 weeks)
++ 3600 ; minimum (1 hour)
++ )
++ NS ns2
++ns2 A 10.53.0.2
++ MX 10 mail
++
++a A 10.0.0.1
++mail A 10.0.0.2
+--- /dev/null
++++ b/bin/tests/system/addzone/ns6/named.conf.j2
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
++ *
++ * SPDX-License-Identifier: MPL-2.0
++ *
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
++ *
++ * See the COPYRIGHT file distributed with this work for additional
++ * information regarding copyright ownership.
++ */
++
++options {
++ port @PORT@;
++ pid-file "named.pid";
++ listen-on { 10.53.0.6; };
++ listen-on-v6 { none; };
++ allow-query { any; };
++ recursion yes;
++ allow-new-zones yes;
++ dnssec-validation no;
++};
++
++include "../../_common/rndc.key";
++
++controls {
++ inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
++};
++
++template primary {
++ type primary;
++ file "$view-$name.db";
++ initial-file "added.db";
++};
++
++zone "." {
++ type hint;
++ file "../../_common/root.hint";
++};
+--- a/bin/tests/system/addzone/tests.sh
++++ b/bin/tests/system/addzone/tests.sh
+@@ -68,6 +68,35 @@ n=$((n + 1))
+ if [ $ret != 0 ]; then echo_i "failed"; fi
+ status=$((status + ret))
+
++echo_i "adding new zone which replaces an automatic empty zone ($n)"
++ret=0
++$DIG $DIGOPTS @10.53.0.6 168.192.in-addr.arpa SOA >dig.out.pre.$n || ret=1
++grep 'status: NOERROR' dig.out.pre.$n >/dev/null || ret=1
++grep '168\.192\.in-addr\.arpa\..86400.IN.SOA.168\.192\.IN-ADDR\.ARPA\. \. 0 28800 7200 604800 86400' dig.out.pre.$n >/dev/null || ret=1
++$RNDCCMD 10.53.0.6 addzone '168.192.in-addr.arpa { type primary; file "added.db"; };' 2>&1 | sed 's/^/I:ns6 /'
++_check_adding_new_zone() (
++ $DIG $DIGOPTS @10.53.0.6 a.168.192.in-addr.arpa a >dig.out.ns6.$n \
++ && grep 'status: NOERROR' dig.out.ns6.$n >/dev/null \
++ && grep '^a.168.192.in-addr.arpa' dig.out.ns6.$n >/dev/null
++)
++retry_quiet 10 _check_adding_new_zone || ret=1
++n=$((n + 1))
++if [ $ret != 0 ]; then echo_i "failed"; fi
++status=$((status + ret))
++
++echo_i "adding new zone which replaces an automatic empty zone with bad file ($n)"
++ret=0
++$DIG $DIGOPTS @10.53.0.6 10.in-addr.arpa SOA >dig.out.pre.$n || ret=1
++grep 'status: NOERROR' dig.out.pre.$n >/dev/null || ret=1
++grep '10\.in-addr\.arpa\..86400.IN.SOA.10\.IN-ADDR\.ARPA\. \. 0 28800 7200 604800 86400' dig.out.pre.$n >/dev/null || ret=1
++$RNDCCMD 10.53.0.6 addzone '10.in-addr.arpa { type primary; file "bad.db"; };' 2>&1 | sed 's/^/I:ns6 /'
++$DIG $DIGOPTS @10.53.0.6 10.in-addr.arpa SOA >dig.out.post.$n || ret=1
++grep 'status: NOERROR' dig.out.post.$n >/dev/null || ret=1
++grep '10\.in-addr\.arpa\..86400.IN.SOA.10\.IN-ADDR\.ARPA\. \. 0 28800 7200 604800 86400' dig.out.post.$n >/dev/null || ret=1
++n=$((n + 1))
++if [ $ret != 0 ]; then echo_i "failed"; fi
++status=$((status + ret))
++
+ nextpart ns2/named.run >/dev/null
+ echo_i "checking addzone errors are logged correctly"
+ ret=0
--- /dev/null
+From 6cea04633d2461456d30cbdd69695ca0da540b4f Mon Sep 17 00:00:00 2001
+From: Mark Andrews <marka@isc.org>
+Date: Tue, 9 Dec 2025 15:51:34 +1100
+Subject: [PATCH 3/4] Document rndc addzone with automatic empty zones
+
+---
+ bin/rndc/rndc.rst | 27 ++++++++++++++-------------
+ 1 file changed, 14 insertions(+), 13 deletions(-)
+
+--- a/bin/rndc/rndc.rst
++++ b/bin/rndc/rndc.rst
+@@ -129,18 +129,19 @@ Currently supported commands are:
+ .. option:: addzone zone [class [view]] configuration
+
+ This command adds a zone while the server is running. This command
+- requires the ``allow-new-zones`` option to be set to ``yes``. The
+- configuration string specified on the command line is the zone
+- configuration text that would ordinarily be placed in :iscman:`named.conf`.
++ requires the ``allow-new-zones`` option to be set to ``yes``.
++ The configuration string specified on the command line is the
++ zone configuration text that would ordinarily be placed in
++ :iscman:`named.conf`. Automatic empty zones will be replaced.
+
+- The configuration is saved in a file called ``viewname.nzf`` (or, if
+- :iscman:`named` is compiled with liblmdb, an LMDB database file called
+- ``viewname.nzd``). ``viewname`` is the name of the view, unless the view
+- name contains characters that are incompatible with use as a file
+- name, in which case a cryptographic hash of the view name is used
+- instead. When :iscman:`named` is restarted, the file is loaded into
+- the view configuration so that zones that were added can persist
+- after a restart.
++ The configuration is saved in a file called ``viewname.nzf``
++ (or, if :iscman:`named` is compiled with liblmdb, an LMDB database
++ file called ``viewname.nzd``). ``viewname`` is the name of the
++ view, unless the view name contains characters that are incompatible
++ with use as a file name, in which case a cryptographic hash of
++ the view name is used instead. When :iscman:`named` is restarted,
++ the file is loaded into the view configuration so that zones
++ that were added can persist after a restart.
+
+ This sample ``addzone`` command adds the zone ``example.com`` to
+ the default view:
--- /dev/null
+From be735c1b5e12117039ac64f802e30b075987dd22 Mon Sep 17 00:00:00 2001
+From: Matthijs Mekking <matthijs@isc.org>
+Date: Thu, 11 Dec 2025 15:14:55 +0100
+Subject: [PATCH 4/4] fixup! Check if adding new zone can replace an automatic
+ empty zone
+
+---
+ bin/tests/system/addzone/tests.sh | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/bin/tests/system/addzone/tests.sh
++++ b/bin/tests/system/addzone/tests.sh
+@@ -84,6 +84,23 @@ n=$((n + 1))
+ if [ $ret != 0 ]; then echo_i "failed"; fi
+ status=$((status + ret))
+
++echo_i "deleting zone which replaced an automatic empty zone ($n)"
++ret=0
++$DIG $DIGOPTS @10.53.0.6 a.168.192.in-addr.arpa a >dig.out.pre.$n || ret=1
++grep 'status: NOERROR' dig.out.pre.$n >/dev/null || ret=1
++grep '^a.168.192.in-addr.arpa' dig.out.pre.$n >/dev/null || ret=1
++$RNDCCMD 10.53.0.6 delzone '168.192.in-addr.arpa' 2>&1 | sed 's/^/I:ns6 /'
++_check_removing_new_zone() (
++ DIGOPTS2="+tcp +nosea +nostat +nocmd +norec +noauth +noadd +nostats +dnssec -p ${PORT}"
++ $DIG $DIGOPTS2 @10.53.0.6 168.192.in-addr.arpa SOA >dig.out.ns6.$n \
++ && grep 'status: NOERROR' dig.out.ns6.$n >/dev/null \
++ && grep '168\.192\.in-addr\.arpa\..86400.IN.SOA.168\.192\.IN-ADDR\.ARPA\. \. 0 28800 7200 604800 86400' dig.out.ns6.$n >/dev/null
++)
++retry_quiet 10 _check_removing_new_zone || ret=1
++n=$((n + 1))
++if [ $ret != 0 ]; then echo_i "failed"; fi
++status=$((status + ret))
++
+ echo_i "adding new zone which replaces an automatic empty zone with bad file ($n)"
+ ret=0
+ $DIG $DIGOPTS @10.53.0.6 10.in-addr.arpa SOA >dig.out.pre.$n || ret=1