]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Test removing DNSKEY records with class ANY
authorMatthijs Mekking <matthijs@isc.org>
Tue, 2 Jun 2026 09:41:13 +0000 (11:41 +0200)
committerMatthijs Mekking <matthijs@isc.org>
Thu, 11 Jun 2026 10:53:56 +0000 (10:53 +0000)
The update should ignore DNSKEY, CDNSKEY and CDS records
for keys that are used for signing.

12 files changed:
bin/tests/system/multisigner/ns1/root.db.in
bin/tests/system/multisigner/ns1/setup.sh
bin/tests/system/multisigner/ns2/named.conf.j2
bin/tests/system/multisigner/ns2/setup.sh
bin/tests/system/multisigner/ns2/update-any.db.in.j2 [new file with mode: 0644]
bin/tests/system/multisigner/ns3/model2.update-any.db [new file with mode: 0644]
bin/tests/system/multisigner/ns3/named.conf.j2
bin/tests/system/multisigner/ns3/setup.sh
bin/tests/system/multisigner/ns4/model2.update-any.db [new file with mode: 0644]
bin/tests/system/multisigner/ns4/named.conf.j2
bin/tests/system/multisigner/ns4/setup.sh
bin/tests/system/multisigner/tests_multisigner.py

index e9dc46ff12dd0c3237ffef7fc6cbfc55225165c9..57213b66c493eb2e7316001122bbab610e7fb739 100644 (file)
@@ -12,6 +12,9 @@ a.root-servers.nil.   A       10.53.0.1
 multisigner.           NS      ns2.multisigner.
 ns2.multisigner.       A       10.53.0.2
 
+update-any.            NS      ns2.update-any.
+ns2.update-any.                A       10.53.0.2
+
 bad-dsync.             NS      ns2.bad-dsync.
 ns2.bad-dsync.         A       10.53.0.2
 
index b6cf3028d1aa18eeb9d6065e7fb62c56db3ba53d..da2383d8b8482808b1b9e7d9e92d472c510e7c4e 100644 (file)
@@ -22,7 +22,7 @@ zonefile=root.db
 
 echo_i "ns1/setup.sh"
 
-for tld in multisigner bad-dsync secondary; do
+for tld in multisigner update-any bad-dsync secondary; do
   cp "../ns2/dsset-${tld}." .
 done
 
index 84cd5beb061528de61d62e9084f2d4172ba1afa9..d90567dff45bce3dfe2a4cad1c3f837aae24ff92 100644 (file)
@@ -27,6 +27,11 @@ zone "multisigner" {
        file "multisigner.db.signed";
 };
 
+zone "update-any" {
+       type primary;
+       file "update-any.db.signed";
+};
+
 zone "bad-dsync" {
        type primary;
        file "bad-dsync.db.signed";
index 4fd349125dc1925490e9bb86d07ee53485f18eb2..786cfa47871e28a57d363c2594eceee2b174a058 100644 (file)
@@ -30,10 +30,10 @@ setup() {
   $DSFROMKEY $KSK.key >dsset-ns2-${zone}.
 
   cat $infile $KSK.key $ZSK.key >$zonefile
-  $SIGNER -g -o $zone $zonefile
-  # >/dev/null 2>&1
+  $SIGNER -g -o $zone $zonefile >/dev/null 2>&1
 }
 
 setup "multisigner"
+setup "update-any"
 setup "bad-dsync"
 setup "secondary"
diff --git a/bin/tests/system/multisigner/ns2/update-any.db.in.j2 b/bin/tests/system/multisigner/ns2/update-any.db.in.j2
new file mode 100644 (file)
index 0000000..e2cd559
--- /dev/null
@@ -0,0 +1,23 @@
+$TTL 300
+$ORIGIN update-any.
+
+update-any.    IN      SOA  mname1. . (
+                       1       ; serial
+                       20      ; refresh (20 seconds)
+                       20      ; retry (20 seconds)
+                       1814400 ; expire (3 weeks)
+                       3600    ; minimum (1 hour)
+                       )
+
+                       NS      ns2
+ns2                    A       10.53.0.2
+
+scanner                        A       10.53.0.2
+
+model2                 NS      ns3
+                       NS      ns4
+
+ns3.model2             A       10.53.0.3
+ns4.model2             A       10.53.0.4
+
+*._dsync               DSYNC   CDS NOTIFY @PORT@ scanner
diff --git a/bin/tests/system/multisigner/ns3/model2.update-any.db b/bin/tests/system/multisigner/ns3/model2.update-any.db
new file mode 100644 (file)
index 0000000..74fa7fa
--- /dev/null
@@ -0,0 +1,16 @@
+$TTL 300
+@              IN      SOA  mname1. . (
+                       1       ; serial
+                       20      ; refresh (20 seconds)
+                       20      ; retry (20 seconds)
+                       1814400 ; expire (3 weeks)
+                       3600    ; minimum (1 hour)
+                       )
+
+                       NS      ns3
+ns3                    A       10.53.0.3
+
+a                      A       10.0.0.1
+b                      A       10.0.0.2
+c                      A       10.0.0.3
+
index a4437a890e651d43862a71f4663591f04bd7a7b7..a7f2546cb598be9642673e3a507432460fcbb978 100644 (file)
@@ -33,6 +33,14 @@ zone "model2.multisigner." {
        inline-signing no;
 };
 
+zone "model2.update-any." {
+       type primary;
+       allow-update { any; };
+       file "model2.update-any.db";
+       dnssec-policy model2;
+       inline-signing no;
+};
+
 zone "model2.bad-dsync." {
        type primary;
        allow-update { any; };
index 50f26480f7f9ac7bd8a21abdb6dd6203af52f31c..2aa711c856881036716e37f64ed11facc48a5984 100644 (file)
@@ -29,6 +29,15 @@ $SETTIME -s -g $O -k $O now -r $O now -d $O now "$KSK" >settime.out.$zone.1 2>&1
 $SETTIME -s -g $O -k $O now -z $O now "$ZSK" >settime.out.$zone.2 2>&1
 $DSFROMKEY $KSK.key >dsset-ns3-${zone}.
 
+zone="model2.update-any"
+echo_i "setting up zone: $zone"
+zonefile="${zone}.db"
+KSK=$($KEYGEN -q -a $DEFAULT_ALGORITHM -f KSK -L 3600 $ksktimes $zone)
+ZSK=$($KEYGEN -q -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone)
+$SETTIME -s -g $O -k $O now -r $O now -d $O now "$KSK" >settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O now -z $O now "$ZSK" >settime.out.$zone.2 2>&1
+$DSFROMKEY $KSK.key >dsset-ns3-${zone}.
+
 zone="model2.bad-dsync"
 echo_i "setting up zone: $zone"
 zonefile="${zone}.db"
diff --git a/bin/tests/system/multisigner/ns4/model2.update-any.db b/bin/tests/system/multisigner/ns4/model2.update-any.db
new file mode 100644 (file)
index 0000000..8a84c8b
--- /dev/null
@@ -0,0 +1,15 @@
+$TTL 300
+@              IN      SOA  mname1. . (
+                       1       ; serial
+                       20      ; refresh (20 seconds)
+                       20      ; retry (20 seconds)
+                       1814400 ; expire (3 weeks)
+                       3600    ; minimum (1 hour)
+                       )
+
+                       NS      ns4
+ns4                    A       10.53.0.4
+
+a                      A       10.0.0.1
+b                      A       10.0.0.2
+c                      A       10.0.0.3
index 0637c2d2b1bb7fd78459474cc4a20ab6f42e3941..cc73f37179e0e7b3713a6d89c80a7d240c888e2e 100644 (file)
@@ -33,6 +33,14 @@ zone "model2.multisigner." {
        inline-signing yes;
 };
 
+zone "model2.update-any." {
+       type primary;
+       allow-update { any; };
+       file "model2.update-any.db";
+       dnssec-policy model2;
+       inline-signing yes;
+};
+
 zone "model2.bad-dsync." {
        type primary;
        allow-update { any; };
index bb13b8bede0f63872c41642cb3a2a34567e2c5e2..6d4509872edd6e1694dd05d362625033368c27dd 100644 (file)
@@ -29,6 +29,15 @@ $SETTIME -s -g $O -k $O now -r $O now -d $O now "$KSK" >settime.out.$zone.1 2>&1
 $SETTIME -s -g $O -k $O now -z $O now "$ZSK" >settime.out.$zone.2 2>&1
 $DSFROMKEY $KSK.key >dsset-ns4-${zone}.
 
+zone="model2.update-any"
+echo_i "setting up zone: $zone"
+zonefile="${zone}.db"
+KSK=$($KEYGEN -q -a $DEFAULT_ALGORITHM -f KSK -L 3600 $ksktimes $zone)
+ZSK=$($KEYGEN -q -a $DEFAULT_ALGORITHM -L 3600 $zsktimes $zone)
+$SETTIME -s -g $O -k $O now -r $O now -d $O now "$KSK" >settime.out.$zone.1 2>&1
+$SETTIME -s -g $O -k $O now -z $O now "$ZSK" >settime.out.$zone.2 2>&1
+$DSFROMKEY $KSK.key >dsset-ns4-${zone}.
+
 zone="model2.bad-dsync"
 echo_i "setting up zone: $zone"
 zonefile="${zone}.db"
index d3db8ad163072763aa968dc14ca5a045cc1ea396..5fa713c9aa84fa0f44f7e176147e3d5488d12819 100644 (file)
@@ -233,7 +233,15 @@ def _check_remove_zsk_fail(
 
 
 def check_remove_zsk(
-    server, zone, keys, expected, extra_keys, extra, primary=None, check_fail=False
+    server,
+    zone,
+    keys,
+    expected,
+    extra_keys,
+    extra,
+    primary=None,
+    check_fail=False,
+    update_any=False,
 ):
     isctest.log.info("remove dnskey record:")
 
@@ -242,20 +250,31 @@ def check_remove_zsk(
 
     if check_fail:
         _check_remove_zsk_fail(
-            server, zone, keys, expected, extra_keys, extra, primary=primary
+            server,
+            zone,
+            keys,
+            expected,
+            extra_keys,
+            extra,
+            primary=primary,
         )
 
-    # Remove actual ZSK.
-    isctest.log.info(
-        f"- zone {zone} {primary.identifier}: remove ZSK from other providers"
-    )
-
-    update_msg = dns.update.UpdateMessage(zone)
-    for zsk in extra_keys:
-        dnskey = str(zsk.dnskey).split()
-        rdata = " ".join(dnskey[4:])
-        update_msg.delete(f"{zone}.", "DNSKEY", rdata)
-    primary.nsupdate(update_msg)
+    if update_any:
+        # Remove ZSK with update ANY.
+        isctest.log.info(
+            f"- zone {zone} {primary.identifier}: remove DNSKEY RRset with update ANY (expect ours)"
+        )
+        update_msg = dns.update.UpdateMessage(zone)
+        update_msg.delete(f"{zone}.", "DNSKEY")
+        primary.nsupdate(update_msg)
+    else:
+        # Remove actual ZSK.
+        update_msg = dns.update.UpdateMessage(zone)
+        for zsk in extra_keys:
+            dnskey = str(zsk.dnskey).split()
+            rdata = " ".join(dnskey[4:])
+            update_msg.delete(f"{zone}.", "DNSKEY", rdata)
+        primary.nsupdate(update_msg)
 
     wait_for_serial(primary, server, zone)
 
@@ -349,7 +368,15 @@ def _check_remove_cdnskey_fail(
 
 
 def check_remove_cdnskey(
-    server, zone, keys, expected, extra_keys, extra, primary=None, check_fail=False
+    server,
+    zone,
+    keys,
+    expected,
+    extra_keys,
+    extra,
+    primary=None,
+    check_fail=False,
+    update_any=False,
 ):
     isctest.log.info("remove cdnskey record:")
 
@@ -358,20 +385,35 @@ def check_remove_cdnskey(
 
     if check_fail:
         _check_remove_cdnskey_fail(
-            server, zone, keys, expected, extra_keys, extra, primary=primary
+            server,
+            zone,
+            keys,
+            expected,
+            extra_keys,
+            extra,
+            primary=primary,
         )
 
-    # Remove actual CDNSKEY.
-    isctest.log.info(
-        f"- zone {zone} {primary.identifier}: remove CDNSKEY from other providers"
-    )
+    if update_any:
+        # Remove CDNSKEY with update ANY.
+        isctest.log.info(
+            f"- zone {zone} {primary.identifier}: remove CDNSKEY RRset with update ANY (expect ours)"
+        )
+        update_msg = dns.update.UpdateMessage(zone)
+        update_msg.delete(f"{zone}.", "CDNSKEY")
+        primary.nsupdate(update_msg)
+    else:
+        # Remove actual CDNSKEY.
+        isctest.log.info(
+            f"- zone {zone} {primary.identifier}: remove CDNSKEY from other providers"
+        )
 
-    update_msg = dns.update.UpdateMessage(zone)
-    for ksk in extra_keys:
-        dnskey = str(ksk.dnskey).split()
-        rdata = " ".join(dnskey[4:])
-        update_msg.delete(f"{zone}.", "CDNSKEY", rdata)
-    primary.nsupdate(update_msg)
+        update_msg = dns.update.UpdateMessage(zone)
+        for ksk in extra_keys:
+            dnskey = str(ksk.dnskey).split()
+            rdata = " ".join(dnskey[4:])
+            update_msg.delete(f"{zone}.", "CDNSKEY", rdata)
+        primary.nsupdate(update_msg)
 
     wait_for_serial(primary, server, zone)
 
@@ -465,7 +507,15 @@ def _check_remove_cds_fail(
 
 
 def check_remove_cds(
-    server, zone, keys, expected, extra_keys, extra, primary=None, check_fail=False
+    server,
+    zone,
+    keys,
+    expected,
+    extra_keys,
+    extra,
+    primary=None,
+    check_fail=False,
+    update_any=False,
 ):
     isctest.log.info("remove cds record:")
 
@@ -477,17 +527,26 @@ def check_remove_cds(
             server, zone, keys, expected, extra_keys, extra, primary=primary
         )
 
-    # Remove actual CDS.
-    isctest.log.info(
-        f"- zone {zone} {primary.identifier}: remove CDS from other providers"
-    )
+    if update_any:
+        # Remove CDS with update ANY.
+        isctest.log.info(
+            f"- zone {zone} {primary.identifier}: remove CDS RRset with update ANY (expect ours)"
+        )
+        update_msg = dns.update.UpdateMessage(zone)
+        update_msg.delete(f"{zone}.", "CDS")
+        primary.nsupdate(update_msg)
+    else:
+        # Remove actual CDS.
+        isctest.log.info(
+            f"- zone {zone} {primary.identifier}: remove CDS from other providers"
+        )
 
-    update_msg = dns.update.UpdateMessage(zone)
-    for ksk in extra_keys:
-        ds = dsfromkey(ksk)
-        rdata = " ".join(ds[4:])
-        update_msg.delete(f"{zone}.", "CDS", rdata)
-    primary.nsupdate(update_msg)
+        update_msg = dns.update.UpdateMessage(zone)
+        for ksk in extra_keys:
+            ds = dsfromkey(ksk)
+            rdata = " ".join(ds[4:])
+            update_msg.delete(f"{zone}.", "CDS", rdata)
+        primary.nsupdate(update_msg)
 
     wait_for_serial(primary, server, zone)
 
@@ -595,6 +654,94 @@ def test_multisigner(ns2, ns3, ns4, default_algorithm):
     check_no_dnssec_in_journal(ns4, zone)
 
 
+def test_multisigner_update_any(ns2, ns3, ns4, default_algorithm):
+    zone = "model2.update-any"
+    keyprops = [
+        f"ksk 0 {default_algorithm.number} {default_algorithm.bits} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent",
+        f"zsk 0 {default_algorithm.number} {default_algorithm.bits} 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)
+
+    with ns3.watch_log_from_start() as watcher:
+        watcher.wait_for_line(
+            f"zone {zone}/IN: dsyncfetch: send NOTIFY(CDS) query to scanner.update-any"
+        )
+
+    with ns4.watch_log_from_start() as watcher:
+        watcher.wait_for_line(
+            f"zone {zone}/IN (signed): dsyncfetch: send NOTIFY(CDS) query to scanner.update-any"
+        )
+
+    with ns2.watch_log_from_start() as watcher:
+        # Receiving NOTIFY(CDS) has not been implemented yet.  Until
+        # then, notifies for child zones towards the parent result in
+        # not authoritative (unless child and parent are served by the
+        # same name server).
+        watcher.wait_for_line(f"received notify for zone '{zone}': NOTAUTH")
+
+    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 {default_algorithm.number} {default_algorithm.bits}"]
+    extra = isctest.kasp.policy_to_properties(ttl=TTL, keys=newprops)
+    extra[0].private = False
+    extra[0].legacy = True
+
+    check_add_zsk(ns3, zone, keys3, expected3, [zsks4[0]], extra)
+    check_add_zsk(ns4, zone, keys4, expected4, [zsks3[0]], extra)
+    check_no_dnssec_in_journal(ns4, zone)
+
+    # Remove DNSKEY from RRset.
+    check_remove_zsk(ns3, zone, keys3, expected3, [zsks4[0]], extra, update_any=True)
+    check_remove_zsk(ns4, zone, keys4, expected4, [zsks3[0]], extra, update_any=True)
+    check_no_dnssec_in_journal(ns4, zone)
+
+    # Add CDNSKEY RRset.
+    newprops = [f"ksk unlimited {default_algorithm.number} {default_algorithm.bits}"]
+    extra = isctest.kasp.policy_to_properties(ttl=TTL, keys=newprops)
+    extra[0].private = False
+    extra[0].legacy = True
+
+    check_add_cdnskey(ns3, zone, keys3, expected3, [ksks4[0]], extra)
+    check_add_cdnskey(ns4, zone, keys4, expected4, [ksks3[0]], extra)
+    check_no_dnssec_in_journal(ns4, zone)
+
+    # Remove CDNSKEY RRset.
+    check_remove_cdnskey(
+        ns3, zone, keys3, expected3, [ksks4[0]], extra, update_any=True
+    )
+    check_remove_cdnskey(
+        ns4, zone, keys4, expected4, [ksks3[0]], extra, update_any=True
+    )
+    check_no_dnssec_in_journal(ns4, zone)
+
+    # Update CDS RRset.
+    check_add_cds(ns3, zone, keys3, expected3, [ksks4[0]], extra)
+    check_add_cds(ns4, zone, keys4, expected4, [ksks3[0]], extra)
+    check_no_dnssec_in_journal(ns4, zone)
+
+    # Remove CDS RRset.
+    check_remove_cds(ns3, zone, keys3, expected3, [ksks4[0]], extra, update_any=True)
+    check_remove_cds(ns4, zone, keys4, expected4, [ksks3[0]], extra, update_any=True)
+    check_no_dnssec_in_journal(ns4, zone)
+
+
 def test_multisigner_bad_dsync(ns3, ns4):
     zone = "model2.bad-dsync"