From 4ee526cb6d3c34ea2736154e15dbc19211e08321 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Fri, 27 Mar 2026 10:32:48 +0100 Subject: [PATCH] Add serve-stale test case for CNAME to A 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). --- .../system/serve_stale/ns1/named.conf.j2 | 1 + .../system/serve_stale/ns1/named4.conf.in | 1 + .../system/serve_stale/ns3/named.conf.j2 | 1 + .../system/serve_stale/ns3/named1.conf.j2 | 1 + .../system/serve_stale/ns3/named2.conf.j2 | 1 + .../system/serve_stale/ns3/named3.conf.j2 | 1 + .../system/serve_stale/ns3/named4.conf.j2 | 1 + .../system/serve_stale/ns3/named5.conf.j2 | 1 + .../system/serve_stale/ns3/named6.conf.j2 | 1 + .../system/serve_stale/ns3/named7.conf.j2 | 1 + .../system/serve_stale/ns3/named9.conf.j2 | 1 + bin/tests/system/serve_stale/tests.sh | 83 +++++++++++++++++++ .../serve_stale/tests_sh_serve_stale.py | 1 + 13 files changed, 95 insertions(+) diff --git a/bin/tests/system/serve_stale/ns1/named.conf.j2 b/bin/tests/system/serve_stale/ns1/named.conf.j2 index 3dff62358c..17b09dd400 100644 --- a/bin/tests/system/serve_stale/ns1/named.conf.j2 +++ b/bin/tests/system/serve_stale/ns1/named.conf.j2 @@ -42,5 +42,6 @@ zone "." { zone "stale.test" { type primary; file "stale.test.db"; + allow-update { any; }; }; {% endif %} diff --git a/bin/tests/system/serve_stale/ns1/named4.conf.in b/bin/tests/system/serve_stale/ns1/named4.conf.in index 92c485542c..28eb0fd67b 100644 --- a/bin/tests/system/serve_stale/ns1/named4.conf.in +++ b/bin/tests/system/serve_stale/ns1/named4.conf.in @@ -34,4 +34,5 @@ zone "." { zone "stale.test" { type primary; file "stale.test.db"; + allow-update { any; }; }; diff --git a/bin/tests/system/serve_stale/ns3/named.conf.j2 b/bin/tests/system/serve_stale/ns3/named.conf.j2 index aff0b00327..227daa0703 100644 --- a/bin/tests/system/serve_stale/ns3/named.conf.j2 +++ b/bin/tests/system/serve_stale/ns3/named.conf.j2 @@ -18,6 +18,7 @@ options { recursion yes; dnssec-validation no; qname-minimization off; + prefetch 0; stale-answer-enable yes; stale-cache-enable yes; diff --git a/bin/tests/system/serve_stale/ns3/named1.conf.j2 b/bin/tests/system/serve_stale/ns3/named1.conf.j2 index 165dacfe1b..c67313e0bf 100644 --- a/bin/tests/system/serve_stale/ns3/named1.conf.j2 +++ b/bin/tests/system/serve_stale/ns3/named1.conf.j2 @@ -19,6 +19,7 @@ options { dump-file "named_dump3.db"; stale-cache-enable yes; dnssec-validation no; + prefetch 0; }; zone "." { diff --git a/bin/tests/system/serve_stale/ns3/named2.conf.j2 b/bin/tests/system/serve_stale/ns3/named2.conf.j2 index 6537de9fa5..f6ad7954f3 100644 --- a/bin/tests/system/serve_stale/ns3/named2.conf.j2 +++ b/bin/tests/system/serve_stale/ns3/named2.conf.j2 @@ -29,6 +29,7 @@ options { max-stale-ttl 3600; resolver-query-timeout 30000; # 30 seconds qname-minimization disabled; + prefetch 0; }; zone "." { diff --git a/bin/tests/system/serve_stale/ns3/named3.conf.j2 b/bin/tests/system/serve_stale/ns3/named3.conf.j2 index 65bddea352..0661a7cc5e 100644 --- a/bin/tests/system/serve_stale/ns3/named3.conf.j2 +++ b/bin/tests/system/serve_stale/ns3/named3.conf.j2 @@ -27,6 +27,7 @@ options { stale-refresh-time 0; max-stale-ttl 3600; resolver-query-timeout 10000; # 10 seconds + prefetch 0; }; zone "." { diff --git a/bin/tests/system/serve_stale/ns3/named4.conf.j2 b/bin/tests/system/serve_stale/ns3/named4.conf.j2 index dbca82b3a4..85da1d1bf9 100644 --- a/bin/tests/system/serve_stale/ns3/named4.conf.j2 +++ b/bin/tests/system/serve_stale/ns3/named4.conf.j2 @@ -29,6 +29,7 @@ options { resolver-query-timeout 10000; # 10 seconds max-stale-ttl 3600; recursive-clients 10; + prefetch 0; }; zone "." { diff --git a/bin/tests/system/serve_stale/ns3/named5.conf.j2 b/bin/tests/system/serve_stale/ns3/named5.conf.j2 index 753a84ba3f..845ee820b6 100644 --- a/bin/tests/system/serve_stale/ns3/named5.conf.j2 +++ b/bin/tests/system/serve_stale/ns3/named5.conf.j2 @@ -28,6 +28,7 @@ options { stale-refresh-time 4; resolver-query-timeout 10000; # 10 seconds max-stale-ttl 3600; + prefetch 0; }; zone "." { diff --git a/bin/tests/system/serve_stale/ns3/named6.conf.j2 b/bin/tests/system/serve_stale/ns3/named6.conf.j2 index d23ec8515a..59a3266af3 100644 --- a/bin/tests/system/serve_stale/ns3/named6.conf.j2 +++ b/bin/tests/system/serve_stale/ns3/named6.conf.j2 @@ -25,6 +25,7 @@ options { fetches-per-zone 1 fail; fetches-per-server 1 fail; max-stale-ttl 3600; + prefetch 0; }; zone "." { diff --git a/bin/tests/system/serve_stale/ns3/named7.conf.j2 b/bin/tests/system/serve_stale/ns3/named7.conf.j2 index 8558640109..79b197bbd1 100644 --- a/bin/tests/system/serve_stale/ns3/named7.conf.j2 +++ b/bin/tests/system/serve_stale/ns3/named7.conf.j2 @@ -33,6 +33,7 @@ options { fetches-per-zone 1 fail; fetches-per-server 1 fail; max-stale-ttl 3600; + prefetch 0; }; zone "." { diff --git a/bin/tests/system/serve_stale/ns3/named9.conf.j2 b/bin/tests/system/serve_stale/ns3/named9.conf.j2 index cac3de04bf..dd46102be7 100644 --- a/bin/tests/system/serve_stale/ns3/named9.conf.j2 +++ b/bin/tests/system/serve_stale/ns3/named9.conf.j2 @@ -21,6 +21,7 @@ options { stale-cache-enable yes; stale-answer-ttl 3; stale-answer-client-timeout 0; + prefetch 0; }; zone "." { diff --git a/bin/tests/system/serve_stale/tests.sh b/bin/tests/system/serve_stale/tests.sh index 71d7468c8b..90841afe6a 100755 --- a/bin/tests/system/serve_stale/tests.sh +++ b/bin/tests/system/serve_stale/tests.sh @@ -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. # #################################################################### diff --git a/bin/tests/system/serve_stale/tests_sh_serve_stale.py b/bin/tests/system/serve_stale/tests_sh_serve_stale.py index 1f96485cd2..b7bb320a5e 100644 --- a/bin/tests/system/serve_stale/tests_sh_serve_stale.py +++ b/bin/tests/system/serve_stale/tests_sh_serve_stale.py @@ -22,6 +22,7 @@ pytestmark = pytest.mark.extra_artifacts( "ns*/named_dump*", "ns*/named.stats*", "ns*/root.bk", + "ns1/stale.test.db.jnl", ] )