diff --git a/cachedb/cachedb.c b/cachedb/cachedb.c index 95ac28904..0f3604576 100644 --- a/cachedb/cachedb.c +++ b/cachedb/cachedb.c @@ -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 */ diff --git a/cachedb/cachedb.h b/cachedb/cachedb.h index 2da8b5c71..482c5db6c 100644 --- a/cachedb/cachedb.h +++ b/cachedb/cachedb.h @@ -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); diff --git a/daemon/remote.c b/daemon/remote.c index 764ae8ffd..2e7d589e2 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -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 @@ -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)) { diff --git a/doc/Changelog b/doc/Changelog index ff61e3374..aed904dfb 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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. diff --git a/doc/unbound-control.8.in b/doc/unbound-control.8.in index 642b4c946..cfaf21393 100644 --- a/doc/unbound-control.8.in +++ b/doc/unbound-control.8.in @@ -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 diff --git a/smallapp/unbound-control.c b/smallapp/unbound-control.c index 57b0787db..59cd5def9 100644 --- a/smallapp/unbound-control.c +++ b/smallapp/unbound-control.c @@ -128,14 +128,15 @@ usage(void) printf(" dump_cache print cache to stdout\n"); printf(" load_cache load cache from stdin\n"); printf(" lookup print nameservers for name\n"); - printf(" flush flushes common types for name from cache\n"); + printf(" flush [+c] 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 flush name, type from cache\n"); - printf(" flush_zone flush everything at or under name\n"); + printf(" flush_type [+c] flush name, type from cache\n"); + printf(" +c remove from cachedb too\n"); + printf(" flush_zone [+c] 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");