Add NSEC3 optout large delegation zone test case

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.

(cherry picked from commit 5e704bbb59)
This commit is contained in:
Matthijs Mekking 2025-12-05 17:01:00 +01:00
parent 7c7b01dd65
commit 71c991d592
5 changed files with 186 additions and 0 deletions

View file

@ -0,0 +1 @@
../../_common/controls.conf.in

View file

@ -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;
};

View file

@ -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

View file

@ -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

View file

@ -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)