]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add test coverage for nameserver processing limits
authorColin Vidal <colin@isc.org>
Wed, 25 Feb 2026 18:01:22 +0000 (19:01 +0100)
committerOndřej Surý <ondrej@sury.org>
Thu, 26 Feb 2026 05:57:54 +0000 (06:57 +0100)
Introduce a new system test (nsprocessinglimit) to verify that the
resolver strictly respects outgoing network fetch quotas when presented
with heavily delegated, unresponsive zones.

This test acts as a regression check for the recent Fisher-Yates nameserver
selection refactor.  It sets up an authoritative server delegating a zone
to 23 distinct nameservers (all pointing to unresponsive loopback IPs).

Using dnstap, the test forces a resolution failure and verifies that:
1. The resolver successfully traverses the zone delegation path.
2. The resolver caps the outgoing network queries to the delegated
   nameservers exactly at the processing limit (20 fetches), ensuring
   array boundaries and dynamic fetch quotas are strictly enforced without
   crashing or hanging.

bin/tests/system/nsprocessinglimit/ns1/named.conf.j2 [new file with mode: 0644]
bin/tests/system/nsprocessinglimit/ns1/root.db [new file with mode: 0644]
bin/tests/system/nsprocessinglimit/ns2/named.conf.j2 [new file with mode: 0644]
bin/tests/system/nsprocessinglimit/ns2/tld.db [new file with mode: 0644]
bin/tests/system/nsprocessinglimit/ns3/example.tld.db [new file with mode: 0644]
bin/tests/system/nsprocessinglimit/ns3/named.conf.j2 [new file with mode: 0644]
bin/tests/system/nsprocessinglimit/ns4/named.args [new file with mode: 0644]
bin/tests/system/nsprocessinglimit/ns4/named.conf.j2 [new file with mode: 0644]
bin/tests/system/nsprocessinglimit/ns4/root.hint [new file with mode: 0644]
bin/tests/system/nsprocessinglimit/tests_nsprocessinglimit.py [new file with mode: 0644]

diff --git a/bin/tests/system/nsprocessinglimit/ns1/named.conf.j2 b/bin/tests/system/nsprocessinglimit/ns1/named.conf.j2
new file mode 100644 (file)
index 0000000..5ad42a1
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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; };
+       recursion no;
+       dnssec-validation no;
+};
+
+view "default" {
+       zone "." {
+               type primary;
+               file "root.db";
+       };
+};
+
+key rndc_key {
+       secret "1234abcd8765";
+       algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+       inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
diff --git a/bin/tests/system/nsprocessinglimit/ns1/root.db b/bin/tests/system/nsprocessinglimit/ns1/root.db
new file mode 100644 (file)
index 0000000..41c97bf
--- /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  marka.isc.org. a.root.servers.nil. (
+                               2010    ; serial
+                               600             ; refresh
+                               600             ; retry
+                               1200            ; expire
+                               600             ; minimum
+                               )
+.                      NS      a.root-servers.nil.
+a.root-servers.nil.    A       10.53.0.1
+
+tld.                   NS      ns.tld.
+ns.tld.                A       10.53.0.2
diff --git a/bin/tests/system/nsprocessinglimit/ns2/named.conf.j2 b/bin/tests/system/nsprocessinglimit/ns2/named.conf.j2
new file mode 100644 (file)
index 0000000..8851c37
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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; };
+       recursion no;
+       dnssec-validation no;
+};
+
+zone "tld." {
+       type primary;
+       file "tld.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/nsprocessinglimit/ns2/tld.db b/bin/tests/system/nsprocessinglimit/ns2/tld.db
new file mode 100644 (file)
index 0000000..003fa08
--- /dev/null
@@ -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
+tld.                   IN SOA  marka.isc.org. ns.tld. (
+                               2010    ; serial
+                               600             ; refresh
+                               600             ; retry
+                               1200            ; expire
+                               600             ; minimum
+                               )
+tld.                   NS      ns.tld.
+ns.tld.                A       10.53.0.2
+
+example.tld.           NS      ns.example.tld.
+ns.example.tld.                A       10.53.0.3
+
diff --git a/bin/tests/system/nsprocessinglimit/ns3/example.tld.db b/bin/tests/system/nsprocessinglimit/ns3/example.tld.db
new file mode 100644 (file)
index 0000000..48f6219
--- /dev/null
@@ -0,0 +1,68 @@
+; 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
+example.tld.           IN SOA  marka.isc.org. ns.dnshoster.tld. (
+                               2010    ; serial
+                               600             ; refresh
+                               600             ; retry
+                               1200            ; expire
+                               600             ; minimum
+                               )
+example.tld.                   NS      ns.example.tld.
+ns.example.tld.                        A       10.53.0.3
+sub.example.tld.               NS      ns01.sub.example.tld.
+sub.example.tld.               NS      ns02.sub.example.tld.
+sub.example.tld.               NS      ns03.sub.example.tld.
+sub.example.tld.               NS      ns04.sub.example.tld.
+sub.example.tld.               NS      ns05.sub.example.tld.
+sub.example.tld.               NS      ns06.sub.example.tld.
+sub.example.tld.               NS      ns07.sub.example.tld.
+sub.example.tld.               NS      ns08.sub.example.tld.
+sub.example.tld.               NS      ns09.sub.example.tld.
+sub.example.tld.               NS      ns10.sub.example.tld.
+sub.example.tld.               NS      ns11.sub.example.tld.
+sub.example.tld.               NS      ns12.sub.example.tld.
+sub.example.tld.               NS      ns12.sub.example.tld.
+sub.example.tld.               NS      ns12.sub.example.tld.
+sub.example.tld.               NS      ns13.sub.example.tld.
+sub.example.tld.               NS      ns14.sub.example.tld.
+sub.example.tld.               NS      ns15.sub.example.tld.
+sub.example.tld.               NS      ns16.sub.example.tld.
+sub.example.tld.               NS      ns17.sub.example.tld.
+sub.example.tld.               NS      ns18.sub.example.tld.
+sub.example.tld.               NS      ns19.sub.example.tld.
+sub.example.tld.               NS      ns20.sub.example.tld.
+sub.example.tld.               NS      ns21.sub.example.tld.
+sub.example.tld.               NS      ns22.sub.example.tld.
+sub.example.tld.               NS      ns23.sub.example.tld.
+ns01.sub.example.tld.          A       127.0.0.1
+ns02.sub.example.tld.          A       127.0.0.2
+ns03.sub.example.tld.          A       127.0.0.3
+ns04.sub.example.tld.          A       127.0.0.4
+ns05.sub.example.tld.          A       127.0.0.5
+ns06.sub.example.tld.          A       127.0.0.6
+ns07.sub.example.tld.          A       127.0.0.7
+ns08.sub.example.tld.          A       127.0.0.8
+ns09.sub.example.tld.          A       127.0.0.9
+ns10.sub.example.tld.          A       127.0.0.10
+ns11.sub.example.tld.          A       127.0.0.11
+ns12.sub.example.tld.          A       127.0.0.12
+ns13.sub.example.tld.          A       127.0.0.13
+ns14.sub.example.tld.          A       127.0.0.14
+ns15.sub.example.tld.          A       127.0.0.15
+ns16.sub.example.tld.          A       127.0.0.16
+ns17.sub.example.tld.          A       127.0.0.17
+ns18.sub.example.tld.          A       127.0.0.18
+ns19.sub.example.tld.          A       127.0.0.19
+ns20.sub.example.tld.          A       127.0.0.20
+ns21.sub.example.tld.          A       127.0.0.21
+ns22.sub.example.tld.          A       127.0.0.22
+ns23.sub.example.tld.          A       127.0.0.23
diff --git a/bin/tests/system/nsprocessinglimit/ns3/named.conf.j2 b/bin/tests/system/nsprocessinglimit/ns3/named.conf.j2
new file mode 100644 (file)
index 0000000..15b68ee
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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; };
+       recursion no;
+       dnssec-validation no;
+};
+
+zone "example.tld." {
+       type primary;
+       file "example.tld.db";
+};
+
+key rndc_key {
+       secret "1234abcd8765";
+       algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+       inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
diff --git a/bin/tests/system/nsprocessinglimit/ns4/named.args b/bin/tests/system/nsprocessinglimit/ns4/named.args
new file mode 100644 (file)
index 0000000..71c23a4
--- /dev/null
@@ -0,0 +1 @@
+-D nsprocessinglimit-ns4 -m record -c named.conf -d 99 -g -T maxcachesize=2097152 -4
diff --git a/bin/tests/system/nsprocessinglimit/ns4/named.conf.j2 b/bin/tests/system/nsprocessinglimit/ns4/named.conf.j2
new file mode 100644 (file)
index 0000000..8f1aea1
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.4;
+       notify-source 10.53.0.4;
+       transfer-source 10.53.0.4;
+       port @PORT@;
+       pid-file "named.pid";
+       listen-on { 10.53.0.4; };
+       recursion yes;
+       dnssec-validation no;
+       dnstap { resolver query; };
+       dnstap-output file "dnstap.out";
+};
+
+zone "." {
+       type hint;
+       file "root.hint";
+};
+
+key rndc_key {
+       secret "1234abcd8765";
+       algorithm @DEFAULT_HMAC@;
+};
+
+controls {
+       inet 10.53.0.4 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
+};
diff --git a/bin/tests/system/nsprocessinglimit/ns4/root.hint b/bin/tests/system/nsprocessinglimit/ns4/root.hint
new file mode 100644 (file)
index 0000000..d7d0e1f
--- /dev/null
@@ -0,0 +1,14 @@
+; 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 999999
+.                       IN NS          a.root-servers.nil.
+a.root-servers.nil.     IN A           10.53.0.1
diff --git a/bin/tests/system/nsprocessinglimit/tests_nsprocessinglimit.py b/bin/tests/system/nsprocessinglimit/tests_nsprocessinglimit.py
new file mode 100644 (file)
index 0000000..3577c89
--- /dev/null
@@ -0,0 +1,74 @@
+# 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_ips_and_queries(line):
+    # dnstap-read output line example
+    # 05-Feb-2026 11:00:57.853 RQ 10.53.0.4:38507 -> 10.53.0.3:22047 TCP 56b sub.example.tld/IN/NS
+    _, _, _, _, _, dst, _, _, query = line.split(" ", 9)
+    ip, _ = dst.split(":", 1)
+    return (ip, query)
+
+
+def extract_dnstap(ns, expectedlen):
+    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()
+    assert expectedlen == len(lines)
+    return map(line_to_ips_and_queries, lines)
+
+
+def expect_query(expected_query, expected_query_count, ips_and_queries):
+    count = 0
+    for _, query in ips_and_queries:
+        if query == expected_query:
+            count += 1
+    assert count == expected_query_count
+
+
+def expect_next_ip_and_query(expected_ips_and_queries, ips_and_queries):
+    for expected_ip, expected_query in expected_ips_and_queries:
+        ip, query = next(ips_and_queries)
+        assert ip == expected_ip
+        assert query == expected_query
+
+
+def test_selfpointedglue_nslimit(ns4):
+    msg = isctest.query.create("a.sub.example.tld.", "A")
+    res = isctest.query.tcp(msg, ns4.ip)
+    isctest.check.servfail(res)
+
+    # The 4 formers lines are request to find sub.example2.tld NSs.
+    # The latest 20 are queries to sub.example2.tld NSs.
+    ips_and_queries = extract_dnstap(ns4, 24)
+
+    # Checking the begining of the resulution
+    expect_next_ip_and_query(
+        [
+            ("10.53.0.1", "./IN/NS"),
+            ("10.53.0.1", "tld/IN/NS"),
+            ("10.53.0.2", "example.tld/IN/NS"),
+            ("10.53.0.3", "sub.example.tld/IN/NS"),
+        ],
+        ips_and_queries,
+    )
+    expect_query("a.sub.example.tld/IN/A", 20, ips_and_queries)