]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Ignore expired error responses.
authorGeorge Thessalonikefs <george@nlnetlabs.nl>
Tue, 22 Nov 2022 16:44:55 +0000 (17:44 +0100)
committerGeorge Thessalonikefs <george@nlnetlabs.nl>
Tue, 22 Nov 2022 16:44:55 +0000 (17:44 +0100)
cachedb/cachedb.c
daemon/worker.c
doc/Changelog
services/cache/dns.c
testdata/fwd_0ttlservfail.rpl
testdata/serve_expired_cached_servfail.rpl [new file with mode: 0644]
testdata/serve_expired_client_timeout_servfail.rpl [moved from testdata/serve_expired_servfail.rpl with 86% similarity]
testdata/subnet_cached_servfail.crpl [new file with mode: 0644]

index 6f987fc0301e1a5acef6eb660f7b16013324e1ba..245daa9869674943b939aac06c29639a0cf903b6 100644 (file)
@@ -551,10 +551,16 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
                verbose(VERB_ALGO, "cachedb msg expired");
                /* If serve-expired is enabled, we still use an expired message
                 * setting the TTL to 0. */
-               if(qstate->env->cfg->serve_expired)
-                       adjust = -1;
-               else
+               if(!qstate->env->cfg->serve_expired ||
+                       (FLAGS_GET_RCODE(qstate->return_msg->rep->flags)
+                       != LDNS_RCODE_NOERROR &&
+                       FLAGS_GET_RCODE(qstate->return_msg->rep->flags)
+                       != LDNS_RCODE_NXDOMAIN &&
+                       FLAGS_GET_RCODE(qstate->return_msg->rep->flags)
+                       != LDNS_RCODE_YXDOMAIN))
                        return 0; /* message expired */
+               else
+                       adjust = -1;
        }
        verbose(VERB_ALGO, "cachedb msg adjusted down by %d", (int)adjust);
        adjust_msg_ttl(qstate->return_msg, adjust);
index caefad62140973bd5018802074bf588e3c9e6f0d..2180b4f96b8a81e236c8550c904d6d186b118bd2 100644 (file)
@@ -623,6 +623,14 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
                                if(worker->env.cfg->serve_expired_ttl &&
                                        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 &&
+                                       FLAGS_GET_RCODE(rep->flags) !=
+                                       LDNS_RCODE_YXDOMAIN)
+                                       return 0;
                                if(!rrset_array_lock(rep->ref, rep->rrset_count, 0))
                                        return 0;
                                *is_expired_answer = 1;
@@ -730,8 +738,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
                                goto bail_out;
                }
        } else {
-               /* We don't check the global ede as this is a warning, not
-                * an error */
                if (*is_expired_answer == 1 &&
                        worker->env.cfg->ede_serve_expired && worker->env.cfg->ede) {
                        EDNS_OPT_LIST_APPEND_EDE(&edns->opt_list_out,
index 66cc6161df615977e7007c23a7bf2f944da8c0c3..0375b07163f560b75c1de59e1431ac2d14547dcb 100644 (file)
@@ -1,3 +1,6 @@
+22 November 2022: George
+       - Ignore expired error responses.
+
 11 November 2022: Wouter
        - Fix #779: [doc] Missing documention in ub_resolve_event() for
          callback parameter was_ratelimited.
index b6e5697349c29f726fca985d23d52dab8d28642e..6fc9919ef4c088a4672b6feb17b09f9a83bbea42 100644 (file)
@@ -636,6 +636,14 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
                                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 {
                        return NULL;
                }
index f1a6dc6291a09d6ec1d2e85a599f341dddba1e1d..ed912c73bf2ffc004f056212839e713c1c9b0630 100644 (file)
@@ -2,6 +2,7 @@
 ; config options go here.
 server:
        serve-expired: yes
+       prefetch: yes
 forward-zone: name: "." forward-addr: 216.0.0.1
 CONFIG_END
 
@@ -45,7 +46,7 @@ SECTION ANSWER
 ENTRY_END
 
 ; enough to pass by the TTL of the servfail answer in cache
-STEP 50 TIME_PASSES ELAPSE 40
+STEP 50 TIME_PASSES ELAPSE 5
 
 ; this query triggers a prefetch
 STEP 210 QUERY
diff --git a/testdata/serve_expired_cached_servfail.rpl b/testdata/serve_expired_cached_servfail.rpl
new file mode 100644 (file)
index 0000000..286de70
--- /dev/null
@@ -0,0 +1,130 @@
+; config options
+server:
+       module-config: "validator iterator"
+       qname-minimisation: "no"
+       minimal-responses: no
+       serve-expired: yes
+       serve-expired-reply-ttl: 123
+       log-servfail: yes
+       ede: yes
+       ede-serve-expired: yes
+
+
+stub-zone:
+       name: "example.com"
+       stub-addr: 1.2.3.4
+CONFIG_END
+
+SCENARIO_BEGIN Test serve-expired with client-timeout and a SERVFAIL upstream reply
+; Scenario overview:
+; - query for example.com. IN A
+; - answer from upstream is SERVFAIL; will be cached for NORR_TTL(5)
+; - check that the client gets the SERVFAIL; also cached
+; - query again right after the TTL expired
+; - cached SERVFAIL should be ignored and upstream queried
+; - check that we get the correct answer
+
+; ns.example.com.
+RANGE_BEGIN 0 20
+       ADDRESS 1.2.3.4
+       ; response to A query
+       ENTRY_BEGIN
+               MATCH opcode qtype qname
+               ADJUST copy_id
+               REPLY QR AA SERVFAIL
+               SECTION QUESTION
+                       example.com. IN A
+       ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 30 100
+       ADDRESS 1.2.3.4
+       ENTRY_BEGIN
+               MATCH opcode qtype qname
+               ADJUST copy_id
+               REPLY QR NOERROR
+               SECTION QUESTION
+                       example.com. 10 IN NS
+               SECTION ANSWER
+                       example.com. 10 IN NS ns.example.com.
+               SECTION ADDITIONAL
+                       ns.example.com. 10 IN A 1.2.3.4
+       ENTRY_END
+
+       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. 10 IN NS ns.example.com.
+               SECTION ADDITIONAL
+                       ns.example.com. 10 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 get the SERVFAIL (will be cached)
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+       MATCH all
+       REPLY QR RD RA SERVFAIL
+       SECTION QUESTION
+               example.com. IN A
+ENTRY_END
+
+; Query again
+STEP 20 QUERY
+ENTRY_BEGIN
+       REPLY RD
+       SECTION QUESTION
+               example.com. IN A
+ENTRY_END
+
+; Check that we get the cached SERVFAIL
+STEP 30 CHECK_ANSWER
+ENTRY_BEGIN
+       MATCH all
+       REPLY QR RD RA SERVFAIL
+       SECTION QUESTION
+               example.com. IN A
+ENTRY_END
+
+; Wait for the SERVFAIL to expire
+STEP 31 TIME_PASSES ELAPSE 6
+
+; Query again
+STEP 40 QUERY
+ENTRY_BEGIN
+       REPLY RD
+       SECTION QUESTION
+               example.com. IN A
+ENTRY_END
+
+; Check that we got the correct answer
+STEP 50 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. 10 IN NS ns.example.com.
+       SECTION ADDITIONAL
+               ns.example.com. 10 IN A 1.2.3.4
+ENTRY_END
+
+SCENARIO_END
similarity index 86%
rename from testdata/serve_expired_servfail.rpl
rename to testdata/serve_expired_client_timeout_servfail.rpl
index 6e3192ef081c80738d384688f22788af0862b048..1cae3fd822ff2d27384eae27233e7bc5857b6234 100644 (file)
@@ -4,7 +4,7 @@ server:
        qname-minimisation: "no"
        minimal-responses: no
        serve-expired: yes
-       serve-expired-client-timeout: 1800
+       serve-expired-client-timeout: 1
        serve-expired-reply-ttl: 123
        log-servfail: yes
        ede: yes
@@ -32,11 +32,11 @@ RANGE_BEGIN 0 20
                ADJUST copy_id
                REPLY QR NOERROR
                SECTION QUESTION
-                       example.com. IN NS
+                       example.com. 10 IN NS
                SECTION ANSWER
-                       example.com. IN NS ns.example.com.
+                       example.com. 10 IN NS ns.example.com.
                SECTION ADDITIONAL
-                       ns.example.com. IN A 1.2.3.4
+                       ns.example.com. 10 IN A 1.2.3.4
        ENTRY_END
 
        ENTRY_BEGIN
@@ -48,14 +48,14 @@ RANGE_BEGIN 0 20
                SECTION ANSWER
                        example.com. 10 IN A 5.6.7.8
                SECTION AUTHORITY
-                       example.com. IN NS ns.example.com.
+                       example.com. 10 IN NS ns.example.com.
                SECTION ADDITIONAL
-                       ns.example.com. IN A 1.2.3.4
+                       ns.example.com. 10 IN A 1.2.3.4
        ENTRY_END
 RANGE_END
 
 ; ns.example.com.
-RANGE_BEGIN 30 100
+RANGE_BEGIN 30 70
        ADDRESS 1.2.3.4
        ; response to A query
        ENTRY_BEGIN
@@ -85,13 +85,13 @@ ENTRY_BEGIN
        SECTION ANSWER
                example.com. 10 IN A 5.6.7.8
        SECTION AUTHORITY
-               example.com. IN NS ns.example.com.
+               example.com. 10 IN NS ns.example.com.
        SECTION ADDITIONAL
-               ns.example.com. IN A 1.2.3.4
+               ns.example.com. 10 IN A 1.2.3.4
 ENTRY_END
 
 ; Wait for the TTL to expire
-STEP 11 TIME_PASSES ELAPSE 3601
+STEP 11 TIME_PASSES ELAPSE 11
 
 ; Query again
 STEP 30 QUERY
diff --git a/testdata/subnet_cached_servfail.crpl b/testdata/subnet_cached_servfail.crpl
new file mode 100644 (file)
index 0000000..9c746d5
--- /dev/null
@@ -0,0 +1,167 @@
+; Check if an expired SERVFAIL answer stored in the global cache does not block
+; ECS queries to reach the ECS cache.
+
+server:
+       trust-anchor-signaling: no
+       target-fetch-policy: "0 0 0 0 0"
+       send-client-subnet: 1.2.3.4
+       max-client-subnet-ipv4: 21
+       module-config: "subnetcache iterator"
+       verbosity: 3
+       access-control: 127.0.0.1 allow_snoop
+       qname-minimisation: no
+       minimal-responses: no
+       serve-expired: yes
+       prefetch: yes
+
+stub-zone:
+       name: "example.com."
+       stub-addr: 1.2.3.4
+CONFIG_END
+
+SCENARIO_BEGIN Test that expired SERVFAIL in global cache does not block clients to reach the ECS cache
+
+; ns.example.com.
+RANGE_BEGIN 0 10
+       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
+
+       ; response to query of interest
+       ENTRY_BEGIN
+               MATCH opcode qtype qname
+               ADJUST copy_id
+               REPLY QR SERVFAIL
+               SECTION QUESTION
+                       www.example.com. IN A
+       ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 11 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
+
+       ; response to query of interest
+       ENTRY_BEGIN
+               MATCH opcode qtype qname ednsdata
+               ADJUST copy_id copy_ednsdata_assume_clientsubnet
+               REPLY QR NOERROR
+               SECTION QUESTION
+                       www.example.com. IN A
+               SECTION ANSWER
+                       www.example.com. 10 IN A        10.20.30.40
+               SECTION AUTHORITY
+                       example.com.    IN NS   ns.example.com.
+               SECTION ADDITIONAL
+                       HEX_EDNSDATA_BEGIN
+                                               ; client is 127.0.0.1
+                               00 08           ; OPC
+                               00 05           ; option length
+                               00 01           ; Family
+                               08 00           ; source mask, scopemask
+                               7f              ; address
+                       HEX_EDNSDATA_END
+                       ns.example.com.         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
+
+; This answer should be in the global cache
+STEP 2 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA SERVFAIL
+SECTION QUESTION
+www.example.com.       IN A
+ENTRY_END
+
+; Bring the cached SERVFAIL to prefetch time
+STEP 10 TIME_PASSES ELAPSE 5
+
+STEP 11 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.com. IN A
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+       00 08 00 05     ; OPC, optlen
+       00 01 08 00     ; ip4, source 8, scope 0
+       7f              ; 127.0.0.0/8
+HEX_EDNSDATA_END
+ENTRY_END
+
+; This answer was cached but a prefetch was triggerred
+STEP 12 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH opcode qtype qname
+REPLY QR RD RA SERVFAIL
+SECTION QUESTION
+www.example.com.       IN A
+ENTRY_END
+
+; Wait for the SERVFAIL to expire
+STEP 13 TIME_PASSES ELAPSE 2
+
+; Query again to verify that the record was prefetched and stored in the ECS
+; cache (because the server replied with ECS this time)
+STEP 14 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.com. IN A
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+       00 08 00 05     ; OPC, optlen
+       00 01 08 00     ; ip4, source 8, scope 0
+       7f              ; 127.0.0.0/8
+HEX_EDNSDATA_END
+ENTRY_END
+
+; This record came from the ECS cache
+STEP 15 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ttl
+REPLY QR RD RA DO NOERROR
+SECTION QUESTION
+www.example.com.               IN A
+SECTION ANSWER
+www.example.com.       8       IN A    10.20.30.40
+SECTION AUTHORITY
+example.com.           3598    IN NS   ns.example.com.
+SECTION ADDITIONAL
+HEX_EDNSDATA_BEGIN
+       00 08 00 05     ; OPC, optlen
+       00 01 08 08     ; ip4, source 8, scope 0
+       7f              ; 127.0.0.0/8
+HEX_EDNSDATA_END
+ns.example.com.                3598    IN A    1.2.3.4
+ENTRY_END
+
+SCENARIO_END