aboutsummaryrefslogtreecommitdiff
path: root/contrib/unbound/cachedb/cachedb.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/unbound/cachedb/cachedb.c')
-rw-r--r--contrib/unbound/cachedb/cachedb.c133
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 */