mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
[9.18] rem: usr: Remove ineffective TCP fallback after repeated UDP timeouts
When an authoritative server failed to respond to two consecutive UDP queries, named marked the next retry as TCP but still sent it over UDP, producing misleading dnstap records. The ineffective retry path has been removed; a corrected TCP fallback will be restored in future BIND 9 versions. Closes #5529 Backport of MR !12022 Merge branch 'backport-5529-fix-tcp-fallback-after-udp-timeouts-9.18' into 'bind-9.18' See merge request isc-projects/bind9!12050
This commit is contained in:
commit
9b53e4be29
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