]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
add a system test for the prefetch bug
authorEvan Hunt <each@isc.org>
Fri, 28 May 2021 02:55:12 +0000 (19:55 -0700)
committerEvan Hunt <each@isc.org>
Sun, 30 May 2021 07:04:01 +0000 (00:04 -0700)
Ensure that if prefetch is triggered as a result of a query
restart, it won't have the TRYSTALE_ONTIMEOUT flag set.

bin/tests/system/serve-stale/ans2/ans.pl
bin/tests/system/serve-stale/clean.sh
bin/tests/system/serve-stale/ns3/named8.conf.in
bin/tests/system/serve-stale/tests.sh

index a046417e09c8ae657a2fdaa2203511871fba72f5..7a40f50a42180eecac5abb6792e8621395f98f58 100644 (file)
@@ -26,7 +26,12 @@ sub rmpid { unlink "ans.pid"; exit 1; };
 $SIG{INT} = \&rmpid;
 $SIG{TERM} = \&rmpid;
 
+# If send_response is set, the server will respond, otherwise the query will
+# be dropped.
 my $send_response = 1;
+# If slow_response is set, a lookup for the CNAME target (target.example) is
+# delayed. Other lookups will not be delayed.
+my $slow_response = 0;
 
 my $localaddr = "10.53.0.2";
 
@@ -49,6 +54,8 @@ my $TXT = "data.example 2 IN TXT \"A text record with a 2 second ttl\"";
 my $LONGTXT = "longttl.example 600 IN TXT \"A text record with a 600 second ttl\"";
 my $CAA = "othertype.example 2 IN CAA 0 issue \"ca1.example.net\"";
 my $negSOA = "example 2 IN SOA . . 0 0 0 0 300";
+my $CNAME = "cname.example 7 IN CNAME target.example";
+my $TARGET = "target.example 9 IN A $localaddr";
 
 sub reply_handler {
     my ($qname, $qclass, $qtype) = @_;
@@ -75,6 +82,15 @@ sub reply_handler {
        }
        $rcode = "NOERROR";
         return ($rcode, \@ans, \@auth, \@add, { aa => 1 });
+    } elsif ($qname eq "slowdown" ) {
+       if ($qtype eq "TXT") {
+           $send_response = 1;
+           $slow_response = 1;
+            my $rr = new Net::DNS::RR("$qname 0 $qclass TXT \"$send_response\"");
+            push @ans, $rr;
+       }
+       $rcode = "NOERROR";
+        return ($rcode, \@ans, \@auth, \@add, { aa => 1 });
     }
 
     # If we are not responding to queries we are done.
@@ -118,7 +134,7 @@ sub reply_handler {
        }
        $rcode = "NOERROR";
     } elsif ($qname eq "a-only.example") {
-        if ($qtype eq "A") {
+       if ($qtype eq "A") {
            my $rr = new Net::DNS::RR("a-only.example 2 IN A $localaddr");
            push @ans, $rr;
        } else {
@@ -126,6 +142,28 @@ sub reply_handler {
            push @auth, $rr;
        }
        $rcode = "NOERROR";
+    } elsif ($qname eq "cname.example") {
+       if ($qtype eq "A") {
+           my $rr = new Net::DNS::RR($CNAME);
+           push @ans, $rr;
+       } else {
+           my $rr = new Net::DNS::RR($negSOA);
+           push @auth, $rr;
+       }
+       $rcode = "NOERROR";
+    } elsif ($qname eq "target.example") {
+       if ($slow_response) {
+                print "  Sleeping 3 seconds\n";
+               sleep(3);
+       }
+       if ($qtype eq "A") {
+           my $rr = new Net::DNS::RR($TARGET);
+           push @ans, $rr;
+       } else {
+           my $rr = new Net::DNS::RR($negSOA);
+           push @auth, $rr;
+       }
+       $rcode = "NOERROR";
     } elsif ($qname eq "longttl.example") {
        if ($qtype eq "TXT") {
            my $rr = new Net::DNS::RR($LONGTXT);
index a089574d370e3d642183ae92f7db816c531ff047..3415ccd004b55e5ec0bde966d02d66d5ca791c01 100644 (file)
@@ -7,7 +7,7 @@
 # See the COPYRIGHT file distributed with this work for additional
 # information regarding copyright ownership.
 
-rm -f dig.out.test*
+rm -f dig.out*
 rm -f ns*/named.conf
 rm -f ns*/root.bk
 rm -f rndc.out.test*
index 49802f7f07d3c5446d7d82353797d2ae971dbcbe..3c135af04f3ddc512d8991c7596d4a5a59ab4718 100644 (file)
@@ -29,11 +29,12 @@ options {
        recursion yes;
        stale-answer-enable yes;
        stale-cache-enable yes;
-        stale-answer-client-timeout 1800;
+       stale-answer-client-timeout 1800;
+       prefetch 2 8;
        dns64 2001:aaaa::/96 {
                clients { any; };
-                mapped { any; };
-        };
+               mapped { any; };
+       };
 };
 
 zone "." {
index 740c8b1c4b03561433669b8065d4c42ec9ebdf99..df58b48b2954e5b2bff946262f57c3bd74fab37e 100755 (executable)
@@ -2244,12 +2244,14 @@ status=$((status+ret))
 
 n=$((n+1))
 echo_i "check DNS64 processing of a stale negative answer ($n)"
+ret=0
 # configure ns3 with dns64
 copy_setports ns3/named8.conf.in ns3/named.conf
 rndc_reload ns3 10.53.0.3
-# flush cache, enable ans2 responses
+# flush cache, enable ans2 responses, make sure serve-stale is on
 $RNDCCMD 10.53.0.3 flush > rndc.out.test$n.1 2>&1 || ret=1
 $DIG -p ${PORT} @10.53.0.2 txt enable > /dev/null
+$RNDCCMD 10.53.0.3 serve-stale on > rndc.out.test$n.2 2>&1 || ret=1
 # prime the cache with an AAAA NXRRSET response
 $DIG -p ${PORT} @10.53.0.3 a-only.example AAAA > dig.out.1.test$n
 grep "status: NOERROR" dig.out.1.test$n > /dev/null || ret=1
@@ -2269,5 +2271,77 @@ grep "2001:aaaa" dig.out.2.test$n > /dev/null || ret=1
 if [ $ret != 0 ]; then echo_i "failed"; fi
 status=$((status+ret))
 
+###########################################################
+# Test serve-stale's interaction with prefetch processing #
+###########################################################
+echo_i "test serve-stale's interaction with prefetch processing"
+
+# Test case for #2733, ensuring that prefetch queries do not trigger
+# a lookup due to stale-answer-client-timeout.
+#
+# 1. Cache the following records:
+#    cname.example 7 IN CNAME target.example.
+#    target.example 9 IN A <addr>.
+# 2. Let the CNAME RRset expire.
+# 3. Query for 'cname.example/A'.
+#
+# This starts recursion because cname.example/CNAME is expired.
+# The authoritative server is up so likely it will respond before
+#  stale-answer-client-timeout is triggered.
+# The 'target.example/A' RRset is found in cache with a positive value
+#  and is eligble for prefetching.
+# A prefetch is done for 'target.example/A', our ans2 server will
+#  delay the request.
+# The 'prefetch_done()' callback should have the right event type
+#  (DNS_EVENT_FETCHDONE).
+
+# flush cache
+n=$((n+1))
+echo_i "flush cache ($n)"
+ret=0
+$RNDCCMD 10.53.0.3 flushtree example > rndc.out.test$n.1 2>&1 || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+# prime the cache with CNAME and A; CNAME expires sooner
+n=$((n+1))
+echo_i "prime cache cname.example (stale-answer-client-timeout 1.8) ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.3 cname.example A > dig.out.test$n
+grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 2," dig.out.test$n > /dev/null || ret=1
+grep "cname\.example\..*7.*IN.*CNAME.*target\.example\." dig.out.test$n > /dev/null || ret=1
+grep "target\.example\..*9.*IN.*A" dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+# wait for the CNAME to be stale; A will still be valid and in prefetch window.
+# (the longer TTL is needed, otherwise data won't be prefetch-eligible.)
+sleep 7
+
+# re-enable auth responses, but with a delay answering the A
+n=$((n+1))
+echo_i "delay responses from authoritative server ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.2 txt slowdown  > dig.out.test$n
+grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
+grep "TXT.\"1\"" dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
+# resend the query and wait in the background; we should get a stale answer
+n=$((n+1))
+echo_i "check prefetch processing of a stale CNAME target ($n)"
+ret=0
+$DIG -p ${PORT} @10.53.0.3 cname.example A > dig.out.test$n &
+sleep 2
+wait
+grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
+grep "ANSWER: 2," dig.out.test$n > /dev/null || ret=1
+grep "cname\.example\..*7.*IN.*CNAME.*target\.example\." dig.out.test$n > /dev/null || ret=1
+grep "target\.example\..*[1-2].*IN.*A" dig.out.test$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=$((status+ret))
+
 echo_i "exit status: $status"
 [ $status -eq 0 ] || exit 1