From 73e408f1d0792267429e9f5f89537cda61297952 Mon Sep 17 00:00:00 2001 From: Yorgos Thessalonikefs Date: Mon, 15 Sep 2025 10:03:35 +0200 Subject: [PATCH] A few changes for TTL processing: - Cached messages that reach 0 TTL are considered expired. This prevents Unbound itself from issuing replies with TTL 0 and possibly causing a thundering herd at the last second. Upstream replies of TTL 0 still get the usual pass-through but they are not considered for caching from Unbound or any of its caching modules. - 'serve-expired-reply-ttl' is changed and is now capped by the original TTL value of the record to try and make some sense when replying with expired records. - TTL decoding was updated to adhere to RFC8767 section 4 where a set high-order bit means the value is positive instead of 0. --- cachedb/cachedb.c | 95 ++++++++------- daemon/worker.c | 14 +-- doc/example.conf.in | 1 + doc/unbound.conf.rst | 6 + services/authzone.c | 12 +- services/cache/dns.c | 86 +++++++++----- services/cache/dns.h | 2 +- services/cache/rrset.c | 19 +-- services/localzone.c | 2 +- services/mesh.c | 6 +- services/rpz.c | 2 +- testcode/unitmain.c | 2 +- testdata/cachedb_expired.crpl | 60 +++++----- testdata/cachedb_expired_client_timeout.crpl | 57 ++++----- testdata/cachedb_expired_reply_ttl.crpl | 47 ++++---- testdata/cachedb_subnet_change.crpl | 46 ++++---- testdata/cachedb_val_expired.crpl | 60 +++++----- testdata/fwd_0ttlservfail.rpl | 21 +--- testdata/rrset_use_cached.rpl | 47 ++++---- testdata/serve_expired.rpl | 17 +-- testdata/serve_expired_0ttl_nodata.rpl | 23 ++-- testdata/serve_expired_0ttl_nxdomain.rpl | 4 +- testdata/serve_expired_0ttl_servfail.rpl | 2 +- testdata/serve_expired_client_timeout.rpl | 4 +- ...rve_expired_client_timeout_no_prefetch.rpl | 110 ------------------ .../serve_expired_client_timeout_servfail.rpl | 30 ++--- testdata/serve_expired_reply_ttl.rpl | 75 +++++++++++- testdata/serve_expired_ttl_client_timeout.rpl | 2 +- testdata/serve_expired_ttl_reset.rpl | 6 +- testdata/serve_expired_zerottl.rpl | 14 +-- ...subnet_global_prefetch_always_forward.crpl | 19 +-- testdata/subnet_global_prefetch_expired.crpl | 29 ++--- testdata/ttl_zero_cacherep.rpl | 21 ---- util/data/msgencode.c | 47 ++++---- util/data/msgencode.h | 10 +- util/data/msgparse.c | 10 ++ util/data/msgparse.h | 25 ++++ util/data/msgreply.c | 72 ++++++++---- util/data/msgreply.h | 13 ++- util/data/packed_rrset.c | 36 +++--- util/data/packed_rrset.h | 3 + validator/val_neg.c | 6 +- validator/val_utils.c | 2 + 43 files changed, 619 insertions(+), 546 deletions(-) delete mode 100644 testdata/serve_expired_client_timeout_no_prefetch.rpl diff --git a/cachedb/cachedb.c b/cachedb/cachedb.c index 8f2e66342..b45c0a3ea 100644 --- a/cachedb/cachedb.c +++ b/cachedb/cachedb.c @@ -401,12 +401,9 @@ prep_data(struct module_qstate* qstate, struct sldns_buffer* buf) 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 */ @@ -421,7 +418,7 @@ prep_data(struct module_qstate* qstate, struct sldns_buffer* buf) 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 @@ -460,7 +457,7 @@ good_expiry_and_qinfo(struct module_qstate* qstate, struct sldns_buffer* buf) * - 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))) @@ -472,7 +469,8 @@ good_expiry_and_qinfo(struct module_qstate* qstate, struct sldns_buffer* buf) /* 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; @@ -484,13 +482,13 @@ packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract) 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) @@ -502,13 +500,13 @@ adjust_msg_ttl(struct dns_msg* msg, time_t adjust) for(i=0; irep->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; @@ -516,12 +514,12 @@ packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl) for(i=0; irr_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; @@ -530,14 +528,14 @@ set_msg_ttl(struct dns_msg* msg, time_t ttl) for(i=0; irep->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; @@ -554,6 +552,9 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf, ×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); @@ -605,11 +606,9 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf, 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 && @@ -618,23 +617,21 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf, 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; } @@ -647,7 +644,7 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf, */ 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)); @@ -664,7 +661,8 @@ cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie, } /* parse dns message into return_msg */ - if( !parse_data(qstate, qstate->env->scratch_buffer, msg_expired) ) { + if( !parse_data(qstate, qstate->env->scratch_buffer, msg_expired, + msg_timestamp, msg_expiry) ) { return 0; } return 1; @@ -736,20 +734,24 @@ cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde) * Store query into the internal cache of unbound. */ static void -cachedb_intcache_store(struct module_qstate* qstate, 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) @@ -767,12 +769,14 @@ cachedb_intcache_store(struct module_qstate* qstate, int msg_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); } } @@ -790,6 +794,7 @@ cachedb_handle_query(struct module_qstate* qstate, 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) { @@ -824,13 +829,15 @@ cachedb_handle_query(struct module_qstate* qstate, } /* 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. @@ -850,6 +857,8 @@ cachedb_handle_query(struct module_qstate* qstate, 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; diff --git a/daemon/worker.c b/daemon/worker.c index 77417c249..0f0af7457 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -651,7 +651,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, } 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)) @@ -746,7 +746,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, *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 @@ -891,7 +891,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, 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)) @@ -1929,11 +1929,11 @@ lookup_cache: 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, diff --git a/doc/example.conf.in b/doc/example.conf.in index b33e65bfe..02f6ec774 100644 --- a/doc/example.conf.in +++ b/doc/example.conf.in @@ -752,6 +752,7 @@ server: # 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. diff --git a/doc/unbound.conf.rst b/doc/unbound.conf.rst index ad8404e11..72522af70 100644 --- a/doc/unbound.conf.rst +++ b/doc/unbound.conf.rst @@ -2306,6 +2306,12 @@ These options are part of the **server:** clause. :ref:`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 diff --git a/services/authzone.c b/services/authzone.c index 6a9de52f8..e4dd32465 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -171,7 +171,7 @@ get_rrset_ttl(struct ub_packed_rrset_key* k) /** 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)); @@ -182,7 +182,7 @@ auth_packed_rrset_copy_region(struct auth_zone* z, struct auth_data* node, 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 */ @@ -236,7 +236,7 @@ msg_add_rrset_an(struct auth_zone* z, struct regional* region, 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++; @@ -260,7 +260,7 @@ msg_add_rrset_ns(struct auth_zone* z, struct regional* region, 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++; @@ -283,7 +283,7 @@ msg_add_rrset_ar(struct auth_zone* z, struct regional* region, 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++; @@ -3530,7 +3530,7 @@ auth_answer_encode(struct query_info* qinfo, struct module_env* env, *(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); diff --git a/services/cache/dns.c b/services/cache/dns.c index 351b3568c..325faa0b2 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -60,10 +60,10 @@ * @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 @@ -100,11 +100,20 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now, 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 */ @@ -169,10 +178,12 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, /* 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"); @@ -272,8 +283,10 @@ addr_to_additional(struct ub_packed_rrset_key* rrset, struct regional* region, { 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); } } @@ -456,8 +469,10 @@ find_add_ds(struct module_env* env, struct regional* region, /* 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); } @@ -487,6 +502,8 @@ dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype, 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, @@ -497,24 +514,28 @@ dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype, } 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; } @@ -585,6 +606,7 @@ gen_dns_msg(struct regional* region, struct query_info* q, size_t num) 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) @@ -606,13 +628,13 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, 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; } @@ -620,15 +642,6 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, 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; @@ -656,13 +669,30 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, return NULL; } for(i=0; irep->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); @@ -701,7 +731,7 @@ rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region, 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) @@ -736,7 +766,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region, 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. */ @@ -844,6 +874,8 @@ fill_any(struct module_env* env, /* 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; } @@ -1069,7 +1101,7 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf, 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. diff --git a/services/cache/dns.h b/services/cache/dns.h index 8aa6b44bc..41d42e60d 100644 --- a/services/cache/dns.h +++ b/services/cache/dns.h @@ -53,7 +53,7 @@ struct delegpt; * 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 diff --git a/services/cache/rrset.c b/services/cache/rrset.c index 6d5c24f80..200e3c701 100644 --- a/services/cache/rrset.c +++ b/services/cache/rrset.c @@ -131,7 +131,7 @@ need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns) 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 @@ -146,13 +146,13 @@ need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns) 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 ) { @@ -300,7 +300,7 @@ rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen, /* 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; } @@ -310,17 +310,18 @@ rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen, 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; i0 && 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; @@ -511,7 +512,7 @@ rrset_cache_expired_above(struct rrset_cache* r, uint8_t** qname, size_t* *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); diff --git a/services/localzone.c b/services/localzone.c index ce796c349..9ea98c250 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -1332,7 +1332,7 @@ local_encode(struct query_info* qinfo, struct module_env* env, 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); diff --git a/services/mesh.c b/services/mesh.c index 30040f752..a0bb9ba2f 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -348,7 +348,7 @@ mesh_serve_expired_lookup(struct module_qstate* qstate, 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) @@ -1351,7 +1351,7 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, !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, @@ -1539,7 +1539,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, !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)) diff --git a/services/rpz.c b/services/rpz.c index b77f47c9b..df39e75b0 100644 --- a/services/rpz.c +++ b/services/rpz.c @@ -1807,7 +1807,7 @@ rpz_local_encode(struct module_env* env, struct query_info* qinfo, 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); diff --git a/testcode/unitmain.c b/testcode/unitmain.c index 14e31927b..07c016d7b 100644 --- a/testcode/unitmain.c +++ b/testcode/unitmain.c @@ -1037,7 +1037,7 @@ static void edns_ede_encode_encodedecode(struct query_info* qinfo, /* 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); diff --git a/testdata/cachedb_expired.crpl b/testdata/cachedb_expired.crpl index d3bf06fe1..697e88e26 100644 --- a/testdata/cachedb_expired.crpl +++ b/testdata/cachedb_expired.crpl @@ -5,7 +5,10 @@ server: 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" @@ -82,7 +85,7 @@ REPLY QR AA NOERROR 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 @@ -91,7 +94,8 @@ REPLY QR AA NOERROR 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 @@ -111,7 +115,7 @@ REPLY QR RD RA NOERROR 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. @@ -130,46 +134,46 @@ REPLY QR RD RA NOERROR 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 @@ -189,7 +193,7 @@ REPLY QR RD RA NOERROR 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 @@ -210,30 +214,30 @@ REPLY QR RD RA NOERROR 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 @@ -254,7 +258,7 @@ REPLY QR RD RA NOERROR 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 @@ -275,30 +279,30 @@ REPLY QR RD RA NOERROR 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 @@ -319,7 +323,7 @@ REPLY QR RD RA NOERROR 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 diff --git a/testdata/cachedb_expired_client_timeout.crpl b/testdata/cachedb_expired_client_timeout.crpl index 78ddf4d8f..16d8cc30d 100644 --- a/testdata/cachedb_expired_client_timeout.crpl +++ b/testdata/cachedb_expired_client_timeout.crpl @@ -4,12 +4,14 @@ server: 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" @@ -86,7 +88,7 @@ REPLY QR AA NOERROR 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 @@ -95,7 +97,8 @@ REPLY QR AA NOERROR 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 @@ -108,7 +111,7 @@ REPLY QR AA NOERROR 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 @@ -117,7 +120,8 @@ REPLY QR AA NOERROR 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 @@ -132,7 +136,7 @@ REPLY QR AA NOERROR 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 @@ -141,7 +145,8 @@ REPLY QR AA NOERROR 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 @@ -156,7 +161,7 @@ REPLY QR AA NOERROR 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 @@ -165,7 +170,7 @@ REPLY QR AA NOERROR 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 @@ -188,7 +193,7 @@ REPLY QR RD RA NOERROR 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. @@ -207,7 +212,7 @@ REPLY QR RD RA NOERROR 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. @@ -217,7 +222,7 @@ STEP 40 FLUSH_MESSAGE www2.example.com. IN A ; 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 @@ -234,11 +239,11 @@ REPLY QR RD RA NOERROR 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 @@ -258,11 +263,11 @@ REPLY QR RD RA NOERROR 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, @@ -271,7 +276,7 @@ STEP 100 TIME_PASSES ELAPSE 20 ; 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 @@ -281,26 +286,26 @@ STEP 112 TIME_PASSES ELAPSE 2 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 @@ -310,12 +315,12 @@ STEP 152 TIME_PASSES ELAPSE 2 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. @@ -337,7 +342,7 @@ REPLY QR RD RA NOERROR 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 diff --git a/testdata/cachedb_expired_reply_ttl.crpl b/testdata/cachedb_expired_reply_ttl.crpl index 03fd01add..b8adbe738 100644 --- a/testdata/cachedb_expired_reply_ttl.crpl +++ b/testdata/cachedb_expired_reply_ttl.crpl @@ -5,8 +5,10 @@ server: 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" @@ -83,7 +85,7 @@ REPLY QR AA NOERROR 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 @@ -92,7 +94,8 @@ REPLY QR AA NOERROR 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 @@ -115,7 +118,7 @@ REPLY QR RD RA NOERROR 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. @@ -134,28 +137,28 @@ REPLY QR RD RA NOERROR 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 @@ -173,25 +176,25 @@ REPLY QR RD RA NOERROR 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 @@ -211,29 +214,29 @@ REPLY QR RD RA NOERROR 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 @@ -254,7 +257,7 @@ REPLY QR RD RA NOERROR 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 diff --git a/testdata/cachedb_subnet_change.crpl b/testdata/cachedb_subnet_change.crpl index 73584305c..87903132c 100644 --- a/testdata/cachedb_subnet_change.crpl +++ b/testdata/cachedb_subnet_change.crpl @@ -4,7 +4,7 @@ server: 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 @@ -14,6 +14,8 @@ server: ; 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" @@ -105,7 +107,7 @@ REPLY QR AA NOERROR 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 @@ -118,7 +120,7 @@ REPLY QR AA NOERROR 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 @@ -131,7 +133,7 @@ REPLY QR AA NOERROR 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 @@ -144,7 +146,7 @@ REPLY QR AA NOERROR 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 @@ -166,7 +168,7 @@ REPLY QR AA NOERROR 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 @@ -179,7 +181,7 @@ REPLY QR AA NOERROR 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 @@ -211,19 +213,19 @@ REPLY QR RD RA NOERROR 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 @@ -231,13 +233,13 @@ 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. @@ -256,12 +258,12 @@ REPLY QR RD RA NOERROR 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 @@ -277,8 +279,8 @@ REPLY QR RD RA NOERROR 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. @@ -297,8 +299,8 @@ REPLY QR RD RA NOERROR 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 diff --git a/testdata/cachedb_val_expired.crpl b/testdata/cachedb_val_expired.crpl index 741445ce8..aa98b5fe6 100644 --- a/testdata/cachedb_val_expired.crpl +++ b/testdata/cachedb_val_expired.crpl @@ -5,8 +5,11 @@ server: 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" @@ -83,7 +86,7 @@ REPLY QR AA NOERROR 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 @@ -92,7 +95,8 @@ REPLY QR AA NOERROR 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 @@ -112,7 +116,7 @@ REPLY QR RD RA NOERROR 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. @@ -131,48 +135,48 @@ REPLY QR RD RA NOERROR 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 @@ -192,7 +196,7 @@ REPLY QR RD RA NOERROR 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 @@ -213,30 +217,30 @@ REPLY QR RD RA NOERROR 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 @@ -257,7 +261,7 @@ REPLY QR RD RA NOERROR 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 @@ -278,30 +282,30 @@ REPLY QR RD RA NOERROR 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 @@ -322,7 +326,7 @@ REPLY QR RD RA NOERROR 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 diff --git a/testdata/fwd_0ttlservfail.rpl b/testdata/fwd_0ttlservfail.rpl index d50d386d4..635ee6db6 100644 --- a/testdata/fwd_0ttlservfail.rpl +++ b/testdata/fwd_0ttlservfail.rpl @@ -46,25 +46,10 @@ www.example.com. IN A 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 @@ -76,7 +61,7 @@ ENTRY_END STEP 240 CHECK_ANSWER ENTRY_BEGIN -MATCH all +MATCH all ttl REPLY QR RD RA NOERROR SECTION QUESTION www.example.com. IN A diff --git a/testdata/rrset_use_cached.rpl b/testdata/rrset_use_cached.rpl index 8420ae02a..7af5c85d2 100644 --- a/testdata/rrset_use_cached.rpl +++ b/testdata/rrset_use_cached.rpl @@ -5,8 +5,11 @@ server: # 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 @@ -35,11 +38,11 @@ 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 STEP 4 CHECK_ANSWER ENTRY_BEGIN @@ -48,15 +51,15 @@ 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 @@ -80,14 +83,14 @@ 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 @@ -95,11 +98,11 @@ 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. 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. @@ -107,7 +110,7 @@ STEP 10 TIME_PASSES ELAPSE 5 STEP 11 QUERY ENTRY_BEGIN - REPLY RD + REPLY RD DO SECTION QUESTION www.example.com. IN A ENTRY_END @@ -129,23 +132,23 @@ ENTRY_BEGIN 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 diff --git a/testdata/serve_expired.rpl b/testdata/serve_expired.rpl index 990a562c7..4aa65e167 100644 --- a/testdata/serve_expired.rpl +++ b/testdata/serve_expired.rpl @@ -5,6 +5,7 @@ server: 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 @@ -44,7 +45,7 @@ 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 @@ -68,15 +69,15 @@ 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. 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 @@ -94,11 +95,11 @@ ENTRY_BEGIN 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) @@ -116,7 +117,7 @@ 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. IN NS ns.example.com. SECTION ADDITIONAL diff --git a/testdata/serve_expired_0ttl_nodata.rpl b/testdata/serve_expired_0ttl_nodata.rpl index 8ca461be2..a53df437a 100644 --- a/testdata/serve_expired_0ttl_nodata.rpl +++ b/testdata/serve_expired_0ttl_nodata.rpl @@ -5,6 +5,7 @@ server: minimal-responses: no serve-expired: yes serve-expired-client-timeout: 0 + serve-expired-reply-ttl: 123 ede: yes ede-serve-expired: yes @@ -48,9 +49,9 @@ RANGE_BEGIN 30 100 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 @@ -62,9 +63,9 @@ RANGE_BEGIN 30 100 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 @@ -106,13 +107,13 @@ ENTRY_BEGIN 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 @@ -120,8 +121,8 @@ 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 @@ -146,9 +147,9 @@ 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 SCENARIO_END diff --git a/testdata/serve_expired_0ttl_nxdomain.rpl b/testdata/serve_expired_0ttl_nxdomain.rpl index 7cf26aedd..7dd27b8d5 100644 --- a/testdata/serve_expired_0ttl_nxdomain.rpl +++ b/testdata/serve_expired_0ttl_nxdomain.rpl @@ -107,7 +107,7 @@ ENTRY_BEGIN 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 @@ -117,7 +117,7 @@ ENTRY_BEGIN 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 diff --git a/testdata/serve_expired_0ttl_servfail.rpl b/testdata/serve_expired_0ttl_servfail.rpl index e9d4c4884..9e5a17a09 100644 --- a/testdata/serve_expired_0ttl_servfail.rpl +++ b/testdata/serve_expired_0ttl_servfail.rpl @@ -101,7 +101,7 @@ ENTRY_BEGIN 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 diff --git a/testdata/serve_expired_client_timeout.rpl b/testdata/serve_expired_client_timeout.rpl index 5560aa05a..c44543692 100644 --- a/testdata/serve_expired_client_timeout.rpl +++ b/testdata/serve_expired_client_timeout.rpl @@ -48,7 +48,7 @@ RANGE_BEGIN 0 20 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 @@ -72,7 +72,7 @@ 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. IN NS ns.example.com. SECTION ADDITIONAL diff --git a/testdata/serve_expired_client_timeout_no_prefetch.rpl b/testdata/serve_expired_client_timeout_no_prefetch.rpl deleted file mode 100644 index 0177dd14a..000000000 --- a/testdata/serve_expired_client_timeout_no_prefetch.rpl +++ /dev/null @@ -1,110 +0,0 @@ -; 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 diff --git a/testdata/serve_expired_client_timeout_servfail.rpl b/testdata/serve_expired_client_timeout_servfail.rpl index 3c5b35e17..46fe032fb 100644 --- a/testdata/serve_expired_client_timeout_servfail.rpl +++ b/testdata/serve_expired_client_timeout_servfail.rpl @@ -40,9 +40,9 @@ RANGE_BEGIN 0 20 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 @@ -52,11 +52,11 @@ RANGE_BEGIN 0 20 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 @@ -84,11 +84,11 @@ RANGE_BEGIN 50 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. 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 @@ -108,15 +108,15 @@ 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 ; Wait for the TTL to expire -STEP 11 TIME_PASSES ELAPSE 11 +STEP 11 TIME_PASSES ELAPSE 200 ; Query again STEP 30 QUERY @@ -209,11 +209,11 @@ 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 SCENARIO_END diff --git a/testdata/serve_expired_reply_ttl.rpl b/testdata/serve_expired_reply_ttl.rpl index e76976bde..c7859e00e 100644 --- a/testdata/serve_expired_reply_ttl.rpl +++ b/testdata/serve_expired_reply_ttl.rpl @@ -18,8 +18,11 @@ 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 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 @@ -43,7 +46,21 @@ 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 @@ -67,15 +84,37 @@ 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. 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 @@ -100,7 +139,31 @@ ENTRY_BEGIN 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 diff --git a/testdata/serve_expired_ttl_client_timeout.rpl b/testdata/serve_expired_ttl_client_timeout.rpl index 169d070ea..d1aef32af 100644 --- a/testdata/serve_expired_ttl_client_timeout.rpl +++ b/testdata/serve_expired_ttl_client_timeout.rpl @@ -78,7 +78,7 @@ ENTRY_BEGIN 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 diff --git a/testdata/serve_expired_ttl_reset.rpl b/testdata/serve_expired_ttl_reset.rpl index 9f215c96b..f732fddcf 100644 --- a/testdata/serve_expired_ttl_reset.rpl +++ b/testdata/serve_expired_ttl_reset.rpl @@ -36,7 +36,7 @@ REPLY QR AA NOERROR 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 @@ -46,11 +46,11 @@ REPLY QR RA RD NOERROR 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 diff --git a/testdata/serve_expired_zerottl.rpl b/testdata/serve_expired_zerottl.rpl index 1411cb8e7..50a50bb3b 100644 --- a/testdata/serve_expired_zerottl.rpl +++ b/testdata/serve_expired_zerottl.rpl @@ -65,11 +65,11 @@ RANGE_BEGIN 11 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. 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 @@ -118,15 +118,15 @@ 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 ; 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 diff --git a/testdata/subnet_global_prefetch_always_forward.crpl b/testdata/subnet_global_prefetch_always_forward.crpl index 775474cbc..f2c8bdb60 100644 --- a/testdata/subnet_global_prefetch_always_forward.crpl +++ b/testdata/subnet_global_prefetch_always_forward.crpl @@ -7,12 +7,15 @@ server: 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: "." @@ -100,7 +103,7 @@ RANGE_BEGIN 0 100 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 @@ -131,11 +134,11 @@ ns.example.com. IN A 1.2.3.4 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 @@ -143,16 +146,16 @@ 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 diff --git a/testdata/subnet_global_prefetch_expired.crpl b/testdata/subnet_global_prefetch_expired.crpl index 374bf3e69..a347550ba 100644 --- a/testdata/subnet_global_prefetch_expired.crpl +++ b/testdata/subnet_global_prefetch_expired.crpl @@ -16,7 +16,11 @@ server: 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: "." @@ -113,7 +117,7 @@ RANGE_BEGIN 0 10 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 @@ -147,7 +151,7 @@ RANGE_BEGIN 11 100 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 @@ -178,7 +182,7 @@ REPLY QR RD RA NOERROR 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 @@ -186,11 +190,11 @@ ns.example.com. IN A 1.2.3.4 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 @@ -198,19 +202,18 @@ 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 @@ -232,7 +235,7 @@ REPLY QR RD RA NOERROR 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 diff --git a/testdata/ttl_zero_cacherep.rpl b/testdata/ttl_zero_cacherep.rpl index 7e9eb5394..fe6f9dcc7 100644 --- a/testdata/ttl_zero_cacherep.rpl +++ b/testdata/ttl_zero_cacherep.rpl @@ -260,27 +260,6 @@ ENTRY_END 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 diff --git a/util/data/msgencode.c b/util/data/msgencode.c index b389800d0..22c3ba9d7 100644 --- a/util/data/msgencode.c +++ b/util/data/msgencode.c @@ -496,10 +496,18 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt, 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, @@ -533,10 +541,18 @@ 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] < 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], @@ -993,11 +1009,11 @@ attach_edns_record(sldns_buffer* pkt, struct edns_data* edns) 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; @@ -1022,17 +1038,6 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, 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; diff --git a/util/data/msgencode.h b/util/data/msgencode.h index 231361680..0363a90bf 100644 --- a/util/data/msgencode.h +++ b/util/data/msgencode.h @@ -64,16 +64,12 @@ struct edns_data; * 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. diff --git a/util/data/msgparse.c b/util/data/msgparse.c index 6963d8501..fc7018def 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -1361,3 +1361,13 @@ msgparse_rrset_remove_rr(const char* str, sldns_buffer* pkt, struct rrset_parse* * 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 diff --git a/util/data/msgparse.h b/util/data/msgparse.h index 7de4e394f..373de677d 100644 --- a/util/data/msgparse.h +++ b/util/data/msgparse.h @@ -98,6 +98,31 @@ extern time_t SERVE_EXPIRED_REPLY_TTL; /** 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. diff --git a/util/data/msgreply.c b/util/data/msgreply.c index 6b65e1eb1..d67c1d0ca 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -178,9 +178,9 @@ reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc, 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 && @@ -188,12 +188,13 @@ reply_info_can_answer_expired(struct reply_info* rep, time_t timenow) 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 && @@ -229,7 +230,7 @@ make_new_reply_info(const struct reply_info* rep, struct regional* region, } /** 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); @@ -237,7 +238,7 @@ soa_find_minttl(struct rr_parse* rr) 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 */ @@ -247,37 +248,40 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, 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 */ @@ -481,6 +485,7 @@ parse_copy_decompress_rrset(sldns_buffer* pkt, struct msg_parse* msg, 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; } @@ -617,6 +622,29 @@ reply_info_set_ttls(struct reply_info* rep, time_t timenow) } } +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; irrset_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; jcount + 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) { diff --git a/util/data/msgreply.h b/util/data/msgreply.h index b65abd922..a63ac49a3 100644 --- a/util/data/msgreply.h +++ b/util/data/msgreply.h @@ -60,10 +60,6 @@ struct local_rrset; 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. @@ -340,6 +336,15 @@ void reply_info_sortref(struct reply_info* rep); */ 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. diff --git a/util/data/packed_rrset.c b/util/data/packed_rrset.c index d18486cc5..89ece3c03 100644 --- a/util/data/packed_rrset.c +++ b/util/data/packed_rrset.c @@ -336,10 +336,9 @@ packed_rrset_copy_region(struct ub_packed_rrset_key* key, 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; @@ -352,22 +351,31 @@ packed_rrset_copy_region(struct ub_packed_rrset_key* key, 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; icount + 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; icount + 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; } diff --git a/util/data/packed_rrset.h b/util/data/packed_rrset.h index 776e8d092..4e0911ccf 100644 --- a/util/data/packed_rrset.h +++ b/util/data/packed_rrset.h @@ -70,6 +70,8 @@ typedef uint64_t rrset_id_type; #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 @@ -99,6 +101,7 @@ struct packed_rrset_key { * 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 */ diff --git a/validator/val_neg.c b/validator/val_neg.c index bc3a83aeb..7817d56fc 100644 --- a/validator/val_neg.c +++ b/validator/val_neg.c @@ -1066,11 +1066,7 @@ grab_nsec(struct rrset_cache* rrset_cache, uint8_t* qname, size_t qname_len, 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 && diff --git a/validator/val_utils.c b/validator/val_utils.c index 549264d76..1a5f19673 100644 --- a/validator/val_utils.c +++ b/validator/val_utils.c @@ -1310,6 +1310,7 @@ val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t c, /* 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; @@ -1319,6 +1320,7 @@ val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t c, 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 */ -- 2.47.3