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.
#
# 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.
#
import os
import shutil
+import time
from datetime import timedelta
import dns
+import dns.update
import pytest
import isctest
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):