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="+tcp +nosea +nostat +nocmd +norec +noques +noauth +noadd +nostats +dnssec -p ${PORT}"
19RNDCCMD="$RNDC -c ../_common/rndc.conf -p ${CONTROLPORT} -s"
20
21check_zonestatus() (
22  $RNDCCMD "10.53.0.$1" zonestatus -redirect >"zonestatus.out.ns$1.$n" \
23    && grep "type: redirect" "zonestatus.out.ns$1.$n" >/dev/null \
24    && grep "serial: 1" "zonestatus.out.ns$1.$n" >/dev/null
25)
26
27status=0
28n=0
29
30echo_i "checking normally loaded zone ($n)"
31ret=0
32$DIG $DIGOPTS @10.53.0.2 a.normal.example a >dig.out.ns2.$n || ret=1
33grep 'status: NOERROR' dig.out.ns2.$n >/dev/null || ret=1
34grep '^a.normal.example' dig.out.ns2.$n >/dev/null || ret=1
35n=$((n + 1))
36if [ $ret != 0 ]; then echo_i "failed"; fi
37status=$((status + ret))
38
39# When LMDB support is compiled in, this tests that migration from
40# NZF to NZD occurs during named startup
41echo_i "checking previously added zone ($n)"
42ret=0
43$DIG $DIGOPTS @10.53.0.2 a.previous.example a >dig.out.ns2.$n || ret=1
44grep 'status: NOERROR' dig.out.ns2.$n >/dev/null || ret=1
45grep '^a.previous.example' dig.out.ns2.$n >/dev/null || ret=1
46n=$((n + 1))
47if [ $ret != 0 ]; then echo_i "failed"; fi
48status=$((status + ret))
49
50if $FEATURETEST --with-lmdb; then
51  echo_i "checking that existing NZF file was renamed after migration ($n)"
52  [ -e ns2/3bf305731dd26307.nzf~ ] || ret=1
53  n=$((n + 1))
54  if [ $ret != 0 ]; then echo_i "failed"; fi
55  status=$((status + ret))
56fi
57
58echo_i "adding new zone ($n)"
59ret=0
60$RNDCCMD 10.53.0.2 addzone 'added.example { type primary; file "added.db"; };' 2>&1 | sed 's/^/I:ns2 /'
61_check_adding_new_zone() (
62  $DIG $DIGOPTS @10.53.0.2 a.added.example a >dig.out.ns2.$n \
63    && grep 'status: NOERROR' dig.out.ns2.$n >/dev/null \
64    && grep '^a.added.example' dig.out.ns2.$n >/dev/null
65)
66retry_quiet 10 _check_adding_new_zone || ret=1
67n=$((n + 1))
68if [ $ret != 0 ]; then echo_i "failed"; fi
69status=$((status + ret))
70
71nextpart ns2/named.run >/dev/null
72echo_i "checking addzone errors are logged correctly"
73ret=0
74$RNDCCMD 10.53.0.2 addzone bad.example '{ type mister; };' 2>&1 | grep 'unexpected token' >/dev/null 2>&1 || ret=1
75wait_for_log_peek 20 "addzone: 'mister' unexpected" ns2/named.run || ret=1
76n=$((n + 1))
77if [ $ret != 0 ]; then echo_i "failed"; fi
78status=$((status + ret))
79
80nextpart ns2/named.run >/dev/null
81echo_i "checking modzone errors are logged correctly"
82ret=0
83$RNDCCMD 10.53.0.2 modzone added.example '{ type mister; };' 2>&1 | grep 'unexpected token' >/dev/null 2>&1 || ret=1
84wait_for_log_peek 20 "modzone: 'mister' unexpected" ns2/named.run || ret=1
85n=$((n + 1))
86if [ $ret != 0 ]; then echo_i "failed"; fi
87status=$((status + ret))
88
89echo_i "adding a zone that requires quotes ($n)"
90ret=0
91$RNDCCMD 10.53.0.2 addzone '"32/1.0.0.127-in-addr.added.example" {
92check-names ignore; type primary; file "added.db"; };' 2>&1 | sed 's/^/I:ns2 /'
93_check_zone_that_requires_quotes() (
94  $DIG $DIGOPTS @10.53.0.2 "a.32/1.0.0.127-in-addr.added.example" a >dig.out.ns2.$n \
95    && grep 'status: NOERROR' dig.out.ns2.$n >/dev/null \
96    && grep '^a.32/1.0.0.127-in-addr.added.example' dig.out.ns2.$n >/dev/null
97)
98retry_quiet 10 _check_zone_that_requires_quotes || ret=1
99n=$((n + 1))
100if [ $ret != 0 ]; then echo_i "failed"; fi
101status=$((status + ret))
102
103echo_i "adding a zone with a quote in the name ($n)"
104ret=0
105$RNDCCMD 10.53.0.2 addzone '"foo\"bar.example" { check-names ignore; type primary; file "added.db"; };' 2>&1 | sed 's/^/I:ns2 /'
106_check_zone_with_a_quote() (
107  $DIG $DIGOPTS @10.53.0.2 "a.foo\"bar.example" a >dig.out.ns2.$n \
108    && grep 'status: NOERROR' dig.out.ns2.$n >/dev/null \
109    && grep '^a.foo\\"bar.example' dig.out.ns2.$n >/dev/null
110)
111retry_quiet 10 _check_zone_with_a_quote || ret=1
112n=$((n + 1))
113if [ $ret != 0 ]; then echo_i "failed"; fi
114status=$((status + ret))
115
116echo_i "adding new zone with missing file ($n)"
117ret=0
118$DIG $DIGOPTS +all @10.53.0.2 a.missing.example a >dig.out.ns2.pre.$n || ret=1
119grep "status: REFUSED" dig.out.ns2.pre.$n >/dev/null || ret=1
120$RNDCCMD 10.53.0.2 addzone 'missing.example { type primary; file "missing.db"; };' 2>rndc.out.ns2.$n && ret=1
121grep "file not found" rndc.out.ns2.$n >/dev/null || ret=1
122$DIG $DIGOPTS +all @10.53.0.2 a.missing.example a >dig.out.ns2.post.$n || ret=1
123grep "status: REFUSED" dig.out.ns2.post.$n >/dev/null || ret=1
124digcomp dig.out.ns2.pre.$n dig.out.ns2.post.$n || ret=1
125n=$((n + 1))
126if [ $ret != 0 ]; then echo_i "failed"; fi
127status=$((status + ret))
128
129if ! $FEATURETEST --with-lmdb; then
130  echo_i "verifying no comments in NZF file ($n)"
131  ret=0
132  hcount=$(grep "^# New zone file for view: _default" ns2/3bf305731dd26307.nzf | wc -l)
133  [ $hcount -eq 0 ] || ret=1
134  n=$((n + 1))
135  if [ $ret != 0 ]; then echo_i "failed"; fi
136  status=$((status + ret))
137fi
138
139echo_i "checking rndc showzone with previously added zone ($n)"
140ret=0
141$RNDCCMD 10.53.0.2 showzone previous.example >rndc.out.ns2.$n
142expected='zone "previous.example" { type primary; file "previous.db"; };'
143[ "$(cat rndc.out.ns2.$n)" = "$expected" ] || ret=1
144n=$((n + 1))
145if [ $ret != 0 ]; then echo_i "failed"; fi
146status=$((status + ret))
147
148if $FEATURETEST --with-lmdb; then
149  echo_i "checking zone is present in NZD ($n)"
150  ret=0
151  $NZD2NZF ns2/_default.nzd | grep previous.example >/dev/null || ret=1
152  if [ $ret != 0 ]; then echo_i "failed"; fi
153  status=$((status + ret))
154fi
155
156echo_i "deleting previously added zone ($n)"
157ret=0
158$RNDCCMD 10.53.0.2 delzone previous.example 2>&1 | sed 's/^/I:ns2 /'
159_check_deleting_previously_added_zone() (
160  $DIG $DIGOPTS @10.53.0.2 a.previous.example a >dig.out.ns2.$n \
161    && grep 'status: REFUSED' dig.out.ns2.$n >/dev/null \
162    && ! grep '^a.previous.example' dig.out.ns2.$n >/dev/null
163)
164retry_quiet 10 _check_deleting_previously_added_zone || ret=1
165n=$((n + 1))
166if [ $ret != 0 ]; then echo_i "failed"; fi
167status=$((status + ret))
168
169check_nzd2nzf() (
170  $NZD2NZF ns2/_default.nzd >nzd2nzf.out.$n \
171    && ! grep previous.example nzd2nzf.out.$n >/dev/null
172)
173
174if $FEATURETEST --with-lmdb; then
175  echo_i "checking zone was deleted from NZD ($n)"
176  retry_quiet 10 check_nzd2nzf || ret=1
177  if [ $ret != 0 ]; then echo_i "failed"; fi
178  status=$((status + ret))
179fi
180
181if ! $FEATURETEST --with-lmdb; then
182  echo_i "checking NZF file now has comment ($n)"
183  ret=0
184  hcount=$(grep "^# New zone file for view: _default" ns2/3bf305731dd26307.nzf | wc -l)
185  [ $hcount -eq 1 ] || ret=1
186  n=$((n + 1))
187  if [ $ret != 0 ]; then echo_i "failed"; fi
188  status=$((status + ret))
189fi
190
191echo_i "deleting newly added zone added.example ($n)"
192ret=0
193$RNDCCMD 10.53.0.2 delzone added.example 2>&1 | sed 's/^/I:ns2 /'
194_check_deleting_newly_added_zone() (
195  $DIG $DIGOPTS @10.53.0.2 a.added.example a >dig.out.ns2.$n \
196    && grep 'status: REFUSED' dig.out.ns2.$n >/dev/null \
197    && ! grep '^a.added.example' dig.out.ns2.$n >/dev/null
198)
199retry_quiet 10 _check_deleting_newly_added_zone || ret=1
200n=$((n + 1))
201if [ $ret != 0 ]; then echo_i "failed"; fi
202status=$((status + ret))
203
204echo_i "deleting newly added zone with escaped quote ($n)"
205ret=0
206$RNDCCMD 10.53.0.2 delzone "foo\\\"bar.example" 2>&1 | sed 's/^/I:ns2 /'
207_check_deleting_newly_added_zone_quote() (
208  $DIG $DIGOPTS @10.53.0.2 "a.foo\"bar.example" a >dig.out.ns2.$n \
209    && grep 'status: REFUSED' dig.out.ns2.$n >/dev/null \
210    && ! grep "^a.foo\"bar.example" dig.out.ns2.$n >/dev/null
211)
212retry_quiet 10 _check_deleting_newly_added_zone_quote || ret=1
213n=$((n + 1))
214if [ $ret != 0 ]; then echo_i "failed"; fi
215status=$((status + ret))
216
217echo_i "checking rndc showzone with a normally-loaded zone ($n)"
218ret=0
219$RNDCCMD 10.53.0.2 showzone normal.example >rndc.out.ns2.$n
220expected='zone "normal.example" { type primary; file "normal.db"; };'
221[ "$(cat rndc.out.ns2.$n)" = "$expected" ] || ret=1
222n=$((n + 1))
223if [ $ret != 0 ]; then echo_i "failed"; fi
224status=$((status + ret))
225
226echo_i "checking rndc showzone with a normally-loaded zone with trailing dot ($n)"
227ret=0
228$RNDCCMD 10.53.0.2 showzone finaldot.example >rndc.out.ns2.$n
229expected='zone "finaldot.example." { type primary; file "normal.db"; };'
230[ "$(cat rndc.out.ns2.$n)" = "$expected" ] || ret=1
231n=$((n + 1))
232if [ $ret != 0 ]; then echo_i "failed"; fi
233status=$((status + ret))
234
235echo_i "checking rndc showzone with a normally-loaded redirect zone ($n)"
236ret=0
237$RNDCCMD 10.53.0.1 showzone -redirect >rndc.out.ns1.$n
238expected='zone "." { type redirect; file "redirect.db"; };'
239[ "$(cat rndc.out.ns1.$n)" = "$expected" ] || ret=1
240n=$((n + 1))
241if [ $ret != 0 ]; then echo_i "failed"; fi
242status=$((status + ret))
243
244echo_i "checking rndc zonestatus with a normally-loaded redirect zone ($n)"
245ret=0
246$RNDCCMD 10.53.0.1 zonestatus -redirect >rndc.out.ns1.$n
247grep "type: redirect" rndc.out.ns1.$n >/dev/null || ret=1
248grep "serial: 0" rndc.out.ns1.$n >/dev/null || ret=1
249n=$((n + 1))
250if [ $ret != 0 ]; then echo_i "failed"; fi
251status=$((status + ret))
252
253echo_i "checking rndc reload with a normally-loaded redirect zone ($n)"
254ret=0
255sleep 1
256cp -f ns1/redirect.db.2 ns1/redirect.db
257$RNDCCMD 10.53.0.1 reload -redirect >rndc.out.ns1.$n
258retry_quiet 5 check_zonestatus 1 || ret=1
259n=$((n + 1))
260if [ $ret != 0 ]; then echo_i "failed"; fi
261status=$((status + ret))
262
263echo_i "delete a normally-loaded zone ($n)"
264ret=0
265$RNDCCMD 10.53.0.2 delzone normal.example >rndc.out.ns2.$n 2>&1
266grep "is no longer active and will be deleted" rndc.out.ns2.$n >/dev/null || ret=11
267grep "To keep it from returning when the server is restarted" rndc.out.ns2.$n >/dev/null || ret=1
268grep "must also be removed from named.conf." rndc.out.ns2.$n >/dev/null || ret=1
269_check_delete_normally_loaded_zone() (
270  $DIG $DIGOPTS @10.53.0.2 a.normal.example a >dig.out.ns2.$n \
271    && grep 'status: REFUSED' dig.out.ns2.$n >/dev/null
272)
273retry_quiet 5 _check_delete_normally_loaded_zone || ret=1
274
275n=$((n + 1))
276if [ $ret != 0 ]; then echo_i "failed"; fi
277status=$((status + ret))
278
279echo_i "attempting to add primary zone with inline signing ($n)"
280$RNDCCMD 10.53.0.2 addzone 'inline.example { type primary; file "inline.db"; inline-signing yes; };' 2>&1 | sed 's/^/I:ns2 /'
281_check_add_primary_zone_with_inline() (
282  $DIG $DIGOPTS @10.53.0.2 a.inline.example a >dig.out.ns2.$n \
283    && grep 'status: NOERROR' dig.out.ns2.$n >/dev/null \
284    && grep '^a.inline.example' dig.out.ns2.$n >/dev/null
285)
286retry_quiet 5 _check_add_primary_zone_with_inline || ret=1
287n=$((n + 1))
288if [ $ret != 0 ]; then echo_i "failed"; fi
289status=$((status + ret))
290
291echo_i "attempting to add primary zone with inline signing and missing file ($n)"
292ret=0
293$RNDCCMD 10.53.0.2 addzone 'inlinemissing.example { type primary; file "missing.db"; inline-signing yes; };' 2>rndc.out.ns2.$n && ret=1
294grep "file not found" rndc.out.ns2.$n >/dev/null || ret=1
295n=$((n + 1))
296if [ $ret != 0 ]; then echo_i "failed"; fi
297status=$((status + ret))
298
299echo_i "attempting to add secondary zone with inline signing ($n)"
300$RNDCCMD 10.53.0.2 addzone 'inlinesec.example { type secondary; primaries { 10.53.0.1; }; file "inlinesec.bk"; inline-signing yes; };' 2>&1 | sed 's/^/I:ns2 /'
301_check_add_secondary_with_inline() (
302  $DIG $DIGOPTS @10.53.0.2 a.inlinesec.example a >dig.out.ns2.$n \
303    && grep 'status: NOERROR' dig.out.ns2.$n >/dev/null \
304    && grep '^a.inlinesec.example' dig.out.ns2.$n >/dev/null
305)
306retry_quiet 5 _check_add_secondary_with_inline || ret=1
307n=$((n + 1))
308if [ $ret != 0 ]; then echo_i "failed"; fi
309status=$((status + ret))
310
311echo_i "attempting to delete secondary zone with inline signing ($n)"
312ret=0
313retry_quiet 10 test -f ns2/inlinesec.bk.signed -a -f ns2/inlinesec.bk || ret=1
314$RNDCCMD 10.53.0.2 delzone inlinesec.example >rndc.out2.test$n 2>&1 || ret=1
315test -f inlinesec.bk \
316  || grep '^inlinesec.bk$' rndc.out2.test$n >/dev/null || {
317  echo_i "failed to report inlinesec.bk"
318  ret=1
319}
320test ! -f inlinesec.bk.signed \
321  || grep '^inlinesec.bk.signed$' rndc.out2.test$n >/dev/null || {
322  echo_i "failed to report inlinesec.bk.signed"
323  ret=1
324}
325n=$((n + 1))
326status=$((status + ret))
327
328echo_i "restoring secondary zone with inline signing ($n)"
329$RNDCCMD 10.53.0.2 addzone 'inlinesec.example { type secondary; primaries { 10.53.0.1; }; file "inlinesec.bk"; inline-signing yes; };' 2>&1 | sed 's/^/I:ns2 /'
330_check_restoring_secondary_with_inline() (
331  $DIG $DIGOPTS @10.53.0.2 a.inlinesec.example a >dig.out.ns2.$n \
332    && grep 'status: NOERROR' dig.out.ns2.$n >/dev/null \
333    && grep '^a.inlinesec.example' dig.out.ns2.$n >/dev/null
334)
335retry_quiet 5 _check_restoring_secondary_with_inline || ret=1
336n=$((n + 1))
337if [ $ret != 0 ]; then echo_i "failed"; fi
338status=$((status + ret))
339
340echo_i "deleting secondary zone with automatic zone file removal ($n)"
341ret=0
342retry_quiet 10 test -f ns2/inlinesec.bk.signed -a -f ns2/inlinesec.bk || ret=1
343$RNDCCMD 10.53.0.2 delzone -clean inlinesec.example >/dev/null 2>&1
344retry_quiet 10 test ! -f ns2/inlinesec.bk.signed -a ! -f ns2/inlinesec.bk
345n=$((n + 1))
346status=$((status + ret))
347
348echo_i "modifying zone configuration ($n)"
349ret=0
350$RNDCCMD 10.53.0.2 addzone 'mod.example { type primary; file "added.db"; };' 2>&1 | sed 's/^/ns2 /' | cat_i
351$DIG +norec $DIGOPTS @10.53.0.2 mod.example ns >dig.out.ns2.1.$n || ret=1
352grep 'status: NOERROR' dig.out.ns2.1.$n >/dev/null || ret=1
353$RNDCCMD 10.53.0.2 modzone 'mod.example { type primary; file "added.db"; allow-query { none; }; };' 2>&1 | sed 's/^/ns2 /' | cat_i
354$DIG +norec $DIGOPTS @10.53.0.2 mod.example ns >dig.out.ns2.2.$n || ret=1
355$RNDCCMD 10.53.0.2 showzone mod.example | grep 'allow-query { "none"; };' >/dev/null 2>&1 || ret=1
356n=$((n + 1))
357if [ $ret != 0 ]; then echo_i "failed"; fi
358status=$((status + ret))
359
360echo_i "check that adding a 'stub' zone works ($n)"
361ret=0
362$RNDCCMD 10.53.0.2 addzone 'stub.example { type stub; primaries { 1.2.3.4; }; file "stub.example.bk"; };' >rndc.out.ns2.$n 2>&1 || ret=1
363n=$((n + 1))
364if [ $ret != 0 ]; then echo_i "failed"; fi
365status=$((status + ret))
366
367echo_i "check that adding a 'static-stub' zone works ($n)"
368ret=0
369$RNDCCMD 10.53.0.2 addzone 'static-stub.example { type static-stub; server-addresses { 1.2.3.4; }; };' >rndc.out.ns2.$n 2>&1 || ret=1
370n=$((n + 1))
371if [ $ret != 0 ]; then echo_i "failed"; fi
372status=$((status + ret))
373
374echo_i "check that adding a 'primary redirect' zone works ($n)"
375ret=0
376$RNDCCMD 10.53.0.2 addzone '"." { type redirect; file "redirect.db"; };' >rndc.out.ns2.$n 2>&1 || ret=1
377_check_add_primary_redirect() (
378  $RNDCCMD 10.53.0.2 showzone -redirect >showzone.out.ns2.$n 2>&1 \
379    && grep "type redirect;" showzone.out.ns2.$n >/dev/null \
380    && $RNDCCMD 10.53.0.2 zonestatus -redirect >zonestatus.out.ns2.$n 2>&1 \
381    && grep "type: redirect" zonestatus.out.ns2.$n >/dev/null \
382    && grep "serial: 0" zonestatus.out.ns2.$n >/dev/null
383)
384retry_quiet 10 _check_add_primary_redirect || ret=1
385n=$((n + 1))
386if [ $ret != 0 ]; then echo_i "failed"; fi
387status=$((status + ret))
388
389echo_i "check that reloading a added 'primary redirect' zone works ($n)"
390ret=0
391sleep 1
392cp -f ns2/redirect.db.2 ns2/redirect.db
393$RNDCCMD 10.53.0.2 reload -redirect >rndc.out.ns2.$n
394retry_quiet 10 check_zonestatus 2 || ret=1
395n=$((n + 1))
396if [ $ret != 0 ]; then echo_i "failed"; fi
397status=$((status + ret))
398
399echo_i "check that retransfer of a added 'primary redirect' zone fails ($n)"
400ret=0
401$RNDCCMD 10.53.0.2 retransfer -redirect >rndc.out.ns2.$n 2>&1 && ret=1
402n=$((n + 1))
403if [ $ret != 0 ]; then echo_i "failed"; fi
404status=$((status + ret))
405
406echo_i "check that deleting a 'primary redirect' zone works ($n)"
407ret=0
408$RNDCCMD 10.53.0.2 delzone -redirect >rndc.out.ns2.$n 2>&1 || ret=1
409_check_deleting_primary_redirect() (
410  $RNDCCMD 10.53.0.2 showzone -redirect >showzone.out.ns2.$n 2>&1 || true
411  grep 'not found' showzone.out.ns2.$n >/dev/null
412)
413retry_quiet 10 _check_deleting_primary_redirect || ret=1
414n=$((n + 1))
415if [ $ret != 0 ]; then echo_i "failed"; fi
416status=$((status + ret))
417
418echo_i "check that adding a 'secondary redirect' zone works ($n)"
419ret=0
420$RNDCCMD 10.53.0.2 addzone '"." { type redirect; primaries { 10.53.0.3;}; file "redirect.bk"; };' >rndc.out.ns2.$n 2>&1 || ret=1
421_check_adding_secondary_redirect() (
422  $RNDCCMD 10.53.0.2 showzone -redirect >showzone.out.ns2.$n 2>&1 \
423    && grep "type redirect;" showzone.out.ns2.$n >/dev/null \
424    && $RNDCCMD 10.53.0.2 zonestatus -redirect >zonestatus.out.ns2.$n 2>&1 \
425    && grep "type: redirect" zonestatus.out.ns2.$n >/dev/null \
426    && grep "serial: 0" zonestatus.out.ns2.$n >/dev/null
427)
428retry_quiet 10 _check_adding_secondary_redirect || ret=1
429n=$((n + 1))
430if [ $ret != 0 ]; then echo_i "failed"; fi
431status=$((status + ret))
432
433echo_i "check that retransfering a added 'secondary redirect' zone works ($n)"
434ret=0
435cp -f ns3/redirect.db.2 ns3/redirect.db
436$RNDCCMD 10.53.0.3 reload . >showzone.out.ns3.$n 2>&1 || ret=1
437_check_retransfering_secondary_redirect() (
438  $RNDCCMD 10.53.0.2 retransfer -redirect >rndc.out.ns2.$n 2>&1 \
439    && $RNDCCMD 10.53.0.2 zonestatus -redirect >zonestatus.out.ns2.$n 2>&1 \
440    && grep "type: redirect" zonestatus.out.ns2.$n >/dev/null \
441    && grep "serial: 1" zonestatus.out.ns2.$n >/dev/null
442)
443retry_quiet 10 _check_retransfering_secondary_redirect || ret=1
444n=$((n + 1))
445if [ $ret != 0 ]; then echo_i "failed"; fi
446status=$((status + ret))
447
448echo_i "check that deleting a 'secondary redirect' zone works ($n)"
449ret=0
450$RNDCCMD 10.53.0.2 delzone -redirect >rndc.out.ns2.$n 2>&1 || ret=1
451_check_deleting_secondary_redirect() (
452  $RNDCCMD 10.53.0.2 showzone -redirect >showzone.out.ns2.$n 2>&1 || true
453  grep 'not found' showzone.out.ns2.$n >/dev/null
454)
455retry_quiet 10 _check_deleting_secondary_redirect || ret=1
456n=$((n + 1))
457if [ $ret != 0 ]; then echo_i "failed"; fi
458status=$((status + ret))
459
460echo_i "check that zone type 'hint' is properly rejected ($n)"
461ret=0
462$RNDCCMD 10.53.0.2 addzone '"." { type hint; file "hints.db"; };' >rndc.out.ns2.$n 2>&1 && ret=1
463grep "zones not supported by addzone" rndc.out.ns2.$n >/dev/null || ret=1
464n=$((n + 1))
465if [ $ret != 0 ]; then echo_i "failed"; fi
466status=$((status + ret))
467
468echo_i "check that zone type 'forward' is properly rejected ($n)"
469ret=0
470$RNDCCMD 10.53.0.2 addzone 'forward.example { type forward; forwarders { 1.2.3.4; }; forward only; };' >rndc.out.ns2.$n 2>&1 && ret=1
471grep "zones not supported by addzone" rndc.out.ns2.$n >/dev/null || ret=1
472n=$((n + 1))
473if [ $ret != 0 ]; then echo_i "failed"; fi
474status=$((status + ret))
475
476echo_i "check that zone type 'delegation-only' is properly rejected ($n)"
477ret=0
478$RNDCCMD 10.53.0.2 addzone 'delegation-only.example { type delegation-only; };' >rndc.out.ns2.$n 2>&1 && ret=1
479grep "zones not supported by addzone" rndc.out.ns2.$n >/dev/null || ret=1
480n=$((n + 1))
481if [ $ret != 0 ]; then echo_i "failed"; fi
482status=$((status + ret))
483
484echo_i "check that 'in-view' zones are properly rejected ($n)"
485ret=0
486$RNDCCMD 10.53.0.2 addzone 'in-view.example { in-view "_default"; };' >rndc.out.ns2.$n 2>&1 && ret=1
487grep "zones not supported by addzone" rndc.out.ns2.$n >/dev/null || ret=1
488n=$((n + 1))
489if [ $ret != 0 ]; then echo_i "failed"; fi
490status=$((status + ret))
491
492echo_i "reconfiguring server with multiple views"
493rm -f ns2/named.conf
494copy_setports ns2/named2.conf.in ns2/named.conf
495rndc_reconfig ns2 10.53.0.2
496
497echo_i "adding new zone to external view ($n)"
498# NOTE: The internal view has "recursion yes" set, and so queries for
499# nonexistent zones should return NOERROR.  The external view is
500# "recursion no", so queries for nonexistent zones should return
501# REFUSED.  This behavior should be the same regardless of whether
502# the zone does not exist because a) it has not yet been loaded, b)
503# it failed to load, or c) it has been deleted.
504ret=0
505$DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.added.example a >dig.out.ns2.intpre.$n || ret=1
506grep 'status: NOERROR' dig.out.ns2.intpre.$n >/dev/null || ret=1
507$DIG +norec $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a >dig.out.ns2.extpre.$n || ret=1
508grep 'status: REFUSED' dig.out.ns2.extpre.$n >/dev/null || ret=1
509$RNDCCMD 10.53.0.2 addzone 'added.example in external { type primary; file "added.db"; };' 2>&1 | sed 's/^/I:ns2 /'
510$DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.added.example a >dig.out.ns2.int.$n || ret=1
511grep 'status: NOERROR' dig.out.ns2.int.$n >/dev/null || ret=1
512$DIG +norec $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a >dig.out.ns2.ext.$n || ret=1
513grep 'status: NOERROR' dig.out.ns2.ext.$n >/dev/null || ret=1
514grep '^a.added.example' dig.out.ns2.ext.$n >/dev/null || ret=1
515n=$((n + 1))
516if [ $ret != 0 ]; then echo_i "failed"; fi
517status=$((status + ret))
518
519if ! $FEATURETEST --with-lmdb; then
520  echo_i "checking new NZF file has comment ($n)"
521  ret=0
522  hcount=$(grep "^# New zone file for view: external" ns2/external.nzf | wc -l)
523  [ $hcount -eq 1 ] || ret=1
524  n=$((n + 1))
525  if [ $ret != 0 ]; then echo_i "failed"; fi
526  status=$((status + ret))
527fi
528
529if $FEATURETEST --with-lmdb; then
530  echo_i "verifying added.example in external view created an external.nzd DB ($n)"
531  ret=0
532  [ -e ns2/external.nzd ] || ret=1
533  n=$((n + 1))
534  if [ $ret != 0 ]; then echo_i "failed"; fi
535  status=$((status + ret))
536fi
537
538echo_i "checking rndc reload causes named to reload the external view's new zone config ($n)"
539ret=0
540$RNDCCMD 10.53.0.2 reload 2>&1 | sed 's/^/ns2 /' | cat_i
541_check_rndc_reload_external_view_config() (
542  $DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.added.example a >dig.out.ns2.int.$n \
543    && grep 'status: NOERROR' dig.out.ns2.int.$n >/dev/null \
544    && $DIG +norec $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a >dig.out.ns2.ext.$n \
545    && grep 'status: NOERROR' dig.out.ns2.ext.$n >/dev/null \
546    && grep '^a.added.example' dig.out.ns2.ext.$n >/dev/null
547)
548retry_quiet 10 _check_rndc_reload_external_view_config || ret=1
549n=$((n + 1))
550if [ $ret != 0 ]; then echo_i "failed"; fi
551status=$((status + ret))
552
553echo_i "checking rndc showzone with newly added zone ($n)"
554_check_rndc_showzone_newly_added() (
555  if ! $FEATURETEST --with-lmdb; then
556    expected='zone "added.example" in external { type primary; file "added.db"; };'
557  else
558    expected='zone "added.example" { type primary; file "added.db"; };'
559  fi
560  $RNDCCMD 10.53.0.2 showzone added.example in external >rndc.out.ns2.$n 2>/dev/null \
561    && [ "$(cat rndc.out.ns2.$n)" = "$expected" ]
562)
563retry_quiet 10 _check_rndc_showzone_newly_added || ret=1
564n=$((n + 1))
565if [ $ret != 0 ]; then echo_i "failed"; fi
566status=$((status + ret))
567
568echo_i "deleting newly added zone ($n)"
569ret=0
570$RNDCCMD 10.53.0.2 delzone 'added.example in external' 2>&1 | sed 's/^/I:ns2 /'
571_check_deleting_newly_added_zone() (
572  $DIG $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a >dig.out.ns2.$n \
573    && grep 'status: REFUSED' dig.out.ns2.$n >/dev/null \
574    && ! grep '^a.added.example' dig.out.ns2.$n >/dev/null
575)
576retry_quiet 10 _check_deleting_newly_added_zone || ret=1
577n=$((n + 1))
578if [ $ret != 0 ]; then echo_i "failed"; fi
579status=$((status + ret))
580
581echo_i "attempting to add zone to internal view ($n)"
582ret=0
583$DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.added.example a >dig.out.ns2.pre.$n || ret=1
584grep 'status: NOERROR' dig.out.ns2.pre.$n >/dev/null || ret=1
585$RNDCCMD 10.53.0.2 addzone 'added.example in internal { type primary; file "added.db"; };' 2>rndc.out.ns2.$n && ret=1
586grep "permission denied" rndc.out.ns2.$n >/dev/null || ret=1
587$DIG $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.added.example a >dig.out.ns2.int.$n || ret=1
588grep 'status: NOERROR' dig.out.ns2.int.$n >/dev/null || ret=1
589$DIG $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a >dig.out.ns2.ext.$n || ret=1
590grep 'status: REFUSED' dig.out.ns2.ext.$n >/dev/null || ret=1
591n=$((n + 1))
592if [ $ret != 0 ]; then echo_i "failed"; fi
593status=$((status + ret))
594
595echo_i "attempting to delete a policy zone ($n)"
596ret=0
597$RNDCCMD 10.53.0.2 delzone 'policy in internal' 2>rndc.out.ns2.$n >&1 && ret=1
598grep 'cannot be deleted' rndc.out.ns2.$n >/dev/null || ret=1
599n=$((n + 1))
600if [ $ret != 0 ]; then echo_i "failed"; fi
601status=$((status + ret))
602
603echo_i "adding new zone again to external view ($n)"
604ret=0
605$RNDCCMD 10.53.0.2 addzone 'added.example in external { type primary; file "added.db"; };' 2>&1 | sed 's/^/I:ns2 /'
606_check_adding_new_zone_again_external() (
607  $DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.added.example a >dig.out.ns2.int.$n \
608    && grep 'status: NOERROR' dig.out.ns2.int.$n >/dev/null \
609    && $DIG +norec $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a >dig.out.ns2.ext.$n \
610    && grep 'status: NOERROR' dig.out.ns2.ext.$n >/dev/null \
611    && grep '^a.added.example' dig.out.ns2.ext.$n >/dev/null
612)
613retry_quiet 10 _check_adding_new_zone_again_external || ret=1
614n=$((n + 1))
615if [ $ret != 0 ]; then echo_i "failed"; fi
616status=$((status + ret))
617
618echo_i "reconfiguring server with multiple views and new-zones-directory"
619rm -f ns2/named.conf
620copy_setports ns2/named3.conf.in ns2/named.conf
621rndc_reconfig ns2 10.53.0.2
622
623echo_i "checking new zone is still loaded after dir change ($n)"
624ret=0
625$DIG +norec $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a >dig.out.ns2.ext.$n || ret=1
626grep 'status: NOERROR' dig.out.ns2.ext.$n >/dev/null || ret=1
627grep '^a.added.example' dig.out.ns2.ext.$n >/dev/null || ret=1
628n=$((n + 1))
629if [ $ret != 0 ]; then echo_i "failed"; fi
630status=$((status + ret))
631
632echo_i "deleting newly added zone from external ($n)"
633ret=0
634$RNDCCMD 10.53.0.2 delzone 'added.example in external' 2>&1 | sed 's/^/I:ns2 /'
635$DIG $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a >dig.out.ns2.$n || ret=1
636grep 'status: REFUSED' dig.out.ns2.$n >/dev/null || ret=1
637grep '^a.added.example' dig.out.ns2.$n >/dev/null && ret=1
638n=$((n + 1))
639if [ $ret != 0 ]; then echo_i "failed"; fi
640status=$((status + ret))
641
642echo_i "adding new zone to directory view ($n)"
643ret=0
644$DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.added.example a >dig.out.ns2.intpre.$n || ret=1
645grep 'status: NOERROR' dig.out.ns2.intpre.$n >/dev/null || ret=1
646$DIG +norec $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a >dig.out.ns2.extpre.$n || ret=1
647grep 'status: REFUSED' dig.out.ns2.extpre.$n >/dev/null || ret=1
648$DIG +norec $DIGOPTS @10.53.0.5 -b 10.53.0.5 a.added.example a >dig.out.ns2.dirpre.$n || ret=1
649grep 'status: REFUSED' dig.out.ns2.dirpre.$n >/dev/null || ret=1
650$RNDCCMD 10.53.0.2 addzone 'added.example in directory { type primary; file "added.db"; };' 2>&1 | sed 's/^/I:ns2 /'
651$DIG +norec $DIGOPTS @10.53.0.2 -b 10.53.0.2 a.added.example a >dig.out.ns2.int.$n || ret=1
652grep 'status: NOERROR' dig.out.ns2.int.$n >/dev/null || ret=1
653$DIG +norec $DIGOPTS @10.53.0.4 -b 10.53.0.4 a.added.example a >dig.out.ns2.ext.$n || ret=1
654grep 'status: REFUSED' dig.out.ns2.ext.$n >/dev/null || ret=1
655$DIG +norec $DIGOPTS @10.53.0.5 -b 10.53.0.5 a.added.example a >dig.out.ns2.dir.$n || ret=1
656grep 'status: NOERROR' dig.out.ns2.dir.$n >/dev/null || ret=1
657grep '^a.added.example' dig.out.ns2.dir.$n >/dev/null || ret=1
658n=$((n + 1))
659if [ $ret != 0 ]; then echo_i "failed"; fi
660status=$((status + ret))
661
662if $FEATURETEST --with-lmdb; then
663  echo_i "checking NZD file was created in new-zones-directory ($n)"
664  expect=ns2/new-zones/directory.nzd
665else
666  echo_i "checking NZF file was created in new-zones-directory ($n)"
667  expect=ns2/new-zones/directory.nzf
668fi
669$RNDCCMD 10.53.0.2 sync 'added.example IN directory' 2>&1 | sed 's/^/I:ns2 /'
670sleep 2
671[ -e "$expect" ] || ret=1
672n=$((n + 1))
673if [ $ret != 0 ]; then echo_i "failed"; fi
674status=$((status + ret))
675
676echo_i "deleting newly added zone from directory ($n)"
677ret=0
678$RNDCCMD 10.53.0.2 delzone 'added.example in directory' 2>&1 | sed 's/^/I:ns2 /'
679$DIG $DIGOPTS @10.53.0.5 -b 10.53.0.5 a.added.example a >dig.out.ns2.$n || ret=1
680grep 'status: REFUSED' dig.out.ns2.$n >/dev/null || ret=1
681grep '^a.added.example' dig.out.ns2.$n >/dev/null && ret=1
682n=$((n + 1))
683if [ $ret != 0 ]; then echo_i "failed"; fi
684status=$((status + ret))
685
686echo_i "ensure the configuration context is cleaned up correctly ($n)"
687ret=0
688rndc_reconfig ns2 10.53.0.2
689$RNDCCMD 10.53.0.2 status >/dev/null 2>&1 || ret=1
690n=$((n + 1))
691if [ $ret != 0 ]; then echo_i "failed"; fi
692status=$((status + ret))
693
694echo_i "check delzone after reconfig failure ($n)"
695ret=0
696$RNDCCMD 10.53.0.3 addzone 'inlinesec.example. IN { type secondary; file "inlinesec.db"; masterfile-format text; primaries { test; }; };' >/dev/null 2>&1 || ret=1
697copy_setports ns3/named2.conf.in ns3/named.conf
698rndc_reconfig ns3 10.53.0.3
699$RNDCCMD 10.53.0.3 delzone inlinesec.example >/dev/null 2>&1 || ret=1
700n=$((n + 1))
701if [ $ret != 0 ]; then echo_i "failed"; fi
702status=$((status + ret))
703
704if ! $FEATURETEST --with-lmdb; then
705  echo_i "check that addzone is fully reversed on failure (--with-lmdb=no) ($n)"
706  ret=0
707  $RNDCCMD 10.53.0.3 addzone "test1.baz" '{ type primary; file "e.db"; };' >/dev/null 2>&1 || ret=1
708  $RNDCCMD 10.53.0.3 addzone "test2.baz" '{ type primary; file "dne.db"; };' >/dev/null 2>&1 && ret=1
709  $RNDCCMD 10.53.0.3 addzone "test3.baz" '{ type primary; file "e.db"; };' >/dev/null 2>&1 || ret=1
710  $RNDCCMD 10.53.0.3 delzone "test3.baz" >/dev/null 2>&1 || ret=1
711  grep test2.baz ns3/_default.nzf >/dev/null && ret=1
712  n=$((n + 1))
713  if [ $ret != 0 ]; then echo_i "failed"; fi
714  status=$((status + ret))
715fi
716
717_check_version_bind() (
718  $DIG $DIGOPTS @10.53.0.3 version.bind txt ch >dig.out.test$n \
719    && grep "status: NOERROR" dig.out.test$n >/dev/null
720)
721
722echo_i "check that named restarts with multiple added zones ($n)"
723ret=0
724$RNDCCMD 10.53.0.3 addzone "test4.baz" '{ type primary; file "e.db"; };' >/dev/null 2>&1 || ret=1
725$RNDCCMD 10.53.0.3 addzone "test5.baz" '{ type primary; file "e.db"; };' >/dev/null 2>&1 || ret=1
726$RNDCCMD 10.53.0.3 addzone '"test/.baz"' '{ type primary; check-names ignore; file "e.db"; };' >/dev/null 2>&1 || ret=1
727$RNDCCMD 10.53.0.3 addzone '"test\".baz"' '{ type primary; check-names ignore; file "e.db"; };' >/dev/null 2>&1 || ret=1
728$RNDCCMD 10.53.0.3 addzone '"test\\.baz"' '{ type primary; check-names ignore; file "e.db"; };' >/dev/null 2>&1 || ret=1
729$RNDCCMD 10.53.0.3 addzone '"test\032.baz"' '{ type primary; check-names ignore; file "e.db"; };' >/dev/null 2>&1 || ret=1
730$RNDCCMD 10.53.0.3 addzone '"test\010.baz"' '{ type primary; check-names ignore; file "e.db"; };' >/dev/null 2>&1 || ret=1
731stop_server ns3
732start_server --noclean --restart --port ${PORT} ns3 || ret=1
733retry_quiet 10 _check_version_bind || ret=1
734$DIG $DIGOPTS @10.53.0.3 SOA "test4.baz" >dig.out.1.test$n || ret=1
735grep "status: NOERROR" dig.out.1.test$n >/dev/null || ret=1
736grep "ANSWER: 1," dig.out.1.test$n >/dev/null || ret=1
737$DIG $DIGOPTS @10.53.0.3 SOA "test5.baz" >dig.out.2.test$n || ret=1
738grep "status: NOERROR" dig.out.2.test$n >/dev/null || ret=1
739grep "ANSWER: 1," dig.out.2.test$n >/dev/null || ret=1
740$DIG $DIGOPTS @10.53.0.3 SOA 'test/.baz' >dig.out.3.test$n || ret=1
741grep "status: NOERROR" dig.out.3.test$n >/dev/null || ret=1
742grep "ANSWER: 1," dig.out.3.test$n >/dev/null || ret=1
743$DIG $DIGOPTS @10.53.0.3 SOA 'test\\.baz' >dig.out.4.test$n || ret=1
744grep "status: NOERROR" dig.out.4.test$n >/dev/null || ret=1
745grep "ANSWER: 1," dig.out.4.test$n >/dev/null || ret=1
746$DIG $DIGOPTS @10.53.0.3 SOA 'test\032.baz' >dig.out.5.test$n || ret=1
747grep "status: NOERROR" dig.out.5.test$n >/dev/null || ret=1
748grep "ANSWER: 1," dig.out.5.test$n >/dev/null || ret=1
749$DIG $DIGOPTS @10.53.0.3 SOA 'test\010.baz' >dig.out.6.test$n || ret=1
750grep "status: NOERROR" dig.out.6.test$n >/dev/null || ret=1
751grep "ANSWER: 1," dig.out.6.test$n >/dev/null || ret=1
752if [ $ret != 0 ]; then echo_i "failed"; fi
753status=$((status + ret))
754n=$((n + 1))
755
756echo_i "exit status: $status"
757[ $status -eq 0 ] || exit 1
758