mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 06:37:08 +00:00
Serve stale (#159)
- Added serve-stale functionality as described in draft-ietf-dnsop-serve-stale-10. `serve-expired-*` options can be used to configure the behavior. - Updated cachedb to honor `serve-expired-ttl`; Fixes #107. - Renamed statistic `num.zero_ttl` to `num.expired` as expired replies come with a configurable TTL value (`serve-expired-reply-ttl`). - Fixed stats when replying with cached, cname-aliased records. - Added missing default values for redis cachedb backend.
This commit is contained in:
parent
5980d9c389
commit
f7fe95ad7b
@ -218,10 +218,6 @@ static int
|
||||
cachedb_apply_cfg(struct cachedb_env* cachedb_env, struct config_file* cfg)
|
||||
{
|
||||
const char* backend_str = cfg->cachedb_backend;
|
||||
|
||||
/* If unspecified we use the in-memory test DB. */
|
||||
if(!backend_str)
|
||||
backend_str = "testframe";
|
||||
cachedb_env->backend = cachedb_find_backend(backend_str);
|
||||
if(!cachedb_env->backend) {
|
||||
log_err("cachedb: cannot find backend name '%s'", backend_str);
|
||||
@ -259,6 +255,15 @@ cachedb_init(struct module_env* env, int id)
|
||||
return 0;
|
||||
}
|
||||
cachedb_env->enabled = 1;
|
||||
if(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 TLL is used for those.");
|
||||
if(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;
|
||||
}
|
||||
|
||||
@ -329,8 +334,7 @@ calc_hash(struct module_qstate* qstate, char* buf, size_t len)
|
||||
size_t clen = 0;
|
||||
uint8_t hash[CACHEDB_HASHSIZE/8];
|
||||
const char* hex = "0123456789ABCDEF";
|
||||
const char* secret = qstate->env->cfg->cachedb_secret ?
|
||||
qstate->env->cfg->cachedb_secret : "default";
|
||||
const char* secret = qstate->env->cfg->cachedb_secret;
|
||||
size_t i;
|
||||
|
||||
/* copy the hash info into the clear buffer */
|
||||
@ -433,8 +437,14 @@ good_expiry_and_qinfo(struct module_qstate* qstate, struct sldns_buffer* buf)
|
||||
&expiry, sizeof(expiry));
|
||||
expiry = be64toh(expiry);
|
||||
|
||||
/* Check if we are allowed to return expired entries:
|
||||
* - serve_expired needs to be set
|
||||
* - if SERVE_EXPIRED_TTL is set make sure that the record is not older
|
||||
* than that. */
|
||||
if((time_t)expiry < *qstate->env->now &&
|
||||
!qstate->env->cfg->serve_expired)
|
||||
(!qstate->env->cfg->serve_expired ||
|
||||
(SERVE_EXPIRED_TTL &&
|
||||
*qstate->env->now - (time_t)expiry > SERVE_EXPIRED_TTL)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@ -445,15 +455,15 @@ good_expiry_and_qinfo(struct module_qstate* qstate, struct sldns_buffer* buf)
|
||||
static void
|
||||
packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract)
|
||||
{
|
||||
size_t i;
|
||||
size_t total = data->count + data->rrsig_count;
|
||||
size_t i;
|
||||
size_t total = data->count + data->rrsig_count;
|
||||
if(subtract >= 0 && data->ttl > subtract)
|
||||
data->ttl -= subtract;
|
||||
else data->ttl = 0;
|
||||
for(i=0; i<total; i++) {
|
||||
for(i=0; i<total; i++) {
|
||||
if(subtract >= 0 && data->rr_ttl[i] > subtract)
|
||||
data->rr_ttl[i] -= subtract;
|
||||
else data->rr_ttl[i] = 0;
|
||||
data->rr_ttl[i] -= subtract;
|
||||
else data->rr_ttl[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -465,7 +475,8 @@ adjust_msg_ttl(struct dns_msg* msg, time_t adjust)
|
||||
size_t i;
|
||||
if(adjust >= 0 && msg->rep->ttl > adjust)
|
||||
msg->rep->ttl -= adjust;
|
||||
else msg->rep->ttl = 0;
|
||||
else
|
||||
msg->rep->ttl = 0;
|
||||
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
|
||||
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
|
||||
|
||||
@ -673,7 +684,8 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
return;
|
||||
}
|
||||
|
||||
/* lookup inside unbound's internal cache */
|
||||
/* lookup inside unbound's internal cache.
|
||||
* This does not look for expired entries. */
|
||||
if(cachedb_intcache_lookup(qstate)) {
|
||||
if(verbosity >= VERB_ALGO) {
|
||||
if(qstate->return_msg->rep)
|
||||
@ -681,8 +693,9 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
&qstate->return_msg->qinfo,
|
||||
qstate->return_msg->rep);
|
||||
else log_info("cachedb internal cache lookup: rcode %s",
|
||||
sldns_lookup_by_id(sldns_rcodes, qstate->return_rcode)?
|
||||
sldns_lookup_by_id(sldns_rcodes, qstate->return_rcode)->name:"??");
|
||||
sldns_lookup_by_id(sldns_rcodes, qstate->return_rcode)
|
||||
?sldns_lookup_by_id(sldns_rcodes, qstate->return_rcode)->name
|
||||
:"??");
|
||||
}
|
||||
/* we are done with the query */
|
||||
qstate->ext_state[id] = module_finished;
|
||||
@ -697,6 +710,19 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
qstate->return_msg->rep);
|
||||
/* store this result in internal cache */
|
||||
cachedb_intcache_store(qstate);
|
||||
/* 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->need_refetch && qstate->serve_expired_data &&
|
||||
qstate->serve_expired_data->timer) {
|
||||
qstate->return_msg = NULL;
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
return;
|
||||
}
|
||||
/* we are done with the query */
|
||||
qstate->ext_state[id] = module_finished;
|
||||
return;
|
||||
|
@ -720,8 +720,8 @@ print_stats(RES* ssl, const char* nm, struct ub_stats_info* s)
|
||||
(unsigned long)s->svr.num_queries_missed_cache)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.prefetch"SQ"%lu\n", nm,
|
||||
(unsigned long)s->svr.num_queries_prefetch)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.zero_ttl"SQ"%lu\n", nm,
|
||||
(unsigned long)s->svr.zero_ttl_responses)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.expired"SQ"%lu\n", nm,
|
||||
(unsigned long)s->svr.ans_expired)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.recursivereplies"SQ"%lu\n", nm,
|
||||
(unsigned long)s->mesh_replies_sent)) return 0;
|
||||
#ifdef USE_DNSCRYPT
|
||||
|
@ -400,6 +400,7 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
|
||||
total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache;
|
||||
total->svr.num_queries_prefetch += a->svr.num_queries_prefetch;
|
||||
total->svr.sum_query_list_size += a->svr.sum_query_list_size;
|
||||
total->svr.ans_expired += a->svr.ans_expired;
|
||||
#ifdef USE_DNSCRYPT
|
||||
total->svr.num_query_dnscrypt_crypted += a->svr.num_query_dnscrypt_crypted;
|
||||
total->svr.num_query_dnscrypt_cert += a->svr.num_query_dnscrypt_cert;
|
||||
@ -432,7 +433,6 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
|
||||
total->svr.qEDNS += a->svr.qEDNS;
|
||||
total->svr.qEDNS_DO += a->svr.qEDNS_DO;
|
||||
total->svr.ans_rcode_nodata += a->svr.ans_rcode_nodata;
|
||||
total->svr.zero_ttl_responses += a->svr.zero_ttl_responses;
|
||||
total->svr.ans_secure += a->svr.ans_secure;
|
||||
total->svr.ans_bogus += a->svr.ans_bogus;
|
||||
total->svr.unwanted_replies += a->svr.unwanted_replies;
|
||||
|
@ -625,10 +625,10 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
|
||||
* be completely dropped, '*need_drop' will be set to 1. */
|
||||
static int
|
||||
answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
struct respip_client_info* cinfo, int* need_drop,
|
||||
struct ub_packed_rrset_key** alias_rrset,
|
||||
struct respip_client_info* cinfo, int* need_drop, int* is_expired_answer,
|
||||
int* is_secure_answer, struct ub_packed_rrset_key** alias_rrset,
|
||||
struct reply_info** partial_repp,
|
||||
struct reply_info* rep, uint16_t id, uint16_t flags,
|
||||
struct reply_info* rep, uint16_t id, uint16_t flags,
|
||||
struct comm_reply* repinfo, struct edns_data* edns)
|
||||
{
|
||||
struct edns_data edns_bak;
|
||||
@ -636,38 +636,37 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
uint16_t udpsize = edns->udp_size;
|
||||
struct reply_info* encode_rep = rep;
|
||||
struct reply_info* partial_rep = *partial_repp;
|
||||
int secure;
|
||||
int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd)
|
||||
&& worker->env.need_to_validate;
|
||||
*partial_repp = NULL; /* avoid accidental further pass */
|
||||
if(worker->env.cfg->serve_expired) {
|
||||
if(worker->env.cfg->serve_expired_ttl &&
|
||||
rep->serve_expired_ttl < timenow)
|
||||
return 0;
|
||||
if(!rrset_array_lock(rep->ref, rep->rrset_count, 0))
|
||||
return 0;
|
||||
/* below, rrsets with ttl before timenow become TTL 0 in
|
||||
* the response */
|
||||
/* This response was served with zero TTL */
|
||||
if (timenow >= rep->ttl) {
|
||||
worker->stats.zero_ttl_responses++;
|
||||
}
|
||||
} else {
|
||||
/* see if it is possible */
|
||||
if(rep->ttl < timenow) {
|
||||
*partial_repp = NULL; /* avoid accidental further pass */
|
||||
|
||||
/* Check TTL */
|
||||
if(rep->ttl < timenow) {
|
||||
/* Check if we need to serve expired now */
|
||||
if(worker->env.cfg->serve_expired &&
|
||||
!worker->env.cfg->serve_expired_client_timeout) {
|
||||
if(worker->env.cfg->serve_expired_ttl &&
|
||||
rep->serve_expired_ttl < timenow)
|
||||
return 0;
|
||||
if(!rrset_array_lock(rep->ref, rep->rrset_count, 0))
|
||||
return 0;
|
||||
*is_expired_answer = 1;
|
||||
} else {
|
||||
/* the rrsets may have been updated in the meantime.
|
||||
* we will refetch the message format from the
|
||||
* authoritative server
|
||||
* authoritative server
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow))
|
||||
return 0;
|
||||
/* locked and ids and ttls are OK. */
|
||||
}
|
||||
/* locked and ids and ttls are OK. */
|
||||
|
||||
/* check CNAME chain (if any) */
|
||||
if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type ==
|
||||
htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type ==
|
||||
if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type ==
|
||||
htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type ==
|
||||
htons(LDNS_RR_TYPE_DNAME))) {
|
||||
if(!reply_check_cname_chain(qinfo, rep)) {
|
||||
/* cname chain invalid, redo iterator steps */
|
||||
@ -686,31 +685,31 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep,
|
||||
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
|
||||
goto bail_out;
|
||||
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
|
||||
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
|
||||
qinfo, id, flags, edns);
|
||||
rrset_array_unlock_touch(worker->env.rrset_cache,
|
||||
rrset_array_unlock_touch(worker->env.rrset_cache,
|
||||
worker->scratchpad, rep->ref, rep->rrset_count);
|
||||
if(worker->stats.extended) {
|
||||
worker->stats.ans_bogus ++;
|
||||
worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++;
|
||||
}
|
||||
return 1;
|
||||
} else if( rep->security == sec_status_unchecked && must_validate) {
|
||||
} else if(rep->security == sec_status_unchecked && must_validate) {
|
||||
verbose(VERB_ALGO, "Cache reply: unchecked entry needs "
|
||||
"validation");
|
||||
goto bail_out; /* need to validate cache entry first */
|
||||
} else if(rep->security == sec_status_secure) {
|
||||
if(reply_all_rrsets_secure(rep))
|
||||
secure = 1;
|
||||
else {
|
||||
if(reply_all_rrsets_secure(rep)) {
|
||||
*is_secure_answer = 1;
|
||||
} else {
|
||||
if(must_validate) {
|
||||
verbose(VERB_ALGO, "Cache reply: secure entry"
|
||||
" changed status");
|
||||
goto bail_out; /* rrset changed, re-verify */
|
||||
}
|
||||
secure = 0;
|
||||
*is_secure_answer = 0;
|
||||
}
|
||||
} else secure = 0;
|
||||
} else *is_secure_answer = 0;
|
||||
|
||||
edns_bak = *edns;
|
||||
edns->edns_version = EDNS_ADVERTISED_VERSION;
|
||||
@ -732,8 +731,10 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
worker->env.auth_zones)) {
|
||||
goto bail_out;
|
||||
}
|
||||
if(encode_rep != rep)
|
||||
secure = 0; /* if rewritten, it can't be considered "secure" */
|
||||
if(encode_rep != rep) {
|
||||
/* if rewritten, it can't be considered "secure" */
|
||||
*is_secure_answer = 0;
|
||||
}
|
||||
if(!encode_rep || *alias_rrset) {
|
||||
if(!encode_rep)
|
||||
*need_drop = 1;
|
||||
@ -750,7 +751,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
repinfo->c, worker->scratchpad) ||
|
||||
!reply_info_answer_encode(qinfo, encode_rep, id, flags,
|
||||
repinfo->c->buffer, timenow, 1, worker->scratchpad,
|
||||
udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
|
||||
udpsize, edns, (int)(edns->bits & EDNS_DO), *is_secure_answer)) {
|
||||
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
|
||||
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad))
|
||||
edns->opt_list = NULL;
|
||||
@ -761,10 +762,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
||||
* is bad while holding locks. */
|
||||
rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad,
|
||||
rep->ref, rep->rrset_count);
|
||||
if(worker->stats.extended) {
|
||||
if(secure) worker->stats.ans_secure++;
|
||||
server_stats_insrcode(&worker->stats, repinfo->c->buffer);
|
||||
}
|
||||
/* go and return this buffer to the client */
|
||||
return 1;
|
||||
|
||||
@ -1099,6 +1096,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
struct acl_addr* acladdr;
|
||||
int rc = 0;
|
||||
int need_drop = 0;
|
||||
int is_expired_answer = 0;
|
||||
int is_secure_answer = 0;
|
||||
/* We might have to chase a CNAME chain internally, in which case
|
||||
* we'll have up to two replies and combine them to build a complete
|
||||
* answer. These variables control this case. */
|
||||
@ -1481,12 +1480,14 @@ lookup_cache:
|
||||
* each pass. We should still pass the original qinfo to
|
||||
* answer_from_cache(), however, since it's used to build the reply. */
|
||||
if(!edns_bypass_cache_stage(edns.opt_list, &worker->env)) {
|
||||
is_expired_answer = 0;
|
||||
is_secure_answer = 0;
|
||||
h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2));
|
||||
if((e=slabhash_lookup(worker->env.msg_cache, h, lookup_qinfo, 0))) {
|
||||
/* answer from cache - we have acquired a readlock on it */
|
||||
if(answer_from_cache(worker, &qinfo,
|
||||
cinfo, &need_drop, &alias_rrset, &partial_rep,
|
||||
(struct reply_info*)e->data,
|
||||
cinfo, &need_drop, &is_expired_answer, &is_secure_answer,
|
||||
&alias_rrset, &partial_rep, (struct reply_info*)e->data,
|
||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
|
||||
&edns)) {
|
||||
@ -1583,6 +1584,13 @@ send_reply_rc:
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
if(is_expired_answer) {
|
||||
worker->stats.ans_expired++;
|
||||
}
|
||||
if(worker->stats.extended) {
|
||||
if(is_secure_answer) worker->stats.ans_secure++;
|
||||
server_stats_insrcode(&worker->stats, repinfo->c->buffer);
|
||||
}
|
||||
#ifdef USE_DNSTAP
|
||||
if(worker->dtenv.log_client_response_messages)
|
||||
dt_msg_send_client_response(&worker->dtenv, &repinfo->addr,
|
||||
@ -1858,6 +1866,10 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
return 0;
|
||||
}
|
||||
worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env);
|
||||
/* Pass on daemon variables that we would need in the mesh area */
|
||||
worker->env.mesh->use_response_ip = worker->daemon->use_response_ip;
|
||||
worker->env.mesh->use_rpz = worker->daemon->use_rpz;
|
||||
|
||||
worker->env.detach_subs = &mesh_detach_subs;
|
||||
worker->env.attach_sub = &mesh_attach_sub;
|
||||
worker->env.add_sub = &mesh_add_sub;
|
||||
|
@ -1,4 +1,14 @@
|
||||
-3 February 2020: Ralph
|
||||
5 February 2020: George
|
||||
- Added serve-stale functionality as described in
|
||||
draft-ietf-dnsop-serve-stale-10. `serve-expired-*` options can be used
|
||||
to configure the behavior.
|
||||
- Updated cachedb to honor `serve-expired-ttl`; Fixes #107.
|
||||
- Renamed statistic `num.zero_ttl` to `num.expired` as expired replies
|
||||
come with a configurable TTL value (`serve-expired-reply-ttl`).
|
||||
- Fixed stats when replying with cached, cname-aliased records.
|
||||
- Added missing default values for redis cachedb backend.
|
||||
|
||||
3 February 2020: Ralph
|
||||
- Add assertion to please static analyzer
|
||||
|
||||
31 January 2020: Wouter
|
||||
|
@ -558,8 +558,8 @@ server:
|
||||
# that set CD but cannot validate themselves.
|
||||
# ignore-cd-flag: no
|
||||
|
||||
# Serve expired responses from cache, with TTL 0 in the response,
|
||||
# and then attempt to fetch the data afresh.
|
||||
# Serve expired responses from cache, with serve-expired-reply-ttl in
|
||||
# the response, and then attempt to fetch the data afresh.
|
||||
# serve-expired: no
|
||||
#
|
||||
# Limit serving of expired responses to configured seconds after
|
||||
@ -571,6 +571,16 @@ server:
|
||||
# that the expired records will be served as long as there are queries
|
||||
# for it.
|
||||
# serve-expired-ttl-reset: no
|
||||
#
|
||||
# TTL value to use when replying with expired data.
|
||||
# serve-expired-reply-ttl: 30
|
||||
#
|
||||
# Time in milliseconds before replying to the client with expired data.
|
||||
# This essentially enables the serve-stale behavior as specified in
|
||||
# draft-ietf-dnsop-serve-stale-10 that first tries to resolve before
|
||||
# immediately responding with expired data. 0 disables this behavior.
|
||||
# A recommended value is 1800.
|
||||
# serve-expired-client-timeout: 0
|
||||
|
||||
# Have the validator log failed validations for your diagnosis.
|
||||
# 0: off. 1: A line per failed user query. 2: With reason and bad IP.
|
||||
|
@ -382,8 +382,8 @@ and resulted in recursive processing, taking a slot in the requestlist.
|
||||
Not part of the recursivereplies (or the histogram thereof) or cachemiss,
|
||||
as a cache response was sent.
|
||||
.TP
|
||||
.I threadX.num.zero_ttl
|
||||
number of replies with ttl zero, because they served an expired cache entry.
|
||||
.I threadX.num.expired
|
||||
number of replies that served an expired cache entry.
|
||||
.TP
|
||||
.I threadX.num.recursivereplies
|
||||
The number of replies sent to queries that needed recursive processing. Could be smaller than threadX.num.cachemiss if due to timeouts no replies were sent for some queries.
|
||||
@ -446,7 +446,7 @@ summed over threads.
|
||||
.I total.num.prefetch
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.num.zero_ttl
|
||||
.I total.num.expired
|
||||
summed over threads.
|
||||
.TP
|
||||
.I total.num.recursivereplies
|
||||
|
@ -1070,20 +1070,35 @@ The default value is "no".
|
||||
.TP
|
||||
.B serve\-expired: \fI<yes or no>
|
||||
If enabled, unbound attempts to serve old responses from cache with a
|
||||
TTL of 0 in the response without waiting for the actual resolution to finish.
|
||||
The actual resolution answer ends up in the cache later on. Default is "no".
|
||||
TTL of \fBserve\-expired\-reply\-ttl\fR in the response without waiting for the
|
||||
actual resolution to finish. The actual resolution answer ends up in the cache
|
||||
later on. Default is "no".
|
||||
.TP
|
||||
.B serve\-expired\-ttl: \fI<seconds>
|
||||
Limit serving of expired responses to configured seconds after expiration. 0
|
||||
disables the limit. This option only applies when \fBserve\-expired\fR is
|
||||
enabled. The default is 0.
|
||||
disables the limit. This option only applies when \fBserve\-expired\fR is
|
||||
enabled. A suggested value per draft-ietf-dnsop-serve-stale-10 is between
|
||||
86400 (1 day) and 259200 (3 days). The default is 0.
|
||||
.TP
|
||||
.B serve\-expired\-ttl\-reset: \fI<yes or no>
|
||||
Set the TTL of expired records to the \fBserve\-expired\-ttl\fR value after a
|
||||
failed attempt to retrieve the record from upstream. This makes sure that the
|
||||
expired records will be served as long as there are queries for it. Default is
|
||||
failed attempt to retrieve the record from upstream. This makes sure that the
|
||||
expired records will be served as long as there are queries for it. Default is
|
||||
"no".
|
||||
.TP
|
||||
.B serve\-expired\-reply\-ttl: \fI<seconds>
|
||||
TTL value to use when replying with expired data. If
|
||||
\fBserve\-expired\-client\-timeout\fR is also used then it is RECOMMENDED to
|
||||
use 30 as the value (draft-ietf-dnsop-serve-stale-10). The default is 30.
|
||||
.TP
|
||||
.B serve\-expired\-client\-timeout: \fI<msec>
|
||||
Time in milliseconds before replying to the client with expired data. This
|
||||
essentially enables the serve-stale behavior as specified in
|
||||
draft-ietf-dnsop-serve-stale-10 that first tries to resolve before immediately
|
||||
responding with expired data. A recommended value per
|
||||
draft-ietf-dnsop-serve-stale-10 is 1800. Setting this to 0 will disable this
|
||||
behavior. Default is 0.
|
||||
.TP
|
||||
.B val\-nsec3\-keysize\-iterations: \fI<"list of values">
|
||||
List of keysize and iteration count values, separated by spaces, surrounded
|
||||
by quotes. Default is "1024 150 2048 500 4096 2500". This determines the
|
||||
@ -2024,6 +2039,13 @@ to the query without performing iterative DNS resolution.
|
||||
If Unbound cannot even find an answer in the backend, it resolves the
|
||||
query as usual, and stores the answer in the backend.
|
||||
.P
|
||||
This module interacts with the \fBserve\-expired\-*\fR options and will reply
|
||||
with expired data if unbound is configured for that. Currently the use
|
||||
of \fBserve\-expired\-client\-timeout:\fR and
|
||||
\fBserve\-expired\-reply\-ttl:\fR is not consistent for data originating from
|
||||
the external cache as these will result in a reply with 0 TTL without trying to
|
||||
update the data first, ignoring the configured values.
|
||||
.P
|
||||
If Unbound was built with
|
||||
\fB\-\-with\-libhiredis\fR
|
||||
on a system that has installed the hiredis C client library of Redis,
|
||||
|
@ -431,7 +431,7 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
}
|
||||
|
||||
qstate->return_msg = tomsg(NULL, &qstate->qinfo,
|
||||
(struct reply_info *)node->elem, qstate->region, *env->now,
|
||||
(struct reply_info *)node->elem, qstate->region, *env->now, 0,
|
||||
env->scratch);
|
||||
scope = (uint8_t)node->scope;
|
||||
lock_rw_unlock(&e->lock);
|
||||
|
@ -561,7 +561,6 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
|
||||
if(!qinfo->qname) {
|
||||
return 0;
|
||||
}
|
||||
qinfo->local_alias = NULL;
|
||||
edns->edns_present = 1;
|
||||
edns->ext_rcode = 0;
|
||||
edns->edns_version = 0;
|
||||
|
@ -735,8 +735,8 @@ struct ub_server_stats {
|
||||
long long unwanted_queries;
|
||||
/** usage of tcp accept list */
|
||||
long long tcp_accept_usage;
|
||||
/** answers served from expired cache */
|
||||
long long zero_ttl_responses;
|
||||
/** expired answers served from cache */
|
||||
long long ans_expired;
|
||||
/** histogram data exported to array
|
||||
* if the array is the same size, no data is lost, and
|
||||
* if all histograms are same size (is so by default) then
|
||||
|
120
services/cache/dns.c
vendored
120
services/cache/dns.c
vendored
@ -45,6 +45,7 @@
|
||||
#include "validator/val_utils.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/msgreply.h"
|
||||
#include "util/data/packed_rrset.h"
|
||||
#include "util/data/dname.h"
|
||||
@ -73,15 +74,15 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
|
||||
time_t leeway, int pside, struct reply_info* qrep,
|
||||
struct regional* region)
|
||||
{
|
||||
size_t i;
|
||||
/* see if rrset already exists in cache, if not insert it. */
|
||||
for(i=0; i<rep->rrset_count; i++) {
|
||||
rep->ref[i].key = rep->rrsets[i];
|
||||
rep->ref[i].id = rep->rrsets[i]->id;
|
||||
/* update ref if it was in the cache */
|
||||
size_t i;
|
||||
/* see if rrset already exists in cache, if not insert it. */
|
||||
for(i=0; i<rep->rrset_count; i++) {
|
||||
rep->ref[i].key = rep->rrsets[i];
|
||||
rep->ref[i].id = rep->rrsets[i]->id;
|
||||
/* update ref if it was in the cache */
|
||||
switch(rrset_cache_update(env->rrset_cache, &rep->ref[i],
|
||||
env->alloc, now + ((ntohs(rep->ref[i].key->rk.type)==
|
||||
LDNS_RR_TYPE_NS && !pside)?0:leeway))) {
|
||||
env->alloc, now + ((ntohs(rep->ref[i].key->rk.type)==
|
||||
LDNS_RR_TYPE_NS && !pside)?0:leeway))) {
|
||||
case 0: /* ref unchanged, item inserted */
|
||||
break;
|
||||
case 2: /* ref updated, cache is superior */
|
||||
@ -104,9 +105,9 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
|
||||
* the fallthrough warning */
|
||||
/* fallthrough */
|
||||
case 1: /* ref updated, item inserted */
|
||||
rep->rrsets[i] = rep->ref[i].key;
|
||||
rep->rrsets[i] = rep->ref[i].key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** delete message from message cache */
|
||||
@ -532,31 +533,51 @@ gen_dns_msg(struct regional* region, struct query_info* q, size_t num)
|
||||
}
|
||||
|
||||
struct dns_msg*
|
||||
tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
|
||||
struct regional* region, time_t now, struct regional* scratch)
|
||||
tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
|
||||
struct regional* region, time_t now, int allow_expired,
|
||||
struct regional* scratch)
|
||||
{
|
||||
struct dns_msg* msg;
|
||||
size_t i;
|
||||
if(now > r->ttl)
|
||||
return NULL;
|
||||
int is_expired = 0;
|
||||
time_t now_control = now;
|
||||
if(now > r->ttl) {
|
||||
/* Check if we are allowed to serve expired */
|
||||
if(allow_expired) {
|
||||
if(env->cfg->serve_expired_ttl &&
|
||||
r->serve_expired_ttl < now) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
/* Change the current time so we can pass the below TTL checks when
|
||||
* serving expired data. */
|
||||
now_control = r->ttl - env->cfg->serve_expired_reply_ttl;
|
||||
is_expired = 1;
|
||||
}
|
||||
|
||||
msg = gen_dns_msg(region, q, r->rrset_count);
|
||||
if(!msg)
|
||||
return NULL;
|
||||
if(!msg) return NULL;
|
||||
msg->rep->flags = r->flags;
|
||||
msg->rep->qdcount = r->qdcount;
|
||||
msg->rep->ttl = r->ttl - now;
|
||||
msg->rep->ttl = is_expired
|
||||
?SERVE_EXPIRED_REPLY_TTL
|
||||
:r->ttl - now;
|
||||
if(r->prefetch_ttl > now)
|
||||
msg->rep->prefetch_ttl = r->prefetch_ttl - now;
|
||||
else msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
|
||||
else
|
||||
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
|
||||
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
|
||||
msg->rep->security = r->security;
|
||||
msg->rep->an_numrrsets = r->an_numrrsets;
|
||||
msg->rep->ns_numrrsets = r->ns_numrrsets;
|
||||
msg->rep->ar_numrrsets = r->ar_numrrsets;
|
||||
msg->rep->rrset_count = r->rrset_count;
|
||||
msg->rep->authoritative = r->authoritative;
|
||||
if(!rrset_array_lock(r->ref, r->rrset_count, now))
|
||||
msg->rep->authoritative = r->authoritative;
|
||||
if(!rrset_array_lock(r->ref, r->rrset_count, now_control)) {
|
||||
return NULL;
|
||||
}
|
||||
if(r->an_numrrsets > 0 && (r->rrsets[0]->rk.type == htons(
|
||||
LDNS_RR_TYPE_CNAME) || r->rrsets[0]->rk.type == htons(
|
||||
LDNS_RR_TYPE_DNAME)) && !reply_check_cname_chain(q, r)) {
|
||||
@ -570,7 +591,7 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
|
||||
return NULL;
|
||||
}
|
||||
for(i=0; i<msg->rep->rrset_count; i++) {
|
||||
msg->rep->rrsets[i] = packed_rrset_copy_region(r->rrsets[i],
|
||||
msg->rep->rrsets[i] = packed_rrset_copy_region(r->rrsets[i],
|
||||
region, now);
|
||||
if(!msg->rep->rrsets[i]) {
|
||||
rrset_array_unlock(r->ref, r->rrset_count);
|
||||
@ -797,7 +818,7 @@ dns_cache_lookup(struct module_env* env,
|
||||
if(e) {
|
||||
struct msgreply_entry* key = (struct msgreply_entry*)e->key;
|
||||
struct reply_info* data = (struct reply_info*)e->data;
|
||||
struct dns_msg* msg = tomsg(env, &key->key, data, region, now,
|
||||
struct dns_msg* msg = tomsg(env, &key->key, data, region, now, 0,
|
||||
scratch);
|
||||
if(msg) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
@ -899,37 +920,38 @@ dns_cache_lookup(struct module_env* env,
|
||||
* Empty nonterminals are NOERROR, so an NXDOMAIN for foo
|
||||
* means bla.foo also does not exist. The DNSSEC proofs are
|
||||
* the same. We search upwards for NXDOMAINs. */
|
||||
if(env->cfg->harden_below_nxdomain)
|
||||
while(!dname_is_root(k.qname)) {
|
||||
dname_remove_label(&k.qname, &k.qname_len);
|
||||
h = query_info_hash(&k, flags);
|
||||
e = slabhash_lookup(env->msg_cache, h, &k, 0);
|
||||
if(!e && k.qtype != LDNS_RR_TYPE_A &&
|
||||
env->cfg->qname_minimisation) {
|
||||
k.qtype = LDNS_RR_TYPE_A;
|
||||
if(env->cfg->harden_below_nxdomain) {
|
||||
while(!dname_is_root(k.qname)) {
|
||||
dname_remove_label(&k.qname, &k.qname_len);
|
||||
h = query_info_hash(&k, flags);
|
||||
e = slabhash_lookup(env->msg_cache, h, &k, 0);
|
||||
}
|
||||
if(e) {
|
||||
struct reply_info* data = (struct reply_info*)e->data;
|
||||
struct dns_msg* msg;
|
||||
if(FLAGS_GET_RCODE(data->flags) == LDNS_RCODE_NXDOMAIN
|
||||
&& data->security == sec_status_secure
|
||||
&& (data->an_numrrsets == 0 ||
|
||||
ntohs(data->rrsets[0]->rk.type) != LDNS_RR_TYPE_CNAME)
|
||||
&& (msg=tomsg(env, &k, data, region, now, scratch))){
|
||||
lock_rw_unlock(&e->lock);
|
||||
msg->qinfo.qname=qname;
|
||||
msg->qinfo.qname_len=qnamelen;
|
||||
/* check that DNSSEC really works out */
|
||||
msg->rep->security = sec_status_unchecked;
|
||||
iter_scrub_nxdomain(msg);
|
||||
return msg;
|
||||
if(!e && k.qtype != LDNS_RR_TYPE_A &&
|
||||
env->cfg->qname_minimisation) {
|
||||
k.qtype = LDNS_RR_TYPE_A;
|
||||
h = query_info_hash(&k, flags);
|
||||
e = slabhash_lookup(env->msg_cache, h, &k, 0);
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
if(e) {
|
||||
struct reply_info* data = (struct reply_info*)e->data;
|
||||
struct dns_msg* msg;
|
||||
if(FLAGS_GET_RCODE(data->flags) == LDNS_RCODE_NXDOMAIN
|
||||
&& data->security == sec_status_secure
|
||||
&& (data->an_numrrsets == 0 ||
|
||||
ntohs(data->rrsets[0]->rk.type) != LDNS_RR_TYPE_CNAME)
|
||||
&& (msg=tomsg(env, &k, data, region, now, 0, scratch))) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
msg->qinfo.qname=qname;
|
||||
msg->qinfo.qname_len=qnamelen;
|
||||
/* check that DNSSEC really works out */
|
||||
msg->rep->security = sec_status_unchecked;
|
||||
iter_scrub_nxdomain(msg);
|
||||
return msg;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
}
|
||||
k.qtype = qtype;
|
||||
}
|
||||
k.qtype = qtype;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill common RR types for ANY response to avoid requery */
|
||||
if(qtype == LDNS_RR_TYPE_ANY) {
|
||||
|
7
services/cache/dns.h
vendored
7
services/cache/dns.h
vendored
@ -143,11 +143,14 @@ struct delegpt* dns_cache_find_delegation(struct module_env* env,
|
||||
* @param r: reply info that, together with qname, will make up the dns message.
|
||||
* @param region: where to allocate dns message.
|
||||
* @param now: the time now, for check if TTL on cache entry is ok.
|
||||
* @param allow_expired: if true and serve-expired is enabled, it will allow
|
||||
* for expired dns_msg to be generated based on the configured serve-expired
|
||||
* logic.
|
||||
* @param scratch: where to allocate temporary data.
|
||||
* */
|
||||
struct dns_msg* tomsg(struct module_env* env, struct query_info* q,
|
||||
struct reply_info* r, struct regional* region, time_t now,
|
||||
struct regional* scratch);
|
||||
int allow_expired, struct regional* scratch);
|
||||
|
||||
/**
|
||||
* Find cached message
|
||||
@ -160,7 +163,7 @@ struct dns_msg* tomsg(struct module_env* env, struct query_info* q,
|
||||
* @param region: where to allocate result.
|
||||
* @param scratch: where to allocate temporary data.
|
||||
* @param no_partial: if true, only complete messages and not a partial
|
||||
* one (with only the start of the CNAME chain and not the rest).
|
||||
* one (with only the start of the CNAME chain and not the rest).
|
||||
* @return new response message (alloced in region, rrsets do not have IDs).
|
||||
* or NULL on error or if not found in cache.
|
||||
* TTLs are made relative to the current time.
|
||||
|
410
services/mesh.c
410
services/mesh.c
@ -46,6 +46,7 @@
|
||||
#include "services/mesh.h"
|
||||
#include "services/outbound_list.h"
|
||||
#include "services/cache/dns.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/module.h"
|
||||
@ -127,7 +128,7 @@ timeval_smaller(const struct timeval* x, const struct timeval* y)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Compare two response-ip client info entries for the purpose of mesh state
|
||||
* compare. It returns 0 if ci_a and ci_b are considered equal; otherwise
|
||||
* 1 or -1 (they mean 'ci_a is larger/smaller than ci_b', respectively, but
|
||||
@ -250,6 +251,7 @@ mesh_create(struct module_stack* stack, struct module_env* env)
|
||||
mesh->num_forever_states = 0;
|
||||
mesh->stats_jostled = 0;
|
||||
mesh->stats_dropped = 0;
|
||||
mesh->ans_expired = 0;
|
||||
mesh->max_reply_states = env->cfg->num_queries_per_thread;
|
||||
mesh->max_forever_states = (mesh->max_reply_states+1)/2;
|
||||
#ifndef S_SPLINT_S
|
||||
@ -345,6 +347,120 @@ int mesh_make_new_space(struct mesh_area* mesh, sldns_buffer* qbuf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_msg*
|
||||
mesh_serve_expired_lookup(struct module_qstate* qstate,
|
||||
struct query_info* lookup_qinfo)
|
||||
{
|
||||
hashvalue_type h;
|
||||
struct lruhash_entry* e;
|
||||
struct dns_msg* msg;
|
||||
struct reply_info* rep, *data;
|
||||
struct msgreply_entry* key;
|
||||
time_t timenow = *qstate->env->now;
|
||||
int must_validate = (!(qstate->query_flags&BIT_CD)
|
||||
|| qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate;
|
||||
/* Lookup cache */
|
||||
h = query_info_hash(lookup_qinfo, qstate->query_flags);
|
||||
e = slabhash_lookup(qstate->env->msg_cache, h, lookup_qinfo, 0);
|
||||
if(!e) return NULL;
|
||||
rep = (struct reply_info*)e->data;
|
||||
/* Check TTL */
|
||||
if(rep->ttl < timenow) {
|
||||
/* Check if we need to serve expired now */
|
||||
if(qstate->env->cfg->serve_expired) {
|
||||
if(qstate->env->cfg->serve_expired_ttl &&
|
||||
rep->serve_expired_ttl < timenow)
|
||||
goto bail_out;
|
||||
if(!rrset_array_lock(rep->ref, rep->rrset_count, 0))
|
||||
goto bail_out;
|
||||
} else {
|
||||
/* the rrsets may have been updated in the meantime.
|
||||
* we will refetch the message format from the
|
||||
* authoritative server
|
||||
*/
|
||||
goto bail_out;
|
||||
}
|
||||
} else {
|
||||
if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow))
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
/* Check CNAME chain (if any)
|
||||
* This is part of tomsg further down; no need to check now. */
|
||||
|
||||
/* Check security status of the cached answer.
|
||||
* tomsg further down has a subset of these checks, so we are leaving
|
||||
* these as is.
|
||||
* In case of bogus or revalidation we don't care to reply here. */
|
||||
if(must_validate && (rep->security == sec_status_bogus ||
|
||||
rep->security == sec_status_secure_sentinel_fail)) {
|
||||
verbose(VERB_ALGO, "Serve expired: bogus answer found in cache");
|
||||
goto bail_out_rrset;
|
||||
} else if(rep->security == sec_status_unchecked && must_validate) {
|
||||
verbose(VERB_ALGO, "Serve expired: unchecked entry needs "
|
||||
"validation");
|
||||
goto bail_out_rrset; /* need to validate cache entry first */
|
||||
} else if(rep->security == sec_status_secure &&
|
||||
!reply_all_rrsets_secure(rep) && must_validate) {
|
||||
verbose(VERB_ALGO, "Serve expired: secure entry"
|
||||
" changed status");
|
||||
goto bail_out_rrset; /* rrset changed, re-verify */
|
||||
}
|
||||
|
||||
key = (struct msgreply_entry*)e->key;
|
||||
data = (struct reply_info*)e->data;
|
||||
msg = tomsg(qstate->env, &key->key, data, qstate->region, timenow,
|
||||
qstate->env->cfg->serve_expired, qstate->env->scratch);
|
||||
rrset_array_unlock_touch(qstate->env->rrset_cache,
|
||||
qstate->region, rep->ref, rep->rrset_count);
|
||||
lock_rw_unlock(&e->lock);
|
||||
return msg;
|
||||
|
||||
bail_out_rrset:
|
||||
rrset_array_unlock_touch(qstate->env->rrset_cache,
|
||||
qstate->region, rep->ref, rep->rrset_count);
|
||||
bail_out:
|
||||
lock_rw_unlock(&e->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/** Init the serve expired data structure */
|
||||
static int
|
||||
mesh_serve_expired_init(struct mesh_state* mstate, int timeout)
|
||||
{
|
||||
struct timeval t;
|
||||
|
||||
/* Create serve_expired_data if not there yet */
|
||||
if(!mstate->s.serve_expired_data) {
|
||||
mstate->s.serve_expired_data = (struct serve_expired_data*)
|
||||
regional_alloc_zero(
|
||||
mstate->s.region, sizeof(struct serve_expired_data));
|
||||
if(!mstate->s.serve_expired_data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Don't overwrite the function if already set */
|
||||
mstate->s.serve_expired_data->get_cached_answer =
|
||||
mstate->s.serve_expired_data->get_cached_answer?
|
||||
mstate->s.serve_expired_data->get_cached_answer:
|
||||
mesh_serve_expired_lookup;
|
||||
|
||||
/* In case this timer already popped, start it again */
|
||||
if(!mstate->s.serve_expired_data->timer) {
|
||||
mstate->s.serve_expired_data->timer = comm_timer_create(
|
||||
mstate->s.env->worker_base, mesh_serve_expired_callback, mstate);
|
||||
if(!mstate->s.serve_expired_data->timer)
|
||||
return 0;
|
||||
#ifndef S_SPLINT_S
|
||||
t.tv_sec = timeout/1000;
|
||||
t.tv_usec = (timeout%1000)*1000;
|
||||
#endif
|
||||
comm_timer_set(mstate->s.serve_expired_data->timer, &t);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
struct respip_client_info* cinfo, uint16_t qflags,
|
||||
struct edns_data* edns, struct comm_reply* rep, uint16_t qid)
|
||||
@ -354,6 +470,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
int was_detached = 0;
|
||||
int was_noreply = 0;
|
||||
int added = 0;
|
||||
int timeout = mesh->env->cfg->serve_expired?
|
||||
mesh->env->cfg->serve_expired_client_timeout:0;
|
||||
struct sldns_buffer* r_buffer = rep->c->buffer;
|
||||
if(rep->c->tcp_req_info) {
|
||||
r_buffer = rep->c->tcp_req_info->spool_buffer;
|
||||
@ -366,7 +484,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
verbose(VERB_ALGO, "Too many queries. dropping "
|
||||
"incoming query.");
|
||||
comm_point_drop_reply(rep);
|
||||
mesh->stats_dropped ++;
|
||||
mesh->stats_dropped++;
|
||||
return;
|
||||
}
|
||||
/* for this new reply state, the reply address is free,
|
||||
@ -376,8 +494,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
if(mesh->num_reply_addrs > mesh->max_reply_states*16) {
|
||||
verbose(VERB_ALGO, "Too many requests queued. "
|
||||
"dropping incoming query.");
|
||||
mesh->stats_dropped++;
|
||||
comm_point_drop_reply(rep);
|
||||
mesh->stats_dropped++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -427,23 +545,16 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
mesh->num_detached_states++;
|
||||
added = 1;
|
||||
}
|
||||
if(!s->reply_list && !s->cb_list && s->super_set.count == 0)
|
||||
was_detached = 1;
|
||||
if(!s->reply_list && !s->cb_list)
|
||||
if(!s->reply_list && !s->cb_list) {
|
||||
was_noreply = 1;
|
||||
if(s->super_set.count == 0) {
|
||||
was_detached = 1;
|
||||
}
|
||||
}
|
||||
/* add reply to s */
|
||||
if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) {
|
||||
log_err("mesh_new_client: out of memory; SERVFAIL");
|
||||
servfail_mem:
|
||||
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s,
|
||||
NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
|
||||
edns->opt_list = NULL;
|
||||
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
|
||||
qinfo, qid, qflags, edns);
|
||||
comm_point_send_reply(rep);
|
||||
if(added)
|
||||
mesh_state_delete(&s->s);
|
||||
return;
|
||||
log_err("mesh_new_client: out of memory; SERVFAIL");
|
||||
goto servfail_mem;
|
||||
}
|
||||
if(rep->c->tcp_req_info) {
|
||||
if(!tcp_req_info_add_meshstate(rep->c->tcp_req_info, mesh, s)) {
|
||||
@ -451,6 +562,11 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
goto servfail_mem;
|
||||
}
|
||||
}
|
||||
/* add serve expired timer if required and not already there */
|
||||
if(timeout && !mesh_serve_expired_init(s, timeout)) {
|
||||
log_err("mesh_new_client: out of memory initializing serve expired");
|
||||
goto servfail_mem;
|
||||
}
|
||||
/* update statistics */
|
||||
if(was_detached) {
|
||||
log_assert(mesh->num_detached_states > 0);
|
||||
@ -475,6 +591,18 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
}
|
||||
if(added)
|
||||
mesh_run(mesh, s, module_event_new, NULL);
|
||||
return;
|
||||
|
||||
servfail_mem:
|
||||
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s,
|
||||
NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch))
|
||||
edns->opt_list = NULL;
|
||||
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
|
||||
qinfo, qid, qflags, edns);
|
||||
comm_point_send_reply(rep);
|
||||
if(added)
|
||||
mesh_state_delete(&s->s);
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
@ -484,6 +612,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
{
|
||||
struct mesh_state* s = NULL;
|
||||
int unique = unique_mesh_state(edns->opt_list, mesh->env);
|
||||
int timeout = mesh->env->cfg->serve_expired?
|
||||
mesh->env->cfg->serve_expired_client_timeout:0;
|
||||
int was_detached = 0;
|
||||
int was_noreply = 0;
|
||||
int added = 0;
|
||||
@ -522,15 +652,21 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
mesh->num_detached_states++;
|
||||
added = 1;
|
||||
}
|
||||
if(!s->reply_list && !s->cb_list && s->super_set.count == 0)
|
||||
was_detached = 1;
|
||||
if(!s->reply_list && !s->cb_list)
|
||||
if(!s->reply_list && !s->cb_list) {
|
||||
was_noreply = 1;
|
||||
if(s->super_set.count == 0) {
|
||||
was_detached = 1;
|
||||
}
|
||||
}
|
||||
/* add reply to s */
|
||||
if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags)) {
|
||||
if(added)
|
||||
mesh_state_delete(&s->s);
|
||||
return 0;
|
||||
if(added)
|
||||
mesh_state_delete(&s->s);
|
||||
return 0;
|
||||
}
|
||||
/* add serve expired timer if not already there */
|
||||
if(timeout && !mesh_serve_expired_init(s, timeout)) {
|
||||
return 0;
|
||||
}
|
||||
/* update statistics */
|
||||
if(was_detached) {
|
||||
@ -546,15 +682,6 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void mesh_schedule_prefetch(struct mesh_area* mesh,
|
||||
struct query_info* qinfo, uint16_t qflags, time_t leeway, int run);
|
||||
|
||||
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, time_t leeway)
|
||||
{
|
||||
mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1);
|
||||
}
|
||||
|
||||
/* Internal backend routine of mesh_new_prefetch(). It takes one additional
|
||||
* parameter, 'run', which controls whether to run the prefetch state
|
||||
* immediately. When this function is called internally 'run' could be
|
||||
@ -631,6 +758,12 @@ static void mesh_schedule_prefetch(struct mesh_area* mesh,
|
||||
mesh_run(mesh, s, module_event_new, NULL);
|
||||
}
|
||||
|
||||
void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, time_t leeway)
|
||||
{
|
||||
mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1);
|
||||
}
|
||||
|
||||
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
|
||||
struct comm_reply* reply, int what)
|
||||
{
|
||||
@ -703,6 +836,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
|
||||
mstate->s.env = env;
|
||||
mstate->s.mesh_info = mstate;
|
||||
mstate->s.prefetch_leeway = 0;
|
||||
mstate->s.serve_expired_data = NULL;
|
||||
mstate->s.no_cache_lookup = 0;
|
||||
mstate->s.no_cache_store = 0;
|
||||
mstate->s.need_refetch = 0;
|
||||
@ -742,6 +876,11 @@ mesh_state_cleanup(struct mesh_state* mstate)
|
||||
if(!mstate)
|
||||
return;
|
||||
mesh = mstate->s.env->mesh;
|
||||
/* Stop and delete the serve expired timer */
|
||||
if(mstate->s.serve_expired_data && mstate->s.serve_expired_data->timer) {
|
||||
comm_timer_delete(mstate->s.serve_expired_data->timer);
|
||||
mstate->s.serve_expired_data->timer = NULL;
|
||||
}
|
||||
/* drop unsent replies */
|
||||
if(!mstate->replies_sent) {
|
||||
struct mesh_reply* rep = mstate->reply_list;
|
||||
@ -752,6 +891,7 @@ mesh_state_cleanup(struct mesh_state* mstate)
|
||||
mstate->reply_list = NULL;
|
||||
for(; rep; rep=rep->next) {
|
||||
comm_point_drop_reply(&rep->query_reply);
|
||||
log_assert(mesh->num_reply_addrs > 0);
|
||||
mesh->num_reply_addrs--;
|
||||
}
|
||||
while((cb = mstate->cb_list)!=NULL) {
|
||||
@ -759,6 +899,7 @@ mesh_state_cleanup(struct mesh_state* mstate)
|
||||
fptr_ok(fptr_whitelist_mesh_cb(cb->cb));
|
||||
(*cb->cb)(cb->cb_arg, LDNS_RCODE_SERVFAIL, NULL,
|
||||
sec_status_unchecked, NULL, 0);
|
||||
log_assert(mesh->num_reply_addrs > 0);
|
||||
mesh->num_reply_addrs--;
|
||||
}
|
||||
}
|
||||
@ -826,7 +967,7 @@ find_in_subsub(struct mesh_state* m, struct mesh_state* tofind, size_t *c)
|
||||
}
|
||||
|
||||
/** find cycle for already looked up mesh_state */
|
||||
static int
|
||||
static int
|
||||
mesh_detect_cycle_found(struct module_qstate* qstate, struct mesh_state* dep_m)
|
||||
{
|
||||
struct mesh_state* cyc_m = qstate->mesh_info;
|
||||
@ -1038,6 +1179,7 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
}
|
||||
}
|
||||
free(reason);
|
||||
log_assert(m->s.env->mesh->num_reply_addrs > 0);
|
||||
m->s.env->mesh->num_reply_addrs--;
|
||||
}
|
||||
|
||||
@ -1139,6 +1281,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
comm_point_send_reply(&r->query_reply);
|
||||
}
|
||||
/* account */
|
||||
log_assert(m->s.env->mesh->num_reply_addrs > 0);
|
||||
m->s.env->mesh->num_reply_addrs--;
|
||||
end_time = *m->s.env->now_tv;
|
||||
timeval_subtract(&duration, &end_time, &r->start_time);
|
||||
@ -1170,14 +1313,23 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
struct mesh_cb* c;
|
||||
struct reply_info* rep = (mstate->s.return_msg?
|
||||
mstate->s.return_msg->rep:NULL);
|
||||
if((mstate->s.return_rcode == LDNS_RCODE_SERVFAIL ||
|
||||
(rep && FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_SERVFAIL))
|
||||
/* No need for the serve expired timer anymore; we are going to reply. */
|
||||
if(mstate->s.serve_expired_data) {
|
||||
comm_timer_delete(mstate->s.serve_expired_data->timer);
|
||||
mstate->s.serve_expired_data->timer = NULL;
|
||||
}
|
||||
if(mstate->s.return_rcode == LDNS_RCODE_SERVFAIL ||
|
||||
(rep && FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_SERVFAIL)) {
|
||||
/* we are SERVFAILing; check for expired asnwer here */
|
||||
mesh_serve_expired_callback(mstate);
|
||||
if((mstate->reply_list || mstate->cb_list)
|
||||
&& mstate->s.env->cfg->log_servfail
|
||||
&& !mstate->s.env->cfg->val_log_squelch) {
|
||||
char* err = errinf_to_str_servfail(&mstate->s);
|
||||
if(err)
|
||||
log_err("%s", err);
|
||||
free(err);
|
||||
char* err = errinf_to_str_servfail(&mstate->s);
|
||||
if(err)
|
||||
log_err("%s", err);
|
||||
free(err);
|
||||
}
|
||||
}
|
||||
for(r = mstate->reply_list; r; r = r->next) {
|
||||
/* if a response-ip address block has been stored the
|
||||
@ -1202,9 +1354,9 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
|
||||
/* if this query is determined to be dropped during the
|
||||
* mesh processing, this is the point to take that action. */
|
||||
if(mstate->s.is_drop)
|
||||
if(mstate->s.is_drop) {
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
else {
|
||||
} else {
|
||||
struct sldns_buffer* r_buffer = r->query_reply.c->buffer;
|
||||
if(r->query_reply.c->tcp_req_info) {
|
||||
r_buffer = r->query_reply.c->tcp_req_info->spool_buffer;
|
||||
@ -1226,6 +1378,7 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
* changed, eg. by adds from the callback routine */
|
||||
if(!mstate->reply_list && mstate->cb_list && !c->next) {
|
||||
/* was a reply state, not anymore */
|
||||
log_assert(mstate->s.env->mesh->num_reply_states > 0);
|
||||
mstate->s.env->mesh->num_reply_states--;
|
||||
}
|
||||
mstate->cb_list = c->next;
|
||||
@ -1591,6 +1744,7 @@ mesh_stats_clear(struct mesh_area* mesh)
|
||||
timehist_clear(mesh->histogram);
|
||||
mesh->ans_secure = 0;
|
||||
mesh->ans_bogus = 0;
|
||||
mesh->ans_expired = 0;
|
||||
memset(&mesh->ans_rcode[0], 0, sizeof(size_t)*UB_STATS_RCODE_NUM);
|
||||
memset(&mesh->rpz_action[0], 0, sizeof(size_t)*UB_STATS_RPZ_ACTION_NUM);
|
||||
mesh->ans_nodata = 0;
|
||||
@ -1658,6 +1812,7 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
if(prev) prev->next = n->next;
|
||||
else m->reply_list = n->next;
|
||||
/* delete it, but allocated in m region */
|
||||
log_assert(mesh->num_reply_addrs > 0);
|
||||
mesh->num_reply_addrs--;
|
||||
|
||||
/* prev = prev; */
|
||||
@ -1678,3 +1833,176 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
mesh->num_reply_states--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
apply_respip_action(struct module_qstate* qstate,
|
||||
const struct query_info* qinfo, struct respip_client_info* cinfo,
|
||||
struct respip_action_info* actinfo, struct reply_info* rep,
|
||||
struct ub_packed_rrset_key** alias_rrset,
|
||||
struct reply_info** encode_repp, struct auth_zones* az)
|
||||
{
|
||||
if(qinfo->qtype != LDNS_RR_TYPE_A &&
|
||||
qinfo->qtype != LDNS_RR_TYPE_AAAA &&
|
||||
qinfo->qtype != LDNS_RR_TYPE_ANY)
|
||||
return 1;
|
||||
|
||||
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, actinfo,
|
||||
alias_rrset, 0, qstate->region, az))
|
||||
return 0;
|
||||
|
||||
/* xxx_deny actions mean dropping the reply, unless the original reply
|
||||
* was redirected to response-ip data. */
|
||||
if((actinfo->action == respip_deny ||
|
||||
actinfo->action == respip_inform_deny) &&
|
||||
*encode_repp == rep)
|
||||
*encode_repp = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
mesh_serve_expired_callback(void* arg)
|
||||
{
|
||||
struct mesh_state* mstate = (struct mesh_state*) arg;
|
||||
struct module_qstate* qstate = &mstate->s;
|
||||
struct mesh_reply* r;
|
||||
struct mesh_area* mesh = qstate->env->mesh;
|
||||
struct dns_msg* msg;
|
||||
struct mesh_cb* c;
|
||||
struct mesh_reply* prev = NULL;
|
||||
struct sldns_buffer* prev_buffer = NULL;
|
||||
struct sldns_buffer* r_buffer = NULL;
|
||||
struct reply_info* partial_rep = NULL;
|
||||
struct ub_packed_rrset_key* alias_rrset = NULL;
|
||||
struct reply_info* encode_rep = NULL;
|
||||
struct respip_action_info actinfo;
|
||||
struct query_info* lookup_qinfo = &qstate->qinfo;
|
||||
struct query_info qinfo_tmp;
|
||||
int must_validate = (!(qstate->query_flags&BIT_CD)
|
||||
|| qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate;
|
||||
if(!qstate->serve_expired_data) return;
|
||||
verbose(VERB_ALGO, "Serve expired: Trying to reply with expired data");
|
||||
comm_timer_delete(qstate->serve_expired_data->timer);
|
||||
qstate->serve_expired_data->timer = NULL;
|
||||
if(qstate->blacklist || qstate->no_cache_lookup || qstate->is_drop) {
|
||||
verbose(VERB_ALGO,
|
||||
"Serve expired: Not allowed to look into cache for stale");
|
||||
return;
|
||||
}
|
||||
/* The following while is used instead of the `goto lookup_cache`
|
||||
* like in the worker. */
|
||||
while(1) {
|
||||
fptr_ok(fptr_whitelist_serve_expired_lookup(
|
||||
qstate->serve_expired_data->get_cached_answer));
|
||||
msg = qstate->serve_expired_data->get_cached_answer(qstate,
|
||||
lookup_qinfo);
|
||||
if(!msg)
|
||||
return;
|
||||
/* Reset these in case we pass a second time from here. */
|
||||
encode_rep = msg->rep;
|
||||
memset(&actinfo, 0, sizeof(actinfo));
|
||||
actinfo.action = respip_none;
|
||||
alias_rrset = NULL;
|
||||
if((mesh->use_response_ip || mesh->use_rpz) &&
|
||||
!partial_rep && !apply_respip_action(qstate, &qstate->qinfo,
|
||||
qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep,
|
||||
qstate->env->auth_zones)) {
|
||||
return;
|
||||
} else if(partial_rep &&
|
||||
!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
|
||||
qstate->client_info, must_validate, &encode_rep, qstate->region,
|
||||
qstate->env->auth_zones)) {
|
||||
return;
|
||||
}
|
||||
if(!encode_rep || alias_rrset) {
|
||||
if(!encode_rep) {
|
||||
/* Needs drop */
|
||||
return;
|
||||
} else {
|
||||
/* A partial CNAME chain is found. */
|
||||
partial_rep = encode_rep;
|
||||
}
|
||||
}
|
||||
/* We've found a partial reply ending with an
|
||||
* alias. Replace the lookup qinfo for the
|
||||
* alias target and lookup the cache again to
|
||||
* (possibly) complete the reply. As we're
|
||||
* passing the "base" reply, there will be no
|
||||
* more alias chasing. */
|
||||
if(partial_rep) {
|
||||
memset(&qinfo_tmp, 0, sizeof(qinfo_tmp));
|
||||
get_cname_target(alias_rrset, &qinfo_tmp.qname,
|
||||
&qinfo_tmp.qname_len);
|
||||
if(!qinfo_tmp.qname) {
|
||||
log_err("Serve expired: unexpected: invalid answer alias");
|
||||
return;
|
||||
}
|
||||
qinfo_tmp.qtype = qstate->qinfo.qtype;
|
||||
qinfo_tmp.qclass = qstate->qinfo.qclass;
|
||||
lookup_qinfo = &qinfo_tmp;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(verbosity >= VERB_ALGO)
|
||||
log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep);
|
||||
|
||||
r = mstate->reply_list;
|
||||
mstate->reply_list = NULL;
|
||||
for(; r; r = r->next) {
|
||||
/* If address info is returned, it means the action should be an
|
||||
* 'inform' variant and the information should be logged. */
|
||||
if(actinfo.addrinfo) {
|
||||
respip_inform_print(&actinfo, r->qname,
|
||||
qstate->qinfo.qtype, qstate->qinfo.qclass,
|
||||
r->local_alias, &r->query_reply);
|
||||
|
||||
if(qstate->env->cfg->stat_extended && actinfo.rpz_used) {
|
||||
if(actinfo.rpz_disabled)
|
||||
qstate->env->mesh->rpz_action[RPZ_DISABLED_ACTION]++;
|
||||
if(actinfo.rpz_cname_override)
|
||||
qstate->env->mesh->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
|
||||
else
|
||||
qstate->env->mesh->rpz_action[
|
||||
respip_action_to_rpz_action(actinfo.action)]++;
|
||||
}
|
||||
}
|
||||
|
||||
r_buffer = r->query_reply.c->buffer;
|
||||
if(r->query_reply.c->tcp_req_info)
|
||||
r_buffer = r->query_reply.c->tcp_req_info->spool_buffer;
|
||||
mesh_send_reply(mstate, LDNS_RCODE_NOERROR, msg->rep,
|
||||
r, r_buffer, prev, prev_buffer);
|
||||
if(r->query_reply.c->tcp_req_info)
|
||||
tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate);
|
||||
prev = r;
|
||||
prev_buffer = r_buffer;
|
||||
|
||||
/* Account for each reply sent. */
|
||||
mesh->ans_expired++;
|
||||
|
||||
}
|
||||
while((c = mstate->cb_list) != NULL) {
|
||||
/* take this cb off the list; so that the list can be
|
||||
* changed, eg. by adds from the callback routine */
|
||||
if(!mstate->reply_list && mstate->cb_list && !c->next) {
|
||||
/* was a reply state, not anymore */
|
||||
log_assert(qstate->env->mesh->num_reply_states > 0);
|
||||
qstate->env->mesh->num_reply_states--;
|
||||
}
|
||||
mstate->cb_list = c->next;
|
||||
if(!mstate->reply_list && !mstate->cb_list &&
|
||||
mstate->super_set.count == 0)
|
||||
qstate->env->mesh->num_detached_states++;
|
||||
mesh_do_callback(mstate, LDNS_RCODE_NOERROR, msg->rep, c);
|
||||
}
|
||||
if(!mstate->reply_list && !mstate->cb_list) {
|
||||
log_assert(mesh->num_reply_states > 0);
|
||||
mesh->num_reply_states--;
|
||||
if(mstate->super_set.count == 0) {
|
||||
mesh->num_detached_states++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +112,8 @@ struct mesh_area {
|
||||
size_t stats_jostled;
|
||||
/** stats, cumulative number of incoming client msgs dropped */
|
||||
size_t stats_dropped;
|
||||
/** stats, number of expired replies sent */
|
||||
size_t ans_expired;
|
||||
/** number of replies sent */
|
||||
size_t replies_sent;
|
||||
/** sum of waiting times for the replies */
|
||||
@ -146,6 +148,11 @@ struct mesh_area {
|
||||
struct mesh_state* jostle_last;
|
||||
/** timeout for jostling. if age is lower, it does not get jostled. */
|
||||
struct timeval jostle_max;
|
||||
|
||||
/** If we need to use response ip (value passed from daemon)*/
|
||||
int use_response_ip;
|
||||
/** If we need to use RPZ (value passed from daemon) */
|
||||
int use_rpz;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -647,4 +654,22 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp,
|
||||
void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
struct comm_point* cp);
|
||||
|
||||
/** Callback for when the serve expired client timer has run out. Tries to
|
||||
* find an expired answer in the cache and reply that to the client.
|
||||
* @param arg: the argument passed to the callback.
|
||||
*/
|
||||
void mesh_serve_expired_callback(void* arg);
|
||||
|
||||
/**
|
||||
* Try to get a (expired) cached answer.
|
||||
* This needs to behave like the worker's answer_from_cache() in order to have
|
||||
* the same behavior as when replying from cache.
|
||||
* @param qstate: the module qstate.
|
||||
* @param lookup_qinfo: the query info to look for in the cache.
|
||||
* @return dns_msg if a cached answer was found, otherwise NULL.
|
||||
*/
|
||||
struct dns_msg*
|
||||
mesh_serve_expired_lookup(struct module_qstate* qstate,
|
||||
struct query_info* lookup_qinfo);
|
||||
|
||||
#endif /* SERVICES_MESH_H */
|
||||
|
@ -211,7 +211,7 @@ static void pr_stats(const char* nm, struct ub_stats_info* s)
|
||||
s->svr.num_queries - s->svr.num_queries_missed_cache);
|
||||
PR_UL_NM("num.cachemiss", s->svr.num_queries_missed_cache);
|
||||
PR_UL_NM("num.prefetch", s->svr.num_queries_prefetch);
|
||||
PR_UL_NM("num.zero_ttl", s->svr.zero_ttl_responses);
|
||||
PR_UL_NM("num.expired", s->svr.ans_expired);
|
||||
PR_UL_NM("num.recursivereplies", s->mesh_replies_sent);
|
||||
#ifdef USE_DNSCRYPT
|
||||
PR_UL_NM("num.dnscrypt.crypted", s->svr.num_query_dnscrypt_crypted);
|
||||
|
@ -74,18 +74,18 @@
|
||||
* o CHECK_ANSWER - followed by entry
|
||||
* o CHECK_OUT_QUERY - followed by entry (if copy-id it is also reply).
|
||||
* o REPLY - followed by entry
|
||||
* o TIMEOUT
|
||||
* o TIME_PASSES ELAPSE [seconds] - increase 'now' time counter, can be
|
||||
* a floating point number.
|
||||
* TIME_PASSES EVAL [macro] - expanded for seconds to move time.
|
||||
* o TRAFFIC - like CHECK_ANSWER, causes traffic to flow.
|
||||
* o TIMEOUT
|
||||
* o TIME_PASSES ELAPSE [seconds] - increase 'now' time counter, can be
|
||||
* a floating point number.
|
||||
* TIME_PASSES EVAL [macro] - expanded for seconds to move time.
|
||||
* o TRAFFIC - like CHECK_ANSWER, causes traffic to flow.
|
||||
* actually the traffic flows before this step is taken.
|
||||
* the step waits for traffic to stop.
|
||||
* o CHECK_AUTOTRUST [id] - followed by FILE_BEGIN [to match] FILE_END.
|
||||
* The file contents is macro expanded before match.
|
||||
* o CHECK_TEMPFILE [fname] - followed by FILE_BEGIN [to match] FILE_END
|
||||
* o INFRA_RTT [ip] [dp] [rtt] - update infra cache entry with rtt.
|
||||
* o ERROR
|
||||
* o CHECK_AUTOTRUST [id] - followed by FILE_BEGIN [to match] FILE_END.
|
||||
* The file contents is macro expanded before match.
|
||||
* o CHECK_TEMPFILE [fname] - followed by FILE_BEGIN [to match] FILE_END
|
||||
* o INFRA_RTT [ip] [dp] [rtt] - update infra cache entry with rtt.
|
||||
* o ERROR
|
||||
* ; following entry starts on the next line, ENTRY_BEGIN.
|
||||
* ; more STEP items
|
||||
* SCENARIO_END
|
||||
|
122
testdata/serve_expired.rpl
vendored
Normal file
122
testdata/serve_expired.rpl
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
; config options
|
||||
server:
|
||||
module-config: "validator iterator"
|
||||
qname-minimisation: "no"
|
||||
minimal-responses: no
|
||||
serve-expired: yes
|
||||
access-control: 127.0.0.1/32 allow_snoop
|
||||
|
||||
stub-zone:
|
||||
name: "example.com"
|
||||
stub-addr: 1.2.3.4
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test serve-expired
|
||||
; Scenario overview:
|
||||
; - query for example.com. IN A
|
||||
; - check that we get an answer for example.com. IN A with the correct TTL
|
||||
; - query again (without the RD bit) right after the TTL expired
|
||||
; - check that we get the expired cached answer (this should trigger prefetching)
|
||||
; - query with RD bit and check that the cached record was updated
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN NS
|
||||
SECTION ANSWER
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 10 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; Query with RD flag
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got the correct answer (should be cached)
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 10 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Wait for the TTL to expire
|
||||
STEP 11 TIME_PASSES ELAPSE 3601
|
||||
|
||||
; Query again without RD bit
|
||||
STEP 30 QUERY
|
||||
ENTRY_BEGIN
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got a stale answer
|
||||
STEP 40 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 30 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. 30 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 30 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Query with RD bit (the record should have been prefetched)
|
||||
STEP 50 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
STEP 60 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 10 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
127
testdata/serve_expired_client_timeout.rpl
vendored
Normal file
127
testdata/serve_expired_client_timeout.rpl
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
; config options
|
||||
server:
|
||||
module-config: "validator iterator"
|
||||
qname-minimisation: "no"
|
||||
minimal-responses: no
|
||||
serve-expired: yes
|
||||
serve-expired-client-timeout: 1
|
||||
serve-expired-reply-ttl: 123
|
||||
|
||||
stub-zone:
|
||||
name: "example.com"
|
||||
stub-addr: 1.2.3.4
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test serve-expired with client-timeout and reply-ttl
|
||||
; Scenario overview:
|
||||
; - query for example.com. IN A
|
||||
; - check that we get an answer for example.com. IN A with the correct TTL
|
||||
; - query again right after the TTL expired
|
||||
; - check that we get the expired cached answer with the configured reply ttl
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN NS
|
||||
SECTION ANSWER
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 20
|
||||
ADDRESS 1.2.3.4
|
||||
; response to A query
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 10 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; Query with RD flag
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got the correct answer (should be cached)
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 10 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Wait for the TTL to expire
|
||||
STEP 11 TIME_PASSES ELAPSE 3600
|
||||
|
||||
; Query again
|
||||
STEP 30 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Allow the client timer to expire
|
||||
STEP 31 TIME_PASSES ELAPSE 1
|
||||
|
||||
; Check that we got a stale answer
|
||||
STEP 40 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 123 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. 123 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 123 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Reply to the outstanding query so that the test doesn't fail with
|
||||
; pending messages.
|
||||
STEP 41 REPLY
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
; authoritative answer
|
||||
REPLY QR AA RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 3600 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. 3600 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 3600 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
103
testdata/serve_expired_reply_ttl.rpl
vendored
Normal file
103
testdata/serve_expired_reply_ttl.rpl
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
; config options
|
||||
server:
|
||||
module-config: "validator iterator"
|
||||
qname-minimisation: "no"
|
||||
minimal-responses: no
|
||||
serve-expired: yes
|
||||
serve-expired-reply-ttl: 123
|
||||
|
||||
stub-zone:
|
||||
name: "example.com"
|
||||
stub-addr: 1.2.3.4
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test serve-expired with reply-ttl
|
||||
; Scenario overview:
|
||||
; - query for example.com. IN A
|
||||
; - check that we get an answer for example.com. IN A with the correct TTL
|
||||
; - query again right after the TTL expired
|
||||
; - check that we get the expired cached answer with the configured TTL
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN NS
|
||||
SECTION ANSWER
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 10 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; Query with RD flag
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got the correct answer (should be cached)
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 10 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Wait for the TTL to expire
|
||||
STEP 11 TIME_PASSES ELAPSE 3601
|
||||
|
||||
; Query again
|
||||
STEP 30 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got a stale answer
|
||||
STEP 40 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 123 A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. 123 NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 123 A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Give time for the pending query to get answered
|
||||
STEP 41 TRAFFIC
|
||||
|
||||
SCENARIO_END
|
117
testdata/serve_expired_servfail.rpl
vendored
Normal file
117
testdata/serve_expired_servfail.rpl
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
; config options
|
||||
server:
|
||||
module-config: "validator iterator"
|
||||
qname-minimisation: "no"
|
||||
minimal-responses: no
|
||||
serve-expired: yes
|
||||
serve-expired-client-timeout: 1800
|
||||
serve-expired-reply-ttl: 123
|
||||
log-servfail: yes
|
||||
|
||||
|
||||
stub-zone:
|
||||
name: "example.com"
|
||||
stub-addr: 1.2.3.4
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test serve-expired with client-timeout and a SERVFAIL upstream reply
|
||||
; Scenario overview:
|
||||
; - query for example.com. IN A
|
||||
; - check that we get an answer for example.com. IN A with the correct TTL
|
||||
; - query again right after the TTL expired
|
||||
; - answer from upstream is servfail
|
||||
; - check that we get the expired cached answer instead
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 20
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN NS
|
||||
SECTION ANSWER
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 10 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 30 100
|
||||
ADDRESS 1.2.3.4
|
||||
; response to A query
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR AA SERVFAIL
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; Query with RD flag
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got the correct answer (should be cached)
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 10 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Wait for the TTL to expire
|
||||
STEP 11 TIME_PASSES ELAPSE 3601
|
||||
|
||||
; Query again
|
||||
STEP 30 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got a stale answer
|
||||
STEP 40 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 123 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. 123 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 123 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
100
testdata/serve_expired_ttl.rpl
vendored
Normal file
100
testdata/serve_expired_ttl.rpl
vendored
Normal file
@ -0,0 +1,100 @@
|
||||
; config options
|
||||
server:
|
||||
module-config: "validator iterator"
|
||||
qname-minimisation: "no"
|
||||
minimal-responses: no
|
||||
serve-expired: yes
|
||||
serve-expired-ttl: 10
|
||||
|
||||
stub-zone:
|
||||
name: "example.com"
|
||||
stub-addr: 1.2.3.4
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test serve-expired
|
||||
; Scenario overview:
|
||||
; - query for example.com. IN A
|
||||
; - check that we get an answer for example.com. IN A with the correct TTL
|
||||
; - query again right after the TTL expired + serve-expired-ttl
|
||||
; - check that we get an updated answer and not the cached one
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN NS
|
||||
SECTION ANSWER
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; Query with RD flag
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got the correct answer (should be cached)
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Wait for the TTL to expire + serve-expired-ttl
|
||||
STEP 11 TIME_PASSES ELAPSE 3611
|
||||
|
||||
; Query again
|
||||
STEP 30 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got an updated answer
|
||||
STEP 40 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
128
testdata/serve_expired_ttl_client_timeout.rpl
vendored
Normal file
128
testdata/serve_expired_ttl_client_timeout.rpl
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
; config options
|
||||
server:
|
||||
module-config: "validator iterator"
|
||||
qname-minimisation: "no"
|
||||
minimal-responses: no
|
||||
serve-expired: yes
|
||||
serve-expired-ttl: 10
|
||||
serve-expired-client-timeout: 1
|
||||
|
||||
stub-zone:
|
||||
name: "example.com"
|
||||
stub-addr: 1.2.3.4
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test serve-expired
|
||||
; Scenario overview:
|
||||
; - query for example.com. IN A
|
||||
; - check that we get an answer for example.com. IN A with the correct TTL
|
||||
; - query again right after the TTL expired + serve-expired-ttl
|
||||
; - check that we get an updated answer and not the cached one
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN NS
|
||||
SECTION ANSWER
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 20
|
||||
ADDRESS 1.2.3.4
|
||||
; response to A query
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; Query with RD flag
|
||||
STEP 1 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got the correct answer (should be cached)
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Wait for the TTL to expire + serve-expired-ttl
|
||||
STEP 11 TIME_PASSES ELAPSE 3611
|
||||
|
||||
; Query again
|
||||
STEP 30 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Allow the client timer to expire
|
||||
STEP 31 TIME_PASSES ELAPSE 1
|
||||
|
||||
; We shouldn't get a reply here.
|
||||
; There is cached data but serve-expired-ttl has passed.
|
||||
|
||||
STEP 40 REPLY
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
; authoritative answer
|
||||
REPLY QR AA RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 3600 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. 3600 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 3600 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got the updated answer
|
||||
STEP 41 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
SCENARIO_END
|
154
testdata/serve_expired_zerottl.rpl
vendored
Normal file
154
testdata/serve_expired_zerottl.rpl
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
; config options
|
||||
server:
|
||||
module-config: "validator iterator"
|
||||
qname-minimisation: "no"
|
||||
minimal-responses: no
|
||||
serve-expired: yes
|
||||
serve-expired-reply-ttl: 123
|
||||
|
||||
stub-zone:
|
||||
name: "example.com"
|
||||
stub-addr: 1.2.3.4
|
||||
CONFIG_END
|
||||
|
||||
SCENARIO_BEGIN Test 0 TLL with serve-expired
|
||||
; Scenario overview:
|
||||
; - query for example.com. IN A
|
||||
; - check that we get an answer for example.com. IN A with the correct 0 TTL
|
||||
; - query again; this time the answer has >0 TTL
|
||||
; - check the answer
|
||||
; - query one last time after expiration
|
||||
; - check that the configured reply ttl is used
|
||||
|
||||
; ns.example.com.
|
||||
RANGE_BEGIN 0 100
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN NS
|
||||
SECTION ANSWER
|
||||
example.com. IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
RANGE_BEGIN 0 10
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 0 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. 0 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 0 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
RANGE_BEGIN 11 100
|
||||
ADDRESS 1.2.3.4
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 10 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. 10 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 10 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
RANGE_END
|
||||
|
||||
; Let some time to pass so that timenow > 0
|
||||
STEP 1 TIME_PASSES ELAPSE 3600
|
||||
|
||||
; Query with RD flag
|
||||
STEP 2 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got the correct answer with 0 TTL
|
||||
STEP 10 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 0 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. 0 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 0 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Let some time to pass
|
||||
STEP 11 TIME_PASSES ELAPSE 1
|
||||
|
||||
; Query with RD flag
|
||||
STEP 20 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got the correct answer
|
||||
STEP 29 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 10 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. 10 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 10 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Wait for the TTL to expire
|
||||
STEP 30 TIME_PASSES ELAPSE 11
|
||||
|
||||
; Query with RD flag
|
||||
STEP 40 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
ENTRY_END
|
||||
|
||||
; Check that we got the correct answer
|
||||
STEP 49 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all ttl
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
example.com. IN A
|
||||
SECTION ANSWER
|
||||
example.com. 123 IN A 5.6.7.8
|
||||
SECTION AUTHORITY
|
||||
example.com. 123 IN NS ns.example.com.
|
||||
SECTION ADDITIONAL
|
||||
ns.example.com. 123 IN A 1.2.3.4
|
||||
ENTRY_END
|
||||
|
||||
; Give time for the pending query to get answered
|
||||
STEP 50 TRAFFIC
|
||||
|
||||
SCENARIO_END
|
@ -246,6 +246,8 @@ config_create(void)
|
||||
cfg->serve_expired = 0;
|
||||
cfg->serve_expired_ttl = 0;
|
||||
cfg->serve_expired_ttl_reset = 0;
|
||||
cfg->serve_expired_reply_ttl = 30;
|
||||
cfg->serve_expired_client_timeout = 0;
|
||||
cfg->add_holddown = 30*24*3600;
|
||||
cfg->del_holddown = 30*24*3600;
|
||||
cfg->keep_missing = 366*24*3600; /* one year plus a little leeway */
|
||||
@ -327,9 +329,14 @@ config_create(void)
|
||||
cfg->ipsecmod_strict = 0;
|
||||
#endif
|
||||
#ifdef USE_CACHEDB
|
||||
cfg->cachedb_backend = NULL;
|
||||
cfg->cachedb_secret = NULL;
|
||||
#endif
|
||||
if(!(cfg->cachedb_backend = strdup("testframe"))) goto error_exit;
|
||||
if(!(cfg->cachedb_secret = strdup("default"))) goto error_exit;
|
||||
#ifdef USE_REDIS
|
||||
if(!(cfg->redis_server_host = strdup("127.0.0.1"))) goto error_exit;
|
||||
cfg->redis_timeout = 100;
|
||||
cfg->redis_server_port = 6379;
|
||||
#endif /* USE_REDIS */
|
||||
#endif /* USE_CACHEDB */
|
||||
#ifdef USE_IPSET
|
||||
cfg->ipset_name_v4 = NULL;
|
||||
cfg->ipset_name_v6 = NULL;
|
||||
@ -581,10 +588,15 @@ int config_set_option(struct config_file* cfg, const char* opt,
|
||||
else S_YNO("val-permissive-mode:", val_permissive_mode)
|
||||
else S_YNO("aggressive-nsec:", aggressive_nsec)
|
||||
else S_YNO("ignore-cd-flag:", ignore_cd)
|
||||
else S_YNO("serve-expired:", serve_expired)
|
||||
else if(strcmp(opt, "serve-expired:") == 0)
|
||||
{ IS_YES_OR_NO; cfg->serve_expired = (strcmp(val, "yes") == 0);
|
||||
SERVE_EXPIRED = cfg->serve_expired; }
|
||||
else if(strcmp(opt, "serve-expired-ttl:") == 0)
|
||||
{ IS_NUMBER_OR_ZERO; cfg->serve_expired_ttl = atoi(val); SERVE_EXPIRED_TTL=(time_t)cfg->serve_expired_ttl;}
|
||||
else S_YNO("serve-expired-ttl-reset:", serve_expired_ttl_reset)
|
||||
else if(strcmp(opt, "serve-expired-reply-ttl:") == 0)
|
||||
{ IS_NUMBER_OR_ZERO; cfg->serve_expired_reply_ttl = atoi(val); SERVE_EXPIRED_REPLY_TTL=(time_t)cfg->serve_expired_reply_ttl;}
|
||||
else S_NUMBER_OR_ZERO("serve-expired-client-timeout:", serve_expired_client_timeout)
|
||||
else S_STR("val-nsec3-keysize-iterations:", val_nsec3_key_iterations)
|
||||
else S_UNSIGNED_OR_ZERO("add-holddown:", add_holddown)
|
||||
else S_UNSIGNED_OR_ZERO("del-holddown:", del_holddown)
|
||||
@ -977,6 +989,8 @@ config_get_option(struct config_file* cfg, const char* opt,
|
||||
else O_YNO(opt, "serve-expired", serve_expired)
|
||||
else O_DEC(opt, "serve-expired-ttl", serve_expired_ttl)
|
||||
else O_YNO(opt, "serve-expired-ttl-reset", serve_expired_ttl_reset)
|
||||
else O_DEC(opt, "serve-expired-reply-ttl", serve_expired_reply_ttl)
|
||||
else O_DEC(opt, "serve-expired-client-timeout", serve_expired_client_timeout)
|
||||
else O_STR(opt, "val-nsec3-keysize-iterations",val_nsec3_key_iterations)
|
||||
else O_UNS(opt, "add-holddown", add_holddown)
|
||||
else O_UNS(opt, "del-holddown", del_holddown)
|
||||
@ -1098,7 +1112,12 @@ config_get_option(struct config_file* cfg, const char* opt,
|
||||
#ifdef USE_CACHEDB
|
||||
else O_STR(opt, "backend", cachedb_backend)
|
||||
else O_STR(opt, "secret-seed", cachedb_secret)
|
||||
#endif
|
||||
#ifdef USE_REDIS
|
||||
else O_STR(opt, "redis-server-host", redis_server_host)
|
||||
else O_DEC(opt, "redis-server-port", redis_server_port)
|
||||
else O_DEC(opt, "redis-timeout", redis_timeout)
|
||||
#endif /* USE_REDIS */
|
||||
#endif /* USE_CACHEDB */
|
||||
#ifdef USE_IPSET
|
||||
else O_STR(opt, "name-v4", ipset_name_v4)
|
||||
else O_STR(opt, "name-v6", ipset_name_v6)
|
||||
@ -1448,7 +1467,10 @@ config_delete(struct config_file* cfg)
|
||||
#ifdef USE_CACHEDB
|
||||
free(cfg->cachedb_backend);
|
||||
free(cfg->cachedb_secret);
|
||||
#endif
|
||||
#ifdef USE_REDIS
|
||||
free(cfg->redis_server_host);
|
||||
#endif /* USE_REDIS */
|
||||
#endif /* USE_CACHEDB */
|
||||
#ifdef USE_IPSET
|
||||
free(cfg->ipset_name_v4);
|
||||
free(cfg->ipset_name_v6);
|
||||
@ -1964,7 +1986,9 @@ config_apply(struct config_file* config)
|
||||
{
|
||||
MAX_TTL = (time_t)config->max_ttl;
|
||||
MIN_TTL = (time_t)config->min_ttl;
|
||||
SERVE_EXPIRED = config->serve_expired;
|
||||
SERVE_EXPIRED_TTL = (time_t)config->serve_expired_ttl;
|
||||
SERVE_EXPIRED_REPLY_TTL = (time_t)config->serve_expired_reply_ttl;
|
||||
MAX_NEG_TTL = (time_t)config->max_negative_ttl;
|
||||
RTT_MIN_TIMEOUT = config->infra_cache_min_rtt;
|
||||
EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size;
|
||||
|
@ -362,6 +362,11 @@ struct config_file {
|
||||
int serve_expired_ttl;
|
||||
/** reset serve expired TTL after failed update attempt */
|
||||
int serve_expired_ttl_reset;
|
||||
/** TTL for the serve expired replies */
|
||||
int serve_expired_reply_ttl;
|
||||
/** serve expired entries only after trying to update the entries and this
|
||||
* timeout (in milliseconds) is reached */
|
||||
int serve_expired_client_timeout;
|
||||
/** nsec3 maximum iterations per key size, string */
|
||||
char* val_nsec3_key_iterations;
|
||||
/** autotrust add holddown time, in seconds */
|
||||
|
2673
util/configlexer.c
2673
util/configlexer.c
File diff suppressed because it is too large
Load Diff
@ -369,6 +369,8 @@ ignore-cd-flag{COLON} { YDVAR(1, VAR_IGNORE_CD_FLAG) }
|
||||
serve-expired{COLON} { YDVAR(1, VAR_SERVE_EXPIRED) }
|
||||
serve-expired-ttl{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_TTL) }
|
||||
serve-expired-ttl-reset{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_TTL_RESET) }
|
||||
serve-expired-reply-ttl{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_REPLY_TTL) }
|
||||
serve-expired-client-timeout{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_CLIENT_TIMEOUT) }
|
||||
fake-dsa{COLON} { YDVAR(1, VAR_FAKE_DSA) }
|
||||
fake-sha1{COLON} { YDVAR(1, VAR_FAKE_SHA1) }
|
||||
val-log-level{COLON} { YDVAR(1, VAR_VAL_LOG_LEVEL) }
|
||||
|
3142
util/configparser.c
3142
util/configparser.c
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,9 @@
|
||||
/* A Bison parser, made by GNU Bison 3.0.4. */
|
||||
/* A Bison parser, made by GNU Bison 3.4.1. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -30,6 +31,9 @@
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
/* Undocumented macros, especially those whose name start with YY_,
|
||||
are private implementation details. Do not rely on them. */
|
||||
|
||||
#ifndef YY_YY_UTIL_CONFIGPARSER_H_INCLUDED
|
||||
# define YY_YY_UTIL_CONFIGPARSER_H_INCLUDED
|
||||
/* Debug traces. */
|
||||
@ -250,74 +254,76 @@ extern int yydebug;
|
||||
VAR_SERVE_EXPIRED = 460,
|
||||
VAR_SERVE_EXPIRED_TTL = 461,
|
||||
VAR_SERVE_EXPIRED_TTL_RESET = 462,
|
||||
VAR_FAKE_DSA = 463,
|
||||
VAR_FAKE_SHA1 = 464,
|
||||
VAR_LOG_IDENTITY = 465,
|
||||
VAR_HIDE_TRUSTANCHOR = 466,
|
||||
VAR_TRUST_ANCHOR_SIGNALING = 467,
|
||||
VAR_AGGRESSIVE_NSEC = 468,
|
||||
VAR_USE_SYSTEMD = 469,
|
||||
VAR_SHM_ENABLE = 470,
|
||||
VAR_SHM_KEY = 471,
|
||||
VAR_ROOT_KEY_SENTINEL = 472,
|
||||
VAR_DNSCRYPT = 473,
|
||||
VAR_DNSCRYPT_ENABLE = 474,
|
||||
VAR_DNSCRYPT_PORT = 475,
|
||||
VAR_DNSCRYPT_PROVIDER = 476,
|
||||
VAR_DNSCRYPT_SECRET_KEY = 477,
|
||||
VAR_DNSCRYPT_PROVIDER_CERT = 478,
|
||||
VAR_DNSCRYPT_PROVIDER_CERT_ROTATED = 479,
|
||||
VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE = 480,
|
||||
VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS = 481,
|
||||
VAR_DNSCRYPT_NONCE_CACHE_SIZE = 482,
|
||||
VAR_DNSCRYPT_NONCE_CACHE_SLABS = 483,
|
||||
VAR_IPSECMOD_ENABLED = 484,
|
||||
VAR_IPSECMOD_HOOK = 485,
|
||||
VAR_IPSECMOD_IGNORE_BOGUS = 486,
|
||||
VAR_IPSECMOD_MAX_TTL = 487,
|
||||
VAR_IPSECMOD_WHITELIST = 488,
|
||||
VAR_IPSECMOD_STRICT = 489,
|
||||
VAR_CACHEDB = 490,
|
||||
VAR_CACHEDB_BACKEND = 491,
|
||||
VAR_CACHEDB_SECRETSEED = 492,
|
||||
VAR_CACHEDB_REDISHOST = 493,
|
||||
VAR_CACHEDB_REDISPORT = 494,
|
||||
VAR_CACHEDB_REDISTIMEOUT = 495,
|
||||
VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM = 496,
|
||||
VAR_FOR_UPSTREAM = 497,
|
||||
VAR_AUTH_ZONE = 498,
|
||||
VAR_ZONEFILE = 499,
|
||||
VAR_MASTER = 500,
|
||||
VAR_URL = 501,
|
||||
VAR_FOR_DOWNSTREAM = 502,
|
||||
VAR_FALLBACK_ENABLED = 503,
|
||||
VAR_TLS_ADDITIONAL_PORT = 504,
|
||||
VAR_LOW_RTT = 505,
|
||||
VAR_LOW_RTT_PERMIL = 506,
|
||||
VAR_FAST_SERVER_PERMIL = 507,
|
||||
VAR_FAST_SERVER_NUM = 508,
|
||||
VAR_ALLOW_NOTIFY = 509,
|
||||
VAR_TLS_WIN_CERT = 510,
|
||||
VAR_TCP_CONNECTION_LIMIT = 511,
|
||||
VAR_FORWARD_NO_CACHE = 512,
|
||||
VAR_STUB_NO_CACHE = 513,
|
||||
VAR_LOG_SERVFAIL = 514,
|
||||
VAR_DENY_ANY = 515,
|
||||
VAR_UNKNOWN_SERVER_TIME_LIMIT = 516,
|
||||
VAR_LOG_TAG_QUERYREPLY = 517,
|
||||
VAR_STREAM_WAIT_SIZE = 518,
|
||||
VAR_TLS_CIPHERS = 519,
|
||||
VAR_TLS_CIPHERSUITES = 520,
|
||||
VAR_IPSET = 521,
|
||||
VAR_IPSET_NAME_V4 = 522,
|
||||
VAR_IPSET_NAME_V6 = 523,
|
||||
VAR_TLS_SESSION_TICKET_KEYS = 524,
|
||||
VAR_RPZ = 525,
|
||||
VAR_TAGS = 526,
|
||||
VAR_RPZ_ACTION_OVERRIDE = 527,
|
||||
VAR_RPZ_CNAME_OVERRIDE = 528,
|
||||
VAR_RPZ_LOG = 529,
|
||||
VAR_RPZ_LOG_NAME = 530
|
||||
VAR_SERVE_EXPIRED_REPLY_TTL = 463,
|
||||
VAR_SERVE_EXPIRED_CLIENT_TIMEOUT = 464,
|
||||
VAR_FAKE_DSA = 465,
|
||||
VAR_FAKE_SHA1 = 466,
|
||||
VAR_LOG_IDENTITY = 467,
|
||||
VAR_HIDE_TRUSTANCHOR = 468,
|
||||
VAR_TRUST_ANCHOR_SIGNALING = 469,
|
||||
VAR_AGGRESSIVE_NSEC = 470,
|
||||
VAR_USE_SYSTEMD = 471,
|
||||
VAR_SHM_ENABLE = 472,
|
||||
VAR_SHM_KEY = 473,
|
||||
VAR_ROOT_KEY_SENTINEL = 474,
|
||||
VAR_DNSCRYPT = 475,
|
||||
VAR_DNSCRYPT_ENABLE = 476,
|
||||
VAR_DNSCRYPT_PORT = 477,
|
||||
VAR_DNSCRYPT_PROVIDER = 478,
|
||||
VAR_DNSCRYPT_SECRET_KEY = 479,
|
||||
VAR_DNSCRYPT_PROVIDER_CERT = 480,
|
||||
VAR_DNSCRYPT_PROVIDER_CERT_ROTATED = 481,
|
||||
VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE = 482,
|
||||
VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS = 483,
|
||||
VAR_DNSCRYPT_NONCE_CACHE_SIZE = 484,
|
||||
VAR_DNSCRYPT_NONCE_CACHE_SLABS = 485,
|
||||
VAR_IPSECMOD_ENABLED = 486,
|
||||
VAR_IPSECMOD_HOOK = 487,
|
||||
VAR_IPSECMOD_IGNORE_BOGUS = 488,
|
||||
VAR_IPSECMOD_MAX_TTL = 489,
|
||||
VAR_IPSECMOD_WHITELIST = 490,
|
||||
VAR_IPSECMOD_STRICT = 491,
|
||||
VAR_CACHEDB = 492,
|
||||
VAR_CACHEDB_BACKEND = 493,
|
||||
VAR_CACHEDB_SECRETSEED = 494,
|
||||
VAR_CACHEDB_REDISHOST = 495,
|
||||
VAR_CACHEDB_REDISPORT = 496,
|
||||
VAR_CACHEDB_REDISTIMEOUT = 497,
|
||||
VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM = 498,
|
||||
VAR_FOR_UPSTREAM = 499,
|
||||
VAR_AUTH_ZONE = 500,
|
||||
VAR_ZONEFILE = 501,
|
||||
VAR_MASTER = 502,
|
||||
VAR_URL = 503,
|
||||
VAR_FOR_DOWNSTREAM = 504,
|
||||
VAR_FALLBACK_ENABLED = 505,
|
||||
VAR_TLS_ADDITIONAL_PORT = 506,
|
||||
VAR_LOW_RTT = 507,
|
||||
VAR_LOW_RTT_PERMIL = 508,
|
||||
VAR_FAST_SERVER_PERMIL = 509,
|
||||
VAR_FAST_SERVER_NUM = 510,
|
||||
VAR_ALLOW_NOTIFY = 511,
|
||||
VAR_TLS_WIN_CERT = 512,
|
||||
VAR_TCP_CONNECTION_LIMIT = 513,
|
||||
VAR_FORWARD_NO_CACHE = 514,
|
||||
VAR_STUB_NO_CACHE = 515,
|
||||
VAR_LOG_SERVFAIL = 516,
|
||||
VAR_DENY_ANY = 517,
|
||||
VAR_UNKNOWN_SERVER_TIME_LIMIT = 518,
|
||||
VAR_LOG_TAG_QUERYREPLY = 519,
|
||||
VAR_STREAM_WAIT_SIZE = 520,
|
||||
VAR_TLS_CIPHERS = 521,
|
||||
VAR_TLS_CIPHERSUITES = 522,
|
||||
VAR_IPSET = 523,
|
||||
VAR_IPSET_NAME_V4 = 524,
|
||||
VAR_IPSET_NAME_V6 = 525,
|
||||
VAR_TLS_SESSION_TICKET_KEYS = 526,
|
||||
VAR_RPZ = 527,
|
||||
VAR_TAGS = 528,
|
||||
VAR_RPZ_ACTION_OVERRIDE = 529,
|
||||
VAR_RPZ_CNAME_OVERRIDE = 530,
|
||||
VAR_RPZ_LOG = 531,
|
||||
VAR_RPZ_LOG_NAME = 532
|
||||
};
|
||||
#endif
|
||||
/* Tokens. */
|
||||
@ -526,87 +532,88 @@ extern int yydebug;
|
||||
#define VAR_SERVE_EXPIRED 460
|
||||
#define VAR_SERVE_EXPIRED_TTL 461
|
||||
#define VAR_SERVE_EXPIRED_TTL_RESET 462
|
||||
#define VAR_FAKE_DSA 463
|
||||
#define VAR_FAKE_SHA1 464
|
||||
#define VAR_LOG_IDENTITY 465
|
||||
#define VAR_HIDE_TRUSTANCHOR 466
|
||||
#define VAR_TRUST_ANCHOR_SIGNALING 467
|
||||
#define VAR_AGGRESSIVE_NSEC 468
|
||||
#define VAR_USE_SYSTEMD 469
|
||||
#define VAR_SHM_ENABLE 470
|
||||
#define VAR_SHM_KEY 471
|
||||
#define VAR_ROOT_KEY_SENTINEL 472
|
||||
#define VAR_DNSCRYPT 473
|
||||
#define VAR_DNSCRYPT_ENABLE 474
|
||||
#define VAR_DNSCRYPT_PORT 475
|
||||
#define VAR_DNSCRYPT_PROVIDER 476
|
||||
#define VAR_DNSCRYPT_SECRET_KEY 477
|
||||
#define VAR_DNSCRYPT_PROVIDER_CERT 478
|
||||
#define VAR_DNSCRYPT_PROVIDER_CERT_ROTATED 479
|
||||
#define VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE 480
|
||||
#define VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS 481
|
||||
#define VAR_DNSCRYPT_NONCE_CACHE_SIZE 482
|
||||
#define VAR_DNSCRYPT_NONCE_CACHE_SLABS 483
|
||||
#define VAR_IPSECMOD_ENABLED 484
|
||||
#define VAR_IPSECMOD_HOOK 485
|
||||
#define VAR_IPSECMOD_IGNORE_BOGUS 486
|
||||
#define VAR_IPSECMOD_MAX_TTL 487
|
||||
#define VAR_IPSECMOD_WHITELIST 488
|
||||
#define VAR_IPSECMOD_STRICT 489
|
||||
#define VAR_CACHEDB 490
|
||||
#define VAR_CACHEDB_BACKEND 491
|
||||
#define VAR_CACHEDB_SECRETSEED 492
|
||||
#define VAR_CACHEDB_REDISHOST 493
|
||||
#define VAR_CACHEDB_REDISPORT 494
|
||||
#define VAR_CACHEDB_REDISTIMEOUT 495
|
||||
#define VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM 496
|
||||
#define VAR_FOR_UPSTREAM 497
|
||||
#define VAR_AUTH_ZONE 498
|
||||
#define VAR_ZONEFILE 499
|
||||
#define VAR_MASTER 500
|
||||
#define VAR_URL 501
|
||||
#define VAR_FOR_DOWNSTREAM 502
|
||||
#define VAR_FALLBACK_ENABLED 503
|
||||
#define VAR_TLS_ADDITIONAL_PORT 504
|
||||
#define VAR_LOW_RTT 505
|
||||
#define VAR_LOW_RTT_PERMIL 506
|
||||
#define VAR_FAST_SERVER_PERMIL 507
|
||||
#define VAR_FAST_SERVER_NUM 508
|
||||
#define VAR_ALLOW_NOTIFY 509
|
||||
#define VAR_TLS_WIN_CERT 510
|
||||
#define VAR_TCP_CONNECTION_LIMIT 511
|
||||
#define VAR_FORWARD_NO_CACHE 512
|
||||
#define VAR_STUB_NO_CACHE 513
|
||||
#define VAR_LOG_SERVFAIL 514
|
||||
#define VAR_DENY_ANY 515
|
||||
#define VAR_UNKNOWN_SERVER_TIME_LIMIT 516
|
||||
#define VAR_LOG_TAG_QUERYREPLY 517
|
||||
#define VAR_STREAM_WAIT_SIZE 518
|
||||
#define VAR_TLS_CIPHERS 519
|
||||
#define VAR_TLS_CIPHERSUITES 520
|
||||
#define VAR_IPSET 521
|
||||
#define VAR_IPSET_NAME_V4 522
|
||||
#define VAR_IPSET_NAME_V6 523
|
||||
#define VAR_TLS_SESSION_TICKET_KEYS 524
|
||||
#define VAR_RPZ 525
|
||||
#define VAR_TAGS 526
|
||||
#define VAR_RPZ_ACTION_OVERRIDE 527
|
||||
#define VAR_RPZ_CNAME_OVERRIDE 528
|
||||
#define VAR_RPZ_LOG 529
|
||||
#define VAR_RPZ_LOG_NAME 530
|
||||
#define VAR_SERVE_EXPIRED_REPLY_TTL 463
|
||||
#define VAR_SERVE_EXPIRED_CLIENT_TIMEOUT 464
|
||||
#define VAR_FAKE_DSA 465
|
||||
#define VAR_FAKE_SHA1 466
|
||||
#define VAR_LOG_IDENTITY 467
|
||||
#define VAR_HIDE_TRUSTANCHOR 468
|
||||
#define VAR_TRUST_ANCHOR_SIGNALING 469
|
||||
#define VAR_AGGRESSIVE_NSEC 470
|
||||
#define VAR_USE_SYSTEMD 471
|
||||
#define VAR_SHM_ENABLE 472
|
||||
#define VAR_SHM_KEY 473
|
||||
#define VAR_ROOT_KEY_SENTINEL 474
|
||||
#define VAR_DNSCRYPT 475
|
||||
#define VAR_DNSCRYPT_ENABLE 476
|
||||
#define VAR_DNSCRYPT_PORT 477
|
||||
#define VAR_DNSCRYPT_PROVIDER 478
|
||||
#define VAR_DNSCRYPT_SECRET_KEY 479
|
||||
#define VAR_DNSCRYPT_PROVIDER_CERT 480
|
||||
#define VAR_DNSCRYPT_PROVIDER_CERT_ROTATED 481
|
||||
#define VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE 482
|
||||
#define VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS 483
|
||||
#define VAR_DNSCRYPT_NONCE_CACHE_SIZE 484
|
||||
#define VAR_DNSCRYPT_NONCE_CACHE_SLABS 485
|
||||
#define VAR_IPSECMOD_ENABLED 486
|
||||
#define VAR_IPSECMOD_HOOK 487
|
||||
#define VAR_IPSECMOD_IGNORE_BOGUS 488
|
||||
#define VAR_IPSECMOD_MAX_TTL 489
|
||||
#define VAR_IPSECMOD_WHITELIST 490
|
||||
#define VAR_IPSECMOD_STRICT 491
|
||||
#define VAR_CACHEDB 492
|
||||
#define VAR_CACHEDB_BACKEND 493
|
||||
#define VAR_CACHEDB_SECRETSEED 494
|
||||
#define VAR_CACHEDB_REDISHOST 495
|
||||
#define VAR_CACHEDB_REDISPORT 496
|
||||
#define VAR_CACHEDB_REDISTIMEOUT 497
|
||||
#define VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM 498
|
||||
#define VAR_FOR_UPSTREAM 499
|
||||
#define VAR_AUTH_ZONE 500
|
||||
#define VAR_ZONEFILE 501
|
||||
#define VAR_MASTER 502
|
||||
#define VAR_URL 503
|
||||
#define VAR_FOR_DOWNSTREAM 504
|
||||
#define VAR_FALLBACK_ENABLED 505
|
||||
#define VAR_TLS_ADDITIONAL_PORT 506
|
||||
#define VAR_LOW_RTT 507
|
||||
#define VAR_LOW_RTT_PERMIL 508
|
||||
#define VAR_FAST_SERVER_PERMIL 509
|
||||
#define VAR_FAST_SERVER_NUM 510
|
||||
#define VAR_ALLOW_NOTIFY 511
|
||||
#define VAR_TLS_WIN_CERT 512
|
||||
#define VAR_TCP_CONNECTION_LIMIT 513
|
||||
#define VAR_FORWARD_NO_CACHE 514
|
||||
#define VAR_STUB_NO_CACHE 515
|
||||
#define VAR_LOG_SERVFAIL 516
|
||||
#define VAR_DENY_ANY 517
|
||||
#define VAR_UNKNOWN_SERVER_TIME_LIMIT 518
|
||||
#define VAR_LOG_TAG_QUERYREPLY 519
|
||||
#define VAR_STREAM_WAIT_SIZE 520
|
||||
#define VAR_TLS_CIPHERS 521
|
||||
#define VAR_TLS_CIPHERSUITES 522
|
||||
#define VAR_IPSET 523
|
||||
#define VAR_IPSET_NAME_V4 524
|
||||
#define VAR_IPSET_NAME_V6 525
|
||||
#define VAR_TLS_SESSION_TICKET_KEYS 526
|
||||
#define VAR_RPZ 527
|
||||
#define VAR_TAGS 528
|
||||
#define VAR_RPZ_ACTION_OVERRIDE 529
|
||||
#define VAR_RPZ_CNAME_OVERRIDE 530
|
||||
#define VAR_RPZ_LOG 531
|
||||
#define VAR_RPZ_LOG_NAME 532
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
|
||||
union YYSTYPE
|
||||
{
|
||||
#line 66 "./util/configparser.y" /* yacc.c:1909 */
|
||||
#line 66 "./util/configparser.y"
|
||||
|
||||
char* str;
|
||||
|
||||
#line 608 "util/configparser.h" /* yacc.c:1909 */
|
||||
};
|
||||
#line 615 "util/configparser.h"
|
||||
|
||||
};
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
|
@ -143,10 +143,11 @@ extern struct config_parser_state* cfg_parser;
|
||||
%token VAR_LOCAL_ZONE_OVERRIDE VAR_ACCESS_CONTROL_TAG_ACTION
|
||||
%token VAR_ACCESS_CONTROL_TAG_DATA VAR_VIEW VAR_ACCESS_CONTROL_VIEW
|
||||
%token VAR_VIEW_FIRST VAR_SERVE_EXPIRED VAR_SERVE_EXPIRED_TTL
|
||||
%token VAR_SERVE_EXPIRED_TTL_RESET VAR_FAKE_DSA VAR_FAKE_SHA1
|
||||
%token VAR_LOG_IDENTITY VAR_HIDE_TRUSTANCHOR VAR_TRUST_ANCHOR_SIGNALING
|
||||
%token VAR_AGGRESSIVE_NSEC VAR_USE_SYSTEMD VAR_SHM_ENABLE VAR_SHM_KEY
|
||||
%token VAR_ROOT_KEY_SENTINEL
|
||||
%token VAR_SERVE_EXPIRED_TTL_RESET VAR_SERVE_EXPIRED_REPLY_TTL
|
||||
%token VAR_SERVE_EXPIRED_CLIENT_TIMEOUT VAR_FAKE_DSA
|
||||
%token VAR_FAKE_SHA1 VAR_LOG_IDENTITY VAR_HIDE_TRUSTANCHOR
|
||||
%token VAR_TRUST_ANCHOR_SIGNALING VAR_AGGRESSIVE_NSEC VAR_USE_SYSTEMD
|
||||
%token VAR_SHM_ENABLE VAR_SHM_KEY VAR_ROOT_KEY_SENTINEL
|
||||
%token VAR_DNSCRYPT VAR_DNSCRYPT_ENABLE VAR_DNSCRYPT_PORT VAR_DNSCRYPT_PROVIDER
|
||||
%token VAR_DNSCRYPT_SECRET_KEY VAR_DNSCRYPT_PROVIDER_CERT
|
||||
%token VAR_DNSCRYPT_PROVIDER_CERT_ROTATED
|
||||
@ -256,6 +257,7 @@ content_server: server_num_threads | server_verbosity | server_port |
|
||||
server_access_control_tag_data | server_access_control_view |
|
||||
server_qname_minimisation_strict | server_serve_expired |
|
||||
server_serve_expired_ttl | server_serve_expired_ttl_reset |
|
||||
server_serve_expired_reply_ttl | server_serve_expired_client_timeout |
|
||||
server_fake_dsa | server_log_identity | server_use_systemd |
|
||||
server_response_ip_tag | server_response_ip | server_response_ip_data |
|
||||
server_shm_enable | server_shm_key | server_fake_sha1 |
|
||||
@ -1757,6 +1759,24 @@ server_serve_expired_ttl_reset: VAR_SERVE_EXPIRED_TTL_RESET STRING_ARG
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
server_serve_expired_reply_ttl: VAR_SERVE_EXPIRED_REPLY_TTL STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_serve_expired_reply_ttl:%s)\n", $2));
|
||||
if(atoi($2) == 0 && strcmp($2, "0") != 0)
|
||||
yyerror("number expected");
|
||||
else cfg_parser->cfg->serve_expired_reply_ttl = atoi($2);
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
server_serve_expired_client_timeout: VAR_SERVE_EXPIRED_CLIENT_TIMEOUT STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_serve_expired_client_timeout:%s)\n", $2));
|
||||
if(atoi($2) == 0 && strcmp($2, "0") != 0)
|
||||
yyerror("number expected");
|
||||
else cfg_parser->cfg->serve_expired_client_timeout = atoi($2);
|
||||
free($2);
|
||||
}
|
||||
;
|
||||
server_fake_dsa: VAR_FAKE_DSA STRING_ARG
|
||||
{
|
||||
OUTYY(("P(server_fake_dsa:%s)\n", $2));
|
||||
@ -2989,9 +3009,6 @@ cachedb_backend_name: VAR_CACHEDB_BACKEND STRING_ARG
|
||||
{
|
||||
#ifdef USE_CACHEDB
|
||||
OUTYY(("P(backend:%s)\n", $2));
|
||||
if(cfg_parser->cfg->cachedb_backend)
|
||||
yyerror("cachedb backend override, there must be one "
|
||||
"backend");
|
||||
free(cfg_parser->cfg->cachedb_backend);
|
||||
cfg_parser->cfg->cachedb_backend = $2;
|
||||
#else
|
||||
@ -3004,9 +3021,6 @@ cachedb_secret_seed: VAR_CACHEDB_SECRETSEED STRING_ARG
|
||||
{
|
||||
#ifdef USE_CACHEDB
|
||||
OUTYY(("P(secret-seed:%s)\n", $2));
|
||||
if(cfg_parser->cfg->cachedb_secret)
|
||||
yyerror("cachedb secret-seed override, there must be "
|
||||
"only one secret");
|
||||
free(cfg_parser->cfg->cachedb_secret);
|
||||
cfg_parser->cfg->cachedb_secret = $2;
|
||||
#else
|
||||
|
@ -480,7 +480,8 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
|
||||
sldns_buffer_write(pkt, &key->rk.type, 2);
|
||||
sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
|
||||
if(data->rr_ttl[j] < timenow)
|
||||
sldns_buffer_write_u32(pkt, 0);
|
||||
sldns_buffer_write_u32(pkt,
|
||||
SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0);
|
||||
else sldns_buffer_write_u32(pkt,
|
||||
data->rr_ttl[j]-timenow);
|
||||
if(c) {
|
||||
@ -517,7 +518,8 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
|
||||
sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG);
|
||||
sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
|
||||
if(data->rr_ttl[i] < timenow)
|
||||
sldns_buffer_write_u32(pkt, 0);
|
||||
sldns_buffer_write_u32(pkt,
|
||||
SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0);
|
||||
else sldns_buffer_write_u32(pkt,
|
||||
data->rr_ttl[i]-timenow);
|
||||
/* rrsig rdata cannot be compressed, perform 100+ byte
|
||||
|
@ -79,8 +79,12 @@ extern time_t MAX_TTL;
|
||||
extern time_t MIN_TTL;
|
||||
/** Maximum Negative TTL that is allowed */
|
||||
extern time_t MAX_NEG_TTL;
|
||||
/** If we serve expired entries and prefetch them */
|
||||
extern int SERVE_EXPIRED;
|
||||
/** Time to serve records after expiration */
|
||||
extern time_t SERVE_EXPIRED_TTL;
|
||||
/** TTL to use for expired records */
|
||||
extern time_t SERVE_EXPIRED_REPLY_TTL;
|
||||
/** Negative cache time (for entries without any RRs.) */
|
||||
#define NORR_TTL 5 /* seconds */
|
||||
|
||||
|
@ -61,8 +61,12 @@ time_t MAX_TTL = 3600 * 24 * 10; /* ten days */
|
||||
time_t MIN_TTL = 0;
|
||||
/** MAX Negative TTL, for SOA records in authority section */
|
||||
time_t MAX_NEG_TTL = 3600; /* one hour */
|
||||
/** If we serve expired entries and prefetch them */
|
||||
int SERVE_EXPIRED = 0;
|
||||
/** Time to serve records after expiration */
|
||||
time_t SERVE_EXPIRED_TTL = 0;
|
||||
/** TTL to use for expired records */
|
||||
time_t SERVE_EXPIRED_REPLY_TTL = 30;
|
||||
|
||||
/** allocate qinfo, return 0 on error */
|
||||
static int
|
||||
|
@ -40,6 +40,7 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/packed_rrset.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/storage/lookup3.h"
|
||||
@ -351,11 +352,11 @@ packed_rrset_copy_region(struct ub_packed_rrset_key* key,
|
||||
/* make TTLs relative - once per rrset */
|
||||
for(i=0; i<d->count + d->rrsig_count; i++) {
|
||||
if(d->rr_ttl[i] < now)
|
||||
d->rr_ttl[i] = 0;
|
||||
d->rr_ttl[i] = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
|
||||
else d->rr_ttl[i] -= now;
|
||||
}
|
||||
if(d->ttl < now)
|
||||
d->ttl = 0;
|
||||
d->ttl = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
|
||||
else d->ttl -= now;
|
||||
return ck;
|
||||
}
|
||||
|
@ -131,6 +131,7 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
|
||||
else if(fptr == &auth_xfer_timer) return 1;
|
||||
else if(fptr == &auth_xfer_probe_timer_callback) return 1;
|
||||
else if(fptr == &auth_xfer_transfer_timer_callback) return 1;
|
||||
else if(fptr == &mesh_serve_expired_callback) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -619,3 +620,9 @@ int fptr_whitelist_inplace_cb_query_response(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fptr_whitelist_serve_expired_lookup(serve_expired_lookup_func_type* fptr)
|
||||
{
|
||||
if(fptr == &mesh_serve_expired_lookup)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -377,6 +377,13 @@ int fptr_whitelist_inplace_cb_edns_back_parsed(
|
||||
int fptr_whitelist_inplace_cb_query_response(
|
||||
inplace_cb_query_response_func_type* fptr);
|
||||
|
||||
/**
|
||||
* Check function pointer whitelist for serve_expired_lookup func values.
|
||||
* @param fptr: function pointer to check.
|
||||
* @return false if not in whitelist.
|
||||
*/
|
||||
int fptr_whitelist_serve_expired_lookup(serve_expired_lookup_func_type* fptr);
|
||||
|
||||
/** Due to module breakage by fptr wlist, these test app declarations
|
||||
* are presented here */
|
||||
/**
|
||||
|
@ -306,6 +306,17 @@ typedef int inplace_cb_edns_back_parsed_func_type(struct module_qstate* qstate,
|
||||
typedef int inplace_cb_query_response_func_type(struct module_qstate* qstate,
|
||||
struct dns_msg* response, int id, void* cb_args);
|
||||
|
||||
/**
|
||||
* Function called when looking for (expired) cached answers during the serve
|
||||
* expired logic.
|
||||
* Called as func(qstate, lookup_qinfo)
|
||||
* Where:
|
||||
* qstate: the query state.
|
||||
* lookup_qinfo: the qinfo to lookup for.
|
||||
*/
|
||||
typedef struct dns_msg* serve_expired_lookup_func_type(
|
||||
struct module_qstate* qstate, struct query_info* lookup_qinfo);
|
||||
|
||||
/**
|
||||
* Module environment.
|
||||
* Services and data provided to the module.
|
||||
@ -571,6 +582,14 @@ struct sock_list {
|
||||
|
||||
struct respip_action_info;
|
||||
|
||||
/**
|
||||
* Struct to hold relevant data for serve expired
|
||||
*/
|
||||
struct serve_expired_data {
|
||||
struct comm_timer* timer;
|
||||
serve_expired_lookup_func_type* get_cached_answer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Module state, per query.
|
||||
*/
|
||||
@ -612,6 +631,8 @@ struct module_qstate {
|
||||
struct mesh_state* mesh_info;
|
||||
/** how many seconds before expiry is this prefetched (0 if not) */
|
||||
time_t prefetch_leeway;
|
||||
/** serve expired data */
|
||||
struct serve_expired_data* serve_expired_data;
|
||||
|
||||
/** incoming edns options from the front end */
|
||||
struct edns_option* edns_opts_front_in;
|
||||
|
Loading…
Reference in New Issue
Block a user