diff options
Diffstat (limited to 'contrib/unbound/cachedb/cachedb.c')
-rw-r--r-- | contrib/unbound/cachedb/cachedb.c | 133 |
1 files changed, 115 insertions, 18 deletions
diff --git a/contrib/unbound/cachedb/cachedb.c b/contrib/unbound/cachedb/cachedb.c index b912be8ed54f..95ac28904693 100644 --- a/contrib/unbound/cachedb/cachedb.c +++ b/contrib/unbound/cachedb/cachedb.c @@ -50,6 +50,8 @@ #include "util/data/msgreply.h" #include "util/data/msgencode.h" #include "services/cache/dns.h" +#include "services/mesh.h" +#include "services/modstack.h" #include "validator/val_neg.h" #include "validator/val_secalgo.h" #include "iterator/iter_utils.h" @@ -265,15 +267,6 @@ cachedb_init(struct module_env* env, int id) return 0; } cachedb_env->enabled = 1; - if(env->cfg->serve_expired && env->cfg->serve_expired_reply_ttl) - log_warn( - "cachedb: serve-expired-reply-ttl is set but not working for data " - "originating from the external cache; 0 TTL is used for those."); - if(env->cfg->serve_expired && env->cfg->serve_expired_client_timeout) - log_warn( - "cachedb: serve-expired-client-timeout is set but not working for " - "data originating from the external cache; expired data are used " - "in the reply without first trying to refresh the data."); return 1; } @@ -511,9 +504,38 @@ adjust_msg_ttl(struct dns_msg* msg, time_t adjust) } } +/* Set the TTL of the given RRset to fixed value. */ +static void +packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl) +{ + size_t i; + size_t total = data->count + data->rrsig_count; + data->ttl = ttl; + for(i=0; i<total; i++) { + data->rr_ttl[i] = ttl; + } + data->ttl_add = 0; +} + +/* Set the TTL of a DNS message and its RRs by to a fixed value. */ +static void +set_msg_ttl(struct dns_msg* msg, time_t ttl) +{ + size_t i; + msg->rep->ttl = ttl; + msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl); + msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL; + + for(i=0; i<msg->rep->rrset_count; i++) { + packed_rrset_ttl_set((struct packed_rrset_data*)msg-> + rep->rrsets[i]->entry.data, ttl); + } +} + /** convert dns message in buffer to return_msg */ static int -parse_data(struct module_qstate* qstate, struct sldns_buffer* buf) +parse_data(struct module_qstate* qstate, struct sldns_buffer* buf, + int* msg_expired) { struct msg_parse* prs; struct edns_data edns; @@ -583,6 +605,7 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf) adjust = *qstate->env->now - (time_t)timestamp; if(qstate->return_msg->rep->ttl < adjust) { verbose(VERB_ALGO, "cachedb msg expired"); + *msg_expired = 1; /* If serve-expired is enabled, we still use an expired message * setting the TTL to 0. */ if(!qstate->env->cfg->serve_expired || @@ -605,6 +628,7 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf) * 'now' should be redundant given how these values were calculated, * but we check it just in case as does good_expiry_and_qinfo(). */ if(qstate->env->cfg->serve_expired && + !qstate->env->cfg->serve_expired_client_timeout && (adjust == -1 || (time_t)expiry < *qstate->env->now)) { qstate->need_refetch = 1; } @@ -617,7 +641,8 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf) * return true if lookup was successful. */ static int -cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie) +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)); @@ -634,7 +659,7 @@ cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie) } /* parse dns message into return_msg */ - if( !parse_data(qstate, qstate->env->scratch_buffer) ) { + if( !parse_data(qstate, qstate->env->scratch_buffer, msg_expired) ) { return 0; } return 1; @@ -666,6 +691,7 @@ cachedb_extcache_store(struct module_qstate* qstate, struct cachedb_env* ie) static int cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde) { + uint8_t dpname_storage[LDNS_MAX_DOMAINLEN+1]; uint8_t* dpname=NULL; size_t dpnamelen=0; struct dns_msg* msg; @@ -674,7 +700,7 @@ cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde) return 0; } if(iter_stub_fwd_no_cache(qstate, &qstate->qinfo, - &dpname, &dpnamelen)) + &dpname, &dpnamelen, dpname_storage, sizeof(dpname_storage))) return 0; /* no cache for these queries */ msg = dns_cache_lookup(qstate->env, qstate->qinfo.qname, qstate->qinfo.qname_len, qstate->qinfo.qtype, @@ -705,17 +731,39 @@ cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde) * Store query into the internal cache of unbound. */ static void -cachedb_intcache_store(struct module_qstate* qstate) +cachedb_intcache_store(struct module_qstate* qstate, int msg_expired) { uint32_t store_flags = qstate->query_flags; + int serve_expired = qstate->env->cfg->serve_expired; if(qstate->env->cfg->serve_expired) store_flags |= DNSCACHE_STORE_ZEROTTL; if(!qstate->return_msg) return; + if(serve_expired && msg_expired) { + /* Set TTLs to a value such that value + *env->now is + * going to be now-3 seconds. Making it expired + * in the cache. */ + set_msg_ttl(qstate->return_msg, (time_t)-3); + } (void)dns_cache_store(qstate->env, &qstate->qinfo, qstate->return_msg->rep, 0, qstate->prefetch_leeway, 0, qstate->region, store_flags, qstate->qstarttime); + if(serve_expired && msg_expired) { + if(qstate->env->cfg->serve_expired_client_timeout) { + /* No expired response from the query state, the + * query resolution needs to continue and it can + * pick up the expired result after the timer out + * of cache. */ + return; + } + /* set TTLs to zero again */ + adjust_msg_ttl(qstate->return_msg, -1); + /* Send serve expired responses based on the cachedb + * returned message, that was just stored in the cache. + * It can then continue to work on this query. */ + mesh_respond_serve_expired(qstate->mesh_info); + } } /** @@ -731,6 +779,7 @@ cachedb_handle_query(struct module_qstate* qstate, struct cachedb_qstate* ATTR_UNUSED(iq), struct cachedb_env* ie, int id) { + int msg_expired = 0; qstate->is_cachedb_answer = 0; /* check if we are enabled, and skip if so */ if(!ie->enabled) { @@ -765,20 +814,28 @@ cachedb_handle_query(struct module_qstate* qstate, } /* ask backend cache to see if we have data */ - if(cachedb_extcache_lookup(qstate, ie)) { + if(cachedb_extcache_lookup(qstate, ie, &msg_expired)) { if(verbosity >= VERB_ALGO) log_dns_msg(ie->backend->name, &qstate->return_msg->qinfo, qstate->return_msg->rep); /* store this result in internal cache */ - cachedb_intcache_store(qstate); + cachedb_intcache_store(qstate, msg_expired); /* In case we have expired data but there is a client timer for expired * answers, pass execution to next module in order to try updating the * data first. * 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. - * Document that ext cachedb does not work properly with - * serve_stale_reply_ttl yet. */ + */ + 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 && qstate->serve_expired_data->timer) { qstate->return_msg = NULL; @@ -791,6 +848,14 @@ cachedb_handle_query(struct module_qstate* qstate, return; } + if(qstate->serve_expired_data && + qstate->env->cfg->cachedb_check_when_serve_expired && + !qstate->env->cfg->serve_expired_client_timeout) { + /* Reply with expired data if any to client, because cachedb + * also has no useful, current data */ + mesh_respond_serve_expired(qstate->mesh_info); + } + /* no cache fetches */ /* pass request to next module */ qstate->ext_state[id] = module_wait_module; @@ -923,4 +988,36 @@ cachedb_get_funcblock(void) { return &cachedb_block; } + +int +cachedb_is_enabled(struct module_stack* mods, struct module_env* env) +{ + struct cachedb_env* ie; + int id = modstack_find(mods, "cachedb"); + if(id == -1) + return 0; + ie = (struct cachedb_env*)env->modinfo[id]; + if(ie && ie->enabled) + 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 */ |