]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Split up dnssec validation tests to multiple modules
authorNicki Křížek <nicki@isc.org>
Fri, 25 Jul 2025 16:22:21 +0000 (18:22 +0200)
committerEvan Hunt <each@isc.org>
Thu, 31 Jul 2025 19:55:40 +0000 (12:55 -0700)
Put each config into a separate module to avoid interfering with other
tests.

bin/tests/system/dnssec/tests_validation.py
bin/tests/system/dnssec/tests_validation_accept_expired.py [new file with mode: 0644]
bin/tests/system/dnssec/tests_validation_managed_keys.py [new file with mode: 0644]
bin/tests/system/dnssec/tests_validation_many_anchors.py [new file with mode: 0644]
bin/tests/system/dnssec/tests_validation_multiview.py [new file with mode: 0644]
bin/tests/system/nta/tests_nta.py

index 74cb7c6dffc275207a85a2824db7d1c9f27be51e..917d517043b422596c717ef56d114d453ecfaad4 100644 (file)
@@ -14,7 +14,7 @@ import re
 import shutil
 import time
 
-from dns import edns, flags, name, rcode, rdataclass, rdatatype
+from dns import edns, flags, name, rdataclass, rdatatype
 
 import pytest
 
@@ -1184,49 +1184,6 @@ def test_expired_signatures(servers):
         assert rrset.ttl <= 60
 
 
-def test_accept_expired(servers, templates):
-    ns4 = servers["ns4"]
-    templates.render("ns4/named.conf", {"accept_expired": True})
-    ns4.reconfigure(log=False)
-
-    # test TTL of about-to-expire rrsets with accept-expired
-    ns4.rndc("flush", log=False)
-    msg = isctest.query.create("expiring.example", "SOA")
-    msg.flags |= flags.CD
-    res1 = isctest.query.tcp(msg, "10.53.0.4")
-    msg = isctest.query.create("expiring.example", "SOA")
-    res2 = isctest.query.tcp(msg, "10.53.0.4")
-    for rrset in res1.answer:
-        assert rrset.ttl <= 3600
-    for rrset in res2.answer:
-        assert rrset.ttl <= 120
-
-    # test TTL is capped at RRSIG expiry time in the additional section
-    # with accept-expired
-    ns4.rndc("flush", log=False)
-    msg = isctest.query.create("expiring.example", "MX")
-    msg.flags |= flags.CD
-    res1 = isctest.query.tcp(msg, "10.53.0.4")
-    msg = isctest.query.create("expiring.example", "MX")
-    res2 = isctest.query.tcp(msg, "10.53.0.4")
-    for rrset in res1.additional:
-        assert rrset.ttl <= 3600
-    for rrset in res2.additional:
-        assert rrset.ttl <= 120
-
-    # test TTL of expired rrsets with accept-expired
-    ns4.rndc("flush", log=False)
-    msg = isctest.query.create("expired.example", "SOA")
-    msg.flags |= flags.CD
-    res1 = isctest.query.tcp(msg, "10.53.0.4")
-    msg = isctest.query.create("expired.example", "SOA")
-    res2 = isctest.query.tcp(msg, "10.53.0.4")
-    for rrset in res1.additional:
-        assert rrset.ttl <= 3600
-    for rrset in res2.additional:
-        assert rrset.ttl <= 120
-
-
 def test_casing():
     # test legacy upper-case signer name validation
     msg = isctest.query.create("upper.example", "SOA")
@@ -1318,132 +1275,6 @@ def test_pending_ds(servers):
     isctest.check.noadflag(res)
 
 
-def test_trust_anchors(servers, templates):
-    # DNSSEC tests related to unsupported, disabled and revoked trust anchors.
-    #
-    # This nameserver is loaded with a bunch of trust anchors.
-    # Some of them are good (enabled.managed, enabled.trusted,
-    # secure.managed, secure.trusted), and some of them are bad
-    # (disabled.managed, revoked.managed, unsupported.managed,
-    # disabled.trusted, revoked.trusted, unsupported.trusted).  Make sure
-    # that the bad trust anchors are ignored.  This is tested by looking
-    # for the corresponding lines in the logfile.
-    ns5 = servers["ns5"]
-    templates.render("ns5/named.conf", {"many_anchors": True})
-    ns5.reconfigure(log=False)
-
-    # check that keys with unsupported/disabled algorithms are ignored
-    grep_q(
-        "ignoring static-key for 'disabled.trusted.': algorithm is disabled",
-        "ns5/named.run",
-    )
-    grep_q(
-        "ignoring static-key for 'disabled.managed.': algorithm is disabled",
-        "ns5/named.run",
-    )
-    grep_q(
-        "ignoring static-key for 'unsupported.trusted.': algorithm is unsupported",
-        "ns5/named.run",
-    )
-    grep_q(
-        "ignoring static-key for 'unsupported.managed.': algorithm is unsupported",
-        "ns5/named.run",
-    )
-    grep_q("ignoring static-key for 'revoked.trusted.': bad key type", "ns5/named.run")
-    grep_q("ignoring static-key for 'revoked.managed.': bad key type", "ns5/named.run")
-
-    # check that a key with supported algorithm validates as secure
-    msg = isctest.query.create("a.secure.trusted", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.3")
-    res2 = isctest.query.tcp(msg, "10.53.0.5")
-    isctest.check.noerror(res1)
-    isctest.check.noerror(res2)
-    isctest.check.adflag(res2)
-    if hasattr(res2, "extended_errors"):
-        assert not res2.extended_errors()
-
-    msg = isctest.query.create("a.secure.managed", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.3")
-    res2 = isctest.query.tcp(msg, "10.53.0.5")
-    isctest.check.noerror(res1)
-    isctest.check.noerror(res2)
-    isctest.check.adflag(res2)
-    if hasattr(res2, "extended_errors"):
-        assert not res2.extended_errors()
-
-    # check that an unsupported signing algorithm yields insecure
-    msg = isctest.query.create("a.unsupported.trusted", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.3")
-    res2 = isctest.query.tcp(msg, "10.53.0.5")
-    isctest.check.noerror(res1)
-    if hasattr(res2, "extended_errors"):
-        assert (
-            res2.extended_errors()[0].code == edns.EDECode.UNSUPPORTED_DNSKEY_ALGORITHM
-        )
-    isctest.check.noerror(res2)
-    isctest.check.noadflag(res2)
-
-    msg = isctest.query.create("a.unsupported.managed", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.3")
-    res2 = isctest.query.tcp(msg, "10.53.0.5")
-    isctest.check.noerror(res1)
-    if hasattr(res2, "extended_errors"):
-        assert (
-            res2.extended_errors()[0].code == edns.EDECode.UNSUPPORTED_DNSKEY_ALGORITHM
-        )
-    isctest.check.noerror(res2)
-    isctest.check.noadflag(res2)
-
-    # check that a disabled signing algorithm yields insecure
-    msg = isctest.query.create("a.disabled.trusted", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.3")
-    res2 = isctest.query.tcp(msg, "10.53.0.5")
-    isctest.check.noerror(res1)
-    isctest.check.noerror(res2)
-    isctest.check.noadflag(res2)
-
-    msg = isctest.query.create("a.disabled.managed", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.3")
-    res2 = isctest.query.tcp(msg, "10.53.0.5")
-    isctest.check.noerror(res1)
-    isctest.check.noerror(res2)
-    isctest.check.noadflag(res2)
-
-    # check that zone signed with an algorithm that's disabled for
-    # some other domain, but not for this one, validates as secure.
-    # "enabled.trusted." and "enabled.managed." do not match the
-    # "disable-algorithms" option, so no special rules apply. (static)
-    msg = isctest.query.create("a.enabled.trusted", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.3")
-    res2 = isctest.query.tcp(msg, "10.53.0.5")
-    isctest.check.noerror(res1)
-    isctest.check.noerror(res2)
-    isctest.check.adflag(res2)
-
-    msg = isctest.query.create("a.enabled.managed", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.3")
-    res2 = isctest.query.tcp(msg, "10.53.0.5")
-    isctest.check.noerror(res1)
-    isctest.check.noerror(res2)
-    isctest.check.adflag(res2)
-
-    # a revoked trust anchor is ignored when configured; check that
-    # this yields insecure.
-    msg = isctest.query.create("a.revoked.trusted", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.3")
-    res2 = isctest.query.tcp(msg, "10.53.0.5")
-    isctest.check.noerror(res1)
-    isctest.check.noerror(res2)
-    isctest.check.noadflag(res2)
-
-    msg = isctest.query.create("a.revoked.managed", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.3")
-    res2 = isctest.query.tcp(msg, "10.53.0.5")
-    isctest.check.noerror(res1)
-    isctest.check.noerror(res2)
-    isctest.check.noadflag(res2)
-
-
 def test_unknown_algorithms():
     # check that unknown DNSKEY algorithm validates as insecure
     msg = isctest.query.create("dnskey-unknown.example", "A", dnssec=False)
@@ -1513,117 +1344,3 @@ def test_unknown_algorithms():
     isctest.check.noerror(res1)
     isctest.check.noerror(res2)
     isctest.check.noadflag(res2)
-
-
-###################################
-##### BEGIN MANAGED KEY TESTS #####
-###################################
-def test_switch_managed(servers, templates):
-    # switch to intializing trust anchor instead of static
-    ns4 = servers["ns4"]
-    assert os.path.exists("ns4/managed-keys.bind.jnl") is False
-    shutil.copyfile("ns4/managed-keys.bind.in", "ns4/managed-keys.bind")
-    templates.render("ns4/named.conf", {"managed_key": True})
-    ns4.reconfigure(log=False)
-
-
-def test_secure_root_managed(servers):
-    # check that a query for a secure root validates
-    msg = isctest.query.create(".", "KEY")
-    res = isctest.query.tcp(msg, "10.53.0.4")
-    isctest.check.noerror(res)
-    isctest.check.adflag(res)
-
-    # check that "rndc secroots" dumps the trusted keys
-    ns4 = servers["ns4"]
-    key = int(getfrom("ns1/managed.key.id"))
-    alg = os.environ["DEFAULT_ALGORITHM"]
-    expected = f"./{alg}/{key} ; managed"
-    response = ns4.rndc("secroots -", log=False).splitlines()
-    assert expected in response
-    assert len(response) == 10
-
-
-def test_positive_validation_nsec_managed():
-    msg = isctest.query.create("a.example", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.2")
-    res2 = isctest.query.tcp(msg, "10.53.0.4")
-    isctest.check.same_answer(res1, res2)
-    isctest.check.adflag(res2)
-
-
-def test_positive_validation_nsec3_managed():
-    msg = isctest.query.create("a.nsec3.example", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.3")
-    res2 = isctest.query.tcp(msg, "10.53.0.4")
-    isctest.check.same_answer(res1, res2)
-    isctest.check.noerror(res2)
-    isctest.check.adflag(res2)
-
-
-def test_positive_validation_optout_managed():
-    msg = isctest.query.create("a.optout.example", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.3")
-    res2 = isctest.query.tcp(msg, "10.53.0.4")
-    isctest.check.same_answer(res1, res2)
-    isctest.check.adflag(res2)
-
-
-def test_negative_validation_nsec_managed():
-    # nxdomain
-    msg = isctest.query.create("q.example", "A")
-    res1 = isctest.query.tcp(msg, "10.53.0.2")
-    res2 = isctest.query.tcp(msg, "10.53.0.4")
-    isctest.check.same_answer(res1, res2)
-    isctest.check.nxdomain(res2)
-    isctest.check.adflag(res2)
-
-
-def test_ds_managed():
-    # check root DS queries validate
-    msg = isctest.query.create(".", "DS")
-    res1 = isctest.query.tcp(msg, "10.53.0.1")
-    res2 = isctest.query.tcp(msg, "10.53.0.4")
-    isctest.check.same_data(res1, res2)
-    isctest.check.adflag(res2)
-    isctest.check.noerror(res2)
-
-    # check DS queries succeed at RFC 1918 empty zone
-    msg = isctest.query.create("10.in-addr.arpa", "DS")
-    res1 = isctest.query.tcp(msg, "10.53.0.2")
-    res2 = isctest.query.tcp(msg, "10.53.0.4")
-    isctest.check.same_data(res1, res2)
-    isctest.check.noerror(res2)
-
-
-def test_keydata_storage(servers):
-    ns4 = servers["ns4"]
-    ns4.rndc("managed-keys sync", log=False)
-    with isctest.log.WatchLogFromStart("ns4/managed-keys.bind") as watcher:
-        watcher.wait_for_line(["KEYDATA", "next refresh:"])
-
-
-############################################
-##### BEGIN MULTIVIEW VALIDATION TESTS #####
-############################################
-def test_insecure_staticstub_delegation(servers, templates):
-    ns4 = servers["ns4"]
-    templates.render("ns4/named.conf", {"multi_view": True})
-    ns4.reconfigure(log=False)
-
-    # check insecure delegation between static-stub zones
-    msg = isctest.query.create("insecure.secure.example", "NS")
-    for _ in range(5):
-        res = isctest.query.tcp(msg, "10.53.0.4")
-        if res.rcode() == rcode.SERVFAIL:
-            time.sleep(1)
-            continue
-    isctest.check.noerror(res)
-
-    msg = isctest.query.create("secure.example", "NS")
-    for _ in range(5):
-        res = isctest.query.tcp(msg, "10.53.0.4")
-        if res.rcode() == rcode.SERVFAIL:
-            time.sleep(1)
-            continue
-    isctest.check.noerror(res)
diff --git a/bin/tests/system/dnssec/tests_validation_accept_expired.py b/bin/tests/system/dnssec/tests_validation_accept_expired.py
new file mode 100644 (file)
index 0000000..dc80695
--- /dev/null
@@ -0,0 +1,64 @@
+# 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.
+
+from dns import flags
+
+import pytest
+
+import isctest
+
+
+@pytest.fixture(scope="module", autouse=True)
+def reconfigure(servers, templates):
+    ns4 = servers["ns4"]
+    templates.render("ns4/named.conf", {"accept_expired": True})
+    ns4.reconfigure(log=False)
+
+
+def test_accept_expired(servers):
+    ns4 = servers["ns4"]
+
+    # test TTL of about-to-expire rrsets with accept-expired
+    ns4.rndc("flush", log=False)
+    msg = isctest.query.create("expiring.example", "SOA")
+    msg.flags |= flags.CD
+    res1 = isctest.query.tcp(msg, "10.53.0.4")
+    msg = isctest.query.create("expiring.example", "SOA")
+    res2 = isctest.query.tcp(msg, "10.53.0.4")
+    for rrset in res1.answer:
+        assert rrset.ttl <= 3600
+    for rrset in res2.answer:
+        assert rrset.ttl <= 120
+
+    # test TTL is capped at RRSIG expiry time in the additional section
+    # with accept-expired
+    ns4.rndc("flush", log=False)
+    msg = isctest.query.create("expiring.example", "MX")
+    msg.flags |= flags.CD
+    res1 = isctest.query.tcp(msg, "10.53.0.4")
+    msg = isctest.query.create("expiring.example", "MX")
+    res2 = isctest.query.tcp(msg, "10.53.0.4")
+    for rrset in res1.additional:
+        assert rrset.ttl <= 3600
+    for rrset in res2.additional:
+        assert rrset.ttl <= 120
+
+    # test TTL of expired rrsets with accept-expired
+    ns4.rndc("flush", log=False)
+    msg = isctest.query.create("expired.example", "SOA")
+    msg.flags |= flags.CD
+    res1 = isctest.query.tcp(msg, "10.53.0.4")
+    msg = isctest.query.create("expired.example", "SOA")
+    res2 = isctest.query.tcp(msg, "10.53.0.4")
+    for rrset in res1.additional:
+        assert rrset.ttl <= 3600
+    for rrset in res2.additional:
+        assert rrset.ttl <= 120
diff --git a/bin/tests/system/dnssec/tests_validation_managed_keys.py b/bin/tests/system/dnssec/tests_validation_managed_keys.py
new file mode 100644 (file)
index 0000000..7195818
--- /dev/null
@@ -0,0 +1,108 @@
+# 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 shutil
+
+import pytest
+
+import isctest
+
+
+@pytest.fixture(scope="module", autouse=True)
+def reconfigure(servers, templates):
+    ns4 = servers["ns4"]
+    assert os.path.exists("ns4/managed-keys.bind.jnl") is False
+    shutil.copyfile("ns4/managed-keys.bind.in", "ns4/managed-keys.bind")
+    templates.render("ns4/named.conf", {"managed_key": True})
+    ns4.reconfigure(log=False)
+
+
+# helper functions
+def getfrom(file):
+    with open(file, encoding="utf-8") as f:
+        return f.read().strip()
+
+
+def test_secure_root_managed(servers):
+    # check that a query for a secure root validates
+    msg = isctest.query.create(".", "KEY")
+    res = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.noerror(res)
+    isctest.check.adflag(res)
+
+    # check that "rndc secroots" dumps the trusted keys
+    ns4 = servers["ns4"]
+    key = int(getfrom("ns1/managed.key.id"))
+    alg = os.environ["DEFAULT_ALGORITHM"]
+    expected = f"./{alg}/{key} ; managed"
+    response = ns4.rndc("secroots -", log=False).splitlines()
+    assert expected in response
+    assert len(response) == 10
+
+
+def test_positive_validation_nsec_managed():
+    msg = isctest.query.create("a.example", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.2")
+    res2 = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.same_answer(res1, res2)
+    isctest.check.adflag(res2)
+
+
+def test_positive_validation_nsec3_managed():
+    msg = isctest.query.create("a.nsec3.example", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.3")
+    res2 = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.same_answer(res1, res2)
+    isctest.check.noerror(res2)
+    isctest.check.adflag(res2)
+
+
+def test_positive_validation_optout_managed():
+    msg = isctest.query.create("a.optout.example", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.3")
+    res2 = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.same_answer(res1, res2)
+    isctest.check.adflag(res2)
+
+
+def test_negative_validation_nsec_managed():
+    # nxdomain
+    msg = isctest.query.create("q.example", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.2")
+    res2 = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.same_answer(res1, res2)
+    isctest.check.nxdomain(res2)
+    isctest.check.adflag(res2)
+
+
+def test_ds_managed():
+    # check root DS queries validate
+    msg = isctest.query.create(".", "DS")
+    res1 = isctest.query.tcp(msg, "10.53.0.1")
+    res2 = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.same_data(res1, res2)
+    isctest.check.adflag(res2)
+    isctest.check.noerror(res2)
+
+    # check DS queries succeed at RFC 1918 empty zone
+    msg = isctest.query.create("10.in-addr.arpa", "DS")
+    res1 = isctest.query.tcp(msg, "10.53.0.2")
+    res2 = isctest.query.tcp(msg, "10.53.0.4")
+    isctest.check.same_data(res1, res2)
+    isctest.check.noerror(res2)
+
+
+def test_keydata_storage(servers):
+    ns4 = servers["ns4"]
+    ns4.rndc("managed-keys sync", log=False)
+    with isctest.log.WatchLogFromStart("ns4/managed-keys.bind") as watcher:
+        watcher.wait_for_line(["KEYDATA", "next refresh:"])
diff --git a/bin/tests/system/dnssec/tests_validation_many_anchors.py b/bin/tests/system/dnssec/tests_validation_many_anchors.py
new file mode 100644 (file)
index 0000000..47c3277
--- /dev/null
@@ -0,0 +1,137 @@
+# 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.
+
+from dns import edns
+import pytest
+
+import isctest
+
+
+@pytest.fixture(scope="module", autouse=True)
+def reconfigure(servers, templates):
+    ns5 = servers["ns5"]
+    templates.render("ns5/named.conf", {"many_anchors": True})
+    with ns5.watch_log_from_here() as watcher:
+        ns5.reconfigure(log=False)
+        watcher.wait_for_line(
+            [
+                "ignoring static-key for 'disabled.trusted.': algorithm is disabled",
+                "ignoring static-key for 'disabled.managed.': algorithm is disabled",
+                "ignoring static-key for 'unsupported.trusted.': algorithm is unsupported",
+                "ignoring static-key for 'unsupported.managed.': algorithm is unsupported",
+                "ignoring static-key for 'unsupported.managed.': algorithm is unsupported",
+                "ignoring static-key for 'revoked.trusted.': bad key type",
+                "ignoring static-key for 'revoked.managed.': bad key type",
+            ]
+        )
+
+
+def test_trust_anchors():
+    # DNSSEC tests related to unsupported, disabled and revoked trust anchors.
+    #
+    # This nameserver is loaded with a bunch of trust anchors.
+    # Some of them are good (enabled.managed, enabled.trusted,
+    # secure.managed, secure.trusted), and some of them are bad
+    # (disabled.managed, revoked.managed, unsupported.managed,
+    # disabled.trusted, revoked.trusted, unsupported.trusted).  Make sure
+    # that the bad trust anchors are ignored.  This is tested by looking
+    # for the corresponding lines in the logfile.
+
+    # check that a key with supported algorithm validates as secure
+    msg = isctest.query.create("a.secure.trusted", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.3")
+    res2 = isctest.query.tcp(msg, "10.53.0.5")
+    isctest.check.noerror(res1)
+    isctest.check.noerror(res2)
+    isctest.check.adflag(res2)
+    if hasattr(res2, "extended_errors"):
+        assert not res2.extended_errors()
+
+    msg = isctest.query.create("a.secure.managed", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.3")
+    res2 = isctest.query.tcp(msg, "10.53.0.5")
+    isctest.check.noerror(res1)
+    isctest.check.noerror(res2)
+    isctest.check.adflag(res2)
+    if hasattr(res2, "extended_errors"):
+        assert not res2.extended_errors()
+
+    # check that an unsupported signing algorithm yields insecure
+    msg = isctest.query.create("a.unsupported.trusted", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.3")
+    res2 = isctest.query.tcp(msg, "10.53.0.5")
+    isctest.check.noerror(res1)
+    if hasattr(res2, "extended_errors"):
+        assert (
+            res2.extended_errors()[0].code == edns.EDECode.UNSUPPORTED_DNSKEY_ALGORITHM
+        )
+    isctest.check.noerror(res2)
+    isctest.check.noadflag(res2)
+
+    msg = isctest.query.create("a.unsupported.managed", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.3")
+    res2 = isctest.query.tcp(msg, "10.53.0.5")
+    isctest.check.noerror(res1)
+    if hasattr(res2, "extended_errors"):
+        assert (
+            res2.extended_errors()[0].code == edns.EDECode.UNSUPPORTED_DNSKEY_ALGORITHM
+        )
+    isctest.check.noerror(res2)
+    isctest.check.noadflag(res2)
+
+    # check that a disabled signing algorithm yields insecure
+    msg = isctest.query.create("a.disabled.trusted", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.3")
+    res2 = isctest.query.tcp(msg, "10.53.0.5")
+    isctest.check.noerror(res1)
+    isctest.check.noerror(res2)
+    isctest.check.noadflag(res2)
+
+    msg = isctest.query.create("a.disabled.managed", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.3")
+    res2 = isctest.query.tcp(msg, "10.53.0.5")
+    isctest.check.noerror(res1)
+    isctest.check.noerror(res2)
+    isctest.check.noadflag(res2)
+
+    # check that zone signed with an algorithm that's disabled for
+    # some other domain, but not for this one, validates as secure.
+    # "enabled.trusted." and "enabled.managed." do not match the
+    # "disable-algorithms" option, so no special rules apply. (static)
+    msg = isctest.query.create("a.enabled.trusted", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.3")
+    res2 = isctest.query.tcp(msg, "10.53.0.5")
+    isctest.check.noerror(res1)
+    isctest.check.noerror(res2)
+    isctest.check.adflag(res2)
+
+    msg = isctest.query.create("a.enabled.managed", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.3")
+    res2 = isctest.query.tcp(msg, "10.53.0.5")
+    isctest.check.noerror(res1)
+    isctest.check.noerror(res2)
+    isctest.check.adflag(res2)
+
+    # a revoked trust anchor is ignored when configured; check that
+    # this yields insecure.
+    msg = isctest.query.create("a.revoked.trusted", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.3")
+    res2 = isctest.query.tcp(msg, "10.53.0.5")
+    isctest.check.noerror(res1)
+    isctest.check.noerror(res2)
+    isctest.check.noadflag(res2)
+
+    msg = isctest.query.create("a.revoked.managed", "A")
+    res1 = isctest.query.tcp(msg, "10.53.0.3")
+    res2 = isctest.query.tcp(msg, "10.53.0.5")
+    isctest.check.noerror(res1)
+    isctest.check.noerror(res2)
+    isctest.check.noadflag(res2)
diff --git a/bin/tests/system/dnssec/tests_validation_multiview.py b/bin/tests/system/dnssec/tests_validation_multiview.py
new file mode 100644 (file)
index 0000000..e8d2168
--- /dev/null
@@ -0,0 +1,62 @@
+# 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 pytest
+
+import isctest
+
+
+@pytest.fixture(scope="module", autouse=True)
+def reconfigure(servers, templates):
+    ns4 = servers["ns4"]
+    templates.render("ns4/named.conf", {"multi_view": True})
+    ns4.reconfigure(log=False)
+
+
+def getfrom(file):
+    with open(file, encoding="utf-8") as f:
+        return f.read().strip()
+
+
+def test_staticstub_delegations():
+    # check insecure delegation between static-stub zones
+    def docheck():
+        msg = isctest.query.create("insecure.secure.example", "NS")
+        res = isctest.query.tcp(msg, "10.53.0.4")
+        isctest.check.noerror(res)
+        msg = isctest.query.create("secure.example", "NS")
+        res = isctest.query.tcp(msg, "10.53.0.4")
+        isctest.check.noerror(res)
+        return True
+
+    isctest.run.retry_with_timeout(docheck, 5)
+
+
+def test_validator_logging(ns4):
+    # check that validator logging includes the view name with multiple views
+    pattern = re.compile("view rec: *validat")
+    with ns4.watch_log_from_start() as watcher:
+        msg = isctest.query.create("secure.example", "NS")
+        isctest.query.tcp(msg, "10.53.0.4")
+        watcher.wait_for_line(pattern)
+
+
+def test_secure_roots(ns4):
+    # check that "rndc secroots" dumps the trusted keys with multiple views
+    key = int(getfrom("ns1/managed.key.id"))
+    alg = os.environ["DEFAULT_ALGORITHM"]
+    expected = f"./{alg}/{key} ; static"
+    response = ns4.rndc("secroots -", log=False).splitlines()
+    assert expected in response, response
+    assert len(response) == 17
index 088a3c5a1d5f7df2ef7bb100785d68e56f2e331a..f4ca8d3e7f88369386812832b5b7257354393500 100644 (file)
@@ -13,8 +13,6 @@ import os
 import re
 import time
 
-import pytest
-
 import isctest