test "$lines" -eq "$_expect" || return 1
}
-#
-# Check secondary server behaviour.
-#
-set_zone "model2.secondary"
-set_policy "model2" "2" "3600"
-
-set_server "ns3" "10.53.0.3"
-check_keys
-check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
-set_keytimes_model2
-check_keytimes
-check_apex
-dnssec_verify
-
-set_server "ns4" "10.53.0.4"
-check_keys
-check_dnssecstatus "$SERVER" "$POLICY" "$ZONE"
-set_keytimes_model2
-check_keytimes
-check_apex
-dnssec_verify
-
-#
-# Update DNSKEY RRset.
-#
-n=$((n + 1))
-echo_i "add dnskey record: update zone ${ZONE} at ns5 with ZSKs from providers ns3 and ns4 ($n)"
-ret=0
-set_server "ns5" "10.53.0.5"
-(
- echo zone "${ZONE}"
- echo server "${SERVER}" "${PORT}"
- echo update add $(cat "ns3/${ZONE}.zsk")
- echo update add $(cat "ns4/${ZONE}.zsk")
- echo send
-) | $NSUPDATE || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-# NS3
-n=$((n + 1))
-set_server "ns3" "10.53.0.3"
-echo_i "check server ${DIR} zone ${ZONE} DNSKEY RRset after update ($n)"
-ret=0
-retry_quiet 10 zsks_are_published || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-dnssec_verify
-no_dnssec_in_journal
-grep "dns_zone_findkeys: error reading ./K${ZONE}.*\.private: file not found" "${DIR}/named.run" && ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-# NS4
-n=$((n + 1))
-set_server "ns4" "10.53.0.4"
-echo_i "check server ${DIR} zone ${ZONE} DNSKEY RRset after update ($n)"
-ret=0
-retry_quiet 10 zsks_are_published || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-dnssec_verify
-no_dnssec_in_journal
-grep "dns_zone_findkeys: error reading ./K${ZONE}.*\.private: file not found" "${DIR}/named.run" && ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "remove dnskey record: remove ns3 and ns4 DNSKEY records from primary ns5 ($n)"
-ret=0
-set_server "ns5" "10.53.0.5"
-(
- echo zone "${ZONE}"
- echo server "${SERVER}" "${PORT}"
- echo update del $(cat "ns3/${ZONE}.zsk")
- echo update del $(cat "ns4/${ZONE}.zsk")
- echo send
-) | $NSUPDATE || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-# Now there should be one DNSKEY record again.
-# While we did remove both DNSKEY records, the bump in the wire signer, i.e
-# the secondary inline-signing zone, should add back the DNSKEY belonging to
-# its own KSK when re-signing the zone.
-#
-# NS3
-n=$((n + 1))
-set_server "ns3" "10.53.0.3"
-echo_i "check server ${DIR} zone ${ZONE} DNSKEY RRset after update ($n)"
-ret=0
-check_keys
-check_apex
-dnssec_verify
-no_dnssec_in_journal
-# NS4
-n=$((n + 1))
-set_server "ns4" "10.53.0.4"
-echo_i "check server ${DIR} zone ${ZONE} DNSKEY RRset after update ($n)"
-ret=0
-check_keys
-check_apex
-dnssec_verify
-no_dnssec_in_journal
-
-#
-# Update CDNSKEY RRset.
-#
-
-# Retrieve CDNSKEY records from the providers.
-n=$((n + 1))
-echo_i "check initial CDSNKEY response for zone ${ZONE} at ns3 and ns4 ($n)"
-ret=0
-dig_with_opts ${ZONE} @10.53.0.3 CDNSKEY >dig.out.ns3.secondary.cdnskey
-awk '$4 == "CDNSKEY" {print}' dig.out.ns3.secondary.cdnskey >secondary.cdnskey.ns3
-dig_with_opts ${ZONE} @10.53.0.4 CDNSKEY >dig.out.ns4.secondary.cdnskey
-awk '$4 == "CDNSKEY" {print}' dig.out.ns4.secondary.cdnskey >secondary.cdnskey.ns4
-# Initially there should be one CDNSKEY.
-set_server "ns3" "10.53.0.3"
-retry_quiet 10 records_published CDNSKEY 1 || ret=1
-set_server "ns4" "10.53.0.4"
-retry_quiet 10 records_published CDNSKEY 1 || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "add cdnskey record: update zone ${ZONE} at ns5 with CDNSKEY records from providers ns3 and ns4 ($n)"
-ret=0
-set_server "ns5" "10.53.0.5"
-(
- echo zone "${ZONE}"
- echo server "${SERVER}" "${PORT}"
- echo update add $(cat "secondary.cdnskey.ns3")
- echo update add $(cat "secondary.cdnskey.ns4")
- echo send
-) | $NSUPDATE || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-# Now there should be two CDNSKEY records (we test that BIND does not
-# skip it during DNSSEC maintenance).
-#
-# NS3
-n=$((n + 1))
-set_server "ns3" "10.53.0.3"
-echo_i "check server ${DIR} zone ${ZONE} CDNSKEY RRset after update ($n)"
-ret=0
-retry_quiet 10 records_published CDNSKEY 2 || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-dnssec_verify
-no_dnssec_in_journal
-# NS4
-n=$((n + 1))
-set_server "ns4" "10.53.0.4"
-echo_i "check server ${DIR} zone ${ZONE} CDNSKEY RRset after update ($n)"
-ret=0
-retry_quiet 10 records_published CDNSKEY 2 || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-dnssec_verify
-no_dnssec_in_journal
-
-n=$((n + 1))
-echo_i "remove cdnskey record: remove ns3 and ns4 CDNSKEY records from primary ns5 ($n)"
-ret=0
-set_server "ns5" "10.53.0.5"
-(
- echo zone "${ZONE}"
- echo server "${SERVER}" "${PORT}"
- echo update del $(cat "secondary.cdnskey.ns3")
- echo update del $(cat "secondary.cdnskey.ns4")
- echo send
-) | $NSUPDATE || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-# Now there should be one CDNSKEY record again.
-# While we did remove both CDNSKEY records, the bump in the wire signer, i.e
-# the secondary inline-signing zone, should add back the CDNSKEY belonging to
-# its own KSK when re-signing the zone.
-#
-# NS3
-n=$((n + 1))
-set_server "ns3" "10.53.0.3"
-echo_i "check server ${DIR} zone ${ZONE} CDNSKEY RRset after update ($n)"
-ret=0
-retry_quiet 10 records_published CDNSKEY 1 || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-dnssec_verify
-no_dnssec_in_journal
-# NS4
-n=$((n + 1))
-set_server "ns4" "10.53.0.4"
-echo_i "check server ${DIR} zone ${ZONE} CDNSKEY RRset after update ($n)"
-ret=0
-retry_quiet 10 records_published CDNSKEY 1 || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-dnssec_verify
-no_dnssec_in_journal
-
-#
-# Update CDS RRset.
-#
-
-# Retrieve CDS records from the other provider.
-n=$((n + 1))
-echo_i "check initial CDS response for zone ${ZONE} at ns3 and ns4 ($n)"
-ret=0
-dig_with_opts ${ZONE} @10.53.0.3 CDS >dig.out.ns3.secondary.cds
-awk '$4 == "CDS" {print}' dig.out.ns3.secondary.cds >secondary.cds.ns3
-dig_with_opts ${ZONE} @10.53.0.4 CDS >dig.out.ns4.secondary.cds
-awk '$4 == "CDS" {print}' dig.out.ns4.secondary.cds >secondary.cds.ns4
-# Initially there should be one CDS.
-set_server "ns3" "10.53.0.3"
-retry_quiet 10 records_published CDS 1 || ret=1
-set_server "ns4" "10.53.0.4"
-retry_quiet 10 records_published CDS 1 || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-
-n=$((n + 1))
-echo_i "add cds record: update zone ${ZONE} at ns5 with CDS from provider ns4 ($n)"
-ret=0
-set_server "ns5" "10.53.0.5"
-(
- echo zone "${ZONE}"
- echo server "${SERVER}" "${PORT}"
- echo update add $(cat "secondary.cds.ns3")
- echo update add $(cat "secondary.cds.ns4")
- echo send
-) | $NSUPDATE || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-# Now there should be two CDS records (we test that BIND does not
-# skip it during DNSSEC maintenance).
-#
-# NS3
-n=$((n + 1))
-set_server "ns3" "10.53.0.3"
-echo_i "check server ${DIR} zone ${ZONE} CDS RRset after update ($n)"
-ret=0
-retry_quiet 10 records_published CDS 2 || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-dnssec_verify
-no_dnssec_in_journal
-# NS4
-n=$((n + 1))
-set_server "ns4" "10.53.0.4"
-echo_i "check server ${DIR} zone ${ZONE} CDS RRset after update ($n)"
-ret=0
-retry_quiet 10 records_published CDS 2 || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-dnssec_verify
-no_dnssec_in_journal
-
-n=$((n + 1))
-echo_i "remove cds record: remove ns3 and ns4 CDS records from primary ns5 ($n)"
-ret=0
-set_server "ns5" "10.53.0.5"
-(
- echo zone "${ZONE}"
- echo server "${SERVER}" "${PORT}"
- echo update del $(cat "secondary.cds.ns3")
- echo update del $(cat "secondary.cds.ns4")
- echo send
-) | $NSUPDATE || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-# Now there should be one CDS record again.
-# While we did remove both CDS records, the bump in the wire signer, i.e
-# the secondary inline-signing zone, should add back the CDS belonging to
-# its own KSK when re-signing the zone.
-#
-# NS3
-n=$((n + 1))
-set_server "ns3" "10.53.0.3"
-echo_i "check server ${DIR} zone ${ZONE} CDS RRset after update ($n)"
-ret=0
-retry_quiet 10 records_published CDS 1 || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-dnssec_verify
-no_dnssec_in_journal
-# NS4
-n=$((n + 1))
-set_server "ns4" "10.53.0.4"
-echo_i "check server ${DIR} zone ${ZONE} CDS RRset after update ($n)"
-ret=0
-retry_quiet 10 records_published CDS 1 || ret=1
-test "$ret" -eq 0 || echo_i "failed"
-status=$((status + ret))
-dnssec_verify
-no_dnssec_in_journal
-
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1
assert not match, f"{match.group(1)} record found in journal"
+def wait_for_serial(primary, server, zone):
+ if primary.identifier == server.identifier:
+ # No need to check if the transfer has been done.
+ return
+
+ def check_serial():
+ response = isctest.query.tcp(
+ query, primary.ip, primary.ports.dns, timeout=3, attempts=1
+ )
+ assert response.rcode() == dns.rcode.NOERROR
+ soa = response.get_rrset(
+ response.answer,
+ dns.name.from_text(fqdn),
+ dns.rdataclass.IN,
+ dns.rdatatype.SOA,
+ )
+ serial1 = soa[0].serial
+
+ response = isctest.query.tcp(
+ query, server.ip, server.ports.dns, timeout=3, attempts=1
+ )
+ assert response.rcode() == dns.rcode.NOERROR
+ soa = response.get_rrset(
+ response.answer,
+ dns.name.from_text(fqdn),
+ dns.rdataclass.IN,
+ dns.rdatatype.SOA,
+ )
+ serial2 = soa[0].serial
+
+ return (
+ f"zone {zone}/IN (signed): serial {serial2} (unsigned {serial1})"
+ in server.log
+ )
+
+ fqdn = f"{zone}."
+ query = isctest.query.create(fqdn, dns.rdatatype.SOA)
+
+ isctest.run.retry_with_timeout(check_serial, timeout=10)
+
+
def check_add_zsk(server, zone, keys, expected, extra_keys, extra, primary=None):
if primary is None:
primary = server
update_msg.add(f"{zone}.", TTL, "DNSKEY", rdata)
primary.nsupdate(update_msg)
+ wait_for_serial(primary, server, zone)
+
# Check the new DNSKEY RRset.
isctest.log.info(
f"- zone {zone} {server.identifier}: check DNSKEY RRset after update add"
update_msg.delete(f"{zone}.", "DNSKEY", rdata)
primary.nsupdate(update_msg)
+ wait_for_serial(primary, server, zone)
+
# We should have only the KSK and ZSK from server.
isctest.log.info(
f"- zone {zone} {server.identifier}: check DNSKEY RRset after update remove"
update_msg.add(f"{zone}.", TTL, "CDNSKEY", rdata)
primary.nsupdate(update_msg)
+ wait_for_serial(primary, server, zone)
+
# Now there should be two CDNSKEY records.
isctest.log.info(
f"- zone {zone} {server.identifier}: check CDNSKEY RRset after update add"
update_msg.delete(f"{zone}.", "CDNSKEY", rdata)
primary.nsupdate(update_msg)
+ wait_for_serial(primary, server, zone)
+
# Now there should be one CDNSKEY record again.
isctest.log.info(
f"- zone {zone} {server.identifier}: check CDNSKEY RRset after update remove"
update_msg.add(f"{zone}.", TTL, "CDS", rdata)
primary.nsupdate(update_msg)
+ wait_for_serial(primary, server, zone)
+
# Now there should be two CDS records.
isctest.log.info(
f"- zone {zone} {server.identifier}: check CDS RRset after update add"
update_msg.delete(f"{zone}.", "CDS", rdata)
primary.nsupdate(update_msg)
+ wait_for_serial(primary, server, zone)
+
# Now there should be one CDS record again.
isctest.log.info(
f"- zone {zone} {server.identifier}: check CDS RRset after update remove"
check_remove_cds(ns3, zone, keys3, expected3, [ksks4[0]], extra, check_fail=True)
check_remove_cds(ns4, zone, keys4, expected4, [ksks3[0]], extra, check_fail=True)
check_no_dnssec_in_journal(ns4, zone)
+
+
+def test_multisigner_secondary(ns3, ns4, ns5):
+ zone = "model2.secondary"
+ keyprops = [
+ f"ksk 0 {ALGORITHM} {SIZE} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent",
+ f"zsk 0 {ALGORITHM} {SIZE} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent",
+ ]
+
+ # First make sure the zone is properly signed.
+ isctest.log.info(f"basic DNSSEC tests for {zone}")
+ isctest.kasp.wait_keymgr_done(ns3, zone)
+ isctest.kasp.wait_keymgr_done(ns4, zone)
+
+ keys3 = isctest.kasp.keydir_to_keylist(zone, ns3.identifier)
+ ksks3 = [k for k in keys3 if k.is_ksk()]
+ zsks3 = [k for k in keys3 if not k.is_ksk()]
+ expected3 = isctest.kasp.policy_to_properties(ttl=TTL, keys=keyprops)
+
+ check_dnssec(ns3, zone, keys3, expected3)
+
+ keys4 = isctest.kasp.keydir_to_keylist(zone, ns4.identifier)
+ ksks4 = [k for k in keys4 if k.is_ksk()]
+ zsks4 = [k for k in keys4 if not k.is_ksk()]
+ expected4 = isctest.kasp.policy_to_properties(ttl=TTL, keys=keyprops)
+
+ check_dnssec(ns4, zone, keys4, expected4)
+
+ # Add DNSKEY to RRset.
+ newprops = [f"zsk unlimited {ALGORITHM} {SIZE}"]
+ extra = isctest.kasp.policy_to_properties(ttl=TTL, keys=newprops)
+ extra[0].private = False # noqa
+ extra[0].legacy = True # noqa
+
+ check_add_zsk(ns3, zone, keys3, expected3, [zsks4[0]], extra, primary=ns5)
+ check_add_zsk(ns4, zone, keys4, expected4, [zsks3[0]], extra, primary=ns5)
+ check_no_dnssec_in_journal(ns3, zone)
+ check_no_dnssec_in_journal(ns4, zone)
+
+ # Remove DNSKEY from RRset.
+ check_remove_zsk(ns3, zone, keys3, expected3, [zsks4[0]], extra, primary=ns5)
+ check_remove_zsk(ns4, zone, keys4, expected4, [zsks3[0]], extra, primary=ns5)
+ check_no_dnssec_in_journal(ns3, zone)
+ check_no_dnssec_in_journal(ns4, zone)
+
+ # Add CDNSKEY RRset.
+ newprops = [f"ksk unlimited {ALGORITHM} {SIZE}"]
+ extra = isctest.kasp.policy_to_properties(ttl=TTL, keys=newprops)
+ extra[0].private = False # noqa
+ extra[0].legacy = True # noqa
+
+ check_add_cdnskey(ns3, zone, keys3, expected3, [ksks4[0]], extra, primary=ns5)
+ check_add_cdnskey(ns4, zone, keys4, expected4, [ksks3[0]], extra, primary=ns5)
+ check_no_dnssec_in_journal(ns3, zone)
+ check_no_dnssec_in_journal(ns4, zone)
+
+ # Remove CDNSKEY RRset.
+ check_remove_cdnskey(ns3, zone, keys3, expected3, [ksks4[0]], extra, primary=ns5)
+ check_remove_cdnskey(ns4, zone, keys4, expected4, [ksks3[0]], extra, primary=ns5)
+ check_no_dnssec_in_journal(ns3, zone)
+ check_no_dnssec_in_journal(ns4, zone)
+
+ # Update CDS RRset.
+ check_add_cds(ns3, zone, keys3, expected3, [ksks4[0]], extra, primary=ns5)
+ check_add_cds(ns4, zone, keys4, expected4, [ksks3[0]], extra, primary=ns5)
+ check_no_dnssec_in_journal(ns3, zone)
+ check_no_dnssec_in_journal(ns4, zone)
+
+ # Remove CDS RRset.
+ check_remove_cds(ns3, zone, keys3, expected3, [ksks4[0]], extra, primary=ns5)
+ check_remove_cds(ns4, zone, keys4, expected4, [ksks3[0]], extra, primary=ns5)
+ check_no_dnssec_in_journal(ns3, zone)
+ check_no_dnssec_in_journal(ns4, zone)