]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: dns: Maximum DNS udp payload set to 8192
authorBaptiste Assmann <bassmann@haproxy.com>
Fri, 18 Aug 2017 21:35:08 +0000 (23:35 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 22 Aug 2017 09:39:57 +0000 (11:39 +0200)
Following up DNS extension introduction, this patch aims at making the
computation of the maximum number of records in DNS response dynamic.
This computation is based on the announced payload size accepted by
HAProxy.

doc/configuration.txt
include/proto/dns.h
include/types/dns.h
src/cfgparse.c
src/dns.c

index 66c932597a06cd3db6f76f4313e01d01a9c0ed70..9f7f9ff3dddfc5d4d8b67ae8d7af9dd98ba9a169 100644 (file)
@@ -11716,9 +11716,11 @@ accepted_payload_size <nb>
   <nb> is in bytes. If not set, HAProxy announces 512. (minimal value defined
        by RFC 6891)
 
-  Note: to get biggers response but still be sure that responses won't be
+  Note: to get bigger responses but still be sure that responses won't be
         dropped on the wire, one can choose a value between 1280 and 1410.
 
+  Note: the maximum allowed value is 8192.
+
 nameserver <id> <ip>:<port>
   DNS server description:
     <id>   : label of the server, should be unique
index 5aed46e78c726ef31e9228aabc6a7976b42c9552..aa063c7b26353f6f025f413e884078f9bcd9b3ec 100644 (file)
@@ -33,7 +33,7 @@ int dns_build_query(int query_id, int query_type, unsigned int accepted_payload_
 struct task *dns_process_resolve(struct task *t);
 int dns_init_resolvers(int close_socket);
 uint16_t dns_rnd16(void);
-int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend, struct dns_resolution *resolution);
+int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend, struct dns_resolution *resolution, int max_answer_records);
 int dns_get_ip_from_response(struct dns_response_packet *dns_p,
                              struct dns_options *dns_opts, void *currentip,
                              short currentip_sin_family,
index 0f9c1b970766954c41a8c95f2e837cf93a2f2399..c7338c79243d04b2c7b50a7a9bde9468f8cad6e6 100644 (file)
@@ -30,7 +30,7 @@
  */
 #define DNS_MAX_LABEL_SIZE     63
 #define DNS_MAX_NAME_SIZE      255
-#define DNS_MAX_UDP_MESSAGE    512
+#define DNS_MAX_UDP_MESSAGE    8192
 
 /* DNS minimun record size: 1 char + 1 NULL + type + class */
 #define DNS_MIN_RECORD_SIZE    ( 1 + 1 + 2 + 2 )
index ee249794f967c50b61905f29a64ffd0c5e7da3bb..e69a4ab78b8da4edc1c38e5df0129d27fcdcbb31 100644 (file)
@@ -2294,13 +2294,24 @@ int cfg_parse_resolvers(const char *file, int linenum, char **args, int kwm)
 
        }
        else if (strcmp(args[0], "accepted_payload_size") == 0) {
+               int i = 0;
+
                if (!*args[1]) {
                        Alert("parsing [%s:%d] : '%s' expects <nb> as argument.\n",
                                file, linenum, args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        goto out;
                }
-               curr_resolvers->accepted_payload_size = atoi(args[1]);
+
+               i = atoi(args[1]);
+               if (i > DNS_MAX_UDP_MESSAGE) {
+                       Alert("parsing [%s:%d] : '%s' size %d exceeds maximum allowed size %d.\n",
+                               file, linenum, args[0], i, DNS_MAX_UDP_MESSAGE);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+
+               curr_resolvers->accepted_payload_size = i;
        }
        else if (strcmp(args[0], "resolution_pool_size") == 0) {
                if (!*args[1]) {
index c91d4237be180278a4f8f833c92925ea1496f1f7..62291fe1fcc9cc60574792eb437899de5a27447b 100644 (file)
--- a/src/dns.c
+++ b/src/dns.c
@@ -391,6 +391,7 @@ void dns_resolve_recv(struct dgram_conn *dgram)
        unsigned char buf[DNS_MAX_UDP_MESSAGE + 1];
        unsigned char *bufend;
        int fd, buflen, dns_resp, need_resend = 0;
+       int max_answer_records = 0;
        unsigned short query_id;
        struct eb32_node *eb;
        struct lru64 *lru = NULL;
@@ -413,15 +414,15 @@ void dns_resolve_recv(struct dgram_conn *dgram)
        while (1) {
                int removed_reso = 0;
                /* read message received */
-               memset(buf, '\0', DNS_MAX_UDP_MESSAGE + 1);
-               if ((buflen = recv(fd, (char*)buf , DNS_MAX_UDP_MESSAGE, 0)) < 0) {
+               memset(buf, '\0', resolvers->accepted_payload_size + 1);
+               if ((buflen = recv(fd, (char*)buf , resolvers->accepted_payload_size + 1, 0)) < 0) {
                        /* FIXME : for now we consider EAGAIN only */
                        fd_cant_recv(fd);
                        break;
                }
 
                /* message too big */
-               if (buflen > DNS_MAX_UDP_MESSAGE) {
+               if (buflen > resolvers->accepted_payload_size) {
                        nameserver->counters.too_big += 1;
                        continue;
                }
@@ -455,7 +456,9 @@ void dns_resolve_recv(struct dgram_conn *dgram)
                /* number of responses received */
                resolution->nb_responses += 1;
 
-               dns_resp = dns_validate_dns_response(buf, bufend, resolution);
+
+               max_answer_records = (resolvers->accepted_payload_size - DNS_HEADER_SIZE) / DNS_MIN_RECORD_SIZE;
+               dns_resp = dns_validate_dns_response(buf, bufend, resolution, max_answer_records);
 
                switch (dns_resp) {
                        case DNS_RESP_VALID:
@@ -1086,7 +1089,7 @@ int dns_read_name(unsigned char *buffer, unsigned char *bufend, unsigned char *n
  * This function returns one of the DNS_RESP_* code to indicate the type of
  * error found.
  */
-int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend, struct dns_resolution *resolution)
+int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend, struct dns_resolution *resolution, int max_answer_records)
 {
        unsigned char *reader;
        char *previous_dname, tmpname[DNS_MAX_NAME_SIZE];
@@ -1157,7 +1160,7 @@ int dns_validate_dns_response(unsigned char *resp, unsigned char *bufend, struct
        if (dns_p->header.ancount == 0)
                return DNS_RESP_ANCOUNT_ZERO;
        /* check if too many records are announced */
-       if (dns_p->header.ancount > DNS_MAX_ANSWER_RECORDS)
+       if (dns_p->header.ancount > max_answer_records)
                return DNS_RESP_INVALID;
        reader += 2;