diff --git a/bin/tests/system/dispatch/ans4/ans.py b/bin/tests/system/dispatch/ans4/ans.py new file mode 100644 index 0000000000..5ec4985a7b --- /dev/null +++ b/bin/tests/system/dispatch/ans4/ans.py @@ -0,0 +1,42 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +from collections.abc import AsyncGenerator + +from isctest.asyncserver import ( + AsyncDnsServer, + DnsProtocol, + DnsResponseSend, + QueryContext, + ResponseAction, + ResponseDrop, + ResponseHandler, +) + + +class TcpOnlyHandler(ResponseHandler): + async def get_responses( + self, qctx: QueryContext + ) -> AsyncGenerator[ResponseAction, None]: + if qctx.protocol == DnsProtocol.TCP: + yield DnsResponseSend(qctx.response) + else: + yield ResponseDrop() + + +def main() -> None: + server = AsyncDnsServer() + server.install_response_handler(TcpOnlyHandler()) + server.run() + + +if __name__ == "__main__": + main() diff --git a/bin/tests/system/dispatch/ans4/tcp-only.db b/bin/tests/system/dispatch/ans4/tcp-only.db new file mode 100644 index 0000000000..1f95670a4b --- /dev/null +++ b/bin/tests/system/dispatch/ans4/tcp-only.db @@ -0,0 +1,15 @@ +; Copyright (C) Internet Systems Consortium, Inc. ("ISC") +; +; SPDX-License-Identifier: MPL-2.0 +; +; This Source Code Form is subject to the terms of the Mozilla Public +; License, v. 2.0. If a copy of the MPL was not distributed with this +; file, you can obtain one at https://mozilla.org/MPL/2.0/. +; +; See the COPYRIGHT file distributed with this work for additional +; information regarding copyright ownership. + +@ 3600 SOA . . 1 1 1 1 1 +@ 3600 NS ns +ns 3600 A 10.53.0.4 +foo 3600 A 127.0.0.1 diff --git a/bin/tests/system/dispatch/ns1/root.db b/bin/tests/system/dispatch/ns1/root.db index b6b73675fd..3d180b5ec0 100644 --- a/bin/tests/system/dispatch/ns1/root.db +++ b/bin/tests/system/dispatch/ns1/root.db @@ -14,3 +14,5 @@ ns.nil. 300 A 10.53.0.1 example. 300 NS ns.example. ns.example. 300 A 10.53.0.2 +tcp-only. 300 NS ns.tcp-only. +ns.tcp-only. 300 A 10.53.0.4 diff --git a/bin/tests/system/dispatch/tests_tcponly.py b/bin/tests/system/dispatch/tests_tcponly.py new file mode 100644 index 0000000000..f87919eb2c --- /dev/null +++ b/bin/tests/system/dispatch/tests_tcponly.py @@ -0,0 +1,33 @@ +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# SPDX-License-Identifier: MPL-2.0 +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +import dns.message +import pytest + +import isctest + +pytestmark = pytest.mark.extra_artifacts( + [ + "ans*/ans.run", + ] +) + + +def test_tcponly_not_resolved(): + """ + An authoritative server that only answers over TCP is unreachable + when its zone is queried over UDP: the resolver does not transparently + fall back to TCP after UDP timeouts. (This confirms the expected behavior + for this commit; TCP fallback will be restored in the next.) + """ + msg = dns.message.make_query("foo.tcp-only.", "A") + res = isctest.query.udp(msg, "10.53.0.2", timeout=15) + isctest.check.servfail(res) diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 47ffaab807..d6ae4478f1 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -2675,33 +2675,16 @@ resquery_send(resquery_t *query) { if (fctx->timeout && (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { isc_sockaddr_t *sockaddr = &query->addrinfo->sockaddr; - struct tried *tried; + struct tried *tried = triededns(fctx, sockaddr); /* * If this is the first timeout for this server in this * fetch context, try setting EDNS UDP buffer size to * the largest UDP response size we have seen from this * server so far. - * - * If this server has already timed out twice or more in - * this fetch context, force TCP. */ - if ((tried = triededns(fctx, sockaddr)) != NULL) { - if (tried->count == 1U) { - hint = dns_adb_getudpsize(fctx->adb, - query->addrinfo); - } else if (tried->count >= 2U) { - if ((query->options & DNS_FETCHOPT_TCP) == 0) { - /* - * Inform the ADB that we're ending a - * UDP fetch, and turn the query into - * a TCP query. - */ - dns_adb_endudpfetch(fctx->adb, - query->addrinfo); - query->options |= DNS_FETCHOPT_TCP; - } - } + if (tried != NULL && tried->count == 1U) { + hint = dns_adb_getudpsize(fctx->adb, query->addrinfo); } } fctx->timeout = false;