Home | History | Annotate | Line # | Download | only in upforwd
      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