]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix #3736: Fix 0 TTL domains stuck on SERVFAIL unless manually
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 13 Mar 2018 12:52:11 +0000 (12:52 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 13 Mar 2018 12:52:11 +0000 (12:52 +0000)
  flushed with serve-expired on.

git-svn-id: file:///svn/unbound/trunk@4582 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
services/cache/dns.c

index 0fe2ba8206e3be2ddd76f246b447452ebe1c2413..74d59e8d5a6cb433e99b6acb464e1d5b57e80362 100644 (file)
@@ -1,5 +1,7 @@
 13 March 2018: Wouter
        - Fix typo in documentation.
+       - Fix #3736: Fix 0 TTL domains stuck on SERVFAIL unless manually
+         flushed with serve-expired on.
 
 12 March 2018: Wouter
        - Added documentation for aggressive-nsec: yes.
index 411793c6c2709c2951ac018af37f6140ac1105c8..382b3296215ade950a381af7f232076d77a146d1 100644 (file)
@@ -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, *env->now, 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;
        }