xref: /netbsd-src/external/mpl/bind/dist/bin/tests/system/xfer/tests.sh (revision 4b004442778f1201b2161e87fd65ba87aae6601a)
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="+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd -p ${PORT}"
18RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s"
19
20status=0
21n=0
22
23n=$((n+1))
24echo_i "testing basic zone transfer functionality (from primary) ($n)"
25tmp=0
26$DIG $DIGOPTS example. @10.53.0.2 axfr > dig.out.ns2.test$n || tmp=1
27grep "^;" dig.out.ns2.test$n | cat_i
28digcomp dig1.good dig.out.ns2.test$n || tmp=1
29if test $tmp != 0 ; then echo_i "failed"; fi
30status=$((status+tmp))
31
32n=$((n+1))
33echo_i "testing basic zone transfer functionality (from secondary) ($n)"
34tmp=0
35#
36# Spin to allow the zone to transfer.
37#
38wait_for_xfer () {
39	$DIG $DIGOPTS example. @10.53.0.3 axfr > dig.out.ns3.test$n || return 1
40	grep "^;" dig.out.ns3.test$n > /dev/null && return 1
41	return 0
42}
43retry_quiet 25 wait_for_xfer || tmp=1
44grep "^;" dig.out.ns3.test$n | cat_i
45digcomp dig1.good dig.out.ns3.test$n || tmp=1
46if test $tmp != 0 ; then echo_i "failed"; fi
47status=$((status+tmp))
48
49n=$((n+1))
50echo_i "testing TSIG signed zone transfers ($n)"
51tmp=0
52$DIG $DIGOPTS tsigzone. @10.53.0.2 axfr -y tsigzone.:1234abcd8765 > dig.out.ns2.test$n || tmp=1
53grep "^;" dig.out.ns2.test$n | cat_i
54
55#
56# Spin to allow the zone to transfer.
57#
58wait_for_xfer_tsig () {
59	$DIG $DIGOPTS tsigzone. @10.53.0.3 axfr -y tsigzone.:1234abcd8765 > dig.out.ns3.test$n || return 1
60	grep "^;" dig.out.ns3.test$n > /dev/null && return 1
61	return 0
62}
63retry_quiet 25 wait_for_xfer_tsig || tmp=1
64grep "^;" dig.out.ns3.test$n | cat_i
65digcomp dig.out.ns2.test$n dig.out.ns3.test$n || tmp=1
66if test $tmp != 0 ; then echo_i "failed"; fi
67status=$((status+tmp))
68
69echo_i "reload servers for in preparation for ixfr-from-differences tests"
70
71rndc_reload ns1 10.53.0.1
72rndc_reload ns2 10.53.0.2
73rndc_reload ns3 10.53.0.3
74rndc_reload ns6 10.53.0.6
75rndc_reload ns7 10.53.0.7
76
77sleep 2
78
79echo_i "updating primary zones for ixfr-from-differences tests"
80
81$PERL -i -p -e '
82	s/0\.0\.0\.0/0.0.0.1/;
83	s/1397051952/1397051953/
84' ns1/sec.db
85
86rndc_reload ns1 10.53.0.1
87
88$PERL -i -p -e '
89	s/0\.0\.0\.0/0.0.0.1/;
90	s/1397051952/1397051953/
91' ns2/example.db
92
93rndc_reload ns2 10.53.0.2
94
95$PERL -i -p -e '
96	s/0\.0\.0\.0/0.0.0.1/;
97	s/1397051952/1397051953/
98' ns6/primary.db
99
100rndc_reload ns6 10.53.0.6
101
102$PERL -i -p -e '
103	s/0\.0\.0\.0/0.0.0.1/;
104	s/1397051952/1397051953/
105' ns7/primary2.db
106
107rndc_reload ns7 10.53.0.7
108
109sleep 3
110
111n=$((n+1))
112echo_i "testing zone is dumped after successful transfer ($n)"
113tmp=0
114$DIG $DIGOPTS +noall +answer +multi @10.53.0.2 \
115	secondary. soa > dig.out.ns2.test$n || tmp=1
116grep "1397051952 ; serial" dig.out.ns2.test$n > /dev/null 2>&1 || tmp=1
117grep "1397051952 ; serial" ns2/sec.db > /dev/null 2>&1 || tmp=1
118if test $tmp != 0 ; then echo_i "failed"; fi
119status=$((status+tmp))
120
121n=$((n+1))
122echo_i "testing ixfr-from-differences yes; ($n)"
123tmp=0
124
125echo_i "wait for reloads..."
126wait_for_reloads() (
127	$DIG $DIGOPTS @10.53.0.6 +noall +answer soa primary > dig.out.soa1.ns6.test$n
128	grep "1397051953" dig.out.soa1.ns6.test$n > /dev/null || return 1
129	$DIG $DIGOPTS @10.53.0.1 +noall +answer soa secondary  > dig.out.soa2.ns1.test$n
130	grep "1397051953" dig.out.soa2.ns1.test$n > /dev/null || return 1
131	$DIG $DIGOPTS @10.53.0.2 +noall +answer soa example > dig.out.soa3.ns2.test$n
132	grep "1397051953" dig.out.soa3.ns2.test$n > /dev/null || return 1
133	return 0
134)
135retry_quiet 20 wait_for_reloads || tmp=1
136
137echo_i "wait for transfers..."
138wait_for_transfers() (
139	a=0 b=0 c=0 d=0
140	$DIG $DIGOPTS @10.53.0.3 +noall +answer soa example > dig.out.soa1.ns3.test$n
141	grep "1397051953" dig.out.soa1.ns3.test$n > /dev/null && a=1
142	$DIG $DIGOPTS @10.53.0.3 +noall +answer soa primary > dig.out.soa2.ns3.test$n
143	grep "1397051953" dig.out.soa2.ns3.test$n > /dev/null && b=1
144	$DIG $DIGOPTS @10.53.0.6 +noall +answer soa secondary > dig.out.soa3.ns6.test$n
145	grep "1397051953" dig.out.soa3.ns6.test$n > /dev/null && c=1
146	[ $a -eq 1 -a $b -eq 1 -a $c -eq 1 ] && return 0
147
148	# re-notify if necessary
149	$RNDCCMD 10.53.0.6 notify primary 2>&1 | sed 's/^/ns6 /' | cat_i
150	$RNDCCMD 10.53.0.1 notify secondary 2>&1 | sed 's/^/ns1 /' | cat_i
151	$RNDCCMD 10.53.0.2 notify example 2>&1 | sed 's/^/ns2 /' | cat_i
152	return 1
153)
154retry_quiet 20 wait_for_transfers || tmp=1
155
156$DIG $DIGOPTS example. \
157	@10.53.0.3 axfr > dig.out.ns3.test$n || tmp=1
158grep "^;" dig.out.ns3.test$n | cat_i
159
160digcomp dig2.good dig.out.ns3.test$n || tmp=1
161
162# ns3 has a journal iff it received an IXFR.
163test -f ns3/example.bk || tmp=1
164test -f ns3/example.bk.jnl || tmp=1
165
166if test $tmp != 0 ; then echo_i "failed"; fi
167status=$((status+tmp))
168
169n=$((n+1))
170echo_i "testing ixfr-from-differences primary; (primary zone) ($n)"
171tmp=0
172
173$DIG $DIGOPTS primary. \
174	@10.53.0.6 axfr > dig.out.ns6.test$n || tmp=1
175grep "^;" dig.out.ns6.test$n | cat_i
176
177$DIG $DIGOPTS primary. \
178	@10.53.0.3 axfr > dig.out.ns3.test$n || tmp=1
179grep "^;" dig.out.ns3.test$n > /dev/null && cat_i dig.out.ns3.test$n
180
181digcomp dig.out.ns6.test$n dig.out.ns3.test$n || tmp=1
182
183# ns3 has a journal iff it received an IXFR.
184test -f ns3/primary.bk || tmp=1
185test -f ns3/primary.bk.jnl || tmp=1
186
187if test $tmp != 0 ; then echo_i "failed"; fi
188status=$((status+tmp))
189
190n=$((n+1))
191echo_i "testing ixfr-from-differences primary; (secondary zone) ($n)"
192tmp=0
193
194$DIG $DIGOPTS secondary. \
195	@10.53.0.6 axfr > dig.out.ns6.test$n || tmp=1
196grep "^;" dig.out.ns6.test$n | cat_i
197
198$DIG $DIGOPTS secondary. \
199	@10.53.0.1 axfr > dig.out.ns1.test$n || tmp=1
200grep "^;" dig.out.ns1.test$n | cat_i
201
202digcomp dig.out.ns6.test$n dig.out.ns1.test$n || tmp=1
203
204# ns6 has a journal iff it received an IXFR.
205test -f ns6/sec.bk || tmp=1
206test -f ns6/sec.bk.jnl && tmp=1
207
208if test $tmp != 0 ; then echo_i "failed"; fi
209status=$((status+tmp))
210
211n=$((n+1))
212echo_i "testing ixfr-from-differences secondary; (secondary zone) ($n)"
213tmp=0
214
215# ns7 has a journal iff it generates an IXFR.
216test -f ns7/primary2.db || tmp=1
217test -f ns7/primary2.db.jnl && tmp=1
218
219if test $tmp != 0 ; then echo_i "failed"; fi
220status=$((status+tmp))
221
222n=$((n+1))
223echo_i "testing ixfr-from-differences secondary; (secondary zone) ($n)"
224tmp=0
225
226$DIG $DIGOPTS secondary. \
227	@10.53.0.1 axfr > dig.out.ns1.test$n || tmp=1
228grep "^;" dig.out.ns1.test$n | cat_i
229
230$DIG $DIGOPTS secondary. \
231	@10.53.0.7 axfr > dig.out.ns7.test$n || tmp=1
232grep "^;" dig.out.ns7.test$n | cat_i
233
234digcomp dig.out.ns7.test$n dig.out.ns1.test$n || tmp=1
235
236# ns7 has a journal iff it generates an IXFR.
237test -f ns7/sec.bk || tmp=1
238test -f ns7/sec.bk.jnl || tmp=1
239
240if test $tmp != 0 ; then echo_i "failed"; fi
241status=$((status+tmp))
242
243n=$((n+1))
244echo_i "check that a multi-message uncompressable zone transfers ($n)"
245$DIG axfr . -p ${PORT} @10.53.0.4 | grep SOA > axfr.out
246if test `wc -l < axfr.out` != 2
247then
248	 echo_i "failed"
249         status=$((status+1))
250fi
251
252# now we test transfers with assorted TSIG glitches
253DIGCMD="$DIG $DIGOPTS @10.53.0.4"
254SENDCMD="$PERL ../send.pl 10.53.0.5 $EXTRAPORT1"
255
256echo_i "testing that incorrectly signed transfers will fail..."
257n=$((n+1))
258echo_i "initial correctly-signed transfer should succeed ($n)"
259
260$SENDCMD < ans5/goodaxfr
261
262# Initially, ns4 is not authoritative for anything.
263# Now that ans is up and running with the right data, we make ns4
264# a secondary for nil.
265
266cat <<EOF >>ns4/named.conf
267zone "nil" {
268	type secondary;
269	file "nil.db";
270	primaries { 10.53.0.5 key tsig_key; };
271};
272EOF
273
274nextpart ns4/named.run >/dev/null
275
276rndc_reload ns4 10.53.0.4
277
278wait_for_soa() (
279	$DIGCMD nil. SOA > dig.out.ns4.test$n
280	grep SOA dig.out.ns4.test$n > /dev/null
281)
282retry_quiet 10 wait_for_soa
283
284nextpart ns4/named.run | grep "Transfer status: success" > /dev/null || {
285    echo_i "failed: expected status was not logged"
286    status=$((status+1))
287}
288
289$DIGCMD nil. TXT | grep 'initial AXFR' >/dev/null || {
290    echo_i "failed"
291    status=$((status+1))
292}
293
294n=$((n+1))
295echo_i "unsigned transfer ($n)"
296
297$SENDCMD < ans5/unsigned
298
299$RNDCCMD 10.53.0.4 retransfer nil | sed 's/^/ns4 /' | cat_i
300
301sleep 2
302
303nextpart ns4/named.run | grep "Transfer status: expected a TSIG or SIG(0)" > /dev/null || {
304    echo_i "failed: expected status was not logged"
305    status=$((status+1))
306}
307
308$DIGCMD nil. TXT | grep 'unsigned AXFR' >/dev/null && {
309    echo_i "failed"
310    status=$((status+1))
311}
312
313n=$((n+1))
314echo_i "bad keydata ($n)"
315
316$SENDCMD < ans5/badkeydata
317
318$RNDCCMD 10.53.0.4 retransfer nil | sed 's/^/ns4 /' | cat_i
319
320sleep 2
321
322nextpart ns4/named.run | grep "Transfer status: tsig verify failure" > /dev/null || {
323    echo_i "failed: expected status was not logged"
324    status=$((status+1))
325}
326
327$DIGCMD nil. TXT | grep 'bad keydata AXFR' >/dev/null && {
328    echo_i "failed"
329    status=$((status+1))
330}
331
332n=$((n+1))
333echo_i "partially-signed transfer ($n)"
334
335$SENDCMD < ans5/partial
336
337$RNDCCMD 10.53.0.4 retransfer nil | sed 's/^/ns4 /' | cat_i
338
339sleep 2
340
341nextpart ns4/named.run | grep "Transfer status: expected a TSIG or SIG(0)" > /dev/null || {
342    echo_i "failed: expected status was not logged"
343    status=$((status+1))
344}
345
346$DIGCMD nil. TXT | grep 'partially signed AXFR' >/dev/null && {
347    echo_i "failed"
348    status=$((status+1))
349}
350
351n=$((n+1))
352echo_i "unknown key ($n)"
353
354$SENDCMD < ans5/unknownkey
355
356$RNDCCMD 10.53.0.4 retransfer nil | sed 's/^/ns4 /' | cat_i
357
358sleep 2
359
360nextpart ns4/named.run | grep "tsig key 'tsig_key': key name and algorithm do not match" > /dev/null || {
361    echo_i "failed: expected status was not logged"
362    status=$((status+1))
363}
364
365$DIGCMD nil. TXT | grep 'unknown key AXFR' >/dev/null && {
366    echo_i "failed"
367    status=$((status+1))
368}
369
370n=$((n+1))
371echo_i "incorrect key ($n)"
372
373$SENDCMD < ans5/wrongkey
374
375$RNDCCMD 10.53.0.4 retransfer nil | sed 's/^/ns4 /' | cat_i
376
377sleep 2
378
379nextpart ns4/named.run | grep "tsig key 'tsig_key': key name and algorithm do not match" > /dev/null || {
380    echo_i "failed: expected status was not logged"
381    status=$((status+1))
382}
383
384$DIGCMD nil. TXT | grep 'incorrect key AXFR' >/dev/null && {
385    echo_i "failed"
386    status=$((status+1))
387}
388
389n=$((n+1))
390echo_i "bad message id ($n)"
391
392$SENDCMD < ans5/badmessageid
393
394# Uncomment to see AXFR stream with mismatching IDs.
395# $DIG $DIGOPTS @10.53.0.5 -y tsig_key:LSAnCU+Z nil. AXFR +all
396
397$RNDCCMD 10.53.0.4 retransfer nil | sed 's/^/ns4 /' | cat_i
398
399sleep 2
400
401msg="detected message ID mismatch on incoming AXFR stream, transfer will fail in BIND 9.17.2 and later if AXFR source is not fixed"
402nextpart ns4/named.run | grep "$msg" > /dev/null || {
403    echo_i "failed: expected status was not logged"
404    status=$((status+1))
405}
406
407$DIGCMD nil. TXT | grep 'bad message id' >/dev/null || {
408    echo_i "failed"
409    status=$((status+1))
410}
411
412n=$((n+1))
413echo_i "mismatched SOA ($n)"
414
415${SENDCMD} < ans5/soamismatch
416
417$RNDCCMD 10.53.0.4 retransfer nil | sed 's/^/ns4 /' | cat_i
418
419sleep 2
420
421nextpart ns4/named.run | grep "Transfer status: FORMERR" > /dev/null || {
422    echo_i "failed: expected status was not logged"
423    status=$((status+1))
424}
425
426$DIGCMD nil. TXT | grep 'SOA mismatch AXFR' >/dev/null && {
427    echo_i "failed"
428    status=$((status+1))
429}
430
431n=$((n+1))
432echo_i "check that we ask for and get a EDNS EXPIRE response ($n)"
433# force a refresh query
434$RNDCCMD 10.53.0.7 refresh edns-expire 2>&1 | sed 's/^/ns7 /' | cat_i
435sleep 10
436
437# there may be multiple log entries so get the last one.
438expire=`awk '/edns-expire\/IN: got EDNS EXPIRE of/ { x=$9 } END { print x }' ns7/named.run`
439test ${expire:-0} -gt 0 -a ${expire:-0} -lt 1814400 || {
440    echo_i "failed (expire=${expire:-0})"
441    status=$((status+1))
442}
443
444n=$((n+1))
445echo_i "test smaller transfer TCP message size ($n)"
446$DIG $DIGOPTS example. @10.53.0.8 axfr \
447	-y key1.:1234abcd8765 > dig.out.msgsize.test$n || status=1
448
449$DOS2UNIX dig.out.msgsize.test$n >/dev/null 2>&1
450
451bytes=`wc -c < dig.out.msgsize.test$n`
452if [ $bytes -ne 459357 ]; then
453	echo_i "failed axfr size check"
454        status=$((status+1))
455fi
456
457num_messages=`cat ns8/named.run | grep "sending TCP message of" | wc -l`
458if [ $num_messages -le 300 ]; then
459	echo_i "failed transfer message count check"
460        status=$((status+1))
461fi
462
463n=$((n+1))
464echo_i "test mapped zone with out of zone data ($n)"
465tmp=0
466$DIG -p ${PORT} txt mapped @10.53.0.3 > dig.out.1.test$n
467grep "status: NOERROR," dig.out.1.test$n > /dev/null || tmp=1
468stop_server ns3
469start_server --noclean --restart --port ${PORT} ns3
470check_mapped () {
471	$DIG -p ${PORT} txt mapped @10.53.0.3 > dig.out.2.test$n
472	grep "status: NOERROR," dig.out.2.test$n > /dev/null || return 1
473	$DIG -p ${PORT} axfr mapped @10.53.0.3 > dig.out.3.test$n
474	digcomp knowngood.mapped dig.out.3.test$n || return 1
475	return 0
476}
477retry_quiet 10 check_mapped || tmp=1
478[ "$tmp" -ne 0 ] && echo_i "failed"
479status=$((status+tmp))
480
481n=$((n+1))
482echo_i "test that a zone with too many records is rejected (AXFR) ($n)"
483tmp=0
484grep "'axfr-too-big/IN'.*: too many records" ns6/named.run >/dev/null || tmp=1
485if test $tmp != 0 ; then echo_i "failed"; fi
486status=$((status+tmp))
487
488n=$((n+1))
489echo_i "test that a zone with too many records is rejected (IXFR) ($n)"
490tmp=0
491nextpart ns6/named.run > /dev/null
492$NSUPDATE << EOF
493zone ixfr-too-big
494server 10.53.0.1 ${PORT}
495update add the-31st-record.ixfr-too-big 0 TXT this is it
496send
497EOF
498msg="'ixfr-too-big/IN' from 10.53.0.1#${PORT}: Transfer status: too many records"
499wait_for_log 10 "$msg" ns6/named.run || tmp=1
500if test $tmp != 0 ; then echo_i "failed"; fi
501status=$((status+tmp))
502
503n=$((n+1))
504echo_i "checking whether dig calculates AXFR statistics correctly ($n)"
505tmp=0
506# Loop until the secondary server manages to transfer the "xfer-stats" zone so
507# that we can both check dig output and immediately proceed with the next test.
508# Use -b so that we can discern between incoming and outgoing transfers in ns3
509# logs later on.
510wait_for_xfer() (
511	$DIG $DIGOPTS +noedns +stat -b 10.53.0.2 @10.53.0.3 xfer-stats. AXFR > dig.out.ns3.test$n
512	grep "; Transfer failed" dig.out.ns3.test$n > /dev/null || return 0
513	return 1
514)
515if retry_quiet 10 wait_for_xfer; then
516	get_dig_xfer_stats dig.out.ns3.test$n > stats.dig
517	diff axfr-stats.good stats.dig || tmp=1
518else
519	echo_i "timed out waiting for zone transfer"
520fi
521if test $tmp != 0 ; then echo_i "failed"; fi
522status=$((status+tmp))
523
524# Note: in the next two tests, we use ns3 logs for checking both incoming and
525# outgoing transfer statistics as ns3 is both a secondary server (for ns1) and a
526# primary server (for dig queries from the previous test) for "xfer-stats".
527n=$((n+1))
528echo_i "checking whether named calculates incoming AXFR statistics correctly ($n)"
529tmp=0
530get_named_xfer_stats ns3/named.run 10.53.0.1 xfer-stats "Transfer completed" > stats.incoming
531diff axfr-stats.good stats.incoming || tmp=1
532if test $tmp != 0 ; then echo_i "failed"; fi
533status=$((status+tmp))
534
535n=$((n+1))
536echo_i "checking whether named calculates outgoing AXFR statistics correctly ($n)"
537tmp=0
538check_xfer_stats() {
539	get_named_xfer_stats ns3/named.run 10.53.0.2 xfer-stats "AXFR ended" > stats.outgoing
540	diff axfr-stats.good stats.outgoing > /dev/null
541}
542retry_quiet 10 check_xfer_stats || tmp=1
543if test $tmp != 0 ; then echo_i "failed"; fi
544status=$((status+tmp))
545
546echo_i "exit status: $status"
547[ $status -eq 0 ] || exit 1
548