From 39e5959406ffd009ca8a6f186c448a4ee42d7b2b Mon Sep 17 00:00:00 2001 From: "W.C.A. Wijngaards" Date: Fri, 5 Jan 2024 13:36:41 +0100 Subject: [PATCH] - fast-reload, unshared stub hints, making the structure locked, with an rwlock. --- Makefile.in | 12 +++++++----- daemon/cachedump.c | 13 ++++++++++--- daemon/daemon.c | 6 ++++++ daemon/remote.c | 28 +++++++++++++++++----------- daemon/worker.c | 7 ------- iterator/iter_fwd.h | 3 ++- iterator/iter_hints.c | 25 ++++++++++++++++++++----- iterator/iter_hints.h | 6 ++++++ iterator/iter_utils.c | 34 ++++++++++++++++++++++++++-------- iterator/iterator.c | 41 +++++++++++++++++++++++++++++++++++------ libunbound/context.c | 4 ++++ libunbound/libunbound.c | 2 ++ libunbound/libworker.c | 14 +++----------- pythonmod/interface.i | 6 +++++- util/module.h | 2 +- 15 files changed, 144 insertions(+), 59 deletions(-) diff --git a/Makefile.in b/Makefile.in index 4c37a980a..79379d8d1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1278,7 +1278,8 @@ 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)/iterator/iter_fwd.h + $(srcdir)/util/random.h $(srcdir)/util/tube.h $(srcdir)/util/net_help.h $(srcdir)/sldns/keyraw.h \ + $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.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 +1485,8 @@ 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)/iterator/iter_fwd.h + $(srcdir)/util/timehist.h $(srcdir)/respip/respip.h $(srcdir)/util/edns.h \ + $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.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 +1498,8 @@ 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)/iterator/iter_fwd.h + $(srcdir)/services/rpz.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h $(srcdir)/respip/respip.h \ + $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.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 \ @@ -1510,8 +1513,7 @@ libworker.lo libworker.o: $(srcdir)/libunbound/libworker.c config.h $(srcdir)/li $(srcdir)/services/cache/rrset.h $(srcdir)/util/storage/slabhash.h $(srcdir)/services/outbound_list.h \ $(srcdir)/util/fptr_wlist.h $(srcdir)/util/tube.h $(srcdir)/util/regional.h $(srcdir)/util/random.h \ $(srcdir)/util/storage/lookup3.h $(srcdir)/util/net_help.h $(srcdir)/util/data/dname.h \ - $(srcdir)/util/data/msgencode.h $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h \ - $(srcdir)/sldns/str2wire.h + $(srcdir)/util/data/msgencode.h $(srcdir)/sldns/str2wire.h unbound-host.lo unbound-host.o: $(srcdir)/smallapp/unbound-host.c config.h $(srcdir)/libunbound/unbound.h \ $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/wire2str.h asynclook.lo asynclook.o: $(srcdir)/testcode/asynclook.c config.h $(srcdir)/libunbound/unbound.h \ diff --git a/daemon/cachedump.c b/daemon/cachedump.c index d12168008..c7523497d 100644 --- a/daemon/cachedump.c +++ b/daemon/cachedump.c @@ -897,22 +897,29 @@ int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm, return 0; continue; } - } + } + lock_rw_rdlock(&worker->env.hints->lock); stub = hints_lookup_stub(worker->env.hints, nm, qinfo.qclass, dp); if(stub) { if(stub->noprime) { if(!ssl_printf(ssl, "The noprime stub servers " - "are used:\n")) + "are used:\n")) { + lock_rw_unlock(&worker->env.hints->lock); return 0; + } } else { if(!ssl_printf(ssl, "The stub is primed " - "with servers:\n")) + "with servers:\n")) { + lock_rw_unlock(&worker->env.hints->lock); return 0; + } } print_dp_main(ssl, stub->dp, NULL); print_dp_details(ssl, worker, stub->dp); + lock_rw_unlock(&worker->env.hints->lock); } else { + lock_rw_unlock(&worker->env.hints->lock); print_dp_main(ssl, dp, msg); print_dp_details(ssl, worker, dp); } diff --git a/daemon/daemon.c b/daemon/daemon.c index 8f672950a..75bae96ba 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -92,6 +92,7 @@ #include "sldns/keyraw.h" #include "respip/respip.h" #include "iterator/iter_fwd.h" +#include "iterator/iter_hints.h" #include #ifdef HAVE_SYSTEMD @@ -720,6 +721,9 @@ daemon_fork(struct daemon* daemon) if(!(daemon->env->fwds = forwards_create()) || !forwards_apply_cfg(daemon->env->fwds, daemon->cfg)) fatal_exit("Could not set forward zones"); + if(!(daemon->env->hints = hints_create()) || + !hints_apply_cfg(daemon->env->hints, daemon->cfg)) + fatal_exit("Could not set root or stub hints"); /* process raw response-ip configuration data */ if(!(daemon->respip_set = respip_set_create())) @@ -838,6 +842,8 @@ daemon_cleanup(struct daemon* daemon) daemon->old_num = daemon->num; /* save the current num */ forwards_delete(daemon->env->fwds); daemon->env->fwds = NULL; + hints_delete(daemon->env->hints); + daemon->env->hints = 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 18cc3dbbc..87246ddfe 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -2244,9 +2244,12 @@ do_stub_add(RES* ssl, struct worker* worker, char* args) if(!parse_fs_args(ssl, args, &nm, &dp, &insecure, &prime)) return; lock_rw_wrlock(&fwd->lock); + lock_rw_wrlock(&worker->env.hints->lock); if(insecure && worker->env.anchors) { if(!anchors_add_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, nm)) { + lock_rw_unlock(&fwd->lock); + lock_rw_unlock(&worker->env.hints->lock); (void)ssl_printf(ssl, "error out of memory\n"); delegpt_free_mlc(dp); free(nm); @@ -2258,6 +2261,7 @@ do_stub_add(RES* ssl, struct worker* worker, char* args) anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, nm); lock_rw_unlock(&fwd->lock); + lock_rw_unlock(&worker->env.hints->lock); (void)ssl_printf(ssl, "error out of memory\n"); delegpt_free_mlc(dp); free(nm); @@ -2270,10 +2274,12 @@ do_stub_add(RES* ssl, struct worker* worker, char* args) anchors_delete_insecure(worker->env.anchors, LDNS_RR_CLASS_IN, nm); lock_rw_unlock(&fwd->lock); + lock_rw_unlock(&worker->env.hints->lock); free(nm); return; } lock_rw_unlock(&fwd->lock); + lock_rw_unlock(&worker->env.hints->lock); free(nm); send_ok(ssl); } @@ -2288,12 +2294,14 @@ do_stub_remove(RES* ssl, struct worker* worker, char* args) if(!parse_fs_args(ssl, args, &nm, NULL, &insecure, NULL)) return; lock_rw_wrlock(&fwd->lock); + lock_rw_wrlock(&worker->env.hints->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); + lock_rw_unlock(&worker->env.hints->lock); free(nm); send_ok(ssl); } @@ -2753,6 +2761,7 @@ do_list_stubs(RES* ssl, struct worker* worker) struct trust_anchor* a; int insecure; char str[32]; + lock_rw_rdlock(&worker->env.hints->lock); RBTREE_FOR(z, struct iter_hints_stub*, &worker->env.hints->tree) { /* see if it is insecure */ @@ -2768,9 +2777,12 @@ do_list_stubs(RES* ssl, struct worker* worker) snprintf(str, sizeof(str), "stub %sprime%s", (z->noprime?"no":""), (insecure?" +i":"")); if(!ssl_print_name_dp(ssl, str, z->node.name, - z->node.dclass, z->dp)) + z->node.dclass, z->dp)) { + lock_rw_unlock(&worker->env.hints->lock); return; + } } + lock_rw_unlock(&worker->env.hints->lock); } /** do the list_auth_zones command */ @@ -3133,16 +3145,6 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, } else if(cmdcmp(p, "auth_zone_transfer", 18)) { do_auth_zone_transfer(ssl, worker, skipwhite(p+18)); return; - } else if(cmdcmp(p, "stub_add", 8)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); - do_stub_add(ssl, worker, skipwhite(p+8)); - return; - } else if(cmdcmp(p, "stub_remove", 11)) { - /* must always distribute this cmd */ - if(rc) distribute_cmd(rc, ssl, cmd); - do_stub_remove(ssl, worker, skipwhite(p+11)); - return; } else if(cmdcmp(p, "insecure_add", 12)) { /* must always distribute this cmd */ if(rc) distribute_cmd(rc, ssl, cmd); @@ -3200,6 +3202,10 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, do_forward_remove(ssl, worker, skipwhite(p+14)); } else if(cmdcmp(p, "forward", 7)) { do_forward(ssl, worker, skipwhite(p+7)); + } else if(cmdcmp(p, "stub_add", 8)) { + do_stub_add(ssl, worker, skipwhite(p+8)); + } else if(cmdcmp(p, "stub_remove", 11)) { + do_stub_remove(ssl, worker, skipwhite(p+11)); } else if(cmdcmp(p, "view_local_zone_remove", 22)) { do_view_zone_remove(ssl, worker, skipwhite(p+22)); } else if(cmdcmp(p, "view_local_zone", 15)) { diff --git a/daemon/worker.c b/daemon/worker.c index 8ac28ba19..c4ae79352 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.hints = hints_create()) || - !hints_apply_cfg(worker->env.hints, cfg)) { - log_err("Could not set root or stub hints"); - worker_delete(worker); - return 0; - } /* one probe timer per process -- if we have 5011 anchors */ if(autr_get_num_anchors(worker->env.anchors) > 0 #ifndef THREADS_DISABLED @@ -2346,7 +2340,6 @@ worker_delete(struct worker* worker) outside_network_quit_prepare(worker->back); mesh_delete(worker->env.mesh); sldns_buffer_free(worker->env.scratch_buffer); - hints_delete(worker->env.hints); listen_delete(worker->front); outside_network_delete(worker->back); comm_signal_delete(worker->comsig); diff --git a/iterator/iter_fwd.h b/iterator/iter_fwd.h index 75ac597bd..c1160b853 100644 --- a/iterator/iter_fwd.h +++ b/iterator/iter_fwd.h @@ -53,7 +53,8 @@ struct delegpt; struct iter_forwards { /** lock on the forwards tree. * When grabbing both this lock and the anchors.lock, this lock - * is grabbed first. */ + * is grabbed first. When grabbing both this lock and the hints.lock + * this lock is grabbed first. */ lock_rw_type lock; /** * Zones are stored in this tree. Sort order is specially chosen. diff --git a/iterator/iter_hints.c b/iterator/iter_hints.c index 4f86f3676..a56aa8e40 100644 --- a/iterator/iter_hints.c +++ b/iterator/iter_hints.c @@ -57,6 +57,8 @@ hints_create(void) sizeof(struct iter_hints)); if(!hints) return NULL; + lock_rw_init(&hints->lock); + lock_protect(&hints->lock, &hints->tree, sizeof(hints->tree)); return hints; } @@ -83,6 +85,7 @@ hints_delete(struct iter_hints* hints) { if(!hints) return; + lock_rw_destroy(&hints->lock); hints_del_tree(hints); free(hints); } @@ -438,29 +441,39 @@ read_root_hints_list(struct iter_hints* hints, struct config_file* cfg) int hints_apply_cfg(struct iter_hints* hints, struct config_file* cfg) { + lock_rw_wrlock(&hints->lock); hints_del_tree(hints); name_tree_init(&hints->tree); - + /* read root hints */ - if(!read_root_hints_list(hints, cfg)) + if(!read_root_hints_list(hints, cfg)) { + lock_rw_unlock(&hints->lock); return 0; + } /* read stub hints */ - if(!read_stubs(hints, cfg)) + if(!read_stubs(hints, cfg)) { + lock_rw_unlock(&hints->lock); return 0; + } /* use fallback compiletime root hints */ if(!hints_lookup_root(hints, LDNS_RR_CLASS_IN)) { struct delegpt* dp = compile_time_root_prime(cfg->do_ip4, cfg->do_ip6); verbose(VERB_ALGO, "no config, using builtin root hints."); - if(!dp) + if(!dp) { + lock_rw_unlock(&hints->lock); return 0; - if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, 0)) + } + if(!hints_insert(hints, LDNS_RR_CLASS_IN, dp, 0)) { + lock_rw_unlock(&hints->lock); return 0; + } } name_tree_init_parents(&hints->tree); + lock_rw_unlock(&hints->lock); return 1; } @@ -524,10 +537,12 @@ hints_get_mem(struct iter_hints* hints) size_t s; struct iter_hints_stub* p; if(!hints) return 0; + lock_rw_rdlock(&hints->lock); s = sizeof(*hints); RBTREE_FOR(p, struct iter_hints_stub*, &hints->tree) { s += sizeof(*p) + delegpt_get_mem(p->dp); } + lock_rw_unlock(&hints->lock); return s; } diff --git a/iterator/iter_hints.h b/iterator/iter_hints.h index 06b4b9667..23af751ef 100644 --- a/iterator/iter_hints.h +++ b/iterator/iter_hints.h @@ -43,6 +43,7 @@ #ifndef ITERATOR_ITER_HINTS_H #define ITERATOR_ITER_HINTS_H #include "util/storage/dnstree.h" +#include "util/locks.h" struct iter_env; struct config_file; struct delegpt; @@ -51,6 +52,10 @@ struct delegpt; * Iterator hints structure */ struct iter_hints { + /** lock on the forwards tree. + * When grabbing both this lock and the anchors.lock, this lock + * is grabbed first. */ + lock_rw_type lock; /** * Hints are stored in this tree. Sort order is specially chosen. * first sorted on qclass. Then on dname in nsec-like order, so that @@ -131,6 +136,7 @@ struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints, /** * Get memory in use by hints + * Locks and unlocks the structure. * @param hints: hint storage. * @return bytes in use */ diff --git a/iterator/iter_utils.c b/iterator/iter_utils.c index c1c4999ad..79a6e3cb0 100644 --- a/iterator/iter_utils.c +++ b/iterator/iter_utils.c @@ -1284,12 +1284,14 @@ iter_get_next_root(struct iter_hints* hints, struct iter_forwards* fwd, uint16_t* c) { uint16_t c1 = *c, c2 = *c; - int r1 = hints_next_root(hints, &c1); - int r2; + int r1, r2; lock_rw_rdlock(&fwd->lock); + lock_rw_rdlock(&hints->lock); + r1 = hints_next_root(hints, &c1); r2 = forwards_next_root(fwd, &c2); lock_rw_unlock(&fwd->lock); + lock_rw_unlock(&hints->lock); if(!r1 && !r2) /* got none, end of list */ return 0; @@ -1462,9 +1464,10 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf, struct delegpt *dp; /* Check for stub. */ + lock_rw_rdlock(&qstate->env->fwds->lock); + lock_rw_rdlock(&qstate->env->hints->lock); 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 */ @@ -1479,8 +1482,9 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf, /* check stub */ if (stub != NULL && stub->dp != NULL) { + int stub_no_cache = stub->dp->no_cache; lock_rw_unlock(&qstate->env->fwds->lock); - if(stub->dp->no_cache) { + if(stub_no_cache) { char qname[255+1]; char dpname[255+1]; dname_str(qinf->qname, qname); @@ -1488,15 +1492,26 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf, verbose(VERB_ALGO, "stub for %s %s has no_cache", qname, dpname); } if(retdpname) { - *retdpname = stub->dp->name; + if(stub->dp->namelen > dpname_storage_len) { + verbose(VERB_ALGO, "no cache stub dpname too long"); + lock_rw_unlock(&qstate->env->hints->lock); + *retdpname = NULL; + *retdpnamelen = 0; + return stub_no_cache; + } + memmove(dpname_storage, stub->dp->name, + stub->dp->namelen); + *retdpname = dpname_storage; *retdpnamelen = stub->dp->namelen; } - return (stub->dp->no_cache); + lock_rw_unlock(&qstate->env->hints->lock); + return stub_no_cache; } /* Check for forward. */ if (dp) { int dp_no_cache = dp->no_cache; + lock_rw_unlock(&qstate->env->hints->lock); if(dp_no_cache) { char qname[255+1]; char dpname[255+1]; @@ -1508,16 +1523,19 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf, 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); + *retdpname = NULL; + *retdpnamelen = 0; + return dp_no_cache; } memmove(dpname_storage, dp->name, dp->namelen); *retdpname = dpname_storage; *retdpnamelen = dp->namelen; } lock_rw_unlock(&qstate->env->fwds->lock); - return (dp_no_cache); + return dp_no_cache; } lock_rw_unlock(&qstate->env->fwds->lock); + lock_rw_unlock(&qstate->env->hints->lock); if(retdpname) { *retdpname = NULL; *retdpnamelen = 0; diff --git a/iterator/iterator.c b/iterator/iterator.c index 45d278254..e0716e967 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -688,15 +688,18 @@ can_have_last_resort(struct module_env* env, uint8_t* nm, size_t nmlen, /* do not process a last resort (the parent side) if a stub * or forward is configured, because we do not want to go 'above' * the configured servers */ + lock_rw_rdlock(&env->hints->lock); if(!dname_is_root(nm) && (stub = (struct iter_hints_stub*) name_tree_find(&env->hints->tree, nm, nmlen, labs, qclass)) && /* has_parent side is turned off for stub_first, where we * are allowed to go to the parent */ stub->dp->has_parent_side_NS) { - if(retdp) *retdp = stub->dp; + if(retdp) *retdp = delegpt_copy(stub->dp, region); + lock_rw_unlock(&env->hints->lock); if(have_dp) *have_dp = 1; return 0; } + lock_rw_unlock(&env->hints->lock); lock_rw_rdlock(&env->fwds->lock); if((fwddp = forwards_find(env->fwds, nm, qclass)) && /* has_parent_side is turned off for forward_first, where @@ -886,8 +889,10 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id, verbose(VERB_DETAIL, "priming . %s NS", sldns_lookup_by_id(sldns_rr_classes, (int)qclass)? sldns_lookup_by_id(sldns_rr_classes, (int)qclass)->name:"??"); + lock_rw_rdlock(&qstate->env->hints->lock); dp = hints_lookup_root(qstate->env->hints, qclass); if(!dp) { + lock_rw_unlock(&qstate->env->hints->lock); verbose(VERB_ALGO, "Cannot prime due to lack of hints"); return 0; } @@ -896,6 +901,7 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id, if(!generate_sub_request((uint8_t*)"\000", 1, LDNS_RR_TYPE_NS, qclass, qstate, id, iq, QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0, 0)) { + lock_rw_unlock(&qstate->env->hints->lock); verbose(VERB_ALGO, "could not prime root"); return 0; } @@ -906,6 +912,7 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id, * copy dp, it is now part of the root prime query. * dp was part of in the fixed hints structure. */ subiq->dp = delegpt_copy(dp, subq->region); + lock_rw_unlock(&qstate->env->hints->lock); if(!subiq->dp) { log_err("out of memory priming root, copydp"); fptr_ok(fptr_whitelist_modenv_kill_sub( @@ -917,6 +924,8 @@ prime_root(struct module_qstate* qstate, struct iter_qstate* iq, int id, subiq->num_target_queries = 0; subiq->dnssec_expected = iter_indicates_dnssec( qstate->env, subiq->dp, NULL, subq->qinfo.qclass); + } else { + lock_rw_unlock(&qstate->env->hints->lock); } /* this module stops, our submodule starts, and does the query. */ @@ -949,16 +958,21 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id, struct module_qstate* subq; if(!qname) return 0; + lock_rw_rdlock(&qstate->env->hints->lock); stub = hints_lookup_stub(qstate->env->hints, qname, qclass, iq->dp); /* The stub (if there is one) does not need priming. */ - if(!stub) + if(!stub) { + lock_rw_unlock(&qstate->env->hints->lock); return 0; + } stub_dp = stub->dp; /* if we have an auth_zone dp, and stub is equal, don't prime stub * yet, unless we want to fallback and avoid the auth_zone */ if(!iq->auth_zone_avoid && iq->dp && iq->dp->auth_dp && - query_dname_compare(iq->dp->name, stub_dp->name) == 0) + query_dname_compare(iq->dp->name, stub_dp->name) == 0) { + lock_rw_unlock(&qstate->env->hints->lock); return 0; + } /* is it a noprime stub (always use) */ if(stub->noprime) { @@ -967,13 +981,14 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id, /* copy the dp out of the fixed hints structure, so that * it can be changed when servicing this query */ iq->dp = delegpt_copy(stub_dp, qstate->region); + lock_rw_unlock(&qstate->env->hints->lock); if(!iq->dp) { log_err("out of memory priming stub"); errinf(qstate, "malloc failure, priming stub"); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); return 1; /* return 1 to make module stop, with error */ } - log_nametypeclass(VERB_DETAIL, "use stub", stub_dp->name, + log_nametypeclass(VERB_DETAIL, "use stub", iq->dp->name, LDNS_RR_TYPE_NS, qclass); return r; } @@ -987,6 +1002,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id, if(!generate_sub_request(stub_dp->name, stub_dp->namelen, LDNS_RR_TYPE_NS, qclass, qstate, id, iq, QUERYTARGETS_STATE, PRIME_RESP_STATE, &subq, 0, 0)) { + lock_rw_unlock(&qstate->env->hints->lock); verbose(VERB_ALGO, "could not prime stub"); errinf(qstate, "could not generate lookup for stub prime"); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); @@ -999,6 +1015,7 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id, /* Set the initial delegation point to the hint. */ /* make copy to avoid use of stub dp by different qs/threads */ subiq->dp = delegpt_copy(stub_dp, subq->region); + lock_rw_unlock(&qstate->env->hints->lock); if(!subiq->dp) { log_err("out of memory priming stub, copydp"); fptr_ok(fptr_whitelist_modenv_kill_sub( @@ -1015,6 +1032,8 @@ prime_stub(struct module_qstate* qstate, struct iter_qstate* iq, int id, subiq->wait_priming_stub = 1; subiq->dnssec_expected = iter_indicates_dnssec( qstate->env, subiq->dp, NULL, subq->qinfo.qclass); + } else { + lock_rw_unlock(&qstate->env->hints->lock); } /* this module stops, our submodule starts, and does the query. */ @@ -1615,15 +1634,18 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, lock_rw_unlock(&qstate->env->fwds->lock); /* forward zone root, no root prime needed */ /* fill in some dp - safety belt */ + lock_rw_rdlock(&qstate->env->hints->lock); iq->dp = hints_lookup_root(qstate->env->hints, iq->qchase.qclass); if(!iq->dp) { + lock_rw_unlock(&qstate->env->hints->lock); log_err("internal error: no hints dp"); errinf(qstate, "no hints for this class"); return error_response(qstate, id, LDNS_RCODE_SERVFAIL); } iq->dp = delegpt_copy(iq->dp, qstate->region); + lock_rw_unlock(&qstate->env->hints->lock); if(!iq->dp) { log_err("out of memory in safety belt"); errinf(qstate, "malloc failure, in safety belt"); @@ -1692,16 +1714,19 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, /* use safety belt */ verbose(VERB_QUERY, "Cache has root NS but " "no addresses. Fallback to the safety belt."); + lock_rw_rdlock(&qstate->env->hints->lock); iq->dp = hints_lookup_root(qstate->env->hints, iq->qchase.qclass); /* note deleg_msg is from previous lookup, * but RD is on, so it is not used */ if(!iq->dp) { + lock_rw_unlock(&qstate->env->hints->lock); log_err("internal error: no hints dp"); return error_response(qstate, id, LDNS_RCODE_REFUSED); } iq->dp = delegpt_copy(iq->dp, qstate->region); + lock_rw_unlock(&qstate->env->hints->lock); if(!iq->dp) { log_err("out of memory in safety belt"); errinf(qstate, "malloc failure, in safety belt, for root"); @@ -1764,6 +1789,7 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq, } /* Do not send queries above stub, do not set delname to dp if * this is above stub without stub-first. */ + lock_rw_rdlock(&qstate->env->hints->lock); stub = hints_lookup_stub( qstate->env->hints, iq->qchase.qname, iq->qchase.qclass, iq->dp); @@ -1772,6 +1798,7 @@ processInitRequest2(struct module_qstate* qstate, struct iter_qstate* iq, delname = iq->dp->name; delnamelen = iq->dp->namelen; } + lock_rw_unlock(&qstate->env->hints->lock); } if(iq->qchase.qtype == LDNS_RR_TYPE_DS || iq->refetch_glue) { if(!dname_is_root(delname)) @@ -2085,8 +2112,9 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL); } if(!iq->dp->has_parent_side_NS && dname_is_root(iq->dp->name)) { - struct delegpt* p = hints_lookup_root(qstate->env->hints, - iq->qchase.qclass); + struct delegpt* p; + lock_rw_rdlock(&qstate->env->hints->lock); + p = hints_lookup_root(qstate->env->hints, iq->qchase.qclass); if(p) { struct delegpt_addr* a; iq->chase_flags &= ~BIT_RD; /* go to authorities */ @@ -2101,6 +2129,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq, a->lame, a->tls_auth_name, -1, NULL); } } + lock_rw_unlock(&qstate->env->hints->lock); iq->dp->has_parent_side_NS = 1; } else if(!iq->dp->has_parent_side_NS) { if(!iter_lookup_parent_NS_from_cache(qstate->env, iq->dp, diff --git a/libunbound/context.c b/libunbound/context.c index f3a57d43d..a319f59cd 100644 --- a/libunbound/context.c +++ b/libunbound/context.c @@ -54,6 +54,7 @@ #include "util/edns.h" #include "sldns/sbuffer.h" #include "iterator/iter_fwd.h" +#include "iterator/iter_hints.h" int context_finalize(struct ub_ctx* ctx) @@ -89,6 +90,9 @@ context_finalize(struct ub_ctx* ctx) if(!(ctx->env->fwds = forwards_create()) || !forwards_apply_cfg(ctx->env->fwds, cfg)) return UB_INITFAIL; + if(!(ctx->env->hints = hints_create()) || + !hints_apply_cfg(ctx->env->hints, 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 68e1990bc..e7636d641 100644 --- a/libunbound/libunbound.c +++ b/libunbound/libunbound.c @@ -67,6 +67,7 @@ #include "services/listen_dnsport.h" #include "sldns/sbuffer.h" #include "iterator/iter_fwd.h" +#include "iterator/iter_hints.h" #ifdef HAVE_PTHREAD #include #endif @@ -381,6 +382,7 @@ ub_ctx_delete(struct ub_ctx* ctx) edns_known_options_delete(ctx->env); edns_strings_delete(ctx->env->edns_strings); forwards_delete(ctx->env->fwds); + hints_delete(ctx->env->hints); auth_zones_delete(ctx->env->auth_zones); free(ctx->env); } diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 9149365c8..788067852 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -70,8 +70,6 @@ #include "util/data/msgreply.h" #include "util/data/msgencode.h" #include "util/tube.h" -#include "iterator/iter_fwd.h" -#include "iterator/iter_hints.h" #include "sldns/sbuffer.h" #include "sldns/str2wire.h" #ifdef USE_DNSTAP @@ -100,7 +98,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); - hints_delete(w->env->hints); ub_randfree(w->env->rnd); free(w->env); } @@ -158,24 +155,19 @@ 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->hints = hints_create(); - if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) { - hints_delete(w->env->hints); - w->env->hints = NULL; - } #ifdef HAVE_SSL w->sslctx = connect_sslctx_create(NULL, NULL, cfg->tls_cert_bundle, cfg->tls_win_cert); if(!w->sslctx) { /* to make the setup fail after unlock */ - hints_delete(w->env->hints); - w->env->hints = NULL; + sldns_buffer_free(w->env->scratch_buffer); + w->env->scratch_buffer = NULL; } #endif if(!w->is_bg || w->is_bg_thread) { lock_basic_unlock(&ctx->cfglock); } - if(!w->env->scratch || !w->env->scratch_buffer || !w->env->hints) { + if(!w->env->scratch || !w->env->scratch_buffer) { libworker_delete(w); return NULL; } diff --git a/pythonmod/interface.i b/pythonmod/interface.i index d9839fc38..5bc7e8492 100644 --- a/pythonmod/interface.i +++ b/pythonmod/interface.i @@ -1455,10 +1455,14 @@ struct delegpt* find_delegation(struct module_qstate* qstate, char *nm, size_t n dname_str((uint8_t*)nm, b); continue; } + lock_rw_rdlock(&qstate->env->hints->lock); stub = hints_lookup_stub(qstate->env->hints, qinfo.qname, qinfo.qclass, dp); if (stub) { - return stub->dp; + struct delegpt* stubdp = delegpt_copy(stub->dp, region); + lock_rw_unlock(&qstate->env->hints->lock); + return stubdp; } else { + lock_rw_unlock(&qstate->env->hints->lock); return dp; } } diff --git a/util/module.h b/util/module.h index 65b82b59c..8e7aca635 100644 --- a/util/module.h +++ b/util/module.h @@ -514,7 +514,7 @@ struct module_env { * iterator forwarder information. */ struct iter_forwards* fwds; /** - * iterator forwarder information. per-thread, created by worker. + * iterator stub information. * The hints -- these aren't stored in the cache because they don't * expire. The hints are always used to "prime" the cache. Note * that both root hints and stub zone "hints" are stored in this -- 2.47.2