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 set -e 15 16 # shellcheck disable=SC1091 17 . ../conf.sh 18 19 common_dig_options="+noadd +nosea +nostat +noquest +nocmd" 20 msg_xfrs_not_allowed=";; zone transfers over the established TLS connection are not allowed" 21 msg_peer_verification_failed=";; TLS peer certificate verification" 22 23 ca_file="./CA/CA.pem" 24 25 OPENSSL_VERSION=$("$PYTHON" "$TOP_SRCDIR/bin/tests/system/doth/get_openssl_version.py") 26 OPENSSL_VERSION_MAJOR=$(echo "$OPENSSL_VERSION" | cut -d ' ' -f 1) 27 OPENSSL_VERSION_MINOR=$(echo "$OPENSSL_VERSION" | cut -d ' ' -f 2) 28 29 # According to the RFC 8310, Section 8.1, Subject field MUST 30 # NOT be inspected when verifying a hostname when using 31 # DoT. Only SubjectAltName must be checked instead. That is 32 # not the case for HTTPS, though. 33 34 # Unfortunately, some quite old versions of OpenSSL (< 1.1.1) 35 # might lack the functionality to implement that. It should 36 # have very little real-world consequences, as most of the 37 # production-ready certificates issued by real CAs will have 38 # SubjectAltName set. In such a case, the Subject field is 39 # ignored. 40 # 41 # On the platforms with too old TLS versions, e.g. RedHat 7, we should 42 # ignore the tests checking the correct handling of absence of 43 # SubjectAltName. 44 if [ $OPENSSL_VERSION_MAJOR -gt 1 ]; then 45 run_san_tests=1 46 elif [ $OPENSSL_VERSION_MAJOR -eq 1 ] && [ $OPENSSL_VERSION_MINOR -ge 1 ]; then 47 run_san_tests=1 48 fi 49 50 dig_with_tls_opts() { 51 # shellcheck disable=SC2086 52 "$DIG" +tls $common_dig_options -p "${TLSPORT}" "$@" 53 } 54 55 dig_with_https_opts() { 56 # shellcheck disable=SC2086 57 "$DIG" +https $common_dig_options -p "${HTTPSPORT}" "$@" 58 } 59 60 dig_with_http_opts() { 61 # shellcheck disable=SC2086 62 "$DIG" +http-plain $common_dig_options -p "${HTTPPORT}" "$@" 63 } 64 65 dig_with_opts() { 66 # shellcheck disable=SC2086 67 "$DIG" $common_dig_options -p "${PORT}" "$@" 68 } 69 70 wait_for_tls_xfer() ( 71 srv_number="$1" 72 shift 73 zone_name="$1" 74 shift 75 # Let's bind to .10 to make it possible to easily distinguish dig from NSs in packet traces 76 dig_with_tls_opts -b 10.53.0.10 "@10.53.0.$srv_number" "${zone_name}." AXFR >"dig.out.ns$srv_number.${zone_name}.test$n" || return 1 77 grep "^;" "dig.out.ns$srv_number.${zone_name}.test$n" >/dev/null && return 1 78 return 0 79 ) 80 81 status=0 82 n=0 83 84 n=$((n + 1)) 85 echo_i "testing XoT server functionality (using dig) ($n)" 86 ret=0 87 dig_with_tls_opts example. -b 10.53.0.10 @10.53.0.1 axfr >dig.out.ns1.test$n || ret=1 88 grep "^;" dig.out.ns1.test$n | cat_i 89 digcomp example.axfr.good dig.out.ns1.test$n || ret=1 90 if test $ret != 0; then echo_i "failed"; fi 91 status=$((status + ret)) 92 93 n=$((n + 1)) 94 echo_i "testing incoming XoT functionality (from the first secondary) ($n)" 95 ret=0 96 if retry_quiet 10 wait_for_tls_xfer 2 example; then 97 digcomp example.axfr.good "dig.out.ns2.example.test$n" || ret=1 98 else 99 echo_i "timed out waiting for zone transfer" 100 grep "^;" "dig.out.ns2.example.test$n" | cat_i 101 ret=1 102 fi 103 if test $ret != 0; then echo_i "failed"; fi 104 status=$((status + ret)) 105 106 if [ -n "$run_san_tests" ]; then 107 n=$((n + 1)) 108 echo_i "testing incoming XoT functionality (from the first secondary, no SubjectAltName, failure expected) ($n)" 109 ret=0 110 if retry_quiet 10 wait_for_tls_xfer 2 example3; then 111 ret=1 112 else 113 echo_i "timed out waiting for zone transfer" 114 fi 115 if [ $ret != 0 ]; then echo_i "failed"; fi 116 status=$((status + ret)) 117 fi 118 119 n=$((n + 1)) 120 echo_i "testing incoming XoT functionality (from the first secondary, StrictTLS via implicit IP) ($n)" 121 ret=0 122 if retry_quiet 10 wait_for_tls_xfer 2 example4; then 123 retry_quiet 5 test -f "ns2/example4.db" || ret=1 124 else 125 echo_i "timed out waiting for zone transfer" 126 grep "^;" "dig.out.ns2.example4.test$n" | cat_i 127 ret=1 128 fi 129 if [ $ret != 0 ]; then echo_i "failed"; fi 130 status=$((status + ret)) 131 132 n=$((n + 1)) 133 echo_i "testing incoming XoT functionality (from the first secondary, StrictTLS via specified IPv4) ($n)" 134 ret=0 135 if retry_quiet 10 wait_for_tls_xfer 2 example5; then 136 retry_quiet 5 test -f "ns2/example5.db" || ret=1 137 else 138 echo_i "timed out waiting for zone transfer" 139 grep "^;" "dig.out.ns2.example5.test$n" | cat_i 140 ret=1 141 fi 142 if [ $ret != 0 ]; then echo_i "failed"; fi 143 status=$((status + ret)) 144 145 n=$((n + 1)) 146 echo_i "testing incoming XoT functionality (from the first secondary, StrictTLS via specified IPv6) ($n)" 147 ret=0 148 if retry_quiet 10 wait_for_tls_xfer 2 example6; then 149 retry_quiet 5 test -f "ns2/example6.db" || ret=1 150 else 151 echo_i "timed out waiting for zone transfer" 152 grep "^;" "dig.out.ns2.example6.test$n" | cat_i 153 ret=1 154 fi 155 if [ $ret != 0 ]; then echo_i "failed"; fi 156 status=$((status + ret)) 157 158 n=$((n + 1)) 159 echo_i "testing incoming XoT functionality (from the first secondary, wrong hostname, failure expected) ($n)" 160 ret=0 161 if retry_quiet 10 wait_for_tls_xfer 2 example7; then 162 ret=1 163 else 164 echo_i "timed out waiting for zone transfer" 165 fi 166 if [ $ret != 0 ]; then echo_i "failed"; fi 167 status=$((status + ret)) 168 169 n=$((n + 1)) 170 echo_i "testing incoming XoT functionality (from the first secondary, expired certificate, failure expected) ($n)" 171 ret=0 172 if retry_quiet 10 wait_for_tls_xfer 2 example8; then 173 ret=1 174 else 175 echo_i "timed out waiting for zone transfer" 176 fi 177 if [ $ret != 0 ]; then echo_i "failed"; fi 178 status=$((status + ret)) 179 180 n=$((n + 1)) 181 echo_i "testing incoming XoT functionality (from the first secondary, MutualTLS) ($n)" 182 ret=0 183 if retry_quiet 10 wait_for_tls_xfer 2 example9; then 184 retry_quiet 5 test -f "ns2/example9.db" || ret=1 185 else 186 echo_i "timed out waiting for zone transfer" 187 grep "^;" "dig.out.ns2.example9.test$n" | cat_i 188 ret=1 189 fi 190 if [ $ret != 0 ]; then echo_i "failed"; fi 191 status=$((status + ret)) 192 193 n=$((n + 1)) 194 echo_i "testing incoming XoT functionality (from the first secondary, MutualTLS, no client cert, failure expected) ($n)" 195 ret=0 196 if retry_quiet 10 wait_for_tls_xfer 2 example10; then 197 ret=1 198 else 199 echo_i "timed out waiting for zone transfer" 200 fi 201 if [ $ret != 0 ]; then echo_i "failed"; fi 202 status=$((status + ret)) 203 204 n=$((n + 1)) 205 echo_i "testing incoming XoT functionality (from the first secondary, MutualTLS, expired client cert, failure expected) ($n)" 206 ret=0 207 if retry_quiet 10 wait_for_tls_xfer 2 example11; then 208 ret=1 209 else 210 echo_i "timed out waiting for zone transfer" 211 fi 212 if [ $ret != 0 ]; then echo_i "failed"; fi 213 status=$((status + ret)) 214 215 n=$((n + 1)) 216 echo_i "testing incoming XoT functionality (from the second secondary) ($n)" 217 ret=0 218 if retry_quiet 10 wait_for_tls_xfer 3 example; then 219 digcomp example.axfr.good "dig.out.ns3.example.test$n" || ret=1 220 else 221 echo_i "timed out waiting for zone transfer" 222 grep "^;" "dig.out.ns3.example.test$n" | cat_i 223 ret=1 224 fi 225 if test $ret != 0; then echo_i "failed"; fi 226 status=$((status + ret)) 227 228 n=$((n + 1)) 229 echo_i "testing incoming XoT functionality (from the second secondary, mismatching ciphers, failure expected) ($n)" 230 ret=0 231 if retry_quiet 10 wait_for_tls_xfer 3 example2; then 232 ret=1 233 else 234 echo_i "timed out waiting for zone transfer" 235 fi 236 if test $ret != 0; then echo_i "failed"; fi 237 status=$((status + ret)) 238 239 n=$((n + 1)) 240 echo_i "testing incoming XoT functionality (from the third secondary) ($n)" 241 ret=0 242 if retry_quiet 10 wait_for_tls_xfer 4 example; then 243 digcomp example.axfr.good "dig.out.ns4.example.test$n" || ret=1 244 else 245 echo_i "timed out waiting for zone transfer" 246 grep "^;" "dig.out.ns4.example.test$n" | cat_i 247 ret=1 248 fi 249 if test $ret != 0; then echo_i "failed"; fi 250 status=$((status + ret)) 251 252 n=$((n + 1)) 253 echo_i "checking DoT query (ephemeral key) ($n)" 254 ret=0 255 dig_with_tls_opts @10.53.0.1 . SOA >dig.out.test$n || ret=1 256 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 257 if [ $ret != 0 ]; then echo_i "failed"; fi 258 status=$((status + ret)) 259 260 n=$((n + 1)) 261 echo_i "checking DoT query via IPv6 (ephemeral key) ($n)" 262 ret=0 263 dig_with_tls_opts -6 @fd92:7065:b8e:ffff::1 . SOA >dig.out.test$n || ret=1 264 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 265 if [ $ret != 0 ]; then echo_i "failed"; fi 266 status=$((status + ret)) 267 268 n=$((n + 1)) 269 echo_i "checking DoT query (static key) ($n)" 270 ret=0 271 dig_with_tls_opts @10.53.0.2 example SOA >dig.out.test$n || ret=1 272 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 273 if [ $ret != 0 ]; then echo_i "failed"; fi 274 status=$((status + ret)) 275 276 n=$((n + 1)) 277 echo_i "checking DoT query via IPv6 (static key) ($n)" 278 ret=0 279 dig_with_tls_opts -6 @fd92:7065:b8e:ffff::2 example SOA >dig.out.test$n || ret=1 280 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 281 if [ $ret != 0 ]; then echo_i "failed"; fi 282 status=$((status + ret)) 283 284 n=$((n + 1)) 285 echo_i "checking DoT XFR ($n)" 286 ret=0 287 dig_with_tls_opts +comm @10.53.0.1 . AXFR >dig.out.test$n || ret=1 288 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 289 if [ $ret != 0 ]; then echo_i "failed"; fi 290 status=$((status + ret)) 291 292 # zone transfers are allowed only via TLS 293 n=$((n + 1)) 294 echo_i "testing zone transfer over Do53 server functionality (using dig, failure expected) ($n)" 295 ret=0 296 dig_with_opts example. -b 10.53.0.10 @10.53.0.1 axfr >dig.out.ns1.test$n || ret=1 297 grep "; Transfer failed." dig.out.ns1.test$n >/dev/null || ret=1 298 if [ $ret != 0 ]; then echo_i "failed"; fi 299 status=$((status + ret)) 300 301 # querying zones is still allowed via UDP/TCP 302 n=$((n + 1)) 303 echo_i "checking Do53 query ($n)" 304 ret=0 305 dig_with_opts @10.53.0.1 example SOA >dig.out.test$n || ret=1 306 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 307 if [ $ret != 0 ]; then echo_i "failed"; fi 308 status=$((status + ret)) 309 310 # In this test we are trying to establish a DoT connection over the 311 # DoH port. That is intentional, as dig should fail right after 312 # handshake has happened and before sending any queries, as XFRs, per 313 # the RFC, could happen only over a connection where "dot" ALPN token 314 # was negotiated. over DoH it cannot happen, as only "h2" token could 315 # be selected for a DoH connection. 316 n=$((n + 1)) 317 echo_i "checking DoT XFR with wrong ALPN token (h2, failure expected) ($n)" 318 ret=0 319 # shellcheck disable=SC2086 320 "$DIG" +tls $common_dig_options -p "${HTTPSPORT}" +comm @10.53.0.1 . AXFR >dig.out.test$n 321 grep "$msg_xfrs_not_allowed" dig.out.test$n >/dev/null || ret=1 322 if [ $ret != 0 ]; then echo_i "failed"; fi 323 status=$((status + ret)) 324 325 # Let's try to issue an HTTP/2 query over TLS port to check if dig 326 # will detect ALPN token negotiation problem. 327 n=$((n + 1)) 328 echo_i "checking DoH query when ALPN is expected to fail (dot, failure expected) ($n)" 329 ret=0 330 # shellcheck disable=SC2086 331 "$DIG" +https $common_dig_options -p "${TLSPORT}" "$@" @10.53.0.1 . SOA >dig.out.test$n && ret=1 332 grep "ALPN for HTTP/2 failed." dig.out.test$n >/dev/null || ret=1 333 if [ $ret != 0 ]; then echo_i "failed"; fi 334 status=$((status + ret)) 335 336 n=$((n + 1)) 337 echo_i "checking DoH query (POST) ($n)" 338 ret=0 339 dig_with_https_opts +stat @10.53.0.1 . SOA >dig.out.test$n || ret=1 340 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 341 grep -F "(HTTPS)" dig.out.test$n >/dev/null || ret=1 342 if [ $ret != 0 ]; then echo_i "failed"; fi 343 status=$((status + ret)) 344 345 n=$((n + 1)) 346 echo_i "checking DoH query via IPv6 (POST) ($n)" 347 ret=0 348 dig_with_https_opts +stat -6 @fd92:7065:b8e:ffff::1 . SOA >dig.out.test$n || ret=1 349 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 350 grep -F "(HTTPS)" dig.out.test$n >/dev/null || ret=1 351 if [ $ret != 0 ]; then echo_i "failed"; fi 352 status=$((status + ret)) 353 354 n=$((n + 1)) 355 echo_i "checking DoH query (POST, static key) ($n)" 356 ret=0 357 dig_with_https_opts @10.53.0.2 example SOA >dig.out.test$n || ret=1 358 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 359 if [ $ret != 0 ]; then echo_i "failed"; fi 360 status=$((status + ret)) 361 362 n=$((n + 1)) 363 echo_i "checking DoH query via IPv6 (POST, static key) ($n)" 364 ret=0 365 dig_with_https_opts -6 @fd92:7065:b8e:ffff::2 example SOA >dig.out.test$n || ret=1 366 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 367 if [ $ret != 0 ]; then echo_i "failed"; fi 368 status=$((status + ret)) 369 370 n=$((n + 1)) 371 echo_i "checking DoH query (POST, nonstandard endpoint) ($n)" 372 ret=0 373 dig_with_https_opts +https=/alter @10.53.0.1 . SOA >dig.out.test$n || ret=1 374 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 375 if [ $ret != 0 ]; then echo_i "failed"; fi 376 status=$((status + ret)) 377 378 n=$((n + 1)) 379 echo_i "checking DoH query via IPv6 (POST, nonstandard endpoint) ($n)" 380 ret=0 381 dig_with_https_opts -6 +https=/alter @fd92:7065:b8e:ffff::1 . SOA >dig.out.test$n || ret=1 382 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 383 if [ $ret != 0 ]; then echo_i "failed"; fi 384 status=$((status + ret)) 385 386 n=$((n + 1)) 387 echo_i "checking DoH query (POST, undefined endpoint, failure expected) ($n)" 388 ret=0 389 dig_with_https_opts +tries=1 +time=1 +https=/fake @10.53.0.1 . SOA >dig.out.test$n && ret=1 390 grep "communications error" dig.out.test$n >/dev/null || ret=1 391 if [ $ret != 0 ]; then echo_i "failed"; fi 392 status=$((status + ret)) 393 394 n=$((n + 1)) 395 echo_i "checking DoH query via IPv6 (POST, undefined endpoint, failure expected) ($n)" 396 ret=0 397 dig_with_https_opts -6 +tries=1 +time=1 +https=/fake @fd92:7065:b8e:ffff::1 . SOA >dig.out.test$n && ret=1 398 grep "communications error" dig.out.test$n >/dev/null || ret=1 399 if [ $ret != 0 ]; then echo_i "failed"; fi 400 status=$((status + ret)) 401 402 n=$((n + 1)) 403 echo_i "checking DoH XFR (POST) (failure expected) ($n)" 404 ret=0 405 dig_with_https_opts +comm @10.53.0.1 . AXFR >dig.out.test$n || ret=1 406 grep "; Transfer failed." dig.out.test$n >/dev/null || ret=1 407 if [ $ret != 0 ]; then echo_i "failed"; fi 408 status=$((status + ret)) 409 410 n=$((n + 1)) 411 echo_i "checking DoH query (GET) ($n)" 412 ret=0 413 dig_with_https_opts +stat +https-get @10.53.0.1 . SOA >dig.out.test$n || ret=1 414 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 415 grep -F "(HTTPS-GET)" dig.out.test$n >/dev/null || ret=1 416 if [ $ret != 0 ]; then echo_i "failed"; fi 417 status=$((status + ret)) 418 419 n=$((n + 1)) 420 echo_i "checking DoH query via IPv6 (GET) ($n)" 421 ret=0 422 dig_with_https_opts -6 +stat +https-get @fd92:7065:b8e:ffff::1 . SOA >dig.out.test$n || ret=1 423 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 424 grep -F "(HTTPS-GET)" dig.out.test$n >/dev/null || ret=1 425 if [ $ret != 0 ]; then echo_i "failed"; fi 426 status=$((status + ret)) 427 428 n=$((n + 1)) 429 echo_i "checking DoH query (GET, static key) ($n)" 430 ret=0 431 dig_with_https_opts +https-get @10.53.0.2 example SOA >dig.out.test$n || ret=1 432 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 433 if [ $ret != 0 ]; then echo_i "failed"; fi 434 status=$((status + ret)) 435 436 n=$((n + 1)) 437 echo_i "checking DoH query via IPv6 (GET, static key) ($n)" 438 ret=0 439 dig_with_https_opts -6 +https-get @fd92:7065:b8e:ffff::2 example SOA >dig.out.test$n || ret=1 440 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 441 if [ $ret != 0 ]; then echo_i "failed"; fi 442 status=$((status + ret)) 443 444 n=$((n + 1)) 445 echo_i "checking DoH query (GET, nonstandard endpoint) ($n)" 446 ret=0 447 dig_with_https_opts +https-get=/alter @10.53.0.1 . SOA >dig.out.test$n || ret=1 448 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 449 if [ $ret != 0 ]; then echo_i "failed"; fi 450 status=$((status + ret)) 451 452 n=$((n + 1)) 453 echo_i "checking DoH query via IPv6 (GET, nonstandard endpoint) ($n)" 454 ret=0 455 dig_with_https_opts -6 +https-get=/alter @fd92:7065:b8e:ffff::1 . SOA >dig.out.test$n || ret=1 456 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 457 if [ $ret != 0 ]; then echo_i "failed"; fi 458 status=$((status + ret)) 459 460 n=$((n + 1)) 461 echo_i "checking DoH query (GET, undefined endpoint, failure expected) ($n)" 462 ret=0 463 dig_with_https_opts +tries=1 +time=1 +https-get=/fake @10.53.0.1 . SOA >dig.out.test$n && ret=1 464 grep "communications error" dig.out.test$n >/dev/null || ret=1 465 if [ $ret != 0 ]; then echo_i "failed"; fi 466 status=$((status + ret)) 467 468 n=$((n + 1)) 469 echo_i "checking DoH query via IPv6 (GET, undefined endpoint, failure expected) ($n)" 470 ret=0 471 dig_with_https_opts -6 +tries=1 +time=1 +https-get=/fake @fd92:7065:b8e:ffff::1 . SOA >dig.out.test$n && ret=1 472 grep "communications error" dig.out.test$n >/dev/null || ret=1 473 if [ $ret != 0 ]; then echo_i "failed"; fi 474 status=$((status + ret)) 475 476 n=$((n + 1)) 477 echo_i "checking DoH XFR (GET) (failure expected) ($n)" 478 ret=0 479 dig_with_https_opts +https-get +comm @10.53.0.1 . AXFR >dig.out.test$n || ret=1 480 grep "; Transfer failed." dig.out.test$n >/dev/null || ret=1 481 if [ $ret != 0 ]; then echo_i "failed"; fi 482 status=$((status + ret)) 483 484 n=$((n + 1)) 485 echo_i "checking unencrypted DoH query (POST) ($n)" 486 ret=0 487 dig_with_http_opts +stat @10.53.0.1 . SOA >dig.out.test$n || ret=1 488 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 489 grep -F "(HTTP)" dig.out.test$n >/dev/null || ret=1 490 if [ $ret != 0 ]; then echo_i "failed"; fi 491 status=$((status + ret)) 492 493 n=$((n + 1)) 494 echo_i "checking unencrypted DoH query via IPv6 (POST) ($n)" 495 ret=0 496 dig_with_http_opts -6 +stat @fd92:7065:b8e:ffff::1 . SOA >dig.out.test$n || ret=1 497 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 498 grep -F "(HTTP)" dig.out.test$n >/dev/null || ret=1 499 if [ $ret != 0 ]; then echo_i "failed"; fi 500 status=$((status + ret)) 501 502 n=$((n + 1)) 503 echo_i "checking unencrypted DoH query (GET) ($n)" 504 ret=0 505 dig_with_http_opts +stat +http-plain-get @10.53.0.1 . SOA >dig.out.test$n || ret=1 506 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 507 grep -F "(HTTP-GET)" dig.out.test$n >/dev/null || ret=1 508 if [ $ret != 0 ]; then echo_i "failed"; fi 509 status=$((status + ret)) 510 511 n=$((n + 1)) 512 echo_i "checking unencrypted DoH query via IPv6 (GET) ($n)" 513 ret=0 514 dig_with_http_opts -6 +stat +http-plain-get @fd92:7065:b8e:ffff::1 . SOA >dig.out.test$n || ret=1 515 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 516 grep -F "(HTTP-GET)" dig.out.test$n >/dev/null || ret=1 517 if [ $ret != 0 ]; then echo_i "failed"; fi 518 status=$((status + ret)) 519 520 n=$((n + 1)) 521 echo_i "checking unencrypted DoH XFR (failure expected) ($n)" 522 ret=0 523 dig_with_http_opts +comm @10.53.0.1 . AXFR >dig.out.test$n || ret=1 524 grep "; Transfer failed." dig.out.test$n >/dev/null || ret=1 525 if [ $ret != 0 ]; then echo_i "failed"; fi 526 status=$((status + ret)) 527 528 n=$((n + 1)) 529 echo_i "checking DoH query for a large answer (POST) ($n)" 530 ret=0 531 dig_with_https_opts @10.53.0.1 biganswer.example A >dig.out.test$n || ret=1 532 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 533 grep "ANSWER: 2500" dig.out.test$n >/dev/null || ret=1 534 if [ $ret != 0 ]; then echo_i "failed"; fi 535 status=$((status + ret)) 536 537 n=$((n + 1)) 538 echo_i "checking DoH query via IPv6 for a large answer (POST) ($n)" 539 ret=0 540 dig_with_https_opts -6 @fd92:7065:b8e:ffff::1 biganswer.example A >dig.out.test$n || ret=1 541 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 542 grep "ANSWER: 2500" dig.out.test$n >/dev/null || ret=1 543 if [ $ret != 0 ]; then echo_i "failed"; fi 544 status=$((status + ret)) 545 546 n=$((n + 1)) 547 echo_i "checking DoH query for a large answer (GET) ($n)" 548 ret=0 549 dig_with_https_opts +https-get @10.53.0.1 biganswer.example A >dig.out.test$n || ret=1 550 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 551 grep "ANSWER: 2500" dig.out.test$n >/dev/null || ret=1 552 if [ $ret != 0 ]; then echo_i "failed"; fi 553 status=$((status + ret)) 554 555 n=$((n + 1)) 556 echo_i "checking DoH query via IPv6 for a large answer (GET) ($n)" 557 ret=0 558 dig_with_https_opts -6 +https-get @fd92:7065:b8e:ffff::1 biganswer.example A >dig.out.test$n || ret=1 559 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 560 grep "ANSWER: 2500" dig.out.test$n >/dev/null || ret=1 561 if [ $ret != 0 ]; then echo_i "failed"; fi 562 status=$((status + ret)) 563 564 n=$((n + 1)) 565 echo_i "checking unencrypted DoH query for a large answer (POST) ($n)" 566 ret=0 567 dig_with_http_opts @10.53.0.1 biganswer.example A >dig.out.test$n || ret=1 568 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 569 grep "ANSWER: 2500" dig.out.test$n >/dev/null || ret=1 570 if [ $ret != 0 ]; then echo_i "failed"; fi 571 status=$((status + ret)) 572 573 n=$((n + 1)) 574 echo_i "checking unencrypted DoH query via IPv6 for a large answer (POST) ($n)" 575 ret=0 576 dig_with_http_opts -6 @fd92:7065:b8e:ffff::1 biganswer.example A >dig.out.test$n || ret=1 577 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 578 grep "ANSWER: 2500" dig.out.test$n >/dev/null || ret=1 579 if [ $ret != 0 ]; then echo_i "failed"; fi 580 status=$((status + ret)) 581 582 n=$((n + 1)) 583 echo_i "checking unencrypted DoH query for a large answer (GET) ($n)" 584 ret=0 585 dig_with_http_opts +http-plain-get @10.53.0.1 biganswer.example A >dig.out.test$n || ret=1 586 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 587 grep "ANSWER: 2500" dig.out.test$n >/dev/null || ret=1 588 if [ $ret != 0 ]; then echo_i "failed"; fi 589 status=$((status + ret)) 590 591 n=$((n + 1)) 592 echo_i "checking unencrypted DoH query via IPv6 for a large answer (GET) ($n)" 593 ret=0 594 dig_with_http_opts -6 +http-plain-get @fd92:7065:b8e:ffff::1 biganswer.example A >dig.out.test$n || ret=1 595 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 596 grep "ANSWER: 2500" dig.out.test$n >/dev/null || ret=1 597 if [ $ret != 0 ]; then echo_i "failed"; fi 598 status=$((status + ret)) 599 600 wait_for_tlsctx_update_ns4() { 601 grep "updating TLS context on 10.53.0.4#${HTTPSPORT}" ns4/named.run >/dev/null || return 1 602 grep "updating TLS context on 10.53.0.4#${TLSPORT}" ns4/named.run >/dev/null || return 1 603 return 0 604 } 605 606 n=$((n + 1)) 607 echo_i "doing rndc reconfig to see that queries keep being served after that ($n)" 608 ret=0 609 rndc_reconfig ns4 10.53.0.4 60 610 retry_quiet 15 wait_for_tlsctx_update_ns4 || ret=1 611 if [ $ret != 0 ]; then echo_i "failed"; fi 612 status=$((status + ret)) 613 614 n=$((n + 1)) 615 echo_i "checking DoT query after a reconfiguration ($n)" 616 ret=0 617 dig_with_tls_opts @10.53.0.4 example SOA >dig.out.test$n || ret=1 618 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 619 if [ $ret != 0 ]; then echo_i "failed"; fi 620 status=$((status + ret)) 621 622 n=$((n + 1)) 623 echo_i "checking DoH query (POST) after a reconfiguration ($n)" 624 ret=0 625 dig_with_https_opts @10.53.0.4 example SOA >dig.out.test$n || ret=1 626 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 627 if [ $ret != 0 ]; then echo_i "failed"; fi 628 status=$((status + ret)) 629 630 n=$((n + 1)) 631 echo_i "doing rndc reconfig to see if HTTP endpoints have gotten reconfigured ($n)" 632 ret=0 633 # 'sed -i ...' is not portable. Sigh... 634 sed 's/\/dns-query/\/dns-query-test/g' "ns4/named.conf" >"ns4/named.conf.sed" 635 mv -f "ns4/named.conf.sed" "ns4/named.conf" 636 rndc_reconfig ns4 10.53.0.4 60 637 retry_quiet 15 wait_for_tlsctx_update_ns4 || ret=1 638 if [ $ret != 0 ]; then echo_i "failed"; fi 639 status=$((status + ret)) 640 641 n=$((n + 1)) 642 echo_i "checking DoH query (POST) to verify HTTP endpoint reconfiguration ($n)" 643 ret=0 644 dig_with_https_opts +https='/dns-query-test' @10.53.0.4 example SOA >dig.out.test$n || ret=1 645 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 646 if [ $ret != 0 ]; then echo_i "failed"; fi 647 status=$((status + ret)) 648 649 n=$((n + 1)) 650 echo_i "checking DoT query (with TLS verification enabled) ($n)" 651 ret=0 652 dig_with_tls_opts +tls-ca="$ca_file" +tls-hostname="srv01.crt01.example.com" @10.53.0.1 . SOA >dig.out.test$n || ret=1 653 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 654 if [ $ret != 0 ]; then echo_i "failed"; fi 655 status=$((status + ret)) 656 657 n=$((n + 1)) 658 echo_i "checking DoH query (with TLS verification enabled, self-signed cert, failure expected) ($n)" 659 ret=0 660 dig_with_https_opts +tls-ca="$ca_file" +tls-hostname="srv01.crt01.example.com" @10.53.0.1 . SOA >dig.out.test$n || ret=1 661 grep "$msg_peer_verification_failed" dig.out.test$n >/dev/null || ret=1 662 if [ $ret != 0 ]; then echo_i "failed"; fi 663 status=$((status + ret)) 664 665 n=$((n + 1)) 666 echo_i "checking DoT query (with TLS verification using the system's CA store, failure expected) ($n)" 667 ret=0 668 dig_with_tls_opts +tls-ca +tls-hostname="srv01.crt01.example.com" @10.53.0.1 . SOA >dig.out.test$n || ret=1 669 grep "$msg_peer_verification_failed" dig.out.test$n >/dev/null || ret=1 670 if [ $ret != 0 ]; then echo_i "failed"; fi 671 status=$((status + ret)) 672 673 n=$((n + 1)) 674 echo_i "checking DoH query (with TLS verification using the system's CA store, failure expected) ($n)" 675 ret=0 676 dig_with_https_opts +tls-ca +tls-hostname="srv01.crt01.example.com" @10.53.0.1 . SOA >dig.out.test$n || ret=1 677 grep "$msg_peer_verification_failed" dig.out.test$n >/dev/null || ret=1 678 if [ $ret != 0 ]; then echo_i "failed"; fi 679 status=$((status + ret)) 680 681 # the primary server's certificate contains the IP address in the 682 # SubjectAltName section 683 n=$((n + 1)) 684 echo_i "checking DoT query (with TLS verification, hostname is not specified, IP address is used instead) ($n)" 685 ret=0 686 dig_with_tls_opts +tls-ca="$ca_file" @10.53.0.1 . SOA >dig.out.test$n || ret=1 687 grep "$msg_peer_verification_failed" dig.out.test$n >/dev/null && ret=1 688 if [ $ret != 0 ]; then echo_i "failed"; fi 689 status=$((status + ret)) 690 691 if [ -n "$run_san_tests" ]; then 692 # SubjectAltName is required for DoT as according to RFC 8310, Subject 693 # field MUST NOT be inspected when verifying hostname for DoT. 694 n=$((n + 1)) 695 echo_i "checking DoT query (with TLS verification enabled when SubjectAltName is not set, failure expected) ($n)" 696 ret=0 697 dig_with_tls_opts +tls-ca="$ca_file" +tls-hostname="srv01.crt02-no-san.example.com" @10.53.0.1 . SOA >dig.out.test$n || ret=1 698 grep "$msg_peer_verification_failed" dig.out.test$n >/dev/null || ret=1 699 if [ $ret != 0 ]; then echo_i "failed"; fi 700 status=$((status + ret)) 701 702 n=$((n + 1)) 703 echo_i "checking DoT XFR over a TLS port where SubjectAltName is not set (failure expected) ($n)" 704 ret=0 705 # shellcheck disable=SC2086 706 dig_with_tls_opts +tls-ca="$ca_file" +tls-hostname="srv01.crt02-no-san.example.com" -p "${EXTRAPORT2}" +comm @10.53.0.1 . AXFR >dig.out.test$n || ret=1 707 grep "$msg_peer_verification_failed" dig.out.test$n >/dev/null || ret=1 708 if [ $ret != 0 ]; then echo_i "failed"; fi 709 status=$((status + ret)) 710 fi 711 712 # SubjectAltName is not required for HTTPS. Having a properly set 713 # Common Name in the Subject field is enough. 714 n=$((n + 1)) 715 echo_i "checking DoH query (when SubjectAltName is not set) ($n)" 716 ret=0 717 dig_with_https_opts +tls-ca="$ca_file" +tls-hostname="srv01.crt02-no-san.example.com" -p "${EXTRAPORT3}" +comm @10.53.0.1 . SOA >dig.out.test$n || ret=1 718 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 719 if [ $ret != 0 ]; then echo_i "failed"; fi 720 status=$((status + ret)) 721 722 n=$((n + 1)) 723 echo_i "checking DoT query (expired certificate, Opportunistic TLS) ($n)" 724 ret=0 725 dig_with_tls_opts +tls -p "${EXTRAPORT4}" +comm @10.53.0.1 . SOA >dig.out.test$n || ret=1 726 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 727 if [ $ret != 0 ]; then echo_i "failed"; fi 728 status=$((status + ret)) 729 730 n=$((n + 1)) 731 echo_i "checking DoT query (expired certificate, Strict TLS, failure expected) ($n)" 732 ret=0 733 dig_with_tls_opts +tls-ca="$ca_file" -p "${EXTRAPORT4}" +comm @10.53.0.1 . SOA >dig.out.test$n || ret=1 734 grep "$msg_peer_verification_failed" dig.out.test$n >/dev/null || ret=1 735 if [ $ret != 0 ]; then echo_i "failed"; fi 736 status=$((status + ret)) 737 738 n=$((n + 1)) 739 echo_i "testing XoT server functionality (using dig, client certificate required, failure expected) ($n)" 740 ret=0 741 dig_with_tls_opts +tls-ca="$ca_file" -p "${EXTRAPORT5}" example8. -b 10.53.0.10 @10.53.0.1 axfr >dig.out.ns1.test$n || ret=1 742 grep "; Transfer failed." dig.out.ns1.test$n >/dev/null || ret=1 743 if test $ret != 0; then echo_i "failed"; fi 744 status=$((status + ret)) 745 746 n=$((n + 1)) 747 echo_i "testing XoT server functionality (using dig, client certificate used) ($n)" 748 ret=0 749 dig_with_tls_opts +tls-ca="$ca_file" +tls-certfile="./CA/certs/srv01.client01.example.com.pem" +tls-keyfile="./CA/certs/srv01.client01.example.com.key" -p "${EXTRAPORT5}" example8. -b 10.53.0.10 @10.53.0.1 axfr >dig.out.ns1.test$n || ret=1 750 digcomp dig.out.ns1.test$n example8.axfr.good >/dev/null || ret=1 751 if test $ret != 0; then echo_i "failed"; fi 752 status=$((status + ret)) 753 754 n=$((n + 1)) 755 echo_i "checking DoH query (client certificate required, failure expected) ($n)" 756 ret=0 757 dig_with_https_opts +tls-ca="$ca_file" -p "${EXTRAPORT6}" +comm @10.53.0.1 . SOA >dig.out.test$n && ret=1 758 grep "status: NOERROR" dig.out.test$n >/dev/null && ret=1 759 if [ $ret != 0 ]; then echo_i "failed"; fi 760 status=$((status + ret)) 761 762 n=$((n + 1)) 763 echo_i "checking DoH query (client certificate used) ($n)" 764 ret=0 765 # shellcheck disable=SC2086 766 dig_with_https_opts +https +tls-ca="$ca_file" +tls-certfile="./CA/certs/srv01.client01.example.com.pem" +tls-keyfile="./CA/certs/srv01.client01.example.com.key" -p "${EXTRAPORT6}" +comm @10.53.0.1 . SOA >dig.out.test$n || ret=1 767 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 768 if [ $ret != 0 ]; then echo_i "failed"; fi 769 status=$((status + ret)) 770 771 # send two requests one after another so that session resumption will happen 772 n=$((n + 1)) 773 echo_i "checking DoH query (client certificate used - session resumption when using Mutual TLS) ($n)" 774 ret=0 775 # shellcheck disable=SC2086 776 dig_with_https_opts +https +tls-ca="$ca_file" +tls-certfile="./CA/certs/srv01.client01.example.com.pem" +tls-keyfile="./CA/certs/srv01.client01.example.com.key" -p "${EXTRAPORT6}" +comm @10.53.0.1 . SOA . SOA >dig.out.test$n || ret=1 777 grep "TLS error" dig.out.test$n >/dev/null && ret=1 778 if [ $ret != 0 ]; then echo_i "failed"; fi 779 status=$((status + ret)) 780 781 test_opcodes() { 782 EXPECT_STATUS="$1" 783 shift 784 for op in "$@"; do 785 n=$((n + 1)) 786 echo_i "checking unexpected opcode query over DoH for opcode $op ($n)" 787 ret=0 788 dig_with_https_opts +https @10.53.0.1 +opcode="$op" >dig.out.test$n || ret=1 789 grep "status: $EXPECT_STATUS" dig.out.test$n >/dev/null || ret=1 790 if [ $ret != 0 ]; then echo_i "failed"; fi 791 status=$((status + ret)) 792 793 n=$((n + 1)) 794 echo_i "checking unexpected opcode query over DoH via IPv6 for opcode $op ($n)" 795 ret=0 796 dig_with_https_opts -6 +https @fd92:7065:b8e:ffff::1 +opcode="$op" >dig.out.test$n || ret=1 797 grep "status: $EXPECT_STATUS" dig.out.test$n >/dev/null || ret=1 798 if [ $ret != 0 ]; then echo_i "failed"; fi 799 status=$((status + ret)) 800 801 n=$((n + 1)) 802 echo_i "checking unexpected opcode query over DoH without encryption for opcode $op ($n)" 803 ret=0 804 dig_with_http_opts +http-plain @10.53.0.1 +opcode="$op" >dig.out.test$n || ret=1 805 grep "status: $EXPECT_STATUS" dig.out.test$n >/dev/null || ret=1 806 if [ $ret != 0 ]; then echo_i "failed"; fi 807 status=$((status + ret)) 808 809 n=$((n + 1)) 810 echo_i "checking unexpected opcode query over DoH via IPv6 without encryption for opcode $op ($n)" 811 ret=0 812 dig_with_http_opts -6 +http-plain @fd92:7065:b8e:ffff::1 +opcode="$op" >dig.out.test$n || ret=1 813 grep "status: $EXPECT_STATUS" dig.out.test$n >/dev/null || ret=1 814 if [ $ret != 0 ]; then echo_i "failed"; fi 815 status=$((status + ret)) 816 817 n=$((n + 1)) 818 echo_i "checking unexpected opcode query over DoT for opcode $op ($n)" 819 ret=0 820 dig_with_tls_opts +tls @10.53.0.1 +opcode="$op" >dig.out.test$n || ret=1 821 grep "status: $EXPECT_STATUS" dig.out.test$n >/dev/null || ret=1 822 if [ $ret != 0 ]; then echo_i "failed"; fi 823 status=$((status + ret)) 824 825 n=$((n + 1)) 826 echo_i "checking unexpected opcode query over DoT via IPv6 for opcode $op ($n)" 827 ret=0 828 dig_with_tls_opts -6 +tls @fd92:7065:b8e:ffff::1 +opcode="$op" >dig.out.test$n || ret=1 829 grep "status: $EXPECT_STATUS" dig.out.test$n >/dev/null || ret=1 830 if [ $ret != 0 ]; then echo_i "failed"; fi 831 status=$((status + ret)) 832 done 833 } 834 835 test_opcodes NOERROR 0 836 test_opcodes NOTIMP 1 2 3 6 7 8 9 10 11 12 13 14 15 837 test_opcodes FORMERR 4 5 838 839 n=$((n + 1)) 840 echo_i "checking server quotas for both encrypted and unencrypted HTTP ($n)" 841 ret=0 842 BINDHOST="10.53.0.1" "$PYTHON" "$TOP_SRCDIR/bin/tests/system/doth/stress_http_quota.py" || ret=$? 843 if [ $ret != 0 ]; then echo_i "failed"; fi 844 status=$((status + ret)) 845 846 # check whether we can use curl for sending test queries. 847 if [ -x "${CURL}" ]; then 848 CURL_HTTP2="$(${CURL} --version | grep -E '^Features:.* HTTP2( |$)' || true)" 849 850 if [ -n "$CURL_HTTP2" ]; then 851 testcurl=1 852 else 853 echo_i "The available version of CURL does not have HTTP/2 support" 854 fi 855 fi 856 857 # Note: see README.curl for information on how to generate curl 858 # queries. 859 if [ -n "$testcurl" ]; then 860 n=$((n + 1)) 861 echo_i "checking max-age for positive answer ($n)" 862 ret=0 863 # use curl to query for 'example/SOA' 864 $CURL -kD headers.$n "https://10.53.0.1:${HTTPSPORT}/dns-query?dns=AAEAAAABAAAAAAAAB2V4YW1wbGUAAAYAAQ" >/dev/null 2>&1 || ret=1 865 grep "cache-control: max-age=86400" headers.$n >/dev/null || ret=1 866 if [ $ret != 0 ]; then echo_i "failed"; fi 867 status=$((status + ret)) 868 869 n=$((n + 1)) 870 echo_i "checking max-age for negative answer ($n)" 871 ret=0 872 # use curl to query for 'fake.example/TXT' 873 $CURL -kD headers.$n "https://10.53.0.1:${HTTPSPORT}/dns-query?dns=AAEAAAABAAAAAAAABGZha2UHZXhhbXBsZQAAEAAB" >/dev/null 2>&1 || ret=1 874 grep "cache-control: max-age=3600" headers.$n >/dev/null || ret=1 875 if [ $ret != 0 ]; then echo_i "failed"; fi 876 status=$((status + ret)) 877 fi 878 879 n=$((n + 1)) 880 echo_i "checking Do53 query to NS5 for zone \"example12\" (verifying successful client TLS context reuse by the NS5 server instance during XoT) ($n)" 881 ret=0 882 dig_with_opts +comm @10.53.0.5 example12 SOA >dig.out.test$n || ret=1 883 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 884 if [ $ret != 0 ]; then echo_i "failed"; fi 885 status=$((status + ret)) 886 887 n=$((n + 1)) 888 echo_i "checking Do53 query to NS5 for zone \"example13\" (verifying successful client TLS context reuse by the NS5 server instance during XoT) ($n)" 889 ret=0 890 dig_with_opts +comm @10.53.0.5 example13 SOA >dig.out.test$n || ret=1 891 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 892 if [ $ret != 0 ]; then echo_i "failed"; fi 893 status=$((status + ret)) 894 895 n=$((n + 1)) 896 echo_i "checking Do53 query to NS5 for zone \"example14\" (verifying successful client TLS context reuse by the NS5 server instance during XoT) ($n)" 897 ret=0 898 dig_with_opts +comm @10.53.0.5 example14 SOA >dig.out.test$n || ret=1 899 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 900 if [ $ret != 0 ]; then echo_i "failed"; fi 901 status=$((status + ret)) 902 903 n=$((n + 1)) 904 echo_i "checking Do53 query to NS5 for zone \"example15\" (verifying successful client TLS context reuse by the NS5 server instance during XoT) ($n)" 905 ret=0 906 dig_with_opts +comm @10.53.0.5 example15 SOA >dig.out.test$n || ret=1 907 grep "status: NOERROR" dig.out.test$n >/dev/null || ret=1 908 if [ $ret != 0 ]; then echo_i "failed"; fi 909 status=$((status + ret)) 910 911 # see GL #4572 912 n=$((n + 1)) 913 echo_i "testing that zone forwarding fails when using a wrong TLS configuration on the server without aborting it (a condition for bug #4572, failure expected) ($n)" 914 ret=0 915 dig_with_opts test.example.com. -b 10.53.0.10 @10.53.0.2 >dig.out.test$n || ret=1 916 grep "status: SERVFAIL" dig.out.test$n >/dev/null || ret=1 917 if test $ret != 0; then echo_i "failed"; fi 918 status=$((status + ret)) 919 920 echo_i "exit status: $status" 921 [ $status -eq 0 ] || exit 1 922