Rewrite nsec3 system test to pytest (3/4)

This converts two test cases:

1. A zone that previously failed to load is now fixed. Make sure the
   zone is signed correctly with the right NSEC3 parameters.

2. Test case to ensure the salt is the same after a restart, i.e. no
   re-salting takes place. Previously we only tested with salt length
   0, this commit adds a test case for salt length 8 as well.
This commit is contained in:
Matthijs Mekking 2025-09-30 15:06:45 +02:00
parent 2c7190609b
commit f98f6ee3d6
4 changed files with 173 additions and 39 deletions

View file

@ -235,44 +235,6 @@ key_clear "KEY2"
key_clear "KEY3"
key_clear "KEY4"
# Test NSEC3 and NSEC3PARAM is the same after restart
set_zone_policy "nsec3.kasp" "nsec3" 1 3600
set_nsec3param "0" "0"
set_key_default_values "KEY1"
echo_i "check zone ${ZONE} before restart"
check_nsec3
# Restart named, NSEC3 should stay the same.
ret=0
echo "stop ns3"
stop_server --use-rndc --port ${CONTROLPORT} ${DIR} || ret=1
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
ret=0
echo "start ns3"
start_server --noclean --restart --port ${PORT} ${DIR}
test "$ret" -eq 0 || echo_i "failed"
status=$((status + ret))
prevsalt="${SALT}"
set_zone_policy "nsec3.kasp" "nsec3" 1 3600
set_nsec3param "0" "0"
set_key_default_values "KEY1"
SALT="${prevsalt}"
echo_i "check zone ${ZONE} after restart has salt ${SALT}"
check_nsec3
# Zone: nsec3-fails-to-load.kasp. (should be fixed after reload)
cp ns3/template.db.in ns3/nsec3-fails-to-load.kasp.db
rndc_reload ns3 10.53.0.3
set_zone_policy "nsec3-fails-to-load.kasp" "nsec3" 1 3600
set_nsec3param "0" "0"
set_key_default_values "KEY1"
echo_i "check zone ${ZONE} after reload"
check_nsec3
# Zone: nsec3-ent.kasp (regression test for #5108)
n=$((n + 1))
echo_i "check query for newly empty name does not crash ($n)"

View file

@ -53,9 +53,10 @@ def after_servers_start(ns3, templates):
return False
nsdir = ns3.identifier
# Extra test for nsec3-change.kasp.
zone = "nsec3-change.kasp"
nsdir = ns3.identifier
fqdn = f"{zone}."
isctest.kasp.wait_keymgr_done(ns3, zone)
shutil.copyfile(f"{nsdir}/template2.db.in", f"{nsdir}/{zone}.db")

View file

@ -0,0 +1,52 @@
# 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.
# pylint: disable=redefined-outer-name,unused-import
import os
import shutil
import time
import pytest
pytest.importorskip("dns", minversion="2.0.0")
import isctest
from nsec3.common import (
ALGORITHM,
SIZE,
check_nsec3_case,
)
def test_nsec3_case(ns3):
# Get test parameters.
params = {
"zone": "nsec3-fails-to-load.kasp",
"policy": "nsec3",
"key-properties": [
f"csk 0 {ALGORITHM} {SIZE} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
],
}
zone = params["zone"]
# nsec3-fails-to-load.kasp. fails to load (should be fixed after reload).
zone = "nsec3-fails-to-load.kasp"
with ns3.watch_log_from_start() as watcher:
watcher.wait_for_line(f"zone {zone}/IN (unsigned): not loaded due to errors.")
shutil.copyfile(f"{ns3.identifier}/template.db.in", f"{ns3.identifier}/{zone}.db")
ns3.rndc(f"reload {zone}")
# First make sure the zone is properly signed.
isctest.kasp.wait_keymgr_done(ns3, zone)
# Test case.
check_nsec3_case(ns3, params)

View file

@ -0,0 +1,119 @@
# 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.
# pylint: disable=redefined-outer-name,unused-import
import os
import dns.update
import pytest
pytest.importorskip("dns", minversion="2.0.0")
import isctest
import isctest.mark
from nsec3.common import (
ALGORITHM,
SIZE,
default_config,
pytestmark,
check_auth_nsec3,
check_nsec3param,
)
def perform_nsec3_tests(server, params):
# Get test parameters.
zone = params["zone"]
fqdn = f"{zone}."
policy = params["policy"]
keydir = server.identifier
config = default_config
ttl = int(config.get("dnskey-ttl", 3600).total_seconds())
minimum = params.get("soa-minimum", 3600)
expected = isctest.kasp.policy_to_properties(ttl=ttl, keys=params["key-properties"])
iterations = 0
optout = 0
saltlen = 0
if "nsec3param" in params:
optout = params["nsec3param"].get("optout", 0)
saltlen = params["nsec3param"].get("salt-length", 0)
match = f"{fqdn} {minimum} IN NSEC3PARAM 1 0 {iterations}"
# Test case.
isctest.log.info(f"check nsec3 case zone {zone} policy {policy}")
# First make sure the zone is properly signed.
isctest.kasp.wait_keymgr_done(server, zone)
keys = isctest.kasp.keydir_to_keylist(zone, keydir)
isctest.kasp.check_keys(zone, keys, expected)
isctest.kasp.check_dnssec_verify(server, zone)
isctest.kasp.check_apex(server, zone, keys, [])
query = isctest.query.create(fqdn, dns.rdatatype.NSEC3PARAM)
response = isctest.query.tcp(query, server.ip)
assert response.rcode() == dns.rcode.NOERROR
salt = check_nsec3param(response, match, saltlen)
query = isctest.query.create(f"nosuchname.{fqdn}", dns.rdatatype.A)
response = isctest.query.tcp(query, server.ip)
assert response.rcode() == dns.rcode.NXDOMAIN
check_auth_nsec3(response, iterations, optout, salt)
return salt
@pytest.mark.parametrize(
"params",
[
pytest.param(
{
"zone": "nsec3.kasp",
"policy": "nsec3",
"key-properties": [
f"csk 0 {ALGORITHM} {SIZE} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
],
},
id="nsec3.kasp",
),
pytest.param(
{
"zone": "nsec3-other.kasp",
"policy": "nsec3-other",
"nsec3param": {
"optout": 1,
"salt-length": 8,
},
"key-properties": [
f"csk 0 {ALGORITHM} {SIZE} goal:omnipresent dnskey:rumoured krrsig:rumoured zrrsig:rumoured ds:hidden",
],
},
id="nsec3-other.kasp",
),
],
)
def test_nsec3_case(ns3, params):
zone = params["zone"]
salt = perform_nsec3_tests(ns3, params)
# Test NSEC3 and NSEC3PARAM is the same after restart
isctest.log.info(f"check zone {zone} after restart has salt {salt}")
prevsalt = salt
# Restart named, NSEC3 should stay the same.
ns3.stop()
ns3.start(["--noclean", "--restart", "--port", os.environ["PORT"]])
salt = perform_nsec3_tests(ns3, params)
assert prevsalt == salt