Commit 2f5f55f614 for bind
commit 2f5f55f6144d1012262b4c5c1f2865cee36ec6d0
Author: Evan Hunt <each@isc.org>
Date: Sat Feb 7 23:48:47 2026 -0800
Create deleg auth test
isctest.query has been extended to take an option to send or
suppress the DE flag with queries, similar to the DO flag.
The default is to send it.
Tests have been added that query deleg-containing zones at the zone
apex, normal non-zonecut nodes, and at and below zonecuts delegated
using NS, DELEG, or both, with and without the DO and DE bits, with
zones signed with NSEC, NSEC3, and NSEC3+OPTOUT, and unsigned.
The checkzone test has been updated to check that a zone is rejected
if there is a DELEG at the zone apex, if a DELEG points to a name in
the delegated zone, or if DELEG is defined in a non-IN zone.
diff --git a/bin/tests/system/checkzone/tests.sh b/bin/tests/system/checkzone/tests.sh
index 9d380e0519..b97fa76eaf 100644
--- a/bin/tests/system/checkzone/tests.sh
+++ b/bin/tests/system/checkzone/tests.sh
@@ -167,6 +167,14 @@ for db in zones/bad*.db; do
$CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$?
grep "zones/badttl.db:1: unexpected end of line" test.out.$n >/dev/null || ret=1
;;
+ zones/bad-deleg-apex.db)
+ $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$?
+ grep "bad-deleg-apex.db:15: DELEG record at top of zone (example)" test.out.$n >/dev/null || ret=1
+ ;;
+ zones/bad-deleg-into-zone.db)
+ $CHECKZONE -i local example $db >test.out.$n 2>&1 || v=$?
+ grep "DELEG: invalid target name 'ns.sub.example'" test.out.$n >/dev/null || ret=1
+ ;;
*)
ret=1
echo "add case entry for $db"
@@ -454,5 +462,13 @@ n=$((n + 1))
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
+echo_i "Checking DELEG in a non-IN zone ($n)"
+ret=0
+$CHECKZONE example zones/deleg.db >test.out.$n || ret=1
+$CHECKZONE -c chaos example zones/deleg.db >test.out.$n && ret=1
+n=$((n + 1))
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=$((status + ret))
+
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1
diff --git a/bin/tests/system/checkzone/zones/bad-deleg-apex.db b/bin/tests/system/checkzone/zones/bad-deleg-apex.db
new file mode 100644
index 0000000000..6c32359d9e
--- /dev/null
+++ b/bin/tests/system/checkzone/zones/bad-deleg-apex.db
@@ -0,0 +1,16 @@
+; 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 600
+@ SOA ns hostmaster 2011012708 3600 1200 604800 1200
+ NS ns
+ DELEG server-ipv4=192.0.2.1
+ns A 192.0.2.1
diff --git a/bin/tests/system/checkzone/zones/bad-deleg-into-zone.db b/bin/tests/system/checkzone/zones/bad-deleg-into-zone.db
new file mode 100644
index 0000000000..5379c5a1f3
--- /dev/null
+++ b/bin/tests/system/checkzone/zones/bad-deleg-into-zone.db
@@ -0,0 +1,17 @@
+; 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 600
+@ SOA ns hostmaster 2011012708 3600 1200 604800 1200
+ NS ns
+ns A 192.0.2.1
+
+sub DELEG server-name=ns.sub
diff --git a/bin/tests/system/checkzone/zones/deleg.db b/bin/tests/system/checkzone/zones/deleg.db
new file mode 100644
index 0000000000..6867266d67
--- /dev/null
+++ b/bin/tests/system/checkzone/zones/deleg.db
@@ -0,0 +1,14 @@
+; 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.
+
+@ SOA . . 0 0 0 0 0
+@ NS .
+sub DELEG server-ipv4=192.0.0.1
diff --git a/bin/tests/system/deleg/ns1/example.db.in b/bin/tests/system/deleg/ns1/example.db.in
new file mode 100644
index 0000000000..1495c053e0
--- /dev/null
+++ b/bin/tests/system/deleg/ns1/example.db.in
@@ -0,0 +1,74 @@
+; 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 300 ; 5 minutes
+@ IN SOA mname1. . (
+ 2000042407 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+ NS ns1
+ns1 A 10.53.0.1
+
+; Used for testing ANY queries
+foo TXT "testing"
+foo A 10.0.1.0
+
+; Used for testing CNAME queries
+cname1 CNAME cname1-target
+cname1-target TXT "testing cname"
+
+; Used for testing DNAME queries
+dname1 DNAME dname1-target
+foo.dname1-target TXT "testing dname"
+
+; An NS-delegated subdomain
+nsonly TXT "this should be occluded"
+nsonly NS ns3.nsonly
+ns3.nsonly A 10.53.0.3
+
+; NS-delegated secure delegation
+nsonly-ds TXT "this should be occluded"
+nsonly-ds DS 7250 13 2 A30B3F78B6DDE9A4A9A2AD0C805518B4F49EC62E7D3F4531D33DE697CDA01CB2
+nsonly-ds NS ns3.nsonly-ds
+ns3.nsonly-ds A 10.53.0.3
+
+; A DELEG-delegated subdomain
+delegonly TXT "this should be occluded"
+delegonly DELEG server-ipv4=10.53.0.3
+
+; DELEG-delegated secure delegation
+delegonly-ds TXT "this should be occluded"
+delegonly-ds DS 7250 13 2 A30B3F78B6DDE9A4A9A2AD0C805518B4F49EC62E7D3F4531D33DE697CDA01CB2
+delegonly-ds DELEG server-ipv4=10.53.0.3
+
+; A subdomain delegated with both NS and DELEG
+mixed TXT "this should be occluded"
+mixed DELEG server-ipv4=10.53.0.3
+mixed NS ns3.mixed
+ns3.mixed A 10.53.0.3
+
+; A secure delegation with both NS and DELEG
+mixed-ds TXT "this should be occluded"
+mixed-ds DS 7250 13 2 A30B3F78B6DDE9A4A9A2AD0C805518B4F49EC62E7D3F4531D33DE697CDA01CB2
+mixed-ds DELEG server-ipv4=10.53.0.3
+mixed-ds NS ns3.mixed
+ns3.mixed-ds A 10.53.0.3
+
+*.wild A 10.0.0.27
+
+; normal positive answer
+data TXT "answer"
+
+; positive answer below an ENT
+data.empty.data TXT "answer below ENT"
diff --git a/bin/tests/system/deleg/ns1/named.conf.j2 b/bin/tests/system/deleg/ns1/named.conf.j2
new file mode 100644
index 0000000000..444c03b3a5
--- /dev/null
+++ b/bin/tests/system/deleg/ns1/named.conf.j2
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+// 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;
+ allow-transfer { any; };
+};
+
+dnssec-policy nsec {
+ dnskey-ttl 3600;
+ parent-ds-ttl 3600;
+ keys {
+ zsk key-directory lifetime 60d algorithm ecdsa256;
+ ksk key-directory lifetime unlimited algorithm ecdsa256;
+ };
+};
+
+dnssec-policy nsec3 {
+ dnskey-ttl 3600;
+ parent-ds-ttl 3600;
+ nsec3param iterations 0 optout no;
+ keys {
+ zsk key-directory lifetime 60d algorithm ecdsa256;
+ ksk key-directory lifetime unlimited algorithm ecdsa256;
+ };
+};
+
+dnssec-policy optout {
+ dnskey-ttl 3600;
+ parent-ds-ttl 3600;
+ nsec3param iterations 0 optout yes;
+ keys {
+ zsk key-directory lifetime 60d algorithm ecdsa256;
+ ksk key-directory lifetime unlimited algorithm ecdsa256;
+ };
+};
+
+zone nsec {
+ type primary;
+ file "nsec.db";
+ initial-file "example.db.in";
+ dnssec-policy nsec;
+ allow-update { any; };
+};
+
+zone nsec3 {
+ type primary;
+ file "nsec3.db";
+ initial-file "example.db.in";
+ dnssec-policy nsec3;
+};
+
+zone optout {
+ type primary;
+ file "optout.db";
+ initial-file "example.db.in";
+ dnssec-policy optout;
+};
+
+zone unsigned {
+ type primary;
+ file "unsigned.db";
+ initial-file "example.db.in";
+ dnssec-policy none;
+};
diff --git a/bin/tests/system/deleg/tests_auth.py b/bin/tests/system/deleg/tests_auth.py
new file mode 100644
index 0000000000..b84f45311d
--- /dev/null
+++ b/bin/tests/system/deleg/tests_auth.py
@@ -0,0 +1,441 @@
+# 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 time
+
+from dns import rdatatype, update
+
+import pytest
+
+import isctest
+import isctest.mark
+
+pytestmark = pytest.mark.extra_artifacts(
+ [
+ "*/K*",
+ "*/dsset-*",
+ "*/*.bk",
+ "*/*.conf",
+ "*/*.db",
+ "*/*.jnl",
+ "*/*.jbk",
+ "*/*.key",
+ "*/*.signed",
+ ]
+)
+
+
+# wait for all of the signed zones to get their signatures
+# before running any tests.
+@pytest.fixture(scope="module", autouse=True)
+def after_servers_start():
+ for zone in ("nsec", "nsec3", "optout"):
+ msg = isctest.query.create(zone, "soa")
+ while True:
+ res = isctest.query.tcp(msg, "10.53.0.1")
+ if len(res.answer) == 1:
+ continue
+ time.sleep(1)
+ break
+
+
+def getfrom(file):
+ with open(file, encoding="utf-8") as f:
+ return f.read().strip()
+
+
+@pytest.mark.parametrize(
+ "zone",
+ [
+ "nsec",
+ "nsec3",
+ "optout",
+ "unsigned",
+ ],
+)
+def test_capture_signed(zone):
+ # This "test" doesn't test anything, it just dumps the signed
+ # version of the test zones into the pytest log so they can be
+ # used for debugging when needed.
+ msg = isctest.query.create(f"{zone}", "axfr")
+ isctest.query.tcp(msg, "10.53.0.1")
+
+
+@pytest.mark.requires_zones_loaded("ns1")
+@pytest.mark.parametrize(
+ "qtype",
+ ["soa", "ns", "ds", 61440],
+)
+@pytest.mark.parametrize(
+ "zone",
+ [
+ "nsec",
+ "nsec3",
+ "optout",
+ "unsigned",
+ ],
+)
+def test_apex_answers(zone, qtype):
+ signed = zone != "unsigned"
+
+ msg = isctest.query.create(zone, qtype)
+ res = isctest.query.tcp(msg, "10.53.0.1")
+ isctest.check.noerror(res)
+ isctest.check.aaflag(res)
+ if qtype == "soa":
+ isctest.check.rr_count_eq(res.answer, 2 if signed else 1)
+ isctest.check.rr_count_eq(res.additional, 0)
+ isctest.check.rr_count_eq(res.authority, 0)
+ elif qtype == "ns":
+ isctest.check.rr_count_eq(res.answer, 2 if signed else 1)
+ isctest.check.rr_count_eq(res.additional, 2 if signed else 1)
+ isctest.check.rr_count_eq(res.authority, 0)
+ elif qtype in ("ds", 61440):
+ isctest.check.rr_count_eq(res.answer, 0)
+ isctest.check.rr_count_eq(res.additional, 0)
+ isctest.check.rr_count_eq(res.authority, 4 if signed else 1)
+
+
+@pytest.mark.requires_zones_loaded("ns1")
+@pytest.mark.parametrize(
+ "do, de",
+ [
+ [True, True],
+ [True, False],
+ [False, True],
+ [False, False],
+ ],
+)
+@pytest.mark.parametrize(
+ "name",
+ [
+ "data",
+ "empty.data",
+ "data.empty.data",
+ ],
+)
+@pytest.mark.parametrize(
+ "zone",
+ [
+ "nsec",
+ "nsec3",
+ "optout",
+ "unsigned",
+ ],
+)
+def test_non_apex_answer(name, zone, do, de):
+ populated = name != "empty.data"
+ signed = do and (zone != "unsigned")
+
+ msg = isctest.query.create(f"{name}.{zone}", "txt", dnssec=do, deleg=de)
+ res = isctest.query.tcp(msg, "10.53.0.1")
+ isctest.check.noerror(res)
+
+ if populated:
+ isctest.check.rr_count_eq(res.answer, 2 if signed else 1)
+ sig = [
+ r
+ for r in res.answer
+ if str(r.name) == f"{name}.{zone}."
+ and r.rdtype == rdatatype.RRSIG
+ and r.covers == rdatatype.TXT
+ ]
+ assert (signed and sig) or (not signed and not sig)
+ else:
+ isctest.check.rr_count_eq(res.answer, 0)
+ isctest.check.rr_count_eq(res.authority, 4 if signed else 1)
+
+
+@pytest.mark.requires_zones_loaded("ns1")
+@pytest.mark.parametrize(
+ "do, de",
+ [
+ [True, True],
+ [True, False],
+ [False, True],
+ [False, False],
+ ],
+)
+@pytest.mark.parametrize(
+ "qtype",
+ [
+ 61440, # deleg is not yet defined by dnspython
+ "nsec",
+ "txt",
+ "a",
+ ],
+)
+@pytest.mark.parametrize(
+ "name",
+ [
+ "nsonly",
+ "delegonly",
+ "mixed",
+ ],
+)
+@pytest.mark.parametrize(
+ "zone",
+ [
+ "nsec",
+ "nsec3",
+ "optout",
+ "unsigned",
+ ],
+)
+def test_zonecut_answers(name, zone, qtype, do, de):
+ # which delegation type should we expect?
+ has_ns = name in ("mixed", "nsonly")
+ has_deleg = name in ("mixed", "delegonly")
+
+ # answers without DO should be the same as unsigned
+ signed = do and (zone != "unsigned")
+ optout = do and (zone == "optout")
+
+ # skip queries for NSEC or DELEG for zones and names that don't have them
+ if qtype == "nsec" and zone != "nsec":
+ return
+ if qtype == 61440 and not has_deleg:
+ return
+
+ msg = isctest.query.create(f"{name}.{zone}", qtype, dnssec=do, deleg=de)
+ res = isctest.query.tcp(msg, "10.53.0.1")
+ isctest.check.noerror(res)
+
+ # check that we get the EDE response for DELEG-only referrals if !DE
+ if has_deleg and not has_ns and qtype != 61440 and qtype != "nsec":
+ if not de:
+ isctest.check.ede(res, 34)
+ else:
+ isctest.check.noede(res)
+
+ # we don't treat deleg as an atparent type if the client is
+ # deleg-unaware or there's an NS that can override it.
+ atparent = qtype == "nsec" or (qtype == 61440 and (de or not has_ns))
+
+ # check that DELEG is in the NSEC bitmap, if present
+ if qtype == "nsec" and has_deleg:
+ assert "TYPE61440" in str(res.answer[0])
+ if qtype == "nsec" and not has_deleg:
+ assert "TYPE61440" not in str(res.answer[0])
+
+ expected_answer = 0
+ expected_authority = 0
+
+ if atparent:
+ # the answer will be in the answer section,
+ # no authority section needed
+ expected_answer = 2 if signed else 1
+ elif not signed:
+ expected_authority = 1 # unsigned NS or DELEG
+ elif has_ns:
+ expected_authority = 3 # NS plus signed NSEC/NSEC3
+ if has_deleg and de:
+ expected_authority = 4 # signed DELEG, signed NSEC/NSEC3
+ if optout:
+ expected_authority += 2 # another signed NSEC3
+ elif has_deleg:
+ expected_authority = 4 # signed DELEG -or- SOA, and signed NSEC/NSEC3
+ else:
+ assert False, "impossible condition"
+
+ isctest.check.rr_count_eq(res.answer, expected_answer)
+ isctest.check.rr_count_eq(res.authority, expected_authority)
+
+ # is this an NXRRSET?
+ negative = res.authority and res.authority[0].rdtype == rdatatype.SOA
+
+ if expected_answer or negative:
+ isctest.check.aaflag(res)
+ else:
+ isctest.check.noaaflag(res)
+
+
+@pytest.mark.requires_zones_loaded("ns1")
+@pytest.mark.parametrize(
+ "do, de",
+ [
+ [True, True],
+ [True, False],
+ [False, True],
+ [False, False],
+ ],
+)
+@pytest.mark.parametrize(
+ "qtype",
+ [
+ 61440, # deleg is not yet defined by dnspython
+ "ds",
+ ],
+)
+@pytest.mark.parametrize(
+ "name",
+ [
+ "nsonly-ds",
+ "delegonly-ds",
+ "mixed-ds",
+ ],
+)
+@pytest.mark.parametrize(
+ "zone",
+ [
+ "nsec",
+ "nsec3",
+ "optout",
+ "unsigned",
+ ],
+)
+def test_secure_zonecut_answers(name, zone, qtype, do, de):
+ has_deleg = name in ("mixed", "delegonly")
+ signed = do and (zone != "unsigned")
+
+ # skip queries for DELEG for names that don't have it
+ if qtype == 61440 and not has_deleg:
+ return
+
+ msg = isctest.query.create(f"{name}.{zone}", qtype, dnssec=do, deleg=de)
+ res = isctest.query.tcp(msg, "10.53.0.1")
+ isctest.check.noerror(res)
+
+ isctest.check.rr_count_eq(res.answer, 2 if signed else 1)
+ isctest.check.rr_count_eq(res.authority, 0)
+
+
+@pytest.mark.requires_zones_loaded("ns1")
+@pytest.mark.parametrize(
+ "do, de",
+ [
+ [True, True],
+ [True, False],
+ [False, True],
+ [False, False],
+ ],
+)
+@pytest.mark.parametrize(
+ "name",
+ [
+ "nsonly",
+ "delegonly",
+ "mixed",
+ ],
+)
+@pytest.mark.parametrize(
+ "zone",
+ [
+ "nsec",
+ "nsec3",
+ "optout",
+ "unsigned",
+ ],
+)
+def test_below_zonecut_answers(name, zone, do, de):
+ # which delegation type should we expect?
+ has_ns = name in ("mixed", "nsonly")
+ has_deleg = name in ("mixed", "delegonly")
+
+ # answers without DO should be the same as unsigned
+ signed = do and (zone != "unsigned")
+ optout = do and (zone == "optout")
+ nsec3 = do and zone in ("optout", "nsec3")
+
+ msg = isctest.query.create(f"foo.{name}.{zone}", "txt", dnssec=do, deleg=de)
+ res = isctest.query.tcp(msg, "10.53.0.1")
+
+ # all of these queries should return referrals except
+ # delegonly, which should be an NXDOMAIN
+ if has_deleg and not has_ns and not de:
+ isctest.check.nxdomain(res)
+ else:
+ isctest.check.noerror(res)
+
+ if not signed:
+ # unsigned NS or DELEG
+ expected = 1
+ elif has_ns:
+ # NS plus signed NSEC/NSEC3
+ expected = 3
+ if has_deleg and de:
+ # signed DELEG, signed NSEC/NSEC3
+ expected = 4
+ if optout:
+ # an extra signed NSEC3: wildcard
+ expected += 2
+ elif has_deleg and de:
+ # signed DELEG and NSEC/NSEC3 -or- signed SOA and NSEC/NSEC3
+ expected = 4
+ elif has_deleg:
+ # signed SOA and NSEC/NSEC3
+ expected = 4
+ if optout:
+ # another signed NSEC3: wildcard
+ expected += 2
+ elif nsec3:
+ # two more signed NSEC3s: encloser, wildcard
+ expected += 4
+ else:
+ assert False, "impossible condition"
+ isctest.check.rr_count_eq(res.authority, expected)
+
+
+@pytest.mark.requires_zones_loaded("ns1")
+@pytest.mark.parametrize(
+ "do, de",
+ [
+ [True, True],
+ [True, False],
+ [False, True],
+ [False, False],
+ ],
+)
+@pytest.mark.parametrize(
+ "qtype",
+ [
+ 61440, # deleg is not yet defined by dnspython
+ "nsec",
+ "txt",
+ "a",
+ ],
+)
+def test_deleg_updates(qtype, do, de):
+ # convert nsonly to a mixed delegation
+ up = update.UpdateMessage("nsec.")
+ # pylint: disable=anomalous-backslash-in-string
+ up.add("nsonly.nsec.", 300, 61440, "\# 8 000100040a350003")
+ res = isctest.query.tcp(up, "10.53.0.1")
+ isctest.check.noerror(res)
+
+ # wait for the update to complete
+ for _ in range(10):
+ msg = isctest.query.create("nsonly.nsec.", 61440, deleg=True)
+ res = isctest.query.tcp(msg, "10.53.0.1")
+ if len(res.answer) == 2:
+ break
+ time.sleep(1)
+
+ msg = isctest.query.create("nsonly.nsec.", qtype, dnssec=do, deleg=de)
+ res = isctest.query.tcp(msg, "10.53.0.1")
+ isctest.check.noerror(res)
+
+ atparent = qtype == "nsec" or (qtype == 61440 and de)
+
+ # check that DELEG is in the NSEC bitmap, if present
+ if qtype == "nsec":
+ assert "TYPE61440" in str(res.answer[0])
+
+ if atparent:
+ isctest.check.rr_count_eq(res.answer, 2 if do else 1)
+ expected = 0
+ elif not do:
+ expected = 1 # unsigned NS or DELEG
+ else:
+ expected = 3 # NS plus signed NSEC/NSEC3
+ if de:
+ expected = 4 # signed DELEG, signed NSEC/NSEC3
+ isctest.check.rr_count_eq(res.authority, expected)
diff --git a/bin/tests/system/isctest/query.py b/bin/tests/system/isctest/query.py
index abeffe883f..5e3d08482a 100644
--- a/bin/tests/system/isctest/query.py
+++ b/bin/tests/system/isctest/query.py
@@ -144,6 +144,7 @@ def create(
dnssec: bool = True,
use_edns: int | bool = True,
payload: int = 1232,
+ deleg: bool = True,
rd: bool = True,
cd: bool = False,
ad: bool = True,
@@ -152,11 +153,17 @@ def create(
"""
Create DNS query with defaults suitable for our tests.
"""
+ eflags = 0
+ if dnssec:
+ eflags |= dns.flags.DO
+ if deleg:
+ eflags |= 0x2000 # DE is not yet defined in dnspython
msg = dns.message.make_query(
qname,
qtype,
qclass,
use_edns=use_edns,
+ ednsflags=eflags,
want_dnssec=dnssec,
payload=payload,
id=message_id,