]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- fast-reload, unshare forwards, making the structure locked, with an rwlock.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Thu, 4 Jan 2024 15:53:02 +0000 (16:53 +0100)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 3 Apr 2024 11:55:54 +0000 (13:55 +0200)
16 files changed:
Makefile.in
cachedb/cachedb.c
daemon/cachedump.c
daemon/daemon.c
daemon/remote.c
daemon/worker.c
edns-subnet/subnetmod.c
iterator/iter_fwd.c
iterator/iter_fwd.h
iterator/iter_utils.c
iterator/iter_utils.h
iterator/iterator.c
libunbound/context.c
libunbound/libunbound.c
libunbound/libworker.c
util/module.h

index 22fb75c123bdacc72c3138a897d38eaa19b698ec..2bbfeae8df44da4ff694a3e16b0407e51eed7582 100644 (file)
@@ -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 \
index b912be8ed54f18ae448f8f650ff6265dfa77697b..aa8b2645a09c4c0f29d47d1e339bdf784719c8eb 100644 (file)
@@ -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,
index 61ee1d29133fa24e94e80e90d1af1ba41ea6acf1..d12168008bdf4bc2e5973914ea864cbcb9e3d133 100644 (file)
@@ -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, 
index 4870089a7320bca84432f649a66266b59068f6bd..248341f274459f83579699f0c5f1222577327634 100644 (file)
@@ -91,6 +91,7 @@
 #include "util/net_help.h"
 #include "sldns/keyraw.h"
 #include "respip/respip.h"
+#include "iterator/iter_fwd.h"
 #include <signal.h>
 
 #ifdef HAVE_SYSTEMD
@@ -714,6 +715,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()))
@@ -830,6 +834,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);
index cbce1198b27dd3119832ee51af9c9098368a4621..65b891aee7345713503d4d9d7fb236ab0fbb38ed 100644 (file)
@@ -1992,12 +1992,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 */
@@ -2082,15 +2090,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);
 }
@@ -2153,9 +2166,11 @@ do_forward_add(RES* ssl, struct worker* worker, char* args)
                return;
        if(tls)
                dp->ssl_upstream = 1;
+       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);
@@ -2163,10 +2178,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);
 }
@@ -2180,10 +2197,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, 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);
 }
@@ -2200,6 +2219,7 @@ do_stub_add(RES* ssl, struct worker* worker, char* args)
                return;
        if(tls)
                dp->ssl_upstream = 1;
+       lock_rw_wrlock(&fwd->lock);
        if(insecure && worker->env.anchors) {
                if(!anchors_add_insecure(worker->env.anchors, LDNS_RR_CLASS_IN,
                        nm)) {
@@ -2213,6 +2233,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);
@@ -2224,9 +2245,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);
 }
@@ -2240,11 +2263,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, 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);
 }
@@ -2673,6 +2698,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 */
 
@@ -2687,9 +2713,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 */
@@ -3088,13 +3117,9 @@ execute_cmd(struct daemon_remote* rc, 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)) {
@@ -3108,8 +3133,6 @@ execute_cmd(struct daemon_remote* rc, 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)) {
index 1a0b9abde36e5fcbac77951d65722d7a5f88c09e..5cd689f694801a225c71b24721d00e5d6d8c0d8e 100644 (file)
@@ -2261,12 +2261,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");
@@ -2345,7 +2339,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);
index 22e3ef17ec0119d42dbbfccce4531fcd8dcfe846..e442fd62fc3cf5dfcb7be9db047b3aeee03aabab 100644 (file)
@@ -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;
        }
 
index c4b2411297e34067e2c302b04b031fec85639928..cf418b0720fce0bae4760e8a322cc2a8917e4ad8 100644 (file)
@@ -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;
        }
index e90b74c16a5d9f8b8ab53feb4d81dd7f15c37b9c..75ac597bd6e7d7a8d03c0cb6e536f8d090c13517 100644 (file)
@@ -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
  */
index 10a8ec3eb08f20781009a68f02c37305ee9af12a..c1c4999ad47205a0863ee522ecf5d31b48d5a392 100644 (file)
@@ -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;
index fa860fa682fc3a139db0739a17467a91db48a747..4024629e686c35ed6b9967f840d83dd01760f47d 100644 (file)
@@ -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
index 6ec8af401c8e67a653f16106ac572502f069e420..8465722182ba3900fb4ac8e98b8601e9f0ac8e1f 100644 (file)
@@ -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;
        }
 
@@ -1442,7 +1453,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
                }
        }
 
-       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;
@@ -1573,7 +1585,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
@@ -1615,8 +1627,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, 
@@ -1636,6 +1650,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))
@@ -1667,15 +1682,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");
@@ -2080,7 +2093,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,");
@@ -2182,7 +2195,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);
index f7c0a2cd5fae99996da6bc3dd4f0966d4e4a9800..f3a57d43d1b3219ff84d994271ac0e8b01825571 100644 (file)
@@ -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,
index 80a82bb47ddf9573327e3bd64159a4c874d92fc0..68e1990bc6985a87b7840c372013c3df4abfa88f 100644 (file)
@@ -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 <signal.h>
 #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);
        }
index 0e1c403937636da4f134cb0431058d6466be642a..5d1a9921046ed0d2cd45493c8cabea8553e77e64 100644 (file)
@@ -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;
        }
index 8a9da3f931a128c6cbff0eac7a4876dca4aea21e..65b82b59cba317733dcdb722ac3e710e5ddb5a3a 100644 (file)
@@ -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.