From: Wouter Wijngaards Date: Thu, 10 Apr 2014 13:56:16 +0000 (+0000) Subject: - Fix #558: failed prefetch lookup does not remove cached response X-Git-Tag: release-1.5.0rc1~147 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eb5e9a89c47940d546f1b5cb544c22a7d28a1e84;p=thirdparty%2Funbound.git - Fix #558: failed prefetch lookup does not remove cached response but delays next prefetch (in lieu of caching a SERVFAIL). git-svn-id: file:///svn/unbound/trunk@3111 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index f765e9322..e4f20f3a9 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -10,6 +10,8 @@ (for NetworkManager integration.) - Fix #554: use unsigned long to print 64bit statistics counters on 64bit systems. + - Fix #558: failed prefetch lookup does not remove cached response + but delays next prefetch (in lieu of caching a SERVFAIL). 8 April 2014: Wouter - Fix #574: make test fails on Ubuntu 14.04. Disabled remote-control diff --git a/iterator/iterator.c b/iterator/iterator.c index 87fac81f3..f240f5034 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -253,6 +253,14 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode) { /* store in cache */ struct reply_info err; + if(qstate->prefetch_leeway > NORR_TTL) { + verbose(VERB_ALGO, "error response for prefetch in cache"); + /* attempt to adjust the cache entry prefetch */ + if(dns_cache_prefetch_adjust(qstate->env, &qstate->qinfo, + NORR_TTL)) + return error_response(qstate, id, rcode); + /* if that fails (not in cache), fall through to store err */ + } memset(&err, 0, sizeof(err)); err.flags = (uint16_t)(BIT_QR | BIT_RA); FLAGS_SET_RCODE(err.flags, rcode); diff --git a/services/cache/dns.c b/services/cache/dns.c index f2a04a227..c663b8e8b 100644 --- a/services/cache/dns.c +++ b/services/cache/dns.c @@ -795,3 +795,22 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf, } return 1; } + +int +dns_cache_prefetch_adjust(struct module_env* env, struct query_info* qinfo, + time_t adjust) +{ + struct msgreply_entry* msg; + msg = msg_cache_lookup(env, qinfo->qname, qinfo->qname_len, + qinfo->qtype, qinfo->qclass, *env->now, 1); + if(msg) { + struct reply_info* rep = (struct reply_info*)msg->entry.data; + if(rep) { + rep->prefetch_ttl += adjust; + lock_rw_unlock(&msg->entry.lock); + return 1; + } + lock_rw_unlock(&msg->entry.lock); + } + return 0; +} diff --git a/services/cache/dns.h b/services/cache/dns.h index a7a6190cf..05a3e6296 100644 --- a/services/cache/dns.h +++ b/services/cache/dns.h @@ -179,4 +179,16 @@ struct dns_msg* dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype, int dns_msg_authadd(struct dns_msg* msg, struct regional* region, struct ub_packed_rrset_key* rrset, time_t now); +/** + * Adjust the prefetch_ttl for a cached message. This adds a value to the + * prefetch ttl - postponing the time when it will be prefetched for future + * incoming queries. + * @param env: module environment with caches and time. + * @param qinfo: query info for the query that needs adjustment. + * @param adjust: time in seconds to add to the prefetch_leeway. + * @return false if not in cache. true if added. + */ +int dns_cache_prefetch_adjust(struct module_env* env, struct query_info* qinfo, + time_t adjust); + #endif /* SERVICES_CACHE_DNS_H */ diff --git a/testdata/iter_prefetch_fail.rpl b/testdata/iter_prefetch_fail.rpl new file mode 100644 index 000000000..2f7f99425 --- /dev/null +++ b/testdata/iter_prefetch_fail.rpl @@ -0,0 +1,393 @@ +; config options +server: + target-fetch-policy: "0 0 0 0 0" + prefetch: "yes" + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test resolver prefetch where it fails to fetch + +; K.ROOT-SERVERS.NET. +RANGE_BEGIN 0 200 + ADDRESS 193.0.14.129 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +. IN NS +SECTION ANSWER +. IN NS K.ROOT-SERVERS.NET. +SECTION ADDITIONAL +K.ROOT-SERVERS.NET. IN A 193.0.14.129 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION AUTHORITY +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END +RANGE_END + +; a.gtld-servers.net. +RANGE_BEGIN 0 200 + ADDRESS 192.5.6.30 +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +com. IN NS +SECTION ANSWER +com. IN NS a.gtld-servers.net. +SECTION ADDITIONAL +a.gtld-servers.net. IN A 192.5.6.30 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode subdomain +ADJUST copy_id copy_query +REPLY QR NOERROR +SECTION QUESTION +example.com. IN NS +SECTION AUTHORITY +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 40 + 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 + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.com. IN AAAA +SECTION ANSWER +SECTION AUTHORITY +example.com. IN SOA ns.example.com. hostmaster.example.com. 1 2 3 4 5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.com. IN A +SECTION ANSWER +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 +www.example.com. IN A +SECTION ANSWER +www.example.com. 3600 IN A 10.20.30.40 +SECTION AUTHORITY +example.com. 3600 IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. 3600 IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; ns.example.com. +RANGE_BEGIN 50 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 + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.com. IN A +SECTION ANSWER +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 +ns.example.com. IN AAAA +SECTION ANSWER +SECTION AUTHORITY +example.com. IN SOA ns.example.com. hostmaster.example.com. 1 2 3 4 5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR AA SERVFAIL +SECTION QUESTION +www.example.com. IN A +;SECTION ANSWER +;www.example.com. 3600 IN A 10.20.30.40 +;SECTION AUTHORITY +;example.com. 3600 IN NS ns.example.com. +;SECTION ADDITIONAL +;ns.example.com. 3600 IN A 1.2.3.4 +ENTRY_END +RANGE_END + +; note ns.example.com range for steps 100 - 160 is not entered +; no queries should be sent there + +; ns.example.com. +RANGE_BEGIN 160 200 + 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 + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.com. IN AAAA +SECTION ANSWER +SECTION AUTHORITY +example.com. IN SOA ns.example.com. hostmaster.example.com. 1 2 3 4 5 +ENTRY_END + +ENTRY_BEGIN +MATCH opcode qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +ns.example.com. IN A +SECTION ANSWER +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 +www.example.com. IN A +SECTION ANSWER +www.example.com. 3600 IN A 10.20.30.40 +SECTION AUTHORITY +example.com. 3600 IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. 3600 IN A 1.2.3.4 +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. 3600 IN A 10.20.30.40 +SECTION AUTHORITY +example.com. 3600 IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. 3600 IN A 1.2.3.4 +ENTRY_END + +; after 1800 secs still the cached answer +STEP 20 TIME_PASSES ELAPSE 1800 + +STEP 30 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END +; recursion happens here. +STEP 40 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. 1800 IN A 10.20.30.40 +SECTION AUTHORITY +example.com. 1800 IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. 1800 IN A 1.2.3.4 +ENTRY_END + +; after 1440 we are 360 seconds before the expiry +; (the authority changes behind the scenes to detect new lookup) +STEP 50 TIME_PASSES ELAPSE 1440 + +STEP 60 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END +; recursion happens here. +STEP 70 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. 360 IN A 10.20.30.40 +SECTION AUTHORITY +example.com. 360 IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. 360 IN A 1.2.3.4 +ENTRY_END +STEP 80 TRAFFIC +; let traffic flow for prefetch to happen + +; above a cache reply with 10% of the original TTL +; but the actual cache could have been updated, try to get that +STEP 120 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END +; recursion happens here. +STEP 130 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. 360 IN A 10.20.30.40 +SECTION AUTHORITY +example.com. 360 IN NS ns.example.com. +SECTION ADDITIONAL +; this is picked up from the parent (because this simulation has the +; parent respond with servfail, not actually timeout) +ns.example.com. 3600 IN A 1.2.3.4 +ENTRY_END + +; another query to see if there is another lookup towards the authority +; the server should not send too many queries towards the authority +STEP 140 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END +; recursion happens here. +STEP 150 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. 360 IN A 10.20.30.40 +SECTION AUTHORITY +example.com. 360 IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. 3600 IN A 1.2.3.4 +ENTRY_END + +; some time later another query, and now it is fine to bother the authority +; with another lookup attempt. +STEP 160 TIME_PASSES ELAPSE 30 +; so we are now 330 seconds before expiry. +STEP 170 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END +; recursion happens here. +STEP 180 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. 330 IN A 10.20.30.40 +SECTION AUTHORITY +example.com. 330 IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. 3570 IN A 1.2.3.4 +ENTRY_END +; now the just-looked-up entry +STEP 190 QUERY +ENTRY_BEGIN +REPLY RD +SECTION QUESTION +www.example.com. IN A +ENTRY_END +; recursion happens here. +STEP 200 CHECK_ANSWER +ENTRY_BEGIN +MATCH all ttl +REPLY QR RD RA NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. 3600 IN A 10.20.30.40 +SECTION AUTHORITY +example.com. 3600 IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. 3570 IN A 1.2.3.4 +ENTRY_END + + +SCENARIO_END