File reduce-edns-payload.patch of Package glibc.8004
2017-04-13 Florian Weimer <fweimer@redhat.com>
[BZ #21361]
Limit EDNS buffer size to 1200 bytes.
* resolv/res_mkquery.c (__res_ntop): Limit EDNS buffer size to the
interval [512, 1200].
* resolv/res_query.c (__libc_res_nquery): Use 1200 buffer size if
we can resize the buffer.
Index: glibc-2.19/resolv/res_mkquery.c
===================================================================
--- glibc-2.19.orig/resolv/res_mkquery.c
+++ glibc-2.19/resolv/res_mkquery.c
@@ -82,6 +82,8 @@ static const char rcsid[] = "$BINDId: re
/* Options. Leave them on. */
/* #define DEBUG */
+#define RESOLV_EDNS_BUFFER_SIZE 1200
+
#ifdef _LIBC
# include <hp-timing.h>
# include <stdint.h>
@@ -246,7 +248,30 @@ __res_nopt(res_state statp,
*cp++ = 0; /* "." */
NS_PUT16(T_OPT, cp); /* TYPE */
- NS_PUT16(MIN(anslen, 0xffff), cp); /* CLASS = UDP payload size */
+
+ /* Lowering the advertised buffer size based on the actual
+ answer buffer size is desirable because the server will
+ minimize the reply to fit into the UDP packet (and A
+ non-minimal response might not fit the buffer).
+
+ The RESOLV_EDNS_BUFFER_SIZE limit could still result in TCP
+ fallback and a non-minimal response which has to be
+ hard-truncated in the stub resolver, but this is price to
+ pay for avoiding fragmentation. (This issue does not
+ affect the nss_dns functions because they use the stub
+ resolver in such a way that it allocates a properly sized
+ response buffer.) */
+ {
+ uint16_t buffer_size;
+ if (anslen < 512)
+ buffer_size = 512;
+ else if (anslen > RESOLV_EDNS_BUFFER_SIZE)
+ buffer_size = RESOLV_EDNS_BUFFER_SIZE;
+ else
+ buffer_size = anslen;
+ NS_PUT16 (buffer_size, cp);
+ }
+
*cp++ = NOERROR; /* extended RCODE */
*cp++ = 0; /* EDNS version */
Index: glibc-2.19/resolv/res_query.c
===================================================================
--- glibc-2.19.orig/resolv/res_query.c
+++ glibc-2.19/resolv/res_query.c
@@ -86,6 +86,8 @@ static const char rcsid[] = "$BINDId: re
/* Options. Leave them on. */
/* #undef DEBUG */
+#define RESOLV_EDNS_BUFFER_SIZE 1200
+
#if PACKETSZ > 65536
#define MAXPACKET PACKETSZ
#else
@@ -151,7 +153,10 @@ __libc_res_nquery(res_state statp,
if ((oflags & RES_F_EDNS0ERR) == 0
&& (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
{
- n = __res_nopt(statp, n, query1, bufsize, anslen / 2);
+ /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
+ buffer can be reallocated. */
+ n = __res_nopt (statp, n, query1, bufsize,
+ RESOLV_EDNS_BUFFER_SIZE);
if (n < 0)
goto unspec_nomem;
}
@@ -172,8 +177,10 @@ __libc_res_nquery(res_state statp,
if (n > 0
&& (oflags & RES_F_EDNS0ERR) == 0
&& (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
- n = __res_nopt(statp, n, query2, bufsize - nused - n,
- anslen / 2);
+ /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
+ buffer can be reallocated. */
+ n = __res_nopt (statp, n, query2, bufsize,
+ RESOLV_EDNS_BUFFER_SIZE);
nquery2 = n;
}
@@ -187,7 +194,16 @@ __libc_res_nquery(res_state statp,
if (n > 0
&& (oflags & RES_F_EDNS0ERR) == 0
&& (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
- n = __res_nopt(statp, n, query1, bufsize, anslen);
+ {
+ /* Use RESOLV_EDNS_BUFFER_SIZE if the receive buffer
+ can be reallocated. */
+ size_t advertise;
+ if (answerp == NULL)
+ advertise = anslen;
+ else
+ advertise = RESOLV_EDNS_BUFFER_SIZE;
+ n = __res_nopt (statp, n, query1, bufsize, advertise);
+ }
nquery1 = n;
}