From b0b3e2f12e995718174f382b352a22f9a8ef1d67 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 5 Oct 2022 13:36:42 +0200 Subject: [PATCH] Allow DNSKEY when syncing secure journal/db When synchronizing the journal or database from the unsigned version of the zone to the secure version of the zone, allow DNSKEY records to be synced, because these may be added by the user with the sole intent to publish the record (not used for signing). This may be the case for example in the multisigner model 2 (RFC 8901). Additional code needs to be added to ensure that we do not remove DNSKEY records that are under our control. Keys under our control are keys that are used for signing the zone and thus that we have key files for. Same counts for CDNSKEY and CDS (records that are derived from keys). --- lib/dns/zone.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- lib/ns/update.c | 24 ++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/lib/dns/zone.c b/lib/dns/zone.c index ae96df07ab..c18fe4bff8 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -16020,7 +16020,6 @@ dns_zone_dnskey_inuse(dns_zone_t *zone, dns_rdata_t *rdata, bool *inuse) { break; } -out: while (!ISC_LIST_EMPTY(keylist)) { key = ISC_LIST_HEAD(keylist); ISC_LIST_UNLINK(keylist, key, link); @@ -16085,14 +16084,32 @@ sync_secure_journal(dns_zone_t *zone, dns_zone_t *raw, dns_journal_t *journal, continue; } + /* + * Skip DNSSEC records that BIND maintains with inline-signing. + */ if (rdata->type == dns_rdatatype_nsec || rdata->type == dns_rdatatype_rrsig || rdata->type == dns_rdatatype_nsec3 || - rdata->type == dns_rdatatype_dnskey || rdata->type == dns_rdatatype_nsec3param) { continue; } + /* + * Allow DNSKEY, CDNSKEY, CDS because users should be able to + * update the zone with these records from a different provider, + * but skip records that are under our control. + */ + if (rdata->type == dns_rdatatype_dnskey || + rdata->type == dns_rdatatype_cdnskey || + rdata->type == dns_rdatatype_cds) + { + bool inuse = false; + isc_result_t r = dns_zone_dnskey_inuse(zone, rdata, + &inuse); + if (r == ISC_R_SUCCESS && inuse) { + continue; + } + } op = (n_soa == 1) ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD; @@ -16138,9 +16155,11 @@ sync_secure_db(dns_zone_t *seczone, dns_zone_t *raw, dns_db_t *secdb, for (tuple = ISC_LIST_HEAD(diff->tuples); tuple != NULL; tuple = next) { next = ISC_LIST_NEXT(tuple, link); + /* + * Skip DNSSEC records that BIND maintains with inline-signing. + */ if (tuple->rdata.type == dns_rdatatype_nsec || tuple->rdata.type == dns_rdatatype_rrsig || - tuple->rdata.type == dns_rdatatype_dnskey || tuple->rdata.type == dns_rdatatype_nsec3 || tuple->rdata.type == dns_rdatatype_nsec3param) { @@ -16148,6 +16167,26 @@ sync_secure_db(dns_zone_t *seczone, dns_zone_t *raw, dns_db_t *secdb, dns_difftuple_free(&tuple); continue; } + + /* + * Allow DNSKEY, CDNSKEY, CDS because users should be able to + * update the zone with these records from a different provider, + * but skip records that are under our control. + */ + if (tuple->rdata.type == dns_rdatatype_dnskey || + tuple->rdata.type == dns_rdatatype_cdnskey || + tuple->rdata.type == dns_rdatatype_cds) + { + bool inuse = false; + isc_result_t r = dns_zone_dnskey_inuse( + seczone, &tuple->rdata, &inuse); + if (r == ISC_R_SUCCESS && inuse) { + ISC_LIST_UNLINK(diff->tuples, tuple, link); + dns_difftuple_free(&tuple); + continue; + } + } + if (tuple->rdata.type == dns_rdatatype_soa) { if (tuple->op == DNS_DIFFOP_DEL) { INSIST(oldtuple == NULL); diff --git a/lib/ns/update.c b/lib/ns/update.c index bd3d3af3d4..493637f147 100644 --- a/lib/ns/update.c +++ b/lib/ns/update.c @@ -3377,6 +3377,30 @@ update_action(void *arg) { continue; } } + /* + * Don't remove DNSKEY, CDNSKEY, CDS records + * that are in use (under our control). + */ + if (rdata.type == dns_rdatatype_dnskey || + rdata.type == dns_rdatatype_cdnskey || + rdata.type == dns_rdatatype_cds) + { + isc_result_t r; + bool inuse = false; + r = dns_zone_dnskey_inuse(zone, &rdata, + &inuse); + if (r != ISC_R_SUCCESS) { + FAIL(r); + } + if (inuse) { + update_log(client, zone, + LOGLEVEL_PROTOCOL, + "attempt to " + "delete in use " + "DNSKEY ignored"); + continue; + } + } } dns_name_format(name, namestr, sizeof(namestr)); dns_rdatatype_format(rdata.type, typestr,