]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
test for auth+res server and glues in delegation
authorColin Vidal <colin@isc.org>
Fri, 27 Mar 2026 15:00:25 +0000 (16:00 +0100)
committerColin Vidal <colin@isc.org>
Mon, 30 Mar 2026 18:41:13 +0000 (20:41 +0200)
When a resolver+auth server has a delegation on a local zone and has a
glue, the glue can only be for in-domain NS.

In this case, when the resolver is looking at the zonecut,
`dns_view_bestzonecut()` synthesizes a delegset from an NS rdataset
found in the local zone (the delegation inside auth zone), and ignores
the glues if any.

As a result, the delegset will contain a single delegation of type
DNS_DELEGTYPE_NS_NAMES, which leads to an ADB fetch. But it's actually an
in-memory fetch, because in this case, the fetch will immediately find
the A/AAAA glues from the local zone.

An alternative approach (not chosen here) would be to make
`dns_view_bestzonecut()`, when converting an NS rdataset into a
`dns_deleg_t`, check for glues for the delegation in the auth zone, and
add those in the `dns_deleg_t`. The delegation would be of type
DNS_DELEGTYPE_NS_GLUES which would avoid the ADB name lookup.

However, that's extra code, extra logic and complexities, for a lookup
that will be done in memory anyway, just a bit later. So for now, this
is not implemented that way.

The test is added, however, to confirm that there is no attempt from the
resolver to get the NS fron the child zone.

bin/tests/system/auth_res_deleg/README [new file with mode: 0644]
bin/tests/system/auth_res_deleg/ns1/named.conf.j2 [new file with mode: 0644]
bin/tests/system/auth_res_deleg/ns1/root.db [new file with mode: 0644]
bin/tests/system/auth_res_deleg/ns2/example.db [new file with mode: 0644]
bin/tests/system/auth_res_deleg/ns2/named.conf.j2 [new file with mode: 0644]
bin/tests/system/auth_res_deleg/ns3/named.conf.j2 [new file with mode: 0644]
bin/tests/system/auth_res_deleg/ns3/sub.example.db [new file with mode: 0644]
bin/tests/system/auth_res_deleg/tests_auth_res_deleg.py [new file with mode: 0644]
lib/dns/view.c
lib/ns/query.c

diff --git a/bin/tests/system/auth_res_deleg/README b/bin/tests/system/auth_res_deleg/README
new file mode 100644 (file)
index 0000000..cc05165
--- /dev/null
@@ -0,0 +1,12 @@
+ns1 simulates a root server
+
+ns2 is an auth server (over example.) which is also a resolver.
+
+ns3 is an auth server on `sub.example.`.
+
+The point of the test is to show that because ns2 knows the IP address of the
+NS delegating sub.example., there won't be any queries to resolve
+ns.sub.example.
+
+In order to prove it, ns2 also does a DNSTAP dump of its outgoing queries  and
+checks there is no NS queries to ns3 (but only an AAAA query).
diff --git a/bin/tests/system/auth_res_deleg/ns1/named.conf.j2 b/bin/tests/system/auth_res_deleg/ns1/named.conf.j2
new file mode 100644 (file)
index 0000000..41a46be
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 {
+       query-source address 10.53.0.1;
+       notify-source 10.53.0.1;
+       transfer-source 10.53.0.1;
+       port @PORT@;
+       pid-file "named.pid";
+       listen-on { 10.53.0.1; };
+       listen-on-v6 { none; };
+       recursion no;
+       notify yes;
+       dnssec-validation no;
+};
+
+zone "." {
+       type primary;
+       file "root.db";
+};
diff --git a/bin/tests/system/auth_res_deleg/ns1/root.db b/bin/tests/system/auth_res_deleg/ns1/root.db
new file mode 100644 (file)
index 0000000..4613a4e
--- /dev/null
@@ -0,0 +1,24 @@
+; 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
+.                      IN SOA  a.root.servers.nil. a.root.servers.nil. (
+                               2000042100      ; serial
+                               600             ; refresh
+                               600             ; retry
+                               1200            ; expire
+                               600             ; minimum
+                               )
+.                      NS      a.root-servers.nil.
+a.root-servers.nil.    A       10.53.0.1
+
+example.               NS      ns.example.
+ns.example.            A       10.53.0.2
diff --git a/bin/tests/system/auth_res_deleg/ns2/example.db b/bin/tests/system/auth_res_deleg/ns2/example.db
new file mode 100644 (file)
index 0000000..e7d388b
--- /dev/null
@@ -0,0 +1,24 @@
+; 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
+@                      IN SOA  example. example. (
+                               2000042100      ; serial
+                               600             ; refresh
+                               600             ; retry
+                               1200            ; expire
+                               600             ; minimum
+                               )
+@                      NS      ns.example.
+ns.example.            A       10.53.0.2
+
+sub.example.           NS      ns.sub.example.
+ns.sub.example.                A       10.53.0.3
diff --git a/bin/tests/system/auth_res_deleg/ns2/named.conf.j2 b/bin/tests/system/auth_res_deleg/ns2/named.conf.j2
new file mode 100644 (file)
index 0000000..dbd8a99
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 {
+       query-source address 10.53.0.2;
+       notify-source 10.53.0.2;
+       transfer-source 10.53.0.2;
+       port @PORT@;
+       pid-file "named.pid";
+       listen-on { 10.53.0.2; };
+       listen-on-v6 { none; };
+       recursion yes;
+       notify yes;
+       dnssec-validation no;
+       dnstap { resolver query; };
+       dnstap-output file "dnstap.out";
+};
+
+zone "." {
+       type primary;
+       file "example.db";
+};
+
+key rndc_key {
+       secret "1234abcd8765";
+       algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+       inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
diff --git a/bin/tests/system/auth_res_deleg/ns3/named.conf.j2 b/bin/tests/system/auth_res_deleg/ns3/named.conf.j2
new file mode 100644 (file)
index 0000000..503891d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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 {
+       query-source address 10.53.0.3;
+       notify-source 10.53.0.3;
+       transfer-source 10.53.0.3;
+       port @PORT@;
+       pid-file "named.pid";
+       listen-on { 10.53.0.3; };
+       listen-on-v6 { none; };
+       recursion no;
+       notify yes;
+       dnssec-validation no;
+};
+
+zone "." {
+       type primary;
+       file "sub.example.db";
+};
diff --git a/bin/tests/system/auth_res_deleg/ns3/sub.example.db b/bin/tests/system/auth_res_deleg/ns3/sub.example.db
new file mode 100644 (file)
index 0000000..da53af6
--- /dev/null
@@ -0,0 +1,23 @@
+; 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
+@                      IN SOA  sub.example. sub.example. (
+                               2000042100      ; serial
+                               600             ; refresh
+                               600             ; retry
+                               1200            ; expire
+                               600             ; minimum
+                               )
+@                      NS      ns.sub.example.
+ns.sub.example.                A       10.53.0.3
+
+aaaa.sub.example.      AAAA    ac::dc
diff --git a/bin/tests/system/auth_res_deleg/tests_auth_res_deleg.py b/bin/tests/system/auth_res_deleg/tests_auth_res_deleg.py
new file mode 100644 (file)
index 0000000..3656dc3
--- /dev/null
@@ -0,0 +1,48 @@
+# 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.
+
+import os
+
+import isctest
+import isctest.mark
+
+pytestmark = [isctest.mark.with_dnstap]
+
+
+def line_to_query(line):
+    # dnstap-read output line example
+    # 05-Feb-2026 11:00:57.853 RQ 10.53.0.6:38507 -> 10.53.0.3:22047 TCP 56b fooXXX.example./IN/NS
+    _, _, _, _, _, _, _, _, query = line.split(" ", 9)
+    return query
+
+
+def extract_dnstap(ns):
+    ns.rndc("dnstap -roll 1")
+    path = os.path.join(ns.identifier, "dnstap.out.0")
+    dnstapread = isctest.run.cmd(
+        [isctest.vars.ALL["DNSTAPREAD"], path],
+    )
+
+    lines = dnstapread.out.splitlines()
+    return list(map(line_to_query, lines))
+
+
+def test_auth_res_deleg(ns2):
+    msg = isctest.query.create("aaaa.sub.example.", "AAAA")
+    res = isctest.query.udp(msg, ns2.ip)
+    isctest.check.noerror(res)
+    assert len(res.answer[0]) == 1
+    res.answer[0].ttl = 300
+    assert str(res.answer[0]) == "aaaa.sub.example. 300 IN AAAA ac::dc"
+
+    queries = extract_dnstap(ns2)
+    assert len(queries) == 1
+    assert queries[0] == "aaaa.sub.example/IN/AAAA"
index 9f18357a244e6e67c295ded073982e69df06341a..2e4853d928b533a662688b14c04d9707ca5e92a9 100644 (file)
@@ -1180,7 +1180,17 @@ dns_view_bestzonecut(dns_view_t *view, const dns_name_t *name,
        if (result != ISC_R_SUCCESS) {
                result = DNS_R_NXDOMAIN;
        } else {
-               dns_delegset_fromrdataset(rdataset, delegsetp);
+               /*
+                * The rdataset came either from a local zone or a hint. Either
+                * way, we only considering the NS rdataset here, so if there
+                * are glues, they'll be ignored. This is okay: the delegation
+                * type will be DNS_DELEGSET_NS_NAMES, so ADB will do a NS name
+                * lookup but immediately find the results locally (because this
+                * came from a local zone or hint). So the resolution will be
+                * the same, and this avoid adding extra code here to extract
+                * A/AAAA rdataset if any.
+                */
+               dns_delegset_fromnsrdataset(rdataset, delegsetp);
        }
 
        dns_rdataset_cleanup(rdataset);
index d59d1f6f73dd76dca4858096ee0385ce602569aa..4deeda60742c20987b0da36ad99ce8d3b1e0246e 100644 (file)
@@ -8668,7 +8668,7 @@ query_delegation_recurse(query_ctx_t *qctx) {
                                               qctx->client->inner.now, 0, true,
                                               true, &delegset);
                if (tresult != ISC_R_SUCCESS) {
-                       dns_delegset_fromrdataset(qctx->rdataset, &delegset);
+                       dns_delegset_fromnsrdataset(qctx->rdataset, &delegset);
                        fname = qctx->fname;
                }