]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add serve-stale test case for CNAME to A
authorMatthijs Mekking <matthijs@isc.org>
Fri, 27 Mar 2026 09:32:48 +0000 (10:32 +0100)
committerMatthijs Mekking <matthijs@isc.org>
Sun, 17 May 2026 08:42:05 +0000 (08:42 +0000)
Add a serve-stale system test case where the authority changes a
CNAME RRset to A (at cname2.stale.test). The CNAME that is in the
cache is stale and should be refreshed. The target A record (at
a2.stale.test) has a longer TTL and is also still in the cache. The
next query should return the refreshed A RRset to the client.

Then the authority changes back the A RRset to CNAME. The A RRset
has become stale and should be refreshed. The next query should
return the refreshed CNAME RRset plus the already cached
a2.stale.test A record.

This test requires ns1 to allow dynamic updates to stale.test, and
prefetch to be disabled. The latter is to ensure the record is not
prefetched, but only refreshed when stale (and logs the expected
"an attempt to refresh the RRset" messages).

13 files changed:
bin/tests/system/serve_stale/ns1/named.conf.j2
bin/tests/system/serve_stale/ns1/named4.conf.in
bin/tests/system/serve_stale/ns3/named.conf.j2
bin/tests/system/serve_stale/ns3/named1.conf.j2
bin/tests/system/serve_stale/ns3/named2.conf.j2
bin/tests/system/serve_stale/ns3/named3.conf.j2
bin/tests/system/serve_stale/ns3/named4.conf.j2
bin/tests/system/serve_stale/ns3/named5.conf.j2
bin/tests/system/serve_stale/ns3/named6.conf.j2
bin/tests/system/serve_stale/ns3/named7.conf.j2
bin/tests/system/serve_stale/ns3/named9.conf.j2
bin/tests/system/serve_stale/tests.sh
bin/tests/system/serve_stale/tests_sh_serve_stale.py

index 3dff62358cc359f6f9f3e70f6734370a3c450158..17b09dd40007fd17b0ae4c5ef2544b7878a25b78 100644 (file)
@@ -42,5 +42,6 @@ zone "." {
 zone "stale.test" {
        type primary;
        file "stale.test.db";
+       allow-update { any; };
 };
 {% endif %}
index 92c485542c34b9183179fe57abba1cfed806e4eb..28eb0fd67b2be23d1d7f841ed53cf7e963b6f0ed 100644 (file)
@@ -34,4 +34,5 @@ zone "." {
 zone "stale.test" {
        type primary;
        file "stale.test.db";
+       allow-update { any; };
 };
index aff0b003275e66e44f0cd7cce9d5cc32759dd15f..227daa0703f8c7ac0cad5fc262e605097ec5ec33 100644 (file)
@@ -18,6 +18,7 @@ options {
        recursion yes;
        dnssec-validation no;
        qname-minimization off;
+       prefetch 0;
 
        stale-answer-enable yes;
        stale-cache-enable yes;
index 165dacfe1bfe88dcd6c6ad5e358e24b3e1e2a507..c67313e0bf306a498a8206c99cc2424ccdac2216 100644 (file)
@@ -19,6 +19,7 @@ options {
        dump-file "named_dump3.db";
        stale-cache-enable yes;
        dnssec-validation no;
+       prefetch 0;
 };
 
 zone "." {
index 6537de9fa59fe59dfbd06500e0a1f824242198c1..f6ad7954f3553d3da75b2e7835d22cb4385f9716 100644 (file)
@@ -29,6 +29,7 @@ options {
        max-stale-ttl 3600;
        resolver-query-timeout 30000; # 30 seconds
        qname-minimization disabled;
+       prefetch 0;
 };
 
 zone "." {
index 65bddea352b78a722607eb6b5f7d4bb4cada3c70..0661a7cc5e164621b203a9c550a6d8a5da443d5a 100644 (file)
@@ -27,6 +27,7 @@ options {
        stale-refresh-time 0;
        max-stale-ttl 3600;
        resolver-query-timeout 10000; # 10 seconds
+       prefetch 0;
 };
 
 zone "." {
index dbca82b3a48ae879d43e379072fa07232fcbbea4..85da1d1bf9ebc525c0ead6de5d6e8c8b4ee97c55 100644 (file)
@@ -29,6 +29,7 @@ options {
        resolver-query-timeout 10000; # 10 seconds
        max-stale-ttl 3600;
        recursive-clients 10;
+       prefetch 0;
 };
 
 zone "." {
index 753a84ba3ff32eb0bf4e608ad51c11935338bbc2..845ee820b61fcf3bc6fe4010c675a00d7839f05b 100644 (file)
@@ -28,6 +28,7 @@ options {
        stale-refresh-time 4;
        resolver-query-timeout 10000; # 10 seconds
        max-stale-ttl 3600;
+       prefetch 0;
 };
 
 zone "." {
index d23ec8515a7054ec95720b409d21e0c6ed208ab0..59a3266af38e81733f72fba91876279d5ce91e6a 100644 (file)
@@ -25,6 +25,7 @@ options {
        fetches-per-zone 1 fail;
        fetches-per-server 1 fail;
        max-stale-ttl 3600;
+       prefetch 0;
 };
 
 zone "." {
index 85586401094ccf181ce84be30eaf2850b81f644a..79b197bbd148ac21862802f4a36ab597db913a25 100644 (file)
@@ -33,6 +33,7 @@ options {
        fetches-per-zone 1 fail;
        fetches-per-server 1 fail;
        max-stale-ttl 3600;
+       prefetch 0;
 };
 
 zone "." {
index cac3de04bfbb30440f88bb5ec06218d5047b19b0..dd46102be7680c0cd3cc32a3c94bf9d92b0f66a3 100644 (file)
@@ -21,6 +21,7 @@ options {
        stale-cache-enable yes;
        stale-answer-ttl 3;
        stale-answer-client-timeout 0;
+       prefetch 0;
 };
 
 zone "." {
index 71d7468c8b1f0cbe33c83a177c86b3348e8266ae..90841afe6aa4c850991f9621e3d0c436c020c3cc 100755 (executable)
@@ -2359,6 +2359,89 @@ grep "cname-b3\.stale\.test\..*3.*IN.*A.*192\.0\.2\.2" dig.out.test$n >/dev/null
 if [ $ret != 0 ]; then echo_i "failed"; fi
 status=$((status + ret))
 
+# Change CNAME to A.
+n=$((n + 1))
+echo_i "change cname2.stale.test. CNAME to A (stale-answer-client-timeout 0) ($n)"
+ret=0
+(
+  echo zone stale.test.
+  echo server 10.53.0.1 "${PORT}"
+  echo update del cname2.stale.test. CNAME a2.stale.test.
+  echo update add cname2.stale.test. 1 A 192.0.0.2
+  echo send
+) | $NSUPDATE || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status + ret))
+
+n=$((n + 1))
+ret=0
+echo_i "check stale cname2.stale.test A comes from cache (stale-answer-client-timeout 0) ($n)"
+nextpart ns3/named.run >/dev/null
+$DIG -p ${PORT} @10.53.0.3 cname2.stale.test A >dig.out.test$n || ret=1
+wait_for_log 5 "cname2.stale.test A stale answer used, an attempt to refresh the RRset" ns3/named.run || ret=1
+grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
+grep "EDE: 3 (Stale Answer): (stale data prioritized over lookup)" dig.out.test$n >/dev/null || ret=1
+grep "ANSWER: 2," dig.out.test$n >/dev/null || ret=1
+grep "cname2\.stale\.test\..*3.*IN.*CNAME.*a2\.stale\.test\." dig.out.test$n >/dev/null || ret=1
+# We can't reliably test the TTL of the a2.stale.test A record.
+grep "a2\.stale\.test\..*IN.*A.*192\.0\.2\.2" dig.out.test$n >/dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=$((status + ret))
+
+n=$((n + 1))
+ret=0
+echo_i "check stale cname2.stale.test A is refreshed (stale-answer-client-timeout 0) ($n)"
+nextpart ns3/named.run >/dev/null
+$DIG -p ${PORT} @10.53.0.3 cname2.stale.test A >dig.out.test$n || ret=1
+grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
+grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
+grep "cname2\.stale\.test\..*IN.*A.*192\.0\.0\.2" dig.out.test$n >/dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=$((status + ret))
+
+# Change A to CNAME.
+n=$((n + 1))
+echo_i "change cname2.stale.test. A to CNAME (stale-answer-client-timeout 0) ($n)"
+ret=0
+(
+  echo zone stale.test.
+  echo server 10.53.0.1 "${PORT}"
+  echo update del cname2.stale.test. A 192.0.0.2
+  echo update add cname2.stale.test. 1 CNAME a2.stale.test.
+  echo send
+) | $NSUPDATE || ret=1
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status + ret))
+
+# Allow A record to become stale.
+sleep 1
+
+n=$((n + 1))
+ret=0
+echo_i "check stale cname2.stale.test A comes from cache (stale-answer-client-timeout 0) ($n)"
+nextpart ns3/named.run >/dev/null
+$DIG -p ${PORT} @10.53.0.3 cname2.stale.test A >dig.out.test$n || ret=1
+wait_for_log 5 "cname2.stale.test A stale answer used, an attempt to refresh the RRset" ns3/named.run || ret=1
+grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
+grep "EDE: 3 (Stale Answer): (stale data prioritized over lookup)" dig.out.test$n >/dev/null || ret=1
+grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
+grep "cname2\.stale\.test\..*3.*IN.*A.*192\.0\.0\.2" dig.out.test$n >/dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=$((status + ret))
+
+n=$((n + 1))
+ret=0
+echo_i "check stale cname2.stale.test A is refreshed (stale-answer-client-timeout 0) ($n)"
+nextpart ns3/named.run >/dev/null
+$DIG -p ${PORT} @10.53.0.3 cname2.stale.test A >dig.out.test$n || ret=1
+grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
+grep "ANSWER: 2," dig.out.test$n >/dev/null || ret=1
+# We can't reliably test the TTL of the these records.
+grep "cname2\.stale\.test\..*IN.*CNAME.*a2\.stale\.test\." dig.out.test$n >/dev/null || ret=1
+grep "a2\.stale\.test\..*IN.*A.*192\.0\.2\.2" dig.out.test$n >/dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=$((status + ret))
+
 ####################################################################
 # Test for stale-answer-client-timeout 0 and stale-refresh-time 4. #
 ####################################################################
index 1f96485cd2e9540d673d39fc914a821b30b70561..b7bb320a5e27fc2b48fe1c84fcff4cc614ce1e17 100644 (file)
@@ -22,6 +22,7 @@ pytestmark = pytest.mark.extra_artifacts(
         "ns*/named_dump*",
         "ns*/named.stats*",
         "ns*/root.bk",
+        "ns1/stale.test.db.jnl",
     ]
 )