From 35bdc94f51abffceef8673d2ef7f034cc393b2cb Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Fri, 17 Oct 2025 15:55:00 +0200 Subject: [PATCH 1/4] Rename notify remote to alsonotify Make it more clear it is tied to the 'also-notify' option. --- lib/dns/zone.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/dns/zone.c b/lib/dns/zone.c index d4275f24d3..9a08871026 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -354,11 +354,12 @@ struct dns_zone { uint32_t nsfetchcount; uint32_t parent_nscount; - dns_remote_t notify; + dns_remote_t alsonotify; dns_notifytype_t notifytype; isc_sockaddr_t notifyfrom; isc_sockaddr_t notifysrc4; isc_sockaddr_t notifysrc6; + isc_sockaddr_t parentalsrc4; isc_sockaddr_t parentalsrc6; isc_sockaddr_t xfrsource4; @@ -1207,7 +1208,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx, isc_tid_t tid) { zone->primaries = r; zone->parentals = r; - zone->notify = r; + zone->alsonotify = r; zone->defaultkasp = NULL; ISC_LIST_INIT(zone->keyring); @@ -6546,11 +6547,11 @@ dns_zone_setalsonotify(dns_zone_t *zone, isc_sockaddr_t *addresses, remote.tlsnames = tlsnames; remote.addrcnt = count; - if (dns_remote_equal(&zone->notify, &remote)) { + if (dns_remote_equal(&zone->alsonotify, &remote)) { goto unlock; } - dns_remote_clear(&zone->notify); + dns_remote_clear(&zone->alsonotify); /* * If count == 0, don't allocate any space for servers to notify. @@ -6562,7 +6563,7 @@ dns_zone_setalsonotify(dns_zone_t *zone, isc_sockaddr_t *addresses, /* * Now set up the notify address and key lists. */ - dns_remote_init(&zone->notify, count, addresses, sources, keynames, + dns_remote_init(&zone->alsonotify, count, addresses, sources, keynames, tlsnames, true, zone->mctx); unlock: @@ -13290,20 +13291,22 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { */ LOCK_ZONE(zone); - dns_remote_reset(&zone->notify, false); - while (!dns_remote_done(&zone->notify)) { + dns_remote_reset(&zone->alsonotify, false); + while (!dns_remote_done(&zone->alsonotify)) { dns_tsigkey_t *key = NULL; dns_transport_t *transport = NULL; dns_notify_t *notify = NULL; dns_view_t *view = dns_zone_getview(zone); - if (dns_remote_keyname(&zone->notify) != NULL) { - dns_name_t *keyname = dns_remote_keyname(&zone->notify); + if (dns_remote_keyname(&zone->alsonotify) != NULL) { + dns_name_t *keyname = + dns_remote_keyname(&zone->alsonotify); (void)dns_view_gettsig(view, keyname, &key); } - if (dns_remote_tlsname(&zone->notify) != NULL) { - dns_name_t *tlsname = dns_remote_tlsname(&zone->notify); + if (dns_remote_tlsname(&zone->alsonotify) != NULL) { + dns_name_t *tlsname = + dns_remote_tlsname(&zone->alsonotify); result = dns_view_gettransport(view, DNS_TRANSPORT_TLS, tlsname, &transport); @@ -13325,8 +13328,8 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { /* TODO: glue the transport to the notify */ - dst = dns_remote_curraddr(&zone->notify); - src = dns_remote_sourceaddr(&zone->notify); + dst = dns_remote_curraddr(&zone->alsonotify); + src = dns_remote_sourceaddr(&zone->alsonotify); INSIST(isc_sockaddr_pf(&src) == isc_sockaddr_pf(&dst)); if (isc_sockaddr_disabled(&dst)) { @@ -13383,7 +13386,7 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { } next: flags &= ~DNS_NOTIFY_TCP; - dns_remote_next(&zone->notify, false); + dns_remote_next(&zone->alsonotify, false); } UNLOCK_ZONE(zone); From e8eebf1ad60c193bdd3993d86b127892d4098b11 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Thu, 16 Oct 2025 17:01:57 +0200 Subject: [PATCH 2/4] Introduce notify source code files Part of refactoring zone.c is to move the notify code into its own source files. This commit initiates this work by creating notify.[c,h] and move notify_create() and the notify state and context there. The function notify_create() cannot fail, so it can return void instead of isc_result_t. --- lib/dns/include/dns/notify.h | 74 +++++++++++++++++ lib/dns/include/dns/types.h | 3 + lib/dns/meson.build | 1 + lib/dns/notify.c | 38 +++++++++ lib/dns/zone.c | 155 +++++++++++------------------------ 5 files changed, 162 insertions(+), 109 deletions(-) create mode 100644 lib/dns/include/dns/notify.h create mode 100644 lib/dns/notify.c diff --git a/lib/dns/include/dns/notify.h b/lib/dns/include/dns/notify.h new file mode 100644 index 0000000000..fd62f527fe --- /dev/null +++ b/lib/dns/include/dns/notify.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#pragma once + +/*! \file dns/notify.h */ + +#include + +#include +#include + +#define NOTIFY_MAGIC ISC_MAGIC('N', 't', 'f', 'y') +#define DNS_NOTIFY_VALID(notify) ISC_MAGIC_VALID(notify, NOTIFY_MAGIC) + +/*% + * Hold notify contxt. + */ +struct dns_notifyctx { + dns_acl_t *notify_acl; + + isc_sockaddr_t notifyfrom; + dns_notifylist_t notifies; + + /* Configuration data. */ + dns_notifytype_t notifytype; + isc_sockaddr_t notifysrc4; + isc_sockaddr_t notifysrc6; +}; + +/*% + * Hold notify state. + */ +struct dns_notify { + unsigned int magic; + unsigned int flags; + isc_mem_t *mctx; + dns_zone_t *zone; + dns_adbfind_t *find; + dns_request_t *request; + dns_name_t ns; + isc_sockaddr_t src; + isc_sockaddr_t dst; + dns_tsigkey_t *key; + dns_transport_t *transport; + ISC_LINK(dns_notify_t) link; + isc_rlevent_t *rlevent; +}; + +typedef enum dns_notify_flags { + DNS_NOTIFY_NOSOA = 1 << 0, + DNS_NOTIFY_STARTUP = 1 << 1, + DNS_NOTIFY_TCP = 1 << 2, +} dns_notify_flags_t; + +void +dns_notify_create(isc_mem_t *mctx, unsigned int flags, dns_notify_t **notifyp); +/*%< + * Create a notify structure to maintain state. + * + * Requires: + * 'mctx' is not NULL. + * 'notifyp' is not NULL and '*notifyp' is NULL. + */ diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index ba1fd98a3d..81dc8f95e2 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -121,6 +121,9 @@ typedef isc_region_t dns_label_t; typedef struct dns_name dns_name_t; typedef struct dns_nametree dns_nametree_t; typedef ISC_LIST(dns_name_t) dns_namelist_t; +typedef struct dns_notify dns_notify_t; +typedef struct dns_notifyctx dns_notifyctx_t; +typedef ISC_LIST(dns_notify_t) dns_notifylist_t; typedef struct dns_ntatable dns_ntatable_t; typedef struct dns_ntnode dns_ntnode_t; typedef enum dns_opcode dns_opcode_t; diff --git a/lib/dns/meson.build b/lib/dns/meson.build index 785aa961c1..02e06dabe7 100644 --- a/lib/dns/meson.build +++ b/lib/dns/meson.build @@ -120,6 +120,7 @@ dns_srcset.add( 'name.c', 'nametree.c', 'ncache.c', + 'notify.c', 'nsec.c', 'nsec3.c', 'nta.c', diff --git a/lib/dns/notify.c b/lib/dns/notify.c new file mode 100644 index 0000000000..53106a0df8 --- /dev/null +++ b/lib/dns/notify.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include + +#include + +void +dns_notify_create(isc_mem_t *mctx, unsigned int flags, dns_notify_t **notifyp) { + dns_notify_t *notify; + + REQUIRE(notifyp != NULL && *notifyp == NULL); + + notify = isc_mem_get(mctx, sizeof(*notify)); + *notify = (dns_notify_t){ + .flags = flags, + }; + + isc_mem_attach(mctx, ¬ify->mctx); + isc_sockaddr_any(¬ify->src); + isc_sockaddr_any(¬ify->dst); + dns_name_init(¬ify->ns); + ISC_LINK_INIT(notify, link); + notify->magic = NOTIFY_MAGIC; + *notifyp = notify; +} diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 9a08871026..918489e4ee 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -101,9 +102,6 @@ #define ZONE_MAGIC ISC_MAGIC('Z', 'O', 'N', 'E') #define DNS_ZONE_VALID(zone) ISC_MAGIC_VALID(zone, ZONE_MAGIC) -#define NOTIFY_MAGIC ISC_MAGIC('N', 't', 'f', 'y') -#define DNS_NOTIFY_VALID(notify) ISC_MAGIC_VALID(notify, NOTIFY_MAGIC) - #define CHECKDS_MAGIC ISC_MAGIC('C', 'h', 'D', 'S') #define DNS_CHECKDS_VALID(checkds) ISC_MAGIC_VALID(checkds, CHECKDS_MAGIC) @@ -173,7 +171,6 @@ #define DNS_DUMP_DELAY 900 /*%< 15 minutes */ #endif /* ifndef DNS_DUMP_DELAY */ -typedef struct dns_notify dns_notify_t; typedef struct dns_checkds dns_checkds_t; typedef struct dns_stub dns_stub_t; typedef struct dns_load dns_load_t; @@ -355,10 +352,7 @@ struct dns_zone { uint32_t parent_nscount; dns_remote_t alsonotify; - dns_notifytype_t notifytype; - isc_sockaddr_t notifyfrom; - isc_sockaddr_t notifysrc4; - isc_sockaddr_t notifysrc6; + dns_notifyctx_t notifyctx; isc_sockaddr_t parentalsrc4; isc_sockaddr_t parentalsrc6; @@ -370,14 +364,13 @@ struct dns_zone { /* Access Control Lists */ dns_acl_t *update_acl; dns_acl_t *forward_acl; - dns_acl_t *notify_acl; dns_acl_t *query_acl; dns_acl_t *queryon_acl; dns_acl_t *xfr_acl; bool update_disabled; bool zero_no_soa_ttl; dns_severity_t check_names; - ISC_LIST(dns_notify_t) notifies; + ISC_LIST(dns_checkds_t) checkds_requests; dns_request_t *request; dns_loadctx_t *loadctx; @@ -658,31 +651,6 @@ struct dns_zonemgr { isc_rwlock_t tlsctx_cache_rwlock; }; -/*% - * Hold notify state. - */ -struct dns_notify { - unsigned int magic; - unsigned int flags; - isc_mem_t *mctx; - dns_zone_t *zone; - dns_adbfind_t *find; - dns_request_t *request; - dns_name_t ns; - isc_sockaddr_t src; - isc_sockaddr_t dst; - dns_tsigkey_t *key; - dns_transport_t *transport; - ISC_LINK(dns_notify_t) link; - isc_rlevent_t *rlevent; -}; - -typedef enum dns_notify_flags { - DNS_NOTIFY_NOSOA = 1 << 0, - DNS_NOTIFY_STARTUP = 1 << 1, - DNS_NOTIFY_TCP = 1 << 2, -} dns_notify_flags_t; - /*% * Hold checkds state. */ @@ -1157,7 +1125,6 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx, isc_tid_t tid) { .maxretry = DNS_ZONE_MAXRETRY, .minretry = DNS_ZONE_MINRETRY, .checkdstype = dns_checkdstype_yes, - .notifytype = dns_notifytype_yes, .zero_no_soa_ttl = true, .check_names = dns_severity_ignore, .idlein = DNS_DEFAULT_IDLEIN, @@ -1179,7 +1146,6 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx, isc_tid_t tid) { .tid = tid, .notifytime = now, .newincludes = ISC_LIST_INITIALIZER, - .notifies = ISC_LIST_INITIALIZER, .checkds_requests = ISC_LIST_INITIALIZER, .signing = ISC_LIST_INITIALIZER, .nsec3chain = ISC_LIST_INITIALIZER, @@ -1191,6 +1157,13 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx, isc_tid_t tid) { dns_remote_t r = { .magic = DNS_REMOTE_MAGIC, }; + dns_notifyctx_t nc = { + .notifytype = dns_notifytype_yes, + .notifies = ISC_LIST_INITIALIZER, + }; + isc_sockaddr_any(&nc.notifysrc4); + isc_sockaddr_any6(&nc.notifysrc6); + zone->notifyctx = nc; isc_mem_attach(mctx, &zone->mctx); isc_mutex_init(&zone->lock); @@ -1199,8 +1172,6 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx, isc_tid_t tid) { isc_refcount_init(&zone->references, 1); isc_refcount_init(&zone->irefs, 0); dns_name_init(&zone->origin); - isc_sockaddr_any(&zone->notifysrc4); - isc_sockaddr_any6(&zone->notifysrc6); isc_sockaddr_any(&zone->parentalsrc4); isc_sockaddr_any6(&zone->parentalsrc6); isc_sockaddr_any(&zone->xfrsource4); @@ -1356,8 +1327,8 @@ zone_free(dns_zone_t *zone) { if (zone->forward_acl != NULL) { dns_acl_detach(&zone->forward_acl); } - if (zone->notify_acl != NULL) { - dns_acl_detach(&zone->notify_acl); + if (zone->notifyctx.notify_acl != NULL) { + dns_acl_detach(&zone->notifyctx.notify_acl); } if (zone->query_acl != NULL) { dns_acl_detach(&zone->query_acl); @@ -1475,7 +1446,7 @@ dns_zone_setnotifytype(dns_zone_t *zone, dns_notifytype_t notifytype) { REQUIRE(DNS_ZONE_VALID(zone)); LOCK_ZONE(zone); - zone->notifytype = notifytype; + zone->notifyctx.notifytype = notifytype; UNLOCK_ZONE(zone); } @@ -6496,7 +6467,7 @@ dns_zone_setnotifysrc4(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) { REQUIRE(notifysrc != NULL); LOCK_ZONE(zone); - zone->notifysrc4 = *notifysrc; + zone->notifyctx.notifysrc4 = *notifysrc; UNLOCK_ZONE(zone); } @@ -6506,7 +6477,7 @@ dns_zone_getnotifysrc4(dns_zone_t *zone, isc_sockaddr_t *notifysrc) { REQUIRE(notifysrc != NULL); LOCK_ZONE(zone); - *notifysrc = zone->notifysrc4; + *notifysrc = zone->notifyctx.notifysrc4; UNLOCK_ZONE(zone); } @@ -6516,7 +6487,7 @@ dns_zone_setnotifysrc6(dns_zone_t *zone, const isc_sockaddr_t *notifysrc) { REQUIRE(notifysrc != NULL); LOCK_ZONE(zone); - zone->notifysrc6 = *notifysrc; + zone->notifyctx.notifysrc6 = *notifysrc; UNLOCK_ZONE(zone); } @@ -6526,7 +6497,7 @@ dns_zone_getnotifysrc6(dns_zone_t *zone, isc_sockaddr_t *notifysrc) { REQUIRE(notifysrc != NULL); LOCK_ZONE(zone); - *notifysrc = zone->notifysrc6; + *notifysrc = zone->notifyctx.notifysrc6; UNLOCK_ZONE(zone); } @@ -12546,7 +12517,7 @@ notify_cancel(dns_zone_t *zone) { REQUIRE(LOCKED_ZONE(zone)); - ISC_LIST_FOREACH(zone->notifies, notify, link) { + ISC_LIST_FOREACH(zone->notifyctx.notifies, notify, link) { if (notify->find != NULL) { dns_adb_cancelfind(notify->find); } @@ -12691,7 +12662,7 @@ notify_isqueued(dns_zone_t *zone, unsigned int flags, dns_name_t *name, dns_zonemgr_t *zmgr = NULL; isc_result_t result; - ISC_LIST_FOREACH(zone->notifies, n, link) { + ISC_LIST_FOREACH(zone->notifyctx.notifies, n, link) { if (n->request != NULL) { continue; } @@ -12749,11 +12720,11 @@ notify_isself(dns_zone_t *zone, isc_sockaddr_t *dst) { switch (isc_sockaddr_pf(dst)) { case PF_INET: - src = zone->notifysrc4; + src = zone->notifyctx.notifysrc4; isc_sockaddr_any(&any); break; case PF_INET6: - src = zone->notifysrc6; + src = zone->notifyctx.notifysrc6; isc_sockaddr_any6(&any); break; default: @@ -12793,7 +12764,8 @@ notify_destroy(dns_notify_t *notify, bool locked) { } REQUIRE(LOCKED_ZONE(notify->zone)); if (ISC_LINK_LINKED(notify, link)) { - ISC_LIST_UNLINK(notify->zone->notifies, notify, link); + ISC_LIST_UNLINK(notify->zone->notifyctx.notifies, + notify, link); } if (!locked) { UNLOCK_ZONE(notify->zone); @@ -12824,27 +12796,6 @@ notify_destroy(dns_notify_t *notify, bool locked) { isc_mem_detach(&mctx); } -static isc_result_t -notify_create(isc_mem_t *mctx, unsigned int flags, dns_notify_t **notifyp) { - dns_notify_t *notify; - - REQUIRE(notifyp != NULL && *notifyp == NULL); - - notify = isc_mem_get(mctx, sizeof(*notify)); - *notify = (dns_notify_t){ - .flags = flags, - }; - - isc_mem_attach(mctx, ¬ify->mctx); - isc_sockaddr_any(¬ify->src); - isc_sockaddr_any(¬ify->dst); - dns_name_init(¬ify->ns); - ISC_LINK_INIT(notify, link); - notify->magic = NOTIFY_MAGIC; - *notifyp = notify; - return ISC_R_SUCCESS; -} - /* * XXXAG should check for DNS_ZONEFLG_EXITING */ @@ -13030,7 +12981,7 @@ notify_send_toaddr(void *arg) { src = notify->src; if (isc_sockaddr_equal(&src, &any)) { - src = notify->zone->notifysrc4; + src = notify->zone->notifyctx.notifysrc4; } } break; @@ -13041,7 +12992,7 @@ notify_send_toaddr(void *arg) { src = notify->src; if (isc_sockaddr_equal(&src, &any)) { - src = notify->zone->notifysrc6; + src = notify->zone->notifyctx.notifysrc6; } } break; @@ -13137,12 +13088,10 @@ notify_send(dns_notify_t *notify) { } newnotify = NULL; flags = notify->flags & DNS_NOTIFY_NOSOA; - result = notify_create(notify->mctx, flags, &newnotify); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } + dns_notify_create(notify->mctx, flags, &newnotify); zone_iattach(notify->zone, &newnotify->zone); - ISC_LIST_APPEND(newnotify->zone->notifies, newnotify, link); + ISC_LIST_APPEND(newnotify->zone->notifyctx.notifies, newnotify, + link); newnotify->dst = dst; if (isc_sockaddr_pf(&dst) == AF_INET6) { isc_sockaddr_any6(&newnotify->src); @@ -13218,7 +13167,7 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { DNS_ZONEFLG_NEEDSTARTUPNOTIFY | DNS_ZONEFLG_NOTIFYNODEFER | DNS_ZONEFLG_NOTIFYDEFERRED); - notifytype = zone->notifytype; + notifytype = zone->notifyctx.notifytype; DNS_ZONE_TIME_ADD(now, zone->notifydelay, &zone->notifytime); UNLOCK_ZONE(zone); @@ -13346,17 +13295,7 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { goto next; } - result = notify_create(zone->mctx, flags, ¬ify); - if (result != ISC_R_SUCCESS) { - if (key != NULL) { - dns_tsigkey_detach(&key); - } - if (transport != NULL) { - dns_transport_detach(&transport); - } - goto next; - } - + dns_notify_create(zone->mctx, flags, ¬ify); zone_iattach(zone, ¬ify->zone); notify->src = src; notify->dst = dst; @@ -13374,7 +13313,7 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { transport = NULL; } - ISC_LIST_APPEND(zone->notifies, notify, link); + ISC_LIST_APPEND(zone->notifyctx.notifies, notify, link); result = notify_send_queue(notify, startup); if (result != ISC_R_SUCCESS) { notify_destroy(notify, true); @@ -13437,14 +13376,11 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { if (isqueued) { continue; } - result = notify_create(zone->mctx, flags, ¬ify); - if (result != ISC_R_SUCCESS) { - continue; - } + dns_notify_create(zone->mctx, flags, ¬ify); dns_zone_iattach(zone, ¬ify->zone); dns_name_dup(&ns.name, zone->mctx, ¬ify->ns); LOCK_ZONE(zone); - ISC_LIST_APPEND(zone->notifies, notify, link); + ISC_LIST_APPEND(zone->notifyctx.notifies, notify, link); UNLOCK_ZONE(zone); notify_find_address(notify); } @@ -15907,14 +15843,15 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, /* * Accept notify requests from non primaries if they are on - * 'zone->notify_acl'. + * 'zone->notifyctx.notify_acl'. */ tsigkey = dns_message_gettsigkey(msg); tsig = dns_tsigkey_identity(tsigkey); if (i >= dns_remote_count(&zone->primaries) && - zone->notify_acl != NULL && - (dns_acl_match(&netaddr, tsig, zone->notify_acl, zone->view->aclenv, - &match, NULL) == ISC_R_SUCCESS) && + zone->notifyctx.notify_acl != NULL && + (dns_acl_match(&netaddr, tsig, zone->notifyctx.notify_acl, + zone->view->aclenv, &match, + NULL) == ISC_R_SUCCESS) && match > 0) { /* Accept notify. */ @@ -15976,7 +15913,7 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, */ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH)) { DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDREFRESH); - zone->notifyfrom = *from; + zone->notifyctx.notifyfrom = *from; UNLOCK_ZONE(zone); if (have_serial) { dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, @@ -16002,7 +15939,7 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO, "notify from %s: no serial", fromtext); } - zone->notifyfrom = *from; + zone->notifyctx.notifyfrom = *from; UNLOCK_ZONE(zone); if (to != NULL) { @@ -16017,10 +15954,10 @@ dns_zone_setnotifyacl(dns_zone_t *zone, dns_acl_t *acl) { REQUIRE(DNS_ZONE_VALID(zone)); LOCK_ZONE(zone); - if (zone->notify_acl != NULL) { - dns_acl_detach(&zone->notify_acl); + if (zone->notifyctx.notify_acl != NULL) { + dns_acl_detach(&zone->notifyctx.notify_acl); } - dns_acl_attach(acl, &zone->notify_acl); + dns_acl_attach(acl, &zone->notifyctx.notify_acl); UNLOCK_ZONE(zone); } @@ -16088,7 +16025,7 @@ dns_acl_t * dns_zone_getnotifyacl(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); - return zone->notify_acl; + return zone->notifyctx.notify_acl; } dns_acl_t * @@ -16153,8 +16090,8 @@ dns_zone_clearnotifyacl(dns_zone_t *zone) { REQUIRE(DNS_ZONE_VALID(zone)); LOCK_ZONE(zone); - if (zone->notify_acl != NULL) { - dns_acl_detach(&zone->notify_acl); + if (zone->notifyctx.notify_acl != NULL) { + dns_acl_detach(&zone->notifyctx.notify_acl); } UNLOCK_ZONE(zone); } From 090a451e66569300280f4b9430ffad0c5c988216 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Fri, 17 Oct 2025 16:14:09 +0200 Subject: [PATCH 3/4] Export zone functions Make some zone functions available that we are going to need in the notify code. --- lib/dns/include/dns/zone.h | 9 +++ lib/dns/zone.c | 138 ++++++++++++++++++++++++--------- lib/dns/zone_p.h | 147 ++++++++++++++++++++++++++++++++++++ tests/dns/nsec3param_test.c | 1 + tests/dns/sigs_test.c | 1 + tests/dns/skr_test.c | 1 + 6 files changed, 260 insertions(+), 37 deletions(-) diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 7a7a8325cf..acde98421b 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -280,6 +280,15 @@ dns_zone_getorigin(dns_zone_t *zone); *\li 'zone' to be a valid zone. */ +dns_rdataclass_t +dns_zone_getrdclass(dns_zone_t *zone); +/*%< + * Returns the value of the rdclass. + * + * Require: + *\li 'zone' to be a valid zone. + */ + void dns_zone_setfile(dns_zone_t *zone, const char *file, const char *initial_file, dns_masterformat_t format, const dns_master_style_t *style); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 918489e4ee..e7ea558681 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -158,10 +158,6 @@ #define DNS_DEFAULT_IDLEOUT 3600 /*%< 1 hour */ #define MAX_XFER_TIME (2 * 3600) /*%< Documented default is 2 hours */ #define RESIGN_DELAY 3600 /*%< 1 hour */ -#define UDP_REQUEST_TIMEOUT 5 /*%< 5 seconds */ -#define UDP_REQUEST_RETRIES 2 -#define TCP_REQUEST_TIMEOUT \ - (UDP_REQUEST_TIMEOUT * (UDP_REQUEST_RETRIES + 1) + 1) #ifndef DNS_MAX_EXPIRE #define DNS_MAX_EXPIRE 14515200 /*%< 24 weeks */ @@ -987,20 +983,6 @@ zone_journal_rollforward(dns_zone_t *zone, dns_db_t *db, bool *needdump, static void setnsec3param(void *arg); -static void -zmgr_tlsctx_attach(dns_zonemgr_t *zmgr, isc_tlsctx_cache_t **ptlsctx_cache); -/*%< - * Attach to TLS client context cache used for zone transfers via - * encrypted transports (e.g. XoT). - * - * The obtained reference needs to be detached by a call to - * 'isc_tlsctx_cache_detach()' when not needed anymore. - * - * Requires: - *\li 'zmgr' is a valid zone manager. - *\li 'ptlsctx_cache' is not 'NULL' and points to 'NULL'. - */ - #define ENTER zone_debuglog(zone, __func__, 1, "enter") static const unsigned int dbargc_default = 1; @@ -6215,15 +6197,6 @@ ISC_REFCOUNT_TRACE_IMPL(dns_zone, zone_destroy); ISC_REFCOUNT_IMPL(dns_zone, zone_destroy); #endif -void -dns_zone_iattach(dns_zone_t *source, dns_zone_t **target) { - REQUIRE(DNS_ZONE_VALID(source)); - - LOCK_ZONE(source); - zone_iattach(source, target); - UNLOCK_ZONE(source); -} - static void zone_iattach(dns_zone_t *source, dns_zone_t **target) { REQUIRE(DNS_ZONE_VALID(source)); @@ -6235,6 +6208,20 @@ zone_iattach(dns_zone_t *source, dns_zone_t **target) { *target = source; } +void +dns__zone_iattach_locked(dns_zone_t *source, dns_zone_t **target) { + zone_iattach(source, target); +} + +void +dns_zone_iattach(dns_zone_t *source, dns_zone_t **target) { + REQUIRE(DNS_ZONE_VALID(source)); + + LOCK_ZONE(source); + zone_iattach(source, target); + UNLOCK_ZONE(source); +} + static void zone_idetach(dns_zone_t **zonep) { dns_zone_t *zone; @@ -6253,6 +6240,11 @@ zone_idetach(dns_zone_t **zonep) { 0); } +void +dns__zone_idetach_locked(dns_zone_t **zonep) { + zone_idetach(zonep); +} + void dns_zone_idetach(dns_zone_t **zonep) { dns_zone_t *zone; @@ -12770,11 +12762,7 @@ notify_destroy(dns_notify_t *notify, bool locked) { if (!locked) { UNLOCK_ZONE(notify->zone); } - if (locked) { - zone_idetach(¬ify->zone); - } else { - dns_zone_idetach(¬ify->zone); - } + dns_zone_idetach(¬ify->zone, locked); } if (notify->find != NULL) { dns_adb_destroyfind(¬ify->find); @@ -13006,7 +12994,7 @@ again: options |= DNS_REQUESTOPT_TCP; } - zmgr_tlsctx_attach(notify->zone->zmgr, &zmgr_tlsctx_cache); + dns_zonemgr_tlsctx_attach(notify->zone->zmgr, &zmgr_tlsctx_cache); const unsigned int connect_timeout = isc_nm_getinitialtimeout() / MS_PER_SEC; @@ -16514,6 +16502,20 @@ dns_zone_getorigin(dns_zone_t *zone) { return &zone->origin; } +dns_rdataclass_t +dns_zone_getrdclass(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + + return zone->rdclass; +} + +dns_notifyctx_t * +dns__zone_getnotifyctx(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + + return &zone->notifyctx; +} + void dns_zone_setidlein(dns_zone_t *zone, uint32_t idlein) { REQUIRE(DNS_ZONE_VALID(zone)); @@ -16545,6 +16547,43 @@ dns_zone_getidleout(dns_zone_t *zone) { return zone->idleout; } +void +dns__zone_stats_increment(dns_zone_t *zone, isc_statscounter_t counter) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(LOCKED_ZONE(zone)); + inc_stats(zone, counter); +} + +void +dns__zone_lock(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + LOCK_ZONE(zone); +} + +void +dns__zone_unlock(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + UNLOCK_ZONE(zone); +} + +bool +dns__zone_locked(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return LOCKED_ZONE(zone); +} + +bool +dns__zone_loaded(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED) != 0; +} + +bool +dns__zone_exiting(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) != 0; +} + static void notify_done(void *arg) { dns_request_t *request = (dns_request_t *)arg; @@ -18889,7 +18928,7 @@ got_transfer_quota(void *arg) { INSIST(isc_sockaddr_pf(&primaryaddr) == isc_sockaddr_pf(&sourceaddr)); - zmgr_tlsctx_attach(zone->zmgr, &zmgr_tlsctx_cache); + dns__zonemgr_tlsctx_attach(zone->zmgr, &zmgr_tlsctx_cache); dns_xfrin_create(zone, xfrtype, ixfr_maxdiffs, &primaryaddr, &sourceaddr, zone->tsigkey, soa_transport_type, @@ -19033,7 +19072,7 @@ next: } } - zmgr_tlsctx_attach(zone->zmgr, &zmgr_tlsctx_cache); + dns__zonemgr_tlsctx_attach(zone->zmgr, &zmgr_tlsctx_cache); const unsigned int connect_timeout = isc_nm_getprimariestimeout() / MS_PER_SEC; result = dns_request_createraw( @@ -19898,6 +19937,13 @@ dns_zonemgr_getnotifyrate(dns_zonemgr_t *zmgr) { return zmgr->notifyrate; } +void +dns__zonemgr_getnotifyrl(dns_zonemgr_t *zmgr, isc_ratelimiter_t **prl) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + *prl = zmgr->notifyrl; +} + unsigned int dns_zonemgr_getstartupnotifyrate(dns_zonemgr_t *zmgr) { REQUIRE(DNS_ZONEMGR_VALID(zmgr)); @@ -19905,6 +19951,13 @@ dns_zonemgr_getstartupnotifyrate(dns_zonemgr_t *zmgr) { return zmgr->startupnotifyrate; } +void +dns__zonemgr_getstartupnotifyrl(dns_zonemgr_t *zmgr, isc_ratelimiter_t **prl) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + *prl = zmgr->startupnotifyrl; +} + unsigned int dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr) { REQUIRE(DNS_ZONEMGR_VALID(zmgr)); @@ -20320,6 +20373,16 @@ dns_zone_setisself(dns_zone_t *zone, dns_isselffunc_t isself, void *arg) { UNLOCK_ZONE(zone); } +void +dns__zone_getisself(dns_zone_t *zone, dns_isselffunc_t *isself, void **arg) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(isself != NULL); + REQUIRE(arg != NULL && *arg == NULL); + + *isself = zone->isself; + *arg = zone->isselfarg; +} + void dns_zone_setnotifydefer(dns_zone_t *zone, uint32_t defer) { REQUIRE(DNS_ZONE_VALID(zone)); @@ -24677,8 +24740,9 @@ dns_zonemgr_set_tlsctx_cache(dns_zonemgr_t *zmgr, RWUNLOCK(&zmgr->tlsctx_cache_rwlock, isc_rwlocktype_write); } -static void -zmgr_tlsctx_attach(dns_zonemgr_t *zmgr, isc_tlsctx_cache_t **ptlsctx_cache) { +void +dns__zonemgr_tlsctx_attach(dns_zonemgr_t *zmgr, + isc_tlsctx_cache_t **ptlsctx_cache) { REQUIRE(DNS_ZONEMGR_VALID(zmgr)); REQUIRE(ptlsctx_cache != NULL && *ptlsctx_cache == NULL); diff --git a/lib/dns/zone_p.h b/lib/dns/zone_p.h index 3cd21982bc..aefa74ea3b 100644 --- a/lib/dns/zone_p.h +++ b/lib/dns/zone_p.h @@ -22,6 +22,11 @@ * associated unit tests. */ +#define UDP_REQUEST_TIMEOUT 5 /*%< 5 seconds */ +#define UDP_REQUEST_RETRIES 2 +#define TCP_REQUEST_TIMEOUT \ + (UDP_REQUEST_TIMEOUT * (UDP_REQUEST_RETRIES + 1) + 1) + typedef struct { dns_diff_t *diff; bool offline; @@ -38,3 +43,145 @@ isc_result_t dns__zone_lookup_nsec3param(dns_zone_t *zone, dns_rdata_nsec3param_t *lookup, dns_rdata_nsec3param_t *param, unsigned char saltbuf[255], bool resalt); + +void +dns__zone_lock(dns_zone_t *zone); +/*%< + * Locks the zone. + * + * Requires: + *\li 'zone' to be a valid zone. + */ + +void +dns__zone_unlock(dns_zone_t *zone); +/*%< + * Unlocks the zone. + * + * Requires: + *\li 'zone' to be a valid zone. + */ + +bool +dns__zone_locked(dns_zone_t *zone); +/*%< + * Checks if the zone is locked. + * + * Requires: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li true if the zone is locked, false otherwise. + */ + +bool +dns__zone_loaded(dns_zone_t *zone); +/*%< + * Checks if the zone is loaded. + * + * Requires: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li true if the zone is loaded, false otherwise. + */ + +bool +dns__zone_exiting(dns_zone_t *zone); +/*%< + * Checks if the zone is exiting. + * + * Requires: + *\li 'zone' to be a valid zone. + * + * Returns: + *\li true if the zone is exiting, false otherwise. + */ + +void +dns__zone_stats_increment(dns_zone_t *zone, isc_statscounter_t counter); +/*% + * Increment resolver-related statistics counters + * + * Requires: + *\li 'zone' to be a valid zone, and locked. + */ + +dns_notifyctx_t * +dns__zone_getnotifyctx(dns_zone_t *zone); +/*%< + * Returns the notify context. + * + * Require: + *\li 'zone' to be a valid zone. + */ + +void +dns__zonemgr_getnotifyrl(dns_zonemgr_t *zmgr, isc_ratelimiter_t **prl); +/*%< + * Get the NOTIFY requests rate limiter + * + * Requires: + *\li 'zmgr' to be a valid zone manager + */ + +void +dns__zonemgr_getstartupnotifyrl(dns_zonemgr_t *zmgr, isc_ratelimiter_t **prl); +/*%< + * Get the startup NOTIFY requests rate limiter + * + * Requires: + *\li 'zmgr' to be a valid zone manager + */ + +void +dns__zonemgr_tlsctx_attach(dns_zonemgr_t *zmgr, + isc_tlsctx_cache_t **ptlsctx_cache); +/*%< + * Attach to TLS client context cache used for zone transfers via + * encrypted transports (e.g. XoT). + * + * The obtained reference needs to be detached by a call to + * 'isc_tlsctx_cache_detach()' when not needed anymore. + * + * Requires: + *\li 'zmgr' is a valid zone manager. + *\li 'ptlsctx_cache' is not 'NULL' and points to 'NULL'. + */ + +void +dns__zone_getisself(dns_zone_t *zone, dns_isselffunc_t *isself, void **arg); +/*%< + * Returns the isself callback function and argument. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'isself' is not NULL. + *\li 'arg' is not NULL and '*arg' is NULL. + */ + +void +dns__zone_iattach_locked(dns_zone_t *source, dns_zone_t **target); +/*%< + * Attach '*target' to 'source' incrementing its internal + * reference count. This is intended for use by operations + * such as zone transfers that need to prevent the zone + * object from being freed but not from shutting down. + * + * Require: + *\li The caller is running in the context of the zone's loop. + *\li 'zone' to be a valid zone, already locked. + *\li 'target' to be non NULL and '*target' to be NULL. + */ + +void +dns__zone_idetach_locked(dns_zone_t **zonep); +/*%< + * Detach from a zone decrementing its internal reference count. + * If there are no more internal or external references to the + * zone, it will be freed. + * + * Require: + *\li The caller is running in the context of the zone's loop. + *\li 'zonep' to point to a valid zone, already locked. + */ diff --git a/tests/dns/nsec3param_test.c b/tests/dns/nsec3param_test.c index ec194f297d..b028f6a4d5 100644 --- a/tests/dns/nsec3param_test.c +++ b/tests/dns/nsec3param_test.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include diff --git a/tests/dns/sigs_test.c b/tests/dns/sigs_test.c index 41faca7d76..040ca26abd 100644 --- a/tests/dns/sigs_test.c +++ b/tests/dns/sigs_test.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include diff --git a/tests/dns/skr_test.c b/tests/dns/skr_test.c index ec41f3b3dd..eb2abd9b74 100644 --- a/tests/dns/skr_test.c +++ b/tests/dns/skr_test.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "zone_p.h" From 680becfb33ea888d08d1e9fa8c1e42c22ecbe343 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Fri, 24 Oct 2025 14:21:25 +0200 Subject: [PATCH 4/4] Move notify functions to notify source files Move dns_notify_destroy, dns_notify_log, dns_notify_cancel, dns_notify_queue, dns_notify_isqueued, dns_notify_find_address, and notify related static functions over to the notify source files. --- lib/dns/include/dns/notify.h | 66 ++++ lib/dns/notify.c | 727 +++++++++++++++++++++++++++++++++++ lib/dns/zone.c | 718 +--------------------------------- 3 files changed, 811 insertions(+), 700 deletions(-) diff --git a/lib/dns/include/dns/notify.h b/lib/dns/include/dns/notify.h index fd62f527fe..2db6028fad 100644 --- a/lib/dns/include/dns/notify.h +++ b/lib/dns/include/dns/notify.h @@ -72,3 +72,69 @@ dns_notify_create(isc_mem_t *mctx, unsigned int flags, dns_notify_t **notifyp); * 'mctx' is not NULL. * 'notifyp' is not NULL and '*notifyp' is NULL. */ + +void +dns_notify_destroy(dns_notify_t *notify, bool zone_locked); +/*%< + * Destroy a notify structure. If 'zone_locked' is true, the attached + * zone is already locked. + * + * Requires: + * 'notify' is a valid notify. + */ + +bool +dns_notify_isqueued(dns_notifyctx_t *nctx, unsigned int flags, dns_name_t *name, + isc_sockaddr_t *addr, dns_tsigkey_t *key, + dns_transport_t *transport); +/*%< + * Check if we already have a notify queued matching name, destination + * address, TSIG key, and transport. Will requeue on the normal notify + * ratelimiter if the notify was enqueued on the startup ratelimiter and + * this is not a startup notify. + * + * Requires: + * 'nctx' is not NULL + * + * Returns: + * true if the notify matching the parameters is already enqueued + * false otherwise + */ + +isc_result_t +dns_notify_queue(dns_notify_t *notify, bool startup); +/*%< + * Queue notify. + * + * Requires: + * 'notify' is a valid notify. + */ + +isc_result_t +dns_notify_dequeue(dns_notify_t *notify, bool startup); +/*%< + * Dequeue notify. + * + * Requires: + * 'notify' is a valid notify. + */ + +void +dns_notify_find_address(dns_notify_t *notify); +/*%< + * Find corresponding addresses for name server to send notify to. + * Does a lookup into the ADB, then sends a notify to the found + * addresses. + * + * Requires: + * 'notify' is a valid notify. + */ + +void +dns_notify_cancel(dns_notifyctx_t *nctx); +/*%< + * Cancel all notifies. The corresponding zone must be locked. + * + * Requires: + * 'nctx' is not NULL + */ diff --git a/lib/dns/notify.c b/lib/dns/notify.c index 53106a0df8..f4d5cfb670 100644 --- a/lib/dns/notify.c +++ b/lib/dns/notify.c @@ -13,9 +13,31 @@ /*! \file */ +#include +#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include + +#include "zone_p.h" + +static void +notify_log(dns_notify_t *notify, int level, const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + dns_zone_logv(notify->zone, DNS_LOGCATEGORY_NOTIFY, level, NULL, fmt, + ap); + va_end(ap); +} void dns_notify_create(isc_mem_t *mctx, unsigned int flags, dns_notify_t **notifyp) { @@ -36,3 +58,708 @@ dns_notify_create(isc_mem_t *mctx, unsigned int flags, dns_notify_t **notifyp) { notify->magic = NOTIFY_MAGIC; *notifyp = notify; } + +void +dns_notify_destroy(dns_notify_t *notify, bool locked) { + REQUIRE(DNS_NOTIFY_VALID(notify)); + + isc_mem_t *mctx; + dns_notifyctx_t *nctx; + + if (notify->zone != NULL) { + if (!locked) { + dns__zone_lock(notify->zone); + } + REQUIRE(dns__zone_locked(notify->zone)); + nctx = dns__zone_getnotifyctx(notify->zone); + if (ISC_LINK_LINKED(notify, link)) { + ISC_LIST_UNLINK(nctx->notifies, notify, link); + } + if (!locked) { + dns__zone_unlock(notify->zone); + } + if (locked) { + dns__zone_idetach_locked(¬ify->zone); + } else { + dns_zone_idetach(¬ify->zone); + } + } + if (notify->find != NULL) { + dns_adb_destroyfind(¬ify->find); + } + if (notify->request != NULL) { + dns_request_destroy(¬ify->request); + } + if (dns_name_dynamic(¬ify->ns)) { + dns_name_free(¬ify->ns, notify->mctx); + } + if (notify->key != NULL) { + dns_tsigkey_detach(¬ify->key); + } + if (notify->transport != NULL) { + dns_transport_detach(¬ify->transport); + } + mctx = notify->mctx; + isc_mem_put(notify->mctx, notify, sizeof(*notify)); + isc_mem_detach(&mctx); +} + +static void +notify_done(void *arg) { + dns_request_t *request = (dns_request_t *)arg; + dns_notify_t *notify = dns_request_getarg(request); + isc_result_t result; + dns_message_t *message = NULL; + isc_buffer_t buf; + char rcode[128]; + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + + REQUIRE(DNS_NOTIFY_VALID(notify)); + + isc_buffer_init(&buf, rcode, sizeof(rcode)); + isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf)); + /* WMM: This is changing the mctx from zone to notify. */ + dns_message_create(notify->mctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE, + &message); + + result = dns_request_getresult(request); + if (result != ISC_R_SUCCESS) { + goto fail; + } + + result = dns_request_getresponse(request, message, + DNS_MESSAGEPARSE_PRESERVEORDER); + if (result != ISC_R_SUCCESS) { + goto fail; + } + + result = dns_rcode_totext(message->rcode, &buf); + if (result == ISC_R_SUCCESS) { + notify_log(notify, ISC_LOG_DEBUG(3), + "notify response from %s: %.*s", addrbuf, + (int)buf.used, rcode); + } +fail: + dns_message_detach(&message); + + if (result == ISC_R_SUCCESS) { + notify_log(notify, ISC_LOG_DEBUG(1), "notify to %s successful", + addrbuf); + } else if (result == ISC_R_SHUTTINGDOWN || result == ISC_R_CANCELED) { + /* just destroy the notify */ + } else if ((notify->flags & DNS_NOTIFY_TCP) == 0) { + notify_log(notify, ISC_LOG_NOTICE, + "notify to %s failed: %s: retrying over TCP", + addrbuf, isc_result_totext(result)); + notify->flags |= DNS_NOTIFY_TCP; + dns_request_destroy(¬ify->request); + dns_notify_queue(notify, notify->flags & DNS_NOTIFY_STARTUP); + return; + } else if (result == ISC_R_TIMEDOUT) { + notify_log(notify, ISC_LOG_WARNING, + "notify to %s failed: %s: retries exceeded", addrbuf, + isc_result_totext(result)); + } else { + notify_log(notify, ISC_LOG_WARNING, "notify to %s failed: %s", + addrbuf, isc_result_totext(result)); + } + dns_notify_destroy(notify, false); +} + +static isc_result_t +notify_createmessage(dns_notify_t *notify, dns_message_t **messagep) { + dns_db_t *zonedb = NULL; + dns_dbnode_t *node = NULL; + dns_dbversion_t *version = NULL; + dns_message_t *message = NULL; + dns_rdataset_t rdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + + dns_name_t *tempname = NULL; + dns_rdata_t *temprdata = NULL; + dns_rdatalist_t *temprdatalist = NULL; + dns_rdataset_t *temprdataset = NULL; + + isc_result_t result; + isc_region_t r; + isc_buffer_t *b = NULL; + + REQUIRE(DNS_NOTIFY_VALID(notify)); + REQUIRE(messagep != NULL && *messagep == NULL); + + /* WMM: This is changing the mctx from zone to notify. */ + dns_message_create(notify->mctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER, + &message); + + message->opcode = dns_opcode_notify; + message->flags |= DNS_MESSAGEFLAG_AA; + message->rdclass = dns_zone_getrdclass(notify->zone); + + dns_message_gettempname(message, &tempname); + dns_message_gettemprdataset(message, &temprdataset); + + /* + * Make question. + */ + dns_name_clone(dns_zone_getorigin(notify->zone), tempname); + dns_rdataset_makequestion(temprdataset, + dns_zone_getrdclass(notify->zone), + dns_rdatatype_soa); + ISC_LIST_APPEND(tempname->list, temprdataset, link); + dns_message_addname(message, tempname, DNS_SECTION_QUESTION); + tempname = NULL; + temprdataset = NULL; + + if ((notify->flags & DNS_NOTIFY_NOSOA) != 0) { + goto done; + } + + dns_message_gettempname(message, &tempname); + dns_message_gettemprdata(message, &temprdata); + dns_message_gettemprdataset(message, &temprdataset); + dns_message_gettemprdatalist(message, &temprdatalist); + + result = dns_zone_getdb(notify->zone, &zonedb); + INSIST(result == ISC_R_SUCCESS); + INSIST(zonedb != NULL); /* XXXJT: is this assumption correct? */ + + dns_name_clone(dns_zone_getorigin(notify->zone), tempname); + dns_db_currentversion(zonedb, &version); + result = dns_db_findnode(zonedb, tempname, false, &node); + if (result != ISC_R_SUCCESS) { + goto soa_cleanup; + } + + dns_rdataset_init(&rdataset); + result = dns_db_findrdataset(zonedb, node, version, dns_rdatatype_soa, + dns_rdatatype_none, 0, &rdataset, NULL); + if (result != ISC_R_SUCCESS) { + goto soa_cleanup; + } + result = dns_rdataset_first(&rdataset); + if (result != ISC_R_SUCCESS) { + goto soa_cleanup; + } + dns_rdataset_current(&rdataset, &rdata); + dns_rdata_toregion(&rdata, &r); + /* WMM: This is changing the mctx from zone to notify. */ + isc_buffer_allocate(notify->mctx, &b, r.length); + isc_buffer_putmem(b, r.base, r.length); + isc_buffer_usedregion(b, &r); + dns_rdata_fromregion(temprdata, rdata.rdclass, rdata.type, &r); + dns_message_takebuffer(message, &b); + result = dns_rdataset_next(&rdataset); + dns_rdataset_disassociate(&rdataset); + if (result != ISC_R_NOMORE) { + goto soa_cleanup; + } + temprdatalist->rdclass = rdata.rdclass; + temprdatalist->type = rdata.type; + temprdatalist->ttl = rdataset.ttl; + ISC_LIST_APPEND(temprdatalist->rdata, temprdata, link); + + dns_rdatalist_tordataset(temprdatalist, temprdataset); + + ISC_LIST_APPEND(tempname->list, temprdataset, link); + dns_message_addname(message, tempname, DNS_SECTION_ANSWER); + temprdatalist = NULL; + temprdataset = NULL; + temprdata = NULL; + tempname = NULL; + +soa_cleanup: + if (node != NULL) { + dns_db_detachnode(&node); + } + if (version != NULL) { + dns_db_closeversion(zonedb, &version, false); + } + if (zonedb != NULL) { + dns_db_detach(&zonedb); + } + if (tempname != NULL) { + dns_message_puttempname(message, &tempname); + } + if (temprdata != NULL) { + dns_message_puttemprdata(message, &temprdata); + } + if (temprdataset != NULL) { + dns_message_puttemprdataset(message, &temprdataset); + } + if (temprdatalist != NULL) { + dns_message_puttemprdatalist(message, &temprdatalist); + } + +done: + *messagep = message; + return ISC_R_SUCCESS; +} + +static void +notify_send_toaddr(void *arg) { + dns_notify_t *notify = (dns_notify_t *)arg; + dns_notifyctx_t *notifyctx = NULL; + isc_result_t result; + dns_db_t *zonedb = NULL; + dns_view_t *view = NULL; + isc_loop_t *loop = NULL; + dns_zonemgr_t *zmgr = NULL; + dns_message_t *message = NULL; + isc_netaddr_t dstip; + dns_tsigkey_t *key = NULL; + char addrbuf[ISC_SOCKADDR_FORMATSIZE]; + isc_sockaddr_t src; + unsigned int options; + bool have_notifysource = false; + isc_tlsctx_cache_t *zmgr_tlsctx_cache = NULL; + + REQUIRE(DNS_NOTIFY_VALID(notify)); + + dns__zone_lock(notify->zone); + + notifyctx = dns__zone_getnotifyctx(notify->zone); + zmgr = dns_zone_getmgr(notify->zone); + view = dns_zone_getview(notify->zone); + loop = dns_zone_getloop(notify->zone); + result = dns_zone_getdb(notify->zone, &zonedb); + isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf)); + + if (!dns__zone_loaded(notify->zone) || notify->rlevent->canceled || + dns__zone_exiting(notify->zone) || zmgr == NULL || view == NULL || + view->requestmgr == NULL || loop == NULL || zonedb == NULL || + result != ISC_R_SUCCESS) + { + result = ISC_R_CANCELED; + goto cleanup; + } + + /* + * The raw IPv4 address should also exist. Don't send to the + * mapped form. + */ + if (isc_sockaddr_pf(¬ify->dst) == PF_INET6 && + IN6_IS_ADDR_V4MAPPED(¬ify->dst.type.sin6.sin6_addr)) + { + notify_log(notify, ISC_LOG_DEBUG(3), + "notify: ignoring IPv6 mapped IPV4 address: %s", + addrbuf); + result = ISC_R_CANCELED; + goto cleanup; + } + + result = notify_createmessage(notify, &message); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + + if (notify->key != NULL) { + /* Transfer ownership of key */ + key = notify->key; + notify->key = NULL; + } else { + isc_netaddr_fromsockaddr(&dstip, ¬ify->dst); + result = dns_view_getpeertsig(view, &dstip, &key); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { + notify_log(notify, ISC_LOG_ERROR, + "NOTIFY to %s not sent. " + "Peer TSIG key lookup failure.", + addrbuf); + goto cleanup_message; + } + } + + if (key != NULL) { + char namebuf[DNS_NAME_FORMATSIZE]; + + dns_name_format(key->name, namebuf, sizeof(namebuf)); + notify_log(notify, ISC_LOG_INFO, + "sending notify to %s : TSIG (%s)", addrbuf, + namebuf); + } else { + notify_log(notify, ISC_LOG_INFO, "sending notify to %s", + addrbuf); + } + options = 0; + if (view->peers != NULL) { + dns_peer_t *peer = NULL; + bool usetcp = false; + result = dns_peerlist_peerbyaddr(view->peers, &dstip, &peer); + if (result == ISC_R_SUCCESS) { + result = dns_peer_getnotifysource(peer, &src); + if (result == ISC_R_SUCCESS) { + have_notifysource = true; + } + result = dns_peer_getforcetcp(peer, &usetcp); + if (result == ISC_R_SUCCESS && usetcp) { + options |= DNS_FETCHOPT_TCP; + } + } + } + switch (isc_sockaddr_pf(¬ify->dst)) { + case PF_INET: + if (!have_notifysource) { + isc_sockaddr_t any; + isc_sockaddr_any(&any); + + src = notify->src; + if (isc_sockaddr_equal(&src, &any)) { + src = notifyctx->notifysrc4; + } + } + break; + case PF_INET6: + if (!have_notifysource) { + isc_sockaddr_t any; + isc_sockaddr_any6(&any); + + src = notify->src; + if (isc_sockaddr_equal(&src, &any)) { + src = notifyctx->notifysrc6; + } + } + break; + default: + result = ISC_R_NOTIMPLEMENTED; + goto cleanup_key; + } + +again: + if ((notify->flags & DNS_NOTIFY_TCP) != 0) { + options |= DNS_REQUESTOPT_TCP; + } + + dns__zonemgr_tlsctx_attach(zmgr, &zmgr_tlsctx_cache); + + const unsigned int connect_timeout = isc_nm_getinitialtimeout() / + MS_PER_SEC; + result = dns_request_create( + view->requestmgr, message, &src, ¬ify->dst, + notify->transport, zmgr_tlsctx_cache, options, key, + connect_timeout, TCP_REQUEST_TIMEOUT, UDP_REQUEST_TIMEOUT, + UDP_REQUEST_RETRIES, loop, notify_done, notify, + ¬ify->request); + + isc_tlsctx_cache_detach(&zmgr_tlsctx_cache); + + if (result == ISC_R_SUCCESS) { + if (isc_sockaddr_pf(¬ify->dst) == AF_INET) { + dns__zone_stats_increment( + notify->zone, dns_zonestatscounter_notifyoutv4); + } else { + dns__zone_stats_increment( + notify->zone, dns_zonestatscounter_notifyoutv6); + } + } else if (result == ISC_R_SHUTTINGDOWN || result == ISC_R_CANCELED) { + goto cleanup_key; + } else if ((notify->flags & DNS_NOTIFY_TCP) == 0) { + notify_log(notify, ISC_LOG_NOTICE, + "notify to %s failed: %s: retrying over TCP", + addrbuf, isc_result_totext(result)); + notify->flags |= DNS_NOTIFY_TCP; + goto again; + } + +cleanup_key: + if (key != NULL) { + dns_tsigkey_detach(&key); + } +cleanup_message: + dns_message_detach(&message); +cleanup: + dns__zone_unlock(notify->zone); + + if (zonedb != NULL) { + dns_db_detach(&zonedb); + } + + if (notify->rlevent != NULL) { + isc_rlevent_free(¬ify->rlevent); + } + + if (result != ISC_R_SUCCESS) { + isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf)); + notify_log(notify, ISC_LOG_WARNING, "notify to %s failed: %s", + addrbuf, isc_result_totext(result)); + dns_notify_destroy(notify, false); + } +} + +static isc_result_t +notify_queue(dns_notify_t *notify, bool startup, bool dequeue) { + REQUIRE(DNS_NOTIFY_VALID(notify)); + + isc_loop_t *loop = dns_zone_getloop(notify->zone); + dns_zonemgr_t *zmgr = dns_zone_getmgr(notify->zone); + isc_ratelimiter_t *notifyrl = NULL; + isc_ratelimiter_t *startupnotifyrl = NULL; + + INSIST(loop != NULL); + INSIST(zmgr != NULL); + + dns__zonemgr_getnotifyrl(zmgr, ¬ifyrl); + dns__zonemgr_getstartupnotifyrl(zmgr, &startupnotifyrl); + + if (dequeue) { + return isc_ratelimiter_dequeue( + startup ? startupnotifyrl : notifyrl, ¬ify->rlevent); + } + + return isc_ratelimiter_enqueue(startup ? startupnotifyrl : notifyrl, + loop, notify_send_toaddr, notify, + ¬ify->rlevent); +} + +isc_result_t +dns_notify_dequeue(dns_notify_t *notify, bool startup) { + return notify_queue(notify, startup, true); +} + +isc_result_t +dns_notify_queue(dns_notify_t *notify, bool startup) { + return notify_queue(notify, startup, false); +} + +bool +dns_notify_isqueued(dns_notifyctx_t *nctx, unsigned int flags, dns_name_t *name, + isc_sockaddr_t *addr, dns_tsigkey_t *key, + dns_transport_t *transport) { + dns_notify_t *notify = NULL; + isc_result_t result; + + REQUIRE(nctx != NULL); + + ISC_LIST_FOREACH(nctx->notifies, n, link) { + if (n->request != NULL) { + continue; + } + if ((name != NULL && dns_name_dynamic(&n->ns) && + dns_name_equal(name, &n->ns)) || + (addr != NULL && isc_sockaddr_equal(addr, &n->dst) && + n->key == key && n->transport == transport)) + { + notify = n; + goto requeue; + } + } + return false; +requeue: + /* + * If we are enqueued on the startup ratelimiter and this is + * not a startup notify, re-enqueue on the normal notify + * ratelimiter. + */ + if (notify->rlevent != NULL && (flags & DNS_NOTIFY_STARTUP) == 0 && + (notify->flags & DNS_NOTIFY_STARTUP) != 0) + { + result = notify_queue(notify, true, true); + if (result != ISC_R_SUCCESS) { + return true; + } + + notify->flags &= ~DNS_NOTIFY_STARTUP; + result = notify_queue(notify, false, false); + if (result != ISC_R_SUCCESS) { + return false; + } + } + + return true; +} + +static bool +notify_isself(dns_notify_t *notify, isc_sockaddr_t *dst) { + dns_tsigkey_t *key = NULL; + isc_sockaddr_t src; + isc_sockaddr_t any; + bool isself; + isc_netaddr_t dstaddr; + isc_result_t result; + dns_notifyctx_t *notifyctx = NULL; + dns_view_t *view = NULL; + dns_isselffunc_t isselffunc; + void *isselfarg = NULL; + + notifyctx = dns__zone_getnotifyctx(notify->zone); + view = dns_zone_getview(notify->zone); + dns__zone_getisself(notify->zone, &isselffunc, &isselfarg); + if (view == NULL || isselffunc == NULL) { + return false; + } + + switch (isc_sockaddr_pf(dst)) { + case PF_INET: + src = notifyctx->notifysrc4; + isc_sockaddr_any(&any); + break; + case PF_INET6: + src = notifyctx->notifysrc6; + isc_sockaddr_any6(&any); + break; + default: + return false; + } + + /* + * When sending from any the kernel will assign a source address + * that matches the destination address. + */ + if (isc_sockaddr_eqaddr(&any, &src)) { + src = *dst; + } + + isc_netaddr_fromsockaddr(&dstaddr, dst); + result = dns_view_getpeertsig(view, &dstaddr, &key); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { + return false; + } + isself = (isselffunc)(view, key, &src, dst, + dns_zone_getrdclass(notify->zone), isselfarg); + if (key != NULL) { + dns_tsigkey_detach(&key); + } + return isself; +} + +static void +notify_send(dns_notify_t *notify) { + isc_sockaddr_t dst; + isc_result_t result; + dns_notify_t *newnotify = NULL; + dns_notifyctx_t *notifyctx = NULL; + unsigned int flags; + bool startup; + + /* + * Zone lock held by caller. + */ + REQUIRE(DNS_NOTIFY_VALID(notify)); + REQUIRE(dns__zone_locked(notify->zone)); + if (dns__zone_exiting(notify->zone)) { + return; + } + notifyctx = dns__zone_getnotifyctx(notify->zone); + + ISC_LIST_FOREACH(notify->find->list, ai, publink) { + dst = ai->sockaddr; + if (dns_notify_isqueued(notifyctx, notify->flags, NULL, &dst, + NULL, NULL)) + { + continue; + } + if (notify_isself(notify, &dst)) { + continue; + } + newnotify = NULL; + flags = notify->flags & DNS_NOTIFY_NOSOA; + dns_notify_create(notify->mctx, flags, &newnotify); + dns__zone_iattach_locked(notify->zone, &newnotify->zone); + ISC_LIST_APPEND(notifyctx->notifies, newnotify, link); + newnotify->dst = dst; + if (isc_sockaddr_pf(&dst) == AF_INET6) { + isc_sockaddr_any6(&newnotify->src); + } + startup = ((notify->flags & DNS_NOTIFY_STARTUP) != 0); + result = dns_notify_queue(newnotify, startup); + if (result != ISC_R_SUCCESS) { + goto cleanup; + } + newnotify = NULL; + } + +cleanup: + if (newnotify != NULL) { + dns_notify_destroy(newnotify, true); + } +} + +/* + * XXXAG should check for DNS_ZONEFLG_EXITING + */ +static void +process_notify_adb_event(void *arg) { + dns_adbfind_t *find = (dns_adbfind_t *)arg; + dns_notify_t *notify = (dns_notify_t *)find->cbarg; + dns_adbstatus_t astat = find->status; + + REQUIRE(DNS_NOTIFY_VALID(notify)); + REQUIRE(find == notify->find); + + switch (astat) { + case DNS_ADB_MOREADDRESSES: + dns_adb_destroyfind(¬ify->find); + dns_notify_find_address(notify); + return; + + case DNS_ADB_NOMOREADDRESSES: + dns__zone_lock(notify->zone); + notify_send(notify); + dns__zone_unlock(notify->zone); + break; + + default: + break; + } + + dns_notify_destroy(notify, false); +} + +void +dns_notify_find_address(dns_notify_t *notify) { + isc_result_t result; + unsigned int options; + dns_adb_t *adb = NULL; + dns_view_t *view = NULL; + isc_loop_t *loop = NULL; + + REQUIRE(DNS_NOTIFY_VALID(notify)); + + options = DNS_ADBFIND_WANTEVENT; + if (isc_net_probeipv4() != ISC_R_DISABLED) { + options |= DNS_ADBFIND_INET; + } + if (isc_net_probeipv6() != ISC_R_DISABLED) { + options |= DNS_ADBFIND_INET6; + } + + loop = dns_zone_getloop(notify->zone); + view = dns_zone_getview(notify->zone); + dns_view_getadb(view, &adb); + if (loop == NULL || view == NULL || adb == NULL) { + goto destroy; + } + + result = dns_adb_createfind(adb, loop, process_notify_adb_event, notify, + ¬ify->ns, options, 0, view->dstport, 0, + NULL, NULL, ¬ify->find); + dns_adb_detach(&adb); + + /* Something failed? */ + if (result != ISC_R_SUCCESS) { + goto destroy; + } + + /* More addresses pending? */ + if ((notify->find->options & DNS_ADBFIND_WANTEVENT) != 0) { + return; + } + + /* We have as many addresses as we can get. */ + dns__zone_lock(notify->zone); + notify_send(notify); + dns__zone_unlock(notify->zone); +destroy: + dns_notify_destroy(notify, false); +} + +void +dns_notify_cancel(dns_notifyctx_t *nctx) { + ISC_LIST_FOREACH(nctx->notifies, notify, link) { + INSIST(dns__zone_locked(notify->zone)); + if (notify->find != NULL) { + dns_adb_cancelfind(notify->find); + } + if (notify->request != NULL) { + dns_request_cancel(notify->request); + } + } +} diff --git a/lib/dns/zone.c b/lib/dns/zone.c index e7ea558681..280cf2b79f 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -833,9 +833,6 @@ static void zone_debuglog(dns_zone_t *zone, const char *, int debuglevel, const char *msg, ...) ISC_FORMAT_PRINTF(4, 5); static void -notify_log(dns_zone_t *zone, int level, const char *fmt, ...) - ISC_FORMAT_PRINTF(3, 4); -static void dnssec_log(dns_zone_t *zone, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); static void @@ -917,19 +914,6 @@ static void checkds_send_toaddr(void *arg); static void nsfetch_levelup(dns_nsfetch_t *nsfetch); -static void -notify_cancel(dns_zone_t *zone); -static void -notify_find_address(dns_notify_t *notify); -static void -notify_send(dns_notify_t *notify); -static isc_result_t -notify_createmessage(dns_zone_t *zone, unsigned int flags, - dns_message_t **messagep); -static void -notify_done(void *arg); -static void -notify_send_toaddr(void *arg); static isc_result_t zone_dump(dns_zone_t *, bool); static void @@ -12501,24 +12485,6 @@ dns_zone_unload(dns_zone_t *zone) { UNLOCK_ZONE(zone); } -static void -notify_cancel(dns_zone_t *zone) { - /* - * 'zone' locked by caller. - */ - - REQUIRE(LOCKED_ZONE(zone)); - - ISC_LIST_FOREACH(zone->notifyctx.notifies, notify, link) { - if (notify->find != NULL) { - dns_adb_cancelfind(notify->find); - } - if (notify->request != NULL) { - dns_request_cancel(notify->request); - } - } -} - static void checkds_cancel(dns_zone_t *zone) { /* @@ -12646,458 +12612,6 @@ dns_zone_setmaxtypepername(dns_zone_t *zone, uint32_t val) { } } -static bool -notify_isqueued(dns_zone_t *zone, unsigned int flags, dns_name_t *name, - isc_sockaddr_t *addr, dns_tsigkey_t *key, - dns_transport_t *transport) { - dns_notify_t *notify = NULL; - dns_zonemgr_t *zmgr = NULL; - isc_result_t result; - - ISC_LIST_FOREACH(zone->notifyctx.notifies, n, link) { - if (n->request != NULL) { - continue; - } - if ((name != NULL && dns_name_dynamic(&n->ns) && - dns_name_equal(name, &n->ns)) || - (addr != NULL && isc_sockaddr_equal(addr, &n->dst) && - n->key == key && n->transport == transport)) - { - notify = n; - goto requeue; - } - } - return false; - -requeue: - /* - * If we are enqueued on the startup ratelimiter and this is - * not a startup notify, re-enqueue on the normal notify - * ratelimiter. - */ - if (notify->rlevent != NULL && (flags & DNS_NOTIFY_STARTUP) == 0 && - (notify->flags & DNS_NOTIFY_STARTUP) != 0) - { - zmgr = notify->zone->zmgr; - result = isc_ratelimiter_dequeue(zmgr->startupnotifyrl, - ¬ify->rlevent); - if (result != ISC_R_SUCCESS) { - return true; - } - - notify->flags &= ~DNS_NOTIFY_STARTUP; - result = isc_ratelimiter_enqueue( - notify->zone->zmgr->notifyrl, notify->zone->loop, - notify_send_toaddr, notify, ¬ify->rlevent); - if (result != ISC_R_SUCCESS) { - return false; - } - } - - return true; -} - -static bool -notify_isself(dns_zone_t *zone, isc_sockaddr_t *dst) { - dns_tsigkey_t *key = NULL; - isc_sockaddr_t src; - isc_sockaddr_t any; - bool isself; - isc_netaddr_t dstaddr; - isc_result_t result; - - if (zone->view == NULL || zone->isself == NULL) { - return false; - } - - switch (isc_sockaddr_pf(dst)) { - case PF_INET: - src = zone->notifyctx.notifysrc4; - isc_sockaddr_any(&any); - break; - case PF_INET6: - src = zone->notifyctx.notifysrc6; - isc_sockaddr_any6(&any); - break; - default: - return false; - } - - /* - * When sending from any the kernel will assign a source address - * that matches the destination address. - */ - if (isc_sockaddr_eqaddr(&any, &src)) { - src = *dst; - } - - isc_netaddr_fromsockaddr(&dstaddr, dst); - result = dns_view_getpeertsig(zone->view, &dstaddr, &key); - if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { - return false; - } - isself = (zone->isself)(zone->view, key, &src, dst, zone->rdclass, - zone->isselfarg); - if (key != NULL) { - dns_tsigkey_detach(&key); - } - return isself; -} - -static void -notify_destroy(dns_notify_t *notify, bool locked) { - isc_mem_t *mctx; - - REQUIRE(DNS_NOTIFY_VALID(notify)); - - if (notify->zone != NULL) { - if (!locked) { - LOCK_ZONE(notify->zone); - } - REQUIRE(LOCKED_ZONE(notify->zone)); - if (ISC_LINK_LINKED(notify, link)) { - ISC_LIST_UNLINK(notify->zone->notifyctx.notifies, - notify, link); - } - if (!locked) { - UNLOCK_ZONE(notify->zone); - } - dns_zone_idetach(¬ify->zone, locked); - } - if (notify->find != NULL) { - dns_adb_destroyfind(¬ify->find); - } - if (notify->request != NULL) { - dns_request_destroy(¬ify->request); - } - if (dns_name_dynamic(¬ify->ns)) { - dns_name_free(¬ify->ns, notify->mctx); - } - if (notify->key != NULL) { - dns_tsigkey_detach(¬ify->key); - } - if (notify->transport != NULL) { - dns_transport_detach(¬ify->transport); - } - mctx = notify->mctx; - isc_mem_put(notify->mctx, notify, sizeof(*notify)); - isc_mem_detach(&mctx); -} - -/* - * XXXAG should check for DNS_ZONEFLG_EXITING - */ -static void -process_notify_adb_event(void *arg) { - dns_adbfind_t *find = (dns_adbfind_t *)arg; - dns_notify_t *notify = (dns_notify_t *)find->cbarg; - dns_adbstatus_t astat = find->status; - - REQUIRE(DNS_NOTIFY_VALID(notify)); - REQUIRE(find == notify->find); - - switch (astat) { - case DNS_ADB_MOREADDRESSES: - dns_adb_destroyfind(¬ify->find); - notify_find_address(notify); - return; - - case DNS_ADB_NOMOREADDRESSES: - LOCK_ZONE(notify->zone); - notify_send(notify); - UNLOCK_ZONE(notify->zone); - break; - - default: - break; - } - - notify_destroy(notify, false); -} - -static void -notify_find_address(dns_notify_t *notify) { - isc_result_t result; - unsigned int options; - dns_adb_t *adb = NULL; - - REQUIRE(DNS_NOTIFY_VALID(notify)); - - options = DNS_ADBFIND_WANTEVENT; - if (isc_net_probeipv4() != ISC_R_DISABLED) { - options |= DNS_ADBFIND_INET; - } - if (isc_net_probeipv6() != ISC_R_DISABLED) { - options |= DNS_ADBFIND_INET6; - } - - dns_view_getadb(notify->zone->view, &adb); - if (adb == NULL) { - goto destroy; - } - - result = dns_adb_createfind( - adb, notify->zone->loop, process_notify_adb_event, notify, - ¬ify->ns, options, 0, notify->zone->view->dstport, 0, NULL, - NULL, ¬ify->find); - dns_adb_detach(&adb); - - /* Something failed? */ - if (result != ISC_R_SUCCESS) { - goto destroy; - } - - /* More addresses pending? */ - if ((notify->find->options & DNS_ADBFIND_WANTEVENT) != 0) { - return; - } - - /* We have as many addresses as we can get. */ - LOCK_ZONE(notify->zone); - notify_send(notify); - UNLOCK_ZONE(notify->zone); - -destroy: - notify_destroy(notify, false); -} - -static isc_result_t -notify_send_queue(dns_notify_t *notify, bool startup) { - return isc_ratelimiter_enqueue( - startup ? notify->zone->zmgr->startupnotifyrl - : notify->zone->zmgr->notifyrl, - notify->zone->loop, notify_send_toaddr, notify, - ¬ify->rlevent); -} - -static void -notify_send_toaddr(void *arg) { - dns_notify_t *notify = (dns_notify_t *)arg; - isc_result_t result; - dns_message_t *message = NULL; - isc_netaddr_t dstip; - dns_tsigkey_t *key = NULL; - char addrbuf[ISC_SOCKADDR_FORMATSIZE]; - isc_sockaddr_t src; - unsigned int options; - bool have_notifysource = false; - isc_tlsctx_cache_t *zmgr_tlsctx_cache = NULL; - - REQUIRE(DNS_NOTIFY_VALID(notify)); - - LOCK_ZONE(notify->zone); - - isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf)); - - if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_LOADED) == 0 || - notify->rlevent->canceled || - DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_EXITING) || - notify->zone->view->requestmgr == NULL || notify->zone->db == NULL) - { - result = ISC_R_CANCELED; - goto cleanup; - } - - /* - * The raw IPv4 address should also exist. Don't send to the - * mapped form. - */ - if (isc_sockaddr_pf(¬ify->dst) == PF_INET6 && - IN6_IS_ADDR_V4MAPPED(¬ify->dst.type.sin6.sin6_addr)) - { - notify_log(notify->zone, ISC_LOG_DEBUG(3), - "notify: ignoring IPv6 mapped IPV4 address: %s", - addrbuf); - result = ISC_R_CANCELED; - goto cleanup; - } - - result = notify_createmessage(notify->zone, notify->flags, &message); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - - if (notify->key != NULL) { - /* Transfer ownership of key */ - key = notify->key; - notify->key = NULL; - } else { - isc_netaddr_fromsockaddr(&dstip, ¬ify->dst); - result = dns_view_getpeertsig(notify->zone->view, &dstip, &key); - if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { - notify_log(notify->zone, ISC_LOG_ERROR, - "NOTIFY to %s not sent. " - "Peer TSIG key lookup failure.", - addrbuf); - goto cleanup_message; - } - } - - if (key != NULL) { - char namebuf[DNS_NAME_FORMATSIZE]; - - dns_name_format(key->name, namebuf, sizeof(namebuf)); - notify_log(notify->zone, ISC_LOG_INFO, - "sending notify to %s : TSIG (%s)", addrbuf, - namebuf); - } else { - notify_log(notify->zone, ISC_LOG_INFO, "sending notify to %s", - addrbuf); - } - options = 0; - if (notify->zone->view->peers != NULL) { - dns_peer_t *peer = NULL; - bool usetcp = false; - result = dns_peerlist_peerbyaddr(notify->zone->view->peers, - &dstip, &peer); - if (result == ISC_R_SUCCESS) { - result = dns_peer_getnotifysource(peer, &src); - if (result == ISC_R_SUCCESS) { - have_notifysource = true; - } - result = dns_peer_getforcetcp(peer, &usetcp); - if (result == ISC_R_SUCCESS && usetcp) { - options |= DNS_FETCHOPT_TCP; - } - } - } - switch (isc_sockaddr_pf(¬ify->dst)) { - case PF_INET: - if (!have_notifysource) { - isc_sockaddr_t any; - isc_sockaddr_any(&any); - - src = notify->src; - if (isc_sockaddr_equal(&src, &any)) { - src = notify->zone->notifyctx.notifysrc4; - } - } - break; - case PF_INET6: - if (!have_notifysource) { - isc_sockaddr_t any; - isc_sockaddr_any6(&any); - - src = notify->src; - if (isc_sockaddr_equal(&src, &any)) { - src = notify->zone->notifyctx.notifysrc6; - } - } - break; - default: - result = ISC_R_NOTIMPLEMENTED; - goto cleanup_key; - } - -again: - if ((notify->flags & DNS_NOTIFY_TCP) != 0) { - options |= DNS_REQUESTOPT_TCP; - } - - dns_zonemgr_tlsctx_attach(notify->zone->zmgr, &zmgr_tlsctx_cache); - - const unsigned int connect_timeout = isc_nm_getinitialtimeout() / - MS_PER_SEC; - result = dns_request_create( - notify->zone->view->requestmgr, message, &src, ¬ify->dst, - notify->transport, zmgr_tlsctx_cache, options, key, - connect_timeout, TCP_REQUEST_TIMEOUT, UDP_REQUEST_TIMEOUT, - UDP_REQUEST_RETRIES, notify->zone->loop, notify_done, notify, - ¬ify->request); - - isc_tlsctx_cache_detach(&zmgr_tlsctx_cache); - - if (result == ISC_R_SUCCESS) { - if (isc_sockaddr_pf(¬ify->dst) == AF_INET) { - inc_stats(notify->zone, - dns_zonestatscounter_notifyoutv4); - } else { - inc_stats(notify->zone, - dns_zonestatscounter_notifyoutv6); - } - } else if (result == ISC_R_SHUTTINGDOWN || result == ISC_R_CANCELED) { - goto cleanup_key; - } else if ((notify->flags & DNS_NOTIFY_TCP) == 0) { - notify_log(notify->zone, ISC_LOG_NOTICE, - "notify to %s failed: %s: retrying over TCP", - addrbuf, isc_result_totext(result)); - notify->flags |= DNS_NOTIFY_TCP; - goto again; - } - -cleanup_key: - if (key != NULL) { - dns_tsigkey_detach(&key); - } -cleanup_message: - dns_message_detach(&message); -cleanup: - UNLOCK_ZONE(notify->zone); - if (notify->rlevent != NULL) { - isc_rlevent_free(¬ify->rlevent); - } - - if (result != ISC_R_SUCCESS) { - isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf)); - notify_log(notify->zone, ISC_LOG_WARNING, - "notify to %s failed: %s", addrbuf, - isc_result_totext(result)); - notify_destroy(notify, false); - } -} - -static void -notify_send(dns_notify_t *notify) { - isc_sockaddr_t dst; - isc_result_t result; - dns_notify_t *newnotify = NULL; - unsigned int flags; - bool startup; - - /* - * Zone lock held by caller. - */ - REQUIRE(DNS_NOTIFY_VALID(notify)); - REQUIRE(LOCKED_ZONE(notify->zone)); - - if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_EXITING)) { - return; - } - - ISC_LIST_FOREACH(notify->find->list, ai, publink) { - dst = ai->sockaddr; - if (notify_isqueued(notify->zone, notify->flags, NULL, &dst, - NULL, NULL)) - { - continue; - } - if (notify_isself(notify->zone, &dst)) { - continue; - } - newnotify = NULL; - flags = notify->flags & DNS_NOTIFY_NOSOA; - dns_notify_create(notify->mctx, flags, &newnotify); - zone_iattach(notify->zone, &newnotify->zone); - ISC_LIST_APPEND(newnotify->zone->notifyctx.notifies, newnotify, - link); - newnotify->dst = dst; - if (isc_sockaddr_pf(&dst) == AF_INET6) { - isc_sockaddr_any6(&newnotify->src); - } - startup = ((notify->flags & DNS_NOTIFY_STARTUP) != 0); - result = notify_send_queue(newnotify, startup); - if (result != ISC_R_SUCCESS) { - goto cleanup; - } - newnotify = NULL; - } - -cleanup: - if (newnotify != NULL) { - notify_destroy(newnotify, true); - } -} - void dns_zone_notify(dns_zone_t *zone, bool nodefer) { isc_time_t now; @@ -13248,8 +12762,9 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { tlsname, &transport); if (result == ISC_R_SUCCESS) { - notify_log( - zone, ISC_LOG_INFO, + dns_zone_logc( + zone, DNS_LOGCATEGORY_NOTIFY, + ISC_LOG_INFO, "got TLS configuration for a notify"); } else { dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, @@ -13273,7 +12788,9 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { goto next; } - if (notify_isqueued(zone, flags, NULL, &dst, key, transport)) { + if (dns_notify_isqueued(&zone->notifyctx, flags, NULL, &dst, + key, transport)) + { if (key != NULL) { dns_tsigkey_detach(&key); } @@ -13302,13 +12819,14 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { } ISC_LIST_APPEND(zone->notifyctx.notifies, notify, link); - result = notify_send_queue(notify, startup); + result = dns_notify_queue(notify, startup); if (result != ISC_R_SUCCESS) { - notify_destroy(notify, true); + dns_notify_destroy(notify, true); } if (!loggednotify) { - notify_log(zone, ISC_LOG_INFO, - "sending notifies (serial %u)", serial); + dns_zone_logc(zone, DNS_LOGCATEGORY_NOTIFY, + ISC_LOG_INFO, + "sending notifies (serial %u)", serial); loggednotify = true; } next: @@ -13352,14 +12870,15 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { } if (!loggednotify) { - notify_log(zone, ISC_LOG_INFO, - "sending notifies (serial %u)", serial); + dns_zone_logc(zone, DNS_LOGCATEGORY_NOTIFY, + ISC_LOG_INFO, + "sending notifies (serial %u)", serial); loggednotify = true; } LOCK_ZONE(zone); - isqueued = notify_isqueued(zone, flags, &ns.name, NULL, NULL, - NULL); + isqueued = dns_notify_isqueued(&zone->notifyctx, flags, + &ns.name, NULL, NULL, NULL); UNLOCK_ZONE(zone); if (isqueued) { continue; @@ -13370,7 +12889,7 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) { LOCK_ZONE(zone); ISC_LIST_APPEND(zone->notifyctx.notifies, notify, link); UNLOCK_ZONE(zone); - notify_find_address(notify); + dns_notify_find_address(notify); } dns_rdataset_disassociate(&nsrdset); @@ -15311,7 +14830,7 @@ zone_shutdown(void *arg) { checkds_cancel(zone); - notify_cancel(zone); + dns_notify_cancel(&zone->notifyctx); forward_cancel(zone); @@ -15596,135 +15115,6 @@ cancel_refresh(dns_zone_t *zone) { zone_settimer(zone, &now); } -static isc_result_t -notify_createmessage(dns_zone_t *zone, unsigned int flags, - dns_message_t **messagep) { - dns_db_t *zonedb = NULL; - dns_dbnode_t *node = NULL; - dns_dbversion_t *version = NULL; - dns_message_t *message = NULL; - dns_rdataset_t rdataset; - dns_rdata_t rdata = DNS_RDATA_INIT; - - dns_name_t *tempname = NULL; - dns_rdata_t *temprdata = NULL; - dns_rdatalist_t *temprdatalist = NULL; - dns_rdataset_t *temprdataset = NULL; - - isc_result_t result; - isc_region_t r; - isc_buffer_t *b = NULL; - - REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(messagep != NULL && *messagep == NULL); - - dns_message_create(zone->mctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER, - &message); - - message->opcode = dns_opcode_notify; - message->flags |= DNS_MESSAGEFLAG_AA; - message->rdclass = zone->rdclass; - - dns_message_gettempname(message, &tempname); - - dns_message_gettemprdataset(message, &temprdataset); - - /* - * Make question. - */ - dns_name_clone(&zone->origin, tempname); - dns_rdataset_makequestion(temprdataset, zone->rdclass, - dns_rdatatype_soa); - ISC_LIST_APPEND(tempname->list, temprdataset, link); - dns_message_addname(message, tempname, DNS_SECTION_QUESTION); - tempname = NULL; - temprdataset = NULL; - - if ((flags & DNS_NOTIFY_NOSOA) != 0) { - goto done; - } - - dns_message_gettempname(message, &tempname); - dns_message_gettemprdata(message, &temprdata); - dns_message_gettemprdataset(message, &temprdataset); - dns_message_gettemprdatalist(message, &temprdatalist); - - ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); - INSIST(zone->db != NULL); /* XXXJT: is this assumption correct? */ - dns_db_attach(zone->db, &zonedb); - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); - - dns_name_clone(&zone->origin, tempname); - dns_db_currentversion(zonedb, &version); - result = dns_db_findnode(zonedb, tempname, false, &node); - if (result != ISC_R_SUCCESS) { - goto soa_cleanup; - } - - dns_rdataset_init(&rdataset); - result = dns_db_findrdataset(zonedb, node, version, dns_rdatatype_soa, - dns_rdatatype_none, 0, &rdataset, NULL); - if (result != ISC_R_SUCCESS) { - goto soa_cleanup; - } - result = dns_rdataset_first(&rdataset); - if (result != ISC_R_SUCCESS) { - goto soa_cleanup; - } - dns_rdataset_current(&rdataset, &rdata); - dns_rdata_toregion(&rdata, &r); - isc_buffer_allocate(zone->mctx, &b, r.length); - isc_buffer_putmem(b, r.base, r.length); - isc_buffer_usedregion(b, &r); - dns_rdata_fromregion(temprdata, rdata.rdclass, rdata.type, &r); - dns_message_takebuffer(message, &b); - result = dns_rdataset_next(&rdataset); - dns_rdataset_disassociate(&rdataset); - if (result != ISC_R_NOMORE) { - goto soa_cleanup; - } - temprdatalist->rdclass = rdata.rdclass; - temprdatalist->type = rdata.type; - temprdatalist->ttl = rdataset.ttl; - ISC_LIST_APPEND(temprdatalist->rdata, temprdata, link); - - dns_rdatalist_tordataset(temprdatalist, temprdataset); - - ISC_LIST_APPEND(tempname->list, temprdataset, link); - dns_message_addname(message, tempname, DNS_SECTION_ANSWER); - temprdatalist = NULL; - temprdataset = NULL; - temprdata = NULL; - tempname = NULL; - -soa_cleanup: - if (node != NULL) { - dns_db_detachnode(&node); - } - if (version != NULL) { - dns_db_closeversion(zonedb, &version, false); - } - if (zonedb != NULL) { - dns_db_detach(&zonedb); - } - if (tempname != NULL) { - dns_message_puttempname(message, &tempname); - } - if (temprdata != NULL) { - dns_message_puttemprdata(message, &temprdata); - } - if (temprdataset != NULL) { - dns_message_puttemprdataset(message, &temprdataset); - } - if (temprdatalist != NULL) { - dns_message_puttemprdatalist(message, &temprdatalist); - } - -done: - *messagep = message; - return ISC_R_SUCCESS; -} - isc_result_t dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, isc_sockaddr_t *to, dns_message_t *msg) { @@ -16329,15 +15719,6 @@ dns_zone_logv(dns_zone_t *zone, isc_logcategory_t category, int level, zstr, zone->strnamerd, message); } -static void -notify_log(dns_zone_t *zone, int level, const char *fmt, ...) { - va_list ap; - - va_start(ap, fmt); - dns_zone_logv(zone, DNS_LOGCATEGORY_NOTIFY, level, NULL, fmt, ap); - va_end(ap); -} - void dns_zone_logc(dns_zone_t *zone, isc_logcategory_t category, int level, const char *fmt, ...) { @@ -16584,69 +15965,6 @@ dns__zone_exiting(dns_zone_t *zone) { return DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) != 0; } -static void -notify_done(void *arg) { - dns_request_t *request = (dns_request_t *)arg; - dns_notify_t *notify = dns_request_getarg(request); - isc_result_t result; - dns_message_t *message = NULL; - isc_buffer_t buf; - char rcode[128]; - char addrbuf[ISC_SOCKADDR_FORMATSIZE]; - - REQUIRE(DNS_NOTIFY_VALID(notify)); - - isc_buffer_init(&buf, rcode, sizeof(rcode)); - isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf)); - dns_message_create(notify->zone->mctx, NULL, NULL, - DNS_MESSAGE_INTENTPARSE, &message); - - result = dns_request_getresult(request); - if (result != ISC_R_SUCCESS) { - goto fail; - } - - result = dns_request_getresponse(request, message, - DNS_MESSAGEPARSE_PRESERVEORDER); - if (result != ISC_R_SUCCESS) { - goto fail; - } - - result = dns_rcode_totext(message->rcode, &buf); - if (result == ISC_R_SUCCESS) { - notify_log(notify->zone, ISC_LOG_DEBUG(3), - "notify response from %s: %.*s", addrbuf, - (int)buf.used, rcode); - } - -fail: - dns_message_detach(&message); - - if (result == ISC_R_SUCCESS) { - notify_log(notify->zone, ISC_LOG_DEBUG(1), - "notify to %s successful", addrbuf); - } else if (result == ISC_R_SHUTTINGDOWN || result == ISC_R_CANCELED) { - /* just destroy the notify */ - } else if ((notify->flags & DNS_NOTIFY_TCP) == 0) { - notify_log(notify->zone, ISC_LOG_NOTICE, - "notify to %s failed: %s: retrying over TCP", - addrbuf, isc_result_totext(result)); - notify->flags |= DNS_NOTIFY_TCP; - dns_request_destroy(¬ify->request); - notify_send_queue(notify, notify->flags & DNS_NOTIFY_STARTUP); - return; - } else if (result == ISC_R_TIMEDOUT) { - notify_log(notify->zone, ISC_LOG_WARNING, - "notify to %s failed: %s: retries exceeded", addrbuf, - isc_result_totext(result)); - } else { - notify_log(notify->zone, ISC_LOG_WARNING, - "notify to %s failed: %s", addrbuf, - isc_result_totext(result)); - } - notify_destroy(notify, false); -} - struct rss { dns_zone_t *zone; dns_db_t *db;