]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix cachedb with serve-expired-client-timeout disabled. The edns
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 26 Apr 2024 11:32:15 +0000 (13:32 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 26 Apr 2024 11:32:15 +0000 (13:32 +0200)
  subnet module deletes global cache and cachedb cache when it
  stores a result, and serve-expired is enabled, so that the global
  reply, that is older than the ecs reply, does not return after
  the ecs reply expires.

cachedb/cachedb.c
cachedb/cachedb.h
daemon/daemon.c
doc/Changelog
edns-subnet/subnetmod.c
libunbound/libunbound.c
testdata/cachedb_subnet_expired.crpl
util/module.h

index 20bc2008ca0f611089769210f5b1a97513461a67..95ac28904693627e76b6d9f4826a7d4901c8c6ab 100644 (file)
@@ -827,10 +827,13 @@ cachedb_handle_query(struct module_qstate* qstate,
                 * TODO: this needs revisit. The expired data stored from cachedb has
                 * 0 TTL which is picked up by iterator later when looking in the cache.
                 */
-               if(qstate->env->cfg->serve_expired && msg_expired &&
-                       qstate->env->cfg->serve_expired_client_timeout) {
+               if(qstate->env->cfg->serve_expired && msg_expired) {
                        qstate->return_msg = NULL;
                        qstate->ext_state[id] = module_wait_module;
+                       /* The expired reply is sent with
+                        * mesh_respond_serve_expired, and so
+                        * the need_refetch is not used. */
+                       qstate->need_refetch = 0;
                        return;
                }
                if(qstate->need_refetch && qstate->serve_expired_data &&
@@ -998,4 +1001,23 @@ cachedb_is_enabled(struct module_stack* mods, struct module_env* env)
                return 1;
        return 0;
 }
+
+void cachedb_msg_remove(struct module_qstate* qstate)
+{
+       char key[(CACHEDB_HASHSIZE/8)*2+1];
+       int id = modstack_find(qstate->env->modstack, "cachedb");
+       struct cachedb_env* ie = (struct cachedb_env*)qstate->env->modinfo[id];
+
+       log_query_info(VERB_ALGO, "cachedb msg remove", &qstate->qinfo);
+       calc_hash(qstate, key, sizeof(key));
+       sldns_buffer_clear(qstate->env->scratch_buffer);
+       sldns_buffer_write_u32(qstate->env->scratch_buffer, 0);
+       sldns_buffer_flip(qstate->env->scratch_buffer);
+
+       /* call backend */
+       (*ie->backend->store)(qstate->env, ie, key,
+               sldns_buffer_begin(qstate->env->scratch_buffer),
+               sldns_buffer_limit(qstate->env->scratch_buffer),
+               0);
+}
 #endif /* USE_CACHEDB */
index 9ca132de22c7a6adac0db9d5504aea284ceda420..2da8b5c71feb6752c750eea995f85bbfe8738c56 100644 (file)
@@ -118,3 +118,11 @@ struct module_func_block* cachedb_get_funcblock(void);
  * @return true if exists and enabled.
  */
 int cachedb_is_enabled(struct module_stack* mods, struct module_env* env);
+
+/**
+ * Remove a message from the global cache. Because edns subnet has a more
+ * specific entry, and if not removed when everything expires, the global
+ * entry is used, instead of a fresh lookup of the edns subnet entry.
+ * @param qstate: query state.
+ */
+void cachedb_msg_remove(struct module_qstate* qstate);
index 037640f0b97a845f47a335edb576101dfdd695e8..f0ee329db90312fddc376599ab53b5947ad32640 100644 (file)
@@ -265,6 +265,7 @@ daemon_init(void)
                free(daemon);
                return NULL;
        }
+       daemon->env->modstack = &daemon->mods;
        /* init edns_known_options */
        if(!edns_known_options_init(daemon->env)) {
                free(daemon->env);
index 73af54ae768a29973062aca952991f387088646e..14ef614364230664aae071325f1f267b65ce2f0a 100644 (file)
@@ -1,3 +1,10 @@
+26 April 2024: Wouter
+       - Fix cachedb with serve-expired-client-timeout disabled. The edns
+         subnet module deletes global cache and cachedb cache when it
+         stores a result, and serve-expired is enabled, so that the global
+         reply, that is older than the ecs reply, does not return after
+         the ecs reply expires.
+
 25 April 2024: Wouter
        - Fix configure flto check error, by finding grep for it.
        - Merge #1041: Stub and Forward unshare. This has one structure
index e8c090b5200b8abd559e52fbf13d64c6142974d9..1dff429ac8ae7cb367d764c76bcb506169f0d1e2 100644 (file)
@@ -57,6 +57,9 @@
 #include "sldns/sbuffer.h"
 #include "sldns/wire2str.h"
 #include "iterator/iter_utils.h"
+#ifdef USE_CACHEDB
+#include "cachedb/cachedb.h"
+#endif
 
 /** externally called */
 void 
@@ -602,7 +605,21 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
        }
        sne->num_msg_nocache++;
        lock_rw_unlock(&sne->biglock);
-       
+
+       /* If there is an expired answer in the global cache, remove that,
+        * because expired answers would otherwise resurface once the ecs data
+        * expires, giving once in a while global data responses for ecs
+        * domains, with serve expired enabled. */
+       if(qstate->env->cfg->serve_expired) {
+               msg_cache_remove(qstate->env, qstate->qinfo.qname,
+                       qstate->qinfo.qname_len, qstate->qinfo.qtype,
+                       qstate->qinfo.qclass, 0);
+#ifdef USE_CACHEDB
+               if(qstate->env->cachedb_enabled)
+                       cachedb_msg_remove(qstate);
+#endif
+       }
+
        if (sq->subnet_downstream) {
                /* Client wants to see the answer, echo option back
                 * and adjust the scope. */
index e7636d6418f1d7f05a2825b6b8c735121caa8ba5..17057ec6c014e9edade6448b63ca65dec0a09e8b 100644 (file)
@@ -173,6 +173,7 @@ static struct ub_ctx* ub_ctx_create_nopipe(void)
        ctx->env->worker = NULL;
        ctx->env->need_to_validate = 0;
        modstack_init(&ctx->mods);
+       ctx->env->modstack = &ctx->mods;
        rbtree_init(&ctx->queries, &context_query_cmp);
        return ctx;
 }
index 0efed94f40fbd2583975ab3b991065fe89d717f9..a6057b0bba8c0ecb1482ca4083de82b4832de6d2 100644 (file)
@@ -272,19 +272,32 @@ ENTRY_END
 
 STEP 122 TIME_PASSES ELAPSE 2
 
-STEP 130 CHECK_ANSWER
+; But the entry has been deleted, so it cannot be served, the reply
+; at step 141 is returned instead.
+;STEP 130 CHECK_ANSWER
+;ENTRY_BEGIN
+;MATCH all
+;REPLY QR RD RA NOERROR
+;SECTION QUESTION
+;www.example.com. IN A
+;SECTION ANSWER
+;www.example.com. 30 IN A 1.2.3.4
+;ENTRY_END
+
+; reply can flow again.
+STEP 140 TRAFFIC
+
+STEP 141 CHECK_ANSWER
 ENTRY_BEGIN
 MATCH all
 REPLY QR RD RA NOERROR
 SECTION QUESTION
 www.example.com. IN A
 SECTION ANSWER
-www.example.com. 30 IN A 1.2.3.4
+www.example.com. 10 IN CNAME example.foo.com.
+example.foo.com. 10 IN A 1.2.3.6
 ENTRY_END
 
-; reply can flow again.
-STEP 140 TRAFFIC
-
 ; see the entry now in cache, from the subnetcache.
 STEP 142 TIME_PASSES ELAPSE 2
 STEP 150 QUERY ADDRESS 127.0.0.1
index 3a72e9aec559be34d52f55ed42ba08d64aa47d44..d54d56895ff38722a0951f11b9be296927f16ec8 100644 (file)
@@ -180,6 +180,7 @@ struct iter_hints;
 struct respip_set;
 struct respip_client_info;
 struct respip_addr_info;
+struct module_stack;
 
 /** Maximum number of modules in operation */
 #define MAX_MODULE 16
@@ -537,6 +538,8 @@ struct module_env {
        /** EDNS client string information */
        struct edns_strings* edns_strings;
 
+       /** module stack */
+       struct module_stack* modstack;
 #ifdef USE_CACHEDB
        /** the cachedb enabled value, copied and stored here. */
        int cachedb_enabled;