From: Matthijs Mekking Date: Fri, 14 Mar 2025 12:08:44 +0000 (+0100) Subject: Convert dynamic zone test cases to pytest X-Git-Tag: v9.21.8~18^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0b41afbd15da6d9564952b63ebe3df5f56ad7d4e;p=thirdparty%2Fbind9.git Convert dynamic zone test cases to pytest This commit deals with converting the dynamic zone test cases to pytest. The tests for 'inline-signing.kasp' are similar to the default case, so these are added to 'test_kasp_default'. Unfortunately I need to add sleep calls in between freezing, updating, and thawing a zone. Without it the intermittent failures are too frequent. --- diff --git a/bin/tests/system/kasp/tests.sh b/bin/tests/system/kasp/tests.sh index 305ae548ac0..fd41fd231af 100644 --- a/bin/tests/system/kasp/tests.sh +++ b/bin/tests/system/kasp/tests.sh @@ -119,29 +119,6 @@ set_keystate "KEY1" "STATE_KRRSIG" "rumoured" set_keystate "KEY1" "STATE_ZRRSIG" "rumoured" set_keystate "KEY1" "STATE_DS" "hidden" -update_is_signed() { - ip_a=$1 - ip_d=$2 - - if [ "$ip_a" != "-" ]; then - dig_with_opts "a.${ZONE}" "@${SERVER}" A >"dig.out.$DIR.test$n.a" || return 1 - grep "status: NOERROR" "dig.out.$DIR.test$n.a" >/dev/null || return 1 - grep "a.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*${ip_a}" "dig.out.$DIR.test$n.a" >/dev/null || return 1 - lines=$(get_keys_which_signed A 0 "dig.out.$DIR.test$n.a" | wc -l) - test "$lines" -eq 1 || return 1 - get_keys_which_signed A 0 "dig.out.$DIR.test$n.a" | grep "^${KEY_ID}$" >/dev/null || return 1 - fi - - if [ "$ip_d" != "-" ]; then - dig_with_opts "d.${ZONE}" "@${SERVER}" A >"dig.out.$DIR.test$n".d || return 1 - grep "status: NOERROR" "dig.out.$DIR.test$n".d >/dev/null || return 1 - grep "d.${ZONE}\..*${DEFAULT_TTL}.*IN.*A.*${ip_d}" "dig.out.$DIR.test$n".d >/dev/null || return 1 - lines=$(get_keys_which_signed A 0 "dig.out.$DIR.test$n".d | wc -l) - test "$lines" -eq 1 || return 1 - get_keys_which_signed A 0 "dig.out.$DIR.test$n".d | grep "^${KEY_ID}$" >/dev/null || return 1 - fi -} - # # A zone with special characters. # @@ -152,129 +129,6 @@ set_server "ns3" "10.53.0.3" # escaping characters, so we will just try to verify the zone. dnssec_verify -# -# Zone: dynamic.kasp -# -set_zone "dynamic.kasp" -set_dynamic -set_policy "default" "1" "3600" -set_server "ns3" "10.53.0.3" -# Key properties, timings and states same as above. -check_keys -check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" -set_keytimes_csk_policy -check_keytimes -check_apex -check_subdomain -dnssec_verify - -# Update zone with nsupdate. -n=$((n + 1)) -echo_i "nsupdate zone and check that new record is signed for zone ${ZONE} ($n)" -ret=0 -( - echo zone ${ZONE} - echo server 10.53.0.3 "$PORT" - echo update del "a.${ZONE}" 300 A 10.0.0.1 - echo update add "a.${ZONE}" 300 A 10.0.0.101 - echo update add "d.${ZONE}" 300 A 10.0.0.4 - echo send -) | $NSUPDATE - -retry_quiet 10 update_is_signed "10.0.0.101" "10.0.0.4" || ret=1 -test "$ret" -eq 0 || echo_i "failed" -status=$((status + ret)) - -# Update zone with nsupdate (reverting the above change). -n=$((n + 1)) -echo_i "nsupdate zone and check that new record is signed for zone ${ZONE} ($n)" -ret=0 -( - echo zone ${ZONE} - echo server 10.53.0.3 "$PORT" - echo update add "a.${ZONE}" 300 A 10.0.0.1 - echo update del "a.${ZONE}" 300 A 10.0.0.101 - echo update del "d.${ZONE}" 300 A 10.0.0.4 - echo send -) | $NSUPDATE - -retry_quiet 10 update_is_signed "10.0.0.1" "-" || ret=1 -test "$ret" -eq 0 || echo_i "failed" -status=$((status + ret)) - -# Update zone with freeze/thaw. -n=$((n + 1)) -echo_i "modify zone file and check that new record is signed for zone ${ZONE} ($n)" -ret=0 -rndccmd 10.53.0.3 freeze "$ZONE" >/dev/null || log_error "rndc freeze zone ${ZONE} failed" -sleep 1 -echo "d.${ZONE}. 300 A 10.0.0.44" >>"${DIR}/${ZONE}.db" -rndccmd 10.53.0.3 thaw "$ZONE" >/dev/null || log_error "rndc thaw zone ${ZONE} failed" - -retry_quiet 10 update_is_signed "10.0.0.1" "10.0.0.44" || ret=1 -test "$ret" -eq 0 || echo_i "failed" -status=$((status + ret)) - -# -# Zone: dynamic-inline-signing.kasp -# -set_zone "dynamic-inline-signing.kasp" -set_dynamic -set_policy "default" "1" "3600" -set_server "ns3" "10.53.0.3" -# Key properties, timings and states same as above. -check_keys -check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" -set_keytimes_csk_policy -check_keytimes -check_apex -check_subdomain -dnssec_verify - -# Update zone with freeze/thaw. -n=$((n + 1)) -echo_i "modify unsigned zone file and check that new record is signed for zone ${ZONE} ($n)" -ret=0 -rndccmd 10.53.0.3 freeze "$ZONE" >/dev/null || log_error "rndc freeze zone ${ZONE} failed" -sleep 1 -cp "${DIR}/template2.db.in" "${DIR}/${ZONE}.db" -rndccmd 10.53.0.3 thaw "$ZONE" >/dev/null || log_error "rndc thaw zone ${ZONE} failed" - -retry_quiet 10 update_is_signed || ret=1 -test "$ret" -eq 0 || echo_i "failed" -status=$((status + ret)) - -# -# Zone: dynamic-signed-inline-signing.kasp -# -set_zone "dynamic-signed-inline-signing.kasp" -set_dynamic -set_policy "default" "1" "3600" -set_server "ns3" "10.53.0.3" -dnssec_verify -# Ensure no zone_resigninc for the unsigned version of the zone is triggered. -n=$((n + 1)) -echo_i "check if resigning the raw version of the zone is prevented for zone ${ZONE} ($n)" -ret=0 -grep "zone_resigninc: zone $ZONE/IN (unsigned): enter" $DIR/named.run && ret=1 -test "$ret" -eq 0 || echo_i "failed" -status=$((status + ret)) - -# -# Zone: inline-signing.kasp -# -set_zone "inline-signing.kasp" -set_policy "default" "1" "3600" -set_server "ns3" "10.53.0.3" -# Key properties, timings and states same as above. -check_keys -check_dnssecstatus "$SERVER" "$POLICY" "$ZONE" -set_keytimes_csk_policy -check_keytimes -check_apex -check_subdomain -dnssec_verify - # # Zone: checkds-ksk.kasp. # diff --git a/bin/tests/system/kasp/tests_kasp.py b/bin/tests/system/kasp/tests_kasp.py index ba9217b3ee3..3daa5eebcc7 100644 --- a/bin/tests/system/kasp/tests_kasp.py +++ b/bin/tests/system/kasp/tests_kasp.py @@ -11,10 +11,12 @@ import os import shutil +import time from datetime import timedelta import dns +import dns.update import pytest import isctest @@ -180,6 +182,161 @@ def test_kasp_default(servers): isctest.kasp.check_keytimes(keys, expected) check_all(server, zone, policy, keys, []) + # A zone that uses inline-signing. + isctest.log.info("check an inline-signed zone with the default policy is signed") + zone = "inline-signing.kasp" + # Key properties. + key1 = KeyProperties.default() + keys = isctest.kasp.keydir_to_keylist(zone, "ns3") + expected = [key1] + isctest.kasp.check_zone_is_signed(server, zone) + isctest.kasp.check_keys(zone, keys, expected) + set_keytimes_default_policy(key1) + isctest.kasp.check_keytimes(keys, expected) + check_all(server, zone, policy, keys, []) + + +def test_kasp_dynamic(servers): + # Dynamic update test cases. + server = servers["ns3"] + + # Standard dynamic zone. + isctest.log.info("check dynamic zone is updated and signed after update") + zone = "dynamic.kasp" + policy = "default" + # Key properties. + key1 = KeyProperties.default() + expected = [key1] + keys = isctest.kasp.keydir_to_keylist(zone, "ns3") + isctest.kasp.check_zone_is_signed(server, zone) + isctest.kasp.check_keys(zone, keys, expected) + set_keytimes_default_policy(key1) + expected = [key1] + isctest.kasp.check_keytimes(keys, expected) + check_all(server, zone, policy, keys, []) + + # Update zone with nsupdate. + def nsupdate(updates): + message = dns.update.UpdateMessage(zone) + for update in updates: + if update[0] == "del": + message.delete(update[1], update[2], update[3]) + else: + assert update[0] == "add" + message.add(update[1], update[2], update[3], update[4]) + + try: + response = isctest.query.udp( + message, server.ip, server.ports.dns, timeout=3 + ) + assert response.rcode() == dns.rcode.NOERROR + except dns.exception.Timeout: + assert False, f"update timeout for {zone}" + + isctest.log.debug(f"update of zone {zone} to server {server.ip} successful") + + def update_is_signed(): + parts = update.split() + qname = parts[0] + qtype = dns.rdatatype.from_text(parts[1]) + rdata = parts[2] + return isctest.kasp.verify_update_is_signed( + server, zone, qname, qtype, rdata, keys, [] + ) + + updates = [ + ["del", f"a.{zone}.", "A", "10.0.0.1"], + ["add", f"a.{zone}.", 300, "A", "10.0.0.101"], + ["add", f"d.{zone}.", 300, "A", "10.0.0.4"], + ] + nsupdate(updates) + + expected_updates = [f"a.{zone}. A 10.0.0.101", f"d.{zone}. A 10.0.0.4"] + for update in expected_updates: + isctest.run.retry_with_timeout(update_is_signed, timeout=5) + + # Update zone with nsupdate (reverting the above change). + updates = [ + ["add", f"a.{zone}.", 300, "A", "10.0.0.1"], + ["del", f"a.{zone}.", "A", "10.0.0.101"], + ["del", f"d.{zone}.", "A", "10.0.0.4"], + ] + nsupdate(updates) + + update = f"a.{zone}. A 10.0.0.1" + isctest.run.retry_with_timeout(update_is_signed, timeout=5) + + # Update zone with freeze/thaw. + isctest.log.info("check dynamic zone is updated and signed after freeze and thaw") + with server.watch_log_from_here() as watcher: + server.rndc(f"freeze {zone}", log=False) + watcher.wait_for_line(f"freezing zone '{zone}/IN': success") + + time.sleep(1) + with open(f"ns3/{zone}.db", "a", encoding="utf-8") as zonefile: + zonefile.write(f"d.{zone}. 300 A 10.0.0.44\n") + time.sleep(1) + + with server.watch_log_from_here() as watcher: + server.rndc(f"thaw {zone}", log=False) + watcher.wait_for_line(f"thawing zone '{zone}/IN': success") + + expected_updates = [f"a.{zone}. A 10.0.0.1", f"d.{zone}. A 10.0.0.44"] + + for update in expected_updates: + isctest.run.retry_with_timeout(update_is_signed, timeout=5) + + # Dynamic, and inline-signing. + zone = "dynamic-inline-signing.kasp" + # Key properties. + key1 = KeyProperties.default() + expected = [key1] + keys = isctest.kasp.keydir_to_keylist(zone, "ns3") + isctest.kasp.check_zone_is_signed(server, zone) + isctest.kasp.check_keys(zone, keys, expected) + set_keytimes_default_policy(key1) + expected = [key1] + isctest.kasp.check_keytimes(keys, expected) + check_all(server, zone, policy, keys, []) + + # Update zone with freeze/thaw. + isctest.log.info( + "check dynamic inline-signed zone is updated and signed after freeze and thaw" + ) + with server.watch_log_from_here() as watcher: + server.rndc(f"freeze {zone}", log=False) + watcher.wait_for_line(f"freezing zone '{zone}/IN': success") + + time.sleep(1) + shutil.copyfile("ns3/template2.db.in", f"ns3/{zone}.db") + time.sleep(1) + + with server.watch_log_from_here() as watcher: + server.rndc(f"thaw {zone}", log=False) + watcher.wait_for_line(f"thawing zone '{zone}/IN': success") + + expected_updates = [f"a.{zone}. A 10.0.0.11", f"d.{zone}. A 10.0.0.44"] + for update in expected_updates: + isctest.run.retry_with_timeout(update_is_signed, timeout=5) + + # Dynamic, signed, and inline-signing. + isctest.log.info("check dynamic signed, and inline-signed zone") + zone = "dynamic-signed-inline-signing.kasp" + # Key properties. + key1 = KeyProperties.default() + # The ns3/setup.sh script sets all states to omnipresent. + key1.metadata["DNSKEYState"] = "omnipresent" + key1.metadata["KRRSIGState"] = "omnipresent" + key1.metadata["ZRRSIGState"] = "omnipresent" + key1.metadata["DSState"] = "omnipresent" + expected = [key1] + keys = isctest.kasp.keydir_to_keylist(zone, "ns3/keys") + isctest.kasp.check_zone_is_signed(server, zone) + isctest.kasp.check_keys(zone, keys, expected) + check_all(server, zone, policy, keys, []) + # Ensure no zone_resigninc for the unsigned version of the zone is triggered. + assert f"zone_resigninc: zone {zone}/IN (unsigned): enter" not in "ns3/named.run" + def test_kasp_dnssec_keygen(): def keygen(zone, policy, keydir=None):