]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add NSEC3 answer correctness test to dnssec_py 12209/head
authorNicki Křížek <nicki@isc.org>
Mon, 8 Jun 2026 15:26:02 +0000 (15:26 +0000)
committerNicki Křížek <nicki@isc.org>
Tue, 9 Jun 2026 09:16:46 +0000 (11:16 +0200)
Rewrite nsec3_answer/tests_nsec3.py as dnssec_py/tests_nsec3_answer.py
using the isctest.zone helpers for zone setup. ns1 (auth) and ns2
(resolver) were renumbered to ns2 and ns9 respectively to fit the
existing dnssec_py server infrastructure.

Assisted-by: Claude:claude-opus-4-8
bin/tests/system/dnssec_py/ns2/zones/nsec3-answer.db [new file with mode: 0644]
bin/tests/system/dnssec_py/tests_nsec3_answer.py [moved from bin/tests/system/nsec3_answer/tests_nsec3.py with 90% similarity, mode: 0644]
bin/tests/system/nsec3_answer/ns1/named.conf.j2 [deleted file]
bin/tests/system/nsec3_answer/ns1/root.db.in [deleted file]
bin/tests/system/nsec3_answer/ns1/sign.sh [deleted file]
bin/tests/system/nsec3_answer/ns2/named.conf.j2 [deleted file]
bin/tests/system/nsec3_answer/setup.sh [deleted file]

diff --git a/bin/tests/system/dnssec_py/ns2/zones/nsec3-answer.db b/bin/tests/system/dnssec_py/ns2/zones/nsec3-answer.db
new file mode 100644 (file)
index 0000000..b5318be
--- /dev/null
@@ -0,0 +1,47 @@
+; This zone file intentionally isn't a jinja2 template.
+;
+; It needs to be read before the templates are rended, to generate hypothesis
+; test cases.
+$ORIGIN nsec3-answer.
+$TTL 300
+nsec3-answer.                  IN SOA  . . (
+                               1               ; serial
+                               20              ; refresh (20 seconds)
+                               20              ; retry (20 seconds)
+                               1814400         ; expire (3 weeks)
+                               3600            ; minimum (1 hour)
+)
+
+nsec3-answer.                  NS      ns2
+ns2                    A       10.53.0.2
+
+02hc3em7bdd011a0gms3hkkjt2if5vp8               A       10.0.0.0
+a                                              A       10.0.0.1
+*.a.a                                          A       10.0.0.6
+a.a.a.a                                        A       10.0.0.3
+b                                              A       10.0.0.2
+b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b      A       10.0.0.2
+cname                                          CNAME   does-not-exist
+cname.cname                                    CNAME   cname
+cname.ent.cname                                        CNAME   cname.cname
+d                                              A       10.0.0.4
+dname-to-nowhere                               DNAME   does-not-exist
+; DNAME owner longer than target to avoid YXDOMAIN dependent on QNAME
+insecure                                       NS      a.root-servers.nil
+ns.insecure                                    A       10.53.0.3
+a.root-servers.nil                             A       10.53.0.1
+secure                                         NS      a.root-servers.nil
+secure                                         DS      11111 13 255 00
+occluded.secure                                        A       0.0.0.0
+*.wild                                         A       10.0.0.6
+explicit.wild                                  A       192.0.2.66
+z                                              A       10.0.0.26
+
+; randomly generated subtree to excercise unknown corner cases
+; intentionally small, to not blow up algorithms with quadratic complexity in ZoneAnalyzer and name generator
+a.a.a.b.a.a.a.b.a.a.b.b.a.random       TXT     "r"
+b.b.a.a.b.b.a.a.a.b.b.a.b.a.a.a.a.a.b.a.a.b.a.b.a.b.b.b.b.b.a.a.a.a.b.a.a.a.b.a.a.b.b.a.random TXT     "r"
+a.a.a.b.b.a.b.b.a.b.a.b.a.b.a.b.b.b.a.random   TXT     "r"
+b.b.a.b.a.b.a.a.a.b.a.a.b.a.a.a.a.b.b.a.b.b.a.b.a.b.a.b.a.b.b.b.a.random       TXT     "r"
+a.b.a.a.b.a.b.a.b.a.a.b.a.b.a.a.a.b.b.a.b.b.a.a.b.b.a.a.b.a.b.a.b.b.b.b.a.a.a.a.a.a.a.a.b.a.b.a.b.b.a.b.a.b.a.a.a.b.a.a.b.a.a.a.a.b.b.a.b.b.a.b.a.b.a.b.a.b.b.b.a.random       TXT     "r"
+a.a.a.a.a.b.b.a.a.b.a.a.b.a.a.b.b.a.a.a.b.a.a.a.b.b.b.b.b.a.a.a.b.b.b.b.b.b.a.b.b.b.a.a.b.b.b.b.a.a.a.a.b.a.b.b.a.b.a.a.b.b.b.b.b.b.b.a.b.b.a.b.a.b.a.a.a.b.b.a.a.b.b.a.b.a.b.b.a.b.b.b.a.b.b.b.b.b.a.a.b.a.a.a.b.b.a.a.a.b.b.b.b.b.a.random   TXT     "r"
old mode 100755 (executable)
new mode 100644 (file)
similarity index 90%
rename from bin/tests/system/nsec3_answer/tests_nsec3.py
rename to bin/tests/system/dnssec_py/tests_nsec3_answer.py
index f510f9e..53bfbba
@@ -1,5 +1,3 @@
-#!/usr/bin/python3
-
 # Copyright (C) Internet Systems Consortium, Inc. ("ISC")
 #
 # SPDX-License-Identifier: MPL-2.0
@@ -11,7 +9,7 @@
 # See the COPYRIGHT file distributed with this work for additional
 # information regarding copyright ownership.
 
-# Silence incorrect warnings cause by hypothesis.assume()
+# Silence incorrect warnings caused by hypothesis.assume()
 # https://github.com/pylint-dev/pylint/issues/10785#issuecomment-3677224217
 # pylint: disable=unreachable
 
@@ -20,6 +18,7 @@ from dataclasses import dataclass
 from pathlib import Path
 
 import os
+import time
 
 from hypothesis import assume, given
 
@@ -34,17 +33,43 @@ import dns.rdtypes.ANY.RRSIG
 import dns.rrset
 import pytest
 
+from dnssec_py.common import DNSSEC_PY_MARK
 from isctest.hypothesis.strategies import dns_names, sampled_from
+from isctest.template import NS2, zones
+from isctest.zone import Zone, configure_root
 
 import isctest
 import isctest.name
 
-SUFFIX = dns.name.from_text(".")
-AUTH = "10.53.0.1"
-RESOLVER = "10.53.0.2"
+pytestmark = DNSSEC_PY_MARK
+
+
+def bootstrap():
+    zone = Zone(
+        "nsec3-answer",
+        NS2,
+        signed=True,
+    )
+    zone.add_keys()
+    salt = int(time.time()) // 3600 % 65536
+    salt_hex = f"{salt:04X}"
+    isctest.log.info(f"NSEC3 salt for this hour: {salt_hex}")
+    zone.sign(f"-3 {salt_hex}")
+
+    root = configure_root([zone])
+    return {
+        "trust_anchors": root.trust_anchors(),
+        "zones": zones([root, zone]),
+    }
+
+
+SUFFIX = dns.name.from_text("nsec3-answer.")
+AUTH = "10.53.0.2"
+RESOLVER = "10.53.0.9"
 TIMEOUT = 5
 ZONE = isctest.name.ZoneAnalyzer.read_path(
-    Path(os.environ["srcdir"]) / "nsec3_answer/ns1/root.db.in", origin=SUFFIX
+    Path(os.environ["srcdir"]) / "dnssec_py/ns2/zones/nsec3-answer.db",
+    origin=SUFFIX,
 )
 
 
@@ -71,7 +96,7 @@ def do_test_query(
 
 
 @pytest.mark.parametrize(
-    "server", [pytest.param(AUTH, id="ns1"), pytest.param(RESOLVER, id="ns2")]
+    "server", [pytest.param(AUTH, id="ns2"), pytest.param(RESOLVER, id="ns9")]
 )
 @given(
     qname=sampled_from(
@@ -84,7 +109,7 @@ def test_nodata(server: str, qname: dns.name.Name, named_port: int) -> None:
     check_nodata(qname, nsec3check)
 
 
-@pytest.mark.parametrize("server", [pytest.param(AUTH, id="ns1")])
+@pytest.mark.parametrize("server", [pytest.param(AUTH, id="ns2")])
 @given(
     qname=dns_names(
         suffix=(ZONE.delegations - ZONE.get_names_with_type(dns.rdatatype.DS))
@@ -116,7 +141,7 @@ def assume_nx_and_no_delegation(qname: dns.name.Name) -> None:
     assume(qname not in ZONE.all_existing_names)
 
     # name must not be under a delegation or DNAME:
-    # it would not work with resolver ns2
+    # it would not work with resolver ns9
     assume(
         not is_related_to_any(
             qname,
@@ -127,7 +152,7 @@ def assume_nx_and_no_delegation(qname: dns.name.Name) -> None:
 
 
 @pytest.mark.parametrize(
-    "server", [pytest.param(AUTH, id="ns1"), pytest.param(RESOLVER, id="ns2")]
+    "server", [pytest.param(AUTH, id="ns2"), pytest.param(RESOLVER, id="ns9")]
 )
 @given(qname=dns_names(suffix=SUFFIX))
 def test_nxdomain(server: str, qname: dns.name.Name, named_port: int) -> None:
@@ -141,7 +166,7 @@ def test_nxdomain(server: str, qname: dns.name.Name, named_port: int) -> None:
 
 
 @pytest.mark.parametrize(
-    "server", [pytest.param(AUTH, id="ns1"), pytest.param(RESOLVER, id="ns2")]
+    "server", [pytest.param(AUTH, id="ns2"), pytest.param(RESOLVER, id="ns9")]
 )
 @given(qname=sampled_from(sorted(ZONE.get_names_with_type(dns.rdatatype.CNAME))))
 def test_cname_nxdomain(server: str, qname: dns.name.Name, named_port: int) -> None:
@@ -157,7 +182,7 @@ def test_cname_nxdomain(server: str, qname: dns.name.Name, named_port: int) -> N
 
 
 @pytest.mark.parametrize(
-    "server", [pytest.param(AUTH, id="ns1"), pytest.param(RESOLVER, id="ns2")]
+    "server", [pytest.param(AUTH, id="ns2"), pytest.param(RESOLVER, id="ns9")]
 )
 @given(qname=dns_names(suffix=ZONE.get_names_with_type(dns.rdatatype.DNAME)))
 def test_dname_nxdomain(server: str, qname: dns.name.Name, named_port: int) -> None:
@@ -175,7 +200,7 @@ def test_dname_nxdomain(server: str, qname: dns.name.Name, named_port: int) -> N
 
 
 @pytest.mark.parametrize(
-    "server", [pytest.param(AUTH, id="ns1"), pytest.param(RESOLVER, id="ns2")]
+    "server", [pytest.param(AUTH, id="ns2"), pytest.param(RESOLVER, id="ns9")]
 )
 @given(qname=dns_names(suffix=ZONE.ents))
 def test_ents(server: str, qname: dns.name.Name, named_port: int) -> None:
@@ -193,7 +218,7 @@ def test_ents(server: str, qname: dns.name.Name, named_port: int) -> None:
 
 
 @pytest.mark.parametrize(
-    "server", [pytest.param(AUTH, id="ns1"), pytest.param(RESOLVER, id="ns2")]
+    "server", [pytest.param(AUTH, id="ns2"), pytest.param(RESOLVER, id="ns9")]
 )
 @given(qname=dns_names(suffix=ZONE.reachable_wildcard_parents))
 def test_wildcard_synthesis(server: str, qname: dns.name.Name, named_port: int) -> None:
@@ -207,7 +232,7 @@ def test_wildcard_synthesis(server: str, qname: dns.name.Name, named_port: int)
 
 
 @pytest.mark.parametrize(
-    "server", [pytest.param(AUTH, id="ns1"), pytest.param(RESOLVER, id="ns2")]
+    "server", [pytest.param(AUTH, id="ns2"), pytest.param(RESOLVER, id="ns9")]
 )
 @given(qname=dns_names(suffix=ZONE.reachable_wildcard_parents))
 def test_wildcard_nodata(server: str, qname: dns.name.Name, named_port: int) -> None:
diff --git a/bin/tests/system/nsec3_answer/ns1/named.conf.j2 b/bin/tests/system/nsec3_answer/ns1/named.conf.j2
deleted file mode 100644 (file)
index acf4ae9..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-// NS1
-
-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;
-       dnssec-validation no;
-};
-
-zone "." {
-       type primary;
-       file "root.db.signed";
-};
diff --git a/bin/tests/system/nsec3_answer/ns1/root.db.in b/bin/tests/system/nsec3_answer/ns1/root.db.in
deleted file mode 100644 (file)
index c3b0c84..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-$TTL 300
-.                      IN SOA  . . (
-                               2025063000      ; serial
-                               600             ; refresh
-                               600             ; retry
-                               1200            ; expire
-                               600             ; minimum
-                               )
-.                      NS      a.root-servers.nil.
-
-02hc3em7bdd011a0gms3hkkjt2if5vp8.              A       10.0.0.0
-a.                                             A       10.0.0.1
-*.a.a.                                         A       10.0.0.6
-a.a.a.a.                                       A       10.0.0.3
-b.                                             A       10.0.0.2
-b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.b.     A       10.0.0.2
-cname.                                         CNAME   does-not-exist.
-cname.cname.                                   CNAME   cname.
-cname.ent.cname.                               CNAME   cname.cname.
-d.                                             A       10.0.0.4
-dname-to-nowhere.                              DNAME   does-not-exist.
-; DNAME owner longer than target to avoid YXDOMAIN dependent on QNAME
-insecure.                                      NS      a.root-servers.nil.
-ns.insecure.                                   A       10.53.0.3
-a.root-servers.nil.                            A       10.53.0.1
-secure.                                                NS      a.root-servers.nil.
-secure.                                                DS      11111 13 255 00
-occluded.secure.                               A       0.0.0.0
-*.wild.                                                A       10.0.0.6
-explicit.wild.                                 A       192.0.2.66
-z.                                             A       10.0.0.26
-
-; randomly generated subtree to excercise unknown corner cases
-; intentionally small, to not blow up algorithms with quadratic complexity in ZoneAnalyzer and name generator
-a.a.a.b.a.a.a.b.a.a.b.b.a.random.      TXT     "r"
-b.b.a.a.b.b.a.a.a.b.b.a.b.a.a.a.a.a.b.a.a.b.a.b.a.b.b.b.b.b.a.a.a.a.b.a.a.a.b.a.a.b.b.a.random.        TXT     "r"
-a.a.a.b.b.a.b.b.a.b.a.b.a.b.a.b.b.b.a.random.  TXT     "r"
-b.b.a.b.a.b.a.a.a.b.a.a.b.a.a.a.a.b.b.a.b.b.a.b.a.b.a.b.a.b.b.b.a.random.      TXT     "r"
-a.b.a.a.b.a.b.a.b.a.a.b.a.b.a.a.a.b.b.a.b.b.a.a.b.b.a.a.b.a.b.a.b.b.b.b.a.a.a.a.a.a.a.a.b.a.b.a.b.b.a.b.a.b.a.a.a.b.a.a.b.a.a.a.a.b.b.a.b.b.a.b.a.b.a.b.a.b.b.b.a.random.      TXT     "r"
-a.a.a.a.a.b.b.a.a.a.a.a.b.b.a.a.b.a.a.b.a.a.b.b.a.a.a.b.a.a.a.b.b.b.b.b.a.a.a.b.b.b.b.b.b.a.b.b.b.a.a.b.b.b.b.a.a.a.a.b.a.b.b.a.b.a.a.b.b.b.b.b.b.b.a.b.b.a.b.a.b.a.a.a.b.b.a.a.b.b.a.b.a.b.b.a.b.b.b.a.b.b.b.b.b.a.a.b.a.a.a.b.b.a.a.a.b.b.b.b.b.a.random.    TXT     "r"
diff --git a/bin/tests/system/nsec3_answer/ns1/sign.sh b/bin/tests/system/nsec3_answer/ns1/sign.sh
deleted file mode 100644 (file)
index 78e3311..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/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.
-
-# shellcheck source=conf.sh
-. ../../conf.sh
-
-set -e
-
-zone=.
-infile=root.db.in
-zonefile=root.db
-
-echo_i "ns1/sign.sh"
-
-ksk=$("$KEYGEN" -q -fk -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
-zsk=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
-
-cat "$infile" "$ksk.key" "$zsk.key" >"$zonefile"
-
-SALT="$(printf "%04x" "$(($(date +%s) / 3600 % 65536))")"
-echo_ic "NSEC3 salt for this hour: $SALT"
-"$SIGNER" -3 "$SALT" -o "$zone" "$zonefile" 2>&1 >"$zonefile.sign.log"
-
-keyfile_to_initial_ds "$ksk" >managed-keys.conf
diff --git a/bin/tests/system/nsec3_answer/ns2/named.conf.j2 b/bin/tests/system/nsec3_answer/ns2/named.conf.j2
deleted file mode 100644 (file)
index 174bd7d..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// validating resolver
-
-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;
-       dnssec-validation yes;
-};
-
-controls {
-       inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
-};
-
-include "../../_common/rndc.key";
-
-zone "." {
-       type hint;
-       file "../../_common/root.hint";
-};
-
-include "../ns1/managed-keys.conf";
diff --git a/bin/tests/system/nsec3_answer/setup.sh b/bin/tests/system/nsec3_answer/setup.sh
deleted file mode 100644 (file)
index 4a4db2d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/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.
-
-# shellcheck source=conf.sh
-. ../conf.sh
-
-set -e
-
-(
-  cd ns1
-  $SHELL sign.sh
-)