FLAGS_GET_RCODE(qstate->return_msg->rep->flags) !=
LDNS_RCODE_YXDOMAIN)
return 0;
- /* We don't store the reply if its TTL is 0 unless serve-expired is
- * enabled. Such a reply won't be reusable and simply be a waste for
- * the backend. It's also compatible with the default behavior of
- * dns_cache_store_msg(). */
- if(qstate->return_msg->rep->ttl == 0 &&
- !qstate->env->cfg->serve_expired)
+ /* We don't store the reply if its TTL is 0. This is probably coming
+ * from upstream and it is not meant to be stored. */
+ if(qstate->return_msg->rep->ttl == 0)
return 0;
/* The EDE is added to the out-list so it is encoded in the cached message */
qstate->return_msg->rep);
if(!reply_info_answer_encode(&qstate->return_msg->qinfo,
qstate->return_msg->rep, 0, qstate->query_flags,
- buf, 0, 1, qstate->env->scratch, 65535, &edns, 1, 0, 1))
+ buf, 0, 1, qstate->env->scratch, 65535, &edns, 1, 0))
return 0;
/* TTLs in the return_msg are relative to time(0) so we have to
* - 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 &&
+ if(TTL_IS_EXPIRED((time_t)expiry, *qstate->env->now) &&
(!qstate->env->cfg->serve_expired ||
(SERVE_EXPIRED_TTL &&
*qstate->env->now - (time_t)expiry > SERVE_EXPIRED_TTL)))
/* Adjust the TTL of the given RRset by 'subtract'. If 'subtract' is
* negative, set the TTL to 0. */
static void
-packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract)
+packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract,
+ time_t timestamp)
{
size_t i;
size_t total = data->count + data->rrsig_count;
data->rr_ttl[i] -= subtract;
else data->rr_ttl[i] = 0;
}
- data->ttl_add = (subtract < data->ttl_add) ? (data->ttl_add - subtract) : 0;
+ data->ttl_add = timestamp;
}
/* Adjust the TTL of a DNS message and its RRs by 'adjust'. If 'adjust' is
* negative, set the TTLs to 0. */
static void
-adjust_msg_ttl(struct dns_msg* msg, time_t adjust)
+adjust_msg_ttl(struct dns_msg* msg, time_t adjust, time_t timestamp)
{
size_t i;
if(adjust >= 0 && msg->rep->ttl > adjust)
for(i=0; i<msg->rep->rrset_count; i++) {
packed_rrset_ttl_subtract((struct packed_rrset_data*)msg->
- rep->rrsets[i]->entry.data, adjust);
+ rep->rrsets[i]->entry.data, adjust, timestamp);
}
}
/* Set the TTL of the given RRset to fixed value. */
static void
-packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl)
+packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl, time_t timestamp)
{
size_t i;
size_t total = data->count + data->rrsig_count;
for(i=0; i<total; i++) {
data->rr_ttl[i] = ttl;
}
- data->ttl_add = 0;
+ data->ttl_add = timestamp;
}
/* Set the TTL of a DNS message and its RRs by to a fixed value. */
static void
-set_msg_ttl(struct dns_msg* msg, time_t ttl)
+set_msg_ttl(struct dns_msg* msg, time_t ttl, time_t timestamp)
{
size_t i;
msg->rep->ttl = ttl;
for(i=0; i<msg->rep->rrset_count; i++) {
packed_rrset_ttl_set((struct packed_rrset_data*)msg->
- rep->rrsets[i]->entry.data, ttl);
+ rep->rrsets[i]->entry.data, ttl, timestamp);
}
}
/** convert dns message in buffer to return_msg */
static int
parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
- int* msg_expired)
+ int* msg_expired, time_t* msg_timestamp, time_t* msg_expiry)
{
struct msg_parse* prs;
struct edns_data edns;
×tamp, sizeof(timestamp));
expiry = be64toh(expiry);
timestamp = be64toh(timestamp);
+ log_assert(timestamp <= expiry);
+ *msg_expiry = (time_t)expiry;
+ *msg_timestamp = (time_t)timestamp;
/* parse DNS packet */
regional_free_all(qstate->env->scratch);
return 1; /* message from the future (clock skew?) */
}
adjust = *qstate->env->now - (time_t)timestamp;
- if(qstate->return_msg->rep->ttl < adjust) {
+ if(TTL_IS_EXPIRED((time_t)expiry, *qstate->env->now)) {
verbose(VERB_ALGO, "cachedb msg expired");
*msg_expired = 1;
- /* If serve-expired is enabled, we still use an expired message
- * setting the TTL to 0. */
if(!qstate->env->cfg->serve_expired ||
(FLAGS_GET_RCODE(qstate->return_msg->rep->flags)
!= LDNS_RCODE_NOERROR &&
FLAGS_GET_RCODE(qstate->return_msg->rep->flags)
!= LDNS_RCODE_YXDOMAIN))
return 0; /* message expired */
- else
- adjust = -1;
+ /* If serve-expired is enabled, we still use an expired message.
+ * Set the TTL to 0 now and it will be handled specially later
+ * when we need to store it internally. */
+ adjust = -1;
}
+ adjust_msg_ttl(qstate->return_msg, adjust, timestamp);
verbose(VERB_ALGO, "cachedb msg adjusted down by %d", (int)adjust);
- adjust_msg_ttl(qstate->return_msg, adjust);
if(qstate->env->cfg->aggressive_nsec) {
limit_nsec_ttl(qstate->return_msg);
}
/* Similar to the unbound worker, if serve-expired is enabled and
* the msg would be considered to be expired, mark the state so a
- * refetch will be scheduled. The comparison between 'expiry' and
- * 'now' should be redundant given how these values were calculated,
- * but we check it just in case as does good_expiry_and_qinfo(). */
- if(qstate->env->cfg->serve_expired &&
- !qstate->env->cfg->serve_expired_client_timeout &&
- (adjust == -1 || (time_t)expiry < *qstate->env->now)) {
+ * refetch will be scheduled. */
+ if(*msg_expired && !qstate->env->cfg->serve_expired_client_timeout) {
qstate->need_refetch = 1;
}
*/
static int
cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie,
- int* msg_expired)
+ int* msg_expired, time_t* msg_timestamp, time_t* msg_expiry)
{
char key[(CACHEDB_HASHSIZE/8)*2+1];
calc_hash(&qstate->qinfo, qstate->env, key, sizeof(key));
}
/* parse dns message into return_msg */
- if( !parse_data(qstate, qstate->env->scratch_buffer, msg_expired) ) {
+ if( !parse_data(qstate, qstate->env->scratch_buffer, msg_expired,
+ msg_timestamp, msg_expiry) ) {
return 0;
}
return 1;
* Store query into the internal cache of unbound.
*/
static void
-cachedb_intcache_store(struct module_qstate* qstate, int msg_expired)
+cachedb_intcache_store(struct module_qstate* qstate, int msg_expired,
+ time_t msg_timestamp, time_t msg_expiry)
{
uint32_t store_flags = qstate->query_flags;
int serve_expired = qstate->env->cfg->serve_expired;
-
- if(qstate->env->cfg->serve_expired)
- store_flags |= DNSCACHE_STORE_ZEROTTL;
if(!qstate->return_msg)
return;
if(serve_expired && msg_expired) {
- /* Set TTLs to a value such that value + *env->now is
- * going to be now-3 seconds. Making it expired
- * in the cache. */
- set_msg_ttl(qstate->return_msg, (time_t)-3);
+ time_t original_ttl = msg_expiry - msg_timestamp;
+ store_flags |= DNSCACHE_STORE_EXPIRED_MSG_CACHEDB;
+ /* Pass the original TTL of the expired message and signal with
+ * the DNSCACHE_STORE_EXPIRED_MSG_CACHEDB flag that
+ * dns_cache_store_msg() needs to set absolute expired TTLs
+ * based on the original message TTL.
+ * Results as expired message in the cache */
+ set_msg_ttl(qstate->return_msg, original_ttl, 0);
+ verbose(VERB_ALGO, "cachedb expired msg set to be expired now "
+ "(original ttl: %d)", (int)original_ttl);
/* The expired entry does not get checked by the validator
* and we need a validation value for it. */
if(qstate->env->cfg->cachedb_check_when_serve_expired)
* of cache. */
return;
}
- /* set TTLs to zero again */
- adjust_msg_ttl(qstate->return_msg, -1);
/* Send serve expired responses based on the cachedb
* returned message, that was just stored in the cache.
* It can then continue to work on this query. */
mesh_respond_serve_expired(qstate->mesh_info);
+ /* set TTLs as expired for this return_msg in case it is used
+ * later on */
+ set_msg_ttl(qstate->return_msg,
+ EXPIRED_REPLY_TTL_CALC(msg_expiry, msg_timestamp), 0);
}
}
struct cachedb_env* ie, int id)
{
int msg_expired = 0;
+ time_t msg_timestamp, msg_expiry;
qstate->is_cachedb_answer = 0;
/* check if we are enabled, and skip if so */
if(!ie->enabled) {
}
/* ask backend cache to see if we have data */
- if(cachedb_extcache_lookup(qstate, ie, &msg_expired)) {
+ if(cachedb_extcache_lookup(qstate, ie, &msg_expired, &msg_timestamp,
+ &msg_expiry)) {
if(verbosity >= VERB_ALGO)
log_dns_msg(ie->backend->name,
&qstate->return_msg->qinfo,
qstate->return_msg->rep);
/* store this result in internal cache */
- cachedb_intcache_store(qstate, msg_expired);
+ cachedb_intcache_store(qstate,
+ msg_expired, msg_timestamp, msg_expiry);
/* 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.
qstate->ext_state[id] = module_wait_module;
return;
}
+ /* No 0TTL answers escaping from external cache. */
+ log_assert(qstate->return_msg->rep->ttl > 0);
qstate->is_cachedb_answer = 1;
/* we are done with the query */
qstate->ext_state[id] = module_finished;
}
if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags,
repinfo->c->buffer, 0, 1, worker->scratchpad,
- udpsize, edns, (int)(edns->bits & EDNS_DO), secure, 1)) {
+ udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
worker->env.now_tv))
*partial_repp = NULL; /* avoid accidental further pass */
/* Check TTL */
- if(rep->ttl < timenow) {
+ if(TTL_IS_EXPIRED(rep->ttl, timenow)) {
/* Check if we need to serve expired now */
if(worker->env.cfg->serve_expired &&
/* if serve-expired-client-timeout is set, serve
if(!reply_info_answer_encode(qinfo, encode_rep, id, flags,
repinfo->c->buffer, timenow, 1, worker->scratchpad,
udpsize, edns, (int)(edns->bits & EDNS_DO),
- *is_secure_answer, 1)) {
+ *is_secure_answer)) {
if(!inplace_cb_reply_servfail_call(&worker->env, qinfo,
NULL, NULL, LDNS_RCODE_SERVFAIL, edns, repinfo,
worker->scratchpad, worker->env.now_tv))
if((worker->env.cfg->prefetch &&
rep->prefetch_ttl <= *worker->env.now) ||
(worker->env.cfg->serve_expired &&
- rep->ttl < *worker->env.now &&
+ TTL_IS_EXPIRED(rep->ttl, *worker->env.now) &&
!(*worker->env.now < rep->serve_expired_norec_ttl))) {
- time_t leeway = rep->ttl - *worker->env.now;
- if(rep->ttl < *worker->env.now)
- leeway = 0;
+ time_t leeway =
+ TTL_IS_EXPIRED(rep->ttl, *worker->env.now)
+ ? 0 : rep->ttl - *worker->env.now;
lock_rw_unlock(&e->lock);
reply_and_prefetch(worker, lookup_qinfo,
# serve-expired-ttl-reset: no
#
# TTL value to use when replying with expired data.
+ # Capped by the original TTL of the record.
# serve-expired-reply-ttl: 30
#
# Time in milliseconds before replying to the client with expired data.
:ref:`serve-expired-client-timeout<unbound.conf.serve-expired-client-timeout>`
is also used then it is RECOMMENDED to use 30 as the value (:rfc:`8767`).
+ This value is capped by the original TTL of the record.
+ This means that records with higher original TTL than this value will use
+ this value for expired replies.
+ Records with lower original TTL than this value will use their original TTL
+ for expired replies.
+
Default: 30
/** Copy rrset into region from domain-datanode and packet rrset */
static struct ub_packed_rrset_key*
auth_packed_rrset_copy_region(struct auth_zone* z, struct auth_data* node,
- struct auth_rrset* rrset, struct regional* region, time_t adjust)
+ struct auth_rrset* rrset, struct regional* region)
{
struct ub_packed_rrset_key key;
memset(&key, 0, sizeof(key));
key.rk.type = htons(rrset->type);
key.rk.rrset_class = htons(z->dclass);
key.entry.hash = rrset_key_hash(&key.rk);
- return packed_rrset_copy_region(&key, region, adjust);
+ return packed_rrset_copy_region(&key, region, 0);
}
/** fix up msg->rep TTL and prefetch ttl */
return 0;
/* copy it */
if(!(msg->rep->rrsets[msg->rep->rrset_count] =
- auth_packed_rrset_copy_region(z, node, rrset, region, 0)))
+ auth_packed_rrset_copy_region(z, node, rrset, region)))
return 0;
msg->rep->rrset_count++;
msg->rep->an_numrrsets++;
return 0;
/* copy it */
if(!(msg->rep->rrsets[msg->rep->rrset_count] =
- auth_packed_rrset_copy_region(z, node, rrset, region, 0)))
+ auth_packed_rrset_copy_region(z, node, rrset, region)))
return 0;
msg->rep->rrset_count++;
msg->rep->ns_numrrsets++;
return 0;
/* copy it */
if(!(msg->rep->rrsets[msg->rep->rrset_count] =
- auth_packed_rrset_copy_region(z, node, rrset, region, 0)))
+ auth_packed_rrset_copy_region(z, node, rrset, region)))
return 0;
msg->rep->rrset_count++;
msg->rep->ar_numrrsets++;
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2),
buf, 0, 0, temp, udpsize, edns,
- (int)(edns->bits&EDNS_DO), 0, 0)) {
+ (int)(edns->bits&EDNS_DO), 0)) {
error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
* @param rep: contains list of rrsets to store.
* @param now: current time.
* @param leeway: during prefetch how much leeway to update TTLs.
- * This makes rrsets (other than type NS) timeout sooner so they get
- * updated with a new full TTL.
- * Type NS does not get this, because it must not be refreshed from the
- * child domain, but keep counting down properly.
+ * This makes rrsets expire sooner so they get updated with a new full
+ * TTL.
+ * Child side type NS does get this but TTL checks are done using the time
+ * the query was created rather than the time the answer was received.
* @param pside: if from parentside discovered NS, so that its NS is okay
* in a prefetch situation to be updated (without becoming sticky).
* @param qrep: update rrsets here if cache is better
rep->ref[i].id != rep->ref[i].key->id)
ck = NULL;
else ck = packed_rrset_copy_region(
- rep->ref[i].key, region, now);
+ rep->ref[i].key, region,
+ ((ntohs(rep->ref[i].key->rk.type)==
+ LDNS_RR_TYPE_NS && !pside)?qstarttime:now));
lock_rw_unlock(&rep->ref[i].key->entry.lock);
if(ck) {
/* use cached copy if memory allows */
qrep->rrsets[i] = ck;
+ ttl = ((struct packed_rrset_data*)
+ ck->entry.data)->ttl;
+ if(ttl < qrep->ttl) {
+ qrep->ttl = ttl;
+ qrep->prefetch_ttl = PREFETCH_TTL_CALC(qrep->ttl);
+ qrep->serve_expired_ttl = qrep->ttl + SERVE_EXPIRED_TTL;
+ }
}
}
/* no break: also copy key item */
/* there was a reply_info_sortref(rep) here but it seems to be
* unnecessary, because the cache gets locked per rrset. */
- reply_info_set_ttls(rep, *env->now);
+ if((flags & DNSCACHE_STORE_EXPIRED_MSG_CACHEDB)) {
+ reply_info_absolute_ttls(rep, *env->now, *env->now - ttl);
+ } else reply_info_set_ttls(rep, *env->now);
store_rrsets(env, rep, *env->now, leeway, pside, qrep, region,
qstarttime);
- if(ttl == 0 && !(flags & DNSCACHE_STORE_ZEROTTL)) {
+ if(ttl == 0) {
/* we do not store the message, but we did store the RRs,
* which could be useful for delegation information */
verbose(VERB_ALGO, "TTL 0: dropped msg from cache");
{
if((msg->rep->rrsets[msg->rep->rrset_count] =
packed_rrset_copy_region(rrset, region, now))) {
+ struct packed_rrset_data* d = rrset->entry.data;
msg->rep->ar_numrrsets++;
msg->rep->rrset_count++;
+ UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
}
}
/* add it to auth section. This is the second rrset. */
if((msg->rep->rrsets[msg->rep->rrset_count] =
packed_rrset_copy_region(rrset, region, now))) {
+ struct packed_rrset_data* d = rrset->entry.data;
msg->rep->ns_numrrsets++;
msg->rep->rrset_count++;
+ UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
}
lock_rw_unlock(&rrset->entry.lock);
}
return NULL; /* integer overflow protection */
msg->rep->flags = BIT_QR; /* with QR, no AA */
msg->rep->qdcount = 1;
+ msg->rep->ttl = MAX_TTL; /* will be updated (brought down) while we add
+ * rrsets to the message */
msg->rep->reason_bogus = LDNS_EDE_NONE;
msg->rep->rrsets = (struct ub_packed_rrset_key**)
regional_alloc(region,
}
int
-dns_msg_authadd(struct dns_msg* msg, struct regional* region,
+dns_msg_authadd(struct dns_msg* msg, struct regional* region,
struct ub_packed_rrset_key* rrset, time_t now)
{
- if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
+ struct packed_rrset_data* d = rrset->entry.data;
+ if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
packed_rrset_copy_region(rrset, region, now)))
return 0;
msg->rep->ns_numrrsets++;
+ UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
return 1;
}
int
-dns_msg_ansadd(struct dns_msg* msg, struct regional* region,
+dns_msg_ansadd(struct dns_msg* msg, struct regional* region,
struct ub_packed_rrset_key* rrset, time_t now)
{
- if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
+ struct packed_rrset_data* d = rrset->entry.data;
+ if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
packed_rrset_copy_region(rrset, region, now)))
return 0;
msg->rep->an_numrrsets++;
+ UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
return 1;
}
sizeof(struct reply_info) - sizeof(struct rrset_ref));
if(!msg->rep)
return NULL;
+ msg->rep->ttl = MAX_TTL;
msg->rep->reason_bogus = LDNS_EDE_NONE;
msg->rep->reason_bogus_str = NULL;
if(num > RR_COUNT_MAX)
size_t i;
int is_expired = 0;
time_t now_control = now;
- if(now > r->ttl) {
+ if(TTL_IS_EXPIRED(r->ttl, now)) {
/* Check if we are allowed to serve expired */
if(!allow_expired || !reply_info_can_answer_expired(r, now))
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;
+ /* Change the current time so we can pass the below TTL checks
+ * when serving expired data. */
+ now_control = 0;
is_expired = 1;
}
if(!msg) return NULL;
msg->rep->flags = r->flags;
msg->rep->qdcount = r->qdcount;
- 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);
- msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
- msg->rep->serve_expired_norec_ttl = 0;
msg->rep->security = r->security;
msg->rep->an_numrrsets = r->an_numrrsets;
msg->rep->ns_numrrsets = r->ns_numrrsets;
return NULL;
}
for(i=0; i<msg->rep->rrset_count; i++) {
+ struct packed_rrset_data* d;
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);
return NULL;
}
+ d = msg->rep->rrsets[i]->entry.data;
+ UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
}
+ if(msg->rep->rrset_count < 1) {
+ 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->ttl has been updated through the RRSets above */
+ msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
+ }
+ msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
+ msg->rep->serve_expired_norec_ttl = 0;
if(env)
rrset_array_unlock_touch(env->rrset_cache, scratch, r->ref,
r->rrset_count);
struct dns_msg* msg;
struct packed_rrset_data* d = (struct packed_rrset_data*)
rrset->entry.data;
- if(now > d->ttl)
+ if(TTL_IS_EXPIRED(d->ttl, now))
return NULL;
msg = gen_dns_msg(region, q, 1); /* only the CNAME (or other) RRset */
if(!msg)
rrset->entry.data;
uint8_t* newname, *dtarg = NULL;
size_t newlen, dtarglen;
- if(now > d->ttl)
+ if(TTL_IS_EXPIRED(d->ttl, now))
return NULL;
/* only allow validated (with DNSSEC) DNAMEs used from cache
* for insecure DNAMEs, query again. */
/* set NOTIMPL for RFC 8482 */
msg->rep->flags |= LDNS_RCODE_NOTIMPL;
msg->rep->security = sec_status_indeterminate;
+ msg->rep->ttl = 1; /* empty NOTIMPL response will never be
+ * updated with rrsets, set TTL to 1 */
return msg;
}
msgqinf->qclass, flags, 0, 1);
if(e) {
struct reply_info* cached = e->entry.data;
- if(cached->ttl < *env->now
+ if(TTL_IS_EXPIRED(cached->ttl, *env->now)
&& reply_info_could_use_expired(cached, *env->now)
/* If we are validating make sure only
* validating modules can update such messages.
* Must be an unsigned 32-bit value larger than 0xffff */
/** Allow caching a DNS message with a zero TTL. */
-#define DNSCACHE_STORE_ZEROTTL 0x100000
+#define DNSCACHE_STORE_EXPIRED_MSG_CACHEDB 0x100000
/**
* Region allocated message reply
struct packed_rrset_data* newd = (struct packed_rrset_data*)nd;
struct packed_rrset_data* cached = (struct packed_rrset_data*)cd;
/* o if new data is expired, cached data is better */
- if( newd->ttl < timenow && timenow <= cached->ttl)
+ if( TTL_IS_EXPIRED(newd->ttl, timenow) && !TTL_IS_EXPIRED(cached->ttl, timenow))
return 0;
/* o store if rrset has been validated
* everything better than bogus data
if( newd->trust > cached->trust ) {
/* if the cached rrset is bogus, and new is equal,
* do not update the TTL - let it expire. */
- if(equal && cached->ttl >= timenow &&
+ if(equal && !TTL_IS_EXPIRED(cached->ttl, timenow) &&
cached->security == sec_status_bogus)
return 0;
return 1;
}
/* o item in cache has expired */
- if( cached->ttl < timenow )
+ if( TTL_IS_EXPIRED(cached->ttl, timenow) )
return 1;
/* o same trust, but different in data - insert it */
if( newd->trust == cached->trust && !equal ) {
/* check TTL */
struct packed_rrset_data* data =
(struct packed_rrset_data*)e->data;
- if(timenow > data->ttl) {
+ if(TTL_IS_EXPIRED(data->ttl, timenow)) {
lock_rw_unlock(&e->lock);
return NULL;
}
return NULL;
}
-int
+int
rrset_array_lock(struct rrset_ref* ref, size_t count, time_t timenow)
{
size_t i;
+ struct packed_rrset_data* d;
for(i=0; i<count; i++) {
if(i>0 && ref[i].key == ref[i-1].key)
continue; /* only lock items once */
lock_rw_rdlock(&ref[i].key->entry.lock);
- if(ref[i].id != ref[i].key->id || timenow >
- ((struct packed_rrset_data*)(ref[i].key->entry.data))
- ->ttl) {
+ d = ref[i].key->entry.data;
+ if(ref[i].id != ref[i].key->id ||
+ TTL_IS_EXPIRED(d->ttl, timenow)) {
/* failure! rollback our readlocks */
rrset_array_unlock(ref, i+1);
return 0;
*qnamelen, searchtype, qclass, 0, 0, 0))) {
struct packed_rrset_data* data =
(struct packed_rrset_data*)rrset->entry.data;
- if(now > data->ttl) {
+ if(TTL_IS_EXPIRED(data->ttl, now)) {
/* it is expired, this is not wanted */
lock_rw_unlock(&rrset->entry.lock);
log_nametypeclass(VERB_ALGO, "this rrset is expired", *qname, searchtype, qclass);
if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,
repinfo, temp, env->now_tv) || !reply_info_answer_encode(qinfo, &rep,
*(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
- buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0, 0)) {
+ buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
key = (struct msgreply_entry*)e->key;
data = (struct reply_info*)e->data;
- if(data->ttl < timenow) *is_expired = 1;
+ if(TTL_IS_EXPIRED(data->ttl, timenow)) *is_expired = 1;
msg = tomsg(qstate->env, &key->key, data, qstate->region, timenow,
qstate->env->cfg->serve_expired, qstate->env->scratch);
if(!msg)
!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
r->qflags, r->buf, 0, 1,
m->s.env->scratch, udp_size, &r->edns,
- (int)(r->edns.bits & EDNS_DO), secure, 0))
+ (int)(r->edns.bits & EDNS_DO), secure))
{
fptr_ok(fptr_whitelist_mesh_cb(r->cb));
(*r->cb)(r->cb_arg, LDNS_RCODE_SERVFAIL, r->buf,
!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
r->qflags, r_buffer, 0, 1, m->s.env->scratch,
udp_size, &r->edns, (int)(r->edns.bits & EDNS_DO),
- secure, 0))
+ secure))
{
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, &r->start_time))
repinfo, temp, env->now_tv) ||
!reply_info_answer_encode(qinfo, &rep,
*(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
- buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0, 0)) {
+ buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
*(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
/* encode */
unit_assert(
reply_info_answer_encode(qinfo, rep, 1, rep->flags, pkt,
- 0, 0, region, 65535, edns, 0, 0, 0));
+ 0, 0, region, 65535, edns, 0, 0));
/* buffer ready for reading; skip after the question section */
sldns_buffer_skip(pkt, LDNS_HEADER_SIZE);
(void)query_dname_len(pkt);
minimal-responses: no
serve-expired: yes
serve-expired-client-timeout: 0
+ serve-expired-reply-ttl: 123
module-config: "cachedb iterator"
+ ede: yes
+ ede-serve-expired: yes
cachedb:
backend: "testframe"
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.5
+; TTL lower than serve-expired-reply-ttl on purpose
+www2.example.com. 100 IN A 1.2.3.5
ENTRY_END
RANGE_END
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; Get another query in cache to make it expired.
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.5
+www2.example.com. 100 IN A 1.2.3.5
ENTRY_END
; it is now expired
-STEP 40 TIME_PASSES ELAPSE 20
+STEP 40 TIME_PASSES ELAPSE 200
; cache is expired, and cachedb is expired.
STEP 50 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www2.example.com. IN A
ENTRY_END
STEP 60 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 30 IN A 1.2.3.5
+www2.example.com. 100 IN A 1.2.3.5
ENTRY_END
; cache is expired, cachedb has no answer
STEP 70 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 80 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 30 IN A 1.2.3.4
+www.example.com. 123 IN A 1.2.3.4
ENTRY_END
STEP 90 TRAFFIC
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; flush the entry from cache
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; it is now expired
-STEP 150 TIME_PASSES ELAPSE 20
+STEP 150 TIME_PASSES ELAPSE 200
; flush the entry from cache
STEP 160 FLUSH_MESSAGE www.example.com. IN A
; cache has no answer, cachedb is expired
STEP 170 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 180 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 30 IN A 1.2.3.4
+www.example.com. 123 IN A 1.2.3.4
ENTRY_END
STEP 190 TRAFFIC
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; expire the entry in cache
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; it is now expired
-STEP 250 TIME_PASSES ELAPSE 20
+STEP 250 TIME_PASSES ELAPSE 200
; expire the entry in cache
STEP 260 EXPIRE_MESSAGE www.example.com. IN A
; cache is expired, cachedb is expired
STEP 270 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 280 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 30 IN A 1.2.3.4
+www.example.com. 123 IN A 1.2.3.4
ENTRY_END
STEP 290 TRAFFIC
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
SCENARIO_END
qname-minimisation: no
minimal-responses: no
serve-expired: yes
- serve-expired-reply-ttl: 30
+ serve-expired-reply-ttl: 123
; at least one second, so we can time skip past the timer in the
; testbound script steps, but also reply within the time.
serve-expired-client-timeout: 1200
module-config: "cachedb iterator"
discard-timeout: 3000
+ ede: yes
+ ede-serve-expired: yes
cachedb:
backend: "testframe"
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.5
+; TTL lower than serve-expired-reply-ttl on purpose
+www2.example.com. 100 IN A 1.2.3.5
ENTRY_END
RANGE_END
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.6
+www.example.com. 200 IN A 1.2.3.6
ENTRY_END
ENTRY_BEGIN
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.7
+; TTL lower than serve-expired-reply-ttl on purpose
+www2.example.com. 100 IN A 1.2.3.7
ENTRY_END
RANGE_END
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.8
+www.example.com. 200 IN A 1.2.3.8
ENTRY_END
ENTRY_BEGIN
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.9
+; TTL lower than serve-expired-reply-ttl on purpose
+www2.example.com. 100 IN A 1.2.3.9
ENTRY_END
RANGE_END
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.10
+www.example.com. 200 IN A 1.2.3.10
ENTRY_END
ENTRY_BEGIN
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.11
+www2.example.com. 100 IN A 1.2.3.11
ENTRY_END
RANGE_END
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; Get another query in cache.
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.5
+www2.example.com. 100 IN A 1.2.3.5
ENTRY_END
; www.example.com and www2.example.com are in cache, www2 in cachedb.
; response from cachedb for www2.
; make 2 seconds pass to decrement the TTL on the response,
-; the upstream TTL would be 10, cachedb 8.
+; the upstream TTL would be 200, cachedb 198.
STEP 48 TIME_PASSES ELAPSE 2
STEP 50 QUERY
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 8 IN A 1.2.3.5
+www2.example.com. 98 IN A 1.2.3.5
ENTRY_END
; make both cache and cachedb expired
-STEP 70 TIME_PASSES ELAPSE 20
+STEP 70 TIME_PASSES ELAPSE 200
; www and www2 expired in cache, www2 expired in cachedb.
; the query should now try to resolve and complete within the
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.7
+www2.example.com. 100 IN A 1.2.3.7
ENTRY_END
; expire the data again
-STEP 100 TIME_PASSES ELAPSE 20
+STEP 100 TIME_PASSES ELAPSE 200
; the query should now try to resolve, but the upstream is not
; responsive for several testbound steps. When the timer expires,
; www2 expired in cache and www2 expired in cachedb.
STEP 110 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www2.example.com. IN A
ENTRY_END
STEP 120 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 30 IN A 1.2.3.7
+www2.example.com. 100 IN A 1.2.3.7
ENTRY_END
; make traffic flow to resolve the query, server responds.
STEP 130 TRAFFIC
; expire the data again
-STEP 140 TIME_PASSES ELAPSE 20
+STEP 140 TIME_PASSES ELAPSE 200
; The client query tries to resolve, but gets no immediate answer,
; so the expired data is used. But the expired data is in cache and
; the query is not in cachedb.
STEP 150 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 160 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 30 IN A 1.2.3.4
+www.example.com. 123 IN A 1.2.3.4
ENTRY_END
; make traffic flow to resolve the query, server responds.
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.11
+www2.example.com. 100 IN A 1.2.3.11
ENTRY_END
SCENARIO_END
minimal-responses: no
serve-expired: yes
serve-expired-client-timeout: 0
- serve-expired-reply-ttl: 30
+ serve-expired-reply-ttl: 123
module-config: "cachedb iterator"
+ ede: yes
+ ede-serve-expired: yes
cachedb:
backend: "testframe"
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.5
+; TTL lower than serve-expired-reply-ttl on purpose
+www2.example.com. 100 IN A 1.2.3.5
ENTRY_END
RANGE_END
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; Get another query in cache to make it expired.
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.5
+www2.example.com. 100 IN A 1.2.3.5
ENTRY_END
; it is now expired
-STEP 40 TIME_PASSES ELAPSE 20
+STEP 40 TIME_PASSES ELAPSE 200
; cache is expired, and cachedb is expired.
STEP 50 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www2.example.com. IN A
ENTRY_END
STEP 60 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 30 IN A 1.2.3.5
+www2.example.com. 100 IN A 1.2.3.5
ENTRY_END
; got an answer from upstream
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.5
+www2.example.com. 100 IN A 1.2.3.5
ENTRY_END
; cache is expired, cachedb has no answer
STEP 70 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 80 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 30 IN A 1.2.3.4
+www.example.com. 123 IN A 1.2.3.4
ENTRY_END
STEP 90 TRAFFIC
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; make both cache and cachedb expired.
-STEP 120 TIME_PASSES ELAPSE 20
+STEP 120 TIME_PASSES ELAPSE 200
STEP 130 FLUSH_MESSAGE www.example.com. IN A
; cache has no entry and cachedb is expired.
STEP 140 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 150 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 30 IN A 1.2.3.4
+www.example.com. 123 IN A 1.2.3.4
ENTRY_END
; the name is resolved
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
SCENARIO_END
qname-minimisation: no
minimal-responses: no
serve-expired: yes
- serve-expired-reply-ttl: 30
+ serve-expired-reply-ttl: 123
; disable the serve expired client timeout.
serve-expired-client-timeout: 0
; store for edns subnet content for modules to the right of it.
; this keeps subnet content out of cachedb as global content.
module-config: "subnetcache cachedb iterator"
+ ede: yes
+ ede-serve-expired: yes
cachedb:
backend: "testframe"
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN CNAME www.initial.com.
+www.example.com. 200 IN CNAME www.initial.com.
ENTRY_END
RANGE_END
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN CNAME example.foo.com.
+www.example.com. 200 IN CNAME example.foo.com.
ENTRY_END
RANGE_END
SECTION QUESTION
www.initial.com. IN A
SECTION ANSWER
-www.initial.com. 10 IN A 1.2.3.4
+www.initial.com. 200 IN A 1.2.3.4
ENTRY_END
RANGE_END
SECTION QUESTION
example.foo.com. IN A
SECTION ANSWER
-example.foo.com. 10 IN A 1.2.3.5
+example.foo.com. 200 IN A 1.2.3.5
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
; client is 127.0.0.1
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN CNAME example.foo.com.
+www.example.com. 200 IN CNAME example.foo.com.
ENTRY_END
RANGE_END
SECTION QUESTION
example.foo.com. IN A
SECTION ANSWER
-example.foo.com. 10 IN A 1.2.3.6
+example.foo.com. 200 IN A 1.2.3.6
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
; client is 127.0.0.1
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN CNAME www.initial.com.
-www.initial.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN CNAME www.initial.com.
+www.initial.com. 200 IN A 1.2.3.4
ENTRY_END
; now valid in cache and valid in cachedb, without subnet.
-STEP 30 TIME_PASSES ELAPSE 20
+STEP 30 TIME_PASSES ELAPSE 200
; now the cache and cachedb have an expired entry.
; the upstream is updated to CNAME to a subnet zone A record.
STEP 40 QUERY ADDRESS 127.0.0.1
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
; the expired answer, while the ECS answer is looked up.
STEP 50 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 30 IN CNAME www.initial.com.
-www.initial.com. 30 IN A 1.2.3.4
+www.example.com. 123 IN CNAME www.initial.com.
+www.initial.com. 123 IN A 1.2.3.4
ENTRY_END
; check that subnet has the query in cache.
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 8 IN CNAME example.foo.com.
-example.foo.com. 8 IN A 1.2.3.5
+www.example.com. 198 IN CNAME example.foo.com.
+example.foo.com. 198 IN A 1.2.3.5
ENTRY_END
; everything is expired, cache, subnetcache and cachedb.
-STEP 80 TIME_PASSES ELAPSE 20
+STEP 80 TIME_PASSES ELAPSE 200
STEP 90 QUERY ADDRESS 127.0.0.1
ENTRY_BEGIN
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN CNAME example.foo.com.
-example.foo.com. 10 IN A 1.2.3.6
+www.example.com. 200 IN CNAME example.foo.com.
+example.foo.com. 200 IN A 1.2.3.6
ENTRY_END
; see the entry now in cache, from the subnetcache.
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 8 IN CNAME example.foo.com.
-example.foo.com. 8 IN A 1.2.3.6
+www.example.com. 198 IN CNAME example.foo.com.
+example.foo.com. 198 IN A 1.2.3.6
ENTRY_END
SCENARIO_END
minimal-responses: yes
serve-expired: yes
serve-expired-client-timeout: 0
+ serve-expired-reply-ttl: 123
;module-config: "subnetcache validator cachedb iterator"
module-config: "validator cachedb iterator"
+ ede: yes
+ ede-serve-expired: yes
cachedb:
backend: "testframe"
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.5
+; TTL lower than serve-expired-reply-ttl on purpose
+www2.example.com. 100 IN A 1.2.3.5
ENTRY_END
RANGE_END
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; Get another query in cache to make it expired.
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 10 IN A 1.2.3.5
+www2.example.com. 100 IN A 1.2.3.5
ENTRY_END
; it is now expired
-STEP 40 TIME_PASSES ELAPSE 20
+STEP 40 TIME_PASSES ELAPSE 200
; cache is expired, and cachedb is expired.
; The expired reply, from cachedb, needs a validation status,
; because the validator module set that validation is needed.
STEP 50 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www2.example.com. IN A
ENTRY_END
STEP 60 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www2.example.com. IN A
SECTION ANSWER
-www2.example.com. 30 IN A 1.2.3.5
+www2.example.com. 100 IN A 1.2.3.5
ENTRY_END
; cache is expired, cachedb has no answer
STEP 70 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 80 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 30 IN A 1.2.3.4
+www.example.com. 123 IN A 1.2.3.4
ENTRY_END
STEP 90 TRAFFIC
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; flush the entry from cache
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; it is now expired
-STEP 150 TIME_PASSES ELAPSE 20
+STEP 150 TIME_PASSES ELAPSE 200
; flush the entry from cache
STEP 160 FLUSH_MESSAGE www.example.com. IN A
; cache has no answer, cachedb is expired
STEP 170 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 180 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 30 IN A 1.2.3.4
+www.example.com. 123 IN A 1.2.3.4
ENTRY_END
STEP 190 TRAFFIC
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; expire the entry in cache
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
; it is now expired
-STEP 250 TIME_PASSES ELAPSE 20
+STEP 250 TIME_PASSES ELAPSE 200
; expire the entry in cache
STEP 260 EXPIRE_MESSAGE www.example.com. IN A
; cache is expired, cachedb is expired
STEP 270 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 280 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 30 IN A 1.2.3.4
+www.example.com. 123 IN A 1.2.3.4
ENTRY_END
STEP 290 TRAFFIC
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 1.2.3.4
+www.example.com. 200 IN A 1.2.3.4
ENTRY_END
SCENARIO_END
SECTION ANSWER
ENTRY_END
-; enough to pass by the TTL of the servfail answer in cache
+; enough to expire the servfail answer in cache
STEP 50 TIME_PASSES ELAPSE 5
-; this query triggers a prefetch
-STEP 210 QUERY
-ENTRY_BEGIN
-REPLY RD
-SECTION QUESTION
-www.example.com. IN A
-ENTRY_END
-
-STEP 220 CHECK_ANSWER
-ENTRY_BEGIN
-MATCH all
-REPLY QR RD RA SERVFAIL
-SECTION QUESTION
-www.example.com. IN A
-SECTION ANSWER
-ENTRY_END
+; Expired SERVFAILS are no longer served from Unbound
; this query gets the 0ttl answer
STEP 230 QUERY
STEP 240 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all
+MATCH all ttl
REPLY QR RD RA NOERROR
SECTION QUESTION
www.example.com. IN A
# We do not want only serve-expired because fetches from that
# apply a generous PREFETCH_LEEWAY.
serve-expired-client-timeout: 1000
+ serve-expired-reply-ttl: 123
# So that we can only have to give one SERVFAIL answer.
outbound-msg-retry: 0
+ ede: yes
+ ede-serve-expired: yes
forward-zone: name: "." forward-addr: 216.0.0.1
CONFIG_END
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
- www.example.com. 5 IN A 10.20.30.40
+ www.example.com. 205 IN A 10.20.30.40
SECTION AUTHORITY
- example.com. 10 IN NS ns.example.com.
+ example.com. 210 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 10.20.30.50
+ ns.example.com. 210 IN A 10.20.30.50
ENTRY_END
STEP 4 CHECK_ANSWER
ENTRY_BEGIN
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
- www.example.com. 5 IN A 10.20.30.40
+ www.example.com. 205 IN A 10.20.30.40
SECTION AUTHORITY
- example.com. 10 IN NS ns.example.com.
+ example.com. 210 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 10.20.30.50
+ ns.example.com. 210 IN A 10.20.30.50
ENTRY_END
; Wait for the A RRSET to expire.
-STEP 5 TIME_PASSES ELAPSE 6
+STEP 5 TIME_PASSES ELAPSE 205
STEP 6 QUERY
ENTRY_BEGIN
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
- www.example.com. 5 IN A 10.20.30.40
+ www.example.com. 205 IN A 10.20.30.40
SECTION AUTHORITY
- example.com. 10 IN NS ns.example.com.
+ example.com. 210 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 10.20.30.50
+ ns.example.com. 210 IN A 10.20.30.50
ENTRY_END
; The cached NS related RRSETs will not be overwritten by the fresh answer.
-; The message should have a TTL of 4 instead of 5 from above.
+; The message should have a TTL of 5 instead of 205 from above.
STEP 9 CHECK_ANSWER
ENTRY_BEGIN
MATCH all ttl
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
- www.example.com. 5 IN A 10.20.30.40
+ www.example.com. 205 IN A 10.20.30.40
SECTION AUTHORITY
- example.com. 4 IN NS ns.example.com.
+ example.com. 5 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 4 IN A 10.20.30.50
+ ns.example.com. 5 IN A 10.20.30.50
ENTRY_END
; Wait for the NS RRSETs to expire.
STEP 11 QUERY
ENTRY_BEGIN
- REPLY RD
+ REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
ENTRY_END
; The SERVFAIL will trigger the serve-expired-client-timeout logic to try and
; replace the SERVFAIL with a possible cached (expired) answer.
-; The A RRSET would be at 0TTL left (not expired) but the message should have
-; been updated to use a TTL of 4 so expired by now.
+; The A RRSET would be at 200 left but the message should have
+; been updated to use a TTL of 5 so expired by now.
; If the message TTL was not updated (bug), this message would be treated as
; non-expired and the now expired NS related RRSETs would fail sanity checks
; for non-expired messages. The result would be SERVFAIL here.
STEP 14 CHECK_ANSWER
ENTRY_BEGIN
- MATCH all ttl
- REPLY QR RD RA
+ MATCH all ttl ede=3
+ REPLY QR RD RA DO
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
- www.example.com. 0 IN A 10.20.30.40
+ www.example.com. 200 IN A 10.20.30.40
SECTION AUTHORITY
- example.com. 30 IN NS ns.example.com.
+ example.com. 123 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 30 IN A 10.20.30.50
+ ns.example.com. 123 IN A 10.20.30.50
ENTRY_END
SCENARIO_END
minimal-responses: no
serve-expired: yes
serve-expired-client-timeout: 0
+ serve-expired-reply-ttl: 123
access-control: 127.0.0.1/32 allow_snoop
ede: yes
ede-serve-expired: yes
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 IN A 5.6.7.8
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 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
+; Wait for the TTL to expire (for all RRSets; default 3600)
+STEP 11 TIME_PASSES ELAPSE 3600
; Query again without RD bit
STEP 30 QUERY
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 30 IN A 5.6.7.8
+ example.com. 123 IN A 5.6.7.8
SECTION AUTHORITY
- example.com. 30 IN NS ns.example.com.
+ example.com. 123 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 30 IN A 1.2.3.4
+ ns.example.com. 123 IN A 1.2.3.4
ENTRY_END
; Query with RD bit (the record should have been prefetched)
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 IN A 5.6.7.8
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
minimal-responses: no
serve-expired: yes
serve-expired-client-timeout: 0
+ serve-expired-reply-ttl: 123
ede: yes
ede-serve-expired: yes
SECTION QUESTION
example.com. IN NS
SECTION ANSWER
- example.com. 10 IN NS ns.example.com.
+ example.com. 200 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 1.2.3.4
+ ns.example.com. 200 IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
SECTION ANSWER
0ttl.example.com. 0 IN A 5.6.7.8
SECTION AUTHORITY
- example.com. 10 IN NS ns.example.com.
+ example.com. 200 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 1.2.3.4
+ ns.example.com. 200 IN A 1.2.3.4
ENTRY_END
RANGE_END
example.com IN SOA ns.example.com dns.example.com 1 7200 3600 2419200 10
ENTRY_END
-; Wait for the NXDOMAIN to expire
-STEP 31 TIME_PASSES ELAPSE 32
+; Wait for the NODATA to expire
+STEP 31 TIME_PASSES ELAPSE 10
; Query again
STEP 40 QUERY
ENTRY_BEGIN
- REPLY RD
+ REPLY RD DO
SECTION QUESTION
0ttl.example.com. IN A
ENTRY_END
; Check that we get the cached NODATA
STEP 50 CHECK_ANSWER
ENTRY_BEGIN
- MATCH all
- REPLY QR RD RA NOERROR
+ MATCH all ede=3
+ REPLY QR RD RA DO NOERROR
SECTION QUESTION
0ttl.example.com. IN A
SECTION AUTHORITY
SECTION ANSWER
0ttl.example.com. 0 IN A 5.6.7.8
SECTION AUTHORITY
- example.com. 10 IN NS ns.example.com.
+ example.com. 200 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 1.2.3.4
+ ns.example.com. 200 IN A 1.2.3.4
ENTRY_END
SCENARIO_END
ENTRY_END
; Wait for the NXDOMAIN to expire
-STEP 31 TIME_PASSES ELAPSE 32
+STEP 31 TIME_PASSES ELAPSE 10
; Query again
STEP 40 QUERY
0ttl.example.com. IN A
ENTRY_END
-; Check that we get the cached NXDOMAIN
+; Check that we get the newly cached NXDOMAIN
STEP 50 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
ENTRY_END
; Wait for the SERVFAIL to expire
-STEP 31 TIME_PASSES ELAPSE 32
+STEP 31 TIME_PASSES ELAPSE 10
; Query again
STEP 40 QUERY
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 IN A 5.6.7.8
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 IN A 5.6.7.8
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
+++ /dev/null
-; 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
- ede: yes
- ede-serve-expired: yes
-
-stub-zone:
- name: "example.com"
- stub-addr: 1.2.3.4
-CONFIG_END
-
-SCENARIO_BEGIN Test that no prefetch is triggered for 0TTL records with serve-expired and client-timeout enabled
-; 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 at the 0TTL cached entry
-; - check that we get the cached answer with no prefetching triggered
-
-; 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 10
- 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 0 QUERY
-ENTRY_BEGIN
- REPLY RD
- SECTION QUESTION
- example.com. IN A
-ENTRY_END
-
-; Check that we got the correct answer (should be cached)
-STEP 1 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 and produce a 0 TTL cached record.
-STEP 10 TIME_PASSES ELAPSE 10
-
-; Query again
-STEP 20 QUERY
-ENTRY_BEGIN
- REPLY RD DO
- SECTION QUESTION
- example.com. IN A
-ENTRY_END
-
-; This should come from the cache with no prefetch triggered (earlier bug).
-STEP 21 CHECK_ANSWER
-ENTRY_BEGIN
- MATCH all ttl
- REPLY QR RD RA DO NOERROR
- SECTION QUESTION
- example.com. IN A
- SECTION ANSWER
- example.com. 1 IN A 5.6.7.8
- SECTION AUTHORITY
- example.com. 3591 IN NS ns.example.com.
- SECTION ADDITIONAL
- ns.example.com. 3591 IN A 1.2.3.4
-ENTRY_END
-
-; If a prefetch triggers the test will fail with 'messages pending'.
-
-SCENARIO_END
SECTION QUESTION
example.com. IN NS
SECTION ANSWER
- example.com. 10 IN NS ns.example.com.
+ example.com. 200 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 1.2.3.4
+ ns.example.com. 200 IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 IN A 5.6.7.8
SECTION AUTHORITY
- example.com. 10 IN NS ns.example.com.
+ example.com. 200 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 1.2.3.4
+ ns.example.com. 200 IN A 1.2.3.4
ENTRY_END
RANGE_END
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 IN A 5.6.7.8
SECTION AUTHORITY
- example.com. 10 IN NS ns.example.com.
+ example.com. 200 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 1.2.3.4
+ ns.example.com. 200 IN A 1.2.3.4
ENTRY_END
RANGE_END
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 IN A 5.6.7.8
SECTION AUTHORITY
- example.com. 10 IN NS ns.example.com.
+ example.com. 200 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 1.2.3.4
+ ns.example.com. 200 IN A 1.2.3.4
ENTRY_END
; Wait for the TTL to expire
-STEP 11 TIME_PASSES ELAPSE 11
+STEP 11 TIME_PASSES ELAPSE 200
; Query again
STEP 30 QUERY
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 IN A 5.6.7.8
SECTION AUTHORITY
- example.com. 10 IN NS ns.example.com.
+ example.com. 200 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 1.2.3.4
+ ns.example.com. 200 IN A 1.2.3.4
ENTRY_END
SCENARIO_END
; Scenario overview:
; - query for example.com. IN A
; - check that we get an answer for example.com. IN A with the correct TTL
+; - query for shorterttl.example.com. IN A
+; - check that we get an answer for shorterttl.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
+; - check that we get the expired cached answer for example.com. with the configured TTL
+; - check that we get the expired cached answer for shorterttl.example.com. with its own original TTL since it is shorter than the configured one
; ns.example.com.
RANGE_BEGIN 0 100
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 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
+
+ ENTRY_BEGIN
+ MATCH opcode qtype qname
+ ADJUST copy_id
+ REPLY QR NOERROR
+ SECTION QUESTION
+ shorterttl.example.com. IN A
+ SECTION ANSWER
+ shorterttl.example.com. 121 IN A 5.6.7.8
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 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
+
+STEP 11 QUERY
+ENTRY_BEGIN
+ REPLY RD
+ SECTION QUESTION
+ shorterttl.example.com. IN A
+ENTRY_END
+
+
+STEP 12 CHECK_ANSWER
+ENTRY_BEGIN
+ MATCH all ttl
+ REPLY QR RD RA NOERROR
+ SECTION QUESTION
+ shorterttl.example.com. IN A
+ SECTION ANSWER
+ shorterttl.example.com. 121 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
+; Wait for the TTL to expire (for all rrsets; default 3600)
+STEP 20 TIME_PASSES ELAPSE 3600
; Query again
STEP 30 QUERY
ns.example.com. 123 A 1.2.3.4
ENTRY_END
+; Query again for shorter ttl
+STEP 50 QUERY
+ENTRY_BEGIN
+ REPLY RD DO
+ SECTION QUESTION
+ shorterttl.example.com. IN A
+ENTRY_END
+
+; Check that we got a stale answer
+; Note: auth, additional rrsets are already updated from previous recursion.
+STEP 60 CHECK_ANSWER
+ENTRY_BEGIN
+ MATCH all ttl ede=3
+ REPLY QR RD RA DO NOERROR
+ SECTION QUESTION
+ shorterttl.example.com. IN A
+ SECTION ANSWER
+ shorterttl.example.com. 121 A 5.6.7.8
+ SECTION AUTHORITY
+ example.com. 3600 NS ns.example.com.
+ SECTION ADDITIONAL
+ ns.example.com. 3600 A 1.2.3.4
+ENTRY_END
+
; Give time for the pending query to get answered
-STEP 41 TRAFFIC
+STEP 61 TRAFFIC
SCENARIO_END
ENTRY_END
; Wait for the TTL to expire + serve-expired-ttl
-STEP 11 TIME_PASSES ELAPSE 3611
+STEP 11 TIME_PASSES ELAPSE 3610
; Query again
STEP 30 QUERY
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 0.0.0.0
+www.example.com. 200 IN A 0.0.0.0
ENTRY_END
STEP 3 CHECK_ANSWER
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 10 IN A 0.0.0.0
+www.example.com. 200 IN A 0.0.0.0
ENTRY_END
; Expire the record (+ serve-expired-ttl)
-STEP 4 TIME_PASSES ELAPSE 12
+STEP 4 TIME_PASSES ELAPSE 201
STEP 5 QUERY
ENTRY_BEGIN
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 IN A 5.6.7.8
SECTION AUTHORITY
- example.com. 10 IN NS ns.example.com.
+ example.com. 200 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 1.2.3.4
+ ns.example.com. 200 IN A 1.2.3.4
ENTRY_END
RANGE_END
SECTION QUESTION
example.com. IN A
SECTION ANSWER
- example.com. 10 IN A 5.6.7.8
+ example.com. 200 IN A 5.6.7.8
SECTION AUTHORITY
- example.com. 10 IN NS ns.example.com.
+ example.com. 200 IN NS ns.example.com.
SECTION ADDITIONAL
- ns.example.com. 10 IN A 1.2.3.4
+ ns.example.com. 200 IN A 1.2.3.4
ENTRY_END
; Wait for the TTL to expire
-STEP 30 TIME_PASSES ELAPSE 11
+STEP 30 TIME_PASSES ELAPSE 200
; Query with RD flag
STEP 40 QUERY
target-fetch-policy: "0 0 0 0 0"
serve-expired: yes
serve-expired-client-timeout: 0
+ serve-expired-reply-ttl: 123
client-subnet-always-forward: yes
module-config: "subnetcache iterator"
verbosity: 3
access-control: 127.0.0.1 allow_snoop
qname-minimisation: no
minimal-responses: no
+ ede: yes
+ ede-serve-expired: yes
stub-zone:
name: "."
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
- www.example.com. 10 IN A 10.20.30.40
+ www.example.com. 200 IN A 10.20.30.40
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ENTRY_END
; Wait for the TTL to expire
-STEP 3 TIME_PASSES ELAPSE 20
+STEP 3 TIME_PASSES ELAPSE 200
STEP 11 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
; This record came from the global cache and a prefetch was triggered
STEP 12 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 30 IN A 10.20.30.40
+www.example.com. 123 IN A 10.20.30.40
SECTION AUTHORITY
-example.com. 3580 IN NS ns.example.com.
+example.com. 3400 IN NS ns.example.com.
SECTION ADDITIONAL
-ns.example.com. 3580 IN A 1.2.3.4
+ns.example.com. 3400 IN A 1.2.3.4
ENTRY_END
STEP 13 CHECK_OUT_QUERY
serve-expired: yes
serve-expired-client-timeout: 0
serve-expired-ttl: 1
- prefetch: yes
+ serve-expired-client-timeout: 0
+ serve-expired-reply-ttl: 123
+ #prefetch: yes #not needed, expired answers also trigger refetch
+ ede: yes
+ ede-serve-expired: yes
stub-zone:
name: "."
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
- www.example.com. 10 IN A 10.20.30.40
+ www.example.com. 200 IN A 10.20.30.40
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
- www.example.com. 10 IN A 10.20.30.40
+ www.example.com. 200 IN A 10.20.30.40
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. IN A 10.20.30.40
+www.example.com. 200 IN A 10.20.30.40
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
ENTRY_END
; Try to trigger a prefetch with expired data
-STEP 3 TIME_PASSES ELAPSE 11
+STEP 3 TIME_PASSES ELAPSE 200
STEP 11 QUERY
ENTRY_BEGIN
-REPLY RD
+REPLY RD DO
SECTION QUESTION
www.example.com. IN A
ENTRY_END
; This expired record came from the global cache and a prefetch is triggered.
STEP 12 CHECK_ANSWER
ENTRY_BEGIN
-MATCH all ttl
-REPLY QR RD RA NOERROR
+MATCH all ttl ede=3
+REPLY QR RD RA DO NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 30 IN A 10.20.30.40
+www.example.com. 123 IN A 10.20.30.40
SECTION AUTHORITY
-example.com. 3589 IN NS ns.example.com.
+example.com. 3400 IN NS ns.example.com.
SECTION ADDITIONAL
-ns.example.com. 3589 IN A 1.2.3.4
+ns.example.com. 3400 IN A 1.2.3.4
ENTRY_END
-;STEP 13 TRAFFIC
; Allow enough time to pass so that the expired record from the global cache
; cannot be used anymore.
STEP 14 TIME_PASSES ELAPSE 1
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
-www.example.com. 9 IN A 10.20.30.40
+www.example.com. 199 IN A 10.20.30.40
SECTION AUTHORITY
example.com. 3599 IN NS ns.example.com.
SECTION ADDITIONAL
STEP 140 CHECK_ANSWER
ENTRY_BEGIN
MATCH all ttl
-REPLY QR RD RA NOERROR
-SECTION QUESTION
-www.example.com. IN A
-SECTION ANSWER
-; note that it did not send 0 TTL. The message can be cached by the receiver
-; during the last second of the TTL.
-www.example.com. 1 IN A 1.2.3.4
-ENTRY_END
-
-STEP 150 TIME_PASSES ELAPSE 1
-
-STEP 160 QUERY
-ENTRY_BEGIN
-REPLY RD
-SECTION QUESTION
-www.example.com. IN A
-ENTRY_END
-
-STEP 170 CHECK_ANSWER
-ENTRY_BEGIN
-MATCH all ttl
REPLY QR RD RA SERVFAIL
SECTION QUESTION
www.example.com. IN A
return r;
sldns_buffer_write(pkt, &key->rk.type, 2);
sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
- if(data->rr_ttl[j] < adjust)
+ if(key->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) {
+ sldns_buffer_write_u32(pkt, 0);
+ } else if(adjust == 0) {
+ sldns_buffer_write_u32(pkt, data->rr_ttl[i]);
+ } else if(TTL_IS_EXPIRED(data->rr_ttl[j], adjust)) {
sldns_buffer_write_u32(pkt,
- SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0);
- else sldns_buffer_write_u32(pkt, data->rr_ttl[j]-adjust);
+ EXPIRED_REPLY_TTL_CALC(
+ data->rr_ttl[i], data->ttl_add));
+ } else {
+ sldns_buffer_write_u32(pkt,
+ data->rr_ttl[i] - adjust);
+ }
if(c) {
if((r=compress_rdata(pkt, data->rr_data[j],
data->rr_len[j], region, tree, c,
}
sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG);
sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
- if(data->rr_ttl[i] < adjust)
+ if(key->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) {
+ sldns_buffer_write_u32(pkt, 0);
+ } else if(adjust == 0) {
+ sldns_buffer_write_u32(pkt, data->rr_ttl[i]);
+ } else if(TTL_IS_EXPIRED(data->rr_ttl[i], adjust)) {
+ sldns_buffer_write_u32(pkt,
+ EXPIRED_REPLY_TTL_CALC(
+ data->rr_ttl[i], data->ttl_add));
+ } else {
sldns_buffer_write_u32(pkt,
- SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0);
- else sldns_buffer_write_u32(pkt, data->rr_ttl[i]-adjust);
+ data->rr_ttl[i] - adjust);
+ }
/* rrsig rdata cannot be compressed, perform 100+ byte
* memcopy. */
sldns_buffer_write(pkt, data->rr_data[i],
attach_edns_record_max_msg_sz(pkt, edns, edns->udp_size);
}
-int
-reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
+int
+reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
uint16_t id, uint16_t qflags, sldns_buffer* pkt, time_t timenow,
- int cached, struct regional* region, uint16_t udpsize,
- struct edns_data* edns, int dnssec, int secure, int cached_ttl)
+ int cached, struct regional* region, uint16_t udpsize,
+ struct edns_data* edns, int dnssec, int secure)
{
uint16_t flags;
unsigned int attach_edns = 0;
flags &= ~BIT_AD;
}
log_assert((flags & BIT_QR)); /* QR bit must be on in our replies */
- if(cached_ttl && rep->ttl - timenow == 0) {
- /* The last remaining second of the TTL for a cached response
- * is replied. This makes a 0 in the protocol message. The
- * response is valid for the cache, but the DNS TTL 0 item
- * causes the received to drop the contents. Even though the
- * contents are cachable, so the time used is decremented
- * to change that into 1 second, and it can be cached, and
- * used for expired response generation, and does not give
- * repeated queries during that last second. */
- timenow --;
- }
if(udpsize < LDNS_HEADER_SIZE)
return 0;
/* currently edns does not change during calculations;
* or if edns_present = 0, it is not included.
* @param dnssec: if 0 DNSSEC records are omitted from the answer.
* @param secure: if 1, the AD bit is set in the reply.
- * @param cached_ttl: the ttl is from a cache response. So that means it
- * was some value minus the current time, and not an authoritative
- * response with an autoritative TTL or a direct upstream response,
- * that could have upstream TTL 0 items.
* @return: 0 on error (server failure).
*/
-int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
+int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
uint16_t id, uint16_t qflags, struct sldns_buffer* dest, time_t timenow,
- int cached, struct regional* region, uint16_t udpsize,
- struct edns_data* edns, int dnssec, int secure, int cached_ttl);
+ int cached, struct regional* region, uint16_t udpsize,
+ struct edns_data* edns, int dnssec, int secure);
/**
* Regenerate the wireformat from the stored msg reply.
* the rr->next works fine to continue. */
return rrset->rr_count == 0;
}
+
+#ifdef UNBOUND_DEBUG
+time_t debug_expired_reply_ttl_calc(time_t ttl, time_t ttl_add) {
+ /* Check that we are serving expired when this is called */
+ /* ttl (absolute) should be later than ttl_add */
+ log_assert(SERVE_EXPIRED && ttl_add <= ttl);
+ return (SERVE_EXPIRED_REPLY_TTL < (ttl) - (ttl_add) ?
+ SERVE_EXPIRED_REPLY_TTL : (ttl) - (ttl_add));
+}
+#endif
/** If we serve the original TTL or decrementing TTLs */
extern int SERVE_ORIGINAL_TTL;
+/** calculate the prefetch TTL as 90% of original. Calculation
+ * without numerical overflow (uin32_t) */
+#define PREFETCH_TTL_CALC(ttl) ((ttl) - (ttl)/10)
+
+/* caclulate the TTL used for expired answers to somewhat make sense wrt the
+ * original TTL; don't reply with higher TTL than the original */
+#ifdef UNBOUND_DEBUG
+time_t debug_expired_reply_ttl_calc(time_t ttl, time_t ttl_add);
+#define EXPIRED_REPLY_TTL_CALC(ttl, ttl_add) \
+ debug_expired_reply_ttl_calc(ttl, ttl_add)
+#else
+#define EXPIRED_REPLY_TTL_CALC(ttl, ttl_add) \
+ (SERVE_EXPIRED_REPLY_TTL < (ttl) - (ttl_add) ? \
+ SERVE_EXPIRED_REPLY_TTL : (ttl) - (ttl_add))
+#endif
+
+/** Update the reply_info TTL from an RRSet's TTL, essentially keeping the TTL
+ * sane with all the (progressively added) rrsets to the message */
+#define UPDATE_TTL_FROM_RRSET(ttl, rrsetttl) \
+ ((ttl) = ((ttl) < (rrsetttl)) ? (ttl) : (rrsetttl))
+
+/** Check if TTL is expired. 0 TTL is considered expired.
+ * Used mainly to identify parts of the code that do this comparison. */
+#define TTL_IS_EXPIRED(ttl, now) ((ttl) <= (now))
+
/**
* Data stored in scratch pad memory during parsing.
* Stores the data that will enter into the msgreply and packet result.
int
reply_info_can_answer_expired(struct reply_info* rep, time_t timenow)
{
- log_assert(rep->ttl < timenow);
+ log_assert(TTL_IS_EXPIRED(rep->ttl, timenow));
/* Really expired */
- if(SERVE_EXPIRED_TTL && rep->serve_expired_ttl < timenow) return 0;
+ if(SERVE_EXPIRED_TTL && TTL_IS_EXPIRED(rep->serve_expired_ttl, timenow)) return 0;
/* Ignore expired failure answers */
if(FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR &&
FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NXDOMAIN &&
return 1;
}
-int reply_info_could_use_expired(struct reply_info* rep, time_t timenow)
+int
+reply_info_could_use_expired(struct reply_info* rep, time_t timenow)
{
- log_assert(rep->ttl < timenow);
+ log_assert(TTL_IS_EXPIRED(rep->ttl, timenow));
/* Really expired */
- if(SERVE_EXPIRED_TTL && rep->serve_expired_ttl < timenow &&
- !SERVE_EXPIRED_TTL_RESET) return 0;
+ if(SERVE_EXPIRED_TTL && TTL_IS_EXPIRED(rep->serve_expired_ttl, timenow)
+ && !SERVE_EXPIRED_TTL_RESET) return 0;
/* Ignore expired failure answers */
if(FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR &&
FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NXDOMAIN &&
}
/** find the minimumttl in the rdata of SOA record */
-static time_t
+static uint32_t
soa_find_minttl(struct rr_parse* rr)
{
uint16_t rlen = sldns_read_uint16(rr->ttl_data+4);
return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */
/* minimum TTL is the last 32bit value in the rdata of the record */
/* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/
- return (time_t)sldns_read_uint32(rr->ttl_data+6+rlen-4);
+ return sldns_read_uint32(rr->ttl_data+6+rlen-4);
}
/** do the rdata copy */
sldns_pkt_section section)
{
uint16_t pkt_len;
+ uint32_t ttl;
const sldns_rr_descriptor* desc;
- *rr_ttl = sldns_read_uint32(rr->ttl_data);
+ ttl = sldns_read_uint32(rr->ttl_data);
/* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */
- if((*rr_ttl & 0x80000000U))
- *rr_ttl = 0;
+ /* RFC 8767 Section 4. values with high-order bit as positive, not 0.
++ * As such, it will be capped by MAX_TTL below. */
if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) {
/* negative response. see if TTL of SOA record larger than the
* minimum-ttl in the rdata of the SOA record */
- if(*rr_ttl > soa_find_minttl(rr)) *rr_ttl = soa_find_minttl(rr);
+ if(ttl > soa_find_minttl(rr)) ttl = soa_find_minttl(rr);
if(!SERVE_ORIGINAL_TTL) {
/* If MIN_NEG_TTL is configured skip setting MIN_TTL */
- if(MIN_NEG_TTL <= 0 && *rr_ttl < MIN_TTL) {
- *rr_ttl = MIN_TTL;
+ if(MIN_NEG_TTL <= 0 && ttl < MIN_TTL) {
+ ttl = MIN_TTL;
}
- if(*rr_ttl > MAX_TTL) *rr_ttl = MAX_TTL;
+ if(ttl > MAX_TTL) ttl = MAX_TTL;
}
/* MAX_NEG_TTL overrides the min and max ttl of everything
* else; it is for a more specific record */
- if(*rr_ttl > MAX_NEG_TTL) *rr_ttl = MAX_NEG_TTL;
+ if(ttl > MAX_NEG_TTL) ttl = MAX_NEG_TTL;
/* MIN_NEG_TTL overrides the min and max ttl of everything
* else if configured; it is for a more specific record */
- if(MIN_NEG_TTL > 0 && *rr_ttl < MIN_NEG_TTL) {
- *rr_ttl = MIN_NEG_TTL;
+ if(MIN_NEG_TTL > 0 && ttl < MIN_NEG_TTL) {
+ ttl = MIN_NEG_TTL;
}
} else if(!SERVE_ORIGINAL_TTL) {
- if(*rr_ttl < MIN_TTL) *rr_ttl = MIN_TTL;
- if(*rr_ttl > MAX_TTL) *rr_ttl = MAX_TTL;
+ if(ttl < MIN_TTL) ttl = MIN_TTL;
+ if(ttl > MAX_TTL) ttl = MAX_TTL;
}
- if(*rr_ttl < data->ttl)
- data->ttl = *rr_ttl;
+ if(ttl < data->ttl)
+ data->ttl = ttl;
+ /* We have concluded the TTL checks */
+ *rr_ttl = (time_t)ttl;
if(rr->outside_packet) {
/* uncompressed already, only needs copy */
pk->entry.key = (void*)pk;
pk->entry.hash = pset->hash;
data->trust = get_rrset_trust(msg, pset);
+ pk->rk.flags |= (data->ttl == 0) ? PACKED_RRSET_UPSTREAM_0TTL : 0;
return 1;
}
}
}
+void
+reply_info_absolute_ttls(struct reply_info* rep, time_t ttl, time_t ttl_add)
+{
+ size_t i, j;
+ rep->ttl = ttl;
+ rep->prefetch_ttl = PREFETCH_TTL_CALC(ttl);
+ rep->serve_expired_ttl = ttl + SERVE_EXPIRED_TTL;
+ /* Don't set rep->serve_expired_norec_ttl; this should only be set
+ * on cached records when encountering an error */
+ log_assert(rep->serve_expired_norec_ttl == 0);
+ for(i=0; i<rep->rrset_count; i++) {
+ struct packed_rrset_data* data = (struct packed_rrset_data*)
+ rep->ref[i].key->entry.data;
+ if(i>0 && rep->ref[i].key == rep->ref[i-1].key)
+ continue;
+ data->ttl = ttl;
+ for(j=0; j<data->count + data->rrsig_count; j++) {
+ data->rr_ttl[j] = ttl;
+ }
+ data->ttl_add = ttl_add;
+ }
+}
+
void
reply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc)
{
struct dns_msg;
enum comm_point_type;
-/** calculate the prefetch TTL as 90% of original. Calculation
- * without numerical overflow (uin32_t) */
-#define PREFETCH_TTL_CALC(ttl) ((ttl) - (ttl)/10)
-
/**
* Structure to store query information that makes answers to queries
* different.
*/
void reply_info_set_ttls(struct reply_info* rep, time_t timenow);
+/**
+ * Set TTLs inside the replyinfo to the given absolute values.
+ * @param rep: reply info. rrsets must be filled in.
+ * Also refs must be filled in.
+ * @param ttl: absolute ttl value to be set.
+ * @param ttl_add: the current time to be used verbatim for ttl_add in the rrsets.
+ */
+void reply_info_absolute_ttls(struct reply_info* rep, time_t ttl, time_t ttl_add);
+
/**
* Delete reply_info and packed_rrsets (while they are not yet added to the
* hashtables.). Returns rrsets to the alloc cache.
struct ub_packed_rrset_key* ck = regional_alloc(region,
sizeof(struct ub_packed_rrset_key));
struct packed_rrset_data* d;
- struct packed_rrset_data* data = (struct packed_rrset_data*)
- key->entry.data;
+ struct packed_rrset_data* data = key->entry.data;
size_t dsize, i;
- time_t adjust = 0;
+ time_t now_control;
if(!ck)
return NULL;
ck->id = key->id;
if(!ck->rk.dname)
return NULL;
dsize = packed_rrset_sizeof(data);
- d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize);
+ d = regional_alloc_init(region, data, dsize);
if(!d)
return NULL;
ck->entry.data = d;
packed_rrset_ptr_fixup(d);
- /* make TTLs relative - once per rrset */
- adjust = SERVE_ORIGINAL_TTL ? data->ttl_add : now;
- for(i=0; i<d->count + d->rrsig_count; i++) {
- if(d->rr_ttl[i] < adjust)
- d->rr_ttl[i] = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
- else d->rr_ttl[i] -= adjust;
+ /* make TTLs relative - once per rr */
+ if(now > 0) {
+ /* NS RRSets may be here with ttl_add higher than now because
+ * of the novel ghost attack mitigation i.e., using the
+ * qstarttime for NS RRSets. In that case make sure that the
+ * returned TTL is not higher than the original one. */
+ log_assert(d->ttl_add <= now ||
+ (ntohs(key->rk.type) == LDNS_RR_TYPE_NS));
+ now_control = SERVE_ORIGINAL_TTL ? data->ttl_add
+ : (d->ttl_add > now ? d->ttl_add : now );
+ for(i=0; i<d->count + d->rrsig_count; i++) {
+ if(TTL_IS_EXPIRED(d->rr_ttl[i], now_control)) {
+ d->rr_ttl[i] = EXPIRED_REPLY_TTL_CALC(d->rr_ttl[i], data->ttl_add);
+ } else d->rr_ttl[i] -= now_control;
+ }
+ if(TTL_IS_EXPIRED(d->ttl, now_control)) {
+ d->ttl = EXPIRED_REPLY_TTL_CALC(d->ttl, data->ttl_add);
+ } else d->ttl -= now_control;
+ d->ttl_add = 0; /* TTLs have been made relative */
}
- if(d->ttl < adjust)
- d->ttl = SERVE_EXPIRED?SERVE_EXPIRED_REPLY_TTL:0;
- else d->ttl -= adjust;
- d->ttl_add = 0; /* TTLs have been made relative */
return ck;
}
#define PACKED_RRSET_RPZ 0x8
/** this rrset is A/AAAA and is an unverified glue record */
#define PACKED_RRSET_UNVERIFIED_GLUE 0x10
+/** this rrset has a 0TTL from upstream */
+#define PACKED_RRSET_UPSTREAM_0TTL 0x20
/** number of rrs and rrsets for integer overflow protection. More than
* this is not really possible (64K packet has much less RRs and RRsets) in
* o PACKED_RRSET_FIXEDTTL (not supposed to be cached)
* o PACKED_RRSET_RPZ
* o PACKED_RRSET_UNVERIFIED_GLUE
+ * o PACKED_RRSET_UPSTREAM_0TTL (not supposed to be cached)
*/
uint32_t flags;
/** the rrset type in network format */
qname, qname_len, qtype, qclass, flags, now, 0);
struct packed_rrset_data* d;
if(!k) return NULL;
- d = (struct packed_rrset_data*)k->entry.data;
- if(d->ttl < now) {
- lock_rw_unlock(&k->entry.lock);
- return NULL;
- }
+ d = k->entry.data;
/* only secure or unchecked records that have signatures. */
if( ! ( d->security == sec_status_secure ||
(d->security == sec_status_unchecked &&
/* DS rrset exists. Return it to the validator immediately*/
struct ub_packed_rrset_key* copy = packed_rrset_copy_region(
rrset, region, *env->now);
+ struct packed_rrset_data* d = copy->entry.data;
lock_rw_unlock(&rrset->entry.lock);
if(!copy)
return NULL;
msg->rep->rrsets[0] = copy;
msg->rep->rrset_count++;
msg->rep->an_numrrsets++;
+ UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
return msg;
}
/* lookup in rrset and negative cache for NSEC/NSEC3 */