mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-05-28 04:02:33 -04:00
- Fix #1071: [FR] Clear both in-memory and cachedb module cache with
`unbound-control flush*` commands.
This commit is contained in:
parent
739a88ceed
commit
da2b307aa3
6 changed files with 133 additions and 51 deletions
|
|
@ -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))
|
||||
|
|
@ -1004,20 +1004,25 @@ cachedb_is_enabled(struct module_stack* mods, struct module_env* env)
|
|||
|
||||
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];
|
||||
cachedb_msg_remove_qinfo(qstate->env, &qstate->qinfo);
|
||||
}
|
||||
|
||||
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);
|
||||
void cachedb_msg_remove_qinfo(struct module_env* env, struct query_info* qinfo)
|
||||
{
|
||||
char key[(CACHEDB_HASHSIZE/8)*2+1];
|
||||
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", 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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Reference in a new issue