1#!/bin/sh
2#
3# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
4#
5# This Source Code Form is subject to the terms of the Mozilla Public
6# License, v. 2.0. If a copy of the MPL was not distributed with this
7# file, You can obtain one at http://mozilla.org/MPL/2.0/.
8#
9# See the COPYRIGHT file distributed with this work for additional
10# information regarding copyright ownership.
11
12SYSTEMTESTTOP=..
13. $SYSTEMTESTTOP/conf.sh
14
15DIGOPTS="-p ${PORT} -b 10.53.0.1 +dnssec +time=2 +tries=1 +multi"
16RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s"
17
18# Wait until the transfer of the given zone to ns3 either completes successfully
19# or is aborted by a verification failure or a REFUSED response from the master.
20# Note that matching on any transfer status is deliberately avoided because some
21# checks performed by this test cause transfer attempts to end with the "IXFR
22# failed" status, which is followed by an AXFR retry and this test needs to
23# check what the result of the latter transfer attempt is.
24wait_for_transfer() {
25	zone=$1
26	for i in 1 2 3 4 5 6 7 8 9 10; do
27		# Wait until a "freeing transfer context" message is logged
28		# after one of the transfer results we are looking for is
29		# logged.  This is needed to prevent races when checking for
30		# "mirror zone is now in use" messages.
31		nextpartpeek ns3/named.run | \
32			awk "matched; /'$zone\/IN'.*Transfer status: (success|verify failure|REFUSED)/ {matched=1}" | \
33			grep "'$zone/IN'.*freeing transfer context" > /dev/null && return
34		sleep 1
35	done
36	echo_i "exceeded time limit waiting for proof of '$zone' being transferred to appear in ns3/named.run"
37	ret=1
38}
39
40# Wait until loading the given zone on the given server either completes
41# successfully for the specified serial number or fails.
42wait_for_load() {
43	zone=$1
44	serial=$2
45	log=$3
46	for i in 1 2 3 4 5 6 7 8 9 10; do
47		# Wait until a "zone_postload: (...): done" message is logged
48		# after one of the loading-related messages we are looking for
49		# is logged.  This is needed to prevent races when checking for
50		# "mirror zone is now in use" messages.
51		nextpartpeek $log | \
52			awk "matched; /$zone.*(loaded serial $serial|unable to load)/ {matched=1}" | \
53			grep "zone_postload: zone $zone/IN: done" > /dev/null && return
54		sleep 1
55	done
56	echo_i "exceeded time limit waiting for proof of '$zone' being loaded to appear in $log"
57	ret=1
58}
59
60# Trigger a reload of ns2 and wait until loading the given zone completes.
61reload_zone() {
62	zone=$1
63	serial=$2
64	rndc_reload ns2 10.53.0.2
65	wait_for_load $zone $serial ns2/named.run
66}
67
68status=0
69n=0
70
71ORIGINAL_SERIAL=`awk '$2 == "SOA" {print $5}' ns2/verify.db.in`
72UPDATED_SERIAL_BAD=`expr ${ORIGINAL_SERIAL} + 1`
73UPDATED_SERIAL_GOOD=`expr ${ORIGINAL_SERIAL} + 2`
74
75n=`expr $n + 1`
76echo_i "checking that an unsigned mirror zone is rejected ($n)"
77ret=0
78wait_for_transfer verify-unsigned
79$DIG $DIGOPTS @10.53.0.3 +norec verify-unsigned SOA > dig.out.ns3.test$n 2>&1 || ret=1
80grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
81grep "${ORIGINAL_SERIAL}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
82nextpartpeek ns3/named.run | grep "verify-unsigned.*Zone contains no DNSSEC keys" > /dev/null || ret=1
83nextpartpeek ns3/named.run | grep "verify-unsigned.*mirror zone is now in use" > /dev/null && ret=1
84if [ $ret != 0 ]; then echo_i "failed"; fi
85status=`expr $status + $ret`
86
87n=`expr $n + 1`
88echo_i "checking that a mirror zone signed using an untrusted key is rejected ($n)"
89ret=0
90nextpartreset ns3/named.run
91wait_for_transfer verify-untrusted
92$DIG $DIGOPTS @10.53.0.3 +norec verify-untrusted SOA > dig.out.ns3.test$n 2>&1 || ret=1
93grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
94grep "${ORIGINAL_SERIAL}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
95nextpartpeek ns3/named.run | grep "verify-untrusted.*No trusted DNSKEY found" > /dev/null || ret=1
96nextpartpeek ns3/named.run | grep "verify-untrusted.*mirror zone is now in use" > /dev/null && ret=1
97if [ $ret != 0 ]; then echo_i "failed"; fi
98status=`expr $status + $ret`
99
100n=`expr $n + 1`
101echo_i "checking that a mirror zone signed using a CSK without the SEP bit set is accepted ($n)"
102ret=0
103nextpartreset ns3/named.run
104wait_for_transfer verify-csk
105$DIG $DIGOPTS @10.53.0.3 +norec verify-csk SOA > dig.out.ns3.test$n 2>&1 || ret=1
106grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null && ret=1
107grep "${ORIGINAL_SERIAL}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1
108nextpartpeek ns3/named.run | grep "verify-csk.*mirror zone is now in use" > /dev/null || ret=1
109if [ $ret != 0 ]; then echo_i "failed"; fi
110status=`expr $status + $ret`
111
112n=`expr $n + 1`
113echo_i "checking that an AXFR of an incorrectly signed mirror zone is rejected ($n)"
114ret=0
115nextpartreset ns3/named.run
116wait_for_transfer verify-axfr
117$DIG $DIGOPTS @10.53.0.3 +norec verify-axfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
118grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
119grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
120nextpartpeek ns3/named.run | grep "No correct RSASHA256 signature for verify-axfr SOA" > /dev/null || ret=1
121nextpartpeek ns3/named.run | grep "verify-axfr.*mirror zone is now in use" > /dev/null && ret=1
122if [ $ret != 0 ]; then echo_i "failed"; fi
123status=`expr $status + $ret`
124
125n=`expr $n + 1`
126echo_i "checking that an AXFR of an updated, correctly signed mirror zone is accepted ($n)"
127ret=0
128nextpart ns3/named.run > /dev/null
129cat ns2/verify-axfr.db.good.signed > ns2/verify-axfr.db.signed
130reload_zone verify-axfr ${UPDATED_SERIAL_GOOD}
131$RNDCCMD 10.53.0.3 retransfer verify-axfr > /dev/null 2>&1
132wait_for_transfer verify-axfr
133$DIG $DIGOPTS @10.53.0.3 +norec verify-axfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
134grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null && ret=1
135grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1
136nextpartpeek ns3/named.run | grep "verify-axfr.*mirror zone is now in use" > /dev/null || ret=1
137if [ $ret != 0 ]; then echo_i "failed"; fi
138status=`expr $status + $ret`
139
140n=`expr $n + 1`
141echo_i "checking that an IXFR of an incorrectly signed mirror zone is rejected ($n)"
142nextpartreset ns3/named.run
143ret=0
144wait_for_transfer verify-ixfr
145# Sanity check: the initial, properly signed version of the zone should have
146# been announced as coming into effect.
147nextpart ns3/named.run | grep "verify-ixfr.*mirror zone is now in use" > /dev/null || ret=1
148# Make a copy of the original zone file for reuse in journal tests below.
149cp ns2/verify-ixfr.db.signed ns3/verify-journal.db.mirror
150# Wait 1 second so that the zone file timestamp changes and the subsequent
151# invocation of "rndc reload" triggers a zone reload.
152sleep 1
153cat ns2/verify-ixfr.db.bad.signed > ns2/verify-ixfr.db.signed
154reload_zone verify-ixfr ${UPDATED_SERIAL_BAD}
155# Make a copy of the bad zone journal for reuse in journal tests below.
156cp ns2/verify-ixfr.db.signed.jnl ns3/verify-journal.db.bad.mirror.jnl
157# Trigger IXFR.
158$RNDCCMD 10.53.0.3 refresh verify-ixfr > /dev/null 2>&1
159wait_for_transfer verify-ixfr
160# Ensure the transfer was incremental as expected.
161if [ `nextpartpeek ns3/named.run | grep "verify-ixfr.*got incremental response" | wc -l` -eq 0 ]; then
162	echo_i "failed: did not get an incremental response"
163	ret=1
164fi
165# Ensure the new, bad version of the zone was not accepted.
166$DIG $DIGOPTS @10.53.0.3 +norec verify-ixfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
167# A positive answer is expected as the original version of the "verify-ixfr"
168# zone should have been successfully verified.
169grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null && ret=1
170grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
171nextpartpeek ns3/named.run | grep "No correct RSASHA256 signature for verify-ixfr SOA" > /dev/null || ret=1
172# Despite the verification failure for this IXFR, this mirror zone should still
173# be in use as its previous version should have been verified successfully.
174nextpartpeek ns3/named.run | grep "verify-ixfr.*mirror zone is no longer in use" > /dev/null && ret=1
175if [ $ret != 0 ]; then echo_i "failed"; fi
176status=`expr $status + $ret`
177
178n=`expr $n + 1`
179echo_i "checking that an IXFR of an updated, correctly signed mirror zone is accepted after AXFR failover ($n)"
180ret=0
181nextpart ns3/named.run > /dev/null
182# Wait 1 second so that the zone file timestamp changes and the subsequent
183# invocation of "rndc reload" triggers a zone reload.
184sleep 1
185cat ns2/verify-ixfr.db.good.signed > ns2/verify-ixfr.db.signed
186reload_zone verify-ixfr ${UPDATED_SERIAL_GOOD}
187# Make a copy of the good zone journal for reuse in journal tests below.
188cp ns2/verify-ixfr.db.signed.jnl ns3/verify-journal.db.good.mirror.jnl
189# Trigger IXFR.
190$RNDCCMD 10.53.0.3 refresh verify-ixfr > /dev/null 2>&1
191wait_for_transfer verify-ixfr
192# Ensure the new, good version of the zone was accepted.
193$DIG $DIGOPTS @10.53.0.3 +norec verify-ixfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
194grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null && ret=1
195grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1
196# The log message announcing the mirror zone coming into effect should not have
197# been logged this time since the mirror zone in question is expected to
198# already be in use before this test case is checked.
199nextpartpeek ns3/named.run | grep "verify-ixfr.*mirror zone is now in use" > /dev/null && ret=1
200if [ $ret != 0 ]; then echo_i "failed"; fi
201status=`expr $status + $ret`
202
203n=`expr $n + 1`
204echo_i "checking that loading an incorrectly signed mirror zone from disk fails ($n)"
205ret=0
206nextpartreset ns3/named.run
207wait_for_load verify-load ${UPDATED_SERIAL_BAD} ns3/named.run
208$DIG $DIGOPTS @10.53.0.3 +norec verify-load SOA > dig.out.ns3.test$n 2>&1 || ret=1
209grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
210grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
211nextpartpeek ns3/named.run | grep "No correct RSASHA256 signature for verify-load SOA" > /dev/null || ret=1
212nextpartpeek ns3/named.run | grep "verify-load.*mirror zone is now in use" > /dev/null && ret=1
213if [ $ret != 0 ]; then echo_i "failed"; fi
214status=`expr $status + $ret`
215
216n=`expr $n + 1`
217echo_i "ensuring trust anchor telemetry queries are sent upstream for a mirror zone ($n)"
218ret=0
219# ns3 is started with "-T tat=3", so TAT queries should have already been sent.
220grep "_ta-[-0-9a-f]*/NULL" ns1/named.run > /dev/null || ret=1
221if [ $ret != 0 ]; then echo_i "failed"; fi
222status=`expr $status + $ret`
223
224n=`expr $n + 1`
225echo_i "checking that loading a correctly signed mirror zone from disk succeeds ($n)"
226ret=0
227$PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} mirror ns3
228cat ns2/verify-load.db.good.signed > ns3/verify-load.db.mirror
229nextpart ns3/named.run > /dev/null
230$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} mirror ns3
231wait_for_load verify-load ${UPDATED_SERIAL_GOOD} ns3/named.run
232$DIG $DIGOPTS @10.53.0.3 +norec verify-load SOA > dig.out.ns3.test$n 2>&1 || ret=1
233grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null && ret=1
234grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1
235nextpartpeek ns3/named.run | grep "verify-load.*mirror zone is now in use" > /dev/null || ret=1
236if [ $ret != 0 ]; then echo_i "failed"; fi
237status=`expr $status + $ret`
238
239n=`expr $n + 1`
240echo_i "checking that loading a journal for an incorrectly signed mirror zone fails ($n)"
241ret=0
242$PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} mirror ns3
243cp ns3/verify-journal.db.mirror ns3/verify-ixfr.db.mirror
244cp ns3/verify-journal.db.bad.mirror.jnl ns3/verify-ixfr.db.mirror.jnl
245# Temporarily disable transfers of the "verify-ixfr" zone on ns2.  This is
246# required to reliably test whether the message announcing the mirror zone
247# coming into effect is not logged after a failed journal verification since
248# otherwise a corrected version of the zone may be transferred after
249# verification fails but before we look for the aforementioned log message.
250# (NOTE: Keep the embedded newline in the sed function list below.)
251sed '/^zone "verify-ixfr" {$/,/^};$/ {
252	s/10.53.0.3/10.53.0.254/
253}' ns2/named.conf > ns2/named.conf.modified
254mv ns2/named.conf.modified ns2/named.conf
255rndc_reconfig ns2 10.53.0.2
256nextpart ns3/named.run > /dev/null
257$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} mirror ns3
258wait_for_load verify-ixfr ${UPDATED_SERIAL_BAD} ns3/named.run
259$DIG $DIGOPTS @10.53.0.3 +norec verify-ixfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
260grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
261grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
262nextpartpeek ns3/named.run | grep "No correct RSASHA256 signature for verify-ixfr SOA" > /dev/null || ret=1
263nextpartpeek ns3/named.run | grep "verify-ixfr.*mirror zone is now in use" > /dev/null && ret=1
264# Restore transfers for the "verify-ixfr" zone on ns2.
265# (NOTE: Keep the embedded newline in the sed function list below.)
266sed '/^zone "verify-ixfr" {$/,/^};$/ {
267	s/10.53.0.254/10.53.0.3/
268}' ns2/named.conf > ns2/named.conf.modified
269mv ns2/named.conf.modified ns2/named.conf
270rndc_reconfig ns2 10.53.0.2
271if [ $ret != 0 ]; then echo_i "failed"; fi
272status=`expr $status + $ret`
273
274n=`expr $n + 1`
275echo_i "checking that loading a journal for a correctly signed mirror zone succeeds ($n)"
276ret=0
277$PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} mirror ns3
278cp ns3/verify-journal.db.mirror ns3/verify-ixfr.db.mirror
279cp ns3/verify-journal.db.good.mirror.jnl ns3/verify-ixfr.db.mirror.jnl
280nextpart ns3/named.run > /dev/null
281$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} mirror ns3
282wait_for_load verify-ixfr ${UPDATED_SERIAL_GOOD} ns3/named.run
283$DIG $DIGOPTS @10.53.0.3 +norec verify-ixfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
284grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null && ret=1
285grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1
286nextpartpeek ns3/named.run | grep "verify-ixfr.*mirror zone is now in use" > /dev/null || ret=1
287if [ $ret != 0 ]; then echo_i "failed"; fi
288status=`expr $status + $ret`
289
290n=`expr $n + 1`
291echo_i "checking delegations sourced from a mirror zone ($n)"
292ret=0
293$DIG $DIGOPTS @10.53.0.3 foo.example A +norec > dig.out.ns3.test$n 2>&1 || ret=1
294# Check response code and flags in the answer.
295grep "NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
296grep "flags:.* ad" dig.out.ns3.test$n > /dev/null && ret=1
297# Check that a delegation containing a DS RRset and glue is present.
298grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1
299grep "example.*IN.*NS" dig.out.ns3.test$n > /dev/null || ret=1
300grep "example.*IN.*DS" dig.out.ns3.test$n > /dev/null || ret=1
301grep "ns2.example.*A.*10.53.0.2" dig.out.ns3.test$n > /dev/null || ret=1
302if [ $ret != 0 ]; then echo_i "failed"; fi
303status=`expr $status + $ret`
304
305n=`expr $n + 1`
306echo_i "checking that resolution involving a mirror zone works as expected ($n)"
307ret=0
308$DIG $DIGOPTS @10.53.0.3 foo.example A > dig.out.ns3.test$n 2>&1 || ret=1
309# Check response code and flags in the answer.
310grep "NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
311grep "flags:.* ad" dig.out.ns3.test$n > /dev/null || ret=1
312# Ensure ns1 was not queried.
313grep "query 'foo.example/A/IN'" ns1/named.run > /dev/null && ret=1
314if [ $ret != 0 ]; then echo_i "failed"; fi
315status=`expr $status + $ret`
316
317n=`expr $n + 1`
318echo_i "checking that non-recursive queries for names below mirror zone get responded from cache ($n)"
319ret=0
320# Issue a non-recursive query for an RRset which is expected to be in cache.
321$DIG $DIGOPTS @10.53.0.3 +norec foo.example. A > dig.out.ns3.test$n 2>&1 || ret=1
322# Check response code and flags in the answer.
323grep "NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
324grep "flags:.* ad" dig.out.ns3.test$n > /dev/null || ret=1
325# Ensure the response is not a delegation.
326grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null && ret=1
327grep "foo.example.*IN.*A.*127.0.0.1" dig.out.ns3.test$n > /dev/null || ret=1
328if [ $ret != 0 ]; then echo_i "failed"; fi
329status=`expr $status + $ret`
330
331n=`expr $n + 1`
332echo_i "checking that delegations from cache which improve mirror zone delegations are properly handled ($n)"
333ret=0
334# First, issue a recursive query in order to cache an RRset which is not within
335# the mirror zone's bailiwick.
336$DIG $DIGOPTS @10.53.0.3 sub.example. NS > dig.out.ns3.test$n.1 2>&1 || ret=1
337# Ensure the child-side NS RRset is returned.
338grep "NOERROR" dig.out.ns3.test$n.1 > /dev/null || ret=1
339grep "ANSWER: 2" dig.out.ns3.test$n.1 > /dev/null || ret=1
340grep "sub.example.*IN.*NS" dig.out.ns3.test$n.1 > /dev/null || ret=1
341# Issue a non-recursive query for something below the cached zone cut.
342$DIG $DIGOPTS @10.53.0.3 +norec foo.sub.example. A > dig.out.ns3.test$n.2 2>&1 || ret=1
343# Ensure the cached NS RRset is returned in a delegation, along with the
344# parent-side DS RRset.
345grep "NOERROR" dig.out.ns3.test$n.2 > /dev/null || ret=1
346grep "ANSWER: 0" dig.out.ns3.test$n.2 > /dev/null || ret=1
347grep "sub.example.*IN.*NS" dig.out.ns3.test$n.2 > /dev/null || ret=1
348grep "sub.example.*IN.*DS" dig.out.ns3.test$n.2 > /dev/null || ret=1
349if [ $ret != 0 ]; then echo_i "failed"; fi
350status=`expr $status + $ret`
351
352n=`expr $n + 1`
353echo_i "checking flags set in a DNSKEY response sourced from a mirror zone ($n)"
354ret=0
355$DIG $DIGOPTS @10.53.0.3 . DNSKEY > dig.out.ns3.test$n 2>&1 || ret=1
356# Check response code and flags in the answer.
357grep "NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
358grep "flags:.* aa" dig.out.ns3.test$n > /dev/null && ret=1
359grep "flags:.* ad" dig.out.ns3.test$n > /dev/null || ret=1
360if [ $ret != 0 ]; then echo_i "failed"; fi
361status=`expr $status + $ret`
362
363n=`expr $n + 1`
364echo_i "checking flags set in a SOA response sourced from a mirror zone ($n)"
365ret=0
366$DIG $DIGOPTS @10.53.0.3 . SOA > dig.out.ns3.test$n 2>&1 || ret=1
367# Check response code and flags in the answer.
368grep "NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
369grep "flags:.* aa" dig.out.ns3.test$n > /dev/null && ret=1
370grep "flags:.* ad" dig.out.ns3.test$n > /dev/null || ret=1
371if [ $ret != 0 ]; then echo_i "failed"; fi
372status=`expr $status + $ret`
373
374n=`expr $n + 1`
375echo_i "checking that resolution succeeds with unavailable mirror zone data ($n)"
376ret=0
377wait_for_transfer initially-unavailable
378# Query for a record in a zone that is set up to be mirrored, but
379# untransferrable from the configured master.  Resolution should still succeed.
380$DIG $DIGOPTS @10.53.0.3 foo.initially-unavailable. A > dig.out.ns3.test$n.1 2>&1 || ret=1
381# Check response code and flags in the answer.
382grep "NOERROR" dig.out.ns3.test$n.1 > /dev/null || ret=1
383grep "flags:.* ad" dig.out.ns3.test$n.1 > /dev/null || ret=1
384# Sanity check: the authoritative server should have been queried.
385nextpart ns2/named.run | grep "query 'foo.initially-unavailable/A/IN'" > /dev/null || ret=1
386# Reconfigure ns2 so that the zone can be mirrored on ns3.
387sed '/^zone "initially-unavailable" {$/,/^};$/ {
388	s/10.53.0.254/10.53.0.3/
389}' ns2/named.conf > ns2/named.conf.modified
390mv ns2/named.conf.modified ns2/named.conf
391rndc_reconfig ns2 10.53.0.2
392# Flush the cache on ns3 and retransfer the mirror zone.
393$RNDCCMD 10.53.0.3 flush > /dev/null 2>&1
394nextpart ns3/named.run > /dev/null
395$RNDCCMD 10.53.0.3 retransfer initially-unavailable > /dev/null 2>&1
396wait_for_transfer initially-unavailable
397# Query for the same record again.  Resolution should still succeed.
398$DIG $DIGOPTS @10.53.0.3 foo.initially-unavailable. A > dig.out.ns3.test$n.2 2>&1 || ret=1
399# Check response code and flags in the answer.
400grep "NOERROR" dig.out.ns3.test$n.2 > /dev/null || ret=1
401grep "flags:.* ad" dig.out.ns3.test$n.2 > /dev/null || ret=1
402# Ensure the authoritative server was not queried.
403nextpart ns2/named.run | grep "query 'foo.initially-unavailable/A/IN'" > /dev/null && ret=1
404if [ $ret != 0 ]; then echo_i "failed"; fi
405status=`expr $status + $ret`
406
407n=`expr $n + 1`
408echo_i "checking that resolution succeeds with expired mirror zone data ($n)"
409ret=0
410# Reconfigure ns2 so that the zone from the previous test can no longer be
411# mirrored on ns3.
412sed '/^zone "initially-unavailable" {$/,/^};$/ {
413	s/10.53.0.3/10.53.0.254/
414}' ns2/named.conf > ns2/named.conf.modified
415mv ns2/named.conf.modified ns2/named.conf
416rndc_reconfig ns2 10.53.0.2
417# Stop ns3, update the timestamp of the zone file to one far in the past, then
418# restart ns3.
419$PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} mirror ns3
420touch -t 200001010000 ns3/initially-unavailable.db.mirror
421nextpart ns3/named.run > /dev/null
422$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} mirror ns3
423# Ensure named attempts to retransfer the zone due to its expiry.
424wait_for_transfer initially-unavailable
425# Ensure the expected messages were logged.
426nextpartpeek ns3/named.run | grep "initially-unavailable.*expired" > /dev/null || ret=1
427nextpartpeek ns3/named.run | grep "initially-unavailable.*mirror zone is no longer in use" > /dev/null || ret=1
428# Query for a record in the expired zone.  Resolution should still succeed.
429$DIG $DIGOPTS @10.53.0.3 foo.initially-unavailable. A > dig.out.ns3.test$n 2>&1 || ret=1
430# Check response code and flags in the answer.
431grep "NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
432grep "flags:.* ad" dig.out.ns3.test$n > /dev/null || ret=1
433# Sanity check: the authoritative server should have been queried.
434nextpart ns2/named.run | grep "query 'foo.initially-unavailable/A/IN'" > /dev/null || ret=1
435if [ $ret != 0 ]; then echo_i "failed"; fi
436status=`expr $status + $ret`
437
438n=`expr $n + 1`
439echo_i "checking that clients without cache access cannot retrieve mirror zone data ($n)"
440ret=0
441$DIG $DIGOPTS @10.53.0.3 -b 10.53.0.3 +norec . SOA > dig.out.ns3.test$n 2>&1 || ret=1
442# Check response code and flags in the answer.
443grep "REFUSED" dig.out.ns3.test$n > /dev/null || ret=1
444grep "flags:.* ad" dig.out.ns3.test$n > /dev/null && ret=1
445if [ $ret != 0 ]; then echo_i "failed"; fi
446status=`expr $status + $ret`
447
448n=`expr $n + 1`
449echo_i "checking that outgoing transfers of mirror zones are disabled by default ($n)"
450ret=0
451$DIG $DIGOPTS @10.53.0.3 . AXFR > dig.out.ns3.test$n 2>&1 || ret=1
452grep "; Transfer failed" dig.out.ns3.test$n > /dev/null || ret=1
453if [ $ret != 0 ]; then echo_i "failed"; fi
454status=`expr $status + $ret`
455
456n=`expr $n + 1`
457echo_i "checking that notifies are disabled by default for mirror zones ($n)"
458ret=0
459grep "initially-unavailable.*sending notifies" ns3/named.run > /dev/null && ret=1
460if [ $ret != 0 ]; then echo_i "failed"; fi
461status=`expr $status + $ret`
462
463n=`expr $n + 1`
464echo_i "checking output of \"rndc zonestatus\" for a mirror zone ($n)"
465ret=0
466$RNDCCMD 10.53.0.3 zonestatus . > rndc.out.ns3.test$n 2>&1
467grep "type: mirror" rndc.out.ns3.test$n > /dev/null || ret=1
468if [ $ret != 0 ]; then echo_i "failed"; fi
469status=`expr $status + $ret`
470
471n=`expr $n + 1`
472echo_i "checking that \"rndc reconfig\" properly handles a mirror -> slave zone type change ($n)"
473ret=0
474# Sanity check before we start.
475$DIG $DIGOPTS @10.53.0.3 +norec verify-reconfig SOA > dig.out.ns3.test$n.1 2>&1 || ret=1
476grep "NOERROR" dig.out.ns3.test$n.1 > /dev/null || ret=1
477grep "flags:.* aa" dig.out.ns3.test$n.1 > /dev/null && ret=1
478grep "flags:.* ad" dig.out.ns3.test$n.1 > /dev/null || ret=1
479# Reconfigure the zone so that it is no longer a mirror zone.
480# (NOTE: Keep the embedded newline in the sed function list below.)
481sed '/^zone "verify-reconfig" {$/,/^};$/ {
482	s/type mirror;/type slave;/
483}' ns3/named.conf > ns3/named.conf.modified
484mv ns3/named.conf.modified ns3/named.conf
485nextpart ns3/named.run > /dev/null
486rndc_reconfig ns3 10.53.0.3
487# Zones whose type was changed should not be reusable, which means the tested
488# zone should have been reloaded from disk.
489wait_for_load verify-reconfig ${ORIGINAL_SERIAL} ns3/named.run
490# Ensure responses sourced from the reconfigured zone have AA=1 and AD=0.
491$DIG $DIGOPTS @10.53.0.3 +norec verify-reconfig SOA > dig.out.ns3.test$n.2 2>&1 || ret=1
492grep "NOERROR" dig.out.ns3.test$n.2 > /dev/null || ret=1
493grep "flags:.* aa" dig.out.ns3.test$n.2 > /dev/null || ret=1
494grep "flags:.* ad" dig.out.ns3.test$n.2 > /dev/null && ret=1
495if [ $ret != 0 ]; then echo_i "failed"; fi
496status=`expr $status + $ret`
497
498n=`expr $n + 1`
499echo_i "checking that \"rndc reconfig\" properly handles a slave -> mirror zone type change ($n)"
500ret=0
501# Put an incorrectly signed version of the zone in the zone file used by ns3.
502nextpart ns3/named.run > /dev/null
503cat ns2/verify-reconfig.db.bad.signed > ns3/verify-reconfig.db.mirror
504# Reconfigure the zone so that it is a mirror zone again.
505# (NOTE: Keep the embedded newline in the sed function list below.)
506sed '/^zone "verify-reconfig" {$/,/^};$/ {
507	s/type slave;/type mirror;/
508}' ns3/named.conf > ns3/named.conf.modified
509mv ns3/named.conf.modified ns3/named.conf
510rndc_reconfig ns3 10.53.0.3
511# The reconfigured zone should fail verification.
512wait_for_load verify-reconfig ${UPDATED_SERIAL_BAD} ns3/named.run
513$DIG $DIGOPTS @10.53.0.3 +norec verify-reconfig SOA > dig.out.ns3.test$n 2>&1 || ret=1
514grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
515nextpart ns3/named.run | grep "No correct RSASHA256 signature for verify-reconfig SOA" > /dev/null || ret=1
516if [ $ret != 0 ]; then echo_i "failed"; fi
517status=`expr $status + $ret`
518
519n=`expr $n + 1`
520echo_i "checking that a mirror zone can be added using rndc ($n)"
521ret=0
522# Sanity check: the zone should not exist in the root zone.
523$DIG $DIGOPTS @10.53.0.3 +norec verify-addzone SOA > dig.out.ns3.test$n.1 2>&1 || ret=1
524grep "NXDOMAIN" dig.out.ns3.test$n.1 > /dev/null || ret=1
525grep "flags:.* aa" dig.out.ns3.test$n.1 > /dev/null && ret=1
526grep "flags:.* ad" dig.out.ns3.test$n.1 > /dev/null || ret=1
527# Mirror a zone which does not exist in the root zone.
528nextpart ns3/named.run > /dev/null
529$RNDCCMD 10.53.0.3 addzone verify-addzone '{ type mirror; masters { 10.53.0.2; }; };' > rndc.out.ns3.test$n 2>&1 || ret=1
530wait_for_transfer verify-addzone
531# Check whether the mirror zone was added and whether it behaves as expected.
532$DIG $DIGOPTS @10.53.0.3 +norec verify-addzone SOA > dig.out.ns3.test$n.2 2>&1 || ret=1
533grep "NOERROR" dig.out.ns3.test$n.2 > /dev/null || ret=1
534grep "flags:.* aa" dig.out.ns3.test$n.2 > /dev/null && ret=1
535grep "flags:.* ad" dig.out.ns3.test$n.2 > /dev/null || ret=1
536if [ $ret != 0 ]; then echo_i "failed"; fi
537status=`expr $status + $ret`
538
539n=`expr $n + 1`
540echo_i "checking that a mirror zone can be deleted using rndc ($n)"
541ret=0
542# Remove the mirror zone added in the previous test.
543nextpart ns3/named.run > /dev/null
544$RNDCCMD 10.53.0.3 delzone verify-addzone > rndc.out.ns3.test$n 2>&1 || ret=1
545wait_for_log 20 "zone verify-addzone/IN: mirror zone is no longer in use; reverting to normal recursion" ns3/named.run || ret=1
546# Check whether the mirror zone was removed.
547$DIG $DIGOPTS @10.53.0.3 +norec verify-addzone SOA > dig.out.ns3.test$n 2>&1 || ret=1
548grep "NXDOMAIN" dig.out.ns3.test$n > /dev/null || ret=1
549grep "flags:.* aa" dig.out.ns3.test$n > /dev/null && ret=1
550grep "flags:.* ad" dig.out.ns3.test$n > /dev/null || ret=1
551if [ $ret != 0 ]; then echo_i "failed"; fi
552status=`expr $status + $ret`
553
554echo_i "exit status: $status"
555[ $status -eq 0 ] || exit 1
556