aboutsummaryrefslogtreecommitdiff
path: root/services/cache/dns.c
diff options
context:
space:
mode:
Diffstat (limited to 'services/cache/dns.c')
-rw-r--r--services/cache/dns.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/services/cache/dns.c b/services/cache/dns.c
index 411793c6c270..35adc35b57ee 100644
--- a/services/cache/dns.c
+++ b/services/cache/dns.c
@@ -108,6 +108,48 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
}
}
+/** delete message from message cache */
+static void
+msg_cache_remove(struct module_env* env, uint8_t* qname, size_t qnamelen,
+ uint16_t qtype, uint16_t qclass, uint16_t flags)
+{
+ struct query_info k;
+ hashvalue_type h;
+
+ k.qname = qname;
+ k.qname_len = qnamelen;
+ k.qtype = qtype;
+ k.qclass = qclass;
+ k.local_alias = NULL;
+ h = query_info_hash(&k, flags);
+ slabhash_remove(env->msg_cache, h, &k);
+}
+
+/** remove servfail msg cache entry */
+static void
+msg_del_servfail(struct module_env* env, struct query_info* qinfo,
+ uint32_t flags)
+{
+ struct msgreply_entry* e;
+ /* see if the entry is servfail, and then remove it, so that
+ * lookups move from the cacheresponse stage to the recursionresponse
+ * stage */
+ e = msg_cache_lookup(env, qinfo->qname, qinfo->qname_len,
+ qinfo->qtype, qinfo->qclass, flags, 0, 0);
+ if(!e) return;
+ /* we don't check for the ttl here, also expired servfail entries
+ * are removed. If the user uses serve-expired, they would still be
+ * used to answer from cache */
+ if(FLAGS_GET_RCODE(((struct reply_info*)e->entry.data)->flags)
+ != LDNS_RCODE_SERVFAIL) {
+ lock_rw_unlock(&e->entry.lock);
+ return;
+ }
+ lock_rw_unlock(&e->entry.lock);
+ msg_cache_remove(env, qinfo->qname, qinfo->qname_len, qinfo->qtype,
+ qinfo->qclass, flags);
+}
+
void
dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
hashvalue_type hash, struct reply_info* rep, time_t leeway, int pside,
@@ -132,6 +174,12 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
* which could be useful for delegation information */
verbose(VERB_ALGO, "TTL 0: dropped msg from cache");
free(rep);
+ /* if the message is SERVFAIL in cache, remove that SERVFAIL,
+ * so that the TTL 0 response can be returned for future
+ * responses (i.e. don't get answered by the servfail from
+ * cache, but instead go to recursion to get this TTL0
+ * response). */
+ msg_del_servfail(env, qinfo, flags);
return;
}