mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
Temporarily remove TCP fallback after UDP timeouts
The retry path in resquery_send() that flipped DNS_FETCHOPT_TCP on a
query whose dispatch had already been bound as UDP in fctx_query() had
no effect on the transport actually used, but did leave a stale TCP
bit visible to downstream consumers (dnstap framing, cookie checks,
the AUTHORITY-NS spoofability guard).
The ineffective code has been removed from resquery_send(). The
TCP fallback functionality will be corrected and restored in the next
commit.
Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit 01523a078a)
This commit is contained in:
parent
0fe9e2c923
commit
f82c6f0cba
5 changed files with 95 additions and 20 deletions
42
bin/tests/system/dispatch/ans4/ans.py
Normal file
42
bin/tests/system/dispatch/ans4/ans.py
Normal file
|
|
@ -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()
|
||||
15
bin/tests/system/dispatch/ans4/tcp-only.db
Normal file
15
bin/tests/system/dispatch/ans4/tcp-only.db
Normal file
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
33
bin/tests/system/dispatch/tests_tcponly.py
Normal file
33
bin/tests/system/dispatch/tests_tcponly.py
Normal file
|
|
@ -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)
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue