1#!/bin/sh
2
3# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
4#
5# SPDX-License-Identifier: MPL-2.0
6#
7# This Source Code Form is subject to the terms of the Mozilla Public
8# License, v. 2.0.  If a copy of the MPL was not distributed with this
9# file, you can obtain one at https://mozilla.org/MPL/2.0/.
10#
11# See the COPYRIGHT file distributed with this work for additional
12# information regarding copyright ownership.
13
14set -e
15
16. ../conf.sh
17
18RNDCCMD="$RNDC -c ../_common/rndc.conf -p ${CONTROLPORT} -s"
19DIG="$DIG +time=12 +tries=1"
20
21max_stale_ttl=$(sed -ne 's,^[[:space:]]*max-stale-ttl \([[:digit:]]*\).*,\1,p' $TOP_SRCDIR/bin/named/config.c)
22stale_answer_ttl=$(sed -ne 's,^[[:space:]]*stale-answer-ttl \([[:digit:]]*\).*,\1,p' $TOP_SRCDIR/bin/named/config.c)
23
24status=0
25n=0
26
27#
28# First test server with serve-stale options set.
29#
30echo_i "test server with serve-stale options set"
31
32n=$((n + 1))
33echo_i "prime cache longttl.example TXT ($n)"
34ret=0
35$DIG -p ${PORT} @10.53.0.1 longttl.example TXT >dig.out.test$n
36grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
37grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
38if [ $ret != 0 ]; then echo_i "failed"; fi
39status=$((status + ret))
40
41n=$((n + 1))
42echo_i "prime cache data.example TXT ($n)"
43ret=0
44$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$n
45grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
46grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
47if [ $ret != 0 ]; then echo_i "failed"; fi
48status=$((status + ret))
49
50n=$((n + 1))
51echo_i "prime cache othertype.example CAA ($n)"
52ret=0
53$DIG -p ${PORT} @10.53.0.1 othertype.example CAA >dig.out.test$n
54grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
55grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
56if [ $ret != 0 ]; then echo_i "failed"; fi
57status=$((status + ret))
58
59n=$((n + 1))
60echo_i "prime cache nodata.example TXT ($n)"
61ret=0
62$DIG -p ${PORT} @10.53.0.1 nodata.example TXT >dig.out.test$n
63grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
64grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
65if [ $ret != 0 ]; then echo_i "failed"; fi
66status=$((status + ret))
67
68n=$((n + 1))
69echo_i "prime cache nxdomain.example TXT ($n)"
70ret=0
71$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT >dig.out.test$n
72grep "status: NXDOMAIN" dig.out.test$n >/dev/null || ret=1
73grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
74if [ $ret != 0 ]; then echo_i "failed"; fi
75status=$((status + ret))
76
77n=$((n + 1))
78echo_i "verify prime cache statistics ($n)"
79ret=0
80rm -f ns1/named.stats
81$RNDCCMD 10.53.0.1 stats >/dev/null 2>&1
82[ -f ns1/named.stats ] || ret=1
83cp ns1/named.stats ns1/named.stats.$n
84# Check first 10 lines of Cache DB statistics.  After prime queries, we expect
85# two active TXT, one active Others, one nxrrset TXT, and one NXDOMAIN.
86grep -A 10 "++ Cache DB RRsets ++" ns1/named.stats.$n >ns1/named.stats.$n.cachedb || ret=1
87grep "1 Others" ns1/named.stats.$n.cachedb >/dev/null || ret=1
88grep "2 TXT" ns1/named.stats.$n.cachedb >/dev/null || ret=1
89grep "1 !TXT" ns1/named.stats.$n.cachedb >/dev/null || ret=1
90grep "1 NXDOMAIN" ns1/named.stats.$n.cachedb >/dev/null || ret=1
91if [ $ret != 0 ]; then echo_i "failed"; fi
92status=$((status + ret))
93
94n=$((n + 1))
95echo_i "disable responses from authoritative server ($n)"
96ret=0
97$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
98grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
99grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
100if [ $ret != 0 ]; then echo_i "failed"; fi
101status=$((status + ret))
102
103n=$((n + 1))
104echo_i "check 'rndc serve-stale status' ($n)"
105ret=0
106$RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1
107grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=4 max-stale-ttl=3600 stale-refresh-time=30)' rndc.out.test$n >/dev/null || ret=1
108if [ $ret != 0 ]; then echo_i "failed"; fi
109status=$((status + ret))
110
111sleep 2
112
113# Run rndc dumpdb, test whether the stale data has correct comment printed.
114# The max-stale-ttl is 3600 seconds, so the comment should say the data is
115# stale for somewhere between 3500-3599 seconds.
116echo_i "check rndc dump stale data.example ($n)"
117rndc_dumpdb ns1 || ret=1
118awk '/; stale/ { x=$0; getline; print x, $0}' ns1/named_dump.db.test$n \
119  | grep "; stale data\.example.*3[56]...*TXT.*A text record with a 2 second ttl" >/dev/null 2>&1 || ret=1
120# Also make sure the not expired data does not have a stale comment.
121awk '/; authanswer/ { x=$0; getline; print x, $0}' ns1/named_dump.db.test$n \
122  | grep "; authanswer longttl\.example.*[56]...*TXT.*A text record with a 600 second ttl" >/dev/null 2>&1 || ret=1
123if [ $ret != 0 ]; then echo_i "failed"; fi
124status=$((status + ret))
125
126echo_i "sending queries for tests $((n + 1))-$((n + 5))..."
127$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$((n + 1)) &
128$DIG -p ${PORT} @10.53.0.1 longttl.example TXT >dig.out.test$((n + 2)) &
129$DIG -p ${PORT} @10.53.0.1 othertype.example CAA >dig.out.test$((n + 3)) &
130$DIG -p ${PORT} @10.53.0.1 nodata.example TXT >dig.out.test$((n + 4)) &
131$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT >dig.out.test$((n + 5)) &
132
133wait
134
135n=$((n + 1))
136echo_i "check stale data.example TXT ($n)"
137ret=0
138grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
139grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
140grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
141grep "data\.example\..*4.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
142if [ $ret != 0 ]; then echo_i "failed"; fi
143status=$((status + ret))
144
145n=$((n + 1))
146echo_i "check non-stale longttl.example TXT ($n)"
147ret=0
148grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
149grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
150grep "EDE" dig.out.test$n >/dev/null && ret=1
151grep "longttl\.example\..*59[0-9].*IN.*TXT.*A text record with a 600 second ttl" dig.out.test$n >/dev/null || ret=1
152if [ $ret != 0 ]; then echo_i "failed"; fi
153status=$((status + ret))
154
155n=$((n + 1))
156echo_i "check stale othertype.example CAA ($n)"
157ret=0
158grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
159grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
160grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
161grep "othertype\.example\..*4.*IN.*CAA.*0.*issue" dig.out.test$n >/dev/null || ret=1
162if [ $ret != 0 ]; then echo_i "failed"; fi
163status=$((status + ret))
164
165n=$((n + 1))
166echo_i "check stale nodata.example TXT ($n)"
167ret=0
168grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
169grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
170grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
171grep "example\..*4.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
172if [ $ret != 0 ]; then echo_i "failed"; fi
173status=$((status + ret))
174
175n=$((n + 1))
176echo_i "check stale nxdomain.example TXT ($n)"
177ret=0
178grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
179grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
180if [ $ret != 0 ]; then echo_i "failed"; fi
181status=$((status + ret))
182
183n=$((n + 1))
184echo_i "verify stale cache statistics ($n)"
185ret=0
186rm -f ns1/named.stats
187$RNDCCMD 10.53.0.1 stats >/dev/null 2>&1
188[ -f ns1/named.stats ] || ret=1
189cp ns1/named.stats ns1/named.stats.$n
190# Check first 10 lines of Cache DB statistics.  After serve-stale queries, we
191# expect one active TXT RRset, one stale TXT, one stale nxrrset TXT, and one
192# stale NXDOMAIN.
193grep -A 10 "++ Cache DB RRsets ++" ns1/named.stats.$n >ns1/named.stats.$n.cachedb || ret=1
194grep "1 TXT" ns1/named.stats.$n.cachedb >/dev/null || ret=1
195grep "1 #Others" ns1/named.stats.$n.cachedb >/dev/null || ret=1
196grep "1 #TXT" ns1/named.stats.$n.cachedb >/dev/null || ret=1
197grep "1 #!TXT" ns1/named.stats.$n.cachedb >/dev/null || ret=1
198status=$((status + ret))
199if [ $ret != 0 ]; then echo_i "failed"; fi
200
201# Test stale-refresh-time when serve-stale is enabled via configuration.
202# Steps for testing stale-refresh-time option (default).
203# 1. Prime cache data.example txt
204# 2. Disable responses from authoritative server.
205# 3. Sleep for TTL duration so rrset TTL expires (2 sec)
206# 4. Query data.example
207# 5. Check if response come from stale rrset (4 sec TTL)
208# 6. Enable responses from authoritative server.
209# 7. Query data.example
210# 8. Check if response come from stale rrset, since the query
211#    is still within stale-refresh-time window.
212n=$((n + 1))
213echo_i "check 'rndc serve-stale status' ($n)"
214ret=0
215$RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1
216grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=4 max-stale-ttl=3600 stale-refresh-time=30)' rndc.out.test$n >/dev/null || ret=1
217if [ $ret != 0 ]; then echo_i "failed"; fi
218status=$((status + ret))
219
220# Step 1-3 done above.
221
222# Step 4.
223n=$((n + 1))
224echo_i "sending query for test ($n)"
225$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$n
226
227# Step 5.
228echo_i "check stale data.example TXT (stale-refresh-time) ($n)"
229ret=0
230grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
231grep "EDE: 3 (Stale Answer): (query within stale refresh time window)" dig.out.test$n >/dev/null || ret=1
232grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
233grep "data\.example\..*4.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
234if [ $ret != 0 ]; then echo_i "failed"; fi
235status=$((status + ret))
236
237# Step 6.
238n=$((n + 1))
239echo_i "enable responses from authoritative server ($n)"
240ret=0
241$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
242grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
243grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
244if [ $ret != 0 ]; then echo_i "failed"; fi
245status=$((status + ret))
246
247# Step 7.
248echo_i "sending query for test $((n + 1))"
249$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$((n + 1))
250
251# Step 8.
252n=$((n + 1))
253echo_i "check stale data.example TXT comes from cache (stale-refresh-time) ($n)"
254ret=0
255grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
256grep "EDE: 3 (Stale Answer): (query within stale refresh time window)" dig.out.test$n >/dev/null || ret=1
257grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
258grep "data\.example\..*4.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
259if [ $ret != 0 ]; then echo_i "failed"; fi
260status=$((status + ret))
261
262#
263# Test interaction with local zone
264#
265
266n=$((n + 1))
267echo_i "check that serve-stale does not recurse for local authoritative zone ($n)"
268ret=0
269
270num=0
271threshold=10
272while [ $num -lt $threshold ]; do
273
274  echo_i "dig test.serve.stale TXT ($n)"
275  $DIG -p ${PORT} @10.53.0.3 test.serve.stale TXT >dig.out.test$n.$num
276  grep "status: SERVFAIL" dig.out.test$n.$num >/dev/null || ret=1
277  if [ $ret != 0 ]; then num=$threshold; fi
278
279  sleep 1
280  num=$((num + 1))
281done
282if [ $ret != 0 ]; then echo_i "failed"; fi
283status=$((status + ret))
284
285#
286# Test disabling serve-stale via rndc.
287#
288
289n=$((n + 1))
290echo_i "updating ns1/named.conf ($n)"
291ret=0
292copy_setports ns1/named2.conf.in ns1/named.conf
293if [ $ret != 0 ]; then echo_i "failed"; fi
294status=$((status + ret))
295
296n=$((n + 1))
297echo_i "running 'rndc reload' ($n)"
298ret=0
299rndc_reload ns1 10.53.0.1
300if [ $ret != 0 ]; then echo_i "failed"; fi
301status=$((status + ret))
302
303n=$((n + 1))
304echo_i "check 'rndc serve-stale status' ($n)"
305ret=0
306$RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1
307grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=4 max-stale-ttl=3600 stale-refresh-time=0)' rndc.out.test$n >/dev/null || ret=1
308if [ $ret != 0 ]; then echo_i "failed"; fi
309status=$((status + ret))
310
311n=$((n + 1))
312echo_i "disable responses from authoritative server ($n)"
313ret=0
314$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
315grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
316grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
317if [ $ret != 0 ]; then echo_i "failed"; fi
318status=$((status + ret))
319
320n=$((n + 1))
321echo_i "running 'rndc serve-stale off' ($n)"
322ret=0
323$RNDCCMD 10.53.0.1 serve-stale off || ret=1
324if [ $ret != 0 ]; then echo_i "failed"; fi
325status=$((status + ret))
326
327n=$((n + 1))
328echo_i "check 'rndc serve-stale status' ($n)"
329ret=0
330$RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1
331grep '_default: stale cache enabled; stale answers disabled (stale-answer-ttl=4 max-stale-ttl=3600 stale-refresh-time=0)' rndc.out.test$n >/dev/null || ret=1
332if [ $ret != 0 ]; then echo_i "failed"; fi
333status=$((status + ret))
334
335echo_i "sending queries for tests $((n + 1))-$((n + 4))..."
336$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$((n + 1)) &
337$DIG -p ${PORT} @10.53.0.1 othertype.example CAA >dig.out.test$((n + 2)) &
338$DIG -p ${PORT} @10.53.0.1 nodata.example TXT >dig.out.test$((n + 3)) &
339$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT >dig.out.test$((n + 4)) &
340
341wait
342
343n=$((n + 1))
344echo_i "check stale data.example TXT (serve-stale off) ($n)"
345ret=0
346grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
347grep "EDE" dig.out.test$n >/dev/null && ret=1
348if [ $ret != 0 ]; then echo_i "failed"; fi
349status=$((status + ret))
350
351n=$((n + 1))
352echo_i "check stale othertype.example CAA (serve-stale off) ($n)"
353ret=0
354grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
355grep "EDE" dig.out.test$n >/dev/null && ret=1
356if [ $ret != 0 ]; then echo_i "failed"; fi
357status=$((status + ret))
358
359n=$((n + 1))
360echo_i "check stale nodata.example TXT (serve-stale off) ($n)"
361ret=0
362grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
363grep "EDE" dig.out.test$n >/dev/null && ret=1
364if [ $ret != 0 ]; then echo_i "failed"; fi
365status=$((status + ret))
366
367n=$((n + 1))
368echo_i "check stale nxdomain.example TXT (serve-stale off) ($n)"
369ret=0
370grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
371grep "EDE" dig.out.test$n >/dev/null && ret=1
372if [ $ret != 0 ]; then echo_i "failed"; fi
373status=$((status + ret))
374
375#
376# Test enabling serve-stale via rndc.
377#
378n=$((n + 1))
379echo_i "running 'rndc serve-stale on' ($n)"
380ret=0
381$RNDCCMD 10.53.0.1 serve-stale on || ret=1
382if [ $ret != 0 ]; then echo_i "failed"; fi
383status=$((status + ret))
384
385n=$((n + 1))
386echo_i "check 'rndc serve-stale status' ($n)"
387ret=0
388$RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1
389grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=4 max-stale-ttl=3600 stale-refresh-time=0)' rndc.out.test$n >/dev/null || ret=1
390if [ $ret != 0 ]; then echo_i "failed"; fi
391status=$((status + ret))
392
393echo_i "sending queries for tests $((n + 1))-$((n + 4))..."
394$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$((n + 1)) &
395$DIG -p ${PORT} @10.53.0.1 othertype.example CAA >dig.out.test$((n + 2)) &
396$DIG -p ${PORT} @10.53.0.1 nodata.example TXT >dig.out.test$((n + 3)) &
397$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT >dig.out.test$((n + 4)) &
398
399wait
400
401n=$((n + 1))
402echo_i "check stale data.example TXT (serve-stale on) ($n)"
403ret=0
404grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
405grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
406grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
407grep "data\.example\..*4.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
408if [ $ret != 0 ]; then echo_i "failed"; fi
409status=$((status + ret))
410
411n=$((n + 1))
412echo_i "check stale othertype.example CAA (serve-stale on) ($n)"
413ret=0
414grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
415grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
416grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
417grep "othertype\.example\..*4.*IN.*CAA.*0.*issue" dig.out.test$n >/dev/null || ret=1
418if [ $ret != 0 ]; then echo_i "failed"; fi
419status=$((status + ret))
420
421n=$((n + 1))
422echo_i "check stale nodata.example TXT (serve-stale on) ($n)"
423ret=0
424grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
425grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
426grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
427grep "example\..*4.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
428if [ $ret != 0 ]; then echo_i "failed"; fi
429status=$((status + ret))
430
431n=$((n + 1))
432echo_i "check stale nxdomain.example TXT (serve-stale on) ($n)"
433ret=0
434grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
435grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
436if [ $ret != 0 ]; then echo_i "failed"; fi
437status=$((status + ret))
438
439n=$((n + 1))
440echo_i "running 'rndc serve-stale off' ($n)"
441ret=0
442$RNDCCMD 10.53.0.1 serve-stale off || ret=1
443if [ $ret != 0 ]; then echo_i "failed"; fi
444status=$((status + ret))
445
446n=$((n + 1))
447echo_i "running 'rndc serve-stale reset' ($n)"
448ret=0
449$RNDCCMD 10.53.0.1 serve-stale reset || ret=1
450if [ $ret != 0 ]; then echo_i "failed"; fi
451status=$((status + ret))
452
453n=$((n + 1))
454echo_i "check 'rndc serve-stale status' ($n)"
455ret=0
456$RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1
457grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=4 max-stale-ttl=3600 stale-refresh-time=0)' rndc.out.test$n >/dev/null || ret=1
458if [ $ret != 0 ]; then echo_i "failed"; fi
459status=$((status + ret))
460
461echo_i "sending queries for tests $((n + 1))-$((n + 4))..."
462$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$((n + 1)) &
463$DIG -p ${PORT} @10.53.0.1 othertype.example CAA >dig.out.test$((n + 2)) &
464$DIG -p ${PORT} @10.53.0.1 nodata.example TXT >dig.out.test$((n + 3)) &
465$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT >dig.out.test$((n + 4)) &
466
467wait
468
469n=$((n + 1))
470echo_i "check stale data.example TXT (serve-stale reset) ($n)"
471ret=0
472grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
473grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
474grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
475grep "data\.example\..*4.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
476if [ $ret != 0 ]; then echo_i "failed"; fi
477status=$((status + ret))
478
479n=$((n + 1))
480echo_i "check stale othertype.example CAA (serve-stale reset) ($n)"
481ret=0
482grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
483grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
484grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
485grep "othertype.example\..*4.*IN.*CAA.*0.*issue" dig.out.test$n >/dev/null || ret=1
486if [ $ret != 0 ]; then echo_i "failed"; fi
487status=$((status + ret))
488
489n=$((n + 1))
490echo_i "check stale nodata.example TXT (serve-stale reset) ($n)"
491ret=0
492grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
493grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
494grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
495grep "example\..*4.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
496if [ $ret != 0 ]; then echo_i "failed"; fi
497status=$((status + ret))
498
499n=$((n + 1))
500echo_i "check stale nxdomain.example TXT (serve-stale reset) ($n)"
501ret=0
502grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
503grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
504if [ $ret != 0 ]; then echo_i "failed"; fi
505status=$((status + ret))
506
507n=$((n + 1))
508echo_i "running 'rndc serve-stale off' ($n)"
509ret=0
510$RNDCCMD 10.53.0.1 serve-stale off || ret=1
511if [ $ret != 0 ]; then echo_i "failed"; fi
512status=$((status + ret))
513
514n=$((n + 1))
515echo_i "check 'rndc serve-stale status' ($n)"
516ret=0
517$RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1
518grep '_default: stale cache enabled; stale answers disabled (stale-answer-ttl=4 max-stale-ttl=3600 stale-refresh-time=0)' rndc.out.test$n >/dev/null || ret=1
519if [ $ret != 0 ]; then echo_i "failed"; fi
520status=$((status + ret))
521
522#
523# Update named.conf.
524# Test server with low max-stale-ttl.
525#
526echo_i "test server with serve-stale options set, low max-stale-ttl"
527
528n=$((n + 1))
529echo_i "updating ns1/named.conf ($n)"
530ret=0
531copy_setports ns1/named3.conf.in ns1/named.conf
532if [ $ret != 0 ]; then echo_i "failed"; fi
533status=$((status + ret))
534
535n=$((n + 1))
536echo_i "running 'rndc reload' ($n)"
537ret=0
538rndc_reload ns1 10.53.0.1
539if [ $ret != 0 ]; then echo_i "failed"; fi
540status=$((status + ret))
541
542n=$((n + 1))
543echo_i "check 'rndc serve-stale status' ($n)"
544ret=0
545$RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1
546grep '_default: stale cache enabled; stale answers disabled (stale-answer-ttl=3 max-stale-ttl=20 stale-refresh-time=30)' rndc.out.test$n >/dev/null || ret=1
547if [ $ret != 0 ]; then echo_i "failed"; fi
548status=$((status + ret))
549
550n=$((n + 1))
551echo_i "flush cache, re-enable serve-stale and query again ($n)"
552ret=0
553$RNDCCMD 10.53.0.1 flushtree example >rndc.out.test$n.1 2>&1 || ret=1
554$RNDCCMD 10.53.0.1 serve-stale on >rndc.out.test$n.2 2>&1 || ret=1
555$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$n
556grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
557grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
558if [ $ret != 0 ]; then echo_i "failed"; fi
559status=$((status + ret))
560
561n=$((n + 1))
562echo_i "check 'rndc serve-stale status' ($n)"
563ret=0
564$RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1
565grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=3 max-stale-ttl=20 stale-refresh-time=30)' rndc.out.test$n >/dev/null || ret=1
566if [ $ret != 0 ]; then echo_i "failed"; fi
567status=$((status + ret))
568
569n=$((n + 1))
570echo_i "enable responses from authoritative server ($n)"
571ret=0
572$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
573grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
574grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
575if [ $ret != 0 ]; then echo_i "failed"; fi
576status=$((status + ret))
577
578n=$((n + 1))
579echo_i "prime cache longttl.example TXT (low max-stale-ttl) ($n)"
580ret=0
581$DIG -p ${PORT} @10.53.0.1 longttl.example TXT >dig.out.test$n
582grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
583grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
584if [ $ret != 0 ]; then echo_i "failed"; fi
585status=$((status + ret))
586
587n=$((n + 1))
588echo_i "prime cache data.example TXT (low max-stale-ttl) ($n)"
589ret=0
590$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$n
591grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
592grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
593if [ $ret != 0 ]; then echo_i "failed"; fi
594status=$((status + ret))
595
596n=$((n + 1))
597echo_i "prime cache othertype.example CAA (low max-stale-ttl) ($n)"
598ret=0
599$DIG -p ${PORT} @10.53.0.1 othertype.example CAA >dig.out.test$n
600grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
601grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
602if [ $ret != 0 ]; then echo_i "failed"; fi
603status=$((status + ret))
604
605n=$((n + 1))
606echo_i "prime cache nodata.example TXT (low max-stale-ttl) ($n)"
607ret=0
608$DIG -p ${PORT} @10.53.0.1 nodata.example TXT >dig.out.test$n
609grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
610grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
611if [ $ret != 0 ]; then echo_i "failed"; fi
612status=$((status + ret))
613
614n=$((n + 1))
615echo_i "prime cache nxdomain.example TXT (low max-stale-ttl) ($n)"
616ret=0
617$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT >dig.out.test$n
618grep "status: NXDOMAIN" dig.out.test$n >/dev/null || ret=1
619grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
620if [ $ret != 0 ]; then echo_i "failed"; fi
621status=$((status + ret))
622
623# Keep track of time so we can access these RRset later, when we expect them
624# to become ancient.
625t1=$($PERL -e 'print time()')
626
627n=$((n + 1))
628echo_i "verify prime cache statistics (low max-stale-ttl) ($n)"
629ret=0
630rm -f ns1/named.stats
631$RNDCCMD 10.53.0.1 stats >/dev/null 2>&1
632[ -f ns1/named.stats ] || ret=1
633cp ns1/named.stats ns1/named.stats.$n
634# Check first 10 lines of Cache DB statistics.  After prime queries, we expect
635# two active TXT RRsets, one active Others, one nxrrset TXT, and one NXDOMAIN.
636grep -A 10 "++ Cache DB RRsets ++" ns1/named.stats.$n >ns1/named.stats.$n.cachedb || ret=1
637grep "2 TXT" ns1/named.stats.$n.cachedb >/dev/null || ret=1
638grep "1 Others" ns1/named.stats.$n.cachedb >/dev/null || ret=1
639grep "1 !TXT" ns1/named.stats.$n.cachedb >/dev/null || ret=1
640grep "1 NXDOMAIN" ns1/named.stats.$n.cachedb >/dev/null || ret=1
641status=$((status + ret))
642if [ $ret != 0 ]; then echo_i "failed"; fi
643
644n=$((n + 1))
645echo_i "disable responses from authoritative server ($n)"
646ret=0
647$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
648grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
649grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
650if [ $ret != 0 ]; then echo_i "failed"; fi
651status=$((status + ret))
652
653sleep 2
654
655echo_i "sending queries for tests $((n + 1))-$((n + 4))..."
656$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$((n + 1)) &
657$DIG -p ${PORT} @10.53.0.1 othertype.example CAA >dig.out.test$((n + 2)) &
658$DIG -p ${PORT} @10.53.0.1 nodata.example TXT >dig.out.test$((n + 3)) &
659$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT >dig.out.test$((n + 4)) &
660
661wait
662
663n=$((n + 1))
664echo_i "check stale data.example TXT (low max-stale-ttl) ($n)"
665ret=0
666grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
667grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
668grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
669grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
670if [ $ret != 0 ]; then echo_i "failed"; fi
671status=$((status + ret))
672
673n=$((n + 1))
674echo_i "check stale othertype.example CAA (low max-stale-ttl) ($n)"
675ret=0
676grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
677grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
678grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
679grep "othertype\.example\..*3.*IN.*CAA.*0.*issue" dig.out.test$n >/dev/null || ret=1
680if [ $ret != 0 ]; then echo_i "failed"; fi
681status=$((status + ret))
682
683n=$((n + 1))
684echo_i "check stale nodata.example TXT (low max-stale-ttl) ($n)"
685ret=0
686grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
687grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
688grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
689grep "example\..*3.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
690if [ $ret != 0 ]; then echo_i "failed"; fi
691status=$((status + ret))
692
693n=$((n + 1))
694echo_i "check stale nxdomain.example TXT (low max-stale-ttl) ($n)"
695ret=0
696grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
697grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
698if [ $ret != 0 ]; then echo_i "failed"; fi
699status=$((status + ret))
700
701n=$((n + 1))
702echo_i "verify stale cache statistics (low max-stale-ttl) ($n)"
703ret=0
704rm -f ns1/named.stats
705$RNDCCMD 10.53.0.1 stats >/dev/null 2>&1
706[ -f ns1/named.stats ] || ret=1
707cp ns1/named.stats ns1/named.stats.$n
708# Check first 10 lines of Cache DB statistics.  After serve-stale queries, we
709# expect one active TXT RRset, one stale TXT, one stale nxrrset TXT, and one
710# stale NXDOMAIN.
711grep -A 10 "++ Cache DB RRsets ++" ns1/named.stats.$n >ns1/named.stats.$n.cachedb || ret=1
712grep "1 TXT" ns1/named.stats.$n.cachedb >/dev/null || ret=1
713grep "1 #TXT" ns1/named.stats.$n.cachedb >/dev/null || ret=1
714grep "1 #Others" ns1/named.stats.$n.cachedb >/dev/null || ret=1
715grep "1 #!TXT" ns1/named.stats.$n.cachedb >/dev/null || ret=1
716
717status=$((status + ret))
718if [ $ret != 0 ]; then echo_i "failed"; fi
719
720# Retrieve max-stale-ttl value.
721interval_to_ancient=$(grep 'max-stale-ttl' ns1/named3.conf.in | awk '{ print $2 }' | tr -d ';')
722# We add 2 seconds to it since this is the ttl value of the records being
723# tested.
724interval_to_ancient=$((interval_to_ancient + 2))
725t2=$($PERL -e 'print time()')
726elapsed=$((t2 - t1))
727
728# If elapsed time so far is less than max-stale-ttl + 2 seconds, then we sleep
729# enough to ensure that we'll ask for ancient RRsets in the next queries.
730if [ $elapsed -lt $interval_to_ancient ]; then
731  sleep $((interval_to_ancient - elapsed))
732fi
733
734echo_i "sending queries for tests $((n + 1))-$((n + 4))..."
735$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$((n + 1)) &
736$DIG -p ${PORT} @10.53.0.1 othertype.example CAA >dig.out.test$((n + 2)) &
737$DIG -p ${PORT} @10.53.0.1 nodata.example TXT >dig.out.test$((n + 3)) &
738$DIG -p ${PORT} @10.53.0.1 nxdomain.example TXT >dig.out.test$((n + 4)) &
739
740wait
741
742n=$((n + 1))
743echo_i "check ancient data.example TXT (low max-stale-ttl) ($n)"
744ret=0
745grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
746grep "EDE" dig.out.test$n >/dev/null && ret=1
747grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
748if [ $ret != 0 ]; then echo_i "failed"; fi
749status=$((status + ret))
750
751n=$((n + 1))
752echo_i "check ancient othertype.example CAA (low max-stale-ttl) ($n)"
753ret=0
754grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
755grep "EDE" dig.out.test$n >/dev/null && ret=1
756grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
757if [ $ret != 0 ]; then echo_i "failed"; fi
758status=$((status + ret))
759
760n=$((n + 1))
761echo_i "check ancient nodata.example TXT (low max-stale-ttl) ($n)"
762ret=0
763grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
764grep "EDE" dig.out.test$n >/dev/null && ret=1
765grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
766if [ $ret != 0 ]; then echo_i "failed"; fi
767status=$((status + ret))
768
769n=$((n + 1))
770echo_i "check ancient nxdomain.example TXT (low max-stale-ttl) ($n)"
771ret=0
772grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
773grep "EDE" dig.out.test$n >/dev/null && ret=1
774grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
775if [ $ret != 0 ]; then echo_i "failed"; fi
776status=$((status + ret))
777
778# Test stale-refresh-time when serve-stale is enabled via rndc.
779# Steps for testing stale-refresh-time option (default).
780# 1. Prime cache data.example txt
781# 2. Disable responses from authoritative server.
782# 3. Sleep for TTL duration so rrset TTL expires (2 sec)
783# 4. Query data.example
784# 5. Check if response come from stale rrset (3 sec TTL)
785# 6. Enable responses from authoritative server.
786# 7. Query data.example
787# 8. Check if response come from stale rrset, since the query
788#    is within stale-refresh-time window.
789n=$((n + 1))
790echo_i "flush cache, enable responses from authoritative server ($n)"
791ret=0
792$RNDCCMD 10.53.0.1 flushtree example >rndc.out.test$n.1 2>&1 || ret=1
793$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
794grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
795grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
796if [ $ret != 0 ]; then echo_i "failed"; fi
797status=$((status + ret))
798
799n=$((n + 1))
800echo_i "check 'rndc serve-stale status' ($n)"
801ret=0
802$RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1
803grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=3 max-stale-ttl=20 stale-refresh-time=30)' rndc.out.test$n >/dev/null || ret=1
804if [ $ret != 0 ]; then echo_i "failed"; fi
805status=$((status + ret))
806
807# Step 1.
808n=$((n + 1))
809echo_i "prime cache data.example TXT (stale-refresh-time rndc) ($n)"
810ret=0
811$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$n
812grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
813grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
814grep "data\.example\..*2.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
815if [ $ret != 0 ]; then echo_i "failed"; fi
816status=$((status + ret))
817
818# Step 2.
819n=$((n + 1))
820echo_i "disable responses from authoritative server ($n)"
821ret=0
822$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
823grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
824grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
825if [ $ret != 0 ]; then echo_i "failed"; fi
826status=$((status + ret))
827
828# Step 3.
829sleep 2
830
831# Step 4.
832n=$((n + 1))
833echo_i "sending query for test ($n)"
834$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$n
835
836# Step 5.
837echo_i "check stale data.example TXT (stale-refresh-time rndc) ($n)"
838ret=0
839grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
840grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
841grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
842grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
843if [ $ret != 0 ]; then echo_i "failed"; fi
844status=$((status + ret))
845
846# Step 6.
847n=$((n + 1))
848echo_i "enable responses from authoritative server ($n)"
849ret=0
850$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
851grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
852grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
853if [ $ret != 0 ]; then echo_i "failed"; fi
854status=$((status + ret))
855
856# Step 7.
857echo_i "sending query for test $((n + 1))"
858$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$((n + 1))
859
860# Step 8.
861n=$((n + 1))
862echo_i "check stale data.example TXT comes from cache (stale-refresh-time rndc) ($n)"
863ret=0
864grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
865grep "EDE: 3 (Stale Answer): (query within stale refresh time window)" dig.out.test$n >/dev/null || ret=1
866grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
867grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
868if [ $ret != 0 ]; then echo_i "failed"; fi
869status=$((status + ret))
870
871# Steps for testing stale-refresh-time option (disabled).
872# 1. Prime cache data.example txt
873# 2. Disable responses from authoritative server.
874# 3. Sleep for TTL duration so rrset TTL expires (2 sec)
875# 4. Query data.example
876# 5. Check if response come from stale rrset (3 sec TTL)
877# 6. Enable responses from authoritative server.
878# 7. Query data.example
879# 8. Check if response come from stale rrset, since the query
880#    is within stale-refresh-time window.
881n=$((n + 1))
882echo_i "updating ns1/named.conf ($n)"
883ret=0
884copy_setports ns1/named4.conf.in ns1/named.conf
885if [ $ret != 0 ]; then echo_i "failed"; fi
886status=$((status + ret))
887
888n=$((n + 1))
889echo_i "running 'rndc reload' ($n)"
890ret=0
891rndc_reload ns1 10.53.0.1
892if [ $ret != 0 ]; then echo_i "failed"; fi
893status=$((status + ret))
894
895n=$((n + 1))
896echo_i "check 'rndc serve-stale status' ($n)"
897ret=0
898$RNDCCMD 10.53.0.1 serve-stale status >rndc.out.test$n 2>&1 || ret=1
899grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=3 max-stale-ttl=20 stale-refresh-time=0)' rndc.out.test$n >/dev/null || ret=1
900if [ $ret != 0 ]; then echo_i "failed"; fi
901status=$((status + ret))
902
903n=$((n + 1))
904echo_i "flush cache, enable responses from authoritative server ($n)"
905ret=0
906$RNDCCMD 10.53.0.1 flushtree example >rndc.out.test$n.1 2>&1 || ret=1
907$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
908grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
909grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
910if [ $ret != 0 ]; then echo_i "failed"; fi
911status=$((status + ret))
912
913# Step 1.
914n=$((n + 1))
915echo_i "prime cache data.example TXT (stale-refresh-time disabled) ($n)"
916ret=0
917$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$n
918grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
919grep "EDE" dig.out.test$n >/dev/null && ret=1
920grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
921grep "data\.example\..*2.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
922if [ $ret != 0 ]; then echo_i "failed"; fi
923status=$((status + ret))
924
925# Step 2.
926n=$((n + 1))
927echo_i "disable responses from authoritative server ($n)"
928ret=0
929$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
930grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
931grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
932if [ $ret != 0 ]; then echo_i "failed"; fi
933status=$((status + ret))
934
935# Step 3.
936sleep 2
937
938# Step 4.
939n=$((n + 1))
940echo_i "sending query for test ($n)"
941$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$n
942
943# Step 5.
944echo_i "check stale data.example TXT (stale-refresh-time disabled) ($n)"
945ret=0
946grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
947grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
948grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
949grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
950if [ $ret != 0 ]; then echo_i "failed"; fi
951status=$((status + ret))
952
953# Step 6.
954n=$((n + 1))
955echo_i "enable responses from authoritative server ($n)"
956ret=0
957$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
958grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
959grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
960if [ $ret != 0 ]; then echo_i "failed"; fi
961status=$((status + ret))
962
963# Step 7.
964echo_i "sending query for test $((n + 1))"
965$DIG -p ${PORT} @10.53.0.1 data.example TXT >dig.out.test$((n + 1))
966
967# Step 8.
968n=$((n + 1))
969echo_i "check data.example TXT comes from authoritative (stale-refresh-time disabled) ($n)"
970ret=0
971grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
972grep "EDE" dig.out.test$n >/dev/null && ret=1
973grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
974grep "data\.example\..*2.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
975if [ $ret != 0 ]; then echo_i "failed"; fi
976status=$((status + ret))
977
978#
979# Now test server with no serve-stale options set.
980#
981echo_i "test server with no serve-stale options set"
982
983n=$((n + 1))
984echo_i "updating ns3/named.conf ($n)"
985ret=0
986copy_setports ns3/named1.conf.in ns3/named.conf
987if [ $ret != 0 ]; then echo_i "failed"; fi
988status=$((status + ret))
989
990echo_i "restart ns3"
991stop_server --use-rndc --port ${CONTROLPORT} ns3
992start_server --noclean --restart --port ${PORT} ns3
993
994n=$((n + 1))
995echo_i "enable responses from authoritative server ($n)"
996ret=0
997$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
998grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
999grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
1000if [ $ret != 0 ]; then echo_i "failed"; fi
1001status=$((status + ret))
1002
1003n=$((n + 1))
1004echo_i "prime cache longttl.example TXT (max-stale-ttl default) ($n)"
1005ret=0
1006$DIG -p ${PORT} @10.53.0.3 longttl.example TXT >dig.out.test$n
1007grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1008grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1009if [ $ret != 0 ]; then echo_i "failed"; fi
1010status=$((status + ret))
1011
1012n=$((n + 1))
1013echo_i "prime cache data.example TXT (max-stale-ttl default) ($n)"
1014ret=0
1015$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
1016grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1017grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1018grep "data\.example\..*2.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
1019if [ $ret != 0 ]; then echo_i "failed"; fi
1020status=$((status + ret))
1021
1022n=$((n + 1))
1023echo_i "prime cache othertype.example CAA (max-stale-ttl default) ($n)"
1024ret=0
1025$DIG -p ${PORT} @10.53.0.3 othertype.example CAA >dig.out.test$n
1026grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1027grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1028grep "othertype\.example\..*2.*IN.*CAA.*0.*issue" dig.out.test$n >/dev/null || ret=1
1029if [ $ret != 0 ]; then echo_i "failed"; fi
1030status=$((status + ret))
1031
1032n=$((n + 1))
1033echo_i "prime cache nodata.example TXT (max-stale-ttl default) ($n)"
1034ret=0
1035$DIG -p ${PORT} @10.53.0.3 nodata.example TXT >dig.out.test$n
1036grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1037grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1038grep "example\..*2.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
1039if [ $ret != 0 ]; then echo_i "failed"; fi
1040status=$((status + ret))
1041
1042n=$((n + 1))
1043echo_i "prime cache nxdomain.example TXT (max-stale-ttl default) ($n)"
1044ret=0
1045$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT >dig.out.test$n
1046grep "status: NXDOMAIN" dig.out.test$n >/dev/null || ret=1
1047grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1048grep "example\..*2.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
1049if [ $ret != 0 ]; then echo_i "failed"; fi
1050status=$((status + ret))
1051
1052n=$((n + 1))
1053echo_i "verify prime cache statistics (max-stale-ttl default) ($n)"
1054ret=0
1055rm -f ns3/named.stats
1056$RNDCCMD 10.53.0.3 stats >/dev/null 2>&1
1057[ -f ns3/named.stats ] || ret=1
1058cp ns3/named.stats ns3/named.stats.$n
1059# Check first 10 lines of Cache DB statistics.  After prime queries, we expect
1060# two active TXT RRsets, one active Others, one nxrrset TXT, and one NXDOMAIN.
1061grep -A 10 "++ Cache DB RRsets ++" ns3/named.stats.$n >ns3/named.stats.$n.cachedb || ret=1
1062grep "2 TXT" ns3/named.stats.$n.cachedb >/dev/null || ret=1
1063grep "1 Others" ns3/named.stats.$n.cachedb >/dev/null || ret=1
1064grep "1 !TXT" ns3/named.stats.$n.cachedb >/dev/null || ret=1
1065grep "1 NXDOMAIN" ns3/named.stats.$n.cachedb >/dev/null || ret=1
1066status=$((status + ret))
1067if [ $ret != 0 ]; then echo_i "failed"; fi
1068
1069n=$((n + 1))
1070echo_i "disable responses from authoritative server ($n)"
1071ret=0
1072$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
1073grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1074grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
1075if [ $ret != 0 ]; then echo_i "failed"; fi
1076status=$((status + ret))
1077
1078n=$((n + 1))
1079echo_i "check 'rndc serve-stale status' ($n)"
1080ret=0
1081$RNDCCMD 10.53.0.3 serve-stale status >rndc.out.test$n 2>&1 || ret=1
1082grep "_default: stale cache enabled; stale answers disabled (stale-answer-ttl=$stale_answer_ttl max-stale-ttl=$max_stale_ttl stale-refresh-time=30)" rndc.out.test$n >/dev/null || ret=1
1083if [ $ret != 0 ]; then echo_i "failed"; fi
1084status=$((status + ret))
1085
1086sleep 2
1087
1088echo_i "sending queries for tests $((n + 1))-$((n + 4))..."
1089$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$((n + 1)) &
1090$DIG -p ${PORT} @10.53.0.3 othertype.example CAA >dig.out.test$((n + 2)) &
1091$DIG -p ${PORT} @10.53.0.3 nodata.example TXT >dig.out.test$((n + 3)) &
1092$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT >dig.out.test$((n + 4)) &
1093
1094wait
1095
1096n=$((n + 1))
1097echo_i "check fail of data.example TXT (max-stale-ttl default) ($n)"
1098ret=0
1099grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1100grep "EDE" dig.out.test$n >/dev/null && ret=1
1101grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1102if [ $ret != 0 ]; then echo_i "failed"; fi
1103status=$((status + ret))
1104
1105n=$((n + 1))
1106echo_i "check fail of othertype.example CAA (max-stale-ttl default) ($n)"
1107ret=0
1108grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1109grep "EDE" dig.out.test$n >/dev/null && ret=1
1110grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1111if [ $ret != 0 ]; then echo_i "failed"; fi
1112status=$((status + ret))
1113
1114n=$((n + 1))
1115echo_i "check fail of nodata.example TXT (max-stale-ttl default) ($n)"
1116ret=0
1117grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1118grep "EDE" dig.out.test$n >/dev/null && ret=1
1119grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1120if [ $ret != 0 ]; then echo_i "failed"; fi
1121status=$((status + ret))
1122
1123n=$((n + 1))
1124echo_i "check fail of nxdomain.example TXT (max-stale-ttl default) ($n)"
1125ret=0
1126grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1127grep "EDE" dig.out.test$n >/dev/null && ret=1
1128grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1129if [ $ret != 0 ]; then echo_i "failed"; fi
1130status=$((status + ret))
1131
1132n=$((n + 1))
1133echo_i "verify stale cache statistics (max-stale-ttl default) ($n)"
1134ret=0
1135rm -f ns3/named.stats
1136$RNDCCMD 10.53.0.3 stats >/dev/null 2>&1
1137[ -f ns3/named.stats ] || ret=1
1138cp ns3/named.stats ns3/named.stats.$n
1139# Check first 10 lines of Cache DB statistics. After last queries, we expect
1140# one active TXT RRset, one stale TXT, one stale nxrrset TXT, and one stale
1141# NXDOMAIN.
1142grep -A 10 "++ Cache DB RRsets ++" ns3/named.stats.$n >ns3/named.stats.$n.cachedb || ret=1
1143grep "1 TXT" ns3/named.stats.$n.cachedb >/dev/null || ret=1
1144grep "1 #TXT" ns3/named.stats.$n.cachedb >/dev/null || ret=1
1145grep "1 #Others" ns3/named.stats.$n.cachedb >/dev/null || ret=1
1146grep "1 #!TXT" ns3/named.stats.$n.cachedb >/dev/null || ret=1
1147
1148status=$((status + ret))
1149if [ $ret != 0 ]; then echo_i "failed"; fi
1150
1151n=$((n + 1))
1152echo_i "check 'rndc serve-stale on' ($n)"
1153ret=0
1154$RNDCCMD 10.53.0.3 serve-stale on >rndc.out.test$n 2>&1 || ret=1
1155if [ $ret != 0 ]; then echo_i "failed"; fi
1156status=$((status + ret))
1157
1158n=$((n + 1))
1159echo_i "check 'rndc serve-stale status' ($n)"
1160ret=0
1161$RNDCCMD 10.53.0.3 serve-stale status >rndc.out.test$n 2>&1 || ret=1
1162grep "_default: stale cache enabled; stale answers enabled (stale-answer-ttl=$stale_answer_ttl max-stale-ttl=$max_stale_ttl stale-refresh-time=30)" rndc.out.test$n >/dev/null || ret=1
1163if [ $ret != 0 ]; then echo_i "failed"; fi
1164status=$((status + ret))
1165
1166sleep 2
1167
1168# Check that if we don't have stale data for a domain name, we will
1169# not answer anything until the resolver query timeout.
1170n=$((n + 1))
1171echo_i "check notincache.example TXT times out (max-stale-ttl default) ($n)"
1172ret=0
1173$DIG -p ${PORT} +tries=1 +timeout=3 @10.53.0.3 notfound.example TXT >dig.out.test$n 2>&1 && ret=1
1174grep "timed out" dig.out.test$n >/dev/null || ret=1
1175grep ";; no servers could be reached" dig.out.test$n >/dev/null || ret=1
1176if [ $ret != 0 ]; then echo_i "failed"; fi
1177status=$((status + ret))
1178
1179echo_i "sending queries for tests $((n + 1))-$((n + 4))..."
1180$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$((n + 1)) &
1181$DIG -p ${PORT} @10.53.0.3 othertype.example CAA >dig.out.test$((n + 2)) &
1182$DIG -p ${PORT} @10.53.0.3 nodata.example TXT >dig.out.test$((n + 3)) &
1183$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT >dig.out.test$((n + 4)) &
1184$DIG -p ${PORT} @10.53.0.3 notfound.example TXT >dig.out.test$((n + 5)) &
1185
1186wait
1187
1188n=$((n + 1))
1189echo_i "check data.example TXT (max-stale-ttl default) ($n)"
1190ret=0
1191grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1192grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
1193grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1194grep "data\.example\..*30.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
1195if [ $ret != 0 ]; then echo_i "failed"; fi
1196status=$((status + ret))
1197
1198n=$((n + 1))
1199echo_i "check othertype.example CAA (max-stale-ttl default) ($n)"
1200ret=0
1201grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1202grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
1203grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1204grep "example\..*30.*IN.*CAA.*0.*issue" dig.out.test$n >/dev/null || ret=1
1205if [ $ret != 0 ]; then echo_i "failed"; fi
1206status=$((status + ret))
1207
1208n=$((n + 1))
1209echo_i "check nodata.example TXT (max-stale-ttl default) ($n)"
1210ret=0
1211grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1212grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
1213grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1214grep "example\..*30.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
1215if [ $ret != 0 ]; then echo_i "failed"; fi
1216status=$((status + ret))
1217
1218n=$((n + 1))
1219echo_i "check nxdomain.example TXT (max-stale-ttl default) ($n)"
1220ret=0
1221grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1222grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1223if [ $ret != 0 ]; then echo_i "failed"; fi
1224status=$((status + ret))
1225
1226# The notfound.example check is different than nxdomain.example because
1227# we didn't send a prime query to add notfound.example to the cache.
1228n=$((n + 1))
1229echo_i "check notfound.example TXT (max-stale-ttl default) ($n)"
1230ret=0
1231grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1232grep "EDE" dig.out.test$n >/dev/null && ret=1
1233grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1234if [ $ret != 0 ]; then echo_i "failed"; fi
1235status=$((status + ret))
1236
1237#
1238# Now test server with serve-stale answers disabled.
1239#
1240echo_i "test server with serve-stale disabled"
1241
1242n=$((n + 1))
1243echo_i "enable responses from authoritative server ($n)"
1244ret=0
1245$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
1246grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1247grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
1248if [ $ret != 0 ]; then echo_i "failed"; fi
1249status=$((status + ret))
1250
1251n=$((n + 1))
1252echo_i "prime cache longttl.example TTL (serve-stale answers disabled) ($n)"
1253ret=0
1254$DIG -p ${PORT} @10.53.0.4 longttl.example TXT >dig.out.test$n
1255grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1256grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1257if [ $ret != 0 ]; then echo_i "failed"; fi
1258status=$((status + ret))
1259
1260n=$((n + 1))
1261echo_i "prime cache data.example TTL (serve-stale answers disabled) ($n)"
1262ret=0
1263$DIG -p ${PORT} @10.53.0.4 data.example TXT >dig.out.test$n
1264grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1265grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1266grep "data\.example\..*2.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
1267if [ $ret != 0 ]; then echo_i "failed"; fi
1268status=$((status + ret))
1269
1270n=$((n + 1))
1271echo_i "prime cache othertype.example CAA (serve-stale answers disabled) ($n)"
1272ret=0
1273$DIG -p ${PORT} @10.53.0.4 othertype.example CAA >dig.out.test$n
1274grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1275grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1276grep "othertype\.example\..*2.*IN.*CAA.*0.*issue" dig.out.test$n >/dev/null || ret=1
1277if [ $ret != 0 ]; then echo_i "failed"; fi
1278status=$((status + ret))
1279
1280n=$((n + 1))
1281echo_i "prime cache nodata.example TXT (serve-stale answers disabled) ($n)"
1282ret=0
1283$DIG -p ${PORT} @10.53.0.4 nodata.example TXT >dig.out.test$n
1284grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1285grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1286grep "example\..*2.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
1287if [ $ret != 0 ]; then echo_i "failed"; fi
1288status=$((status + ret))
1289
1290n=$((n + 1))
1291echo_i "prime cache nxdomain.example TXT (serve-stale answers disabled) ($n)"
1292ret=0
1293$DIG -p ${PORT} @10.53.0.4 nxdomain.example TXT >dig.out.test$n
1294grep "status: NXDOMAIN" dig.out.test$n >/dev/null || ret=1
1295grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1296grep "example\..*2.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
1297if [ $ret != 0 ]; then echo_i "failed"; fi
1298status=$((status + ret))
1299
1300n=$((n + 1))
1301echo_i "verify prime cache statistics (serve-stale answers disabled) ($n)"
1302ret=0
1303rm -f ns4/named.stats
1304$RNDCCMD 10.53.0.4 stats >/dev/null 2>&1
1305[ -f ns4/named.stats ] || ret=1
1306cp ns4/named.stats ns4/named.stats.$n
1307# Check first 10 lines of Cache DB statistics.  After prime queries, we expect
1308# two active TXT RRsets, one active Others, one nxrrset TXT, and one NXDOMAIN.
1309grep -A 10 "++ Cache DB RRsets ++" ns4/named.stats.$n >ns4/named.stats.$n.cachedb || ret=1
1310grep "2 TXT" ns4/named.stats.$n.cachedb >/dev/null || ret=1
1311grep "1 Others" ns4/named.stats.$n.cachedb >/dev/null || ret=1
1312grep "1 !TXT" ns4/named.stats.$n.cachedb >/dev/null || ret=1
1313grep "1 NXDOMAIN" ns4/named.stats.$n.cachedb >/dev/null || ret=1
1314status=$((status + ret))
1315if [ $ret != 0 ]; then echo_i "failed"; fi
1316
1317n=$((n + 1))
1318echo_i "disable responses from authoritative server ($n)"
1319ret=0
1320$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
1321grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1322grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
1323if [ $ret != 0 ]; then echo_i "failed"; fi
1324status=$((status + ret))
1325
1326n=$((n + 1))
1327echo_i "check 'rndc serve-stale status' ($n)"
1328ret=0
1329$RNDCCMD 10.53.0.4 serve-stale status >rndc.out.test$n 2>&1 || ret=1
1330grep "_default: stale cache enabled; stale answers disabled (stale-answer-ttl=$stale_answer_ttl max-stale-ttl=$max_stale_ttl stale-refresh-time=30)" rndc.out.test$n >/dev/null || ret=1
1331if [ $ret != 0 ]; then echo_i "failed"; fi
1332status=$((status + ret))
1333
1334sleep 2
1335
1336echo_i "sending queries for tests $((n + 1))-$((n + 4))..."
1337$DIG -p ${PORT} @10.53.0.4 data.example TXT >dig.out.test$((n + 1)) &
1338$DIG -p ${PORT} @10.53.0.4 othertype.example CAA >dig.out.test$((n + 2)) &
1339$DIG -p ${PORT} @10.53.0.4 nodata.example TXT >dig.out.test$((n + 3)) &
1340$DIG -p ${PORT} @10.53.0.4 nxdomain.example TXT >dig.out.test$((n + 4)) &
1341
1342wait
1343
1344n=$((n + 1))
1345echo_i "check fail of data.example TXT (serve-stale answers disabled) ($n)"
1346ret=0
1347grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1348grep "EDE" dig.out.test$n >/dev/null && ret=1
1349grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1350if [ $ret != 0 ]; then echo_i "failed"; fi
1351status=$((status + ret))
1352
1353n=$((n + 1))
1354echo_i "check fail of othertype.example TXT (serve-stale answers disabled) ($n)"
1355ret=0
1356grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1357grep "EDE" dig.out.test$n >/dev/null && ret=1
1358grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1359if [ $ret != 0 ]; then echo_i "failed"; fi
1360status=$((status + ret))
1361
1362n=$((n + 1))
1363echo_i "check fail of nodata.example TXT (serve-stale answers disabled) ($n)"
1364ret=0
1365grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1366grep "EDE" dig.out.test$n >/dev/null && ret=1
1367grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1368if [ $ret != 0 ]; then echo_i "failed"; fi
1369status=$((status + ret))
1370
1371n=$((n + 1))
1372echo_i "check fail of nxdomain.example TXT (serve-stale answers disabled) ($n)"
1373ret=0
1374grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1375grep "EDE" dig.out.test$n >/dev/null && ret=1
1376grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1377if [ $ret != 0 ]; then echo_i "failed"; fi
1378status=$((status + ret))
1379
1380n=$((n + 1))
1381echo_i "verify stale cache statistics (serve-stale answers disabled) ($n)"
1382ret=0
1383rm -f ns4/named.stats
1384$RNDCCMD 10.53.0.4 stats >/dev/null 2>&1
1385[ -f ns4/named.stats ] || ret=1
1386cp ns4/named.stats ns4/named.stats.$n
1387# Check first 10 lines of Cache DB statistics. After last queries, we expect
1388# one active TXT RRset, one stale TXT, one stale nxrrset TXT, and one stale
1389# NXDOMAIN.
1390grep -A 10 "++ Cache DB RRsets ++" ns4/named.stats.$n >ns4/named.stats.$n.cachedb || ret=1
1391grep "1 TXT" ns4/named.stats.$n.cachedb >/dev/null || ret=1
1392grep "1 #TXT" ns4/named.stats.$n.cachedb >/dev/null || ret=1
1393grep "1 #Others" ns4/named.stats.$n.cachedb >/dev/null || ret=1
1394grep "1 #!TXT" ns4/named.stats.$n.cachedb >/dev/null || ret=1
1395status=$((status + ret))
1396if [ $ret != 0 ]; then echo_i "failed"; fi
1397
1398# Dump the cache.
1399n=$((n + 1))
1400echo_i "dump the cache (serve-stale answers disabled) ($n)"
1401ret=0
1402rndc_dumpdb ns4 -cache || ret=1
1403if [ $ret != 0 ]; then echo_i "failed"; fi
1404status=$((status + ret))
1405
1406echo_i "stop ns4"
1407stop_server --use-rndc --port ${CONTROLPORT} ns4
1408
1409# Load the cache as if it was five minutes (RBTDB_VIRTUAL) older. Since
1410# max-stale-ttl defaults to a week, we need to adjust the date by one week and
1411# five minutes.
1412LASTWEEK=$(TZ=UTC perl -e 'my $now = time();
1413        my $oneWeekAgo = $now - 604800;
1414        my $fiveMinutesAgo = $oneWeekAgo - 300;
1415        my ($s, $m, $h, $d, $mo, $y) = (localtime($fiveMinutesAgo))[0, 1, 2, 3, 4, 5];
1416        printf("%04d%02d%02d%02d%02d%02d", $y+1900, $mo+1, $d, $h, $m, $s);')
1417
1418echo_i "mock the cache date to $LASTWEEK (serve-stale answers disabled) ($n)"
1419ret=0
1420sed -E "s/DATE [0-9]{14}/DATE $LASTWEEK/g" ns4/named_dump.db.test$n >ns4/named_dump.db.out || ret=1
1421cp ns4/named_dump.db.out ns4/named_dump.db
1422if [ $ret != 0 ]; then echo_i "failed"; fi
1423status=$((status + ret))
1424
1425echo_i "start ns4"
1426start_server --noclean --restart --port ${PORT} ns4
1427
1428n=$((n + 1))
1429echo_i "verify ancient cache statistics (serve-stale answers disabled) ($n)"
1430ret=0
1431rm -f ns4/named.stats
1432$RNDCCMD 10.53.0.4 stats #> /dev/null 2>&1
1433[ -f ns4/named.stats ] || ret=1
1434cp ns4/named.stats ns4/named.stats.$n
1435# Check first 10 lines of Cache DB statistics. After last queries, we expect
1436# everything to be removed or scheduled to be removed.
1437grep -A 10 "++ Cache DB RRsets ++" ns4/named.stats.$n >ns4/named.stats.$n.cachedb || ret=1
1438grep "#TXT" ns4/named.stats.$n.cachedb >/dev/null && ret=1
1439grep "#Others" ns4/named.stats.$n.cachedb >/dev/null && ret=1
1440grep "#!TXT" ns4/named.stats.$n.cachedb >/dev/null && ret=1
1441grep "#NXDOMAIN" ns4/named.stats.$n.cachedb >/dev/null && ret=1
1442status=$((status + ret))
1443if [ $ret != 0 ]; then echo_i "failed"; fi
1444
1445#
1446# Test the server with stale-cache disabled.
1447#
1448echo_i "test server with serve-stale cache disabled"
1449
1450n=$((n + 1))
1451echo_i "enable responses from authoritative server ($n)"
1452ret=0
1453$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
1454grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1455grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
1456if [ $ret != 0 ]; then echo_i "failed"; fi
1457status=$((status + ret))
1458
1459n=$((n + 1))
1460echo_i "prime cache longttl.example TXT (serve-stale cache disabled) ($n)"
1461ret=0
1462$DIG -p ${PORT} @10.53.0.5 longttl.example TXT >dig.out.test$n
1463grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1464grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1465if [ $ret != 0 ]; then echo_i "failed"; fi
1466status=$((status + ret))
1467
1468n=$((n + 1))
1469echo_i "prime cache data.example TXT (serve-stale cache disabled) ($n)"
1470ret=0
1471$DIG -p ${PORT} @10.53.0.5 data.example TXT >dig.out.test$n
1472grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1473grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1474grep "data\.example\..*2.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
1475if [ $ret != 0 ]; then echo_i "failed"; fi
1476status=$((status + ret))
1477
1478n=$((n + 1))
1479echo_i "prime cache othertype.example CAA (serve-stale cache disabled) ($n)"
1480ret=0
1481$DIG -p ${PORT} @10.53.0.5 othertype.example CAA >dig.out.test$n
1482grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1483grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1484grep "othertype\.example\..*2.*IN.*CAA.*0.*issue" dig.out.test$n >/dev/null || ret=1
1485if [ $ret != 0 ]; then echo_i "failed"; fi
1486status=$((status + ret))
1487
1488n=$((n + 1))
1489echo_i "prime cache nodata.example TXT (serve-stale cache disabled) ($n)"
1490ret=0
1491$DIG -p ${PORT} @10.53.0.5 nodata.example TXT >dig.out.test$n
1492grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1493grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1494grep "example\..*2.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
1495if [ $ret != 0 ]; then echo_i "failed"; fi
1496status=$((status + ret))
1497
1498n=$((n + 1))
1499echo_i "prime cache nxdomain.example TXT (serve-stale cache disabled) ($n)"
1500ret=0
1501$DIG -p ${PORT} @10.53.0.5 nxdomain.example TXT >dig.out.test$n
1502grep "status: NXDOMAIN" dig.out.test$n >/dev/null || ret=1
1503grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1504grep "example\..*2.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
1505if [ $ret != 0 ]; then echo_i "failed"; fi
1506status=$((status + ret))
1507
1508n=$((n + 1))
1509echo_i "verify prime cache statistics (serve-stale cache disabled) ($n)"
1510ret=0
1511rm -f ns5/named.stats
1512$RNDCCMD 10.53.0.5 stats >/dev/null 2>&1
1513[ -f ns5/named.stats ] || ret=1
1514cp ns5/named.stats ns5/named.stats.$n
1515# Check first 10 lines of Cache DB statistics.  After serve-stale queries,
1516# we expect two active TXT RRsets, one active Others, one nxrrset TXT, and
1517# one NXDOMAIN.
1518grep -A 10 "++ Cache DB RRsets ++" ns5/named.stats.$n >ns5/named.stats.$n.cachedb || ret=1
1519grep "2 TXT" ns5/named.stats.$n.cachedb >/dev/null || ret=1
1520grep "1 Others" ns5/named.stats.$n.cachedb >/dev/null || ret=1
1521grep "1 !TXT" ns5/named.stats.$n.cachedb >/dev/null || ret=1
1522status=$((status + ret))
1523if [ $ret != 0 ]; then echo_i "failed"; fi
1524
1525n=$((n + 1))
1526echo_i "disable responses from authoritative server ($n)"
1527ret=0
1528$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
1529grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1530grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
1531if [ $ret != 0 ]; then echo_i "failed"; fi
1532status=$((status + ret))
1533
1534n=$((n + 1))
1535echo_i "check 'rndc serve-stale status' ($n)"
1536ret=0
1537$RNDCCMD 10.53.0.5 serve-stale status >rndc.out.test$n 2>&1 || ret=1
1538grep "_default: stale cache disabled; stale answers unavailable" rndc.out.test$n >/dev/null || ret=1
1539if [ $ret != 0 ]; then echo_i "failed"; fi
1540status=$((status + ret))
1541
1542sleep 2
1543
1544echo_i "sending queries for tests $((n + 1))-$((n + 4))..."
1545$DIG -p ${PORT} @10.53.0.5 data.example TXT >dig.out.test$((n + 1)) &
1546$DIG -p ${PORT} @10.53.0.5 othertype.example CAA >dig.out.test$((n + 2)) &
1547$DIG -p ${PORT} @10.53.0.5 nodata.example TXT >dig.out.test$((n + 3)) &
1548$DIG -p ${PORT} @10.53.0.5 nxdomain.example TXT >dig.out.test$((n + 4)) &
1549
1550wait
1551
1552n=$((n + 1))
1553echo_i "check fail of data.example TXT (serve-stale cache disabled) ($n)"
1554ret=0
1555grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1556grep "EDE" dig.out.test$n >/dev/null && ret=1
1557grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1558if [ $ret != 0 ]; then echo_i "failed"; fi
1559status=$((status + ret))
1560
1561n=$((n + 1))
1562echo_i "check fail of othertype.example CAA (serve-stale cache disabled) ($n)"
1563ret=0
1564grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1565grep "EDE" dig.out.test$n >/dev/null && ret=1
1566grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1567if [ $ret != 0 ]; then echo_i "failed"; fi
1568status=$((status + ret))
1569
1570n=$((n + 1))
1571echo_i "check fail of nodata.example TXT (serve-stale cache disabled) ($n)"
1572ret=0
1573grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1574grep "EDE" dig.out.test$n >/dev/null && ret=1
1575grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1576if [ $ret != 0 ]; then echo_i "failed"; fi
1577status=$((status + ret))
1578
1579n=$((n + 1))
1580echo_i "check fail of nxdomain.example TXT (serve-stale cache disabled) ($n)"
1581ret=0
1582grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
1583grep "EDE" dig.out.test$n >/dev/null && ret=1
1584grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1585if [ $ret != 0 ]; then echo_i "failed"; fi
1586status=$((status + ret))
1587
1588n=$((n + 1))
1589echo_i "verify stale cache statistics (serve-stale cache disabled) ($n)"
1590ret=0
1591rm -f ns5/named.stats
1592$RNDCCMD 10.53.0.5 stats >/dev/null 2>&1
1593[ -f ns5/named.stats ] || ret=1
1594cp ns5/named.stats ns5/named.stats.$n
1595# Check first 10 lines of Cache DB statistics.  After serve-stale queries,
1596# we expect one active TXT (longttl) and the rest to be expired from cache,
1597# but since we keep everything for 5 minutes (RBTDB_VIRTUAL) in the cache
1598# after expiry, they still show up in the stats.
1599grep -A 10 "++ Cache DB RRsets ++" ns5/named.stats.$n >ns5/named.stats.$n.cachedb || ret=1
1600grep -F "1 Others" ns5/named.stats.$n.cachedb >/dev/null || ret=1
1601grep -F "2 TXT" ns5/named.stats.$n.cachedb >/dev/null || ret=1
1602grep -F "1 !TXT" ns5/named.stats.$n.cachedb >/dev/null || ret=1
1603status=$((status + ret))
1604if [ $ret != 0 ]; then echo_i "failed"; fi
1605
1606# Dump the cache.
1607n=$((n + 1))
1608echo_i "dump the cache (serve-stale cache disabled) ($n)"
1609ret=0
1610rndc_dumpdb ns5 || ret=1
1611if [ $ret != 0 ]; then echo_i "failed"; fi
1612status=$((status + ret))
1613# Check that expired records are not dumped.
1614ret=0
1615grep "; expired since .* (awaiting cleanup)" ns5/named_dump.db.test$n && ret=1
1616if [ $ret != 0 ]; then echo_i "failed"; fi
1617status=$((status + ret))
1618
1619# Dump the cache including expired entries.
1620n=$((n + 1))
1621echo_i "dump the cache including expired entries (serve-stale cache disabled) ($n)"
1622ret=0
1623rndc_dumpdb ns5 -expired || ret=1
1624if [ $ret != 0 ]; then echo_i "failed"; fi
1625status=$((status + ret))
1626
1627# Check that expired records are dumped.
1628echo_i "check rndc dump expired data.example ($n)"
1629ret=0
1630awk '/; expired/ { x=$0; getline; print x, $0}' ns5/named_dump.db.test$n \
1631  | grep "; expired since .* (awaiting cleanup) data\.example\..*A text record with a 2 second ttl" >/dev/null 2>&1 || ret=1
1632awk '/; expired/ { x=$0; getline; print x, $0}' ns5/named_dump.db.test$n \
1633  | grep "; expired since .* (awaiting cleanup) nodata\.example\." >/dev/null 2>&1 || ret=1
1634awk '/; expired/ { x=$0; getline; print x, $0}' ns5/named_dump.db.test$n \
1635  | grep "; expired since .* (awaiting cleanup) nxdomain\.example\." >/dev/null 2>&1 || ret=1
1636awk '/; expired/ { x=$0; getline; print x, $0}' ns5/named_dump.db.test$n \
1637  | grep "; expired since .* (awaiting cleanup) othertype\.example\." >/dev/null 2>&1 || ret=1
1638# Also make sure the not expired data does not have an expired comment.
1639awk '/; authanswer/ { x=$0; getline; print x, $0}' ns5/named_dump.db.test$n \
1640  | grep "; authanswer longttl\.example.*A text record with a 600 second ttl" >/dev/null 2>&1 || ret=1
1641if [ $ret != 0 ]; then echo_i "failed"; fi
1642status=$((status + ret))
1643
1644echo_i "stop ns5"
1645stop_server --use-rndc --port ${CONTROLPORT} ns5
1646
1647# Load the cache as if it was five minutes (RBTDB_VIRTUAL) older.
1648cp ns5/named_dump.db.test$n ns5/named_dump.db
1649FIVEMINUTESAGO=$(TZ=UTC perl -e 'my $now = time();
1650        my $fiveMinutesAgo = 300;
1651        my ($s, $m, $h, $d, $mo, $y) = (localtime($fiveMinutesAgo))[0, 1, 2, 3, 4, 5];
1652        printf("%04d%02d%02d%02d%02d%02d", $y+1900, $mo+1, $d, $h, $m, $s);')
1653
1654n=$((n + 1))
1655echo_i "mock the cache date to $FIVEMINUTESAGO (serve-stale cache disabled) ($n)"
1656ret=0
1657sed -E "s/DATE [0-9]{14}/DATE $FIVEMINUTESAGO/g" ns5/named_dump.db >ns5/named_dump.db.out || ret=1
1658cp ns5/named_dump.db.out ns5/named_dump.db
1659if [ $ret != 0 ]; then echo_i "failed"; fi
1660status=$((status + ret))
1661
1662echo_i "start ns5"
1663start_server --noclean --restart --port ${PORT} ns5
1664
1665n=$((n + 1))
1666echo_i "verify ancient cache statistics (serve-stale cache disabled) ($n)"
1667ret=0
1668rm -f ns5/named.stats
1669$RNDCCMD 10.53.0.5 stats #> /dev/null 2>&1
1670[ -f ns5/named.stats ] || ret=1
1671cp ns5/named.stats ns5/named.stats.$n
1672# Check first 10 lines of Cache DB statistics. After last queries, we expect
1673# everything to be removed or scheduled to be removed.
1674grep -A 10 "++ Cache DB RRsets ++" ns5/named.stats.$n >ns5/named.stats.$n.cachedb || ret=1
1675grep -F "#TXT" ns5/named.stats.$n.cachedb >/dev/null && ret=1
1676grep -F "#Others" ns5/named.stats.$n.cachedb >/dev/null && ret=1
1677grep -F "#!TXT" ns5/named.stats.$n.cachedb >/dev/null && ret=1
1678status=$((status + ret))
1679if [ $ret != 0 ]; then echo_i "failed"; fi
1680
1681################################################
1682# Test for stale-answer-client-timeout (1.8s). #
1683################################################
1684echo_i "test stale-answer-client-timeout (1.8)"
1685
1686n=$((n + 1))
1687echo_i "updating ns3/named.conf ($n)"
1688ret=0
1689copy_setports ns3/named2.conf.in ns3/named.conf
1690if [ $ret != 0 ]; then echo_i "failed"; fi
1691status=$((status + ret))
1692
1693echo_i "restart ns3"
1694stop_server --use-rndc --port ${CONTROLPORT} ns3
1695start_server --noclean --restart --port ${PORT} ns3
1696
1697n=$((n + 1))
1698echo_i "check 'rndc serve-stale status' ($n)"
1699ret=0
1700$RNDCCMD 10.53.0.3 serve-stale status >rndc.out.test$n 2>&1 || ret=1
1701grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=3 max-stale-ttl=3600 stale-refresh-time=0)' rndc.out.test$n >/dev/null || ret=1
1702if [ $ret != 0 ]; then echo_i "failed"; fi
1703status=$((status + ret))
1704
1705n=$((n + 1))
1706echo_i "enable responses from authoritative server ($n)"
1707ret=0
1708$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
1709grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1710grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
1711if [ $ret != 0 ]; then echo_i "failed"; fi
1712status=$((status + ret))
1713
1714n=$((n + 1))
1715echo_i "prime cache data.example TXT (stale-answer-client-timeout) ($n)"
1716ret=0
1717$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
1718grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1719grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1720if [ $ret != 0 ]; then echo_i "failed"; fi
1721status=$((status + ret))
1722
1723n=$((n + 1))
1724echo_i "prime cache nodata.example TXT (stale-answer-client-timeout) ($n)"
1725ret=0
1726$DIG -p ${PORT} @10.53.0.3 nodata.example TXT >dig.out.test$n
1727grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1728grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1729if [ $ret != 0 ]; then echo_i "failed"; fi
1730status=$((status + ret))
1731
1732n=$((n + 1))
1733echo_i "delay responses from authoritative server ($n)"
1734ret=0
1735$DIG -p ${PORT} @10.53.0.2 txt slowdown >dig.out.test$n
1736grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1737grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
1738if [ $ret != 0 ]; then echo_i "failed"; fi
1739status=$((status + ret))
1740
1741n=$((n + 1))
1742echo_i "prime cache data.slow TXT (stale-answer-client-timeout) ($n)"
1743ret=0
1744$DIG -p ${PORT} @10.53.0.3 data.slow TXT >dig.out.test$n
1745grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1746grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1747if [ $ret != 0 ]; then echo_i "failed"; fi
1748status=$((status + ret))
1749
1750n=$((n + 1))
1751echo_i "disable responses from authoritative server ($n)"
1752ret=0
1753$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
1754grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1755grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
1756if [ $ret != 0 ]; then echo_i "failed"; fi
1757status=$((status + ret))
1758
1759# Allow RRset to become stale.
1760sleep 2
1761
1762nextpart ns3/named.run >/dev/null
1763
1764echo_i "sending queries for tests $((n + 1))-$((n + 3))..."
1765t1=$($PERL -e 'print time()')
1766$DIG -p ${PORT} +tries=1 +timeout=11 @10.53.0.3 data.example TXT >dig.out.test$((n + 1)) &
1767$DIG -p ${PORT} +tries=1 +timeout=11 @10.53.0.3 nodata.example TXT >dig.out.test$((n + 2)) &
1768$DIG -p ${PORT} +tries=1 +timeout=11 @10.53.0.3 data.slow TXT >dig.out.test$((n + 3)) &
1769wait
1770t2=$($PERL -e 'print time()')
1771
1772# We configured a long value of 30 seconds for resolver-query-timeout.
1773# That should give us enough time to receive an stale answer from cache
1774# after stale-answer-client-timeout timer of 1.8 sec triggers.
1775n=$((n + 1))
1776echo_i "check stale data.example TXT comes from cache (stale-answer-client-timeout 1.8) ($n)"
1777ret=0
1778wait_for_log 5 "data.example client timeout, stale answer used" ns3/named.run || ret=1
1779grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1780grep "EDE: 3 (Stale Answer): (client timeout)" dig.out.test$n >/dev/null || ret=1
1781grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1782grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
1783# Configured stale-answer-client-timeout is 1.8s, we allow some extra time
1784# just in case other tests are taking too much cpu.
1785[ $((t2 - t1)) -le 10 ] || {
1786  echo_i "query took $((t2 - t1))s to resolve."
1787  ret=1
1788}
1789if [ $ret != 0 ]; then echo_i "failed"; fi
1790status=$((status + ret))
1791
1792n=$((n + 1))
1793echo_i "check stale nodata.example TXT comes from cache (stale-answer-client-timeout 1.8) ($n)"
1794ret=0
1795grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1796grep "EDE: 3 (Stale Answer): (client timeout)" dig.out.test$n >/dev/null || ret=1
1797grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
1798grep "example\..*3.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
1799if [ $ret != 0 ]; then echo_i "failed"; fi
1800status=$((status + ret))
1801
1802n=$((n + 1))
1803echo_i "check stale data.slow TXT comes from cache (stale-answer-client-timeout 1.8) ($n)"
1804ret=0
1805grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1806grep "EDE: 3 (Stale Answer): (client timeout)" dig.out.test$n >/dev/null || ret=1
1807grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1808grep "data\.slow\..*3.*IN.*TXT.*A slow text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
1809if [ $ret != 0 ]; then echo_i "failed"; fi
1810status=$((status + ret))
1811
1812# Now query for RRset not in cache. The first query should time out, but once
1813# we enable the authoritative server, the second query should be able to get a
1814# response.
1815
1816nextpart ns3/named.run >/dev/null
1817
1818echo_i "sending queries for tests $((n + 2))-$((n + 4))..."
1819# first dig runs in background for 10 seconds, second in background for 3
1820# seconds and the last for 3 seconds in the foreground.
1821# the second RRSIG lookup triggers the issue in [GL #3622]
1822$DIG -p ${PORT} +tries=1 +timeout=10 @10.53.0.3 longttl.example TXT >dig.out.test$((n + 3)) &
1823$DIG -p ${PORT} +tries=1 +timeout=3 @10.53.0.3 longttl.example RRSIG >dig.out.test$((n + 4)) &
1824$DIG -p ${PORT} +tries=1 +timeout=3 @10.53.0.3 longttl.example TXT >dig.out.test$((n + 2)) || true
1825
1826# Enable the authoritative name server after stale-answer-client-timeout.
1827n=$((n + 1))
1828echo_i "enable responses from authoritative server ($n)"
1829ret=0
1830$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
1831grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1832grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
1833if [ $ret != 0 ]; then echo_i "failed"; fi
1834status=$((status + ret))
1835
1836n=$((n + 1))
1837echo_i "check not in cache longttl.example TXT times out (stale-answer-client-timeout 1.8) ($n)"
1838ret=0
1839wait_for_log 4 "longttl.example client timeout, stale answer unavailable" ns3/named.run || ret=1
1840grep "timed out" dig.out.test$n >/dev/null || ret=1
1841grep ";; no servers could be reached" dig.out.test$n >/dev/null || ret=1
1842if [ $ret != 0 ]; then echo_i "failed"; fi
1843status=$((status + ret))
1844
1845wait
1846
1847n=$((n + 1))
1848echo_i "check not in cache longttl.example TXT comes from authoritative (stale-answer-client-timeout 1.8) ($n)"
1849ret=0
1850grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1851grep "EDE" dig.out.test$n >/dev/null && ret=1
1852grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1853if [ $ret != 0 ]; then echo_i "failed"; fi
1854status=$((status + ret))
1855
1856n=$((n + 1))
1857echo_i "check not in cache longttl.example RRSIG times out (stale-answer-client-timeout 1.8) ($n)"
1858ret=0
1859grep "timed out" dig.out.test$n >/dev/null || ret=1
1860grep ";; no servers could be reached" dig.out.test$n >/dev/null || ret=1
1861if [ $ret != 0 ]; then echo_i "failed"; fi
1862status=$((status + ret))
1863
1864# CVE-2022-3924, GL #3619
1865n=$((n + 1))
1866echo_i "check that named survives reaching recursive-clients quota (stale-answer-client-timeout 1.8) ($n)"
1867ret=0
1868num=0
1869# Make sure to exceed the configured value of 'recursive-clients 10;' by running
1870# 20 parallel queries with simulated network latency.
1871while [ $num -lt 20 ]; do
1872  $DIG +tries=1 -p ${PORT} @10.53.0.3 "latency${num}.data.example" TXT >/dev/null 2>&1 &
1873  num=$((num + 1))
1874done
1875check_server_responds() {
1876  $DIG -p ${PORT} @10.53.0.3 version.bind txt ch >dig.out.test$n || return 1
1877  grep "status: NOERROR" dig.out.test$n >/dev/null || return 1
1878}
1879retry_quiet 5 check_server_responds || ret=1
1880if [ $ret != 0 ]; then echo_i "failed"; fi
1881status=$((status + ret))
1882
1883#############################################
1884# Test for stale-answer-client-timeout off. #
1885#############################################
1886echo_i "test stale-answer-client-timeout (off)"
1887
1888n=$((n + 1))
1889echo_i "updating ns3/named.conf ($n)"
1890ret=0
1891copy_setports ns3/named3.conf.in ns3/named.conf
1892if [ $ret != 0 ]; then echo_i "failed"; fi
1893status=$((status + ret))
1894
1895n=$((n + 1))
1896echo_i "running 'rndc reload' ($n)"
1897ret=0
1898rndc_reload ns3 10.53.0.3
1899if [ $ret != 0 ]; then echo_i "failed"; fi
1900status=$((status + ret))
1901
1902# Send a query, auth server is disabled, we will enable it after a while in
1903# order to receive an answer before resolver-query-timeout expires. Since
1904# stale-answer-client-timeout is disabled we must receive an answer from
1905# authoritative server.
1906echo_i "sending query for test $((n + 2))"
1907$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$((n + 2)) &
1908sleep 3
1909
1910n=$((n + 1))
1911echo_i "enable responses from authoritative server ($n)"
1912ret=0
1913$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
1914grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1915grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
1916if [ $ret != 0 ]; then echo_i "failed"; fi
1917status=$((status + ret))
1918
1919# Wait until dig is done.
1920wait
1921
1922n=$((n + 1))
1923echo_i "check data.example TXT comes from authoritative server (stale-answer-client-timeout off) ($n)"
1924grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1925grep "EDE" dig.out.test$n >/dev/null && ret=1
1926grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1927grep "data\.example\..*[12].*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
1928if [ $ret != 0 ]; then echo_i "failed"; fi
1929status=$((status + ret))
1930
1931##############################################################
1932# Test for stale-answer-client-timeout off and CNAME record. #
1933##############################################################
1934echo_i "test stale-answer-client-timeout (0) and CNAME record"
1935
1936n=$((n + 1))
1937echo_i "prime cache shortttl.cname.example (stale-answer-client-timeout off) ($n)"
1938ret=0
1939$DIG -p ${PORT} @10.53.0.3 shortttl.cname.example A >dig.out.test$n
1940grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1941grep "ANSWER: 2," dig.out.test$n >/dev/null || ret=1
1942grep "shortttl\.cname\.example\..*1.*IN.*CNAME.*longttl\.target\.example\." dig.out.test$n >/dev/null || ret=1
1943grep "longttl\.target\.example\..*600.*IN.*A.*10\.53\.0\.2" dig.out.test$n >/dev/null || ret=1
1944if [ $ret != 0 ]; then echo_i "failed"; fi
1945status=$((status + ret))
1946
1947# Allow RRset to become stale.
1948sleep 1
1949
1950n=$((n + 1))
1951echo_i "disable responses from authoritative server ($n)"
1952ret=0
1953$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
1954grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1955grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
1956if [ $ret != 0 ]; then echo_i "failed"; fi
1957status=$((status + ret))
1958
1959n=$((n + 1))
1960ret=0
1961echo_i "check stale shortttl.cname.example comes from cache (stale-answer-client-timeout off) ($n)"
1962nextpart ns3/named.run >/dev/null
1963$DIG -p ${PORT} @10.53.0.3 shortttl.cname.example A >dig.out.test$n
1964wait_for_log 5 "shortttl.cname.example resolver failure, stale answer used" ns3/named.run || ret=1
1965grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
1966grep "EDE: 3 (Stale Answer): (resolver failure)" dig.out.test$n >/dev/null || ret=1
1967grep "ANSWER: 2," dig.out.test$n >/dev/null || ret=1
1968grep "shortttl\.cname\.example\..*3.*IN.*CNAME.*longttl\.target\.example\." dig.out.test$n >/dev/null || ret=1
1969# We can't reliably test the TTL of the longttl.target.example A record.
1970grep "longttl\.target\.example\..*IN.*A.*10\.53\.0\.2" dig.out.test$n >/dev/null || ret=1
1971if [ $ret != 0 ]; then echo_i "failed"; fi
1972status=$((status + ret))
1973
1974n=$((n + 1))
1975echo_i "enable responses from authoritative server ($n)"
1976ret=0
1977$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
1978grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
1979grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
1980if [ $ret != 0 ]; then echo_i "failed"; fi
1981status=$((status + ret))
1982
1983n=$((n + 1))
1984echo_i "check server is alive or restart ($n)"
1985ret=0
1986$RNDCCMD 10.53.0.3 status >rndc.out.test$n 2>&1 || ret=1
1987if [ $ret != 0 ]; then
1988  echo_i "failed"
1989  echo_i "restart ns3"
1990  start_server --noclean --restart --port ${PORT} serve-stale ns3
1991fi
1992status=$((status + ret))
1993
1994n=$((n + 1))
1995echo_i "check server is alive or restart ($n)"
1996ret=0
1997$RNDCCMD 10.53.0.3 status >rndc.out.test$n 2>&1 || ret=1
1998if [ $ret != 0 ]; then
1999  echo_i "failed"
2000  echo_i "restart ns3"
2001  start_server --noclean --restart --port ${PORT} serve-stale ns3
2002fi
2003status=$((status + ret))
2004
2005#############################################
2006# Test for stale-answer-client-timeout 0.   #
2007#############################################
2008echo_i "test stale-answer-client-timeout (0)"
2009
2010n=$((n + 1))
2011echo_i "updating ns3/named.conf ($n)"
2012ret=0
2013copy_setports ns3/named4.conf.in ns3/named.conf
2014if [ $ret != 0 ]; then echo_i "failed"; fi
2015status=$((status + ret))
2016
2017echo_i "restart ns3"
2018stop_server --use-rndc --port ${CONTROLPORT} ns3
2019start_server --noclean --restart --port ${PORT} ns3
2020
2021n=$((n + 1))
2022echo_i "prime cache data.example TXT (stale-answer-client-timeout 0)"
2023ret=0
2024$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
2025grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2026grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2027if [ $ret != 0 ]; then echo_i "failed"; fi
2028status=$((status + ret))
2029
2030n=$((n + 1))
2031echo_i "prime cache nodata.example TXT (stale-answer-client-timeout 0)"
2032ret=0
2033$DIG -p ${PORT} @10.53.0.3 nodata.example TXT >dig.out.test$n
2034grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2035grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
2036if [ $ret != 0 ]; then echo_i "failed"; fi
2037status=$((status + ret))
2038
2039n=$((n + 1))
2040echo_i "disable responses from authoritative server ($n)"
2041ret=0
2042$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
2043grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2044grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
2045if [ $ret != 0 ]; then echo_i "failed"; fi
2046status=$((status + ret))
2047
2048# Allow RRset to become stale.
2049sleep 2
2050
2051n=$((n + 1))
2052ret=0
2053echo_i "check stale nodata.example TXT comes from cache (stale-answer-client-timeout 0) ($n)"
2054nextpart ns3/named.run >/dev/null
2055$DIG -p ${PORT} @10.53.0.3 nodata.example TXT >dig.out.test$n
2056wait_for_log 5 "nodata.example stale answer used, an attempt to refresh the RRset" ns3/named.run || ret=1
2057grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2058grep "EDE: 3 (Stale Answer): (stale data prioritized over lookup)" dig.out.test$n >/dev/null || ret=1
2059grep "ANSWER: 0," dig.out.test$n >/dev/null || ret=1
2060grep "example\..*3.*IN.*SOA" dig.out.test$n >/dev/null || ret=1
2061if [ $ret != 0 ]; then echo_i "failed"; fi
2062status=$((status + ret))
2063
2064n=$((n + 1))
2065ret=0
2066echo_i "check stale data.example TXT comes from cache (stale-answer-client-timeout 0) ($n)"
2067nextpart ns3/named.run >/dev/null
2068$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
2069wait_for_log 5 "data.example stale answer used, an attempt to refresh the RRset" ns3/named.run || ret=1
2070grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2071grep "EDE: 3 (Stale Answer): (stale data prioritized over lookup)" dig.out.test$n >/dev/null || ret=1
2072grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2073grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
2074if [ $ret != 0 ]; then echo_i "failed"; fi
2075status=$((status + ret))
2076
2077n=$((n + 1))
2078echo_i "enable responses from authoritative server ($n)"
2079ret=0
2080$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
2081grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2082grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
2083if [ $ret != 0 ]; then echo_i "failed"; fi
2084status=$((status + ret))
2085
2086wait_for_rrset_refresh() {
2087  $DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
2088  grep "status: NOERROR" dig.out.test$n >/dev/null || return 1
2089  grep "EDE" dig.out.test$n >/dev/null && return 1
2090  grep "ANSWER: 1," dig.out.test$n >/dev/null || return 1
2091  grep "data\.example\..*[12].*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || return 1
2092}
2093
2094# This test ensures that after we get stale data due to
2095# stale-answer-client-timeout 0, enabling the authoritative server will allow
2096# the RRset to be updated.
2097n=$((n + 1))
2098ret=0
2099echo_i "check stale data.example TXT was refreshed (stale-answer-client-timeout 0) ($n)"
2100retry_quiet 10 wait_for_rrset_refresh || ret=1
2101if [ $ret != 0 ]; then echo_i "failed"; fi
2102status=$((status + ret))
2103
2104wait_for_nodata_refresh() {
2105  $DIG -p ${PORT} @10.53.0.3 nodata.example TXT >dig.out.test$n
2106  grep "status: NOERROR" dig.out.test$n >/dev/null || return 1
2107  grep "ANSWER: 0," dig.out.test$n >/dev/null || return 1
2108  grep "example\..*[12].*IN.*SOA" dig.out.test$n >/dev/null || return 1
2109  return 0
2110}
2111
2112n=$((n + 1))
2113ret=0
2114echo_i "check stale nodata.example TXT was refreshed (stale-answer-client-timeout 0) ($n)"
2115retry_quiet 10 wait_for_nodata_refresh || ret=1
2116if [ $ret != 0 ]; then echo_i "failed"; fi
2117status=$((status + ret))
2118
2119####################################################################
2120# Test for stale-answer-client-timeout 0 and recursive-clients 10. #
2121# CVE-2023-2911, GL #4089                                          #
2122# ##################################################################
2123echo_i "test stale-answer-client-timeout (0) and recursive-clients 10"
2124
2125n=$((n + 1))
2126echo_i "prime cache data.slow TXT (stale-answer-client-timeout 0) ($n)"
2127ret=0
2128$DIG -p ${PORT} @10.53.0.3 data.slow TXT >dig.out.test$n
2129grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2130grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2131if [ $ret != 0 ]; then echo_i "failed"; fi
2132status=$((status + ret))
2133
2134# Run the following check twice. Sometimes a priming query interrupts the first
2135# attempt to exceed the quota.
2136attempt=0
2137while [ $ret -eq 0 ] && [ $attempt -lt 2 ]; do
2138  n=$((n + 1))
2139  echo_i "slow down response from authoritative server ($n)"
2140  ret=0
2141  $DIG -p ${PORT} @10.53.0.2 slowdown TXT >dig.out.test$n
2142  grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2143  grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
2144  if [ $ret != 0 ]; then echo_i "failed"; fi
2145  status=$((status + ret))
2146
2147  # Let the data.slow TTL expire
2148  sleep 2
2149
2150  n=$((n + 1))
2151  echo_i "check that named survives reaching recursive-clients quota (stale-answer-client-timeout 0) ($n)"
2152  ret=0
2153  num=0
2154  # Attempt to exceed the configured value of 'recursive-clients 10;' by running
2155  # 20 parallel queries for the stale domain which has slow auth.
2156  while [ $num -lt 20 ]; do
2157    $DIG +tries=1 +timeout=10 -p ${PORT} @10.53.0.3 data.slow TXT >/dev/null 2>&1 &
2158    num=$((num + 1))
2159  done
2160  # Let the dig processes finish.
2161  wait
2162  retry_quiet 5 check_server_responds || ret=1
2163  if [ $ret != 0 ]; then echo_i "failed"; fi
2164  status=$((status + ret))
2165
2166  attempt=$((attempt + 1))
2167done
2168
2169# Restart ns3 to avoid the exceeded recursive-clients limit from previous check
2170# to interfere with subsequent checks.
2171echo_i "restart ns3"
2172stop_server --use-rndc --port ${CONTROLPORT} ns3
2173start_server --noclean --restart --port ${PORT} ns3
2174
2175############################################################
2176# Test for stale-answer-client-timeout 0 and CNAME record. #
2177############################################################
2178echo_i "test stale-answer-client-timeout (0) and CNAME record"
2179
2180n=$((n + 1))
2181echo_i "prime cache cname1.stale.test A (stale-answer-client-timeout 0) ($n)"
2182ret=0
2183$DIG -p ${PORT} @10.53.0.3 cname1.stale.test A >dig.out.test$n
2184grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2185grep "ANSWER: 2," dig.out.test$n >/dev/null || ret=1
2186grep "cname1\.stale\.test\..*1.*IN.*CNAME.*a1\.stale\.test\." dig.out.test$n >/dev/null || ret=1
2187grep "a1\.stale\.test\..*1.*IN.*A.*192\.0\.2\.1" dig.out.test$n >/dev/null || ret=1
2188if [ $ret != 0 ]; then echo_i "failed"; fi
2189status=$((status + ret))
2190
2191# Allow RRset to become stale.
2192sleep 1
2193
2194n=$((n + 1))
2195ret=0
2196echo_i "check stale cname1.stale.test A comes from cache (stale-answer-client-timeout 0) ($n)"
2197nextpart ns3/named.run >/dev/null
2198$DIG -p ${PORT} @10.53.0.3 cname1.stale.test A >dig.out.test$n
2199wait_for_log 5 "cname1.stale.test stale answer used, an attempt to refresh the RRset" ns3/named.run || ret=1
2200grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2201grep "EDE: 3 (Stale Answer): (stale data prioritized over lookup)" dig.out.test$n >/dev/null || ret=1
2202grep "ANSWER: 2," dig.out.test$n >/dev/null || ret=1
2203grep "cname1\.stale\.test\..*3.*IN.*CNAME.*a1\.stale\.test\." dig.out.test$n >/dev/null || ret=1
2204grep "a1\.stale\.test\..*3.*IN.*A.*192\.0\.2\.1" dig.out.test$n >/dev/null || ret=1
2205if [ $ret != 0 ]; then echo_i "failed"; fi
2206status=$((status + ret))
2207
2208n=$((n + 1))
2209echo_i "check server is alive or restart ($n)"
2210ret=0
2211$RNDCCMD 10.53.0.3 status >rndc.out.test$n 2>&1 || ret=1
2212if [ $ret != 0 ]; then
2213  echo_i "failed"
2214  echo_i "restart ns3"
2215  start_server --noclean --restart --port ${PORT} ns3
2216fi
2217status=$((status + ret))
2218
2219n=$((n + 1))
2220echo_i "prime cache cname2.stale.test A (stale-answer-client-timeout 0) ($n)"
2221ret=0
2222$DIG -p ${PORT} @10.53.0.3 cname2.stale.test A >dig.out.test$n
2223grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2224grep "ANSWER: 2," dig.out.test$n >/dev/null || ret=1
2225grep "cname2\.stale\.test\..*1.*IN.*CNAME.*a2\.stale\.test\." dig.out.test$n >/dev/null || ret=1
2226grep "a2\.stale\.test\..*300.*IN.*A.*192\.0\.2\.2" dig.out.test$n >/dev/null || ret=1
2227if [ $ret != 0 ]; then echo_i "failed"; fi
2228status=$((status + ret))
2229
2230# Allow CNAME record in the RRSET to become stale.
2231sleep 1
2232
2233n=$((n + 1))
2234ret=0
2235echo_i "check stale cname2.stale.test A comes from cache (stale-answer-client-timeout 0) ($n)"
2236nextpart ns3/named.run >/dev/null
2237$DIG -p ${PORT} @10.53.0.3 cname2.stale.test A >dig.out.test$n
2238wait_for_log 5 "cname2.stale.test stale answer used, an attempt to refresh the RRset" ns3/named.run || ret=1
2239grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2240grep "EDE: 3 (Stale Answer): (stale data prioritized over lookup)" dig.out.test$n >/dev/null || ret=1
2241grep "ANSWER: 2," dig.out.test$n >/dev/null || ret=1
2242grep "cname2\.stale\.test\..*3.*IN.*CNAME.*a2\.stale\.test\." dig.out.test$n >/dev/null || ret=1
2243# We can't reliably test the TTL of the a2.stale.test A record.
2244grep "a2\.stale\.test\..*IN.*A.*192\.0\.2\.2" dig.out.test$n >/dev/null || ret=1
2245if [ $ret != 0 ]; then echo_i "failed"; fi
2246status=$((status + ret))
2247
2248n=$((n + 1))
2249echo_i "check server is alive or restart ($n)"
2250ret=0
2251$RNDCCMD 10.53.0.3 status >rndc.out.test$n 2>&1 || ret=1
2252if [ $ret != 0 ]; then
2253  echo_i "failed"
2254  echo_i "restart ns3"
2255  start_server --noclean --restart --port ${PORT} ns3
2256fi
2257status=$((status + ret))
2258
2259####################################################################
2260# Test for stale-answer-client-timeout 0 and stale-refresh-time 4. #
2261####################################################################
2262echo_i "test stale-answer-client-timeout (0) and stale-refresh-time (4)"
2263
2264n=$((n + 1))
2265echo_i "updating ns3/named.conf ($n)"
2266ret=0
2267copy_setports ns3/named5.conf.in ns3/named.conf
2268if [ $ret != 0 ]; then echo_i "failed"; fi
2269status=$((status + ret))
2270
2271n=$((n + 1))
2272echo_i "running 'rndc reload' ($n)"
2273ret=0
2274rndc_reload ns3 10.53.0.3
2275if [ $ret != 0 ]; then echo_i "failed"; fi
2276status=$((status + ret))
2277
2278n=$((n + 1))
2279echo_i "flush cache, enable responses from authoritative server ($n)"
2280ret=0
2281$RNDCCMD 10.53.0.3 flushtree example >rndc.out.test$n.1 2>&1 || ret=1
2282$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
2283grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2284grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
2285if [ $ret != 0 ]; then echo_i "failed"; fi
2286status=$((status + ret))
2287
2288n=$((n + 1))
2289echo_i "prime cache data.example TXT (stale-answer-client-timeout 0, stale-refresh-time 4) ($n)"
2290ret=0
2291$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
2292grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2293grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2294grep "data\.example\..*2.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
2295if [ $ret != 0 ]; then echo_i "failed"; fi
2296status=$((status + ret))
2297
2298# Allow RRset to become stale.
2299sleep 2
2300
2301n=$((n + 1))
2302echo_i "disable responses from authoritative server ($n)"
2303ret=0
2304$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
2305grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2306grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
2307if [ $ret != 0 ]; then echo_i "failed"; fi
2308status=$((status + ret))
2309
2310n=$((n + 1))
2311ret=0
2312echo_i "check stale data.example TXT comes from cache (stale-answer-client-timeout 0 stale-refresh-time 4) ($n)"
2313nextpart ns3/named.run >/dev/null
2314$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
2315wait_for_log 5 "data.example stale answer used, an attempt to refresh the RRset" ns3/named.run || ret=1
2316grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2317grep "EDE: 3 (Stale Answer): (stale data prioritized over lookup)" dig.out.test$n >/dev/null || ret=1
2318grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2319grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
2320if [ $ret != 0 ]; then echo_i "failed"; fi
2321status=$((status + ret))
2322
2323n=$((n + 1))
2324echo_i "enable responses from authoritative server ($n)"
2325ret=0
2326$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
2327grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2328grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
2329if [ $ret != 0 ]; then echo_i "failed"; fi
2330status=$((status + ret))
2331
2332# This test ensures that after we get stale data due to
2333# stale-answer-client-timeout 0, enabling the authoritative server will allow
2334# the RRset to be updated.
2335n=$((n + 1))
2336ret=0
2337echo_i "check stale data.example TXT was refreshed (stale-answer-client-timeout 0 stale-refresh-time 4) ($n)"
2338retry_quiet 10 wait_for_rrset_refresh || ret=1
2339if [ $ret != 0 ]; then echo_i "failed"; fi
2340status=$((status + ret))
2341
2342# Allow RRset to become stale.
2343sleep 2
2344
2345n=$((n + 1))
2346echo_i "disable responses from authoritative server ($n)"
2347ret=0
2348$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
2349grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2350grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
2351if [ $ret != 0 ]; then echo_i "failed"; fi
2352status=$((status + ret))
2353
2354n=$((n + 1))
2355ret=0
2356echo_i "check stale data.example TXT comes from cache (stale-answer-client-timeout 0 stale-refresh-time 4) ($n)"
2357nextpart ns3/named.run >/dev/null
2358$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
2359wait_for_log 5 "data.example stale answer used, an attempt to refresh the RRset" ns3/named.run || ret=1
2360grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2361grep "EDE: 3 (Stale Answer): (stale data prioritized over lookup)" dig.out.test$n >/dev/null || ret=1
2362grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2363grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
2364if [ $ret != 0 ]; then echo_i "failed"; fi
2365status=$((status + ret))
2366
2367# Allow stale-refresh-time to be activated.
2368n=$((n + 1))
2369ret=0
2370echo_i "wait until resolver query times out, activating stale-refresh-time"
2371wait_for_log 15 "data.example resolver failure, stale answer used" ns3/named.run || ret=1
2372if [ $ret != 0 ]; then echo_i "failed"; fi
2373status=$((status + ret))
2374
2375n=$((n + 1))
2376ret=0
2377echo_i "check stale data.example TXT comes from cache within stale-refresh-time (stale-answer-client-timeout 0 stale-refresh-time 4) ($n)"
2378nextpart ns3/named.run >/dev/null
2379$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
2380wait_for_log 5 "data.example query within stale refresh time" ns3/named.run || ret=1
2381grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2382grep "EDE: 3 (Stale Answer): (query within stale refresh time window)" dig.out.test$n >/dev/null || ret=1
2383grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2384grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
2385if [ $ret != 0 ]; then echo_i "failed"; fi
2386status=$((status + ret))
2387
2388n=$((n + 1))
2389echo_i "enable responses from authoritative server ($n)"
2390ret=0
2391$DIG -p ${PORT} @10.53.0.2 txt enable >dig.out.test$n
2392grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2393grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
2394if [ $ret != 0 ]; then echo_i "failed"; fi
2395status=$((status + ret))
2396
2397# We give BIND some time to ensure that after we enable authoritative server,
2398# this RRset is still not refreshed because it was hit during
2399# stale-refresh-time window.
2400sleep 1
2401
2402n=$((n + 1))
2403ret=0
2404echo_i "check stale data.example TXT was not refreshed (stale-answer-client-timeout 0 stale-refresh-time 4) ($n)"
2405nextpart ns3/named.run >/dev/null
2406$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
2407wait_for_log 5 "data.example query within stale refresh time" ns3/named.run || ret=1
2408grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2409grep "EDE: 3 (Stale Answer): (query within stale refresh time window)" dig.out.test$n >/dev/null || ret=1
2410grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2411grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
2412if [ $ret != 0 ]; then echo_i "failed"; fi
2413status=$((status + ret))
2414
2415# After the refresh-time-window, the RRset will be refreshed.
2416sleep 4
2417
2418n=$((n + 1))
2419ret=0
2420echo_i "check stale data.example TXT comes from cache (stale-answer-client-timeout 0 stale-refresh-time 4) ($n)"
2421$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
2422wait_for_log 5 "data.example stale answer used, an attempt to refresh the RRset" ns3/named.run || ret=1
2423grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2424grep "EDE: 3 (Stale Answer): (stale data prioritized over lookup)" dig.out.test$n >/dev/null || ret=1
2425grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2426grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
2427if [ $ret != 0 ]; then echo_i "failed"; fi
2428status=$((status + ret))
2429
2430n=$((n + 1))
2431ret=0
2432echo_i "check stale data.example TXT was refreshed (stale-answer-client-timeout 0 stale-refresh-time 4) ($n)"
2433$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
2434grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2435grep "EDE" dig.out.test$n >/dev/null && ret=1
2436grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2437grep "data\.example\..*[12].*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
2438if [ $ret != 0 ]; then echo_i "failed"; fi
2439status=$((status + ret))
2440
2441####################################################################
2442# Test serve-stale's interaction with fetch limits (cache only) #
2443#################################################################
2444echo_i "test serve-stale's interaction with fetch-limits (cache only)"
2445
2446# We update the named configuration to enable fetch-limits. The fetch-limits
2447# are set to 1, which is ridiciously low, but that is because for this test we
2448# want to reach the fetch-limits.
2449n=$((n + 1))
2450echo_i "updating ns3/named.conf ($n)"
2451ret=0
2452copy_setports ns3/named6.conf.in ns3/named.conf
2453if [ $ret != 0 ]; then echo_i "failed"; fi
2454status=$((status + ret))
2455
2456n=$((n + 1))
2457echo_i "running 'rndc reload' ($n)"
2458ret=0
2459rndc_reload ns3 10.53.0.3
2460if [ $ret != 0 ]; then echo_i "failed"; fi
2461status=$((status + ret))
2462
2463# Disable responses from authoritative server. If we can't resolve the example
2464# zone, fetch limits will be reached.
2465n=$((n + 1))
2466echo_i "disable responses from authoritative server ($n)"
2467ret=0
2468$DIG -p ${PORT} @10.53.0.2 txt disable >dig.out.test$n
2469grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2470grep "TXT.\"0\"" dig.out.test$n >/dev/null || ret=1
2471if [ $ret != 0 ]; then echo_i "failed"; fi
2472status=$((status + ret))
2473
2474# Allow RRset to become stale.
2475sleep 2
2476
2477# Turn on serve-stale.
2478n=$((n + 1))
2479echo_i "running 'rndc serve-stale on' ($n)"
2480ret=0
2481$RNDCCMD 10.53.0.3 serve-stale on || ret=1
2482if [ $ret != 0 ]; then echo_i "failed"; fi
2483status=$((status + ret))
2484
2485n=$((n + 1))
2486echo_i "check 'rndc serve-stale status' ($n)"
2487ret=0
2488$RNDCCMD 10.53.0.3 serve-stale status >rndc.out.test$n 2>&1 || ret=1
2489grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=3 max-stale-ttl=3600 stale-refresh-time=4)' rndc.out.test$n >/dev/null || ret=1
2490if [ $ret != 0 ]; then echo_i "failed"; fi
2491status=$((status + ret))
2492
2493# Hit the fetch-limits. We burst the name server with a small batch of queries.
2494# Only 2 queries are required to hit the fetch-limits. The first query will
2495# start to resolve, the second one hit the fetch-limits.
2496burst() {
2497  num=${1}
2498  rm -f burst.input.$$
2499  while [ $num -gt 0 ]; do
2500    num=$((num - 1))
2501    echo "fetch${num}.example A" >>burst.input.$$
2502  done
2503  $PERL ../ditch.pl -p ${PORT} -s 10.53.0.3 burst.input.$$
2504  rm -f burst.input.$$
2505}
2506
2507wait_for_fetchlimits() {
2508  burst 2
2509  # We expect a query for nx.example to fail because fetch-limits for
2510  # the domain 'example.' (and everything below) has been reached.
2511  $DIG -p ${PORT} +tries=1 +timeout=1 @10.53.0.3 nx.example >dig.out.test$n
2512  grep "status: SERVFAIL" dig.out.test$n >/dev/null || return 1
2513}
2514
2515n=$((n + 1))
2516echo_i "hit fetch limits ($n)"
2517ret=0
2518retry_quiet 10 wait_for_fetchlimits || ret=1
2519if [ $ret != 0 ]; then echo_i "failed"; fi
2520status=$((status + ret))
2521
2522# Expect stale data now (because fetch-limits for the domain 'example.' (and
2523# everything below) has been reached. But we have a stale RRset for
2524# 'data.example/TXT' that can be used.
2525n=$((n + 1))
2526ret=0
2527echo_i "check stale data.example TXT comes from cache (fetch-limits) ($n)"
2528nextpart ns3/named.run >/dev/null
2529$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
2530wait_for_log 5 "data.example resolver failure, stale answer used" ns3/named.run || ret=1
2531grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2532grep "EDE: 3 (Stale Answer): (resolver failure" dig.out.test$n >/dev/null || ret=1
2533grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2534grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
2535if [ $ret != 0 ]; then echo_i "failed"; fi
2536status=$((status + ret))
2537
2538# The previous query should not have started the stale-refresh-time window.
2539n=$((n + 1))
2540ret=0
2541echo_i "check stale data.example TXT comes from cache again (fetch-limits) ($n)"
2542nextpart ns3/named.run >/dev/null
2543$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$n
2544wait_for_log 5 "data.example resolver failure, stale answer used" ns3/named.run || ret=1
2545grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2546grep "EDE: 3 (Stale Answer): (resolver failure" dig.out.test$n >/dev/null || ret=1
2547grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2548grep "data\.example\..*3.*IN.*TXT.*A text record with a 2 second ttl" dig.out.test$n >/dev/null || ret=1
2549if [ $ret != 0 ]; then echo_i "failed"; fi
2550status=$((status + ret))
2551
2552########################################################################
2553# Test serve-stale's interaction with fetch limits (dual-mode) #
2554########################################################################
2555echo_i "test serve-stale's interaction with fetch limits (dual-mode)"
2556
2557# Update named configuration so that ns3 becomes a recursive resolver which is
2558# also a secondary server for the root zone.
2559n=$((n + 1))
2560echo_i "updating ns3/named.conf ($n)"
2561ret=0
2562copy_setports ns3/named7.conf.in ns3/named.conf
2563if [ $ret != 0 ]; then echo_i "failed"; fi
2564status=$((status + ret))
2565
2566n=$((n + 1))
2567echo_i "running 'rndc reload' ($n)"
2568ret=0
2569rndc_reload ns3 10.53.0.3
2570if [ $ret != 0 ]; then echo_i "failed"; fi
2571status=$((status + ret))
2572
2573n=$((n + 1))
2574echo_i "check 'rndc serve-stale status' ($n)"
2575ret=0
2576$RNDCCMD 10.53.0.3 serve-stale status >rndc.out.test$n 2>&1 || ret=1
2577grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=3 max-stale-ttl=3600 stale-refresh-time=4)' rndc.out.test$n >/dev/null || ret=1
2578if [ $ret != 0 ]; then echo_i "failed"; fi
2579status=$((status + ret))
2580
2581# Flush the cache to ensure the example/NS RRset cached during previous tests
2582# does not override the authoritative delegation found in the root zone.
2583n=$((n + 1))
2584echo_i "flush cache ($n)"
2585ret=0
2586$RNDCCMD 10.53.0.3 flush >rndc.out.test$n 2>&1 || ret=1
2587if [ $ret != 0 ]; then echo_i "failed"; fi
2588status=$((status + ret))
2589
2590# Test that after flush, serve-stale configuration is not reset.
2591n=$((n + 1))
2592echo_i "check serve-stale configuration is not reset after flush ($n)"
2593ret=0
2594$RNDCCMD 10.53.0.3 serve-stale status >rndc.out.test$n 2>&1 || ret=1
2595grep '_default: stale cache enabled; stale answers enabled (stale-answer-ttl=3 max-stale-ttl=3600 stale-refresh-time=4)' rndc.out.test$n >/dev/null || ret=1
2596if [ $ret != 0 ]; then echo_i "failed"; fi
2597status=$((status + ret))
2598
2599# Query name server with low fetch limits. The authoritative server (ans2) is
2600# not responding. Sending queries for multiple names in the 'example' zone
2601# in parallel causes the fetch limit for that zone (set to 1) to be
2602# reached. This should not trigger a crash.
2603echo_i "sending queries for tests $((n + 1))-$((n + 4))..."
2604$DIG -p ${PORT} @10.53.0.3 data.example TXT >dig.out.test$((n + 1)) &
2605$DIG -p ${PORT} @10.53.0.3 othertype.example CAA >dig.out.test$((n + 2)) &
2606$DIG -p ${PORT} @10.53.0.3 nodata.example TXT >dig.out.test$((n + 3)) &
2607$DIG -p ${PORT} @10.53.0.3 nxdomain.example TXT >dig.out.test$((n + 4)) &
2608
2609wait
2610
2611# Expect SERVFAIL for the entries not in cache.
2612n=$((n + 1))
2613echo_i "check stale data.example TXT (fetch-limits dual-mode) ($n)"
2614ret=0
2615grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
2616if [ $ret != 0 ]; then echo_i "failed"; fi
2617status=$((status + ret))
2618
2619n=$((n + 1))
2620echo_i "check stale othertype.example CAA (fetch-limits dual-mode) ($n)"
2621ret=0
2622grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
2623if [ $ret != 0 ]; then echo_i "failed"; fi
2624status=$((status + ret))
2625
2626n=$((n + 1))
2627echo_i "check stale nodata.example TXT (fetch-limits dual-mode) ($n)"
2628ret=0
2629grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
2630if [ $ret != 0 ]; then echo_i "failed"; fi
2631status=$((status + ret))
2632
2633n=$((n + 1))
2634echo_i "check stale nxdomain.example TXT (fetch-limits dual-mode) ($n)"
2635ret=0
2636grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1
2637if [ $ret != 0 ]; then echo_i "failed"; fi
2638status=$((status + ret))
2639
2640n=$((n + 1))
2641echo_i "check DNS64 processing of a stale negative answer ($n)"
2642ret=0
2643# configure ns3 with dns64
2644copy_setports ns3/named8.conf.in ns3/named.conf
2645rndc_reload ns3 10.53.0.3
2646# flush cache, enable ans2 responses, make sure serve-stale is on
2647$RNDCCMD 10.53.0.3 flush >rndc.out.test$n.1 2>&1 || ret=1
2648$DIG -p ${PORT} @10.53.0.2 txt enable >/dev/null
2649$RNDCCMD 10.53.0.3 serve-stale on >rndc.out.test$n.2 2>&1 || ret=1
2650# prime the cache with an AAAA NXRRSET response
2651$DIG -p ${PORT} @10.53.0.3 a-only.example AAAA >dig.out.1.test$n
2652grep "status: NOERROR" dig.out.1.test$n >/dev/null || ret=1
2653grep "2001:aaaa" dig.out.1.test$n >/dev/null || ret=1
2654# disable responses from the auth server
2655$DIG -p ${PORT} @10.53.0.2 txt disable >/dev/null
2656# wait two seconds for the previous answer to become stale
2657sleep 2
2658# resend the query and wait in the background; we should get a stale answer
2659$DIG -p ${PORT} @10.53.0.3 a-only.example AAAA >dig.out.2.test$n &
2660# re-enable queries after a pause, so the server gets a real answer too
2661sleep 2
2662$DIG -p ${PORT} @10.53.0.2 txt enable >/dev/null
2663wait
2664grep "status: NOERROR" dig.out.2.test$n >/dev/null || ret=1
2665grep "2001:aaaa" dig.out.2.test$n >/dev/null || ret=1
2666if [ $ret != 0 ]; then echo_i "failed"; fi
2667status=$((status + ret))
2668
2669###########################################################
2670# Test serve-stale's interaction with prefetch processing #
2671###########################################################
2672echo_i "test serve-stale's interaction with prefetch processing"
2673
2674# Test case for #2733, ensuring that prefetch queries do not trigger
2675# a lookup due to stale-answer-client-timeout.
2676#
2677# 1. Cache the following records:
2678#    cname.example 7 IN CNAME target.example.
2679#    target.example 9 IN A <addr>.
2680# 2. Let the CNAME RRset expire.
2681# 3. Query for 'cname.example/A'.
2682#
2683# This starts recursion because cname.example/CNAME is expired.
2684# The authoritative server is up so likely it will respond before
2685#  stale-answer-client-timeout is triggered.
2686# The 'target.example/A' RRset is found in cache with a positive value
2687#  and is eligble for prefetching.
2688# A prefetch is done for 'target.example/A', our ans2 server will
2689#  delay the request.
2690# The 'prefetch_done()' callback should have the right event type
2691#  (DNS_EVENT_FETCHDONE).
2692
2693# flush cache
2694n=$((n + 1))
2695echo_i "flush cache ($n)"
2696ret=0
2697$RNDCCMD 10.53.0.3 flushtree example >rndc.out.test$n.1 2>&1 || ret=1
2698if [ $ret != 0 ]; then echo_i "failed"; fi
2699status=$((status + ret))
2700
2701# prime the cache with CNAME and A; CNAME expires sooner
2702n=$((n + 1))
2703echo_i "prime cache cname.example A (stale-answer-client-timeout 1.8) ($n)"
2704ret=0
2705$DIG -p ${PORT} @10.53.0.3 cname.example A >dig.out.test$n
2706grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2707grep "ANSWER: 2," dig.out.test$n >/dev/null || ret=1
2708grep "cname\.example\..*7.*IN.*CNAME.*target\.example\." dig.out.test$n >/dev/null || ret=1
2709grep "target\.example\..*9.*IN.*A" dig.out.test$n >/dev/null || ret=1
2710if [ $ret != 0 ]; then echo_i "failed"; fi
2711status=$((status + ret))
2712
2713# wait for the CNAME to be stale; A will still be valid and in prefetch window.
2714# (the longer TTL is needed, otherwise data won't be prefetch-eligible.)
2715sleep 7
2716
2717# re-enable auth responses, but with a delay answering the A
2718n=$((n + 1))
2719echo_i "delay responses from authoritative server ($n)"
2720ret=0
2721$DIG -p ${PORT} @10.53.0.2 txt slowdown >dig.out.test$n
2722grep "ANSWER: 1," dig.out.test$n >/dev/null || ret=1
2723grep "TXT.\"1\"" dig.out.test$n >/dev/null || ret=1
2724if [ $ret != 0 ]; then echo_i "failed"; fi
2725status=$((status + ret))
2726
2727# resend the query and wait in the background; we should get a stale answer
2728n=$((n + 1))
2729echo_i "check prefetch processing of a stale CNAME target ($n)"
2730ret=0
2731$DIG -p ${PORT} @10.53.0.3 cname.example A >dig.out.test$n &
2732sleep 2
2733wait
2734grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1
2735grep "ANSWER: 2," dig.out.test$n >/dev/null || ret=1
2736grep "cname\.example\..*7.*IN.*CNAME.*target\.example\." dig.out.test$n >/dev/null || ret=1
2737grep "target\.example\..*[1-2].*IN.*A" dig.out.test$n >/dev/null || ret=1
2738if [ $ret != 0 ]; then echo_i "failed"; fi
2739status=$((status + ret))
2740
2741echo_i "exit status: $status"
2742[ $status -eq 0 ] || exit 1
2743