]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add NSEC3 optout large delegation zone test case
authorMatthijs Mekking <matthijs@isc.org>
Fri, 5 Dec 2025 16:01:00 +0000 (17:01 +0100)
committerMatthijs Mekking <matthijs@isc.org>
Wed, 10 Dec 2025 13:18:52 +0000 (14:18 +0100)
This test signs a large delegation with mostly insecure delegations
with NSEC3 optout. Once the NSEC3PARAM record is published, run
dnssec-verify to ensure the zone is correctly signed.

bin/tests/system/optout/ns2/controls.conf.j2 [new symlink]
bin/tests/system/optout/ns2/named.conf.j2 [new file with mode: 0644]
bin/tests/system/optout/ns2/test.db [new file with mode: 0644]
bin/tests/system/optout/setup.sh [new file with mode: 0644]
bin/tests/system/optout/tests_optout.py [new file with mode: 0755]

diff --git a/bin/tests/system/optout/ns2/controls.conf.j2 b/bin/tests/system/optout/ns2/controls.conf.j2
new file mode 120000 (symlink)
index 0000000..f1371a0
--- /dev/null
@@ -0,0 +1 @@
+../../_common/controls.conf.in
\ No newline at end of file
diff --git a/bin/tests/system/optout/ns2/named.conf.j2 b/bin/tests/system/optout/ns2/named.conf.j2
new file mode 100644 (file)
index 0000000..4d9aed3
--- /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 {
+        port @PORT@;
+        pid-file "named.pid";
+        listen-on { 10.53.0.2; };
+        listen-on-v6 { none; };
+       allow-transfer { any; };
+        recursion no;
+        dnssec-validation no;
+        ixfr-from-differences yes;
+       sig-signing-nodes 900;
+       sig-signing-signatures 900;
+};
+
+include "controls.conf";
+
+dnssec-policy "optout" {
+       keys {
+               csk lifetime unlimited algorithm ecdsa256;
+       };
+       nsec3param iterations 0 optout yes salt-length 0;
+};
+
+zone "test" {
+       type primary;
+       file "test.db";
+       dnssec-policy "optout";
+       inline-signing yes;
+};
diff --git a/bin/tests/system/optout/ns2/test.db b/bin/tests/system/optout/ns2/test.db
new file mode 100644 (file)
index 0000000..d3a9302
--- /dev/null
@@ -0,0 +1,22 @@
+; 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   3600
+@                              IN      SOA     ns2.test. hostmaster.test. 1 7200 3600 24796800 3600
+                               IN      NS      ns2
+
+ns2                            IN      A       10.53.0.2
+
+a                              IN      A       127.0.0.1
+
+$GENERATE 1-50000      child$  IN      NS      ns.example.
+
+child303                       IN      DS      7250 13 2 A30B3F78B6DDE9A4A9A2AD0C805518B4F49EC62E7D3F4531D33DE697 CDA01CB2
diff --git a/bin/tests/system/optout/setup.sh b/bin/tests/system/optout/setup.sh
new file mode 100644 (file)
index 0000000..bb08b9c
--- /dev/null
@@ -0,0 +1,14 @@
+#!/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
diff --git a/bin/tests/system/optout/tests_optout.py b/bin/tests/system/optout/tests_optout.py
new file mode 100755 (executable)
index 0000000..67628c2
--- /dev/null
@@ -0,0 +1,108 @@
+#!/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 os
+import re
+import sys
+
+import isctest
+import pytest
+
+pytest.importorskip("dns", minversion="2.0.0")
+import dns.exception
+import dns.message
+import dns.name
+import dns.query
+import dns.rcode
+import dns.rdataclass
+import dns.rdatatype
+
+
+pytestmark = [
+    pytest.mark.skipif(
+        sys.version_info < (3, 7), reason="Python >= 3.7 required [GL #3001]"
+    ),
+    pytest.mark.extra_artifacts(
+        [
+            "*.out",
+            "ns2/*.infile",
+            "ns2/*.signed",
+            "ns2/*.jnl",
+            "ns2/*.jbk",
+            "ns2/controls.conf",
+            "ns2/dsset-*",
+            "ns2/K*",
+        ]
+    ),
+]
+
+
+def has_nsec3param(zone, response):
+    match = rf"{re.escape(zone)}\.\s+\d+\s+IN\s+NSEC3PARAM\s+1\s+0\s+0\s+-"
+
+    for rr in response.answer:
+        if re.search(match, rr.to_text()):
+            return True
+
+    return False
+
+
+def do_query(server, qname, qtype, tcp=False):
+    msg = isctest.query.create(qname, qtype)
+    query_func = isctest.query.tcp if tcp else isctest.query.udp
+    response = query_func(msg, server.ip, expected_rcode=dns.rcode.NOERROR)
+    return response
+
+
+def do_xfr(server, qname):
+    xfr = dns.zone.Zone(origin=f"{qname}.", relativize=False)
+    dns.query.inbound_xfr(
+        where=server.ip, txn_manager=xfr, port=int(os.environ["PORT"])
+    )
+    return xfr
+
+
+def verify_zone(zone, transfer):
+    verify = os.getenv("VERIFY")
+    assert verify is not None
+
+    filename = f"{zone}.out"
+    with open(filename, "w", encoding="utf-8") as file:
+        file.write(transfer.to_text())
+
+    # dnssec-verify command with default arguments.
+    verify_cmd = [verify, "-z", "-o", zone, filename]
+
+    verifier = isctest.run.cmd(verify_cmd)
+
+    if verifier.rc != 0:
+        isctest.log.error(f"dnssec-verify {zone} failed")
+
+    return verifier.rc == 0
+
+
+def test_optout(ns2):
+    zone = "test"
+
+    # Wait until the provided zone is signed and then verify its DNSSEC data.
+    def check_nsec3param():
+        response = do_query(ns2, zone, "NSEC3PARAM")
+        return has_nsec3param(zone, response)
+
+    # check zone is fully signed.
+    isctest.run.retry_with_timeout(check_nsec3param, timeout=300)
+
+    # check if zone if DNSSEC valid.
+    transfer = do_xfr(ns2, zone)
+    assert verify_zone(zone, transfer)