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