bind9/bin/tests/system/dispatch/tests_tcponly.py
Ondřej Surý 59c00a6f31
Force TCP after repeated UDP timeouts to the same authoritative
Make the decision in fctx_query() before the dispatch is bound so the
chosen transport and the DNS_FETCHOPT_TCP flag agree.  The previous
location in resquery_send() ran after the UDP dispatch had already been
attached, so the flag flip had no effect on the wire.

Moving the decision earlier also means FCTX_ADDRINFO_NOEDNS0 servers,
previously exempt, now escalate to TCP too.  TCP works regardless of
EDNS state, so this is the intended behaviour.

Assisted-by: Claude:claude-opus-4-7
2026-05-19 11:18:30 +02:00

57 lines
1.8 KiB
Python

# 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 re import compile as Re
from re import escape
import dns.message
import dns.name
import dns.rdataclass
import dns.rdatatype
import pytest
import isctest
pytestmark = pytest.mark.extra_artifacts(
[
"ans*/ans.run",
]
)
def _count_received(path, qname, protocol):
pattern = Re(rf"Received {escape(qname)}/IN/A .* \({protocol}\)$")
with open(path, encoding="utf-8") as fh:
return sum(1 for line in fh if pattern.search(line.rstrip()))
def test_tcponly_fallback():
"""
A resolver must fall back to TCP after repeated UDP timeouts to the
same authoritative server. ans4 drops every UDP query and answers
only over TCP; the resolver must reach the answer via the TCP
fallback path, after at least two UDP attempts have been dropped.
"""
msg = dns.message.make_query("foo.tcp-only.", "A")
res = isctest.query.udp(msg, "10.53.0.2", timeout=15)
isctest.check.noerror(res)
rdataset = res.find_rrset(
res.answer,
dns.name.from_text("foo.tcp-only."),
dns.rdataclass.IN,
dns.rdatatype.A,
)
assert str(rdataset[0]) == "127.0.0.1"
udp = _count_received("ans4/ans.run", "foo.tcp-only", "UDP")
tcp = _count_received("ans4/ans.run", "foo.tcp-only", "TCP")
assert udp == 2, f"expected exactly 2 UDP queries, got {udp}"
assert tcp == 1, f"expected exactly 1 TCP query, got {tcp}"