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.
This commit is contained in:
Matthijs Mekking 2026-03-19 17:10:18 +01:00
parent 634194484d
commit 080e849eaa
14 changed files with 1128 additions and 1030 deletions

View file

@ -103,6 +103,7 @@
#include <dns/ttl.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zonemgr.h>
#include <dns/zoneproperties.h>
#include <dns/zt.h>

View file

@ -36,6 +36,7 @@
#include <dns/transport.h>
#include <dns/view.h>
#include <dns/xfrin.h>
#include <dns/zonemgr.h>
#include <dns/zoneproperties.h>
#include <dns/zt.h>

View file

@ -45,6 +45,7 @@
#include <dns/name.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zonemgr.h>
#include "db.h"
#include "log.h"

View file

@ -40,6 +40,7 @@
#include <dns/dyndb.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zonemgr.h>
#include <dns/zoneproperties.h>
#include "instance.h"

View file

@ -25,6 +25,7 @@
#include <dns/types.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zonemgr.h>
#include "dyndb_p.h"

View file

@ -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);
/*%<

View file

@ -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 <dns/zone.h>
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.
*/

View file

@ -169,6 +169,7 @@ dns_srcset.add(
'view.c',
'zone.c',
'zonefetch.c',
'zonemgr.c',
'zoneproperties.c',
'zoneverify.c',
'zt.c',

View file

@ -95,6 +95,7 @@
#include <dns/xfrin.h>
#include <dns/zone.h>
#include <dns/zonefetch.h>
#include <dns/zonemgr.h>
#include <dns/zoneproperties.h>
#include <dns/zoneverify.h>
#include <dns/zt.h>
@ -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,

View file

@ -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.
*/

807
lib/dns/zonemgr.c Normal file
View file

@ -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 <isc/async.h>
#include <isc/random.h>
#include <isc/ratelimiter.h>
#include <dns/peer.h>
#include <dns/stats.h>
#include <dns/unreachcache.h>
#include <dns/zone.h>
#include <dns/zonemgr.h>
#include <dns/zoneproperties.h>
#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;
}

View file

@ -32,6 +32,7 @@
#include <dns/name.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zonemgr.h>
#include <dns/zoneproperties.h>
#include <tests/dns.h>

View file

@ -48,6 +48,7 @@
#include <dns/name.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zonemgr.h>
#include <dns/zoneproperties.h>
#include <tests/dns.h>

View file

@ -43,6 +43,7 @@
#include <dns/name.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zonemgr.h>
#include <dns/zoneproperties.h>
#include <ns/client.h>