]> git.kaiwu.me - haproxy.git/commitdiff
MEDIUM: resolvers: accept full-size DNS messages over streams
authorManu Nicolas <e.nicolas@criteo.com>
Tue, 1 Sep 2026 10:44:50 +0000 (10:44 +0000)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 2 Sep 2026 11:40:53 +0000 (13:40 +0200)
accepted_payload_size is both the EDNS UDP advertisement and the
response size limit. A complete stream response larger than this value
is therefore discarded even though DNS stream framing can carry it. It
also makes it impossible to advertise a conservative UDP size while
accepting the complete response after a transport switch.

The stream code already rejects messages above the DNS protocol limit
and buffers the message before the resolver checks its size. Accepting
up to DNS_MAX_MSG_SIZE in the resolver therefore does not increase the
stream allocation.

Keep accepted_payload_size as the UDP advertisement and receive limit,
and use the protocol maximum for stream responses. Configurations that
used it to reject large stream responses will now accept those valid
messages.

doc/configuration.txt
include/haproxy/resolvers-t.h
src/resolvers.c

index fa9b418f42a88665954c819ba0a65c8b0be77479..26e930f4b96ae1a91c156bd08de31889b8a8d6a8 100644 (file)
@@ -20377,17 +20377,17 @@ resolvers <resolvers id>
 A resolvers section accept the following parameters:
 
 accepted_payload_size <nb>
-  Defines the maximum payload size accepted by HAProxy and announced to all the
-  name servers configured in this resolvers section.
+  Defines the maximum UDP payload size accepted by HAProxy and announced to all
+  the name servers configured in this resolvers section.
   <nb> is in bytes. If not set, HAProxy announces 512. (minimal value defined
        by RFC 6891)
 
   Note: the maximum allowed value is 65535. Recommended value for UDP is
         4096 and it is not recommended to exceed 8192 except if you are sure
         that your system and network can handle this (over 65507 makes no sense
-        since is the maximum UDP payload size). If you are using only TCP
-        nameservers to handle huge DNS responses, you should put this value
-        to the max: 65535.
+        since it is the maximum UDP payload size). DNS responses received over a
+        stream transport are accepted up to the DNS protocol maximum of 65535
+        bytes regardless of this setting.
 
 nameserver <name> <address>[:port] [param*]
   Used to configure a nameserver. <name> of the nameserver should ne unique.
index 4b7213a0a52ed8dcbcc55f1d21fc09cb0720832b..cc923c85111d35c0026930ccc82a09dd481fc3fa 100644 (file)
@@ -142,7 +142,7 @@ struct resolv_response {
  */
 struct resolvers {
        __decl_thread(HA_SPINLOCK_T lock);
-       unsigned int accepted_payload_size; /* maximum payload size we accept for responses */
+       unsigned int accepted_payload_size; /* maximum UDP payload size we announce and accept */
        int          nb_nameservers;        /* total number of nameservers in a resolvers section */
        int          resolve_retries;       /* number of retries before giving up */
        struct {                            /* time to: */
index 17d21d1f4e8d94619e0e75eb054318ae47f40107..e9d97a67a0b82bcde30825adb1c3fd3b443432f1 100644 (file)
@@ -2332,12 +2332,15 @@ static int resolv_process_responses(struct dns_nameserver *ns, enum dns_server_t
        unsigned char *bufend;
        int buflen, dns_resp;
        int max_answer_records;
+       unsigned int max_payload_size;
        unsigned short query_id;
        struct eb32_node *eb;
        struct resolv_requester *req;
        int keep_answer_items;
 
        resolvers = ns->parent;
+       max_payload_size = dns_server_type_is_stream(type) ?
+                          DNS_MAX_MSG_SIZE : resolvers->accepted_payload_size;
        enter_resolver_code();
        HA_SPIN_LOCK(DNS_LOCK, &resolvers->lock);
 
@@ -2349,7 +2352,7 @@ static int resolv_process_responses(struct dns_nameserver *ns, enum dns_server_t
                        break;
 
                /* message too big */
-               if (buflen > resolvers->accepted_payload_size) {
+               if (buflen > max_payload_size) {
                        ns->counters->app.resolver.too_big++;
                        continue;
                }
@@ -2377,7 +2380,7 @@ static int resolv_process_responses(struct dns_nameserver *ns, enum dns_server_t
                /* number of responses received */
                res->nb_responses++;
 
-               max_answer_records = (resolvers->accepted_payload_size - DNS_HEADER_SIZE) / DNS_MIN_RECORD_SIZE;
+               max_answer_records = (max_payload_size - DNS_HEADER_SIZE) / DNS_MIN_RECORD_SIZE;
                dns_resp = resolv_validate_dns_response(buf, bufend, res, max_answer_records);
 
                switch (dns_resp) {