From 9c35c96deeb7526b280e3c1e35fd4486a7a38d50 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 13 May 2026 20:03:43 -0700 Subject: [PATCH] Prevent UDPATE deleting keys in dnssec-policy zones In dnssec-policy zones, DNSKEY, CDNSKEY and CDS data at the zone apex should not be deleted by UPDATE. Previously, this was prevented when deleting individual RRs. It is now also prevented when deleting the entire RRset. --- bin/tests/system/nsupdate/tests.sh | 18 ++++++++++ lib/ns/update.c | 55 ++++++++++++++++++------------ 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/bin/tests/system/nsupdate/tests.sh b/bin/tests/system/nsupdate/tests.sh index 7a77faea6be..bce4b98b810 100755 --- a/bin/tests/system/nsupdate/tests.sh +++ b/bin/tests/system/nsupdate/tests.sh @@ -2303,6 +2303,24 @@ retry_quiet 5 has_positive_response multisigner.test CDNSKEY 10.53.0.3 || ret=1 status=1 } +n=$((n + 1)) +ret=0 +echo_i "check that DNSKEY removal in dnssec-policy zone is rejected ($n)" +$DIG $DIGOPTS +tcp +norec multisigner.test DNSKEY @10.53.0.3 >dig.out.pre.test$n || ret=1 +grep "status: NOERROR" dig.out.pre.test$n >/dev/null || ret=1 +grep "ANSWER: 1," dig.out.pre.test$n >/dev/null || ret=1 +$NSUPDATE -d <nsupdate.out.test$n 2>&1 || ret=1 +server 10.53.0.3 ${PORT} +zone multisigner.test +update delete multisigner.test DNSKEY +send +END +retry_quiet 5 has_positive_response multisigner.test DNSKEY 10.53.0.3 || ret=1 +[ $ret = 0 ] || { + echo_i "failed" + status=1 +} + n=$((n + 1)) ret=0 echo_i "check that excessive NSEC3PARAM iterations are rejected by nsupdate ($n)" diff --git a/lib/ns/update.c b/lib/ns/update.c index 93240ca250c..f2ad9fe3d39 100644 --- a/lib/ns/update.c +++ b/lib/ns/update.c @@ -3044,32 +3044,45 @@ update_action(void *arg) { dns_rdatatype_none, &rdata, &diff)); } - } else if (dns_name_equal(name, zonename) && - (rdata.type == dns_rdatatype_soa || - rdata.type == dns_rdatatype_ns)) - { - update_log(client, zone, LOGLEVEL_PROTOCOL, - "attempt to delete all SOA or NS " - "records ignored"); continue; - } else { - if (isc_log_wouldlog(LOGLEVEL_PROTOCOL)) { - char namestr[DNS_NAME_FORMATSIZE]; - char typestr[DNS_RDATATYPE_FORMATSIZE]; - dns_name_format(name, namestr, - sizeof(namestr)); - dns_rdatatype_format(rdata.type, - typestr, - sizeof(typestr)); + } else if (dns_name_equal(name, zonename)) { + char typestr[DNS_RDATATYPE_FORMATSIZE]; + dns_rdatatype_format(rdata.type, typestr, + sizeof(typestr)); + if (rdata.type == dns_rdatatype_soa || + rdata.type == dns_rdatatype_ns) + { update_log(client, zone, LOGLEVEL_PROTOCOL, - "deleting rrset at '%s' %s", - namestr, typestr); + "attempt to delete all %s " + "records ignored", + typestr); + continue; + } else if (dns_zone_getkasp(zone) != NULL && + dns_rdatatype_iskeymaterial( + rdata.type)) + { + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "attempt to delete %s " + "records in dnssec-policy " + "zone ignored", + typestr); + continue; } - CHECK(delete_if(true_p, db, ver, name, - rdata.type, covers, &rdata, - &diff)); } + if (isc_log_wouldlog(LOGLEVEL_PROTOCOL)) { + char namestr[DNS_NAME_FORMATSIZE]; + char typestr[DNS_RDATATYPE_FORMATSIZE]; + dns_name_format(name, namestr, sizeof(namestr)); + dns_rdatatype_format(rdata.type, typestr, + sizeof(typestr)); + update_log(client, zone, LOGLEVEL_PROTOCOL, + "deleting rrset at '%s' %s", namestr, + typestr); + } + CHECK(delete_if(true_p, db, ver, name, rdata.type, + covers, &rdata, &diff)); } else if (update_class == dns_rdataclass_none) { char namestr[DNS_NAME_FORMATSIZE]; char typestr[DNS_RDATATYPE_FORMATSIZE]; -- 2.47.3