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 217sleep 1 218cp ns3/mytest1.db ns3/mytest.db 219$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i 220 221# wait for primary to reload 222retry_quiet 10 wait_for_serial 10.53.0.3 test. 2 dig.out.test$n || ret=1 223 224# wait for secondary to reload 225tret=0 226retry_quiet 5 wait_for_serial 10.53.0.4 test. 2 dig.out.test$n || tret=1 227if [ $tret -eq 1 ]; then 228 # re-noitfy after 5 seconds, then wait another 10 229 $RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i 230 retry_quiet 10 wait_for_serial 10.53.0.4 test. 2 dig.out.test$n || ret=1 231fi 232 233wait_for_log 10 'got incremental' ns4/named.run || ret=1 234if [ $ret != 0 ]; then echo_i "failed"; fi 235status=$((status+ret)) 236 237n=$((n+1)) 238echo_i "testing 'request-ixfr no' option inheritance from view ($n)" 239ret=0 240# There's a view with 2 zones. In the view, "request-ixfr yes" 241# but in the zone "sub.test", request-ixfr no" 242# we want to make sure that a change to sub.test results in AXFR, while 243# changes to test. result in IXFR 244 245sleep 1 246cp ns3/subtest1.db ns3/subtest.db # change to sub.test zone, should be AXFR 247nextpart ns4/named.run > /dev/null 248$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i 249 250# wait for primary to reload 251retry_quiet 10 wait_for_serial 10.53.0.3 sub.test. 3 dig.out.test$n || ret=1 252 253# wait for secondary to reload 254tret=0 255retry_quiet 5 wait_for_serial 10.53.0.4 sub.test. 3 dig.out.test$n || tret=1 256if [ $tret -eq 1 ]; then 257 # re-noitfy after 5 seconds, then wait another 10 258 $RNDCCMD 10.53.0.3 notify sub.test | set 's/^/ns3 /' | cat_i 259 retry_quiet 10 wait_for_serial 10.53.0.4 sub.test. 3 dig.out.test$n || ret=1 260fi 261 262wait_for_log 10 'got nonincremental response' ns4/named.run || ret=1 263if [ $ret != 0 ]; then echo_i "failed"; fi 264status=$((status+ret)) 265 266n=$((n+1)) 267echo_i "testing 'request-ixfr yes' option inheritance from view ($n)" 268ret=0 269sleep 1 270cp ns3/mytest2.db ns3/mytest.db # change to test zone, should be IXFR 271nextpart ns4/named.run > /dev/null 272$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i 273 274# wait for primary to reload 275retry_quiet 10 wait_for_serial 10.53.0.3 test. 3 dig.out.test$n || ret=1 276 277# wait for secondary to reload 278tret=0 279retry_quiet 5 wait_for_serial 10.53.0.4 test. 3 dig.out.test$n || tret=1 280if [ $tret -eq 1 ]; then 281 # re-noitfy after 5 seconds, then wait another 10 282 $RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i 283 retry_quiet 10 wait_for_serial 10.53.0.4 test. 3 dig.out.test$n || ret=1 284fi 285 286wait_for_log 10 'got incremental response' ns4/named.run || ret=1 287if [ $ret != 0 ]; then echo_i "failed"; fi 288status=$((status+ret)) 289 290n=$((n+1)) 291ret=0 292echo_i "testing DiG's handling of a multi message AXFR style IXFR response ($n)" 293( 294(sleep 10 && kill $$) 2>/dev/null & 295sub=$! 296$DIG -p ${PORT} ixfr=0 large @10.53.0.3 > dig.out.test$n 297kill $sub 298) 299lines=`grep hostmaster.large dig.out.test$n | wc -l` 300test ${lines:-0} -eq 2 || ret=1 301messages=`sed -n 's/^;;.*messages \([0-9]*\),.*/\1/p' dig.out.test$n` 302test ${messages:-0} -gt 1 || ret=1 303if [ $ret != 0 ]; then echo_i "failed"; fi 304status=$((status+ret)) 305 306n=$((n+1)) 307echo_i "test 'dig +notcp ixfr=<value>' vs 'dig ixfr=<value> +notcp' vs 'dig ixfr=<value>' ($n)" 308ret=0 309# Should be "switch to TCP" response 310$DIG $DIGOPTS +notcp ixfr=1 test @10.53.0.4 > dig.out1.test$n || ret=1 311$DIG $DIGOPTS ixfr=1 +notcp test @10.53.0.4 > dig.out2.test$n || ret=1 312digcomp dig.out1.test$n dig.out2.test$n || ret=1 313awk '$4 == "SOA" { soacnt++} END {if (soacnt == 1) exit(0); else exit(1);}' dig.out1.test$n || ret=1 314awk '$4 == "SOA" { if ($7 == 3) exit(0); else exit(1);}' dig.out1.test$n || ret=1 315# 316nextpart ns4/named.run > /dev/null 317# Should be incremental transfer. 318$DIG $DIGOPTS ixfr=1 test @10.53.0.4 > dig.out3.test$n || ret=1 319awk '$4 == "SOA" { soacnt++} END { if (soacnt == 6) exit(0); else exit(1);}' dig.out3.test$n || ret=1 320if [ $ret != 0 ]; then echo_i "failed"; fi 321status=$((status+ret)) 322 323n=$((n+1)) 324echo_i "check estimated IXFR size ($n)" 325ret=0 326# note IXFR delta size will be slightly bigger with version 1 transaction 327# headers as there is no correction for the overall record length storage. 328# Ver1 = 4 * (6 + 10 + 10 + 17 + 5 * 4) + 2 * (13 + 10 + 4) + (6 * 4) = 330 329# Ver2 = 4 * (6 + 10 + 10 + 17 + 5 * 4) + 2 * (13 + 10 + 4) = 306 330nextpart ns4/named.run | grep "IXFR delta size (306 bytes)" > /dev/null || ret=1 331if [ $ret != 0 ]; then echo_i "failed"; fi 332status=$((status+ret)) 333 334# make sure ns5 has transfered the zone 335# wait for secondary to reload 336tret=0 337retry_quiet 5 wait_for_serial 10.53.0.5 test. 4 dig.out.test$n || tret=1 338if [ $tret -eq 1 ]; then 339 # re-noitfy after 5 seconds, then wait another 10 340 $RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i 341 retry_quiet 10 wait_for_serial 10.53.0.5 test. 3 dig.out.test$n || ret=1 342fi 343 344n=$((n+1)) 345echo_i "test 'provide-ixfr no;' (serial < current) ($n)" 346ret=0 347nextpart ns5/named.run > /dev/null 348# Should be "AXFR style" response 349$DIG $DIGOPTS ixfr=1 test @10.53.0.5 > dig.out1.test$n || ret=1 350# Should be "switch to TCP" response 351$DIG $DIGOPTS ixfr=1 +notcp test @10.53.0.5 > dig.out2.test$n || ret=1 352awk '$4 == "SOA" { soacnt++} END {if (soacnt == 2) exit(0); else exit(1);}' dig.out1.test$n || ret=1 353awk '$4 == "SOA" { soacnt++} END {if (soacnt == 1) exit(0); else exit(1);}' dig.out2.test$n || ret=1 354if [ $ret != 0 ]; then echo_i "failed"; fi 355status=$((status+ret)) 356 357n=$((n+1)) 358echo_i "checking whether dig calculates IXFR statistics correctly ($n)" 359ret=0 360$DIG $DIGOPTS +noedns +stat -b 10.53.0.4 @10.53.0.4 test. ixfr=2 > dig.out1.test$n 361get_dig_xfer_stats dig.out1.test$n > stats.dig 362diff ixfr-stats.good stats.dig > /dev/null || ret=1 363if [ $ret != 0 ]; then echo_i "failed"; fi 364status=$((status+ret)) 365 366# Note: in the next two tests, we use ns4 logs for checking both incoming and 367# outgoing transfer statistics as ns4 is both a secondary server (for ns3) and a 368# primary server (for dig queries from the previous test) for "test". 369 370_wait_for_stats () { 371 get_named_xfer_stats ns4/named.run "$1" test "$2" > "$3" 372 diff ixfr-stats.good "$3" > /dev/null || return 1 373 return 0 374} 375 376n=$((n+1)) 377echo_i "checking whether named calculates incoming IXFR statistics correctly ($n)" 378ret=0 379retry_quiet 10 _wait_for_stats 10.53.0.3 "Transfer completed" stats.incoming 380if [ $ret != 0 ]; then echo_i "failed"; fi 381status=$((status+ret)) 382 383n=$((n+1)) 384echo_i "checking whether named calculates outgoing IXFR statistics correctly ($n)" 385retry_quiet 10 _wait_for_stats 10.53.0.4 "IXFR ended" stats.outgoing 386if [ $ret != 0 ]; then echo_i "failed"; fi 387status=$((status+ret)) 388 389n=$((n+1)) 390ret=0 391echo_i "testing fallback to AXFR when max-ixfr-ratio is exceeded ($n)" 392nextpart ns4/named.run > /dev/null 393 394sleep 1 395cp ns3/mytest3.db ns3/mytest.db # change to test zone, too big for IXFR 396$RNDCCMD 10.53.0.3 reload | sed 's/^/ns3 /' | cat_i 397 398# wait for secondary to reload 399tret=0 400retry_quiet 5 wait_for_serial 10.53.0.4 test. 4 dig.out.test$n || tret=1 401if [ $tret -eq 1 ]; then 402 # re-noitfy after 5 seconds, then wait another 10 403 $RNDCCMD 10.53.0.3 notify test | set 's/^/ns3 /' | cat_i 404 retry_quiet 10 wait_for_serial 10.53.0.4 test. 4 dig.out.test$n || ret=1 405fi 406 407wait_for_log 10 'got nonincremental response' ns4/named.run || ret=1 408if [ $ret != 0 ]; then echo_i "failed"; fi 409status=$((status+ret)) 410 411echo_i "exit status: $status" 412[ $status -eq 0 ] || exit 1 413