diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c index 9956e351fa..873da27849 100644 --- a/bin/named/zoneconf.c +++ b/bin/named/zoneconf.c @@ -1710,6 +1710,28 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig, dns_zone_clearforwardacl)); } + /*% + * Configure parental agents, applies to primary and secondary zones. + */ + if (ztype == dns_zone_master || ztype == dns_zone_slave) { + obj = NULL; + (void)cfg_map_get(zoptions, "parental-agents", &obj); + if (obj != NULL) { + dns_ipkeylist_t ipkl; + dns_ipkeylist_init(&ipkl); + RETERR(named_config_getipandkeylist( + config, "parental-agents", obj, mctx, &ipkl)); + result = dns_zone_setparentals(zone, ipkl.addrs, + ipkl.keys, ipkl.tlss, + ipkl.count); + dns_ipkeylist_clear(mctx, &ipkl); + RETERR(result); + } else { + RETERR(dns_zone_setparentals(zone, NULL, NULL, NULL, + 0)); + } + } + /*% * Primary master functionality. */ diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index a981f0dd23..dc8350c6e3 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -642,12 +642,30 @@ dns_zone_setprimaries(dns_zone_t *zone, const isc_sockaddr_t *primaries, *\li 'zone' to be a valid zone. *\li 'primaries' array of isc_sockaddr_t with port set or NULL. *\li 'count' the number of primaries. - *\li 'keynames' array of dns_name_t's for tsig keys or NULL. + *\li 'keynames' array of dns_name_t's for tsig keys or NULL. * - * \li dns_zone_setprimaries() is just a wrapper to setprimarieswithkeys(), - * passing NULL in the keynames field. + *\li If 'primaries' is NULL then 'count' must be zero. * - * \li If 'primaries' is NULL then 'count' must be zero. + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li Any result dns_name_dup() can return, if keynames!=NULL + */ + +isc_result_t +dns_zone_setparentals(dns_zone_t *zone, const isc_sockaddr_t *parentals, + dns_name_t **keynames, dns_name_t **tlsnames, + uint32_t count); +/*%< + * Set the list of parental agents for the zone. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'parentals' array of isc_sockaddr_t with port set or NULL. + *\li 'count' the number of primaries. + *\li 'keynames' array of dns_name_t's for tsig keys or NULL. + * + *\li If 'parentals' is NULL then 'count' must be zero. * * Returns: *\li #ISC_R_SUCCESS diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 46a0aff8f9..3211c54de8 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -281,6 +281,15 @@ struct dns_zone { unsigned int masterscnt; unsigned int curmaster; isc_sockaddr_t masteraddr; + + isc_sockaddr_t *parentals; + isc_dscp_t *parentaldscps; + dns_name_t **parentalkeynames; + dns_name_t **parentaltlsnames; + dns_dnsseckeylist_t checkds_ok; + unsigned int parentalscnt; + isc_sockaddr_t parentaladdr; + dns_notifytype_t notifytype; isc_sockaddr_t *notify; dns_name_t **notifykeynames; @@ -1129,6 +1138,16 @@ free_refs: return (result); } +static void +clear_keylist(dns_dnsseckeylist_t *list, isc_mem_t *mctx) { + dns_dnsseckey_t *key; + while (!ISC_LIST_EMPTY(*list)) { + key = ISC_LIST_HEAD(*list); + ISC_LIST_UNLINK(*list, key, link); + dns_dnsseckey_destroy(mctx, &key); + } +} + /* * Free a zone. Because we require that there be no more * outstanding events or references, no locking is necessary. @@ -1222,6 +1241,10 @@ zone_free(dns_zone_t *zone) { if (zone->kasp != NULL) { dns_kasp_detach(&zone->kasp); } + if (!ISC_LIST_EMPTY(zone->checkds_ok)) { + clear_keylist(&zone->checkds_ok, zone->mctx); + } + zone->journalsize = -1; if (zone->journal != NULL) { isc_mem_free(zone->mctx, zone->journal); @@ -1251,6 +1274,8 @@ zone_free(dns_zone_t *zone) { dns_catz_catzs_detach(&zone->catzs); } zone_freedbargs(zone); + RUNTIME_CHECK(dns_zone_setparentals(zone, NULL, NULL, NULL, 0) == + ISC_R_SUCCESS); RUNTIME_CHECK(dns_zone_setprimaries(zone, NULL, NULL, NULL, 0) == ISC_R_SUCCESS); RUNTIME_CHECK(dns_zone_setalsonotify(zone, NULL, NULL, NULL, NULL, 0) == @@ -6305,6 +6330,62 @@ unlock: return (result); } +isc_result_t +dns_zone_setparentals(dns_zone_t *zone, const isc_sockaddr_t *parentals, + dns_name_t **keynames, dns_name_t **tlsnames, + uint32_t count) { + isc_result_t result = ISC_R_SUCCESS; + isc_sockaddr_t *newaddrs = NULL; + isc_dscp_t *newdscps = NULL; + dns_name_t **newkeynames = NULL; + dns_name_t **newtlsnames = NULL; + + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(count == 0 || parentals != NULL); + if (keynames != NULL || tlsnames != NULL) { + REQUIRE(count != 0); + } + + LOCK_ZONE(zone); + + clear_serverslist(&zone->parentals, &zone->parentaldscps, + &zone->parentalkeynames, &zone->parentaltlsnames, + &zone->parentalscnt, zone->mctx); + /* + * If count == 0, don't allocate any space for parentals, or keynames + * so internally, those pointers are NULL if count == 0 + */ + if (count == 0) { + goto unlock; + } + + /* + * Now set up the parentals and parental key lists + */ + result = set_serverslist(count, parentals, &newaddrs, NULL, &newdscps, + keynames, &newkeynames, tlsnames, &newtlsnames, + zone->mctx); + INSIST(newdscps == NULL); + if (result != ISC_R_SUCCESS) { + goto unlock; + } + + /* + * Everything is ok so attach to the zone. + */ + zone->parentals = newaddrs; + zone->parentaldscps = newdscps; + zone->parentalkeynames = newkeynames; + zone->parentaltlsnames = newtlsnames; + zone->parentalscnt = count; + + dns_zone_log(zone, ISC_LOG_NOTICE, "checkds: set %u parentals", count); + +unlock: + UNLOCK_ZONE(zone); + return (result); +} + isc_result_t dns_zone_getdb(dns_zone_t *zone, dns_db_t **dpb) { isc_result_t result = ISC_R_SUCCESS; @@ -19617,16 +19698,6 @@ cleanup: return (result); } -static void -clear_keylist(dns_dnsseckeylist_t *list, isc_mem_t *mctx) { - dns_dnsseckey_t *key; - while (!ISC_LIST_EMPTY(*list)) { - key = ISC_LIST_HEAD(*list); - ISC_LIST_UNLINK(*list, key, link); - dns_dnsseckey_destroy(mctx, &key); - } -} - /* Called once; *timep should be set to the current time. */ static isc_result_t next_keyevent(dst_key_t *key, isc_stdtime_t *timep) {