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;
 	  }
openSUSE Build Service is sponsored by