From: Matthijs Mekking Date: Thu, 16 Apr 2026 14:17:34 +0000 (+0200) Subject: Add test for SIG in prequisites of dynamic update X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ab16e86a5035347df8a23feb78e135020a1403e5;p=thirdparty%2Fbind9.git Add test for SIG in prequisites of dynamic update Make sure the nameserver correctly handles SIG records in the prerequisites of the dynamic update. The first check is to ensure that the prerequisites are not examined prior to checking the credentials. The second test case checks that the SIG present prerequisite is examined and therefore refuses the update. Also this should not trigger an assertion failure in dns__db_findrdataset() (due to the REQUIRE() only accepted dns_rdatatype_rrsig when the covers parameter was set). (cherry picked from commit 51f27fda46870acea69835f82835ca857c000bd0) --- diff --git a/bin/tests/system/nsupdate/tests_sh_nsupdate.py b/bin/tests/system/nsupdate/tests_sh_nsupdate.py index f3ddfe2c01f..8239d668dd8 100644 --- a/bin/tests/system/nsupdate/tests_sh_nsupdate.py +++ b/bin/tests/system/nsupdate/tests_sh_nsupdate.py @@ -58,6 +58,7 @@ pytestmark = pytest.mark.extra_artifacts( "ns5/local.db", "ns6/2.0.0.2.ip6.addr.db", "ns6/in-addr.db", + "ns6/sigaxfr.bk", "ns7/_default.tsigkeys", "ns7/example.com.db", "ns7/in-addr.db", diff --git a/bin/tests/system/nsupdate/tests_tcp_self_sig.py b/bin/tests/system/nsupdate/tests_update_sig.py similarity index 83% rename from bin/tests/system/nsupdate/tests_tcp_self_sig.py rename to bin/tests/system/nsupdate/tests_update_sig.py index 6e83aded291..261b47efa2f 100644 --- a/bin/tests/system/nsupdate/tests_tcp_self_sig.py +++ b/bin/tests/system/nsupdate/tests_update_sig.py @@ -32,16 +32,38 @@ by the AXFR-based regression test in this file. """ import time +from pathlib import Path import dns.rcode import dns.rdata import dns.rdataclass import dns.rdataset import dns.rdatatype +import dns.tsigkeyring import dns.update +import pytest import isctest +pytestmark = pytest.mark.extra_artifacts( + [ + "ans*/ans.run", + "ns*/*.bk", + "ns*/*.conf", + "ns*/*.db", + "ns*/*.db.jnl", + "ns*/*.db.signed", + "ns*/*.jnl", + "ns*/*.key", + "ns*/K*.key", + "ns*/K*.private", + "ns*/K*.state", + "ns*/dsset-*.", + "ns6/sigaxfr.bk", + "verylarge", + ] +) + def _make_sig_rdata(text): """Create a SIG rdata from text. @@ -79,9 +101,9 @@ def test_tcp_self_sig_record(ns6): crash-reproducing precondition. """ ptr_update = dns.update.UpdateMessage("in-addr.arpa.") - ptr_update.add("1.0.0.127.in-addr.arpa.", 600, "PTR", "localhost.") + ptr_update.add("1.0.53.10.in-addr.arpa.", 600, "PTR", "localhost.") response = isctest.query.tcp( - ptr_update, ns6.ip, port=ns6.ports.dns, source="127.0.0.1" + ptr_update, ns6.ip, port=ns6.ports.dns, source="10.53.0.1" ) assert response.rcode() == dns.rcode.NOERROR @@ -92,18 +114,58 @@ def test_tcp_self_sig_record(ns6): sig_update = dns.update.UpdateMessage("in-addr.arpa.") sig_update.add("1.0.0.127.in-addr.arpa.", rds) - response = isctest.query.tcp( - sig_update, ns6.ip, port=ns6.ports.dns, source="127.0.0.1" - ) - assert response.rcode() == dns.rcode.REFUSED + with ns6.watch_log_from_here() as watcher: + response = isctest.query.tcp( + sig_update, ns6.ip, port=ns6.ports.dns, source="10.53.0.1" + ) + assert response.rcode() == dns.rcode.REFUSED + + watcher.wait_for_line( + "updating zone 'in-addr.arpa/IN': update failed: SIG updates are not allowed (REFUSED)" + ) # Confirm nothing of type SIG was stored. - msg = isctest.query.create("1.0.0.127.in-addr.arpa.", "SIG") + msg = isctest.query.create("1.0.53.10.in-addr.arpa.", "SIG") res = isctest.query.tcp(msg, ns6.ip, port=ns6.ports.dns) stored = any(rrset.rdtype == dns.rdatatype.SIG for rrset in res.answer) assert not stored, "SIG record was stored despite REFUSED response" +def test_tcp_self_nxt_record(ns6): + """NXT (type 30) updates must be refused at the front door. + + NXT is the legacy DNSSEC denial-of-existence type, obsolete since + RFC 3755 replaced it with NSEC. Accepting it via dynamic update + would let an authorised updater inject records that the signing + and cut-point logic has no provision for. + """ + # A second owner under a source that also matches tcp-self. + source = "10.53.0.2" + owner = "2.0.53.10.in-addr.arpa." + + ptr_update = dns.update.UpdateMessage("in-addr.arpa.") + ptr_update.add(owner, 600, "PTR", "localhost.") + response = isctest.query.tcp(ptr_update, ns6.ip, port=ns6.ports.dns, source=source) + assert response.rcode() == dns.rcode.NOERROR + + nxt = _make_nxt_rdata() + rds = dns.rdataset.Rdataset(dns.rdataclass.IN, dns.rdatatype.NXT) + rds.update_ttl(600) + rds.add(nxt) + nxt_update = dns.update.UpdateMessage("in-addr.arpa.") + nxt_update.add(owner, rds) + + with ns6.watch_log_from_here() as watcher: + response = isctest.query.tcp( + nxt_update, ns6.ip, port=ns6.ports.dns, source="10.53.0.1" + ) + assert response.rcode() == dns.rcode.REFUSED + + watcher.wait_for_line( + "updating zone 'in-addr.arpa/IN': update failed: NXT updates are not allowed (REFUSED)" + ) + + def test_sig_covers_preserved_via_axfr(ns6): """Regression test for GL#5818 Finding 1, reached via AXFR. @@ -122,7 +184,7 @@ def test_sig_covers_preserved_via_axfr(ns6): """ zone = "sigaxfr.nil" owner = f"host.{zone}." - dump_path = ns6.directory / "named_dump.db" + dump_path = Path("ns6") / "named_dump.db" # ns6 may have tried to SOA-poll ans11 before it was listening; force # a fresh refresh attempt and wait for the transfer to complete. @@ -170,31 +232,3 @@ def test_sig_covers_preserved_via_axfr(ns6): "the Finding 1 bug both records are filed under typepair (SIG, 0) " "and share the first-seen TTL (600)." ) - - -def test_tcp_self_nxt_record(ns6): - """NXT (type 30) updates must be refused at the front door. - - NXT is the legacy DNSSEC denial-of-existence type, obsolete since - RFC 3755 replaced it with NSEC. Accepting it via dynamic update - would let an authorised updater inject records that the signing - and cut-point logic has no provision for. - """ - # A second owner under a source that also matches tcp-self. - source = "127.0.0.2" - owner = "2.0.0.127.in-addr.arpa." - - ptr_update = dns.update.UpdateMessage("in-addr.arpa.") - ptr_update.add(owner, 600, "PTR", "localhost.") - response = isctest.query.tcp(ptr_update, ns6.ip, port=ns6.ports.dns, source=source) - assert response.rcode() == dns.rcode.NOERROR - - nxt = _make_nxt_rdata() - rds = dns.rdataset.Rdataset(dns.rdataclass.IN, dns.rdatatype.NXT) - rds.update_ttl(600) - rds.add(nxt) - nxt_update = dns.update.UpdateMessage("in-addr.arpa.") - nxt_update.add(owner, rds) - - response = isctest.query.tcp(nxt_update, ns6.ip, port=ns6.ports.dns, source=source) - assert response.rcode() == dns.rcode.REFUSED