From 4304754c76dc8ac6e7856293048797d028eaddd9 Mon Sep 17 00:00:00 2001 From: "W.C.A. Wijngaards" Date: Thu, 4 Jan 2024 16:53:02 +0100 Subject: [PATCH] - fast-reload, unshare forwards, making the structure locked, with an rwlock. --- Makefile.in | 6 +++--- cachedb/cachedb.c | 3 ++- daemon/cachedump.c | 9 +++++++-- daemon/daemon.c | 6 ++++++ daemon/remote.c | 43 +++++++++++++++++++++++++++++++---------- daemon/worker.c | 7 ------- edns-subnet/subnetmod.c | 2 +- iterator/iter_fwd.c | 21 +++++++++++++++++--- iterator/iter_fwd.h | 10 ++++++++++ iterator/iter_utils.c | 27 +++++++++++++++++++++----- iterator/iter_utils.h | 6 +++++- iterator/iterator.c | 43 +++++++++++++++++++++++++++-------------- libunbound/context.c | 4 ++++ libunbound/libunbound.c | 2 ++ libunbound/libworker.c | 9 +-------- util/module.h | 2 +- 16 files changed, 143 insertions(+), 57 deletions(-) diff --git a/Makefile.in b/Makefile.in index 2ed4d1199..4c37a980a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1278,7 +1278,7 @@ daemon.lo daemon.o: $(srcdir)/daemon/daemon.c config.h $(srcdir)/daemon/daemon.h $(srcdir)/util/edns.h $(srcdir)/services/listen_dnsport.h $(srcdir)/services/cache/rrset.h \ $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/services/localzone.h \ $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h $(srcdir)/services/rpz.h $(srcdir)/respip/respip.h \ - $(srcdir)/util/random.h $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h + $(srcdir)/util/random.h $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h $(srcdir)/iterator/iter_fwd.h remote.lo remote.o: $(srcdir)/daemon/remote.c config.h $(srcdir)/daemon/remote.h $(srcdir)/daemon/worker.h \ $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h $(srcdir)/util/data/packed_rrset.h \ $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/netevent.h \ @@ -1484,7 +1484,7 @@ context.lo context.o: $(srcdir)/libunbound/context.c config.h $(srcdir)/libunbou $(srcdir)/util/storage/slabhash.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h \ $(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \ $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h $(srcdir)/services/rpz.h $(srcdir)/daemon/stats.h \ - $(srcdir)/util/timehist.h $(srcdir)/respip/respip.h $(srcdir)/util/edns.h + $(srcdir)/util/timehist.h $(srcdir)/respip/respip.h $(srcdir)/util/edns.h $(srcdir)/iterator/iter_fwd.h libunbound.lo libunbound.o: $(srcdir)/libunbound/libunbound.c $(srcdir)/libunbound/unbound.h \ $(srcdir)/libunbound/unbound-event.h config.h $(srcdir)/libunbound/context.h $(srcdir)/util/locks.h \ $(srcdir)/util/log.h $(srcdir)/util/alloc.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h \ @@ -1496,7 +1496,7 @@ libunbound.lo libunbound.o: $(srcdir)/libunbound/libunbound.c $(srcdir)/libunbou $(srcdir)/sldns/sbuffer.h $(srcdir)/services/cache/infra.h $(srcdir)/util/rtt.h $(srcdir)/util/netevent.h \ $(srcdir)/dnscrypt/dnscrypt.h $(srcdir)/services/cache/rrset.h \ $(srcdir)/util/storage/slabhash.h $(srcdir)/services/authzone.h $(srcdir)/services/mesh.h \ - $(srcdir)/services/rpz.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/respip/respip.h + $(srcdir)/services/rpz.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/respip/respip.h $(srcdir)/iterator/iter_fwd.h libworker.lo libworker.o: $(srcdir)/libunbound/libworker.c config.h $(srcdir)/libunbound/libworker.h \ $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \ $(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h $(srcdir)/util/rbtree.h $(srcdir)/services/modstack.h \ diff --git a/cachedb/cachedb.c b/cachedb/cachedb.c index b912be8ed..aa8b2645a 100644 --- a/cachedb/cachedb.c +++ b/cachedb/cachedb.c @@ -666,6 +666,7 @@ cachedb_extcache_store(struct module_qstate* qstate, struct cachedb_env* ie) static int cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde) { + uint8_t dpname_storage[LDNS_MAX_DOMAINLEN+1]; uint8_t* dpname=NULL; size_t dpnamelen=0; struct dns_msg* msg; @@ -674,7 +675,7 @@ cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde) return 0; } if(iter_stub_fwd_no_cache(qstate, &qstate->qinfo, - &dpname, &dpnamelen)) + &dpname, &dpnamelen, dpname_storage, sizeof(dpname_storage))) return 0; /* no cache for these queries */ msg = dns_cache_lookup(qstate->env, qstate->qinfo.qname, qstate->qinfo.qname_len, qstate->qinfo.qtype, diff --git a/daemon/cachedump.c b/daemon/cachedump.c index 61ee1d291..d12168008 100644 --- a/daemon/cachedump.c +++ b/daemon/cachedump.c @@ -850,15 +850,20 @@ int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm, if(!ssl_printf(ssl, "The following name servers are used for lookup " "of %s\n", b)) return 0; - + + lock_rw_rdlock(&worker->env.fwds->lock); dp = forwards_lookup(worker->env.fwds, nm, qinfo.qclass); if(dp) { - if(!ssl_printf(ssl, "forwarding request:\n")) + if(!ssl_printf(ssl, "forwarding request:\n")) { + lock_rw_unlock(&worker->env.fwds->lock); return 0; + } print_dp_main(ssl, dp, NULL); print_dp_details(ssl, worker, dp); + lock_rw_unlock(&worker->env.fwds->lock); return 1; } + lock_rw_unlock(&worker->env.fwds->lock); while(1) { dp = dns_cache_find_delegation(&worker->env, nm, nmlen, diff --git a/daemon/daemon.c b/daemon/daemon.c index b229d2edb..8f672950a 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -91,6 +91,7 @@ #include "util/net_help.h" #include "sldns/keyraw.h" #include "respip/respip.h" +#include "iterator/iter_fwd.h" #include #ifdef HAVE_SYSTEMD @@ -716,6 +717,9 @@ daemon_fork(struct daemon* daemon) fatal_exit("Could not create local zones: out of memory"); if(!local_zones_apply_cfg(daemon->local_zones, daemon->cfg)) fatal_exit("Could not set up local zones"); + if(!(daemon->env->fwds = forwards_create()) || + !forwards_apply_cfg(daemon->env->fwds, daemon->cfg)) + fatal_exit("Could not set forward zones"); /* process raw response-ip configuration data */ if(!(daemon->respip_set = respip_set_create())) @@ -832,6 +836,8 @@ daemon_cleanup(struct daemon* daemon) slabhash_clear(daemon->env->msg_cache); } daemon->old_num = daemon->num; /* save the current num */ + forwards_delete(daemon->env->fwds); + daemon->env->fwds = NULL; local_zones_delete(daemon->local_zones); daemon->local_zones = NULL; respip_set_delete(daemon->respip_set); diff --git a/daemon/remote.c b/daemon/remote.c index 1d6b18978..bc275ab9e 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -2022,12 +2022,20 @@ static int print_root_fwds(RES* ssl, struct iter_forwards* fwds, uint8_t* root) { struct delegpt* dp; + lock_rw_rdlock(&fwds->lock); dp = forwards_lookup(fwds, root, LDNS_RR_CLASS_IN); - if(!dp) + if(!dp) { + lock_rw_unlock(&fwds->lock); return ssl_printf(ssl, "off (using root hints)\n"); + } /* if dp is returned it must be the root */ log_assert(query_dname_compare(dp->name, root)==0); - return ssl_print_name_dp(ssl, NULL, root, LDNS_RR_CLASS_IN, dp); + if(!ssl_print_name_dp(ssl, NULL, root, LDNS_RR_CLASS_IN, dp)) { + lock_rw_unlock(&fwds->lock); + return 0; + } + lock_rw_unlock(&fwds->lock); + return 1; } /** parse args into delegpt */ @@ -2112,15 +2120,20 @@ do_forward(RES* ssl, struct worker* worker, char* args) /* delete all the existing queries first */ mesh_delete_all(worker->env.mesh); if(strcmp(args, "off") == 0) { + lock_rw_wrlock(&fwd->lock); forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, root); + lock_rw_unlock(&fwd->lock); } else { struct delegpt* dp; if(!(dp = parse_delegpt(ssl, args, root))) return; + lock_rw_wrlock(&fwd->lock); if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp)) { + lock_rw_unlock(&fwd->lock); (void)ssl_printf(ssl, "error out of memory\n"); return; } + lock_rw_unlock(&fwd->lock); } send_ok(ssl); } @@ -2179,9 +2192,11 @@ do_forward_add(RES* ssl, struct worker* worker, char* args) struct delegpt* dp = NULL; if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, NULL)) return; + lock_rw_wrlock(&fwd->lock); if(insecure && worker->env.anchors) { if(!anchors_add_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, nm)) { + lock_rw_unlock(&fwd->lock); (void)ssl_printf(ssl, "error out of memory\n"); delegpt_free_mlc(dp); free(nm); @@ -2189,10 +2204,12 @@ do_forward_add(RES* ssl, struct worker* worker, char* args) } } if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp)) { + lock_rw_unlock(&fwd->lock); (void)ssl_printf(ssl, "error out of memory\n"); free(nm); return; } + lock_rw_unlock(&fwd->lock); free(nm); send_ok(ssl); } @@ -2206,10 +2223,12 @@ do_forward_remove(RES* ssl, struct worker* worker, char* args) uint8_t* nm = NULL; if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL)) return; + lock_rw_wrlock(&fwd->lock); if(insecure && worker->env.anchors) anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, nm); forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, nm); + lock_rw_unlock(&fwd->lock); free(nm); send_ok(ssl); } @@ -2224,6 +2243,7 @@ do_stub_add(RES* ssl, struct worker* worker, char* args) struct delegpt* dp = NULL; if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, &prime)) return; + lock_rw_wrlock(&fwd->lock); if(insecure && worker->env.anchors) { if(!anchors_add_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, nm)) { @@ -2237,6 +2257,7 @@ do_stub_add(RES* ssl, struct worker* worker, char* args) if(insecure && worker->env.anchors) anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, nm); + lock_rw_unlock(&fwd->lock); (void)ssl_printf(ssl, "error out of memory\n"); delegpt_free_mlc(dp); free(nm); @@ -2248,9 +2269,11 @@ do_stub_add(RES* ssl, struct worker* worker, char* args) if(insecure && worker->env.anchors) anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, nm); + lock_rw_unlock(&fwd->lock); free(nm); return; } + lock_rw_unlock(&fwd->lock); free(nm); send_ok(ssl); } @@ -2264,11 +2287,13 @@ do_stub_remove(RES* ssl, struct worker* worker, char* args) uint8_t* nm = NULL; if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL)) return; + lock_rw_wrlock(&fwd->lock); if(insecure && worker->env.anchors) anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, nm); forwards_delete_stub_hole(fwd, LDNS_RR_CLASS_IN, nm); hints_delete_stub(worker->env.hints, LDNS_RR_CLASS_IN, nm); + lock_rw_unlock(&fwd->lock); free(nm); send_ok(ssl); } @@ -2697,6 +2722,7 @@ do_list_forwards(RES* ssl, struct worker* worker) struct iter_forward_zone* z; struct trust_anchor* a; int insecure; + lock_rw_rdlock(&fwds->lock); RBTREE_FOR(z, struct iter_forward_zone*, fwds->tree) { if(!z->dp) continue; /* skip empty marker for stub */ @@ -2711,9 +2737,12 @@ do_list_forwards(RES* ssl, struct worker* worker) } if(!ssl_print_name_dp(ssl, (insecure?"forward +i":"forward"), - z->name, z->dclass, z->dp)) + z->name, z->dclass, z->dp)) { + lock_rw_unlock(&fwds->lock); return; + } } + lock_rw_unlock(&fwds->lock); } /** do the list_stubs command */ @@ -3115,13 +3144,9 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, do_stub_remove(ssl, worker, skipwhite(p+11)); return; } else if(cmdcmp(p, "forward_add", 11)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); do_forward_add(ssl, worker, skipwhite(p+11)); return; } else if(cmdcmp(p, "forward_remove", 14)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); do_forward_remove(ssl, worker, skipwhite(p+14)); return; } else if(cmdcmp(p, "insecure_add", 12)) { @@ -3135,8 +3160,6 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, do_insecure_remove(ssl, worker, skipwhite(p+15)); return; } else if(cmdcmp(p, "forward", 7)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); do_forward(ssl, worker, skipwhite(p+7)); return; } else if(cmdcmp(p, "flush_stats", 11)) { @@ -4564,7 +4587,7 @@ fr_printq_remove(struct fast_reload_printq* printq) { if(!printq) return; - if(printq->worker && printq->worker->daemon->fast_reload_thread && + if(printq->worker->daemon->fast_reload_thread && printq->worker->daemon->fast_reload_thread->printq == printq) printq->worker->daemon->fast_reload_thread->printq = NULL; if(printq->in_list) diff --git a/daemon/worker.c b/daemon/worker.c index aeadf32d4..8ac28ba19 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -2268,12 +2268,6 @@ worker_init(struct worker* worker, struct config_file *cfg, worker_delete(worker); return 0; } - if(!(worker->env.fwds = forwards_create()) || - !forwards_apply_cfg(worker->env.fwds, cfg)) { - log_err("Could not set forward zones"); - worker_delete(worker); - return 0; - } if(!(worker->env.hints = hints_create()) || !hints_apply_cfg(worker->env.hints, cfg)) { log_err("Could not set root or stub hints"); @@ -2352,7 +2346,6 @@ worker_delete(struct worker* worker) outside_network_quit_prepare(worker->back); mesh_delete(worker->env.mesh); sldns_buffer_free(worker->env.scratch_buffer); - forwards_delete(worker->env.fwds); hints_delete(worker->env.hints); listen_delete(worker->front); outside_network_delete(worker->back); diff --git a/edns-subnet/subnetmod.c b/edns-subnet/subnetmod.c index cefde84e5..2e663b1af 100644 --- a/edns-subnet/subnetmod.c +++ b/edns-subnet/subnetmod.c @@ -152,7 +152,7 @@ int ecs_whitelist_check(struct query_info* qinfo, /* Cache by default, might be disabled after parsing EDNS option * received from nameserver. */ - if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL)) { + if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)) { qstate->no_cache_store = 0; } diff --git a/iterator/iter_fwd.c b/iterator/iter_fwd.c index 151372912..cf418b072 100644 --- a/iterator/iter_fwd.c +++ b/iterator/iter_fwd.c @@ -71,6 +71,7 @@ forwards_create(void) sizeof(struct iter_forwards)); if(!fwd) return NULL; + lock_rw_init(&fwd->lock); return fwd; } @@ -100,6 +101,7 @@ forwards_delete(struct iter_forwards* fwd) { if(!fwd) return; + lock_rw_destroy(&fwd->lock); fwd_del_tree(fwd); free(fwd); } @@ -332,17 +334,27 @@ make_stub_holes(struct iter_forwards* fwd, struct config_file* cfg) 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)) + if(!read_forwards(fwd, cfg)) { + lock_rw_unlock(&fwd->lock); return 0; - if(!make_stub_holes(fwd, cfg)) + } + if(!make_stub_holes(fwd, cfg)) { + lock_rw_unlock(&fwd->lock); return 0; + } fwd_init_parents(fwd); + lock_rw_unlock(&fwd->lock); return 1; } @@ -458,10 +470,12 @@ forwards_get_mem(struct iter_forwards* fwd) 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; } @@ -504,6 +518,8 @@ forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm) int forwards_add_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm) { + if(fwd_zone_find(fwd, c, nm) != NULL) + return 1; /* already a stub zone there */ if(!fwd_add_stub_hole(fwd, c, nm)) { return 0; } @@ -523,4 +539,3 @@ forwards_delete_stub_hole(struct iter_forwards* fwd, uint16_t c, uint8_t* nm) fwd_zone_free(z); fwd_init_parents(fwd); } - diff --git a/iterator/iter_fwd.h b/iterator/iter_fwd.h index e90b74c16..75ac597bd 100644 --- a/iterator/iter_fwd.h +++ b/iterator/iter_fwd.h @@ -43,6 +43,7 @@ #ifndef ITERATOR_ITER_FWD_H #define ITERATOR_ITER_FWD_H #include "util/rbtree.h" +#include "util/locks.h" struct config_file; struct delegpt; @@ -50,6 +51,10 @@ struct delegpt; * Iterator forward zones structure */ struct iter_forwards { + /** lock on the forwards tree. + * When grabbing both this lock and the anchors.lock, this lock + * is grabbed first. */ + lock_rw_type lock; /** * Zones are stored in this tree. Sort order is specially chosen. * first sorted on qclass. Then on dname in nsec-like order, so that @@ -106,6 +111,8 @@ int forwards_apply_cfg(struct iter_forwards* fwd, struct config_file* cfg); /** * Find forward zone exactly by name + * The return value is contents of the forwards structure, caller should + * lock and unlock a readlock on the forwards structure. * @param fwd: forward storage. * @param qname: The qname of the query. * @param qclass: The qclass of the query. @@ -118,6 +125,8 @@ struct delegpt* forwards_find(struct iter_forwards* fwd, uint8_t* qname, * Find forward zone information * For this qname/qclass find forward zone information, returns delegation * point with server names and addresses, or NULL if no forwarding is needed. + * The return value is contents of the forwards structure, caller should + * lock and unlock a readlock on the forwards structure. * * @param fwd: forward storage. * @param qname: The qname of the query. @@ -147,6 +156,7 @@ int forwards_next_root(struct iter_forwards* fwd, uint16_t* qclass); /** * Get memory in use by forward storage + * Locks and unlocks the structure. * @param fwd: forward storage. * @return bytes in use */ diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index 10a8ec3eb..c1c4999ad 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -1285,7 +1285,12 @@ iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd, { uint16_t c1 = *c, c2 = *c; int r1 = hints_next_root(hints, &c1); - int r2 = forwards_next_root(fwd, &c2); + int r2; + + lock_rw_rdlock(&fwd->lock); + r2 = forwards_next_root(fwd, &c2); + lock_rw_unlock(&fwd->lock); + if(!r1 && !r2) /* got none, end of list */ return 0; else if(!r1) /* got one, return that */ @@ -1450,7 +1455,8 @@ int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp) int iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf, - uint8_t** retdpname, size_t* retdpnamelen) + uint8_t** retdpname, size_t* retdpnamelen, uint8_t* dpname_storage, + size_t dpname_storage_len) { struct iter_hints_stub *stub; struct delegpt *dp; @@ -1458,6 +1464,7 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf, /* Check for stub. */ stub = hints_lookup_stub(qstate->env->hints, qinf->qname, qinf->qclass, NULL); + lock_rw_rdlock(&qstate->env->fwds->lock); dp = forwards_lookup(qstate->env->fwds, qinf->qname, qinf->qclass); /* see if forward or stub is more pertinent */ @@ -1472,6 +1479,7 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf, /* check stub */ if (stub != NULL && stub->dp != NULL) { + lock_rw_unlock(&qstate->env->fwds->lock); if(stub->dp->no_cache) { char qname[255+1]; char dpname[255+1]; @@ -1488,7 +1496,8 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf, /* Check for forward. */ if (dp) { - if(dp->no_cache) { + int dp_no_cache = dp->no_cache; + if(dp_no_cache) { char qname[255+1]; char dpname[255+1]; dname_str(qinf->qname, qname); @@ -1496,11 +1505,19 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf, verbose(VERB_ALGO, "forward for %s %s has no_cache", qname, dpname); } if(retdpname) { - *retdpname = dp->name; + if(dp->namelen > dpname_storage_len) { + verbose(VERB_ALGO, "no cache dpname too long"); + lock_rw_unlock(&qstate->env->fwds->lock); + return (dp_no_cache); + } + memmove(dpname_storage, dp->name, dp->namelen); + *retdpname = dpname_storage; *retdpnamelen = dp->namelen; } - return (dp->no_cache); + lock_rw_unlock(&qstate->env->fwds->lock); + return (dp_no_cache); } + lock_rw_unlock(&qstate->env->fwds->lock); if(retdpname) { *retdpname = NULL; *retdpnamelen = 0; diff --git a/iterator/iter_utils.h b/iterator/iter_utils.h index fa860fa68..4024629e6 100644 --- a/iterator/iter_utils.h +++ b/iterator/iter_utils.h @@ -407,10 +407,14 @@ int iter_dp_cangodown(struct query_info* qinfo, struct delegpt* dp); * Used for NXDOMAIN checks, above that it is an nxdomain from a * different server and zone. You can pass NULL to not get it. * @param retdpnamelen: returns the length of the dpname. + * @param dpname_storage: this is where the dpname buf is stored, if any. + * So that caller can manage the buffer. + * @param dpname_storage_len: size of dpname_storage buffer. * @return true if no_cache is set in stub or fwd. */ int iter_stub_fwd_no_cache(struct module_qstate *qstate, - struct query_info *qinf, uint8_t** retdpname, size_t* retdpnamelen); + struct query_info *qinf, uint8_t** retdpname, size_t* retdpnamelen, + uint8_t* dpname_storage, size_t dpname_storage_len); /** * Set support for IP4 and IP6 depending on outgoing interfaces diff --git a/iterator/iterator.c b/iterator/iterator.c index 6ff811a27..45d278254 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -679,7 +679,8 @@ errinf_reply(struct module_qstate* qstate, struct iter_qstate* iq) /** see if last resort is possible - does config allow queries to parent */ static int can_have_last_resort(struct module_env* env, uint8_t* nm, size_t nmlen, - uint16_t qclass, struct delegpt** retdp) + uint16_t qclass, int* have_dp, struct delegpt** retdp, + struct regional* region) { struct delegpt* fwddp; struct iter_hints_stub* stub; @@ -693,15 +694,20 @@ can_have_last_resort(struct module_env* env, uint8_t* nm, size_t nmlen, * are allowed to go to the parent */ stub->dp->has_parent_side_NS) { if(retdp) *retdp = stub->dp; + if(have_dp) *have_dp = 1; return 0; } + lock_rw_rdlock(&env->fwds->lock); if((fwddp = forwards_find(env->fwds, nm, qclass)) && /* has_parent_side is turned off for forward_first, where * we are allowed to go to the parent */ fwddp->has_parent_side_NS) { - if(retdp) *retdp = fwddp; + if(retdp) *retdp = delegpt_copy(fwddp, region); + lock_rw_unlock(&env->fwds->lock); + if(have_dp) *have_dp = 1; return 0; } + lock_rw_unlock(&env->fwds->lock); return 1; } @@ -1181,7 +1187,7 @@ generate_ns_check(struct module_qstate* qstate, struct iter_qstate* iq, int id) if(iq->depth == ie->max_dependency_depth) return; if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, - iq->qchase.qclass, NULL)) + iq->qchase.qclass, NULL, NULL, NULL)) return; /* is this query the same as the nscheck? */ if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS && @@ -1302,12 +1308,16 @@ forward_request(struct module_qstate* qstate, struct iter_qstate* iq) if( (iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue) && !dname_is_root(iq->qchase.qname)) dname_remove_label(&delname, &delnamelen); + lock_rw_rdlock(&qstate->env->fwds->lock); dp = forwards_lookup(qstate->env->fwds, delname, iq->qchase.qclass); - if(!dp) + if(!dp) { + lock_rw_unlock(&qstate->env->fwds->lock); return 0; + } /* send recursion desired to forward addr */ iq->chase_flags |= BIT_RD; iq->dp = delegpt_copy(dp, qstate->region); + lock_rw_unlock(&qstate->env->fwds->lock); /* iq->dp checked by caller */ verbose(VERB_ALGO, "forwarding request"); return 1; @@ -1335,6 +1345,7 @@ static int processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, struct iter_env* ie, int id) { + uint8_t dpname_storage[LDNS_MAX_DOMAINLEN+1]; uint8_t* delname, *dpname=NULL; size_t delnamelen, dpnamelen=0; struct dns_msg* msg = NULL; @@ -1381,7 +1392,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, if (iq->refetch_glue && iq->dp && !can_have_last_resort(qstate->env, iq->dp->name, - iq->dp->namelen, iq->qchase.qclass, NULL)) { + iq->dp->namelen, iq->qchase.qclass, NULL, NULL, NULL)) { iq->refetch_glue = 0; } @@ -1390,7 +1401,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, /* This either results in a query restart (CNAME cache response), a * terminating response (ANSWER), or a cache miss (null). */ - if (iter_stub_fwd_no_cache(qstate, &iq->qchase, &dpname, &dpnamelen)) { + if (iter_stub_fwd_no_cache(qstate, &iq->qchase, &dpname, &dpnamelen, + dpname_storage, sizeof(dpname_storage))) { /* Asked to not query cache. */ verbose(VERB_ALGO, "no-cache set, going to the network"); qstate->no_cache_lookup = 1; @@ -1555,7 +1567,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, } if(iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue || (iq->qchase.qtype == LDNS_RR_TYPE_NS && qstate->prefetch_leeway - && can_have_last_resort(qstate->env, delname, delnamelen, iq->qchase.qclass, NULL))) { + && can_have_last_resort(qstate->env, delname, delnamelen, iq->qchase.qclass, NULL, NULL, NULL))) { /* remove first label from delname, root goes to hints, * but only to fetch glue, not for qtype=DS. */ /* also when prefetching an NS record, fetch it again from @@ -1597,8 +1609,10 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, break; /* got noprime-stub-zone, continue */ else if(r) return 0; /* stub prime request made */ + lock_rw_rdlock(&qstate->env->fwds->lock); if(forwards_lookup_root(qstate->env->fwds, iq->qchase.qclass)) { + lock_rw_unlock(&qstate->env->fwds->lock); /* forward zone root, no root prime needed */ /* fill in some dp - safety belt */ iq->dp = hints_lookup_root(qstate->env->hints, @@ -1618,6 +1632,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, } return next_state(iq, INIT_REQUEST_2_STATE); } + lock_rw_unlock(&qstate->env->fwds->lock); /* Note that the result of this will set a new * DelegationPoint based on the result of priming. */ if(!prime_root(qstate, iq, id, iq->qchase.qclass)) @@ -1649,15 +1664,13 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, if(iter_dp_is_useless(&qstate->qinfo, qstate->query_flags, iq->dp, ie->supports_ipv4, ie->supports_ipv6, ie->use_nat64)) { - struct delegpt* retdp = NULL; - if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, iq->qchase.qclass, &retdp)) { - if(retdp) { + int have_dp = 0; + if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, iq->qchase.qclass, &have_dp, &iq->dp, qstate->region)) { + if(have_dp) { verbose(VERB_QUERY, "cache has stub " "or fwd but no addresses, " "fallback to config"); - iq->dp = delegpt_copy(retdp, - qstate->region); - if(!iq->dp) { + if(have_dp && !iq->dp) { log_err("out of memory in " "stub/fwd fallback"); errinf(qstate, "malloc failure, for fallback to config"); @@ -2062,7 +2075,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, log_assert(iq->dp); if(!can_have_last_resort(qstate->env, iq->dp->name, iq->dp->namelen, - iq->qchase.qclass, NULL)) { + iq->qchase.qclass, NULL, NULL, NULL)) { /* fail -- no more targets, no more hope of targets, no hope * of a response. */ errinf(qstate, "all the configured stub or forward servers failed,"); @@ -2164,7 +2177,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, if( ((ie->supports_ipv6 && !ns->done_pside6) || ((ie->supports_ipv4 || ie->use_nat64) && !ns->done_pside4)) && !can_have_last_resort(qstate->env, ns->name, ns->namelen, - iq->qchase.qclass, NULL)) { + iq->qchase.qclass, NULL, NULL, NULL)) { log_nametypeclass(VERB_ALGO, "cannot pside lookup ns " "because it is also a stub/forward,", ns->name, LDNS_RR_TYPE_NS, iq->qchase.qclass); diff --git a/libunbound/context.c b/libunbound/context.c index f7c0a2cd5..f3a57d43d 100644 --- a/libunbound/context.c +++ b/libunbound/context.c @@ -53,6 +53,7 @@ #include "util/storage/slabhash.h" #include "util/edns.h" #include "sldns/sbuffer.h" +#include "iterator/iter_fwd.h" int context_finalize(struct ub_ctx* ctx) @@ -85,6 +86,9 @@ context_finalize(struct ub_ctx* ctx) if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz, ctx->env, &ctx->mods)) return UB_INITFAIL; + if(!(ctx->env->fwds = forwards_create()) || + !forwards_apply_cfg(ctx->env->fwds, cfg)) + return UB_INITFAIL; if(!edns_strings_apply_cfg(ctx->env->edns_strings, cfg)) return UB_INITFAIL; if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size, diff --git a/libunbound/libunbound.c b/libunbound/libunbound.c index 80a82bb47..68e1990bc 100644 --- a/libunbound/libunbound.c +++ b/libunbound/libunbound.c @@ -66,6 +66,7 @@ #include "services/authzone.h" #include "services/listen_dnsport.h" #include "sldns/sbuffer.h" +#include "iterator/iter_fwd.h" #ifdef HAVE_PTHREAD #include #endif @@ -379,6 +380,7 @@ ub_ctx_delete(struct ub_ctx* ctx) config_delete(ctx->env->cfg); edns_known_options_delete(ctx->env); edns_strings_delete(ctx->env->edns_strings); + forwards_delete(ctx->env->fwds); auth_zones_delete(ctx->env->auth_zones); free(ctx->env); } diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 412293f9a..9149365c8 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -100,7 +100,6 @@ libworker_delete_env(struct libworker* w) !w->is_bg || w->is_bg_thread); sldns_buffer_free(w->env->scratch_buffer); regional_destroy(w->env->scratch); - forwards_delete(w->env->fwds); hints_delete(w->env->hints); ub_randfree(w->env->rnd); free(w->env); @@ -159,11 +158,6 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb) } w->env->scratch = regional_create_custom(cfg->msg_buffer_size); w->env->scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size); - w->env->fwds = forwards_create(); - if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) { - forwards_delete(w->env->fwds); - w->env->fwds = NULL; - } w->env->hints = hints_create(); if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) { hints_delete(w->env->hints); @@ -181,8 +175,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb) if(!w->is_bg || w->is_bg_thread) { lock_basic_unlock(&ctx->cfglock); } - if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds || - !w->env->hints) { + if(!w->env->scratch || !w->env->scratch_buffer || !w->env->hints) { libworker_delete(w); return NULL; } diff --git a/util/module.h b/util/module.h index 8a9da3f93..65b82b59c 100644 --- a/util/module.h +++ b/util/module.h @@ -511,7 +511,7 @@ struct module_env { /** auth zones */ struct auth_zones* auth_zones; /** Mapping of forwarding zones to targets. - * iterator forwarder information. per-thread, created by worker */ + * iterator forwarder information. */ struct iter_forwards* fwds; /** * iterator forwarder information. per-thread, created by worker. -- 2.47.2