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