]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix that fast_reload when a zonemd verification lookup
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Mon, 15 Jun 2026 14:16:50 +0000 (16:16 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Mon, 15 Jun 2026 14:16:50 +0000 (16:16 +0200)
  it in progress with subnet loaded, deregisters the
  callback. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.

daemon/remote.c
doc/Changelog
libunbound/context.h
libunbound/libworker.c
services/authzone.c
services/authzone.h
services/mesh.c
services/mesh.h
validator/autotrust.c

index 4e4647237c13677c5ca62c59235f4b2981d5c714..bce73dc864bd55e0151cb92c740fe35286cf1975 100644 (file)
@@ -7612,7 +7612,8 @@ auth_zone_zonemd_stop_lookup(struct auth_zone* z, struct mesh_area* mesh)
        qinfo.local_alias = NULL;
 
        mesh_remove_callback(mesh, &qinfo, qflags,
-               &auth_zonemd_dnskey_lookup_callback, z);
+               &auth_zonemd_dnskey_lookup_callback, z,
+               z->zonemd_callback_unique_info);
 }
 
 /** Pick up the auth zone locks. */
index ac17fa191ef21b2d8a2671ea6ebcf99f5fb155da..e81c9aaf36a89f7baf575417953e3e393d9f5952 100644 (file)
        - Fix that misconfigured `iter-scrub-ns: 0` causes request
          failures. Thanks to Qifan Zhang, Palo Alto Networks,
          for the report.
+       - Fix that fast_reload when a zonemd verification lookup
+         it in progress with subnet loaded, deregisters the
+         callback. Thanks to Qifan Zhang, Palo Alto Networks,
+         for the report.
 
 12 June 2026: Wouter
        - Fix that for auth-zone and rpz zones the allow-notify
index c0fc80e57be4d2e425cf9f1b65d10aeb7e142bbe..090df345b0e7148eaded938b4c3463750ce539a3 100644 (file)
@@ -167,6 +167,8 @@ struct ctx_query {
         ub_event_callback_type cb_event;
        /** for async query, the callback user arg */
        void* cb_arg;
+       /** for async query the unique info */
+       void* unique_info;
 
        /** answer message, result from resolver lookup. */
        uint8_t* msg;
index c8692ba26d765fe0486dfbdc8fab42fa9d3973c5..9ce747bce95ebc29565b10b66514343b3f83c78d 100644 (file)
@@ -642,7 +642,8 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
        }
        /* process new query */
        if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 
-               w->back->udp_buff, qid, libworker_fg_done_cb, q, 0)) {
+               w->back->udp_buff, qid, libworker_fg_done_cb, q, 0,
+               &q->unique_info)) {
                free(qinfo.qname);
                return UB_NOMEM;
        }
@@ -723,7 +724,8 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
        if(async_id)
                *async_id = q->querynum;
        if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 
-               w->back->udp_buff, qid, libworker_event_done_cb, q, 0)) {
+               w->back->udp_buff, qid, libworker_event_done_cb, q, 0,
+               &q->unique_info)) {
                free(qinfo.qname);
                return UB_NOMEM;
        }
@@ -861,7 +863,8 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
        q->w = w;
        /* process new query */
        if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 
-               w->back->udp_buff, qid, libworker_bg_done_cb, q, 0)) {
+               w->back->udp_buff, qid, libworker_bg_done_cb, q, 0,
+               &q->unique_info)) {
                add_bg_result(w, q, NULL, UB_NOMEM, NULL, 0);
        }
        free(qinfo.qname);
index 3d31e467492a4f4b50906cfdc8dba47faf3170de..f7224a3df2706b1edc2523187756a24bd7b80411 100644 (file)
@@ -5558,7 +5558,8 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env)
         * called straight away */
        lock_basic_unlock(&xfr->lock);
        if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
-               &auth_xfer_transfer_lookup_callback, xfr, 0)) {
+               &auth_xfer_transfer_lookup_callback, xfr, 0,
+               &xfr->task_transfer->lookup_unique_info)) {
                lock_basic_lock(&xfr->lock);
                log_err("out of memory lookup up master %s", master->host);
                return 0;
@@ -6804,7 +6805,8 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
         * called straight away */
        lock_basic_unlock(&xfr->lock);
        if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
-               &auth_xfer_probe_lookup_callback, xfr, 0)) {
+               &auth_xfer_probe_lookup_callback, xfr, 0,
+               &xfr->task_probe->lookup_unique_info)) {
                lock_basic_lock(&xfr->lock);
                log_err("out of memory lookup up master %s", master->host);
                return 0;
@@ -8640,7 +8642,8 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
        /* the callback can be called straight away */
        lock_rw_unlock(&z->lock);
        if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
-               &auth_zonemd_dnskey_lookup_callback, z, 0)) {
+               &auth_zonemd_dnskey_lookup_callback, z, 0,
+               &z->zonemd_callback_unique_info)) {
                lock_rw_wrlock(&z->lock);
                log_err("out of memory lookup of %s for zonemd",
                        (fetch_ds?"DS":"DNSKEY"));
index 23a6b0f9303b597ad84233334405123e2d32aaef..b55b711aed1b03b7def3a634017df4444a2339a4 100644 (file)
@@ -144,6 +144,8 @@ struct auth_zone {
        struct module_env* zonemd_callback_env;
        /** for the zonemd callback, the type of data looked up */
        uint16_t zonemd_callback_qtype;
+       /** for the zonemd callback, the unique info */
+       void* zonemd_callback_unique_info;
        /** zone has been deleted */
        int zone_deleted;
        /** deletelist pointer, unused normally except during delete */
@@ -344,6 +346,8 @@ struct auth_probe {
 
        /** for the hostname lookups, which master is current */
        struct auth_master* lookup_target;
+       /** for the lookup, the callback unique info */
+       void* lookup_unique_info;
        /** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */
        int lookup_aaaa;
        /** we only want to do lookups for making config work (for notify),
@@ -402,6 +406,8 @@ struct auth_transfer {
 
        /** for the hostname lookups, which master is current */
        struct auth_master* lookup_target;
+       /** for the lookup, the callback unique info */
+       void* lookup_unique_info;
        /** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */
        int lookup_aaaa;
 
index 5cb2cba4b689341e40d6db2175e1cc76a1f218fb..2347bcee2bef1e728f17c241b365bc70b57713c7 100644 (file)
@@ -662,7 +662,8 @@ servfail_mem:
 int
 mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
        uint16_t qflags, struct edns_data* edns, sldns_buffer* buf,
-       uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru)
+       uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru,
+       void** unique_info)
 {
        struct mesh_state* s = NULL;
        int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
@@ -751,6 +752,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
                mesh->num_reply_states ++;
        }
        mesh->num_reply_addrs++;
+       if(unique_info)
+               *unique_info = s->unique;
        if(added)
                mesh_run(mesh, s, module_event_new, NULL);
        return 1;
@@ -1969,6 +1972,25 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh,
        return result;
 }
 
+struct mesh_state* mesh_area_find_unique(struct mesh_area* mesh,
+       struct respip_client_info* cinfo, struct query_info* qinfo,
+       uint16_t qflags, int prime, int valrec, void* unique_info)
+{
+       struct mesh_state key;
+       struct mesh_state* result;
+
+       key.node.key = &key;
+       key.s.is_priming = prime;
+       key.s.is_valrec = valrec;
+       key.s.qinfo = *qinfo;
+       key.s.query_flags = qflags;
+       key.unique = (struct mesh_state*)unique_info;
+       key.s.client_info = cinfo;
+
+       result = (struct mesh_state*)rbtree_search(&mesh->all, &key);
+       return result;
+}
+
 /** remove mesh state callback */
 int mesh_state_del_cb(struct mesh_state* s, mesh_cb_func_type cb, void* cb_arg)
 {
@@ -2700,13 +2722,30 @@ int mesh_jostle_exceeded(struct mesh_area* mesh)
 }
 
 void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo,
-       uint16_t qflags, mesh_cb_func_type cb, void* cb_arg)
+       uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info)
 {
        struct mesh_state* s = NULL;
        s = mesh_area_find(mesh, NULL, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
-       if(!s) return;
-       if(!mesh_state_del_cb(s, cb, cb_arg)) return;
+       if(s && mesh_state_del_cb(s, cb, cb_arg))
+               goto removed;
+       if(unique_info) {
+               s = mesh_area_find_unique(mesh, NULL, qinfo,
+                       qflags&(BIT_RD|BIT_CD), 0, 0, unique_info);
+               if(s && mesh_state_del_cb(s, cb, cb_arg))
+                       goto removed;
+       }
+       /* mesh_area_find builds key.unique=NULL and cannot match a state
+        * created with mesh_state_make_unique (e.g. subnetcache sets
+        * env->unique_mesh). Fall back to a linear scan; cb+cb_arg is an
+        * exact key (mesh_state_del_cb compares both).
+        * This works for both lookups for zonemd and for hostname authzone. */
+       RBTREE_FOR(s, struct mesh_state*, &mesh->all) {
+               if(s->cb_list && mesh_state_del_cb(s, cb, cb_arg))
+                       goto removed;
+       }
+       return;
 
+removed:
        /* It was in the list and removed. */
        log_assert(mesh->num_reply_addrs > 0);
        mesh->num_reply_addrs--;
index 8f8b8a169228cdc9f6ae68cff03ddea9af1698fd..77b3c7025680db631681a1801b81ae8a34d985f0 100644 (file)
@@ -342,11 +342,14 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
  * @param cb_arg: callback user arg.
  * @param rpz_passthru: if true, the rpz passthru was previously found and
  *     further rpz processing is stopped.
+ * @param unique_info: if nonnull, unique info is passed back to be used
+ *     for the callback remove call. It does not need to be deallocated.
  * @return 0 on error.
  */
 int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
        uint16_t qflags, struct edns_data* edns, struct sldns_buffer* buf, 
-       uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru);
+       uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru,
+       void** unique_info);
 
 /**
  * New prefetch message. Create new query state if needed.
@@ -543,6 +546,23 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh,
        struct respip_client_info* cinfo, struct query_info* qinfo,
        uint16_t qflags, int prime, int valrec);
 
+/**
+ * Find a unique mesh state in the mesh area. Pass relevant flags.
+ *
+ * @param mesh: the mesh area to look in.
+ * @param cinfo: if non-NULL client specific info that may affect IP-based
+ *     actions that apply to the query result.
+ * @param qinfo: what query
+ * @param qflags: if RD / CD bit is set or not.
+ * @param prime: if it is a priming query.
+ * @param valrec: if it is a validation-recursion query.
+ * @param unique_info: the unique info for the state. NULL can be passed.
+ * @return: mesh state or NULL if not found.
+ */
+struct mesh_state* mesh_area_find_unique(struct mesh_area* mesh,
+       struct respip_client_info* cinfo, struct query_info* qinfo,
+       uint16_t qflags, int prime, int valrec, void* unique_info);
+
 /**
  * Setup attachment super/sub relation between super and sub mesh state.
  * The relation must not be present when calling the function.
@@ -736,8 +756,9 @@ void mesh_respond_serve_expired(struct mesh_state* mstate);
  * @param qflags: flags from client query.
  * @param cb: callback function.
  * @param cb_arg: callback user arg.
+ * @param unique_info: if not NULL, used to find a unique state for removal.
  */
 void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo,
-       uint16_t qflags, mesh_cb_func_type cb, void* cb_arg);
+       uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info);
 
 #endif /* SERVICES_MESH_H */
index 078007da5bd90ccfa233fbc0f8bcdac294063cb6..4ee105371ba3c737b99e899443d0d97489902f6e 100644 (file)
@@ -2431,7 +2431,7 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp)
                qinfo.qclass);
 
        if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, 
-               &probe_answer_cb, env, 0)) {
+               &probe_answer_cb, env, 0, NULL)) {
                log_err("out of memory making 5011 probe");
        }
 }