diff --git a/bin/named/server.c b/bin/named/server.c index 03e3dbf5e5..7b676197aa 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 87b708b5e3..14cde7fe47 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 7c3b842cca..cf4d075af1 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 4a7d04d8e5..37724d4428 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 1b5337f3ec..55043ec2ee 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 5e6bfb70ef..31ec62871f 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 0000000000..0e60410ce0 --- /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 61b64bbfa4..f95cb7a15f 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 b397a1672f..a75d79582d 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 143b65a7b1..65583aef94 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 0000000000..91ba0dadef --- /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 def4a4e3a3..26594e67b9 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 2da4a1a37c..9b6b8dc655 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 9d81e013c9..7c5c9babbb 100644 --- a/tests/libtest/ns.c +++ b/tests/libtest/ns.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include