From: Christopher Faulet Date: Tue, 29 Sep 2026 08:53:04 +0000 (+0200) Subject: BUG/MINOR: resolvers: use truncated SRV responses when no TCP fallback is possible X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=d7eae26a2315aed6da80c84273239949ed5daf00;p=haproxy.git BUG/MINOR: resolvers: use truncated SRV responses when no TCP fallback is possible Commit bc20f8c0b ("MEDIUM: resolvers: retry truncated UDP responses over TCP") states that a truncated SRV response can still be partially processed when no TCP fallback can be initiated for it. However for a nameserver having both a UDP and a TCP server, the UDP response is validated with allow_truncated_srv=0 before knowing whether the fallback can be queued, so when resolv_send_tcp_fallback() fails (e.g. the TCP request ring is full), the truncated SRV response is treated as an error instead of being used, and the servers are not updated. This was reproduced with a debug patch making resolv_send_tcp_fallback() always fail, and a nameserver answering the SRV query with a truncated response still carrying the SRV record and its glue: the server remained without address before this fix, and gets 127.0.0.1 after. Let's validate the response again allowing truncated SRV responses when the fallback could not be queued. This is safe since the validation stops before parsing any record for truncated responses, and rebuilds the header and question information from scratch. This was introduced in 3.5-dev6 by the commit above, no backport is needed. --- diff --git a/src/resolvers.c b/src/resolvers.c index eb72dd7be..27b383f0f 100644 --- a/src/resolvers.c +++ b/src/resolvers.c @@ -2402,6 +2402,7 @@ static int resolv_process_responses(struct dns_nameserver *ns, enum dns_server_t struct eb32_node *eb; struct resolv_requester *req; int keep_answer_items; + int allow_truncated_srv; resolvers = ns->parent; max_payload_size = dns_server_type_is_stream(type) ? @@ -2449,9 +2450,11 @@ static int resolv_process_responses(struct dns_nameserver *ns, enum dns_server_t res->nb_responses++; max_answer_records = (max_payload_size - DNS_HEADER_SIZE) / DNS_MIN_RECORD_SIZE; + allow_truncated_srv = !(dns_server_type_is_dgram(type) && + dns_nameserver_has_fallback(ns)); + validate: dns_resp = resolv_validate_dns_response(buf, bufend, res, max_answer_records, - !(dns_server_type_is_dgram(type) && - dns_nameserver_has_fallback(ns))); + allow_truncated_srv); switch (dns_resp) { case RSLV_RESP_VALID: @@ -2494,6 +2497,14 @@ static int resolv_process_responses(struct dns_nameserver *ns, enum dns_server_t res->status = RSLV_STATUS_TIMEOUT; continue; } + if (!allow_truncated_srv && + res->response_query_records[0].type == DNS_RTYPE_SRV) { + /* no fallback possible, a truncated SRV + * response may still be partially used. + */ + allow_truncated_srv = 1; + goto validate; + } res->status = RSLV_STATUS_OTHER; break;