]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
System test for nxdomain-redirect combined with dns64
authorOndřej Surý <ondrej@isc.org>
Wed, 20 May 2026 16:28:15 +0000 (18:28 +0200)
committerOndřej Surý <ondrej@isc.org>
Tue, 2 Jun 2026 07:48:13 +0000 (09:48 +0200)
An AAAA query for a non-existent name into a view that combines
nxdomain-redirect with dns64 used to abort named via the DNS64
fallback in query_nodata(). The new module exercises all three
documented entry paths into query_redirect(): the authoritative
NXDOMAIN path (ns7, tripping INSIST(!is_zone) in
query_notfound()), the recursive NCACHENXRRSET path (ns8,
tripping REQUIRE in dns_rdataset_first() on a disassociated
rdataset), and the synth-from-dnssec path (ns10 validating
against ns9's signed root, with a primer A query so the second
AAAA reaches query_redirect() via query_coveringnsec()). ns9
serves as a neutral upstream so the cached and synthesized
negatives land real NXRRSETs.

Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit 739a067de89834820372ae14171c0889f7aedc83)

15 files changed:
bin/tests/system/redirect/ns10/named.conf.j2 [new file with mode: 0644]
bin/tests/system/redirect/ns10/redirect.db [new file with mode: 0644]
bin/tests/system/redirect/ns10/root.hints [new file with mode: 0644]
bin/tests/system/redirect/ns7/named.conf.j2 [new file with mode: 0644]
bin/tests/system/redirect/ns7/redirect.db [new file with mode: 0644]
bin/tests/system/redirect/ns7/root.db [new file with mode: 0644]
bin/tests/system/redirect/ns8/named.conf.j2 [new file with mode: 0644]
bin/tests/system/redirect/ns8/root.hints [new file with mode: 0644]
bin/tests/system/redirect/ns9/named.conf.j2 [new file with mode: 0644]
bin/tests/system/redirect/ns9/redirect.db [new file with mode: 0644]
bin/tests/system/redirect/ns9/root.db.in [new file with mode: 0644]
bin/tests/system/redirect/ns9/sign.sh [new file with mode: 0644]
bin/tests/system/redirect/setup.sh
bin/tests/system/redirect/tests_redirect_dns64.py [new file with mode: 0644]
bin/tests/system/redirect/tests_sh_redirect.py

diff --git a/bin/tests/system/redirect/ns10/named.conf.j2 b/bin/tests/system/redirect/ns10/named.conf.j2
new file mode 100644 (file)
index 0000000..9e019cc
--- /dev/null
@@ -0,0 +1,29 @@
+// NS10 — validating recursor used to drive the synth-from-dnssec entry
+// into query_redirect (covering NSEC from ns9 synthesizes NXDOMAIN
+// locally, then nxdomain-redirect+dns64 hit the same buggy path as ns7).
+
+options {
+       port @PORT@;
+       listen-on port @PORT@ { 10.53.0.10; };
+       pid-file "named.pid";
+       nxdomain-redirect redirect;
+       dnssec-validation yes;
+       synth-from-dnssec yes;
+       dns64 64:ff9b::/96 {
+               clients { any; };
+               mapped { any; };
+               suffix ::;
+       };
+};
+
+include "trusted.conf";
+
+zone "." {
+       type hint;
+       file "root.hints";
+};
+
+zone "redirect" {
+       type primary;
+       file "redirect.db";
+};
diff --git a/bin/tests/system/redirect/ns10/redirect.db b/bin/tests/system/redirect/ns10/redirect.db
new file mode 100644 (file)
index 0000000..aa7dc60
--- /dev/null
@@ -0,0 +1,5 @@
+$TTL 300
+@   IN  SOA ns.redirect. admin.redirect. 1 3600 900 604800 86400
+@   IN  NS  ns.redirect.
+ns  IN  A   10.53.0.10
+*   IN  A   203.0.113.1
diff --git a/bin/tests/system/redirect/ns10/root.hints b/bin/tests/system/redirect/ns10/root.hints
new file mode 100644 (file)
index 0000000..8150fab
--- /dev/null
@@ -0,0 +1,2 @@
+.                      518400  IN      NS      a.root-servers.nil.
+a.root-servers.nil.    518400  IN      A       10.53.0.9
diff --git a/bin/tests/system/redirect/ns7/named.conf.j2 b/bin/tests/system/redirect/ns7/named.conf.j2
new file mode 100644 (file)
index 0000000..0ceb769
--- /dev/null
@@ -0,0 +1,24 @@
+// NS7
+
+options {
+       port @PORT@;
+       listen-on port @PORT@ { 10.53.0.7; };
+       pid-file "named.pid";
+       nxdomain-redirect redirect;
+       dnssec-validation no;
+       dns64 64:ff9b::/96 {
+               clients { any; };
+               mapped { any; };
+               suffix ::;
+       };
+};
+
+zone "." {
+        type primary;
+        file "root.db";
+};
+
+zone "redirect" {
+        type primary;
+        file "redirect.db";
+};
diff --git a/bin/tests/system/redirect/ns7/redirect.db b/bin/tests/system/redirect/ns7/redirect.db
new file mode 100644 (file)
index 0000000..5d3d435
--- /dev/null
@@ -0,0 +1,5 @@
+$TTL 300
+@   IN  SOA ns.redirect. admin.redirect. 1 3600 900 604800 86400
+@   IN  NS  ns.redirect.
+ns  IN  A   10.53.0.7
+*   IN  A   203.0.113.1
diff --git a/bin/tests/system/redirect/ns7/root.db b/bin/tests/system/redirect/ns7/root.db
new file mode 100644 (file)
index 0000000..f2fa910
--- /dev/null
@@ -0,0 +1,3 @@
+.                      86400   IN      SOA     a.root-servers.nil. hostmaster.example.net. 2019022100 1800 900 604800 86400
+.                      518400  IN      NS      a.root-servers.nil.
+a.root-servers.nil.    518400  IN      A       10.53.0.7
diff --git a/bin/tests/system/redirect/ns8/named.conf.j2 b/bin/tests/system/redirect/ns8/named.conf.j2
new file mode 100644 (file)
index 0000000..d1513b3
--- /dev/null
@@ -0,0 +1,19 @@
+// NS8
+
+options {
+       port @PORT@;
+       listen-on port @PORT@ { 10.53.0.8; };
+       pid-file "named.pid";
+       nxdomain-redirect redirect;
+       dnssec-validation no;
+       dns64 64:ff9b::/96 {
+               clients { any; };
+               mapped { any; };
+               suffix ::;
+       };
+};
+
+zone "." {
+        type hint;
+        file "root.hints";
+};
diff --git a/bin/tests/system/redirect/ns8/root.hints b/bin/tests/system/redirect/ns8/root.hints
new file mode 100644 (file)
index 0000000..8150fab
--- /dev/null
@@ -0,0 +1,2 @@
+.                      518400  IN      NS      a.root-servers.nil.
+a.root-servers.nil.    518400  IN      A       10.53.0.9
diff --git a/bin/tests/system/redirect/ns9/named.conf.j2 b/bin/tests/system/redirect/ns9/named.conf.j2
new file mode 100644 (file)
index 0000000..1001396
--- /dev/null
@@ -0,0 +1,20 @@
+// NS9 — signed-root upstream for ns8 (advisor cached path) and ns10
+// (synth-from-dnssec path)
+
+options {
+       port @PORT@;
+       listen-on port @PORT@ { 10.53.0.9; };
+       pid-file "named.pid";
+       dnssec-validation no;
+       recursion no;
+};
+
+zone "." {
+       type primary;
+       file "root.db.signed";
+};
+
+zone "redirect" {
+       type primary;
+       file "redirect.db";
+};
diff --git a/bin/tests/system/redirect/ns9/redirect.db b/bin/tests/system/redirect/ns9/redirect.db
new file mode 100644 (file)
index 0000000..a6ae61e
--- /dev/null
@@ -0,0 +1,5 @@
+$TTL 300
+@   IN  SOA ns.redirect. admin.redirect. 1 3600 900 604800 86400
+@   IN  NS  ns.redirect.
+ns  IN  A   10.53.0.9
+*   IN  A   203.0.113.1
diff --git a/bin/tests/system/redirect/ns9/root.db.in b/bin/tests/system/redirect/ns9/root.db.in
new file mode 100644 (file)
index 0000000..e512a4c
--- /dev/null
@@ -0,0 +1,3 @@
+.                      86400   IN      SOA     a.root-servers.nil. hostmaster.example.net. 2019022100 1800 900 604800 86400
+.                      518400  IN      NS      a.root-servers.nil.
+a.root-servers.nil.    518400  IN      A       10.53.0.9
diff --git a/bin/tests/system/redirect/ns9/sign.sh b/bin/tests/system/redirect/ns9/sign.sh
new file mode 100644 (file)
index 0000000..4de4111
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh -e
+
+# 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.
+
+. ../../conf.sh
+
+zone=.
+infile=root.db.in
+zonefile=root.db
+
+key1=$($KEYGEN -q -a $DEFAULT_ALGORITHM $zone)
+key2=$($KEYGEN -q -a $DEFAULT_ALGORITHM -fk $zone)
+
+cat $infile $key1.key $key2.key >$zonefile
+
+$SIGNER -P -g -O full -o $zone $zonefile >sign.ns9.root.out
+
+keyfile_to_static_keys $key2 >../ns10/trusted.conf
index b98c65951788ea1c68cee74f9187ab381cc67f7b..bbe3a9d4456df3ef8545c6413e07e4986f09f4b5 100644 (file)
@@ -20,3 +20,4 @@ cp ns2/example.db.in ns2/example.db
 cp ns4/example.db.in ns4/example.db
 (cd ns3 && $SHELL sign.sh)
 (cd ns5 && $SHELL sign.sh)
+(cd ns9 && $SHELL sign.sh)
diff --git a/bin/tests/system/redirect/tests_redirect_dns64.py b/bin/tests/system/redirect/tests_redirect_dns64.py
new file mode 100644 (file)
index 0000000..7a4b121
--- /dev/null
@@ -0,0 +1,102 @@
+#!/usr/bin/python3
+
+# 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 pytest
+
+import isctest
+
+pytestmark = pytest.mark.extra_artifacts(
+    [
+        "dig.out.*",
+        "ns1/K*",
+        "ns1/*.signed",
+        "ns1/dsset-nsec3.",
+        "ns1/dsset-signed.",
+        "ns1/nsec3.db",
+        "ns1/signed.db",
+        "ns2/example.db",
+        "ns2/named.stats",
+        "ns2/redirect.db",
+        "ns3/K*",
+        "ns3/*.signed",
+        "ns3/dsset-nsec3.",
+        "ns3/dsset-signed.",
+        "ns3/nsec3.db",
+        "ns3/signed.db",
+        "ns4/example.db",
+        "ns4/named.stats",
+        "ns5/K*",
+        "ns5/dsset-*",
+        "ns5/*.signed",
+        "ns5/root.db",
+        "ns5/sign.ns5.*",
+        "ns5/signed.db",
+        "ns6/signed.db.signed",
+        "ns9/K*",
+        "ns9/dsset-*",
+        "ns9/root.db",
+        "ns9/root.db.signed",
+        "ns9/sign.ns9.*",
+        "ns10/trusted.conf",
+    ]
+)
+
+
+def _no_crash(server, qname):
+    # DO=0 so nxdomain-redirect is not skipped on validated upstream
+    # responses; the documented landing-page deployment serves
+    # non-DNSSEC clients.
+    msg = isctest.query.create(qname, "AAAA", dnssec=False)
+    response = isctest.query.tcp(msg, server.ip)
+    isctest.check.noerror(response)
+
+
+def _alive(server):
+    msg = isctest.query.create("ns.redirect.", "A", dnssec=False)
+    response = isctest.query.tcp(msg, server.ip)
+    isctest.check.noerror(response)
+
+
+def test_nxdomain_redirect_dns64_authoritative(ns7):
+    # Direct AAAA to a server that is authoritative for both '.' (NXDOMAIN)
+    # and the redirect zone (wildcard A only). Reproduces the
+    # INSIST(!qctx->is_zone) abort in query_notfound() entered via
+    # authoritative NXDOMAIN.
+    _no_crash(ns7, "no-exist.")
+    _alive(ns7)
+
+
+def test_nxdomain_redirect_dns64_recursive(ns8):
+    # Recursive resolver: the upstream returns a real NOERROR-empty AAAA
+    # for '*.redirect.', which the resolver caches as NCACHENXRRSET.
+    # Reproduces the REQUIRE(rdataset->methods != NULL) abort in
+    # dns_rdataset_first() reached via the disassociated rdataset on the
+    # second pass through redirect2().
+    _no_crash(ns8, "no-exist.")
+    _alive(ns8)
+
+
+def test_nxdomain_redirect_dns64_synth_from_dnssec(ns10):
+    # Validating recursor with synth-from-dnssec. Prime the NSEC chain
+    # with an A query (the redirect zone serves a wildcard A, so this
+    # path returns successfully without entering the DNS64 fallback). A
+    # subsequent AAAA query for a different nonexistent name is then
+    # synthesized via query_coveringnsec() and reaches query_redirect()
+    # through the third documented entry. Same downstream bug as the
+    # authoritative path.
+    msg = isctest.query.create("prime.", "A", dnssec=False)
+    response = isctest.query.tcp(msg, ns10.ip)
+    isctest.check.noerror(response)
+
+    _no_crash(ns10, "trigger.")
+    _alive(ns10)
index 5f20aad6f266a322fe03c7decaf97d64d9dd1ad1..e985527c94294e7e8bb0c162503ef4944f84c24e 100644 (file)
@@ -38,6 +38,12 @@ pytestmark = pytest.mark.extra_artifacts(
         "ns5/sign.ns5.*",
         "ns5/signed.db",
         "ns6/signed.db.signed",
+        "ns9/K*",
+        "ns9/dsset-*",
+        "ns9/root.db",
+        "ns9/root.db.signed",
+        "ns9/sign.ns9.*",
+        "ns10/trusted.conf",
     ]
 )