From: Matthijs Mekking Date: Thu, 19 Mar 2026 16:10:18 +0000 (+0100) Subject: Move zonemgr to own source file X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=080e849eaa8ce40f5be462ae8598f14a0dc5303f;p=thirdparty%2Fbind9.git Move zonemgr to own source file In order to make zone.c more readable, we are splitting it up in separate source files. This moves the zonemgr to its own file ("zonemgr.c"). Since this code accesses the zone structure directly, move the 'struct dns_zonemgr' and its prerequisites to "zone_p.h". The helper functions 'forward_cancel()', 'zone_xfrdone()', 'zmgr_start_xfrin_ifquota()', and 'zmgr_resume_xfrs() need to be internally accessible to both source files. Note: This commit does not compile. --- diff --git a/bin/named/server.c b/bin/named/server.c index 03e3dbf5e54..7b676197aa2 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -103,6 +103,7 @@ #include #include #include +#include #include #include diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c index 87b708b5e34..14cde7fe47f 100644 --- a/bin/named/statschannel.c +++ b/bin/named/statschannel.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include diff --git a/bin/tests/system/dyndb/driver/instance.c b/bin/tests/system/dyndb/driver/instance.c index 7c3b842cca3..cf4d075af12 100644 --- a/bin/tests/system/dyndb/driver/instance.c +++ b/bin/tests/system/dyndb/driver/instance.c @@ -45,6 +45,7 @@ #include #include #include +#include #include "db.h" #include "log.h" diff --git a/bin/tests/system/dyndb/driver/zone.c b/bin/tests/system/dyndb/driver/zone.c index 4a7d04d8e5a..37724d44280 100644 --- a/bin/tests/system/dyndb/driver/zone.c +++ b/bin/tests/system/dyndb/driver/zone.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include "instance.h" diff --git a/lib/dns/dyndb.c b/lib/dns/dyndb.c index 1b5337f3ec5..55043ec2ee5 100644 --- a/lib/dns/dyndb.c +++ b/lib/dns/dyndb.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "dyndb_p.h" diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 5e6bfb70ef9..31ec62871fb 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -617,201 +617,6 @@ dns_zone_prepare_shutdown(dns_zone_t *zone); *\li 'zone' to be a valid initialised zone. */ -void -dns_zonemgr_create(isc_mem_t *mctx, dns_zonemgr_t **zmgrp); -/*%< - * Create a zone manager. - * - * Requires: - *\li 'mctx' to be a valid memory context. - *\li 'zmgrp' to point to a NULL pointer. - */ - -isc_result_t -dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep); -/*%< - * Allocate a new zone using a memory context from the - * zone manager's memory context pool. - * - * Require: - *\li 'zmgr' to be a valid zone manager. - *\li 'zonep' != NULL and '*zonep' == NULL. - */ - -isc_result_t -dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone); -/*%< - * Bring the zone under control of a zone manager. - * - * Require: - *\li 'zmgr' to be a valid zone manager. - *\li 'zone' to be a valid zone. - */ - -isc_result_t -dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr); -/*%< - * Force zone maintenance of all loaded zones managed by 'zmgr' - * to take place at the system's earliest convenience. - */ - -void -dns_zonemgr_shutdown(dns_zonemgr_t *zmgr); -/*%< - * Shut down the zone manager. - * - * Requires: - *\li 'zmgr' to be a valid zone manager. - */ - -void -dns_zonemgr_attach(dns_zonemgr_t *source, dns_zonemgr_t **target); -/*%< - * Attach '*target' to 'source' incrementing its external - * reference count. - * - * Require: - *\li 'zone' to be a valid zone. - *\li 'target' to be non NULL and '*target' to be NULL. - */ - -void -dns_zonemgr_detach(dns_zonemgr_t **zmgrp); -/*%< - * Detach from a zone manager. - * - * Requires: - *\li '*zmgrp' is a valid, non-NULL zone manager pointer. - * - * Ensures: - *\li '*zmgrp' is NULL. - */ - -void -dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone); -/*%< - * Release 'zone' from the managed by 'zmgr'. 'zmgr' is implicitly - * detached from 'zone'. - * - * Requires: - *\li 'zmgr' to be a valid zone manager. - *\li 'zone' to be a valid zone. - *\li 'zmgr' == 'zone->zmgr' - * - * Ensures: - *\li 'zone->zmgr' == NULL; - */ - -void -dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, uint32_t value); -/*%< - * Set the maximum number of simultaneous transfers in allowed by - * the zone manager. - * - * Requires: - *\li 'zmgr' to be a valid zone manager. - */ - -uint32_t -dns_zonemgr_gettransfersin(dns_zonemgr_t *zmgr); -/*%< - * Return the maximum number of simultaneous transfers in allowed. - * - * Requires: - *\li 'zmgr' to be a valid zone manager. - */ - -void -dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, uint32_t value); -/*%< - * Set the number of zone transfers allowed per nameserver. - * - * Requires: - *\li 'zmgr' to be a valid zone manager - */ - -uint32_t -dns_zonemgr_gettransfersperns(dns_zonemgr_t *zmgr); -/*%< - * Return the number of transfers allowed per nameserver. - * - * Requires: - *\li 'zmgr' to be a valid zone manager. - */ - -void -dns_zonemgr_setcheckdsrate(dns_zonemgr_t *zmgr, unsigned int value); -/*%< - * Set the number of parental DS queries sent per second. - * - * Requires: - *\li 'zmgr' to be a valid zone manager - */ - -void -dns_zonemgr_setnotifyrate(dns_zonemgr_t *zmgr, unsigned int value); -/*%< - * Set the number of NOTIFY requests sent per second. - * - * Requires: - *\li 'zmgr' to be a valid zone manager - */ - -void -dns_zonemgr_setstartupnotifyrate(dns_zonemgr_t *zmgr, unsigned int value); -/*%< - * Set the number of startup NOTIFY requests sent per second. - * - * Requires: - *\li 'zmgr' to be a valid zone manager - */ - -void -dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value); -/*%< - * Set the number of SOA queries sent per second. - * - * Requires: - *\li 'zmgr' to be a valid zone manager - */ - -unsigned int -dns_zonemgr_getnotifyrate(dns_zonemgr_t *zmgr); -/*%< - * Return the number of NOTIFY requests sent per second. - * - * Requires: - *\li 'zmgr' to be a valid zone manager. - */ - -unsigned int -dns_zonemgr_getstartupnotifyrate(dns_zonemgr_t *zmgr); -/*%< - * Return the number of startup NOTIFY requests sent per second. - * - * Requires: - *\li 'zmgr' to be a valid zone manager. - */ - -unsigned int -dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr); -/*%< - * Return the number of SOA queries sent per second. - * - * Requires: - *\li 'zmgr' to be a valid zone manager. - */ - -unsigned int -dns_zonemgr_getcount(dns_zonemgr_t *zmgr, dns_zonestate_t state); -/*%< - * Returns the number of zones in the specified state. - * - * Requires: - *\li 'zmgr' to be a valid zone manager. - *\li 'state' to be a valid DNS_ZONESTATE_ enum. - */ - isc_result_t dns_zone_getxfr(dns_zone_t *zone, dns_xfrin_t **xfrp, bool *is_firstrefresh, bool *is_running, bool *is_deferred, bool *is_presoa, @@ -836,18 +641,6 @@ dns_zone_getxfr(dns_zone_t *zone, dns_xfrin_t **xfrp, bool *is_firstrefresh, * ISC_R_FAILURE error while trying to get the transfer information */ -void -dns_zonemgr_set_tlsctx_cache(dns_zonemgr_t *zmgr, - isc_tlsctx_cache_t *tlsctx_cache); -/*%< - * Set the TLS client context cache used for zone transfers via - * encrypted transports (e.g. XoT). - * - * Requires: - *\li 'zmgr' is a valid zone manager. - *\li 'tlsctx_cache' is a valid TLS context cache. - */ - void dns_zone_stopxfr(dns_zone_t *zone); /*%< diff --git a/lib/dns/include/dns/zonemgr.h b/lib/dns/include/dns/zonemgr.h new file mode 100644 index 00000000000..0e60410ce0c --- /dev/null +++ b/lib/dns/include/dns/zonemgr.h @@ -0,0 +1,225 @@ +/* + * 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/zonemgr.h */ + +#include + +void +dns_zonemgr_create(isc_mem_t *mctx, dns_zonemgr_t **zmgrp); +/*%< + * Create a zone manager. + * + * Requires: + *\li 'mctx' to be a valid memory context. + *\li 'zmgrp' to point to a NULL pointer. + */ + +isc_result_t +dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep); +/*%< + * Allocate a new zone using a memory context from the + * zone manager's memory context pool. + * + * Require: + *\li 'zmgr' to be a valid zone manager. + *\li 'zonep' != NULL and '*zonep' == NULL. + */ + +isc_result_t +dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone); +/*%< + * Bring the zone under control of a zone manager. + * + * Require: + *\li 'zmgr' to be a valid zone manager. + *\li 'zone' to be a valid zone. + */ + +isc_result_t +dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr); +/*%< + * Force zone maintenance of all loaded zones managed by 'zmgr' + * to take place at the system's earliest convenience. + */ + +void +dns_zonemgr_shutdown(dns_zonemgr_t *zmgr); +/*%< + * Shut down the zone manager. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +void +dns_zonemgr_attach(dns_zonemgr_t *source, dns_zonemgr_t **target); +/*%< + * Attach '*target' to 'source' incrementing its external + * reference count. + * + * Require: + *\li 'zone' to be a valid zone. + *\li 'target' to be non NULL and '*target' to be NULL. + */ + +void +dns_zonemgr_detach(dns_zonemgr_t **zmgrp); +/*%< + * Detach from a zone manager. + * + * Requires: + *\li '*zmgrp' is a valid, non-NULL zone manager pointer. + * + * Ensures: + *\li '*zmgrp' is NULL. + */ + +void +dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone); +/*%< + * Release 'zone' from the managed by 'zmgr'. 'zmgr' is implicitly + * detached from 'zone'. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + *\li 'zone' to be a valid zone. + *\li 'zmgr' == 'zone->zmgr' + * + * Ensures: + *\li 'zone->zmgr' == NULL; + */ + +void +dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, uint32_t value); +/*%< + * Set the maximum number of simultaneous transfers in allowed by + * the zone manager. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +uint32_t +dns_zonemgr_gettransfersin(dns_zonemgr_t *zmgr); +/*%< + * Return the maximum number of simultaneous transfers in allowed. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +void +dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, uint32_t value); +/*%< + * Set the number of zone transfers allowed per nameserver. + * + * Requires: + *\li 'zmgr' to be a valid zone manager + */ + +uint32_t +dns_zonemgr_gettransfersperns(dns_zonemgr_t *zmgr); +/*%< + * Return the number of transfers allowed per nameserver. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +void +dns_zonemgr_setcheckdsrate(dns_zonemgr_t *zmgr, unsigned int value); +/*%< + * Set the number of parental DS queries sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager + */ + +void +dns_zonemgr_setnotifyrate(dns_zonemgr_t *zmgr, unsigned int value); +/*%< + * Set the number of NOTIFY requests sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager + */ + +void +dns_zonemgr_setstartupnotifyrate(dns_zonemgr_t *zmgr, unsigned int value); +/*%< + * Set the number of startup NOTIFY requests sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager + */ + +void +dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value); +/*%< + * Set the number of SOA queries sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager + */ + +unsigned int +dns_zonemgr_getnotifyrate(dns_zonemgr_t *zmgr); +/*%< + * Return the number of NOTIFY requests sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +unsigned int +dns_zonemgr_getstartupnotifyrate(dns_zonemgr_t *zmgr); +/*%< + * Return the number of startup NOTIFY requests sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +unsigned int +dns_zonemgr_getserialqueryrate(dns_zonemgr_t *zmgr); +/*%< + * Return the number of SOA queries sent per second. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + */ + +unsigned int +dns_zonemgr_getcount(dns_zonemgr_t *zmgr, dns_zonestate_t state); +/*%< + * Returns the number of zones in the specified state. + * + * Requires: + *\li 'zmgr' to be a valid zone manager. + *\li 'state' to be a valid DNS_ZONESTATE_ enum. + */ + +void +dns_zonemgr_set_tlsctx_cache(dns_zonemgr_t *zmgr, + isc_tlsctx_cache_t *tlsctx_cache); +/*%< + * Set the TLS client context cache used for zone transfers via + * encrypted transports (e.g. XoT). + * + * Requires: + *\li 'zmgr' is a valid zone manager. + *\li 'tlsctx_cache' is a valid TLS context cache. + */ diff --git a/lib/dns/meson.build b/lib/dns/meson.build index 61b64bbfa44..f95cb7a15ff 100644 --- a/lib/dns/meson.build +++ b/lib/dns/meson.build @@ -169,6 +169,7 @@ dns_srcset.add( 'view.c', 'zone.c', 'zonefetch.c', + 'zonemgr.c', 'zoneproperties.c', 'zoneverify.c', 'zt.c', diff --git a/lib/dns/zone.c b/lib/dns/zone.c index b397a1672fd..a75d79582d7 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -95,6 +95,7 @@ #include #include #include +#include #include #include #include @@ -164,38 +165,6 @@ typedef enum { * load. */ } dns_zoneloadflag_t; -struct dns_zonemgr { - unsigned int magic; - isc_mem_t *mctx; - isc_refcount_t refs; - uint32_t workers; - isc_mem_t **mctxpool; - isc_ratelimiter_t *checkdsrl; - isc_ratelimiter_t *notifyrl; - isc_ratelimiter_t *refreshrl; - isc_ratelimiter_t *startupnotifyrl; - isc_ratelimiter_t *startuprefreshrl; - isc_rwlock_t rwlock; - - /* Locked by rwlock. */ - dns_zonelist_t zones; - dns_zonelist_t waiting_for_xfrin; - dns_zonelist_t xfrin_in_progress; - - /* Configuration data. */ - uint32_t transfersin; - uint32_t transfersperns; - unsigned int checkdsrate; - unsigned int notifyrate; - unsigned int startupnotifyrate; - unsigned int serialqueryrate; - unsigned int startupserialqueryrate; - dns_keystorelist_t *keystores; - - isc_tlsctx_cache_t *tlsctx_cache; - isc_rwlock_t tlsctx_cache_rwlock; -}; - /*% * dns_stub holds state while performing a 'stub' transfer. * 'db' is the zone's 'db' or a new one if this is the initial @@ -286,8 +255,6 @@ static void zone_catz_enable(dns_zone_t *zone, dns_catz_zones_t *catzs); static void zone_catz_disable(dns_zone_t *zone); -static void -zone_xfrdone(dns_zone_t *zone, uint32_t *expireopt, isc_result_t result); static isc_result_t zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime, isc_result_t result); @@ -334,14 +301,6 @@ checkds_send_toaddr(void *arg); static isc_result_t zone_dump(dns_zone_t *, bool); static void -got_transfer_quota(void *arg); -static isc_result_t -zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone); -static void -zmgr_resume_xfrs(dns_zonemgr_t *zmgr, bool multi); -static void -zonemgr_free(dns_zonemgr_t *zmgr); -static void rss_post(void *arg); static isc_result_t @@ -375,8 +334,6 @@ zone_send_securedb(dns_zone_t *zone, dns_db_t *db); static dns_ttl_t zone_nsecttl(dns_zone_t *zone); static void -setrl(isc_ratelimiter_t *rl, unsigned int *rate, unsigned int value); -static void zone_journal_compact(dns_zone_t *zone, dns_db_t *db, uint32_t serial); static isc_result_t zone_journal_rollforward(dns_zone_t *zone, dns_db_t *db, bool *needdump, @@ -10855,7 +10812,7 @@ checkds_cancel(dns_zone_t *zone) { } } -static void +void forward_cancel(dns_zone_t *zone) { /* * 'zone' locked by caller. @@ -15300,7 +15257,7 @@ zone_detachdb(dns_zone_t *zone) { dns_db_detach(&zone->db); } -static void +void zone_xfrdone(dns_zone_t *zone, uint32_t *expireopt, isc_result_t result) { isc_time_t now, expiretime; bool again = false; @@ -15772,221 +15729,6 @@ dns_zone_getrequesttransporttype(dns_zone_t *zone) { return transport_type; } -/* - * This event callback is called when a zone has received - * any necessary zone transfer quota. This is the time - * to go ahead and start the transfer. - */ -static void -got_transfer_quota(void *arg) { - dns_zone_t *zone = (dns_zone_t *)arg; - isc_result_t result = ISC_R_SUCCESS; - dns_peer_t *peer = NULL; - char primary[ISC_SOCKADDR_FORMATSIZE]; - char source[ISC_SOCKADDR_FORMATSIZE]; - dns_rdatatype_t xfrtype; - uint32_t ixfr_maxdiffs = 0; - isc_netaddr_t primaryip; - isc_sockaddr_t primaryaddr; - isc_sockaddr_t sourceaddr; - dns_transport_type_t soa_transport_type = DNS_TRANSPORT_NONE; - const char *soa_before = ""; - bool loaded; - isc_tlsctx_cache_t *zmgr_tlsctx_cache = NULL; - dns_xfrin_t *xfr = NULL; - - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { - zone_xfrdone(zone, NULL, ISC_R_CANCELED); - return; - } - - primaryaddr = dns_remote_curraddr(&zone->primaries); - isc_sockaddr_format(&primaryaddr, primary, sizeof(primary)); - if (dns_unreachcache_find(zone->view->unreachcache, &primaryaddr, - &zone->sourceaddr) == ISC_R_SUCCESS) - { - isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source)); - dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO, - "got_transfer_quota: skipping zone transfer as " - "primary %s (source %s) is unreachable (cached)", - primary, source); - zone_xfrdone(zone, NULL, ISC_R_CANCELED); - return; - } - - isc_netaddr_fromsockaddr(&primaryip, &primaryaddr); - (void)dns_peerlist_peerbyaddr(zone->view->peers, &primaryip, &peer); - - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) { - soa_before = "SOA before "; - } - /* - * Decide whether we should request IXFR or AXFR. - */ - ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); - loaded = (zone->db != NULL); - ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); - - if (!loaded) { - dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_DEBUG(1), - "no database exists yet, requesting AXFR of " - "initial version from %s", - primary); - xfrtype = dns_rdatatype_axfr; - } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) { - dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_DEBUG(1), - "forced reload, requesting AXFR of " - "initial version from %s", - primary); - xfrtype = dns_rdatatype_axfr; - } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOIXFR)) { - dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_DEBUG(1), - "retrying with AXFR from %s due to " - "previous IXFR failure", - primary); - xfrtype = dns_rdatatype_axfr; - LOCK_ZONE(zone); - DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOIXFR); - UNLOCK_ZONE(zone); - } else { - bool use_ixfr = true; - - if (peer != NULL) { - result = dns_peer_getrequestixfr(peer, &use_ixfr); - } - if (peer == NULL || result != ISC_R_SUCCESS) { - use_ixfr = zone->requestixfr; - } - if (peer != NULL) { - result = dns_peer_getrequestixfrmaxdiffs( - peer, &ixfr_maxdiffs); - } - if (peer == NULL || result != ISC_R_SUCCESS) { - ixfr_maxdiffs = zone->requestixfr_maxdiffs; - } - if (!use_ixfr) { - dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, - ISC_LOG_DEBUG(1), - "IXFR disabled, " - "requesting %sAXFR from %s", - soa_before, primary); - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) { - xfrtype = dns_rdatatype_soa; - } else { - xfrtype = dns_rdatatype_axfr; - } - } else { - dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, - ISC_LOG_DEBUG(1), - "requesting IXFR from %s", primary); - xfrtype = dns_rdatatype_ixfr; - } - } - - /* - * Determine if we should attempt to sign the request with TSIG. - */ - result = ISC_R_NOTFOUND; - - /* - * First, look for a tsig key in the primaries statement, then - * try for a server key. - */ - if (dns_remote_keyname(&zone->primaries) != NULL) { - dns_view_t *view = dns_zone_getview(zone); - dns_name_t *keyname = dns_remote_keyname(&zone->primaries); - result = dns_view_gettsig(view, keyname, &zone->tsigkey); - } - if (result != ISC_R_SUCCESS) { - INSIST(zone->tsigkey == NULL); - result = dns_view_getpeertsig(zone->view, &primaryip, - &zone->tsigkey); - } - if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { - dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_ERROR, - "could not get TSIG key for zone transfer: %s", - isc_result_totext(result)); - } - - /* - * Get the TLS transport for the primary, if configured. - */ - if (dns_remote_tlsname(&zone->primaries) != NULL) { - dns_view_t *view = dns_zone_getview(zone); - dns_name_t *tlsname = dns_remote_tlsname(&zone->primaries); - result = dns_view_gettransport(view, DNS_TRANSPORT_TLS, tlsname, - &zone->transport); - if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { - dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, - ISC_LOG_ERROR, - "could not get TLS configuration for " - "zone transfer: %s", - isc_result_totext(result)); - } - } - - LOCK_ZONE(zone); - if (xfrtype != dns_rdatatype_soa) { - /* - * If 'xfrtype' is dns_rdatatype_soa, then the SOA query will be - * performed by xfrin, otherwise, the SOA request performed by - * soa_query() was successful and we should inform the xfrin - * about the transport type used for that query, so that the - * information can be presented in the statistics channel. - */ - soa_transport_type = get_request_transport_type(zone); - } - sourceaddr = zone->sourceaddr; - UNLOCK_ZONE(zone); - - INSIST(isc_sockaddr_pf(&primaryaddr) == isc_sockaddr_pf(&sourceaddr)); - - dns__zonemgr_tlsctx_attach(zone->zmgr, &zmgr_tlsctx_cache); - - dns_xfrin_create(zone, xfrtype, ixfr_maxdiffs, &primaryaddr, - &sourceaddr, zone->tsigkey, soa_transport_type, - zone->transport, zmgr_tlsctx_cache, zone->mctx, &xfr); - INSIST(xfr != NULL); - - isc_tlsctx_cache_detach(&zmgr_tlsctx_cache); - - LOCK_ZONE(zone); - if (zone->xfr != NULL) { - dns_xfrin_detach(&zone->xfr); - } - dns_xfrin_attach(xfr, &zone->xfr); - UNLOCK_ZONE(zone); - - dns_xfrin_detach(&xfr); - - /* - * Any failure in this function is handled like a failed - * zone transfer. This ensures that we get removed from - * zmgr->xfrin_in_progress. - */ - result = dns_xfrin_start(zone->xfr, zone_xfrdone); - if (result != ISC_R_SUCCESS) { - zone_xfrdone(zone, NULL, result); - return; - } - - LOCK_ZONE(zone); - if (xfrtype == dns_rdatatype_axfr) { - if (isc_sockaddr_pf(&primaryaddr) == PF_INET) { - inc_stats(zone, dns_zonestatscounter_axfrreqv4); - } else { - inc_stats(zone, dns_zonestatscounter_axfrreqv6); - } - } else if (xfrtype == dns_rdatatype_ixfr) { - if (isc_sockaddr_pf(&primaryaddr) == PF_INET) { - inc_stats(zone, dns_zonestatscounter_ixfrreqv4); - } else { - inc_stats(zone, dns_zonestatscounter_ixfrreqv6); - } - } - UNLOCK_ZONE(zone); -} - /* * Update forwarding support. */ @@ -16308,10 +16050,6 @@ dns_zone_first(dns_zonemgr_t *zmgr, dns_zone_t **first) { } } -/*** - *** Zone manager. - ***/ - static isc_mutex_t * zone_keymgmt_getlock(dns_zone_t *zone) { uint32_t hash = dns_name_hash(&zone->origin); @@ -16332,401 +16070,6 @@ dns__zone_keymgmt_shutdown(void) { } } -void -dns_zonemgr_create(isc_mem_t *mctx, dns_zonemgr_t **zmgrp) { - dns_zonemgr_t *zmgr = NULL; - isc_loop_t *loop = isc_loop(); - - REQUIRE(mctx != NULL); - REQUIRE(zmgrp != NULL && *zmgrp == NULL); - - zmgr = isc_mem_get(mctx, sizeof(*zmgr)); - - *zmgr = (dns_zonemgr_t){ - .workers = isc_loopmgr_nloops(), - .transfersin = 10, - .transfersperns = 2, - }; - - isc_refcount_init(&zmgr->refs, 1); - isc_mem_attach(mctx, &zmgr->mctx); - - ISC_LIST_INIT(zmgr->zones); - ISC_LIST_INIT(zmgr->waiting_for_xfrin); - ISC_LIST_INIT(zmgr->xfrin_in_progress); - isc_rwlock_init(&zmgr->rwlock); - - isc_ratelimiter_create(loop, &zmgr->checkdsrl); - isc_ratelimiter_create(loop, &zmgr->notifyrl); - isc_ratelimiter_create(loop, &zmgr->refreshrl); - isc_ratelimiter_create(loop, &zmgr->startupnotifyrl); - isc_ratelimiter_create(loop, &zmgr->startuprefreshrl); - - zmgr->mctxpool = isc_mem_cget(zmgr->mctx, zmgr->workers, - sizeof(zmgr->mctxpool[0])); - for (size_t i = 0; i < zmgr->workers; i++) { - isc_mem_create("zonemgr-mctxpool", &zmgr->mctxpool[i]); - } - - /* Default to 20 refresh queries / notifies / checkds per second. */ - setrl(zmgr->checkdsrl, &zmgr->checkdsrate, 20); - setrl(zmgr->notifyrl, &zmgr->notifyrate, 20); - setrl(zmgr->startupnotifyrl, &zmgr->startupnotifyrate, 20); - setrl(zmgr->refreshrl, &zmgr->serialqueryrate, 20); - setrl(zmgr->startuprefreshrl, &zmgr->startupserialqueryrate, 20); - isc_ratelimiter_setpushpop(zmgr->startupnotifyrl, true); - isc_ratelimiter_setpushpop(zmgr->startuprefreshrl, true); - - zmgr->tlsctx_cache = NULL; - isc_rwlock_init(&zmgr->tlsctx_cache_rwlock); - - zmgr->magic = ZONEMGR_MAGIC; - - *zmgrp = zmgr; -} - -isc_result_t -dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep) { - isc_mem_t *mctx = NULL; - dns_zone_t *zone = NULL; - isc_tid_t tid; - - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - REQUIRE(zonep != NULL && *zonep == NULL); - - if (zmgr->mctxpool == NULL) { - return ISC_R_FAILURE; - } - - tid = isc_random_uniform(zmgr->workers); - - mctx = zmgr->mctxpool[tid]; - if (mctx == NULL) { - return ISC_R_FAILURE; - } - - dns_zone_create(&zone, mctx, tid); - - *zonep = zone; - - return ISC_R_SUCCESS; -} - -isc_result_t -dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); - LOCK_ZONE(zone); - REQUIRE(zone->timer == NULL); - REQUIRE(zone->zmgr == NULL); - - isc_loop_t *loop = isc_loop_get(zone->tid); - isc_loop_attach(loop, &zone->loop); - - ISC_LIST_APPEND(zmgr->zones, zone, link); - zone->zmgr = zmgr; - - isc_refcount_increment(&zmgr->refs); - - UNLOCK_ZONE(zone); - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); - return ISC_R_SUCCESS; -} - -void -dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) { - REQUIRE(DNS_ZONE_VALID(zone)); - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - REQUIRE(zone->zmgr == zmgr); - - RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); - LOCK_ZONE(zone); - - ISC_LIST_UNLINK(zmgr->zones, zone, link); - - if (zone->timer != NULL) { - isc_refcount_decrement(&zone->irefs); - isc_timer_destroy(&zone->timer); - } - - isc_loop_detach(&zone->loop); - - /* Detach below, outside of the write lock. */ - zone->zmgr = NULL; - - UNLOCK_ZONE(zone); - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); - - dns_zonemgr_detach(&zmgr); -} - -void -dns_zonemgr_attach(dns_zonemgr_t *source, dns_zonemgr_t **target) { - REQUIRE(DNS_ZONEMGR_VALID(source)); - REQUIRE(target != NULL && *target == NULL); - - isc_refcount_increment(&source->refs); - - *target = source; -} - -void -dns_zonemgr_detach(dns_zonemgr_t **zmgrp) { - dns_zonemgr_t *zmgr; - - REQUIRE(zmgrp != NULL); - zmgr = *zmgrp; - *zmgrp = NULL; - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - if (isc_refcount_decrement(&zmgr->refs) == 1) { - zonemgr_free(zmgr); - } -} - -isc_result_t -dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); - ISC_LIST_FOREACH(zmgr->zones, zone, link) { - isc_time_t now; - - LOCK_ZONE(zone); - now = isc_time_now(); - dns__zone_settimer(zone, &now); - UNLOCK_ZONE(zone); - } - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); - - /* - * Recent configuration changes may have increased the - * amount of available transfers quota. Make sure any - * transfers currently blocked on quota get started if - * possible. - */ - RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); - zmgr_resume_xfrs(zmgr, true); - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); - return ISC_R_SUCCESS; -} - -void -dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - isc_ratelimiter_shutdown(zmgr->checkdsrl); - isc_ratelimiter_shutdown(zmgr->notifyrl); - isc_ratelimiter_shutdown(zmgr->refreshrl); - isc_ratelimiter_shutdown(zmgr->startupnotifyrl); - isc_ratelimiter_shutdown(zmgr->startuprefreshrl); - - for (size_t i = 0; i < zmgr->workers; i++) { - isc_mem_detach(&zmgr->mctxpool[i]); - } - - RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); - ISC_LIST_FOREACH(zmgr->zones, zone, link) { - LOCK_ZONE(zone); - forward_cancel(zone); - UNLOCK_ZONE(zone); - } - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); -} - -static void -zonemgr_free(dns_zonemgr_t *zmgr) { - REQUIRE(ISC_LIST_EMPTY(zmgr->zones)); - - zmgr->magic = 0; - - isc_refcount_destroy(&zmgr->refs); - isc_ratelimiter_detach(&zmgr->checkdsrl); - isc_ratelimiter_detach(&zmgr->notifyrl); - isc_ratelimiter_detach(&zmgr->refreshrl); - isc_ratelimiter_detach(&zmgr->startupnotifyrl); - isc_ratelimiter_detach(&zmgr->startuprefreshrl); - - isc_mem_cput(zmgr->mctx, zmgr->mctxpool, zmgr->workers, - sizeof(zmgr->mctxpool[0])); - - isc_rwlock_destroy(&zmgr->rwlock); - isc_rwlock_destroy(&zmgr->tlsctx_cache_rwlock); - - if (zmgr->tlsctx_cache != NULL) { - isc_tlsctx_cache_detach(&zmgr->tlsctx_cache); - } - isc_mem_putanddetach(&zmgr->mctx, zmgr, sizeof(*zmgr)); -} - -void -dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, uint32_t value) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - zmgr->transfersin = value; -} - -uint32_t -dns_zonemgr_gettransfersin(dns_zonemgr_t *zmgr) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - return zmgr->transfersin; -} - -void -dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, uint32_t value) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - zmgr->transfersperns = value; -} - -uint32_t -dns_zonemgr_gettransfersperns(dns_zonemgr_t *zmgr) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - return zmgr->transfersperns; -} - -/* - * Try to start a new incoming zone transfer to fill a quota - * slot that was just vacated. - * - * Requires: - * The zone manager is locked by the caller. - */ -static void -zmgr_resume_xfrs(dns_zonemgr_t *zmgr, bool multi) { - ISC_LIST_FOREACH(zmgr->waiting_for_xfrin, zone, statelink) { - isc_result_t result; - result = zmgr_start_xfrin_ifquota(zmgr, zone); - if (result == ISC_R_SUCCESS) { - if (multi) { - continue; - } - /* - * We successfully filled the slot. We're done. - */ - break; - } else if (result == ISC_R_QUOTA) { - /* - * Not enough quota. This is probably the per-server - * quota, because we usually get called when a unit of - * global quota has just been freed. Try the next - * zone, it may succeed if it uses another primary. - */ - continue; - } else { - dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, - ISC_LOG_DEBUG(1), - "starting zone transfer: %s", - isc_result_totext(result)); - break; - } - } -} - -/* - * Try to start an incoming zone transfer for 'zone', quota permitting. - * - * Requires: - * The zone manager is locked by the caller. - * - * Returns: - * ISC_R_SUCCESS There was enough quota and we attempted to - * start a transfer. zone_xfrdone() has been or will - * be called. - * ISC_R_QUOTA Not enough quota. - * Others Failure. - */ -static isc_result_t -zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) { - dns_peer_t *peer = NULL; - isc_netaddr_t primaryip; - isc_sockaddr_t curraddr; - uint32_t nxfrsin, nxfrsperns; - uint32_t maxtransfersin, maxtransfersperns; - - /* - * If we are exiting just pretend we got quota so the zone will - * be cleaned up in the zone's loop context. - */ - LOCK_ZONE(zone); - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { - UNLOCK_ZONE(zone); - goto gotquota; - } - - /* - * Find any configured information about the server we'd - * like to transfer this zone from. - */ - curraddr = dns_remote_curraddr(&zone->primaries); - isc_netaddr_fromsockaddr(&primaryip, &curraddr); - (void)dns_peerlist_peerbyaddr(zone->view->peers, &primaryip, &peer); - UNLOCK_ZONE(zone); - - /* - * Determine the total maximum number of simultaneous - * transfers allowed, and the maximum for this specific - * primary. - */ - maxtransfersin = zmgr->transfersin; - maxtransfersperns = zmgr->transfersperns; - if (peer != NULL) { - (void)dns_peer_gettransfers(peer, &maxtransfersperns); - } - - /* - * Count the total number of transfers that are in progress, - * and the number of transfers in progress from this primary. - * We linearly scan a list of all transfers; if this turns - * out to be too slow, we could hash on the primary address. - */ - nxfrsin = nxfrsperns = 0; - ISC_LIST_FOREACH(zmgr->xfrin_in_progress, x, statelink) { - isc_netaddr_t xip; - isc_sockaddr_t xaddr; - - LOCK_ZONE(x); - xaddr = dns_remote_curraddr(&x->primaries); - isc_netaddr_fromsockaddr(&xip, &xaddr); - UNLOCK_ZONE(x); - - nxfrsin++; - if (isc_netaddr_equal(&xip, &primaryip)) { - nxfrsperns++; - } - } - - /* Enforce quota. */ - if (nxfrsin >= maxtransfersin) { - return ISC_R_QUOTA; - } - - if (nxfrsperns >= maxtransfersperns) { - return ISC_R_QUOTA; - } - -gotquota: - /* - * We have sufficient quota. Move the zone to the "xfrin_in_progress" - * list and start the actual transfer asynchronously. - */ - LOCK_ZONE(zone); - INSIST(zone->statelist == &zmgr->waiting_for_xfrin); - ISC_LIST_UNLINK(zmgr->waiting_for_xfrin, zone, statelink); - ISC_LIST_APPEND(zmgr->xfrin_in_progress, zone, statelink); - zone->statelist = &zmgr->xfrin_in_progress; - isc_async_run(zone->loop, got_transfer_quota, zone); - dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO, - "Transfer started."); - UNLOCK_ZONE(zone); - - return ISC_R_SUCCESS; -} - static void zone_saveunique(dns_zone_t *zone, const char *path, const char *templat) { char *buf; @@ -16751,113 +16094,11 @@ cleanup: isc_mem_put(zone->mctx, buf, buflen); } -static void -setrl(isc_ratelimiter_t *rl, unsigned int *rate, unsigned int value) { - isc_interval_t interval; - uint32_t s, ns; - uint32_t pertic; - - if (value == 0) { - value = 1; - } - - if (value == 1) { - s = 1; - ns = 0; - pertic = 1; - } else if (value <= 10) { - s = 0; - ns = 1000000000 / value; - pertic = 1; - } else { - s = 0; - ns = (1000000000 / value) * 10; - pertic = 10; - } - - isc_interval_set(&interval, s, ns); - - isc_ratelimiter_setinterval(rl, &interval); - isc_ratelimiter_setpertic(rl, pertic); - - *rate = value; -} - -void -dns_zonemgr_setcheckdsrate(dns_zonemgr_t *zmgr, unsigned int value) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - setrl(zmgr->checkdsrl, &zmgr->checkdsrate, value); -} - -void -dns_zonemgr_setnotifyrate(dns_zonemgr_t *zmgr, unsigned int value) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - setrl(zmgr->notifyrl, &zmgr->notifyrate, value); -} - -void -dns_zonemgr_setstartupnotifyrate(dns_zonemgr_t *zmgr, unsigned int value) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - setrl(zmgr->startupnotifyrl, &zmgr->startupnotifyrate, value); -} - -void -dns_zonemgr_setkeystores(dns_zonemgr_t *zmgr, dns_keystorelist_t *keystores) { - zmgr->keystores = keystores; -} - dns_keystorelist_t * dns_zone_getkeystores(dns_zone_t *zone) { return zone->zmgr->keystores; } -void -dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) { - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - setrl(zmgr->refreshrl, &zmgr->serialqueryrate, value); - /* XXXMPA separate out once we have the code to support this. */ - setrl(zmgr->startuprefreshrl, &zmgr->startupserialqueryrate, value); -} - -unsigned int -dns_zonemgr_getnotifyrate(dns_zonemgr_t *zmgr) { - REQUIRE(DNS_ZONEMGR_VALID(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)); - - 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)); - - return zmgr->serialqueryrate; -} - void dns_zone_stopxfr(dns_zone_t *zone) { dns_xfrin_t *xfr = NULL; @@ -16980,67 +16221,6 @@ zone_viewname_tostr(dns_zone_t *zone, char *buf, size_t length) { buf[isc_buffer_usedlength(&buffer)] = '\0'; } -unsigned int -dns_zonemgr_getcount(dns_zonemgr_t *zmgr, dns_zonestate_t state) { - unsigned int count = 0; - - REQUIRE(DNS_ZONEMGR_VALID(zmgr)); - - RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); - switch (state) { - case DNS_ZONESTATE_XFERRUNNING: - ISC_LIST_FOREACH(zmgr->xfrin_in_progress, zone, statelink) { - count++; - } - break; - case DNS_ZONESTATE_XFERDEFERRED: - ISC_LIST_FOREACH(zmgr->waiting_for_xfrin, zone, statelink) { - count++; - } - break; - case DNS_ZONESTATE_XFERFIRSTREFRESH: - ISC_LIST_FOREACH(zmgr->zones, zone, link) { - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FIRSTREFRESH)) { - count++; - } - } - break; - case DNS_ZONESTATE_SOAQUERY: - ISC_LIST_FOREACH(zmgr->zones, zone, link) { - if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH)) { - count++; - } - } - break; - case DNS_ZONESTATE_ANY: - ISC_LIST_FOREACH(zmgr->zones, zone, link) { - dns_view_t *view = zone->view; - if (view != NULL && strcmp(view->name, "_bind") == 0) { - continue; - } - count++; - } - break; - case DNS_ZONESTATE_AUTOMATIC: - ISC_LIST_FOREACH(zmgr->zones, zone, link) { - dns_view_t *view = zone->view; - if (view != NULL && strcmp(view->name, "_bind") == 0) { - continue; - } - if (zone->automatic) { - count++; - } - } - break; - default: - UNREACHABLE(); - } - - RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); - - return count; -} - isc_result_t dns_zone_getxfr(dns_zone_t *zone, dns_xfrin_t **xfrp, bool *is_firstrefresh, bool *is_running, bool *is_deferred, bool *is_presoa, diff --git a/lib/dns/zone_p.h b/lib/dns/zone_p.h index 143b65a7b1b..65583aef946 100644 --- a/lib/dns/zone_p.h +++ b/lib/dns/zone_p.h @@ -296,6 +296,41 @@ typedef struct zone_settimer { isc_time_t now; } zone_settimer_t; +/*% + * Zone manager structure. + */ +struct dns_zonemgr { + unsigned int magic; + isc_mem_t *mctx; + isc_refcount_t refs; + uint32_t workers; + isc_mem_t **mctxpool; + isc_ratelimiter_t *checkdsrl; + isc_ratelimiter_t *notifyrl; + isc_ratelimiter_t *refreshrl; + isc_ratelimiter_t *startupnotifyrl; + isc_ratelimiter_t *startuprefreshrl; + isc_rwlock_t rwlock; + + /* Locked by rwlock. */ + dns_zonelist_t zones; + dns_zonelist_t waiting_for_xfrin; + dns_zonelist_t xfrin_in_progress; + + /* Configuration data. */ + uint32_t transfersin; + uint32_t transfersperns; + unsigned int checkdsrate; + unsigned int notifyrate; + unsigned int startupnotifyrate; + unsigned int serialqueryrate; + unsigned int startupserialqueryrate; + dns_keystorelist_t *keystores; + + isc_tlsctx_cache_t *tlsctx_cache; + isc_rwlock_t tlsctx_cache_rwlock; +}; + /*% * Zone structure. */ @@ -824,3 +859,52 @@ dns__zone_set_resigntime(dns_zone_t *zone); * *\li 'zone' to be a valid zone, locked. */ + +void +forward_cancel(dns_zone_t *zone); +/*%< + * Cancel forwarding. + * + * Requires: + * + *\li 'zone' to be a valid zone, locked. + */ + +void +zone_xfrdone(dns_zone_t *zone, uint32_t *expireopt, isc_result_t result); +/*%< + * Process a finished zone transfer. + * + * Requires: + * + *\li 'zone' to be a valid zone. + */ + +isc_result_t +zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone); +/*%< + * Try to start an incoming zone transfer for 'zone', quota permitting. + * + * Requires: + * + *\li 'zmgr' to be a valid zone manager. + * + * Returns: + * + *\li #ISC_R_SUCCESS There was enough quota and we attempted to + * start a transfer. zone_xfrdone() has been or will + * be called. + *\li #ISC_R_QUOTA Not enough quota. + *\li Other failure. + */ + +void +zmgr_resume_xfrs(dns_zonemgr_t *zmgr, bool multi); +/*%< + * Try to start a new incoming zone transfer to fill a quota + * slot that was just vacated. + * + * Requires: + * + *\li 'zmgr' to be a valid zone manager. + */ diff --git a/lib/dns/zonemgr.c b/lib/dns/zonemgr.c new file mode 100644 index 00000000000..91ba0dadef0 --- /dev/null +++ b/lib/dns/zonemgr.c @@ -0,0 +1,807 @@ +/* + * 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 +#include + +#include +#include +#include +#include +#include +#include + +#include "zone_p.h" + +static void +zonemgr_free(dns_zonemgr_t *zmgr); + +/*** + *** Zone manager. + ***/ + +static void +setrl(isc_ratelimiter_t *rl, unsigned int *rate, unsigned int value) { + isc_interval_t interval; + uint32_t s, ns; + uint32_t pertic; + + if (value == 0) { + value = 1; + } + + if (value == 1) { + s = 1; + ns = 0; + pertic = 1; + } else if (value <= 10) { + s = 0; + ns = 1000000000 / value; + pertic = 1; + } else { + s = 0; + ns = (1000000000 / value) * 10; + pertic = 10; + } + + isc_interval_set(&interval, s, ns); + + isc_ratelimiter_setinterval(rl, &interval); + isc_ratelimiter_setpertic(rl, pertic); + + *rate = value; +} + +void +dns_zonemgr_create(isc_mem_t *mctx, dns_zonemgr_t **zmgrp) { + dns_zonemgr_t *zmgr = NULL; + isc_loop_t *loop = isc_loop(); + + REQUIRE(mctx != NULL); + REQUIRE(zmgrp != NULL && *zmgrp == NULL); + + zmgr = isc_mem_get(mctx, sizeof(*zmgr)); + + *zmgr = (dns_zonemgr_t){ + .workers = isc_loopmgr_nloops(), + .transfersin = 10, + .transfersperns = 2, + }; + + isc_refcount_init(&zmgr->refs, 1); + isc_mem_attach(mctx, &zmgr->mctx); + + ISC_LIST_INIT(zmgr->zones); + ISC_LIST_INIT(zmgr->waiting_for_xfrin); + ISC_LIST_INIT(zmgr->xfrin_in_progress); + isc_rwlock_init(&zmgr->rwlock); + + isc_ratelimiter_create(loop, &zmgr->checkdsrl); + isc_ratelimiter_create(loop, &zmgr->notifyrl); + isc_ratelimiter_create(loop, &zmgr->refreshrl); + isc_ratelimiter_create(loop, &zmgr->startupnotifyrl); + isc_ratelimiter_create(loop, &zmgr->startuprefreshrl); + + zmgr->mctxpool = isc_mem_cget(zmgr->mctx, zmgr->workers, + sizeof(zmgr->mctxpool[0])); + for (size_t i = 0; i < zmgr->workers; i++) { + isc_mem_create("zonemgr-mctxpool", &zmgr->mctxpool[i]); + } + + /* Default to 20 refresh queries / notifies / checkds per second. */ + setrl(zmgr->checkdsrl, &zmgr->checkdsrate, 20); + setrl(zmgr->notifyrl, &zmgr->notifyrate, 20); + setrl(zmgr->startupnotifyrl, &zmgr->startupnotifyrate, 20); + setrl(zmgr->refreshrl, &zmgr->serialqueryrate, 20); + setrl(zmgr->startuprefreshrl, &zmgr->startupserialqueryrate, 20); + isc_ratelimiter_setpushpop(zmgr->startupnotifyrl, true); + isc_ratelimiter_setpushpop(zmgr->startuprefreshrl, true); + + zmgr->tlsctx_cache = NULL; + isc_rwlock_init(&zmgr->tlsctx_cache_rwlock); + + zmgr->magic = ZONEMGR_MAGIC; + + *zmgrp = zmgr; +} + +isc_result_t +dns_zonemgr_createzone(dns_zonemgr_t *zmgr, dns_zone_t **zonep) { + isc_mem_t *mctx = NULL; + dns_zone_t *zone = NULL; + isc_tid_t tid; + + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + REQUIRE(zonep != NULL && *zonep == NULL); + + if (zmgr->mctxpool == NULL) { + return ISC_R_FAILURE; + } + + tid = isc_random_uniform(zmgr->workers); + + mctx = zmgr->mctxpool[tid]; + if (mctx == NULL) { + return ISC_R_FAILURE; + } + + dns_zone_create(&zone, mctx, tid); + + *zonep = zone; + + return ISC_R_SUCCESS; +} + +isc_result_t +dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); + LOCK_ZONE(zone); + REQUIRE(zone->timer == NULL); + REQUIRE(zone->zmgr == NULL); + + isc_loop_t *loop = isc_loop_get(zone->tid); + isc_loop_attach(loop, &zone->loop); + + ISC_LIST_APPEND(zmgr->zones, zone, link); + zone->zmgr = zmgr; + + isc_refcount_increment(&zmgr->refs); + + UNLOCK_ZONE(zone); + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); + return ISC_R_SUCCESS; +} + +void +dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + REQUIRE(zone->zmgr == zmgr); + + RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); + LOCK_ZONE(zone); + + ISC_LIST_UNLINK(zmgr->zones, zone, link); + + if (zone->timer != NULL) { + isc_refcount_decrement(&zone->irefs); + isc_timer_destroy(&zone->timer); + } + + isc_loop_detach(&zone->loop); + + /* Detach below, outside of the write lock. */ + zone->zmgr = NULL; + + UNLOCK_ZONE(zone); + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); + + dns_zonemgr_detach(&zmgr); +} + +void +dns_zonemgr_attach(dns_zonemgr_t *source, dns_zonemgr_t **target) { + REQUIRE(DNS_ZONEMGR_VALID(source)); + REQUIRE(target != NULL && *target == NULL); + + isc_refcount_increment(&source->refs); + + *target = source; +} + +void +dns_zonemgr_detach(dns_zonemgr_t **zmgrp) { + dns_zonemgr_t *zmgr; + + REQUIRE(zmgrp != NULL); + zmgr = *zmgrp; + *zmgrp = NULL; + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + if (isc_refcount_decrement(&zmgr->refs) == 1) { + zonemgr_free(zmgr); + } +} + +isc_result_t +dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); + ISC_LIST_FOREACH(zmgr->zones, zone, link) { + isc_time_t now; + + LOCK_ZONE(zone); + now = isc_time_now(); + dns__zone_settimer(zone, &now); + UNLOCK_ZONE(zone); + } + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); + + /* + * Recent configuration changes may have increased the + * amount of available transfers quota. Make sure any + * transfers currently blocked on quota get started if + * possible. + */ + RWLOCK(&zmgr->rwlock, isc_rwlocktype_write); + zmgr_resume_xfrs(zmgr, true); + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write); + return ISC_R_SUCCESS; +} + +void +dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + isc_ratelimiter_shutdown(zmgr->checkdsrl); + isc_ratelimiter_shutdown(zmgr->notifyrl); + isc_ratelimiter_shutdown(zmgr->refreshrl); + isc_ratelimiter_shutdown(zmgr->startupnotifyrl); + isc_ratelimiter_shutdown(zmgr->startuprefreshrl); + + for (size_t i = 0; i < zmgr->workers; i++) { + isc_mem_detach(&zmgr->mctxpool[i]); + } + + RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); + ISC_LIST_FOREACH(zmgr->zones, zone, link) { + LOCK_ZONE(zone); + forward_cancel(zone); + UNLOCK_ZONE(zone); + } + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); +} + +static void +zonemgr_free(dns_zonemgr_t *zmgr) { + REQUIRE(ISC_LIST_EMPTY(zmgr->zones)); + + zmgr->magic = 0; + + isc_refcount_destroy(&zmgr->refs); + isc_ratelimiter_detach(&zmgr->checkdsrl); + isc_ratelimiter_detach(&zmgr->notifyrl); + isc_ratelimiter_detach(&zmgr->refreshrl); + isc_ratelimiter_detach(&zmgr->startupnotifyrl); + isc_ratelimiter_detach(&zmgr->startuprefreshrl); + + isc_mem_cput(zmgr->mctx, zmgr->mctxpool, zmgr->workers, + sizeof(zmgr->mctxpool[0])); + + isc_rwlock_destroy(&zmgr->rwlock); + isc_rwlock_destroy(&zmgr->tlsctx_cache_rwlock); + + if (zmgr->tlsctx_cache != NULL) { + isc_tlsctx_cache_detach(&zmgr->tlsctx_cache); + } + isc_mem_putanddetach(&zmgr->mctx, zmgr, sizeof(*zmgr)); +} + +void +dns_zonemgr_settransfersin(dns_zonemgr_t *zmgr, uint32_t value) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + zmgr->transfersin = value; +} + +uint32_t +dns_zonemgr_gettransfersin(dns_zonemgr_t *zmgr) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + return zmgr->transfersin; +} + +void +dns_zonemgr_settransfersperns(dns_zonemgr_t *zmgr, uint32_t value) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + zmgr->transfersperns = value; +} + +uint32_t +dns_zonemgr_gettransfersperns(dns_zonemgr_t *zmgr) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + return zmgr->transfersperns; +} + +/* + * Try to start a new incoming zone transfer to fill a quota + * slot that was just vacated. + * + * Requires: + * The zone manager is locked by the caller. + */ +void +zmgr_resume_xfrs(dns_zonemgr_t *zmgr, bool multi) { + ISC_LIST_FOREACH(zmgr->waiting_for_xfrin, zone, statelink) { + isc_result_t result; + result = zmgr_start_xfrin_ifquota(zmgr, zone); + if (result == ISC_R_SUCCESS) { + if (multi) { + continue; + } + /* + * We successfully filled the slot. We're done. + */ + break; + } else if (result == ISC_R_QUOTA) { + /* + * Not enough quota. This is probably the per-server + * quota, because we usually get called when a unit of + * global quota has just been freed. Try the next + * zone, it may succeed if it uses another primary. + */ + continue; + } else { + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, + ISC_LOG_DEBUG(1), + "starting zone transfer: %s", + isc_result_totext(result)); + break; + } + } +} + +/* + * This event callback is called when a zone has received + * any necessary zone transfer quota. This is the time + * to go ahead and start the transfer. + */ +static void +got_transfer_quota(void *arg) { + dns_zone_t *zone = (dns_zone_t *)arg; + isc_result_t result = ISC_R_SUCCESS; + dns_peer_t *peer = NULL; + char primary[ISC_SOCKADDR_FORMATSIZE]; + char source[ISC_SOCKADDR_FORMATSIZE]; + dns_rdatatype_t xfrtype; + uint32_t ixfr_maxdiffs = 0; + isc_netaddr_t primaryip; + isc_sockaddr_t primaryaddr; + isc_sockaddr_t sourceaddr; + dns_transport_type_t soa_transport_type = DNS_TRANSPORT_NONE; + const char *soa_before = ""; + bool loaded; + isc_tlsctx_cache_t *zmgr_tlsctx_cache = NULL; + dns_xfrin_t *xfr = NULL; + + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { + zone_xfrdone(zone, NULL, ISC_R_CANCELED); + return; + } + + primaryaddr = dns_remote_curraddr(&zone->primaries); + isc_sockaddr_format(&primaryaddr, primary, sizeof(primary)); + if (dns_unreachcache_find(zone->view->unreachcache, &primaryaddr, + &zone->sourceaddr) == ISC_R_SUCCESS) + { + isc_sockaddr_format(&zone->sourceaddr, source, sizeof(source)); + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO, + "got_transfer_quota: skipping zone transfer as " + "primary %s (source %s) is unreachable (cached)", + primary, source); + zone_xfrdone(zone, NULL, ISC_R_CANCELED); + return; + } + + isc_netaddr_fromsockaddr(&primaryip, &primaryaddr); + (void)dns_peerlist_peerbyaddr(zone->view->peers, &primaryip, &peer); + + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) { + soa_before = "SOA before "; + } + /* + * Decide whether we should request IXFR or AXFR. + */ + ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); + loaded = (zone->db != NULL); + ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read); + + if (!loaded) { + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_DEBUG(1), + "no database exists yet, requesting AXFR of " + "initial version from %s", + primary); + xfrtype = dns_rdatatype_axfr; + } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) { + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_DEBUG(1), + "forced reload, requesting AXFR of " + "initial version from %s", + primary); + xfrtype = dns_rdatatype_axfr; + } else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NOIXFR)) { + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_DEBUG(1), + "retrying with AXFR from %s due to " + "previous IXFR failure", + primary); + xfrtype = dns_rdatatype_axfr; + LOCK_ZONE(zone); + DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOIXFR); + UNLOCK_ZONE(zone); + } else { + bool use_ixfr = true; + + if (peer != NULL) { + result = dns_peer_getrequestixfr(peer, &use_ixfr); + } + if (peer == NULL || result != ISC_R_SUCCESS) { + use_ixfr = zone->requestixfr; + } + if (peer != NULL) { + result = dns_peer_getrequestixfrmaxdiffs( + peer, &ixfr_maxdiffs); + } + if (peer == NULL || result != ISC_R_SUCCESS) { + ixfr_maxdiffs = zone->requestixfr_maxdiffs; + } + if (!use_ixfr) { + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, + ISC_LOG_DEBUG(1), + "IXFR disabled, " + "requesting %sAXFR from %s", + soa_before, primary); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR)) { + xfrtype = dns_rdatatype_soa; + } else { + xfrtype = dns_rdatatype_axfr; + } + } else { + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, + ISC_LOG_DEBUG(1), + "requesting IXFR from %s", primary); + xfrtype = dns_rdatatype_ixfr; + } + } + + /* + * Determine if we should attempt to sign the request with TSIG. + */ + result = ISC_R_NOTFOUND; + + /* + * First, look for a tsig key in the primaries statement, then + * try for a server key. + */ + if (dns_remote_keyname(&zone->primaries) != NULL) { + dns_view_t *view = dns_zone_getview(zone); + dns_name_t *keyname = dns_remote_keyname(&zone->primaries); + result = dns_view_gettsig(view, keyname, &zone->tsigkey); + } + if (result != ISC_R_SUCCESS) { + INSIST(zone->tsigkey == NULL); + result = dns_view_getpeertsig(zone->view, &primaryip, + &zone->tsigkey); + } + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_ERROR, + "could not get TSIG key for zone transfer: %s", + isc_result_totext(result)); + } + + /* + * Get the TLS transport for the primary, if configured. + */ + if (dns_remote_tlsname(&zone->primaries) != NULL) { + dns_view_t *view = dns_zone_getview(zone); + dns_name_t *tlsname = dns_remote_tlsname(&zone->primaries); + result = dns_view_gettransport(view, DNS_TRANSPORT_TLS, tlsname, + &zone->transport); + if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) { + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, + ISC_LOG_ERROR, + "could not get TLS configuration for " + "zone transfer: %s", + isc_result_totext(result)); + } + } + + LOCK_ZONE(zone); + if (xfrtype != dns_rdatatype_soa) { + /* + * If 'xfrtype' is dns_rdatatype_soa, then the SOA query will be + * performed by xfrin, otherwise, the SOA request performed by + * soa_query() was successful and we should inform the xfrin + * about the transport type used for that query, so that the + * information can be presented in the statistics channel. + */ + soa_transport_type = get_request_transport_type(zone); + } + sourceaddr = zone->sourceaddr; + UNLOCK_ZONE(zone); + + INSIST(isc_sockaddr_pf(&primaryaddr) == isc_sockaddr_pf(&sourceaddr)); + + dns__zonemgr_tlsctx_attach(zone->zmgr, &zmgr_tlsctx_cache); + + dns_xfrin_create(zone, xfrtype, ixfr_maxdiffs, &primaryaddr, + &sourceaddr, zone->tsigkey, soa_transport_type, + zone->transport, zmgr_tlsctx_cache, zone->mctx, &xfr); + INSIST(xfr != NULL); + + isc_tlsctx_cache_detach(&zmgr_tlsctx_cache); + + LOCK_ZONE(zone); + if (zone->xfr != NULL) { + dns_xfrin_detach(&zone->xfr); + } + dns_xfrin_attach(xfr, &zone->xfr); + UNLOCK_ZONE(zone); + + dns_xfrin_detach(&xfr); + + /* + * Any failure in this function is handled like a failed + * zone transfer. This ensures that we get removed from + * zmgr->xfrin_in_progress. + */ + result = dns_xfrin_start(zone->xfr, zone_xfrdone); + if (result != ISC_R_SUCCESS) { + zone_xfrdone(zone, NULL, result); + return; + } + + LOCK_ZONE(zone); + if (xfrtype == dns_rdatatype_axfr) { + if (isc_sockaddr_pf(&primaryaddr) == PF_INET) { + inc_stats(zone, dns_zonestatscounter_axfrreqv4); + } else { + inc_stats(zone, dns_zonestatscounter_axfrreqv6); + } + } else if (xfrtype == dns_rdatatype_ixfr) { + if (isc_sockaddr_pf(&primaryaddr) == PF_INET) { + inc_stats(zone, dns_zonestatscounter_ixfrreqv4); + } else { + inc_stats(zone, dns_zonestatscounter_ixfrreqv6); + } + } + UNLOCK_ZONE(zone); +} + +/* + * Try to start an incoming zone transfer for 'zone', quota permitting. + * + * Requires: + * The zone manager is locked by the caller. + * + * Returns: + * ISC_R_SUCCESS There was enough quota and we attempted to + * start a transfer. zone_xfrdone() has been or will + * be called. + * ISC_R_QUOTA Not enough quota. + * Others Failure. + */ +isc_result_t +zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) { + dns_peer_t *peer = NULL; + isc_netaddr_t primaryip; + isc_sockaddr_t curraddr; + uint32_t nxfrsin, nxfrsperns; + uint32_t maxtransfersin, maxtransfersperns; + + /* + * If we are exiting just pretend we got quota so the zone will + * be cleaned up in the zone's loop context. + */ + LOCK_ZONE(zone); + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING)) { + UNLOCK_ZONE(zone); + goto gotquota; + } + + /* + * Find any configured information about the server we'd + * like to transfer this zone from. + */ + curraddr = dns_remote_curraddr(&zone->primaries); + isc_netaddr_fromsockaddr(&primaryip, &curraddr); + (void)dns_peerlist_peerbyaddr(zone->view->peers, &primaryip, &peer); + UNLOCK_ZONE(zone); + + /* + * Determine the total maximum number of simultaneous + * transfers allowed, and the maximum for this specific + * primary. + */ + maxtransfersin = zmgr->transfersin; + maxtransfersperns = zmgr->transfersperns; + if (peer != NULL) { + (void)dns_peer_gettransfers(peer, &maxtransfersperns); + } + + /* + * Count the total number of transfers that are in progress, + * and the number of transfers in progress from this primary. + * We linearly scan a list of all transfers; if this turns + * out to be too slow, we could hash on the primary address. + */ + nxfrsin = nxfrsperns = 0; + ISC_LIST_FOREACH(zmgr->xfrin_in_progress, x, statelink) { + isc_netaddr_t xip; + isc_sockaddr_t xaddr; + + LOCK_ZONE(x); + xaddr = dns_remote_curraddr(&x->primaries); + isc_netaddr_fromsockaddr(&xip, &xaddr); + UNLOCK_ZONE(x); + + nxfrsin++; + if (isc_netaddr_equal(&xip, &primaryip)) { + nxfrsperns++; + } + } + + /* Enforce quota. */ + if (nxfrsin >= maxtransfersin) { + return ISC_R_QUOTA; + } + + if (nxfrsperns >= maxtransfersperns) { + return ISC_R_QUOTA; + } + +gotquota: + /* + * We have sufficient quota. Move the zone to the "xfrin_in_progress" + * list and start the actual transfer asynchronously. + */ + LOCK_ZONE(zone); + INSIST(zone->statelist == &zmgr->waiting_for_xfrin); + ISC_LIST_UNLINK(zmgr->waiting_for_xfrin, zone, statelink); + ISC_LIST_APPEND(zmgr->xfrin_in_progress, zone, statelink); + zone->statelist = &zmgr->xfrin_in_progress; + isc_async_run(zone->loop, got_transfer_quota, zone); + dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN, ISC_LOG_INFO, + "Transfer started."); + UNLOCK_ZONE(zone); + + return ISC_R_SUCCESS; +} + +void +dns_zonemgr_setcheckdsrate(dns_zonemgr_t *zmgr, unsigned int value) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + setrl(zmgr->checkdsrl, &zmgr->checkdsrate, value); +} + +void +dns_zonemgr_setnotifyrate(dns_zonemgr_t *zmgr, unsigned int value) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + setrl(zmgr->notifyrl, &zmgr->notifyrate, value); +} + +void +dns_zonemgr_setstartupnotifyrate(dns_zonemgr_t *zmgr, unsigned int value) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + setrl(zmgr->startupnotifyrl, &zmgr->startupnotifyrate, value); +} + +void +dns_zonemgr_setkeystores(dns_zonemgr_t *zmgr, dns_keystorelist_t *keystores) { + zmgr->keystores = keystores; +} + +void +dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) { + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + setrl(zmgr->refreshrl, &zmgr->serialqueryrate, value); + /* XXXMPA separate out once we have the code to support this. */ + setrl(zmgr->startuprefreshrl, &zmgr->startupserialqueryrate, value); +} + +unsigned int +dns_zonemgr_getnotifyrate(dns_zonemgr_t *zmgr) { + REQUIRE(DNS_ZONEMGR_VALID(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)); + + 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)); + + return zmgr->serialqueryrate; +} + +unsigned int +dns_zonemgr_getcount(dns_zonemgr_t *zmgr, dns_zonestate_t state) { + unsigned int count = 0; + + REQUIRE(DNS_ZONEMGR_VALID(zmgr)); + + RWLOCK(&zmgr->rwlock, isc_rwlocktype_read); + switch (state) { + case DNS_ZONESTATE_XFERRUNNING: + ISC_LIST_FOREACH(zmgr->xfrin_in_progress, zone, statelink) { + count++; + } + break; + case DNS_ZONESTATE_XFERDEFERRED: + ISC_LIST_FOREACH(zmgr->waiting_for_xfrin, zone, statelink) { + count++; + } + break; + case DNS_ZONESTATE_XFERFIRSTREFRESH: + ISC_LIST_FOREACH(zmgr->zones, zone, link) { + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FIRSTREFRESH)) { + count++; + } + } + break; + case DNS_ZONESTATE_SOAQUERY: + ISC_LIST_FOREACH(zmgr->zones, zone, link) { + if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_REFRESH)) { + count++; + } + } + break; + case DNS_ZONESTATE_ANY: + ISC_LIST_FOREACH(zmgr->zones, zone, link) { + dns_view_t *view = zone->view; + if (view != NULL && strcmp(view->name, "_bind") == 0) { + continue; + } + count++; + } + break; + case DNS_ZONESTATE_AUTOMATIC: + ISC_LIST_FOREACH(zmgr->zones, zone, link) { + dns_view_t *view = zone->view; + if (view != NULL && strcmp(view->name, "_bind") == 0) { + continue; + } + if (zone->automatic) { + count++; + } + } + break; + default: + UNREACHABLE(); + } + + RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read); + + return count; +} diff --git a/tests/dns/zonemgr_test.c b/tests/dns/zonemgr_test.c index def4a4e3a3e..26594e67b9a 100644 --- a/tests/dns/zonemgr_test.c +++ b/tests/dns/zonemgr_test.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/tests/libtest/dns.c b/tests/libtest/dns.c index 2da4a1a37cf..9b6b8dc655d 100644 --- a/tests/libtest/dns.c +++ b/tests/libtest/dns.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include diff --git a/tests/libtest/ns.c b/tests/libtest/ns.c index 9d81e013c9e..7c5c9babbb0 100644 --- a/tests/libtest/ns.c +++ b/tests/libtest/ns.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include