From 8cd3b9ef6672a86364553e5ab35744d87d0842fd Mon Sep 17 00:00:00 2001 From: Artem Boldariev Date: Thu, 2 Sep 2021 15:39:50 +0300 Subject: [PATCH] Do not allow zone transfers in dig over TLS without ALPN This commit makes dig fail with error in case a zone transfer is attempted over a connections where ALPN was not negotiated. All other request types will work fine. --- bin/dig/dighost.c | 20 ++++++++++++++++++++ bin/tests/system/doth/tests.sh | 27 ++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index c40a1992f7..2397ac7c81 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -3121,6 +3121,7 @@ launch_next_query(dig_query_t *query) { int local_timeout = timeout * 1000; dig_lookup_t *l = NULL; isc_region_t r; + bool xfr; REQUIRE(DIG_VALID_QUERY(query)); INSIST(!free_now); @@ -3149,6 +3150,25 @@ launch_next_query(dig_query_t *query) { isc_nmhandle_settimeout(query->handle, local_timeout); query_attach(query, &readquery); + + xfr = query->lookup->rdtype == dns_rdatatype_ixfr || + query->lookup->rdtype == dns_rdatatype_axfr; + if (xfr && isc_nm_is_tlsdns_handle(query->handle) && + !isc_nm_xfr_allowed(query->handle)) + { + dighost_error("zone transfers over the " + "established TLS connection are not allowed"); + dighost_error("as the " + "connection does not meet the requirements " + "enforced by the RFC 9103"); + isc_refcount_decrement0(&recvcount); + isc_nmhandle_detach(&query->readhandle); + cancel_lookup(l); + lookup_detach(&l); + clear_current_lookup(); + return; + } + isc_nm_read(query->handle, recv_done, readquery); if (!query->first_soa_rcvd) { diff --git a/bin/tests/system/doth/tests.sh b/bin/tests/system/doth/tests.sh index 39ed8571f5..00ef08c771 100644 --- a/bin/tests/system/doth/tests.sh +++ b/bin/tests/system/doth/tests.sh @@ -12,16 +12,22 @@ # shellcheck disable=SC1091 . ../conf.sh +common_dig_options="+noadd +nosea +nostat +noquest +nocmd" +msg_xfrs_not_allowed=";; zone transfers over the established TLS connection are not allowed" + dig_with_tls_opts() { - "$DIG" +tls +noadd +nosea +nostat +noquest +nocmd -p "${TLSPORT}" "$@" + # shellcheck disable=SC2086 + "$DIG" +tls $common_dig_options -p "${TLSPORT}" "$@" } dig_with_https_opts() { - "$DIG" +https +noadd +nosea +nostat +noquest +nocmd -p "${HTTPSPORT}" "$@" + # shellcheck disable=SC2086 + "$DIG" +https $common_dig_options -p "${HTTPSPORT}" "$@" } dig_with_http_opts() { - "$DIG" +http-plain +noadd +nosea +nostat +noquest +nocmd -p "${HTTPPORT}" "$@" + # shellcheck disable=SC2086 + "$DIG" +http-plain $common_dig_options -p "${HTTPPORT}" "$@" } wait_for_tls_xfer() ( @@ -95,6 +101,21 @@ grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=$((status + ret)) +# In this test we are trying to establish a DoT connection over the +# DoH port. That is intentional, as dig should fail right after +# handshake has happened and before sending any queries, as XFRs, per +# the RFC, could happen only over a connection where "dot" ALPN token +# was negotiated. over DoH it cannot happen, as only "h2" token could +# be selected for a DoH connection. +n=$((n + 1)) +echo_i "checking DoT XFR with wrong ALPN token (h2, failure expected) ($n)" +ret=0 +# shellcheck disable=SC2086 +"$DIG" +tls $common_dig_options -p "${HTTPSPORT}" +comm @10.53.0.1 . AXFR > dig.out.test$n +grep "$msg_xfrs_not_allowed" dig.out.test$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=$((status + ret)) + n=$((n + 1)) echo_i "checking DoH query (POST) ($n)" ret=0