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 18 set -e 19 20 . ../conf.sh 21 22 DIGOPTS="+tcp +noadd +nosea +nostat +noquest +nocomm +nocmd -p ${PORT}" 23 RNDCCMD="$RNDC -p ${CONTROLPORT} -c ../_common/rndc.conf" 24 25 nextpart_thrice() { 26 nextpart ns1/named.run >/dev/null 27 nextpart ns2/named.run >/dev/null 28 nextpart ns3/named.run >/dev/null 29 } 30 31 wait_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 38 status=0 39 n=1 40 capture_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 45 uq_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 55 echo_i "waiting for servers to be ready for testing ($n)" 56 for 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 66 done 67 if [ $ret != 0 ]; then 68 echo_i "failed" 69 status=$((status + ret)) 70 fi 71 n=$((n + 1)) 72 73 echo_i "fetching primary copy of zone before update ($n)" 74 ret=0 75 $DIG $DIGOPTS example. @10.53.0.1 axfr >dig.out.ns1.example.before || ret=1 76 if [ $ret != 0 ]; then 77 echo_i "failed" 78 status=$((status + ret)) 79 fi 80 n=$((n + 1)) 81 82 echo_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 84 if [ $ret != 0 ]; then 85 echo_i "failed" 86 status=$((status + ret)) 87 fi 88 n=$((n + 1)) 89 90 echo_i "fetching secondary 2 copy of zone before update ($n)" 91 ret=0 92 $DIG $DIGOPTS example. @10.53.0.3 axfr >dig.out.ns3.example.before || ret=1 93 if [ $ret != 0 ]; then 94 echo_i "failed" 95 status=$((status + ret)) 96 fi 97 n=$((n + 1)) 98 99 echo_i "comparing pre-update copies to known good data ($n)" 100 ret=0 101 digcomp knowngood.before dig.out.ns1.example.before || ret=1 102 digcomp knowngood.before dig.out.ns2.example.before || ret=1 103 digcomp knowngood.before dig.out.ns3.example.before || ret=1 104 if [ $ret != 0 ]; then 105 echo_i "failed" 106 status=$((status + ret)) 107 fi 108 109 echo_i "checking update forwarding of a zone (signed) (Do53 -> DoT) ($n)" 110 nextpart_thrice 111 ret=0 112 $NSUPDATE -y "${DEFAULT_HMAC}:update.example:c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K" -- - <<EOF || ret=1 113 local 10.53.0.1 114 server 10.53.0.3 ${PORT} 115 update add updated.example. 600 A 10.10.10.1 116 update add updated.example. 600 TXT Foo 117 send 118 EOF 119 if [ $ret != 0 ]; then 120 echo_i "failed" 121 status=$((status + ret)) 122 fi 123 n=$((n + 1)) 124 wait_for_log_thrice 125 126 echo_i "fetching primary copy of zone after update ($n)" 127 ret=0 128 $DIG $DIGOPTS example. @10.53.0.1 axfr >dig.out.ns1.example.after1 || ret=1 129 if [ $ret != 0 ]; then 130 echo_i "failed" 131 status=$((status + ret)) 132 fi 133 n=$((n + 1)) 134 135 echo_i "fetching secondary 1 copy of zone after update ($n)" 136 ret=0 137 $DIG $DIGOPTS example. @10.53.0.2 axfr >dig.out.ns2.example.after1 || ret=1 138 if [ $ret != 0 ]; then 139 echo_i "failed" 140 status=$((status + ret)) 141 fi 142 143 echo_i "fetching secondary 2 copy of zone after update ($n)" 144 ret=0 145 $DIG $DIGOPTS example. @10.53.0.3 axfr >dig.out.ns3.example.after1 || ret=1 146 if [ $ret != 0 ]; then 147 echo_i "failed" 148 status=$((status + ret)) 149 fi 150 n=$((n + 1)) 151 152 echo_i "comparing post-update copies to known good data ($n)" 153 ret=0 154 digcomp knowngood.after1 dig.out.ns1.example.after1 || ret=1 155 digcomp knowngood.after1 dig.out.ns2.example.after1 || ret=1 156 digcomp knowngood.after1 dig.out.ns3.example.after1 || ret=1 157 if [ $ret != 0 ]; then 158 echo_i "failed" 159 status=$((status + ret)) 160 fi 161 162 echo_i "checking update forwarding of a zone (signed) (DoT -> DoT) ($n)" 163 nextpart_thrice 164 ret=0 165 $NSUPDATE -y "${DEFAULT_HMAC}:update.example:c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K" -S -O -- - <<EOF || ret=1 166 local 10.53.0.1 167 server 10.53.0.3 ${TLSPORT} 168 update add updated-dot.example. 600 A 10.10.10.1 169 update add updated-dot.example. 600 TXT Foo 170 send 171 EOF 172 if [ $ret != 0 ]; then 173 echo_i "failed" 174 status=$((status + ret)) 175 fi 176 n=$((n + 1)) 177 wait_for_log_thrice 178 179 echo_i "fetching primary copy of zone after update ($n)" 180 ret=0 181 $DIG $DIGOPTS example. @10.53.0.1 axfr >dig.out.ns1.example.after2 || ret=1 182 if [ $ret != 0 ]; then 183 echo_i "failed" 184 status=$((status + ret)) 185 fi 186 n=$((n + 1)) 187 188 echo_i "fetching secondary 1 copy of zone after update ($n)" 189 ret=0 190 $DIG $DIGOPTS example. @10.53.0.2 axfr >dig.out.ns2.example.after2 || ret=1 191 if [ $ret != 0 ]; then 192 echo_i "failed" 193 status=$((status + ret)) 194 fi 195 196 echo_i "fetching secondary 2 copy of zone after update ($n)" 197 ret=0 198 $DIG $DIGOPTS example. @10.53.0.3 axfr >dig.out.ns3.example.after2 || ret=1 199 if [ $ret != 0 ]; then 200 echo_i "failed" 201 status=$((status + ret)) 202 fi 203 n=$((n + 1)) 204 205 echo_i "comparing post-update copies to known good data ($n)" 206 ret=0 207 digcomp knowngood.after2 dig.out.ns1.example.after2 || ret=1 208 digcomp knowngood.after2 dig.out.ns2.example.after2 || ret=1 209 digcomp knowngood.after2 dig.out.ns3.example.after2 || ret=1 210 if [ $ret != 0 ]; then 211 echo_i "failed" 212 status=$((status + ret)) 213 fi 214 215 echo_i "checking 'forwarding update for zone' is logged twice ($n)" 216 ret=0 217 cnt=$(grep -F "forwarding update for zone 'example/IN'" ns3/named.run | wc -l || ret=1) 218 test "${cnt}" -eq 2 || ret=1 219 if [ $ret != 0 ]; then 220 echo_i "failed" 221 status=$((status + ret)) 222 fi 223 n=$((n + 1)) 224 225 if $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)) 233 fi 234 235 echo_i "updating zone (unsigned) ($n)" 236 nextpart_thrice 237 ret=0 238 $NSUPDATE -- - <<EOF || ret=1 239 local 10.53.0.1 240 server 10.53.0.3 ${PORT} 241 update add unsigned.example. 600 A 10.10.10.1 242 update add unsigned.example. 600 TXT Foo 243 send 244 EOF 245 if [ $ret != 0 ]; then 246 echo_i "failed" 247 status=$((status + ret)) 248 fi 249 n=$((n + 1)) 250 wait_for_log_thrice 251 252 echo_i "fetching primary copy of zone after update ($n)" 253 ret=0 254 $DIG $DIGOPTS example. @10.53.0.1 axfr >dig.out.ns1.example.after3 || ret=1 255 if [ $ret != 0 ]; then 256 echo_i "failed" 257 status=$((status + ret)) 258 fi 259 260 echo_i "fetching secondary 1 copy of zone after update ($n)" 261 ret=0 262 $DIG $DIGOPTS example. @10.53.0.2 axfr >dig.out.ns2.example.after3 || ret=1 263 if [ $ret != 0 ]; then 264 echo_i "failed" 265 status=$((status + ret)) 266 fi 267 n=$((n + 1)) 268 269 echo_i "fetching secondary 2 copy of zone after update ($n)" 270 ret=0 271 $DIG $DIGOPTS example. @10.53.0.3 axfr >dig.out.ns3.example.after3 || ret=1 272 if [ $ret != 0 ]; then 273 echo_i "failed" 274 status=$((status + ret)) 275 fi 276 277 echo_i "comparing post-update copies to known good data ($n)" 278 ret=0 279 digcomp knowngood.after3 dig.out.ns1.example.after3 || ret=1 280 digcomp knowngood.after3 dig.out.ns2.example.after3 || ret=1 281 digcomp knowngood.after3 dig.out.ns3.example.after3 || ret=1 282 if [ $ret != 0 ]; then 283 echo_i "failed" 284 status=$((status + ret)) 285 fi 286 287 echo_i "fetching primary copy of zone before update, first primary fails ($n)" 288 ret=0 289 $DIG $DIGOPTS example3. @10.53.0.1 axfr >dig.out.ns1.example3.before || ret=1 290 if [ $ret != 0 ]; then 291 echo_i "failed" 292 status=$((status + ret)) 293 fi 294 n=$((n + 1)) 295 296 echo_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 298 if [ $ret != 0 ]; then 299 echo_i "failed" 300 status=$((status + ret)) 301 fi 302 n=$((n + 1)) 303 304 echo_i "fetching secondary 2 copy of zone before update, first primary fails ($n)" 305 ret=0 306 $DIG $DIGOPTS example3. @10.53.0.3 axfr >dig.out.ns3.example3.before || ret=1 307 if [ $ret != 0 ]; then 308 echo_i "failed" 309 status=$((status + ret)) 310 fi 311 n=$((n + 1)) 312 313 echo_i "comparing pre-update copies to known good data, first primary fails ($n)" 314 ret=0 315 digcomp knowngood.before.example3 dig.out.ns1.example3.before || ret=1 316 digcomp knowngood.before.example3 dig.out.ns2.example3.before || ret=1 317 digcomp knowngood.before.example3 dig.out.ns3.example3.before || ret=1 318 if [ $ret != 0 ]; then 319 echo_i "failed" 320 status=$((status + ret)) 321 fi 322 323 echo_i "checking update forwarding of a zone (signed) (Do53 -> DoT) ($n)" 324 nextpart_thrice 325 ret=0 326 $NSUPDATE -y "${DEFAULT_HMAC}:update.example:c3Ryb25nIGVub3VnaCBmb3IgYSBtYW4gYnV0IG1hZGUgZm9yIGEgd29tYW4K" -- - <<EOF || ret=1 327 local 10.53.0.1 328 server 10.53.0.3 ${PORT} 329 update add updated.example3. 600 A 10.10.10.1 330 update add updated.example3. 600 TXT Foo 331 send 332 EOF 333 if [ $ret != 0 ]; then 334 echo_i "failed" 335 status=$((status + ret)) 336 fi 337 n=$((n + 1)) 338 wait_for_log_thrice 339 340 echo_i "fetching primary copy of zone after update, first primary fails ($n)" 341 ret=0 342 $DIG $DIGOPTS example3. @10.53.0.1 axfr >dig.out.ns1.example3.after1 || ret=1 343 if [ $ret != 0 ]; then 344 echo_i "failed" 345 status=$((status + ret)) 346 fi 347 n=$((n + 1)) 348 349 echo_i "fetching secondary 1 copy of zone after update, first primary fails ($n)" 350 ret=0 351 $DIG $DIGOPTS example3. @10.53.0.2 axfr >dig.out.ns2.example3.after1 || ret=1 352 if [ $ret != 0 ]; then 353 echo_i "failed" 354 status=$((status + ret)) 355 fi 356 357 echo_i "fetching secondary 2 copy of zone after update, first primary fails ($n)" 358 ret=0 359 $DIG $DIGOPTS example3. @10.53.0.3 axfr >dig.out.ns3.example3.after1 || ret=1 360 if [ $ret != 0 ]; then 361 echo_i "failed" 362 status=$((status + ret)) 363 fi 364 n=$((n + 1)) 365 366 echo_i "comparing post-update copies to known good data, first primary fails ($n)" 367 ret=0 368 digcomp knowngood.after1.example3 dig.out.ns1.example3.after1 || ret=1 369 digcomp knowngood.after1.example3 dig.out.ns2.example3.after1 || ret=1 370 digcomp knowngood.after1.example3 dig.out.ns3.example3.after1 || ret=1 371 if [ $ret != 0 ]; then 372 echo_i "failed" 373 status=$((status + ret)) 374 fi 375 376 if $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)) 384 fi 385 n=$((n + 1)) 386 387 if 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 399 EOF 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 434 EOF 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 4 5 6 7 8 9 10 11 12 13 14 15 16 17; 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 471 EOF 472 done 473 # There are 17 keys in the zone but by default named checks maximum 16 keys 474 # to find a matching key, so one of these updates should have been failed. 475 [ $good = 16 ] && [ $bad = 1 ] || ret=1 476 if [ $ret != 0 ]; then echo_i "failed"; fi 477 status=$((status + ret)) 478 n=$((n + 1)) 479 fi 480 481 echo_i "attempting an update that should be rejected by ACL ($n)" 482 ret=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 490 EOF 491 } >nsupdate.out.$n 2>&1 && ret=1 492 grep REFUSED nsupdate.out.$n >/dev/null || ret=1 493 if [ $ret != 0 ]; then 494 echo_i "failed" 495 status=$((status + ret)) 496 fi 497 n=$((n + 1)) 498 499 echo_i "checking update forwarding to dead primary ($n)" 500 count=0 501 ret=0 502 while [ $count -lt 5 -a $ret -eq 0 ]; do 503 ( 504 $NSUPDATE -- - <<EOF 505 local 10.53.0.1 506 server 10.53.0.3 ${PORT} 507 zone noprimary 508 update add unsigned.noprimary. 600 A 10.10.10.1 509 update add unsigned.noprimary. 600 TXT Foo 510 send 511 EOF 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)) 516 done 517 if [ $ret != 0 ]; then 518 echo_i "failed" 519 status=$((status + ret)) 520 fi 521 n=$((n + 1)) 522 523 echo_i "waiting for nsupdate to finish ($n)" 524 wait 525 n=$((n + 1)) 526 527 if $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)) 535 fi 536 537 n=$((n + 1)) 538 ret=0 539 echo_i "attempting updates that should exceed quota ($n)" 540 # lower the update quota to 1. 541 cp ns3/named2.conf ns3/named.conf 542 rndc_reconfig ns3 10.53.0.3 543 nextpart ns3/named.run >/dev/null 544 for 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 551 END 552 } & 553 done 554 wait_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 560 echo_i "exit status: $status" 561 [ $status -eq 0 ] || exit 1 562