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 14# WARNING: The test labelled "testing request-ixfr option in view vs zone" 15# is fragile because it depends upon counting instances of records 16# in the log file - need a better approach <sdm> - until then, 17# if you add any tests above that point, you will break the test. 18 19SYSTEMTESTTOP=.. 20. $SYSTEMTESTTOP/conf.sh 21 22wait_for_serial() ( 23 $DIG $DIGOPTS "@$1" "$2" SOA > "$4" 24 serial=$(awk '$4 == "SOA" { print $7 }' "$4") 25 [ "$3" -eq "${serial:--1}" ] 26) 27 28status=0 29n=0 30 31DIGOPTS="+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd -p ${PORT}" 32SENDCMD="$PERL ../send.pl 10.53.0.2 ${EXTRAPORT1}" 33RNDCCMD="$RNDC -p ${CONTROLPORT} -c ../common/rndc.conf -s" 34 35n=$((n+1)) 36echo_i "testing initial AXFR ($n)" 37ret=0 38 39$SENDCMD <<EOF 40/SOA/ 41nil. 300 SOA ns.nil. root.nil. 1 300 300 604800 300 42/AXFR/ 43nil. 300 SOA ns.nil. root.nil. 1 300 300 604800 300 44/AXFR/ 45nil. 300 NS ns.nil. 46nil. 300 TXT "initial AXFR" 47a.nil. 60 A 10.0.0.61 48b.nil. 60 A 10.0.0.62 49/AXFR/ 50nil. 300 SOA ns.nil. root.nil. 1 300 300 604800 300 51EOF 52 53sleep 1 54 55# Initially, ns1 is not authoritative for anything (see setup.sh). 56# Now that ans is up and running with the right data, we make it 57# a secondary for nil. 58 59cat <<EOF >>ns1/named.conf 60zone "nil" { 61 type secondary; 62 file "myftp.db"; 63 primaries { 10.53.0.2; }; 64}; 65EOF 66 67rndc_reload ns1 10.53.0.1 68 69retry_quiet 10 wait_for_serial 10.53.0.1 nil. 1 dig.out.test$n || ret=1 70 71$DIG $DIGOPTS @10.53.0.1 nil. TXT | grep 'initial AXFR' >/dev/null || ret=1 72if [ $ret != 0 ]; then echo_i "failed"; fi 73status=$((status+ret)) 74 75n=$((n+1)) 76echo_i "testing successful IXFR ($n)" 77ret=0 78 79# We change the IP address of a.nil., and the TXT record at the apex. 80# Then we do a SOA-only update. 81 82$SENDCMD <<EOF 83/SOA/ 84nil. 300 SOA ns.nil. root.nil. 3 300 300 604800 300 85/IXFR/ 86nil. 300 SOA ns.nil. root.nil. 3 300 300 604800 300 87nil. 300 SOA ns.nil. root.nil. 1 300 300 604800 300 88a.nil. 60 A 10.0.0.61 89nil. 300 TXT "initial AXFR" 90nil. 300 SOA ns.nil. root.nil. 2 300 300 604800 300 91nil. 300 TXT "successful IXFR" 92a.nil. 60 A 10.0.1.61 93nil. 300 SOA ns.nil. root.nil. 2 300 300 604800 300 94nil. 300 SOA ns.nil. root.nil. 3 300 300 604800 300 95nil. 300 SOA ns.nil. root.nil. 3 300 300 604800 300 96EOF 97 98sleep 1 99 100$RNDCCMD 10.53.0.1 refresh nil | sed 's/^/ns1 /' | cat_i 101 102sleep 2 103 104$DIG $DIGOPTS @10.53.0.1 nil. TXT | grep 'successful IXFR' >/dev/null || ret=1 105if [ $ret != 0 ]; then echo_i "failed"; fi 106status=$((status+ret)) 107 108n=$((n+1)) 109echo_i "testing AXFR fallback after IXFR failure (not exact error) ($n)" 110ret=0 111 112# Provide a broken IXFR response and a working fallback AXFR response 113 114$SENDCMD <<EOF 115/SOA/ 116nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300 117/IXFR/ 118nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300 119nil. 300 SOA ns.nil. root.nil. 3 300 300 604800 300 120nil. 300 TXT "delete-nonexistent-txt-record" 121nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300 122nil. 300 TXT "this-txt-record-would-be-added" 123nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300 124/AXFR/ 125nil. 300 SOA ns.nil. root.nil. 3 300 300 604800 300 126/AXFR/ 127nil. 300 NS ns.nil. 128nil. 300 TXT "fallback AXFR" 129/AXFR/ 130nil. 300 SOA ns.nil. root.nil. 3 300 300 604800 300 131EOF 132 133sleep 1 134 135$RNDCCMD 10.53.0.1 refresh nil | sed 's/^/ns1 /' | cat_i 136 137sleep 2 138 139$DIG $DIGOPTS @10.53.0.1 nil. TXT | grep 'fallback AXFR' >/dev/null || ret=1 140if [ $ret != 0 ]; then echo_i "failed"; fi 141status=$((status+ret)) 142 143n=$((n+1)) 144echo_i "testing AXFR fallback after IXFR failure (bad SOA owner) ($n)" 145ret=0 146 147# Prepare for checking the logs later on. 148nextpart ns1/named.run >/dev/null 149 150# Provide a broken IXFR response and a working fallback AXFR response. 151$SENDCMD <<EOF 152/SOA/ 153nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300 154/IXFR/ 155nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300 156nil. 300 SOA ns.nil. root.nil. 3 300 300 604800 300 157bad-owner. 300 SOA ns.nil. root.nil. 4 300 300 604800 300 158test.nil. 300 TXT "serial 4, malformed IXFR" 159nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300 160/AXFR/ 161nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300 162/AXFR/ 163nil. 300 NS ns.nil. 164test.nil. 300 TXT "serial 4, fallback AXFR" 165/AXFR/ 166nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300 167EOF 168$RNDCCMD 10.53.0.1 refresh nil | sed 's/^/ns1 /' | cat_i 169 170# A broken server would accept the malformed IXFR and apply its contents to the 171# zone. A fixed one would reject the IXFR and fall back to AXFR. Both IXFR and 172# AXFR above bring the nil. zone up to serial 4, but we cannot reliably query 173# for the SOA record to check whether the transfer was finished because a broken 174# server would send back SERVFAIL responses to SOA queries after accepting the 175# malformed IXFR. Instead, check transfer progress by querying for a TXT record 176# at test.nil. which is present in both IXFR and AXFR (with different contents). 177_wait_until_transfer_is_finished() { 178 $DIG $DIGOPTS +tries=1 +time=1 @10.53.0.1 test.nil. TXT > dig.out.test$n.1 && 179 grep -q -F "serial 4" dig.out.test$n.1 180} 181if ! retry_quiet 10 _wait_until_transfer_is_finished; then 182 echo_i "timed out waiting for version 4 of zone nil. to be transferred" 183 ret=1 184fi 185 186# At this point a broken server would be serving a zone with no SOA records. 187# Try crashing it by triggering a SOA refresh query. 188$RNDCCMD 10.53.0.1 refresh nil | sed 's/^/ns1 /' | cat_i 189 190# Do not wait until the zone refresh completes - even if a crash has not 191# happened by now, a broken server would never serve the record which is only 192# present in the fallback AXFR, so checking for that is enough to verify if a 193# server is broken or not; if it is, it is bound to crash shortly anyway. 194$DIG $DIGOPTS test.nil. TXT @10.53.0.1 > dig.out.test$n.2 || ret=1 195grep -q -F "serial 4, fallback AXFR" dig.out.test$n.2 || ret=1 196 197# Ensure the expected error is logged. 198nextpart ns1/named.run | grep -q -F "SOA name mismatch" || ret=1 199 200if [ $ret != 0 ]; then echo_i "failed"; fi 201status=$((status+ret)) 202 203n=$((n+1)) 204echo_i "testing ixfr-from-differences option ($n)" 205# ns3 is primary; ns4 is secondary 206$CHECKZONE test. ns3/mytest.db > /dev/null 2>&1 207if [ $? -ne 0 ] 208then 209 echo_i "named-checkzone returned failure on ns3/mytest.db" 210fi 211 212retry_quiet 10 wait_for_serial 10.53.0.4 test. 1 dig.out.test$n || ret=1 213 214nextpart ns4/named.run > /dev/null 215 216# modify the primary 217cp ns3/mytest1.db ns3/mytest.db 218$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i 219 220# wait for primary to reload 221retry_quiet 10 wait_for_serial 10.53.0.3 test. 2 dig.out.test$n || ret=1 222 223# wait for secondary to reload 224tret=0 225retry_quiet 5 wait_for_serial 10.53.0.4 test. 2 dig.out.test$n || tret=1 226if [ $tret -eq 1 ]; then 227 # re-noitfy after 5 seconds, then wait another 10 228 $RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i 229 retry_quiet 10 wait_for_serial 10.53.0.4 test. 2 dig.out.test$n || ret=1 230fi 231 232wait_for_log 10 'got incremental' ns4/named.run || ret=1 233if [ $ret != 0 ]; then echo_i "failed"; fi 234status=$((status+ret)) 235 236n=$((n+1)) 237echo_i "testing 'request-ixfr no' option inheritance from view ($n)" 238ret=0 239# There's a view with 2 zones. In the view, "request-ixfr yes" 240# but in the zone "sub.test", request-ixfr no" 241# we want to make sure that a change to sub.test results in AXFR, while 242# changes to test. result in IXFR 243 244cp ns3/subtest1.db ns3/subtest.db # change to sub.test zone, should be AXFR 245nextpart ns4/named.run > /dev/null 246$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i 247 248# wait for primary to reload 249retry_quiet 10 wait_for_serial 10.53.0.3 sub.test. 3 dig.out.test$n || ret=1 250 251# wait for secondary to reload 252tret=0 253retry_quiet 5 wait_for_serial 10.53.0.4 sub.test. 3 dig.out.test$n || tret=1 254if [ $tret -eq 1 ]; then 255 # re-noitfy after 5 seconds, then wait another 10 256 $RNDCCMD 10.53.0.3 notify sub.test | set 's/^/ns3 /' | cat_i 257 retry_quiet 10 wait_for_serial 10.53.0.4 sub.test. 3 dig.out.test$n || ret=1 258fi 259 260wait_for_log 10 'got nonincremental response' ns4/named.run || ret=1 261if [ $ret != 0 ]; then echo_i "failed"; fi 262status=$((status+ret)) 263 264n=$((n+1)) 265echo_i "testing 'request-ixfr yes' option inheritance from view ($n)" 266ret=0 267cp ns3/mytest2.db ns3/mytest.db # change to test zone, should be IXFR 268nextpart ns4/named.run > /dev/null 269$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i 270 271# wait for primary to reload 272retry_quiet 10 wait_for_serial 10.53.0.3 test. 3 dig.out.test$n || ret=1 273 274# wait for secondary to reload 275tret=0 276retry_quiet 5 wait_for_serial 10.53.0.4 test. 3 dig.out.test$n || tret=1 277if [ $tret -eq 1 ]; then 278 # re-noitfy after 5 seconds, then wait another 10 279 $RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i 280 retry_quiet 10 wait_for_serial 10.53.0.4 test. 3 dig.out.test$n || ret=1 281fi 282 283wait_for_log 10 'got incremental response' ns4/named.run || ret=1 284if [ $ret != 0 ]; then echo_i "failed"; fi 285status=$((status+ret)) 286 287n=$((n+1)) 288ret=0 289echo_i "testing DiG's handling of a multi message AXFR style IXFR response ($n)" 290( 291(sleep 10 && kill $$) 2>/dev/null & 292sub=$! 293$DIG -p ${PORT} ixfr=0 large @10.53.0.3 > dig.out.test$n 294kill $sub 295) 296lines=`grep hostmaster.large dig.out.test$n | wc -l` 297test ${lines:-0} -eq 2 || ret=1 298messages=`sed -n 's/^;;.*messages \([0-9]*\),.*/\1/p' dig.out.test$n` 299test ${messages:-0} -gt 1 || ret=1 300if [ $ret != 0 ]; then echo_i "failed"; fi 301status=$((status+ret)) 302 303n=$((n+1)) 304echo_i "test 'dig +notcp ixfr=<value>' vs 'dig ixfr=<value> +notcp' vs 'dig ixfr=<value>' ($n)" 305ret=0 306# Should be "switch to TCP" response 307$DIG $DIGOPTS +notcp ixfr=1 test @10.53.0.4 > dig.out1.test$n || ret=1 308$DIG $DIGOPTS ixfr=1 +notcp test @10.53.0.4 > dig.out2.test$n || ret=1 309digcomp dig.out1.test$n dig.out2.test$n || ret=1 310awk '$4 == "SOA" { soacnt++} END {if (soacnt == 1) exit(0); else exit(1);}' dig.out1.test$n || ret=1 311awk '$4 == "SOA" { if ($7 == 3) exit(0); else exit(1);}' dig.out1.test$n || ret=1 312# 313nextpart ns4/named.run > /dev/null 314# Should be incremental transfer. 315$DIG $DIGOPTS ixfr=1 test @10.53.0.4 > dig.out3.test$n || ret=1 316awk '$4 == "SOA" { soacnt++} END { if (soacnt == 6) exit(0); else exit(1);}' dig.out3.test$n || ret=1 317if [ $ret != 0 ]; then echo_i "failed"; fi 318status=$((status+ret)) 319 320n=$((n+1)) 321echo_i "check estimated IXFR size ($n)" 322ret=0 323# note IXFR delta size will be slightly bigger with version 1 transaction 324# headers as there is no correction for the overall record length storage. 325# Ver1 = 4 * (6 + 10 + 10 + 17 + 5 * 4) + 2 * (13 + 10 + 4) + (6 * 4) = 330 326# Ver2 = 4 * (6 + 10 + 10 + 17 + 5 * 4) + 2 * (13 + 10 + 4) = 306 327nextpart ns4/named.run | grep "IXFR delta size (306 bytes)" > /dev/null || ret=1 328if [ $ret != 0 ]; then echo_i "failed"; fi 329status=$((status+ret)) 330 331# make sure ns5 has transfered the zone 332# wait for secondary to reload 333tret=0 334retry_quiet 5 wait_for_serial 10.53.0.5 test. 4 dig.out.test$n || tret=1 335if [ $tret -eq 1 ]; then 336 # re-noitfy after 5 seconds, then wait another 10 337 $RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i 338 retry_quiet 10 wait_for_serial 10.53.0.5 test. 3 dig.out.test$n || ret=1 339fi 340 341n=$((n+1)) 342echo_i "test 'provide-ixfr no;' (serial < current) ($n)" 343ret=0 344nextpart ns5/named.run > /dev/null 345# Should be "AXFR style" response 346$DIG $DIGOPTS ixfr=1 test @10.53.0.5 > dig.out1.test$n || ret=1 347# Should be "switch to TCP" response 348$DIG $DIGOPTS ixfr=1 +notcp test @10.53.0.5 > dig.out2.test$n || ret=1 349awk '$4 == "SOA" { soacnt++} END {if (soacnt == 2) exit(0); else exit(1);}' dig.out1.test$n || ret=1 350awk '$4 == "SOA" { soacnt++} END {if (soacnt == 1) exit(0); else exit(1);}' dig.out2.test$n || ret=1 351if [ $ret != 0 ]; then echo_i "failed"; fi 352status=$((status+ret)) 353 354n=$((n+1)) 355echo_i "checking whether dig calculates IXFR statistics correctly ($n)" 356ret=0 357$DIG $DIGOPTS +noedns +stat -b 10.53.0.4 @10.53.0.4 test. ixfr=2 > dig.out1.test$n 358get_dig_xfer_stats dig.out1.test$n > stats.dig 359diff ixfr-stats.good stats.dig > /dev/null || ret=1 360if [ $ret != 0 ]; then echo_i "failed"; fi 361status=$((status+ret)) 362 363# Note: in the next two tests, we use ns4 logs for checking both incoming and 364# outgoing transfer statistics as ns4 is both a secondary server (for ns3) and a 365# primary server (for dig queries from the previous test) for "test". 366 367_wait_for_stats () { 368 get_named_xfer_stats ns4/named.run "$1" test "$2" > "$3" 369 diff ixfr-stats.good "$3" > /dev/null || return 1 370 return 0 371} 372 373n=$((n+1)) 374echo_i "checking whether named calculates incoming IXFR statistics correctly ($n)" 375ret=0 376retry_quiet 10 _wait_for_stats 10.53.0.3 "Transfer completed" stats.incoming 377if [ $ret != 0 ]; then echo_i "failed"; fi 378status=$((status+ret)) 379 380n=$((n+1)) 381echo_i "checking whether named calculates outgoing IXFR statistics correctly ($n)" 382retry_quiet 10 _wait_for_stats 10.53.0.4 "IXFR ended" stats.outgoing 383if [ $ret != 0 ]; then echo_i "failed"; fi 384status=$((status+ret)) 385 386n=$((n+1)) 387ret=0 388echo_i "testing fallback to AXFR when max-ixfr-ratio is exceeded ($n)" 389nextpart ns4/named.run > /dev/null 390 391cp ns3/mytest3.db ns3/mytest.db # change to test zone, too big for IXFR 392$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i 393 394# wait for secondary to reload 395tret=0 396retry_quiet 5 wait_for_serial 10.53.0.4 test. 4 dig.out.test$n || tret=1 397if [ $tret -eq 1 ]; then 398 # re-noitfy after 5 seconds, then wait another 10 399 $RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i 400 retry_quiet 10 wait_for_serial 10.53.0.4 test. 4 dig.out.test$n || ret=1 401fi 402 403wait_for_log 10 'got nonincremental response' ns4/named.run || ret=1 404if [ $ret != 0 ]; then echo_i "failed"; fi 405status=$((status+ret)) 406 407echo_i "exit status: $status" 408[ $status -eq 0 ] || exit 1 409