diff options
Diffstat (limited to 'services/cache/dns.c')
| -rw-r--r-- | services/cache/dns.c | 59 |
1 files changed, 39 insertions, 20 deletions
diff --git a/services/cache/dns.c b/services/cache/dns.c index 5e74c31693b3..7ab63bacf492 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -88,7 +88,7 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now, /* update ref if it was in the cache */ switch(rrset_cache_update(env->rrset_cache, &rep->ref[i], env->alloc, ((ntohs(rep->ref[i].key->rk.type)== - LDNS_RR_TYPE_NS && !pside)?qstarttime:now + leeway))) { + LDNS_RR_TYPE_NS && !pside)?qstarttime:now) + leeway)) { case 0: /* ref unchanged, item inserted */ break; case 2: /* ref updated, cache is superior */ @@ -162,7 +162,7 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, size_t i; /* store RRsets */ - for(i=0; i<rep->rrset_count; i++) { + for(i=0; i<rep->rrset_count; i++) { rep->ref[i].key = rep->rrsets[i]; rep->ref[i].id = rep->rrsets[i]->id; } @@ -197,6 +197,7 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo, reply_info_sortref(rep); if(!(e = query_info_entrysetup(qinfo, rep, hash))) { log_err("store_msg: malloc failed"); + reply_info_delete(rep, NULL); return; } slabhash_insert(env->msg_cache, hash, &e->entry, rep, env->alloc); @@ -365,7 +366,7 @@ find_add_addrs(struct module_env* env, uint16_t qclass, /** find and add A and AAAA records for missing nameservers in delegpt */ int cache_fill_missing(struct module_env* env, uint16_t qclass, - struct regional* region, struct delegpt* dp) + struct regional* region, struct delegpt* dp, uint32_t flags) { struct delegpt_ns* ns; struct msgreply_entry* neg; @@ -376,7 +377,7 @@ cache_fill_missing(struct module_env* env, uint16_t qclass, continue; ns->cache_lookup_count++; akey = rrset_cache_lookup(env->rrset_cache, ns->name, - ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0); + ns->namelen, LDNS_RR_TYPE_A, qclass, flags, now, 0); if(akey) { if(!delegpt_add_rrset_A(dp, region, akey, ns->lame, NULL)) { @@ -397,7 +398,7 @@ cache_fill_missing(struct module_env* env, uint16_t qclass, } } akey = rrset_cache_lookup(env->rrset_cache, ns->name, - ns->namelen, LDNS_RR_TYPE_AAAA, qclass, 0, now, 0); + ns->namelen, LDNS_RR_TYPE_AAAA, qclass, flags, now, 0); if(akey) { if(!delegpt_add_rrset_AAAA(dp, region, akey, ns->lame, NULL)) { @@ -607,22 +608,8 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, time_t now_control = now; if(now > r->ttl) { /* Check if we are allowed to serve expired */ - if(allow_expired) { - if(env->cfg->serve_expired_ttl && - r->serve_expired_ttl < now) { - return NULL; - } - /* Ignore expired failure answers */ - if(FLAGS_GET_RCODE(r->flags) != - LDNS_RCODE_NOERROR && - FLAGS_GET_RCODE(r->flags) != - LDNS_RCODE_NXDOMAIN && - FLAGS_GET_RCODE(r->flags) != - LDNS_RCODE_YXDOMAIN) - return 0; - } else { + 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; @@ -641,6 +628,7 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, 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; @@ -724,6 +712,7 @@ rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region, msg->rep->ttl = d->ttl - now; 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 = sec_status_unchecked; msg->rep->an_numrrsets = 1; msg->rep->ns_numrrsets = 0; @@ -763,6 +752,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region, msg->rep->ttl = d->ttl - now; 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 = sec_status_unchecked; msg->rep->an_numrrsets = 1; msg->rep->ns_numrrsets = 0; @@ -1070,6 +1060,35 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf, struct regional* region, uint32_t flags, time_t qstarttime) { struct reply_info* rep = NULL; + if(SERVE_EXPIRED) { + /* We are serving expired records. Before caching, check if a + * useful expired record exists. */ + struct msgreply_entry* e = msg_cache_lookup(env, + msgqinf->qname, msgqinf->qname_len, msgqinf->qtype, + msgqinf->qclass, flags, 0, 0); + if(e) { + struct reply_info* cached = e->entry.data; + if(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. + * In that case don't cache it and let a + * subsequent module handle the caching. For + * example, the iterator should not replace an + * expired secure answer with a fresh unchecked + * one and let the validator manage caching. */ + && cached->security != sec_status_bogus + && (env->need_to_validate && + msgrep->security == sec_status_unchecked)) { + verbose(VERB_ALGO, "a validated expired entry " + "could be overwritten, skip caching " + "the new message at this stage"); + lock_rw_unlock(&e->entry.lock); + return 1; + } + lock_rw_unlock(&e->entry.lock); + } + } /* alloc, malloc properly (not in region, like msg is) */ rep = reply_info_copy(msgrep, env->alloc, NULL); if(!rep) |
