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