]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix #1071: [FR] Clear both in-memory and cachedb module cache with
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Thu, 16 May 2024 14:56:58 +0000 (16:56 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Thu, 16 May 2024 14:56:58 +0000 (16:56 +0200)
  `unbound-control flush*` commands.

cachedb/cachedb.c
cachedb/cachedb.h
daemon/remote.c
doc/Changelog
doc/unbound-control.8.in
smallapp/unbound-control.c

index 95ac28904693627e76b6d9f4826a7d4901c8c6ab..0f3604576190e2f3e517def62116fa05689c216f 100644 (file)
@@ -322,30 +322,30 @@ error_response(struct module_qstate* qstate, int id, int rcode)
 
 /**
  * Hash the query name, type, class and dbacess-secret into lookup buffer.
- * @param qstate: query state with query info
- *     and env->cfg with secret.
+ * @param qinfo: query info
+ * @param env: with env->cfg with secret.
  * @param buf: returned buffer with hash to lookup
  * @param len: length of the buffer.
  */
 static void
-calc_hash(struct module_qstate* qstate, char* buf, size_t len)
+calc_hash(struct query_info* qinfo, struct module_env* env, char* buf,
+       size_t len)
 {
        uint8_t clear[1024];
        size_t clen = 0;
        uint8_t hash[CACHEDB_HASHSIZE/8];
        const char* hex = "0123456789ABCDEF";
-       const char* secret = qstate->env->cfg->cachedb_secret;
+       const char* secret = env->cfg->cachedb_secret;
        size_t i;
 
        /* copy the hash info into the clear buffer */
-       if(clen + qstate->qinfo.qname_len < sizeof(clear)) {
-               memmove(clear+clen, qstate->qinfo.qname,
-                       qstate->qinfo.qname_len);
-               clen += qstate->qinfo.qname_len;
+       if(clen + qinfo->qname_len < sizeof(clear)) {
+               memmove(clear+clen, qinfo->qname, qinfo->qname_len);
+               clen += qinfo->qname_len;
        }
        if(clen + 4 < sizeof(clear)) {
-               uint16_t t = htons(qstate->qinfo.qtype);
-               uint16_t c = htons(qstate->qinfo.qclass);
+               uint16_t t = htons(qinfo->qtype);
+               uint16_t c = htons(qinfo->qclass);
                memmove(clear+clen, &t, 2);
                memmove(clear+clen+2, &c, 2);
                clen += 4;
@@ -645,7 +645,7 @@ cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie,
        int* msg_expired)
 {
        char key[(CACHEDB_HASHSIZE/8)*2+1];
-       calc_hash(qstate, key, sizeof(key));
+       calc_hash(&qstate->qinfo, qstate->env, key, sizeof(key));
 
        /* call backend to fetch data for key into scratch buffer */
        if( !(*ie->backend->lookup)(qstate->env, ie, key,
@@ -672,7 +672,7 @@ static void
 cachedb_extcache_store(struct module_qstate* qstate, struct cachedb_env* ie)
 {
        char key[(CACHEDB_HASHSIZE/8)*2+1];
-       calc_hash(qstate, key, sizeof(key));
+       calc_hash(&qstate->qinfo, qstate->env, key, sizeof(key));
 
        /* prepare data in scratch buffer */
        if(!prep_data(qstate, qstate->env->scratch_buffer))
@@ -1003,21 +1003,26 @@ cachedb_is_enabled(struct module_stack* mods, struct module_env* env)
 }
 
 void cachedb_msg_remove(struct module_qstate* qstate)
+{
+       cachedb_msg_remove_qinfo(qstate->env, &qstate->qinfo);
+}
+
+void cachedb_msg_remove_qinfo(struct module_env* env, struct query_info* qinfo)
 {
        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];
+       int id = modstack_find(env->modstack, "cachedb");
+       struct cachedb_env* ie = (struct cachedb_env*)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);
+       log_query_info(VERB_ALGO, "cachedb msg remove", qinfo);
+       calc_hash(qinfo, env, key, sizeof(key));
+       sldns_buffer_clear(env->scratch_buffer);
+       sldns_buffer_write_u32(env->scratch_buffer, 0);
+       sldns_buffer_flip(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),
+       (*ie->backend->store)(env, ie, key,
+               sldns_buffer_begin(env->scratch_buffer),
+               sldns_buffer_limit(env->scratch_buffer),
                0);
 }
 #endif /* USE_CACHEDB */
index 2da8b5c71feb6752c750eea995f85bbfe8738c56..482c5db6c063d64d06b77f64e346829ba7345065 100644 (file)
@@ -126,3 +126,11 @@ int cachedb_is_enabled(struct module_stack* mods, struct module_env* env);
  * @param qstate: query state.
  */
 void cachedb_msg_remove(struct module_qstate* qstate);
+
+/**
+ * Remove message from the cachedb cache, by query info.
+ * @param env: module environment to look up cachedb state.
+ * @param qinfo: the message to remove.
+ */
+void cachedb_msg_remove_qinfo(struct module_env* env,
+       struct query_info* qinfo);
index 764ae8ffda3ca89f8f0e9c0c3a556ad7aa338870..2e7d589e26170c5c418562494c3e4cc71e7d8f87 100644 (file)
@@ -88,6 +88,9 @@
 #include "sldns/wire2str.h"
 #include "sldns/sbuffer.h"
 #include "util/timeval_func.h"
+#ifdef USE_CACHEDB
+#include "cachedb/cachedb.h"
+#endif
 
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
@@ -1553,7 +1556,7 @@ do_lookup(RES* ssl, struct worker* worker, char* arg)
 /** flush something from rrset and msg caches */
 static void
 do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen,
-       uint16_t t, uint16_t c)
+       uint16_t t, uint16_t c, int remcachedb)
 {
        hashvalue_type h;
        struct query_info k;
@@ -1573,6 +1576,27 @@ do_cache_remove(struct worker* worker, uint8_t* nm, size_t nmlen,
                h = query_info_hash(&k, BIT_CD);
                slabhash_remove(worker->env.msg_cache, h, &k);
        }
+#ifdef USE_CACHEDB
+       if(remcachedb && worker->env.cachedb_enabled)
+               cachedb_msg_remove_qinfo(&worker->env, &k);
+#endif
+}
+
+/** parse '+c' option, modifies string to return remainder. */
+static int
+parse_remcachedb(RES* ssl, char** arg, int* pc)
+{
+       *arg = skipwhite(*arg);
+       if((*arg)[0] == '+' && (*arg)[1] == 'c') {
+               char* arg2;
+               *pc = 1;
+               if(!find_arg2(ssl, *arg, &arg2))
+                       return 0;
+               *arg = arg2;
+               return 1;
+       }
+       /* The option was not found, no problem */
+       return 1;
 }
 
 /** flush a type */
@@ -1584,15 +1608,20 @@ do_flush_type(RES* ssl, struct worker* worker, char* arg)
        size_t nmlen;
        char* arg2;
        uint16_t t;
+       int pc = 0; /* '+c' option */
+       if(!parse_remcachedb(ssl, &arg, &pc))
+               return;
        if(!find_arg2(ssl, arg, &arg2))
                return;
        if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
                return;
        t = sldns_get_rr_type_by_name(arg2);
        if(t == 0 && strcmp(arg2, "TYPE0") != 0) {
+               (void)ssl_printf(ssl, "error parsing RRset type: '%s'\n", arg2);
+               free(nm);
                return;
        }
-       do_cache_remove(worker, nm, nmlen, t, LDNS_RR_CLASS_IN);
+       do_cache_remove(worker, nm, nmlen, t, LDNS_RR_CLASS_IN, pc);
 
        free(nm);
        send_ok(ssl);
@@ -1630,6 +1659,8 @@ struct del_info {
        socklen_t addrlen;
        /** socket address for host deletion */
        struct sockaddr_storage addr;
+       /** if cachedb information should be flushed too */
+       int remcachedb;
 };
 
 /** callback to delete hosts in infra cache */
@@ -1681,6 +1712,7 @@ do_flush_infra(RES* ssl, struct worker* worker, char* arg)
        inf.num_msgs = 0;
        inf.num_keys = 0;
        inf.addrlen = len;
+       inf.remcachedb = 0;
        memmove(&inf.addr, &addr, len);
        slabhash_traverse(worker->env.infra_cache->hosts, 1, &infra_del_host,
                &inf);
@@ -1727,6 +1759,10 @@ zone_del_msg(struct lruhash_entry* e, void* arg)
                        d->serve_expired_ttl = inf->expired;
                        inf->num_msgs++;
                }
+#ifdef USE_CACHEDB
+               if(inf->remcachedb && inf->worker->env.cachedb_enabled)
+                       cachedb_msg_remove_qinfo(&inf->worker->env, &k->key);
+#endif
        }
 }
 
@@ -1754,6 +1790,9 @@ do_flush_zone(RES* ssl, struct worker* worker, char* arg)
        int nmlabs;
        size_t nmlen;
        struct del_info inf;
+       int pc = 0; /* '+c' option */
+       if(!parse_remcachedb(ssl, &arg, &pc))
+               return;
        if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
                return;
        /* delete all RRs and key entries from zone */
@@ -1767,6 +1806,7 @@ do_flush_zone(RES* ssl, struct worker* worker, char* arg)
        inf.num_rrsets = 0;
        inf.num_msgs = 0;
        inf.num_keys = 0;
+       inf.remcachedb = pc;
        slabhash_traverse(&worker->env.rrset_cache->table, 1,
                &zone_del_rrset, &inf);
 
@@ -1808,6 +1848,11 @@ bogus_del_msg(struct lruhash_entry* e, void* arg)
        if(d->security == sec_status_bogus) {
                d->ttl = inf->expired;
                inf->num_msgs++;
+#ifdef USE_CACHEDB
+               if(inf->remcachedb && inf->worker->env.cachedb_enabled)
+                       cachedb_msg_remove_qinfo(&inf->worker->env,
+                               &((struct msgreply_entry*)e->key)->key);
+#endif
        }
 }
 
@@ -1826,9 +1871,12 @@ bogus_del_kcache(struct lruhash_entry* e, void* arg)
 
 /** remove all bogus rrsets, msgs and keys from cache */
 static void
-do_flush_bogus(RES* ssl, struct worker* worker)
+do_flush_bogus(RES* ssl, struct worker* worker, char* arg)
 {
        struct del_info inf;
+       int pc = 0; /* '+c' option */
+       if(!parse_remcachedb(ssl, &arg, &pc))
+               return;
        /* what we do is to set them all expired */
        inf.worker = worker;
        inf.expired = *worker->env.now;
@@ -1836,6 +1884,7 @@ do_flush_bogus(RES* ssl, struct worker* worker)
        inf.num_rrsets = 0;
        inf.num_msgs = 0;
        inf.num_keys = 0;
+       inf.remcachedb = pc;
        slabhash_traverse(&worker->env.rrset_cache->table, 1,
                &bogus_del_rrset, &inf);
 
@@ -1881,6 +1930,11 @@ negative_del_msg(struct lruhash_entry* e, void* arg)
        if(FLAGS_GET_RCODE(d->flags) != 0 || d->an_numrrsets == 0) {
                d->ttl = inf->expired;
                inf->num_msgs++;
+#ifdef USE_CACHEDB
+               if(inf->remcachedb && inf->worker->env.cachedb_enabled)
+                       cachedb_msg_remove_qinfo(&inf->worker->env,
+                               &((struct msgreply_entry*)e->key)->key);
+#endif
        }
 }
 
@@ -1901,9 +1955,12 @@ negative_del_kcache(struct lruhash_entry* e, void* arg)
 
 /** remove all negative(NODATA,NXDOMAIN), and servfail messages from cache */
 static void
-do_flush_negative(RES* ssl, struct worker* worker)
+do_flush_negative(RES* ssl, struct worker* worker, char* arg)
 {
        struct del_info inf;
+       int pc = 0; /* '+c' option */
+       if(!parse_remcachedb(ssl, &arg, &pc))
+               return;
        /* what we do is to set them all expired */
        inf.worker = worker;
        inf.expired = *worker->env.now;
@@ -1911,6 +1968,7 @@ do_flush_negative(RES* ssl, struct worker* worker)
        inf.num_rrsets = 0;
        inf.num_msgs = 0;
        inf.num_keys = 0;
+       inf.remcachedb = pc;
        slabhash_traverse(&worker->env.rrset_cache->table, 1,
                &negative_del_rrset, &inf);
 
@@ -1934,20 +1992,23 @@ do_flush_name(RES* ssl, struct worker* w, char* arg)
        uint8_t* nm;
        int nmlabs;
        size_t nmlen;
+       int pc = 0; /* '+c' option */
+       if(!parse_remcachedb(ssl, &arg, &pc))
+               return;
        if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
                return;
-       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN);
-       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_AAAA, LDNS_RR_CLASS_IN);
-       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN);
-       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SOA, LDNS_RR_CLASS_IN);
-       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_CNAME, LDNS_RR_CLASS_IN);
-       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_DNAME, LDNS_RR_CLASS_IN);
-       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_MX, LDNS_RR_CLASS_IN);
-       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_PTR, LDNS_RR_CLASS_IN);
-       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SRV, LDNS_RR_CLASS_IN);
-       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NAPTR, LDNS_RR_CLASS_IN);
-       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SVCB, LDNS_RR_CLASS_IN);
-       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_HTTPS, LDNS_RR_CLASS_IN);
+       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, pc);
+       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_AAAA, LDNS_RR_CLASS_IN, pc);
+       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN, pc);
+       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SOA, LDNS_RR_CLASS_IN, pc);
+       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_CNAME, LDNS_RR_CLASS_IN, pc);
+       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_DNAME, LDNS_RR_CLASS_IN, pc);
+       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_MX, LDNS_RR_CLASS_IN, pc);
+       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_PTR, LDNS_RR_CLASS_IN, pc);
+       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SRV, LDNS_RR_CLASS_IN, pc);
+       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_NAPTR, LDNS_RR_CLASS_IN, pc);
+       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_SVCB, LDNS_RR_CLASS_IN, pc);
+       do_cache_remove(w, nm, nmlen, LDNS_RR_TYPE_HTTPS, LDNS_RR_CLASS_IN, pc);
 
        free(nm);
        send_ok(ssl);
@@ -3214,9 +3275,9 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd,
        } else if(cmdcmp(p, "get_option", 10)) {
                do_get_option(ssl, worker, skipwhite(p+10));
        } else if(cmdcmp(p, "flush_bogus", 11)) {
-               do_flush_bogus(ssl, worker);
+               do_flush_bogus(ssl, worker, skipwhite(p+11));
        } else if(cmdcmp(p, "flush_negative", 14)) {
-               do_flush_negative(ssl, worker);
+               do_flush_negative(ssl, worker, skipwhite(p+14));
        } else if(cmdcmp(p, "rpz_enable", 10)) {
                do_rpz_enable(ssl, worker, skipwhite(p+10));
        } else if(cmdcmp(p, "rpz_disable", 11)) {
index ff61e3374259c2e34c5858127f07a76e0cbc0521..aed904dfb18b0112d230ad28b348fc8959a5b2d0 100644 (file)
@@ -2,6 +2,10 @@
        - Merge #1070: Fix rtt assignement for low values of
          infra-cache-max-rtt.
 
+16 May 2024: Wouter
+       - Fix #1071: [FR] Clear both in-memory and cachedb module cache with
+         `unbound-control flush*` commands.
+
 15 May 2024: Yorgos
        - Add missing common functions to tdir tests.
 
index 642b4c946d35ab54b7b54ed8dc79ad5cefeefdaa..cfaf2139389033993acc71b89032c8c5d8d82746 100644 (file)
@@ -134,18 +134,21 @@ in this way is supported in order to aid with debugging.
 Print to stdout the name servers that would be used to look up the
 name specified.
 .TP
-.B flush \fIname
+.B flush \fR[\fI+c\fR] \fIname
 Remove the name from the cache. Removes the types
 A, AAAA, NS, SOA, CNAME, DNAME, MX, PTR, SRV, NAPTR, SVCB and HTTPS.
 Because that is fast to do. Other record types can be removed using
 .B flush_type
 or
 .B flush_zone\fR.
+.IP
+The '+c' option removes the items also from the cachedb cache. If
+cachedb is in use.
 .TP
-.B flush_type \fIname\fR \fItype
+.B flush_type \fR[\fI+c\fR] \fIname\fR \fItype
 Remove the name, type information from the cache.
 .TP
-.B flush_zone \fIname
+.B flush_zone \fR[\fI+c\fR] \fIname
 Remove all information at or below the name from the cache.
 The rrsets and key entries are removed so that new lookups will be performed.
 This needs to walk and inspect the entire cache, and is a slow operation.
@@ -153,10 +156,10 @@ The entries are set to expired in the implementation of this command (so,
 with serve\-expired enabled, it'll serve that information but schedule a
 prefetch for new information).
 .TP
-.B flush_bogus
+.B flush_bogus \fR[\fI+c\fR]
 Remove all bogus data from the cache.
 .TP
-.B flush_negative
+.B flush_negative \fR[\fI+c\fR]
 Remove all negative data from the cache.  This is nxdomain answers,
 nodata answers and servfail answers.  Also removes bad key entries
 (which could be due to failed lookups) from the dnssec key cache, and
index 57b0787dbeeb2a8a376afcab13aa8468e6bd5ff1..59cd5def91fb59132fc64382d9d25942bcf59616 100644 (file)
@@ -128,14 +128,15 @@ usage(void)
        printf("  dump_cache                    print cache to stdout\n");
        printf("  load_cache                    load cache from stdin\n");
        printf("  lookup <name>                 print nameservers for name\n");
-       printf("  flush <name>                  flushes common types for name from cache\n");
+       printf("  flush [+c] <name>                     flushes common types for name from cache\n");
        printf("                                types:  A, AAAA, MX, PTR, NS,\n");
        printf("                                        SOA, CNAME, DNAME, SRV, NAPTR\n");
-       printf("  flush_type <name> <type>      flush name, type from cache\n");
-       printf("  flush_zone <name>             flush everything at or under name\n");
+       printf("  flush_type [+c] <name> <type> flush name, type from cache\n");
+       printf("                +c              remove from cachedb too\n");
+       printf("  flush_zone [+c] <name>        flush everything at or under name\n");
        printf("                                from rr and dnssec caches\n");
-       printf("  flush_bogus                   flush all bogus data\n");
-       printf("  flush_negative                flush all negative data\n");
+       printf("  flush_bogus [+c]              flush all bogus data\n");
+       printf("  flush_negative [+c]           flush all negative data\n");
        printf("  flush_stats                   flush statistics, make zero\n");
        printf("  flush_requestlist             drop queries that are worked on\n");
        printf("  dump_requestlist              show what is worked on by first thread\n");