]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MINOR: resolvers: report a timeout when a TCP fallback gets no response
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 29 Sep 2026 07:41:15 +0000 (09:41 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Tue, 10 Nov 2026 14:47:52 +0000 (15:47 +0100)
When a truncated UDP response triggers a TCP fallback, the resolution's
status is first set to RSLV_STATUS_OTHER, then the fallback query is
queued. If the TCP query never gets a response (e.g. the nameserver
refuses TCP connections or doesn't respond over TCP), the resolution
eventually fails on timeout, but process_resolvers() only sets the
status to RSLV_STATUS_TIMEOUT when no response at all was received, which
is not the case since the truncated UDP response was counted. The
requesters are then notified of an "other" error: servers are put into
maintenance for an "unspecified DNS error", and the "hold other" period
applies instead of "hold timeout".

This can be reproduced with a nameserver answering all UDP queries with
the TC flag set and refusing TCP, and a server using this name with
"hold other 100ms" and "hold timeout 100ms": the server goes down for
"unspecified DNS error" instead of "DNS timeout status".

Let's set the status to RSLV_STATUS_TIMEOUT when the fallback is queued.
Any subsequent response will update it as usual, and if none comes, it
is the right status to report.

This was introduced in 3.5-dev6 by commit bc20f8c0b ("MEDIUM: resolvers:
retry truncated UDP responses over TCP"), no backport is needed.

src/resolvers.c

index 25139c39e99acbbf77aeb0801f6524c96bd6e93b..eb72dd7beee5954fc5868f5d8edd3eb69842a939 100644 (file)
@@ -2485,13 +2485,16 @@ static int resolv_process_responses(struct dns_nameserver *ns, enum dns_server_t
                                break;
 
                        case RSLV_RESP_TRUNCATED:
-                               res->status = RSLV_STATUS_OTHER;
                                ns->counters->app.resolver.truncated++;
                                if (dns_server_type_is_dgram(type) &&
                                    dns_nameserver_has_fallback(ns) &&
                                    resolv_send_tcp_fallback(res, ns,
-                                                           res->response_query_records[0].type))
+                                                           res->response_query_records[0].type)) {
+                                       /* if the TCP response never comes, it's a timeout */
+                                       res->status = RSLV_STATUS_TIMEOUT;
                                        continue;
+                               }
+                               res->status = RSLV_STATUS_OTHER;
                                break;
 
                        case RSLV_RESP_NO_EXPECTED_RECORD: