Add system test for SIG record handling in update-policy tcp-self

Verify that a SIG record sent via TCP dynamic update is accepted
by the tcp-self update-policy and correctly stored in the zone.

(cherry picked from commit ecddeab696)
This commit is contained in:
Ondřej Surý 2026-04-07 16:40:36 +02:00
parent 62920a981f
commit 7e5c15ce9b

View file

@ -0,0 +1,88 @@
# 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.
"""
Regression test for GL#5818: update-policy tcp-self must handle SIG records.
The dns_db_findrdataset() REQUIRE check only accepted dns_rdatatype_rrsig
for the covers parameter, causing named to abort when processing a SIG
record (type 24) via dynamic update with tcp-self policy.
"""
import dns.rcode
import dns.rdata
import dns.rdataclass
import dns.rdataset
import dns.rdatatype
import dns.update
import isctest
def _make_sig_rdata(text):
"""Create a SIG rdata from text.
dnspython has no native text parser for the legacy SIG type (24),
but the wire format is identical to RRSIG (46). Parse as RRSIG,
then re-wrap as SIG via the wire representation.
"""
rrsig = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.RRSIG, text)
wire = rrsig.to_digestable()
return dns.rdata.from_wire(dns.rdataclass.IN, dns.rdatatype.SIG, wire, 0, len(wire))
def test_tcp_self_sig_record(ns6):
"""Verify that update-policy tcp-self accepts a SIG record via TCP.
The node must already exist (have at least one RR) so that
dns_db_findrdataset() is called during the update that is the
function whose REQUIRE was too strict. We therefore add a PTR
record first.
"""
# First, create the node by adding a PTR record (allowed by tcp-self).
ptr_update = dns.update.UpdateMessage("in-addr.arpa.")
ptr_update.add("1.0.0.127.in-addr.arpa.", 600, "PTR", "localhost.")
response = isctest.query.tcp(
ptr_update, ns6.ip, port=ns6.ports.dns, source="127.0.0.1"
)
assert response.rcode() == dns.rcode.NOERROR
# Now add a SIG record at the same node — this triggers the
# dns_db_findrdataset() call with type=SIG and covers=A.
sig = _make_sig_rdata("A 6 0 86400 20260331170000 20260318160000 21831 . 0000")
rds = dns.rdataset.Rdataset(dns.rdataclass.IN, dns.rdatatype.SIG)
rds.update_ttl(600)
rds.add(sig)
sig_update = dns.update.UpdateMessage("in-addr.arpa.")
sig_update.add("1.0.0.127.in-addr.arpa.", rds)
with ns6.watch_log_from_here() as watcher:
response = isctest.query.tcp(
sig_update, ns6.ip, port=ns6.ports.dns, source="127.0.0.1"
)
assert response.rcode() == dns.rcode.NOERROR
watcher.wait_for_sequence(
[
"update-policy: using: signer= name=1.0.0.127.in-addr.arpa"
" addr=127.0.0.1 tcp=1 type=SIG target=",
"update-policy: trying: grant * tcp-self . PTR(1) ANY(2) A",
"update-policy: tcp-self=1.0.0.127.IN-ADDR.ARPA",
"update-policy: matched: grant * tcp-self . PTR(1) ANY(2) A",
]
)
# Verify the SIG record was actually stored
msg = isctest.query.create("1.0.0.127.in-addr.arpa.", "SIG")
res = isctest.query.tcp(msg, ns6.ip, port=ns6.ports.dns)
found = any(rrset.rdtype == dns.rdatatype.SIG for rrset in res.answer)
assert found, "SIG record not found in answer section"