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# ns1 = stealth primary 15# ns2 = secondary with update forwarding disabled; not currently used 16# ns3 = secondary with update forwarding enabled 17 18set -e 19 20. ../conf.sh 21 22DIGOPTS="+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd -p ${PORT}" 23RNDCCMD="$RNDC -p ${CONTROLPORT} -c ../_common/rndc.conf" 24 25nextpart_thrice() { 26 nextpart ns1/named.run >/dev/null 27 nextpart ns2/named.run >/dev/null 28 nextpart ns3/named.run >/dev/null 29} 30 31wait_for_log_thrice() { 32 echo_i "waiting for servers to incorporate changes" 33 wait_for_log 10 "committing update transaction" ns1/named.run 34 wait_for_log 10 "zone transfer finished" ns2/named.run 35 wait_for_log 10 "zone transfer finished" ns3/named.run 36} 37 38status=0 39n=1 40capture_dnstap() { 41 retry_quiet 20 test -f ns3/dnstap.out && mv ns3/dnstap.out dnstap.out.$n 42 $RNDCCMD -s 10.53.0.3 dnstap -reopen 43} 44 45uq_equals_ur() { 46 zonename="$1" 47 "$DNSTAPREAD" dnstap.out.$n \ 48 | awk '$9 ~ /^'$zonename'\// { print }' \ 49 | awk '$3 == "UQ" { UQ+=1 } $3 == "UR" { UR += 1 } END { print UQ+0, UR+0 }' >dnstapread.out$n 50 read UQ UR <dnstapread.out$n 51 echo_i "UQ=$UQ UR=$UR" 52 test $UQ -eq $UR || return 1 53} 54 55echo_i "waiting for servers to be ready for testing ($n)" 56for i in 1 2 3 4 5 6 7 8 9 10; do 57 ret=0 58 $DIG +tcp -p ${PORT} example. @10.53.0.1 soa >dig.out.ns1.$n || ret=1 59 grep "status: NOERROR" dig.out.ns1.$n >/dev/null || ret=1 60 $DIG +tcp -p ${PORT} example. @10.53.0.2 soa >dig.out.ns2.$n || ret=1 61 grep "status: NOERROR" dig.out.ns2.$n >/dev/null || ret=1 62 $DIG +tcp -p ${PORT} example. @10.53.0.3 soa >dig.out.ns3.$n || ret=1 63 grep "status: NOERROR" dig.out.ns3.$n >/dev/null || ret=1 64 test $ret = 0 && break 65 sleep 1 66done 67if [ $ret != 0 ]; then 68 echo_i "failed" 69 status=$((status + ret)) 70fi 71n=$((n + 1)) 72 73echo_i "fetching primary copy of zone before update ($n)" 74ret=0 75$DIG $DIGOPTS example. @10.53.0.1 axfr >dig.out.ns1.example.before || ret=1 76if [ $ret != 0 ]; then 77 echo_i "failed" 78 status=$((status + ret)) 79fi 80n=$((n + 1)) 81 82echo_i "fetching secondary 1 copy of zone before update ($n)" 83$DIG $DIGOPTS example. @10.53.0.2 axfr >dig.out.ns2.example.before || ret=1 84if [ $ret != 0 ]; then 85 echo_i "failed" 86 status=$((status + ret)) 87fi 88n=$((n + 1)) 89 90echo_i "fetching secondary 2 copy of zone before update ($n)" 91ret=0 92$DIG $DIGOPTS example. @10.53.0.3 axfr >dig.out.ns3.example.before || ret=1 93if [ $ret != 0 ]; then 94 echo_i "failed" 95 status=$((status + ret)) 96fi 97n=$((n + 1)) 98 99echo_i "comparing pre-update copies to known good data ($n)" 100ret=0 101digcomp knowngood.before dig.out.ns1.example.before || ret=1 102digcomp knowngood.before dig.out.ns2.example.before || ret=1 103digcomp knowngood.before dig.out.ns3.example.before || ret=1 104if [ $ret != 0 ]; then 105 echo_i "failed" 106 status=$((status + ret)) 107fi 108 109echo_i "checking update forwarding of a zone (signed) (Do53 -> DoT) ($n)" 110nextpart_thrice 111ret=0 112$NSUPDATE -y "${DEFAULT_HMAC}:update.example:c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K" -- - <<EOF || ret=1 113local 10.53.0.1 114server 10.53.0.3 ${PORT} 115update add updated.example. 600 A 10.10.10.1 116update add updated.example. 600 TXT Foo 117send 118EOF 119if [ $ret != 0 ]; then 120 echo_i "failed" 121 status=$((status + ret)) 122fi 123n=$((n + 1)) 124wait_for_log_thrice 125 126echo_i "fetching primary copy of zone after update ($n)" 127ret=0 128$DIG $DIGOPTS example. @10.53.0.1 axfr >dig.out.ns1.example.after1 || ret=1 129if [ $ret != 0 ]; then 130 echo_i "failed" 131 status=$((status + ret)) 132fi 133n=$((n + 1)) 134 135echo_i "fetching secondary 1 copy of zone after update ($n)" 136ret=0 137$DIG $DIGOPTS example. @10.53.0.2 axfr >dig.out.ns2.example.after1 || ret=1 138if [ $ret != 0 ]; then 139 echo_i "failed" 140 status=$((status + ret)) 141fi 142 143echo_i "fetching secondary 2 copy of zone after update ($n)" 144ret=0 145$DIG $DIGOPTS example. @10.53.0.3 axfr >dig.out.ns3.example.after1 || ret=1 146if [ $ret != 0 ]; then 147 echo_i "failed" 148 status=$((status + ret)) 149fi 150n=$((n + 1)) 151 152echo_i "comparing post-update copies to known good data ($n)" 153ret=0 154digcomp knowngood.after1 dig.out.ns1.example.after1 || ret=1 155digcomp knowngood.after1 dig.out.ns2.example.after1 || ret=1 156digcomp knowngood.after1 dig.out.ns3.example.after1 || ret=1 157if [ $ret != 0 ]; then 158 echo_i "failed" 159 status=$((status + ret)) 160fi 161 162echo_i "checking update forwarding of a zone (signed) (DoT -> DoT) ($n)" 163nextpart_thrice 164ret=0 165$NSUPDATE -y "${DEFAULT_HMAC}:update.example:c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K" -S -O -- - <<EOF || ret=1 166local 10.53.0.1 167server 10.53.0.3 ${TLSPORT} 168update add updated-dot.example. 600 A 10.10.10.1 169update add updated-dot.example. 600 TXT Foo 170send 171EOF 172if [ $ret != 0 ]; then 173 echo_i "failed" 174 status=$((status + ret)) 175fi 176n=$((n + 1)) 177wait_for_log_thrice 178 179echo_i "fetching primary copy of zone after update ($n)" 180ret=0 181$DIG $DIGOPTS example. @10.53.0.1 axfr >dig.out.ns1.example.after2 || ret=1 182if [ $ret != 0 ]; then 183 echo_i "failed" 184 status=$((status + ret)) 185fi 186n=$((n + 1)) 187 188echo_i "fetching secondary 1 copy of zone after update ($n)" 189ret=0 190$DIG $DIGOPTS example. @10.53.0.2 axfr >dig.out.ns2.example.after2 || ret=1 191if [ $ret != 0 ]; then 192 echo_i "failed" 193 status=$((status + ret)) 194fi 195 196echo_i "fetching secondary 2 copy of zone after update ($n)" 197ret=0 198$DIG $DIGOPTS example. @10.53.0.3 axfr >dig.out.ns3.example.after2 || ret=1 199if [ $ret != 0 ]; then 200 echo_i "failed" 201 status=$((status + ret)) 202fi 203n=$((n + 1)) 204 205echo_i "comparing post-update copies to known good data ($n)" 206ret=0 207digcomp knowngood.after2 dig.out.ns1.example.after2 || ret=1 208digcomp knowngood.after2 dig.out.ns2.example.after2 || ret=1 209digcomp knowngood.after2 dig.out.ns3.example.after2 || ret=1 210if [ $ret != 0 ]; then 211 echo_i "failed" 212 status=$((status + ret)) 213fi 214 215echo_i "checking 'forwarding update for zone' is logged twice ($n)" 216ret=0 217cnt=$(grep -F "forwarding update for zone 'example/IN'" ns3/named.run | wc -l || ret=1) 218test "${cnt}" -eq 2 || ret=1 219if [ $ret != 0 ]; then 220 echo_i "failed" 221 status=$((status + ret)) 222fi 223n=$((n + 1)) 224 225if $FEATURETEST --enable-dnstap; then 226 echo_i "checking DNSTAP logging of UPDATE forwarded update replies ($n)" 227 ret=0 228 capture_dnstap 229 uq_equals_ur example || ret=1 230 if [ $ret != 0 ]; then echo_i "failed"; fi 231 status=$((status + ret)) 232 n=$((n + 1)) 233fi 234 235echo_i "updating zone (unsigned) ($n)" 236nextpart_thrice 237ret=0 238$NSUPDATE -- - <<EOF || ret=1 239local 10.53.0.1 240server 10.53.0.3 ${PORT} 241update add unsigned.example. 600 A 10.10.10.1 242update add unsigned.example. 600 TXT Foo 243send 244EOF 245if [ $ret != 0 ]; then 246 echo_i "failed" 247 status=$((status + ret)) 248fi 249n=$((n + 1)) 250wait_for_log_thrice 251 252echo_i "fetching primary copy of zone after update ($n)" 253ret=0 254$DIG $DIGOPTS example. @10.53.0.1 axfr >dig.out.ns1.example.after3 || ret=1 255if [ $ret != 0 ]; then 256 echo_i "failed" 257 status=$((status + ret)) 258fi 259 260echo_i "fetching secondary 1 copy of zone after update ($n)" 261ret=0 262$DIG $DIGOPTS example. @10.53.0.2 axfr >dig.out.ns2.example.after3 || ret=1 263if [ $ret != 0 ]; then 264 echo_i "failed" 265 status=$((status + ret)) 266fi 267n=$((n + 1)) 268 269echo_i "fetching secondary 2 copy of zone after update ($n)" 270ret=0 271$DIG $DIGOPTS example. @10.53.0.3 axfr >dig.out.ns3.example.after3 || ret=1 272if [ $ret != 0 ]; then 273 echo_i "failed" 274 status=$((status + ret)) 275fi 276 277echo_i "comparing post-update copies to known good data ($n)" 278ret=0 279digcomp knowngood.after3 dig.out.ns1.example.after3 || ret=1 280digcomp knowngood.after3 dig.out.ns2.example.after3 || ret=1 281digcomp knowngood.after3 dig.out.ns3.example.after3 || ret=1 282if [ $ret != 0 ]; then 283 echo_i "failed" 284 status=$((status + ret)) 285fi 286 287echo_i "fetching primary copy of zone before update, first primary fails ($n)" 288ret=0 289$DIG $DIGOPTS example3. @10.53.0.1 axfr >dig.out.ns1.example3.before || ret=1 290if [ $ret != 0 ]; then 291 echo_i "failed" 292 status=$((status + ret)) 293fi 294n=$((n + 1)) 295 296echo_i "fetching secondary 1 copy of zone before update, first primary fails ($n)" 297$DIG $DIGOPTS example3. @10.53.0.2 axfr >dig.out.ns2.example3.before || ret=1 298if [ $ret != 0 ]; then 299 echo_i "failed" 300 status=$((status + ret)) 301fi 302n=$((n + 1)) 303 304echo_i "fetching secondary 2 copy of zone before update, first primary fails ($n)" 305ret=0 306$DIG $DIGOPTS example3. @10.53.0.3 axfr >dig.out.ns3.example3.before || ret=1 307if [ $ret != 0 ]; then 308 echo_i "failed" 309 status=$((status + ret)) 310fi 311n=$((n + 1)) 312 313echo_i "comparing pre-update copies to known good data, first primary fails ($n)" 314ret=0 315digcomp knowngood.before.example3 dig.out.ns1.example3.before || ret=1 316digcomp knowngood.before.example3 dig.out.ns2.example3.before || ret=1 317digcomp knowngood.before.example3 dig.out.ns3.example3.before || ret=1 318if [ $ret != 0 ]; then 319 echo_i "failed" 320 status=$((status + ret)) 321fi 322 323echo_i "checking update forwarding of a zone (signed) (Do53 -> DoT) ($n)" 324nextpart_thrice 325ret=0 326$NSUPDATE -y "${DEFAULT_HMAC}:update.example:c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K" -- - <<EOF || ret=1 327local 10.53.0.1 328server 10.53.0.3 ${PORT} 329update add updated.example3. 600 A 10.10.10.1 330update add updated.example3. 600 TXT Foo 331send 332EOF 333if [ $ret != 0 ]; then 334 echo_i "failed" 335 status=$((status + ret)) 336fi 337n=$((n + 1)) 338wait_for_log_thrice 339 340echo_i "fetching primary copy of zone after update, first primary fails ($n)" 341ret=0 342$DIG $DIGOPTS example3. @10.53.0.1 axfr >dig.out.ns1.example3.after1 || ret=1 343if [ $ret != 0 ]; then 344 echo_i "failed" 345 status=$((status + ret)) 346fi 347n=$((n + 1)) 348 349echo_i "fetching secondary 1 copy of zone after update, first primary fails ($n)" 350ret=0 351$DIG $DIGOPTS example3. @10.53.0.2 axfr >dig.out.ns2.example3.after1 || ret=1 352if [ $ret != 0 ]; then 353 echo_i "failed" 354 status=$((status + ret)) 355fi 356 357echo_i "fetching secondary 2 copy of zone after update, first primary fails ($n)" 358ret=0 359$DIG $DIGOPTS example3. @10.53.0.3 axfr >dig.out.ns3.example3.after1 || ret=1 360if [ $ret != 0 ]; then 361 echo_i "failed" 362 status=$((status + ret)) 363fi 364n=$((n + 1)) 365 366echo_i "comparing post-update copies to known good data, first primary fails ($n)" 367ret=0 368digcomp knowngood.after1.example3 dig.out.ns1.example3.after1 || ret=1 369digcomp knowngood.after1.example3 dig.out.ns2.example3.after1 || ret=1 370digcomp knowngood.after1.example3 dig.out.ns3.example3.after1 || ret=1 371if [ $ret != 0 ]; then 372 echo_i "failed" 373 status=$((status + ret)) 374fi 375 376if $FEATURETEST --enable-dnstap; then 377 echo_i "checking DNSTAP logging of UPDATE forwarded update replies ($n)" 378 ret=0 379 capture_dnstap 380 uq_equals_ur example3 || ret=1 381 if [ $ret != 0 ]; then echo_i "failed"; fi 382 status=$((status + ret)) 383 n=$((n + 1)) 384fi 385n=$((n + 1)) 386 387if test -f keyname; then 388 echo_i "checking update forwarding with sig0 (Do53 -> Do53) ($n)" 389 nextpart_thrice 390 ret=0 391 keyname=$(cat keyname) 392 $NSUPDATE -k $keyname.private -- - <<EOF >nsupdate.out.test$n 2>&1 || ret=1 393 local 10.53.0.1 394 server 10.53.0.3 ${PORT} 395 zone example2 396 update add unsigned.example2. 600 A 10.10.10.1 397 update add unsigned.example2. 600 TXT Foo 398 send 399EOF 400 if [ $ret != 0 ]; then 401 echo_i "failed" 402 status=$((status + ret)) 403 fi 404 n=$((n + 1)) 405 wait_for_log_thrice 406 407 $DIG -p ${PORT} unsigned.example2 A @10.53.0.1 >dig.out.ns1.test$n || ret=1 408 grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1 409 if [ $ret != 0 ]; then echo_i "failed"; fi 410 status=$((status + ret)) 411 n=$((n + 1)) 412 413 if $FEATURETEST --enable-dnstap; then 414 echo_i "checking DNSTAP logging of UPDATE forwarded update replies ($n)" 415 ret=0 416 capture_dnstap 417 uq_equals_ur example2 || ret=1 418 if [ $ret != 0 ]; then echo_i "failed"; fi 419 status=$((status + ret)) 420 n=$((n + 1)) 421 fi 422 423 echo_i "checking update forwarding with sig0 (DoT -> Do53) ($n)" 424 nextpart_thrice 425 ret=0 426 keyname=$(cat keyname) 427 $NSUPDATE -k $keyname.private -S -O -- - <<EOF >nsupdate.out.test$n 2>&1 || ret=1 428 local 10.53.0.1 429 server 10.53.0.3 ${TLSPORT} 430 zone example2 431 update add unsigned-dot.example2. 600 A 10.10.10.1 432 update add unsigned-dot.example2. 600 TXT Foo 433 send 434EOF 435 if [ $ret != 0 ]; then 436 echo_i "failed" 437 status=$((status + ret)) 438 fi 439 n=$((n + 1)) 440 wait_for_log_thrice 441 442 $DIG -p ${PORT} unsigned-dot.example2 A @10.53.0.1 >dig.out.ns1.test$n || ret=1 443 grep "status: NOERROR" dig.out.ns1.test$n >/dev/null || ret=1 444 if [ $ret != 0 ]; then echo_i "failed"; fi 445 status=$((status + ret)) 446 n=$((n + 1)) 447 448 if $FEATURETEST --enable-dnstap; then 449 echo_i "checking DNSTAP logging of UPDATE forwarded update replies ($n)" 450 ret=0 451 capture_dnstap 452 uq_equals_ur example2 || ret=1 453 if [ $ret != 0 ]; then echo_i "failed"; fi 454 status=$((status + ret)) 455 n=$((n + 1)) 456 fi 457 458 echo_i "checking update forwarding with sig0 with too many keys ($n)" 459 nextpart_thrice 460 ret=0 461 good=0 462 bad=0 463 for i in 1 2 3; do 464 keyname=$(cat keyname$i) 465 $NSUPDATE -d -D -k $keyname.private -- - <<EOF >nsupdate.out.test$n.$i 2>&1 && good=$((good + 1)) || bad=$((bad + 1)) 466 local 10.53.0.1 467 server 10.53.0.3 ${PORT} 468 zone example2-toomanykeys 469 update add toomanykeys$i.example2-toomanykeys. 600 A 10.10.10.1 470 send 471EOF 472 done 473 # There are three keys in the zone but named checks the signature using 474 # maximum two keys, so one of these updates should have been failed. 475 [ $good = 2 ] && [ $bad = 1 ] || ret=1 476 if [ $ret != 0 ]; then echo_i "failed"; fi 477 status=$((status + ret)) 478 n=$((n + 1)) 479fi 480 481echo_i "attempting an update that should be rejected by ACL ($n)" 482ret=0 483{ 484 $NSUPDATE -- - <<EOF 485 local 10.53.0.2 486 server 10.53.0.3 ${PORT} 487 update add another.unsigned.example. 600 A 10.10.10.2 488 update add another.unsigned.example. 600 TXT Bar 489 send 490EOF 491} >nsupdate.out.$n 2>&1 && ret=1 492grep REFUSED nsupdate.out.$n >/dev/null || ret=1 493if [ $ret != 0 ]; then 494 echo_i "failed" 495 status=$((status + ret)) 496fi 497n=$((n + 1)) 498 499echo_i "checking update forwarding to dead primary ($n)" 500count=0 501ret=0 502while [ $count -lt 5 -a $ret -eq 0 ]; do 503 ( 504 $NSUPDATE -- - <<EOF 505local 10.53.0.1 506server 10.53.0.3 ${PORT} 507zone noprimary 508update add unsigned.noprimary. 600 A 10.10.10.1 509update add unsigned.noprimary. 600 TXT Foo 510send 511EOF 512 ) >/dev/null 2>&1 & 513 $DIG -p ${PORT} +noadd +notcp +noauth noprimary. @10.53.0.3 soa >dig.out.ns3.test$n.$count || ret=1 514 grep "status: NOERROR" dig.out.ns3.test$n.$count >/dev/null || ret=1 515 count=$((count + 1)) 516done 517if [ $ret != 0 ]; then 518 echo_i "failed" 519 status=$((status + ret)) 520fi 521n=$((n + 1)) 522 523echo_i "waiting for nsupdate to finish ($n)" 524wait 525n=$((n + 1)) 526 527if $FEATURETEST --enable-dnstap; then 528 echo_i "checking DNSTAP logging of UPDATE forwarded update replies ($n)" 529 ret=0 530 capture_dnstap 531 uq_equals_ur noprimary && ret=1 532 if [ $ret != 0 ]; then echo_i "failed"; fi 533 status=$((status + ret)) 534 n=$((n + 1)) 535fi 536 537n=$((n + 1)) 538ret=0 539echo_i "attempting updates that should exceed quota ($n)" 540# lower the update quota to 1. 541copy_setports ns3/named2.conf.in ns3/named.conf 542rndc_reconfig ns3 10.53.0.3 543nextpart ns3/named.run >/dev/null 544for loop in 1 2 3 4 5 6 7 8 9 10; do 545 { 546 $NSUPDATE -- - >/dev/null 2>&1 <<END 547 local 10.53.0.1 548 server 10.53.0.3 ${PORT} 549 update add txt-$loop.unsigned.example 300 IN TXT Whatever 550 send 551END 552 } & 553done 554wait_for_log 10 "too many DNS UPDATEs queued" ns3/named.run || ret=1 555[ $ret = 0 ] || { 556 echo_i "failed" 557 status=1 558} 559 560echo_i "exit status: $status" 561[ $status -eq 0 ] || exit 1 562