unbound/iterator/iter_fwd.c

653 lines
17 KiB
C
Raw Normal View History

/*
* iterator/iter_fwd.c - iterative resolver module forward zones.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains functions to assist the iterator module.
* Keep track of forward zones and config settings.
*/
#include "config.h"
#include "iterator/iter_fwd.h"
#include "iterator/iter_delegpt.h"
#include "util/log.h"
#include "util/config_file.h"
#include "util/net_help.h"
#include "util/data/dname.h"
#include "sldns/rrdef.h"
#include "sldns/str2wire.h"
int
fwd_cmp(const void* k1, const void* k2)
{
int m;
struct iter_forward_zone* n1 = (struct iter_forward_zone*)k1;
struct iter_forward_zone* n2 = (struct iter_forward_zone*)k2;
if(n1->dclass != n2->dclass) {
if(n1->dclass < n2->dclass)
return -1;
return 1;
}
return dname_lab_cmp(n1->name, n1->namelabs, n2->name, n2->namelabs,
&m);
}
struct iter_forwards*
forwards_create(void)
{
struct iter_forwards* fwd = (struct iter_forwards*)calloc(1,
sizeof(struct iter_forwards));
if(!fwd)
return NULL;
lock_rw_init(&fwd->lock);
return fwd;
}
static void fwd_zone_free(struct iter_forward_zone* n)
{
if(!n) return;
delegpt_free_mlc(n->dp);
free(n->name);
free(n);
}
static void delfwdnode(rbnode_type* n, void* ATTR_UNUSED(arg))
{
struct iter_forward_zone* node = (struct iter_forward_zone*)n;
fwd_zone_free(node);
}
static void fwd_del_tree(struct iter_forwards* fwd)
{
if(fwd->tree)
traverse_postorder(fwd->tree, &delfwdnode, NULL);
free(fwd->tree);
}
void
forwards_delete(struct iter_forwards* fwd)
{
if(!fwd)
return;
lock_rw_destroy(&fwd->lock);
fwd_del_tree(fwd);
free(fwd);
}
/** insert info into forward structure */
static int
forwards_insert_data(struct iter_forwards* fwd, uint16_t c, uint8_t* nm,
size_t nmlen, int nmlabs, struct delegpt* dp)
{
struct iter_forward_zone* node = (struct iter_forward_zone*)malloc(
sizeof(struct iter_forward_zone));
if(!node) {
delegpt_free_mlc(dp);
return 0;
}
node->node.key = node;
node->dclass = c;
node->name = memdup(nm, nmlen);
if(!node->name) {
delegpt_free_mlc(dp);
free(node);
return 0;
}
node->namelen = nmlen;
node->namelabs = nmlabs;
node->dp = dp;
if(!rbtree_insert(fwd->tree, &node->node)) {
char buf[LDNS_MAX_DOMAINLEN];
dname_str(nm, buf);
log_err("duplicate forward zone %s ignored.", buf);
delegpt_free_mlc(dp);
free(node->name);
free(node);
}
return 1;
}
static struct iter_forward_zone*
fwd_zone_find(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
{
struct iter_forward_zone key;
key.node.key = &key;
key.dclass = c;
key.name = nm;
key.namelabs = dname_count_size_labels(nm, &key.namelen);
return (struct iter_forward_zone*)rbtree_search(fwd->tree, &key);
}
/** insert new info into forward structure given dp */
static int
forwards_insert(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp)
{
return forwards_insert_data(fwd, c, dp->name, dp->namelen,
dp->namelabs, dp);
}
/** initialise parent pointers in the tree */
static void
fwd_init_parents(struct iter_forwards* fwd)
{
struct iter_forward_zone* node, *prev = NULL, *p;
int m;
RBTREE_FOR(node, struct iter_forward_zone*, fwd->tree) {
node->parent = NULL;
if(!prev || prev->dclass != node->dclass) {
prev = node;
continue;
}
(void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
node->namelabs, &m); /* we know prev is smaller */
/* sort order like: . com. bla.com. zwb.com. net. */
/* find the previous, or parent-parent-parent */
for(p = prev; p; p = p->parent)
/* looking for name with few labels, a parent */
if(p->namelabs <= m) {
/* ==: since prev matched m, this is closest*/
/* <: prev matches more, but is not a parent,
* this one is a (grand)parent */
node->parent = p;
break;
}
prev = node;
}
}
/** set zone name */
static struct delegpt*
read_fwds_name(struct config_stub* s)
{
struct delegpt* dp;
uint8_t* dname;
size_t dname_len;
if(!s->name) {
log_err("forward zone without a name (use name \".\" to forward everything)");
return NULL;
}
dname = sldns_str2wire_dname(s->name, &dname_len);
if(!dname) {
log_err("cannot parse forward zone name %s", s->name);
return NULL;
}
if(!(dp=delegpt_create_mlc(dname))) {
free(dname);
log_err("out of memory");
return NULL;
}
free(dname);
return dp;
}
/** set fwd host names */
static int
read_fwds_host(struct config_stub* s, struct delegpt* dp)
{
struct config_strlist* p;
uint8_t* dname;
char* tls_auth_name;
int port;
for(p = s->hosts; p; p = p->next) {
log_assert(p->str);
dname = authextstrtodname(p->str, &port, &tls_auth_name);
if(!dname) {
log_err("cannot parse forward %s server name: '%s'",
s->name, p->str);
return 0;
}
#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
if(tls_auth_name)
log_err("no name verification functionality in "
"ssl library, ignored name for %s", p->str);
#endif
if(!delegpt_add_ns_mlc(dp, dname, 0, tls_auth_name, port)) {
free(dname);
log_err("out of memory");
return 0;
}
free(dname);
}
return 1;
}
/** set fwd server addresses */
static int
read_fwds_addr(struct config_stub* s, struct delegpt* dp)
{
struct config_strlist* p;
struct sockaddr_storage addr;
socklen_t addrlen;
char* tls_auth_name;
for(p = s->addrs; p; p = p->next) {
log_assert(p->str);
if(!authextstrtoaddr(p->str, &addr, &addrlen, &tls_auth_name)) {
log_err("cannot parse forward %s ip address: '%s'",
s->name, p->str);
return 0;
}
#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
if(tls_auth_name)
log_err("no name verification functionality in "
"ssl library, ignored name for %s", p->str);
#endif
if(!delegpt_add_addr_mlc(dp, &addr, addrlen, 0, 0,
tls_auth_name, -1)) {
log_err("out of memory");
return 0;
}
}
return 1;
}
/** read forwards config */
static int
read_forwards(struct iter_forwards* fwd, struct config_file* cfg)
{
struct config_stub* s;
for(s = cfg->forwards; s; s = s->next) {
struct delegpt* dp;
if(!(dp=read_fwds_name(s)))
return 0;
if(!read_fwds_host(s, dp) || !read_fwds_addr(s, dp)) {
delegpt_free_mlc(dp);
return 0;
}
/* set flag that parent side NS information is included.
* Asking a (higher up) server on the internet is not useful */
/* the flag is turned off for 'forward-first' so that the
* last resort will ask for parent-side NS record and thus
* fallback to the internet name servers on a failure */
dp->has_parent_side_NS = (uint8_t)!s->isfirst;
/* Do not cache if set. */
dp->no_cache = s->no_cache;
/* use SSL for queries to this forwarder */
dp->ssl_upstream = (uint8_t)s->ssl_upstream;
/* use TCP for queries to this forwarder */
dp->tcp_upstream = (uint8_t)s->tcp_upstream;
verbose(VERB_QUERY, "Forward zone server list:");
delegpt_log(VERB_QUERY, dp);
if(!forwards_insert(fwd, LDNS_RR_CLASS_IN, dp))
return 0;
}
return 1;
}
/** insert a stub hole (if necessary) for stub name */
static int
fwd_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
{
struct iter_forward_zone key;
key.node.key = &key;
key.dclass = c;
key.name = nm;
key.namelabs = dname_count_size_labels(key.name, &key.namelen);
return forwards_insert_data(fwd, key.dclass, key.name,
key.namelen, key.namelabs, NULL);
}
/** make NULL entries for stubs */
static int
make_stub_holes(struct iter_forwards* fwd, struct config_file* cfg)
{
struct config_stub* s;
uint8_t* dname;
size_t dname_len;
for(s = cfg->stubs; s; s = s->next) {
if(!s->name) continue;
dname = sldns_str2wire_dname(s->name, &dname_len);
if(!dname) {
log_err("cannot parse stub name '%s'", s->name);
return 0;
}
if(fwd_zone_find(fwd, LDNS_RR_CLASS_IN, dname) != NULL) {
/* Already a forward zone there. */
free(dname);
continue;
}
if(!fwd_add_stub_hole(fwd, LDNS_RR_CLASS_IN, dname)) {
free(dname);
log_err("out of memory");
return 0;
}
free(dname);
}
return 1;
}
/** make NULL entries for auths */
static int
make_auth_holes(struct iter_forwards* fwd, struct config_file* cfg)
{
struct config_auth* a;
uint8_t* dname;
size_t dname_len;
for(a = cfg->auths; a; a = a->next) {
if(!a->name) continue;
dname = sldns_str2wire_dname(a->name, &dname_len);
if(!dname) {
log_err("cannot parse auth name '%s'", a->name);
return 0;
}
if(fwd_zone_find(fwd, LDNS_RR_CLASS_IN, dname) != NULL) {
/* Already a forward zone there. */
free(dname);
continue;
}
if(!fwd_add_stub_hole(fwd, LDNS_RR_CLASS_IN, dname)) {
free(dname);
log_err("out of memory");
return 0;
}
free(dname);
}
return 1;
}
int
forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg)
{
if(fwd->tree) {
lock_unprotect(&fwd->lock, fwd->tree);
}
fwd_del_tree(fwd);
fwd->tree = rbtree_create(fwd_cmp);
if(!fwd->tree)
return 0;
lock_protect(&fwd->lock, fwd->tree, sizeof(*fwd->tree));
lock_rw_wrlock(&fwd->lock);
/* read forward zones */
if(!read_forwards(fwd, cfg)) {
lock_rw_unlock(&fwd->lock);
return 0;
}
if(!make_stub_holes(fwd, cfg)) {
lock_rw_unlock(&fwd->lock);
return 0;
}
/* TODO: Now we punch holes for auth zones as well so that in
* iterator:forward_request() we see the configured
* delegation point, but code flow/naming is hard to follow.
* Consider having a single tree with configured
* delegation points for all categories
* (stubs, forwards, auths). */
if(!make_auth_holes(fwd, cfg)) {
lock_rw_unlock(&fwd->lock);
return 0;
}
fwd_init_parents(fwd);
lock_rw_unlock(&fwd->lock);
return 1;
}
struct delegpt*
forwards_find(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass,
int nolock)
{
struct iter_forward_zone* res;
struct iter_forward_zone key;
int has_dp;
key.node.key = &key;
key.dclass = qclass;
key.name = qname;
key.namelabs = dname_count_size_labels(qname, &key.namelen);
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_rdlock(&fwd->lock); }
res = (struct iter_forward_zone*)rbtree_search(fwd->tree, &key);
has_dp = res && res->dp;
if(!has_dp && !nolock) { lock_rw_unlock(&fwd->lock); }
return has_dp?res->dp:NULL;
}
struct delegpt*
forwards_lookup(struct iter_forwards* fwd, uint8_t* qname, uint16_t qclass,
int nolock)
{
/* lookup the forward zone in the tree */
rbnode_type* res = NULL;
struct iter_forward_zone *result;
struct iter_forward_zone key;
int has_dp;
key.node.key = &key;
key.dclass = qclass;
key.name = qname;
key.namelabs = dname_count_size_labels(qname, &key.namelen);
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_rdlock(&fwd->lock); }
if(rbtree_find_less_equal(fwd->tree, &key, &res)) {
/* exact */
result = (struct iter_forward_zone*)res;
} else {
/* smaller element (or no element) */
int m;
result = (struct iter_forward_zone*)res;
if(!result || result->dclass != qclass) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return NULL;
}
/* count number of labels matched */
(void)dname_lab_cmp(result->name, result->namelabs, key.name,
key.namelabs, &m);
while(result) { /* go up until qname is subdomain of stub */
if(result->namelabs <= m)
break;
result = result->parent;
}
}
has_dp = result && result->dp;
if(!has_dp && !nolock) { lock_rw_unlock(&fwd->lock); }
return has_dp?result->dp:NULL;
}
struct delegpt*
forwards_lookup_root(struct iter_forwards* fwd, uint16_t qclass, int nolock)
{
uint8_t root = 0;
return forwards_lookup(fwd, &root, qclass, nolock);
}
/* Finds next root item in forwards lookup tree.
* Caller needs to handle locking of the forwards structure. */
static int
next_root_locked(struct iter_forwards* fwd, uint16_t* dclass)
{
struct iter_forward_zone key;
rbnode_type* n;
struct iter_forward_zone* p;
if(*dclass == 0) {
/* first root item is first item in tree */
n = rbtree_first(fwd->tree);
if(n == RBTREE_NULL)
return 0;
p = (struct iter_forward_zone*)n;
if(dname_is_root(p->name)) {
*dclass = p->dclass;
return 1;
}
/* root not first item? search for higher items */
*dclass = p->dclass + 1;
return next_root_locked(fwd, dclass);
}
/* find class n in tree, we may get a direct hit, or if we don't
* this is the last item of the previous class so rbtree_next() takes
* us to the next root (if any) */
key.node.key = &key;
key.name = (uint8_t*)"\000";
key.namelen = 1;
key.namelabs = 0;
key.dclass = *dclass;
n = NULL;
if(rbtree_find_less_equal(fwd->tree, &key, &n)) {
/* exact */
return 1;
} else {
/* smaller element */
if(!n || n == RBTREE_NULL)
return 0; /* nothing found */
n = rbtree_next(n);
if(n == RBTREE_NULL)
return 0; /* no higher */
p = (struct iter_forward_zone*)n;
if(dname_is_root(p->name)) {
*dclass = p->dclass;
return 1;
}
/* not a root node, return next higher item */
*dclass = p->dclass+1;
return next_root_locked(fwd, dclass);
}
}
int
forwards_next_root(struct iter_forwards* fwd, uint16_t* dclass, int nolock)
{
int ret;
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_rdlock(&fwd->lock); }
ret = next_root_locked(fwd, dclass);
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return ret;
}
size_t
forwards_get_mem(struct iter_forwards* fwd)
{
struct iter_forward_zone* p;
size_t s;
if(!fwd)
return 0;
lock_rw_rdlock(&fwd->lock);
s = sizeof(*fwd) + sizeof(*fwd->tree);
RBTREE_FOR(p, struct iter_forward_zone*, fwd->tree) {
s += sizeof(*p) + p->namelen + delegpt_get_mem(p->dp);
}
lock_rw_unlock(&fwd->lock);
return s;
}
int
forwards_add_zone(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp,
int nolock)
{
struct iter_forward_zone *z;
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_wrlock(&fwd->lock); }
if((z=fwd_zone_find(fwd, c, dp->name)) != NULL) {
(void)rbtree_delete(fwd->tree, &z->node);
fwd_zone_free(z);
}
if(!forwards_insert(fwd, c, dp)) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return 0;
}
fwd_init_parents(fwd);
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return 1;
}
void
forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm,
int nolock)
{
struct iter_forward_zone *z;
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_wrlock(&fwd->lock); }
if(!(z=fwd_zone_find(fwd, c, nm))) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return; /* nothing to do */
}
(void)rbtree_delete(fwd->tree, &z->node);
fwd_zone_free(z);
fwd_init_parents(fwd);
if(!nolock) { lock_rw_unlock(&fwd->lock); }
}
int
forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm,
int nolock)
{
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_wrlock(&fwd->lock); }
if(fwd_zone_find(fwd, c, nm) != NULL) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return 1; /* already a stub zone there */
}
if(!fwd_add_stub_hole(fwd, c, nm)) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return 0;
}
fwd_init_parents(fwd);
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return 1;
}
void
forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c,
uint8_t* nm, int nolock)
{
struct iter_forward_zone *z;
/* lock_() calls are macros that could be nothing, surround in {} */
if(!nolock) { lock_rw_wrlock(&fwd->lock); }
if(!(z=fwd_zone_find(fwd, c, nm))) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return; /* nothing to do */
}
if(z->dp != NULL) {
if(!nolock) { lock_rw_unlock(&fwd->lock); }
return; /* not a stub hole */
}
(void)rbtree_delete(fwd->tree, &z->node);
fwd_zone_free(z);
fwd_init_parents(fwd);
if(!nolock) { lock_rw_unlock(&fwd->lock); }
}
Fast Reload Option (#1042) * - fast-reload, add unbound-control fast_reload * - fast-reload, make a thread to service the unbound-control command. * - fast-reload, communication sockets for information transfer. * - fast-reload, fix compile for unbound-dnstap-socket. * - fast-reload, set nonblocking communication to keep the server thread responding to DNS requests. * - fast-reload, poll routine to test for readiness, timeout fails connection. * - fast-reload, detect loop in sock_poll_timeout routine. * - fast-reload, send done and exited notification. * - fast-reload, defines for constants in ipc. * - fast-reload, ipc socket recv and send resists partial reads and writes and can continue byte by byte. Also it can continue after an interrupt. * - fast-reload, send exit command to thread when done. * - fast-reload, output strings for client on string list. * - fast-reload, add newline to terminal output. * - fast-reload, send client string to remote client. * - fast-reload, better debug output. * - fast-reload, print queue structure, for output to the remote client. * - fast-reload, move print items to print queue from fast_reload_thread struct. * - fast-reload, keep list of pending print queue items in daemon struct. * - fast-reload, comment explains in_list for printq to print remainder. * - fast-reload, unit test testdata/fast_reload_thread.tdir that tests the thread output. * - fast-reload, fix test link for fast_reload_printq_list_delete function. * - fast-reload, reread config file from disk. * - fast-reload, unshare forwards, making the structure locked, with an rwlock. * - fast-reload, for nonthreaded, the unbound-control commands forward, forward_add and forward_delete should be distributed to other processes, but when threaded, they should not be distributed to other threads because the structure is not thread specific any more. * - fast-reload, unshared stub hints, making the structure locked, with an rwlock. * - fast-reload, helpful comments for hints lookup function return value. * - fast-reload, fix bug in fast reload printout, the strlist appendlist routine, and printout time statistics after the reload is done. * - fast-reload, keep track of reloadtime and deletestime and print them. * - fast-reload, keep track of constructtime and print it. * - fast-reload, construct new items. * - fast-reload, better comment. * - fast-reload, reload the config and swap trees for forwards and stub hints. * - fast-reload, in forwards_swap_tree set protection of trees with locks. * - fast-reload, in hints_swap_tree also swap the node count of the trees. * - fast-reload, reload ipc to stop and start threads. * - fast-reload, unused forward declarations removed. * - fast-reload, unit test that fast reload works with forwards and stubs. * - fast-reload, fix clang analyzer warnings. * - fast-reload, small documentation entry in unbound-control -h output. * - fast-reload, printout memory use by fast reload, in bytes. * - fast-reload, compile without threads. * - fast-reload, document fast_reload in man page. * - fast-reload, print ok when done successfully. * - fast-reload, option for fast-reload commandline, +v verbosity option, with timing and memory use output. * - fast-reload, option for fast-reload commandline, +p does not pause threads. * - fast-reload, option for fast-reload commandline, +d drops mesh queries. * - fast-reload, fix to poll every thread with nopause to make certain that resources are not held by the threads and can be deleted. * - fast-reload, fix to use atomic store for config variables with nopause. * - fast-reload, reload views. * - fast-reload, when tag defines are different, it drops the queries. * - fast-reload, fix tag define check. * - fast-reload, document that tag change causes drop of queries. * - fast-reload, fix space in documentation man page. * - fast-reload, copy respip client information to query state, put views tree in module env for lookup. * - fast-reload, nicer respip view comparison. * - fast-reload, respip global set is in module env. * - fast-reload, document that respip_client_info acl info is copied. * - fast-reload, reload the respip_set. * - fast-reload, document no pause and pick up of use_response_ip boolean. * - fast-reload, fix test compile. * - fast-reload, reload local zones. * Update locking management for iter_fwd and iter_hints methods. (#1054) fast reload, move most of the locking management to iter_fwd and iter_hints methods. The caller still has the ability to handle its own locking, if desired, for atomic operations on sets of different structs. Co-authored-by: Wouter Wijngaards <wcawijngaards@users.noreply.github.com> * - fast-reload, reload access-control. * - fast-reload, reload access control interface, such as interface-action. * - fast-reload, reload tcp-connection-limit. * - fast-reload, improve comments on acl_list and tcl_list swap tree. * - fast-reload, fixup references to old tcp connection limits in open tcp connections. * - fast-reload, fixup to clean tcp connection also for different linked order. * - fast-reload, if no tcp connection limits existed, no need to remove references for that. * - fast-reload, document more options that work and do not work. * - fast-reload, reload auth_zone and rpz data. * - fast-reload, fix auth_zones_get_mem. * - fast-reload, fix compilation of testbound for the new comm_timer_get_mem reference in remote control. * - fast-reload, change use_rpz with reload. * - fast-reload, list changes in auth zones and stop zonemd callbacks for deleted auth zones. * - fast-reload, note xtree is not swapped, and why it is not swapped. * - fast-reload, for added auth zones, pick up zone transfer and zonemd tasks. * - fast-reload, unlock xfr when done with transfer pick up. * - fast-reload, unlock z when picking up the xfr for it during transfer task pick up. * - fast-reload, pick up task changes for added, deleted and modified auth zones. * - fast-reload, remove xfr of auth zone deletion without tasks. * - fast-reload, pick up zone transfer config. * - fast-reload, the main worker thread picks up the transfer tasks and also performs setup of the xfer struct. * - fast-reload, keep writelock on newzone when auth zone changes. * - fast-reload, change cachedb_enabled setting. * - fast-reload, pick up edns-strings config. * - fast-reload, note that settings are not updated. * - fast-reload, pick up dnstap config. * - fast-reload, dnstap options that need to be loaded without +p. * - fast-reload, fix auth zone reload * - fast-reload, remove debug for auth zone test. * - fast-reload, fix auth zone reload with zone transfer. * - fast-reload, fix auth zone reload lock order. * - fast-reload, remove debug from fast reload test. * - fast-reload, remove unused function. * - fast-reload, fix the worker trust anchor probe timer lock acquisition in the probe answer callback routine for trust anchor probes. * - fast-reload, reload trust anchors. * - fast-reload, fix trust anchor reload lock on autr global data and test for trust anchor reload. * - fast-reload, adjust cache sizes. * - fast-reload, reload cache sizes when changed. * - fast-reload, reload validator env changes. * - fast-reload, reload mesh changes. * - fast-reload, check for incompatible changes. * - fast-reload, improve error text for incompatible change. * - fast-reload, fix check config option compatibility. * - fast-reload, improve error text for nopause change. * - fast-reload, fix spelling of incompatible options. * - fast-reload, reload target-fetch-policy, outbound-msg-retry, max-sent-count and max-query-restarts. * - fast-reload, check nopause config change for target-fetch-policy. * - fast-reload, reload do-not-query-address, private-address and capt-exempt. * - fast-reload, check nopause config change for do-not-query-address, private-address and capt-exempt. * - fast-reload, check fast reload not possible due to interface and outgoing-interface changes. * - fast-reload, reload nat64 settings. * - fast-reload, reload settings stored in the infra structure. * - fast-reload, fix modstack lookup and remove outgoing-range check. * - fast-reload, more explanation for config parse failure. * - fast-reload, reload worker outside network changes. * - fast-reload, detect incompatible changes in network settings. * fast-reload, commit test files. * - fast-reload, fix warnings for call types in windows compile. * - fast-reload, fix warnings and comm_point_internal for tcp wouldblock calls. * - fast-reload, extend lock checks for repeat thread ids. * - fast-reload, additional test cases, cache change and tag changes. * - fast-reload, fix documentation for auth_zone_verify_zonemd_with_key. * - fast-reload, fix copy_cfg type casts and memory leak on config parse failure. * - fast-reload, fix use of WSAPoll. * Review comments for the fast reload feature (#1259) * - fast-reload review, respip set can be null from a view. * - fast-reload review, typos. * - fast-reload review, keep clang static analyzer happy. * - fast-reload review, don't forget to copy tag_actions. * - fast-reload review, less indentation. * - fast-reload review, don't leak respip_actions when reloading. * - fast-reload review, protect NULL pointer dereference in get_mem functions. * - fast-reload review, add fast_reload_most_options.tdir to test most options with high verbosity when fast reloading. * - fast-reload review, don't skip new line on long error printouts. * - fast-reload review, typo. * - fast-reload review, use new_z for consistency. * - fast-reload review, nit for unlock ordering to make eye comparison with the lock counterpart easier. * - fast-reload review, in case of error the sockets are already closed. * - fast-reload review, identation. * - fast-reload review, add static keywords. * - fast-reload review, update unbound-control usage text. * - fast-reload review, updates to the man page. * - fast-reload, the fast-reload command is experimental. * - fast-reload, fix compile of doqclient for fast reload functions. * Changelog comment for #1042 - Merge #1042: Fast Reload. The unbound-control fast_reload is added. It reads changed config in a thread, then only briefly pauses the service threads, that keep running. DNS service is only interrupted briefly, less than a second. --------- Co-authored-by: Yorgos Thessalonikefs <yorgos@nlnetlabs.nl>
2025-03-31 09:25:24 -04:00
void
forwards_swap_tree(struct iter_forwards* fwd, struct iter_forwards* data)
{
rbtree_type* oldtree = fwd->tree;
if(oldtree) {
lock_unprotect(&fwd->lock, oldtree);
}
if(data->tree) {
lock_unprotect(&data->lock, data->tree);
}
fwd->tree = data->tree;
data->tree = oldtree;
lock_protect(&fwd->lock, fwd->tree, sizeof(*fwd->tree));
lock_protect(&data->lock, data->tree, sizeof(*data->tree));
}