about summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2008-07-28 22:55:10 +0000
committerUlrich Drepper <drepper@redhat.com>2008-07-28 22:55:10 +0000
commitb7da31a1647e378258174d1d69097a594e31f89b (patch)
treea38031232a20545f6c044a94f6823ecfb6090ead
parent372aece0e4b7497f894f21b36bcc32ec52344ad5 (diff)
downloadglibc-b7da31a1647e378258174d1d69097a594e31f89b.tar.gz
glibc-b7da31a1647e378258174d1d69097a594e31f89b.tar.xz
glibc-b7da31a1647e378258174d1d69097a594e31f89b.zip
* resolv/res_send.c (__libc_res_nsend): Take additional parameter. cvs/fedora-glibc-20080728T2320
	Use it instead of locally defined resplen2 variable.
	(res_nsend): Adjust for __libc_res_nsend interface change.
	(send_vc): Initialize *resplen2 if necessary.  Read length of
	package into an appropriately aligned variable.  Store converted length
	in new variable and use it appropriately.
	Add branch prediction help.
	* resolv/res_query.c (__libc_res_nquery): Take additional parameter
	and pass it on to __libc_res_nsend.  Adjust all callers.
	(__libc_res_nsearch): Likewise.
	(__libc_res_nqeurydomain): Likewise.
	* resolv/nss_dns/dns-host.c: Adjust for __libc_res_nsearch interface
	change.
	(_nss_dns_gethostbyname4): Don't unconditionally allocate tmp array.
	Define resplen2 variable and pass it to __libc_res_nsearch and then
	to gaih_getanswer.
	(getanswer_r): In case of incorrect DNS data don't overread buffer.
	Add branch prediction.
	(gaih_getanswer_slice): Likewise.  Check for invalid data types.
	(gaih_getanswer): Don't decode second slice if first one failed due
	to a too small buffer.  Don't let not found status of second
	decoder shadow results of the first.
	* resolv/gethnamaddr.c (gethostbyname2): Adjust for __libc_res_nsearch
	and __libc_res_nquery interface changes
	(gethostbyaddr): Adjust for __libc_res_nquery interface change.
	* include/resolv.h: Adjust prototypes for __libc_res_nquery,
	__libc_res_nsearch, and __libc_res_nsend.
	* resolv/nss_dns/dns-canon.c: Adjust for __libc_res_nquery interface
	change.
	* resolv/nss_dns/dns-network.c: Adjust for __libc_res_nquery and
	__libc_res_nsearch interface changes.
-rw-r--r--ChangeLog34
-rw-r--r--include/resolv.h6
-rw-r--r--resolv/gethnamaddr.c6
-rw-r--r--resolv/nss_dns/dns-canon.c3
-rw-r--r--resolv/nss_dns/dns-host.c65
-rw-r--r--resolv/nss_dns/dns-network.c4
-rw-r--r--resolv/res_query.c32
-rw-r--r--resolv/res_send.c53
8 files changed, 132 insertions, 71 deletions
diff --git a/ChangeLog b/ChangeLog
index 4d5b530cf7..d4cccb6837 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,37 @@
+2008-07-28  Ulrich Drepper  <drepper@redhat.com>
+
+	* resolv/res_send.c (__libc_res_nsend): Take additional parameter.
+	Use it instead of locally defined resplen2 variable.
+	(res_nsend): Adjust for __libc_res_nsend interface change.
+	(send_vc): Initialize *resplen2 if necessary.  Read length of
+	package into an appropriately aligned variable.  Store converted length
+	in new variable and use it appropriately.
+	Add branch prediction help.
+	* resolv/res_query.c (__libc_res_nquery): Take additional parameter
+	and pass it on to __libc_res_nsend.  Adjust all callers.
+	(__libc_res_nsearch): Likewise.
+	(__libc_res_nqeurydomain): Likewise.
+	* resolv/nss_dns/dns-host.c: Adjust for __libc_res_nsearch interface
+	change.
+	(_nss_dns_gethostbyname4): Don't unconditionally allocate tmp array.
+	Define resplen2 variable and pass it to __libc_res_nsearch and then
+	to gaih_getanswer.
+	(getanswer_r): In case of incorrect DNS data don't overread buffer.
+	Add branch prediction.
+	(gaih_getanswer_slice): Likewise.  Check for invalid data types.
+	(gaih_getanswer): Don't decode second slice if first one failed due
+	to a too small buffer.  Don't let not found status of second
+	decoder shadow results of the first.
+	* resolv/gethnamaddr.c (gethostbyname2): Adjust for __libc_res_nsearch
+	and __libc_res_nquery interface changes
+	(gethostbyaddr): Adjust for __libc_res_nquery interface change.
+	* include/resolv.h: Adjust prototypes for __libc_res_nquery,
+	__libc_res_nsearch, and __libc_res_nsend.
+	* resolv/nss_dns/dns-canon.c: Adjust for __libc_res_nquery interface
+	change.
+	* resolv/nss_dns/dns-network.c: Adjust for __libc_res_nquery and
+	__libc_res_nsearch interface changes.
+
 2008-07-27  Ulrich Drepper  <drepper@redhat.com>
 
 	* libio/iopopen.c (_IO_new_proc_open): Remove unnecessary volatile.
diff --git a/include/resolv.h b/include/resolv.h
index 925746f685..6dae0495b2 100644
--- a/include/resolv.h
+++ b/include/resolv.h
@@ -58,11 +58,11 @@ libc_hidden_proto (__res_randomid)
 libc_hidden_proto (__res_state)
 
 int __libc_res_nquery (res_state, const char *, int, int, u_char *, int,
-		       u_char **, u_char **, int *);
+		       u_char **, u_char **, int *, int *);
 int __libc_res_nsearch (res_state, const char *, int, int, u_char *, int,
-			u_char **, u_char **, int *);
+			u_char **, u_char **, int *, int *);
 int __libc_res_nsend (res_state, const u_char *, int, const u_char *, int,
-		      u_char *, int, u_char **, u_char **, int *)
+		      u_char *, int, u_char **, u_char **, int *, int *)
   attribute_hidden;
 
 libresolv_hidden_proto (_sethtent)
diff --git a/resolv/gethnamaddr.c b/resolv/gethnamaddr.c
index 2a9bd0b3c2..5cf660a8d4 100644
--- a/resolv/gethnamaddr.c
+++ b/resolv/gethnamaddr.c
@@ -621,7 +621,7 @@ gethostbyname2(name, af)
 	buf.buf = origbuf = (querybuf *) alloca (1024);
 
 	if ((n = __libc_res_nsearch(&_res, name, C_IN, type, buf.buf->buf, 1024,
-				    &buf.ptr, NULL, NULL)) < 0) {
+				    &buf.ptr, NULL, NULL, NULL)) < 0) {
 		if (buf.buf != origbuf)
 			free (buf.buf);
 		Dprintf("res_nsearch failed (%d)\n", n);
@@ -716,12 +716,12 @@ gethostbyaddr(addr, len, af)
 	buf.buf = orig_buf = (querybuf *) alloca (1024);
 
 	n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf, 1024,
-			      &buf.ptr, NULL, NULL);
+			      &buf.ptr, NULL, NULL, NULL);
 	if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0) {
 		strcpy(qp, "ip6.int");
 		n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf,
 				      buf.buf != orig_buf ? MAXPACKET : 1024,
-				      &buf.ptr, NULL, NULL);
+				      &buf.ptr, NULL, NULL, NULL);
 	}
 	if (n < 0) {
 		if (buf.buf != orig_buf)
diff --git a/resolv/nss_dns/dns-canon.c b/resolv/nss_dns/dns-canon.c
index 47949b862f..cee3d57bc1 100644
--- a/resolv/nss_dns/dns-canon.c
+++ b/resolv/nss_dns/dns-canon.c
@@ -61,7 +61,8 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
   for (int i = 0; i < nqtypes; ++i)
     {
       int r = __libc_res_nquery (&_res, name, ns_c_in, qtypes[i],
-				 buf, sizeof (buf), &ansp.ptr, NULL, NULL);
+				 buf, sizeof (buf), &ansp.ptr, NULL, NULL,
+				 NULL);
       if (r > 0)
 	{
 	  /* We need to decode the response.  Just one question record.
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index cae077445f..80c0bd9fa8 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -195,7 +195,7 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
   host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
 
   n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf,
-			  1024, &host_buffer.ptr, NULL, NULL);
+			  1024, &host_buffer.ptr, NULL, NULL, NULL);
   if (n < 0)
     {
       status = (errno == ECONNREFUSED
@@ -213,7 +213,7 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
 	n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer.buf->buf,
 				host_buffer.buf != orig_host_buffer
 				? MAXPACKET : 1024, &host_buffer.ptr,
-				NULL, NULL);
+				NULL, NULL, NULL);
 
       if (n < 0)
 	{
@@ -273,8 +273,6 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
   if (__res_maybe_init (&_res, 0) == -1)
     return NSS_STATUS_UNAVAIL;
 
-  char tmp[NS_MAXDNAME];
-
   /*
    * if there aren't any dots, it could be a user-level alias.
    * this is also done in res_query() since we are not the only
@@ -282,7 +280,8 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
    */
   if (strchr (name, '.') == NULL)
     {
-      const char *cp = res_hostalias (&_res, name, tmp, sizeof (tmp));
+      char *tmp = alloca (NS_MAXDNAME);
+      const char *cp = res_hostalias (&_res, name, tmp, NS_MAXDNAME);
       if (cp != NULL)
 	name = cp;
     }
@@ -296,12 +295,13 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
   host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
   u_char *ans2p = NULL;
   int nans2p = 0;
+  int resplen2 = 0;
 
   int olderr = errno;
   enum nss_status status;
   int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC,
 			      host_buffer.buf->buf, 2048, &host_buffer.ptr,
-			      &ans2p, &nans2p);
+			      &ans2p, &nans2p, &resplen2);
   if (n < 0)
     {
       status = (errno == ECONNREFUSED
@@ -319,7 +319,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
     }
 
   status = gaih_getanswer(host_buffer.buf, n, (const querybuf *) ans2p,
-			  nans2p, name, pat, buffer, buflen,
+			  resplen2, name, pat, buffer, buflen,
 			  errnop, herrnop, ttlp);
 
   if (host_buffer.buf != orig_host_buffer)
@@ -417,7 +417,7 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
 	  strcpy (qp, "].ip6.arpa");
 	  n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR,
 				 host_buffer.buf->buf, 1024, &host_buffer.ptr,
-				 NULL, NULL);
+				 NULL, NULL, NULL);
 	  if (n >= 0)
 	    goto got_it_already;
 	}
@@ -438,14 +438,14 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
     }
 
   n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
-			 1024, &host_buffer.ptr, NULL, NULL);
+			 1024, &host_buffer.ptr, NULL, NULL, NULL);
   if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0)
     {
       strcpy (qp, "ip6.int");
       n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
 			     host_buffer.buf != orig_host_buffer
 			     ? MAXPACKET : 1024, &host_buffer.ptr,
-			     NULL, NULL);
+			     NULL, NULL, NULL);
     }
   if (n < 0)
     {
@@ -685,12 +685,19 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
 	  n = -1;
 	}
 
-      if (n < 0 || (*name_ok) (bp) == 0)
+      if (__builtin_expect (n < 0 || (*name_ok) (bp) == 0, 0))
 	{
 	  ++had_error;
 	  continue;
 	}
       cp += n;				/* name */
+
+      if (__builtin_expect (cp + 10 > end_of_message, 0))
+	{
+	  ++had_error;
+	  continue;
+	}
+
       type = ns_get16 (cp);
       cp += INT16SZ;			/* type */
       class = ns_get16 (cp);
@@ -699,7 +706,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
       cp += INT32SZ;			/* TTL */
       n = ns_get16 (cp);
       cp += INT16SZ;			/* len */
-      if (class != C_IN)
+      if (__builtin_expect (class != C_IN, 0))
 	{
 	  /* XXX - debug? syslog? */
 	  cp += n;
@@ -711,7 +718,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
 	  if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
 	    continue;
 	  n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
-	  if (n < 0 || (*name_ok) (tbuf) == 0)
+	  if (__builtin_expect (n < 0 || (*name_ok) (tbuf) == 0, 0))
 	    {
 	      ++had_error;
 	      continue;
@@ -745,7 +752,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
       if (qtype == T_PTR && type == T_CNAME)
 	{
 	  n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
-	  if (n < 0 || res_dnok (tbuf) == 0)
+	  if (__builtin_expect (n < 0 || res_dnok (tbuf) == 0, 0))
 	    {
 	      ++had_error;
 	      continue;
@@ -792,7 +799,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
       switch (type)
 	{
 	case T_PTR:
-	  if (__strcasecmp (tname, bp) != 0)
+	  if (__builtin_expect (__strcasecmp (tname, bp) != 0, 0))
 	    {
 	      syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, qname, bp);
 	      cp += n;
@@ -809,7 +816,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
 	      n = -1;
 	    }
 
-	  if (n < 0 || res_hnok (bp) == 0)
+	  if (__builtin_expect (n < 0 || res_hnok (bp) == 0, 0))
 	    {
 	      ++had_error;
 	      break;
@@ -839,7 +846,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
 	  if (have_to_map)
 	    {
 	      n = strlen (bp) + 1;	/* for the \0 */
-	      if (n >= MAXHOSTNAMELEN)
+	      if (__builtin_expect (n >= MAXHOSTNAMELEN, 0))
 		{
 		  ++had_error;
 		  break;
@@ -957,7 +964,7 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
       return NSS_STATUS_UNAVAIL;
     }
 
-   u_char packtmp[NS_MAXCDNAME];
+  u_char packtmp[NS_MAXCDNAME];
   int n = __ns_name_unpack (answer->buf, end_of_message, cp,
 			    packtmp, sizeof packtmp);
   /* We unpack the name to check it for validity.  But we do not need
@@ -1005,7 +1012,7 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
 
 	  n = -1;
 	}
-      if (n < 0 || res_hnok (buffer) == 0)
+      if (__builtin_expect (n < 0 || res_hnok (buffer) == 0, 0))
 	{
 	  ++had_error;
 	  continue;
@@ -1018,6 +1025,13 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
 	}
 
       cp += n;				/* name */
+
+      if (__builtin_expect (cp + 10 > end_of_message, 0))
+	{
+	  ++had_error;
+	  continue;
+	}
+
       int type = ns_get16 (cp);
       cp += INT16SZ;			/* type */
       int class = ns_get16 (cp);
@@ -1037,7 +1051,7 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
 	{
 	  char tbuf[MAXDNAME];
 	  n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
-	  if (n < 0 || res_hnok (tbuf) == 0)
+	  if (__builtin_expect (n < 0 || res_hnok (tbuf) == 0, 0))
 	    {
 	      ++had_error;
 	      continue;
@@ -1130,6 +1144,12 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
 	}
 
       (*pat)->family = type == T_A ? AF_INET : AF_INET6;
+      if (__builtin_expect ((type == T_A && n != INADDRSZ)
+			    || (type == T_AAAA && n != IN6ADDRSZ), 0))
+	{
+	  ++had_error;
+	  continue;
+	}
       memcpy ((*pat)->addr, cp, n);
       cp += n;
       (*pat)->scopeid = 0;
@@ -1172,14 +1192,15 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
 				  errnop, h_errnop, ttlp,
 				  &first);
   if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND
-       || status == NSS_STATUS_TRYAGAIN)
+       || (status == NSS_STATUS_TRYAGAIN
+	   && (errno != ERANGE || *h_errnop != NO_RECOVERY)))
       && answer2 != NULL && anslen2 > 0)
     {
       enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname,
 						     &pat, &buffer, &buflen,
 						     errnop, h_errnop, ttlp,
 						     &first);
-      if (status != NSS_STATUS_SUCCESS)
+      if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND)
 	status = status2;
     }
 
diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c
index 40736fbe94..c9969e08dc 100644
--- a/resolv/nss_dns/dns-network.c
+++ b/resolv/nss_dns/dns-network.c
@@ -130,7 +130,7 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
   net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
 
   anslen = __libc_res_nsearch (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
-			       1024, &net_buffer.ptr, NULL, NULL);
+			       1024, &net_buffer.ptr, NULL, NULL, NULL);
   if (anslen < 0)
     {
       /* Nothing found.  */
@@ -206,7 +206,7 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
   net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
 
   anslen = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
-			      1024, &net_buffer.ptr, NULL, NULL);
+			      1024, &net_buffer.ptr, NULL, NULL, NULL);
   if (anslen < 0)
     {
       /* Nothing found.  */
diff --git a/resolv/res_query.c b/resolv/res_query.c
index b2b45acde7..7102ba948e 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -97,7 +97,8 @@ static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vix
 static int
 __libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
 			int class, int type, u_char *answer, int anslen,
-			u_char **answerp, u_char **answerp2, int *nanswerp2);
+			u_char **answerp, u_char **answerp2, int *nanswerp2,
+			int *resplen2);
 
 /*
  * Formulate a normal query, send, and await answer.
@@ -117,7 +118,8 @@ __libc_res_nquery(res_state statp,
 		  int anslen,		/* size of answer buffer */
 		  u_char **answerp,	/* if buffer needs to be enlarged */
 		  u_char **answerp2,
-		  int *nanswerp2)
+		  int *nanswerp2,
+		  int *resplen2)
 {
 	HEADER *hp = (HEADER *) answer;
 	int n, use_malloc = 0;
@@ -221,7 +223,7 @@ __libc_res_nquery(res_state statp,
 	}
 	assert (answerp == NULL || (void *) *answerp == (void *) answer);
 	n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
-			     anslen, answerp, answerp2, nanswerp2);
+			     anslen, answerp, answerp2, nanswerp2, resplen2);
 	if (use_malloc)
 		free (buf);
 	if (n < 0) {
@@ -307,7 +309,7 @@ res_nquery(res_state statp,
 	   int anslen)		/* size of answer buffer */
 {
 	return __libc_res_nquery(statp, name, class, type, answer, anslen,
-				 NULL, NULL, NULL);
+				 NULL, NULL, NULL, NULL);
 }
 libresolv_hidden_def (res_nquery)
 
@@ -325,7 +327,8 @@ __libc_res_nsearch(res_state statp,
 		   int anslen,		/* size of answer */
 		   u_char **answerp,
 		   u_char **answerp2,
-		   int *nanswerp2)
+		   int *nanswerp2,
+		   int *resplen2)
 {
 	const char *cp, * const *domain;
 	HEADER *hp = (HEADER *) answer;
@@ -349,7 +352,7 @@ __libc_res_nsearch(res_state statp,
 	if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
 		return (__libc_res_nquery(statp, cp, class, type, answer,
 					  anslen, answerp, answerp2,
-					  nanswerp2));
+					  nanswerp2, resplen2));
 
 #ifdef DEBUG
 	if (statp->options & RES_DEBUG)
@@ -366,7 +369,7 @@ __libc_res_nsearch(res_state statp,
 	if (dots >= statp->ndots || trailing_dot) {
 		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
 					      answer, anslen, answerp,
-					      answerp2, nanswerp2);
+					      answerp2, nanswerp2, resplen2);
 		if (ret > 0 || trailing_dot)
 			return (ret);
 		saved_herrno = h_errno;
@@ -404,7 +407,8 @@ __libc_res_nsearch(res_state statp,
 			ret = __libc_res_nquerydomain(statp, name, *domain,
 						      class, type,
 						      answer, anslen, answerp,
-						      answerp2, nanswerp2);
+						      answerp2, nanswerp2,
+						      resplen2);
 			if (ret > 0)
 				return (ret);
 
@@ -473,7 +477,7 @@ __libc_res_nsearch(res_state statp,
 	if (dots && !(tried_as_is || root_on_list)) {
 		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
 					      answer, anslen, answerp,
-					      answerp2, nanswerp2);
+					      answerp2, nanswerp2, resplen2);
 		if (ret > 0)
 			return (ret);
 	}
@@ -508,7 +512,7 @@ res_nsearch(res_state statp,
 	    int anslen)		/* size of answer */
 {
 	return __libc_res_nsearch(statp, name, class, type, answer,
-				  anslen, NULL, NULL, NULL);
+				  anslen, NULL, NULL, NULL, NULL);
 }
 libresolv_hidden_def (res_nsearch)
 
@@ -525,7 +529,8 @@ __libc_res_nquerydomain(res_state statp,
 			int anslen,			/* size of answer */
 			u_char **answerp,
 			u_char **answerp2,
-			int *nanswerp2)
+			int *nanswerp2,
+			int *resplen2)
 {
 	char nbuf[MAXDNAME];
 	const char *longname = nbuf;
@@ -562,7 +567,8 @@ __libc_res_nquerydomain(res_state statp,
 		sprintf(nbuf, "%s.%s", name, domain);
 	}
 	return (__libc_res_nquery(statp, longname, class, type, answer,
-				  anslen, answerp, answerp2, nanswerp2));
+				  anslen, answerp, answerp2, nanswerp2,
+				  resplen2));
 }
 
 int
@@ -574,7 +580,7 @@ res_nquerydomain(res_state statp,
 	    int anslen)		/* size of answer */
 {
 	return __libc_res_nquerydomain(statp, name, domain, class, type,
-				       answer, anslen, NULL, NULL, NULL);
+				       answer, anslen, NULL, NULL, NULL, NULL);
 }
 libresolv_hidden_def (res_nquerydomain)
 
diff --git a/resolv/res_send.c b/resolv/res_send.c
index dec3ac7a3f..3130f64281 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -339,9 +339,9 @@ int
 __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
 		 const u_char *buf2, int buflen2,
 		 u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
-		 int *nansp2)
+		 int *nansp2, int *resplen2)
 {
-  int gotsomewhere, terrno, try, v_circuit, resplen, resplen2, ns, n;
+  int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
 
 	if (statp->nscount == 0) {
 		__set_errno (ESRCH);
@@ -539,7 +539,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
 			try = statp->retry;
 			n = send_vc(statp, buf, buflen, buf2, buflen2,
 				    &ans, &anssiz, &terrno,
-				    ns, ansp, ansp2, nansp2, &resplen2);
+				    ns, ansp, ansp2, nansp2, resplen2);
 			if (n < 0)
 				return (-1);
 			if (n == 0)
@@ -549,14 +549,14 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
 			n = send_dg(statp, buf, buflen, buf2, buflen2,
 				    &ans, &anssiz, &terrno,
 				    ns, &v_circuit, &gotsomewhere, ansp,
-				    ansp2, nansp2, &resplen2);
+				    ansp2, nansp2, resplen2);
 			if (n < 0)
 				return (-1);
 			if (n == 0)
 				goto next_ns;
 			if (v_circuit)
 			  // XXX Check whether both requests failed or
-			  // XXX whether one have been answered successfully
+			  // XXX whether one has been answered successfully
 				goto same_ns;
 		}
 
@@ -575,7 +575,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
 		  DprintQ((statp->options & RES_DEBUG) ||
 			  (statp->pfcode & RES_PRF_REPLY),
 			  (stdout, "%s", ""),
-			  *ansp2, (resplen2 > *nansp2) ? *nansp2 : resplen2);
+			  *ansp2, (*resplen2 > *nansp2) ? *nansp2 : *resplen2);
 
 		/*
 		 * If we have temporarily opened a virtual circuit,
@@ -638,7 +638,7 @@ res_nsend(res_state statp,
 	  const u_char *buf, int buflen, u_char *ans, int anssiz)
 {
   return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
-			  NULL, NULL, NULL);
+			  NULL, NULL, NULL, NULL);
 }
 libresolv_hidden_def (res_nsend)
 
@@ -665,6 +665,8 @@ send_vc(res_state statp,
 	u_short len2;
 	u_char *cp;
 
+	if (resplen2 != NULL)
+	  *resplen2 = 0;
 	connreset = 0;
  same_ns:
 	truncating = 0;
@@ -734,8 +736,9 @@ send_vc(res_state statp,
 	int recvresp2 = buf2 == NULL;
  read_len:
 	cp = ans;
-	len = INT16SZ;
-	while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, (char *)cp,
+	uint16_t rlen16;
+	len = sizeof(rlen16);
+	while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, &rlen16,
 					     (int)len))) > 0) {
 		cp += n;
 		if ((len -= n) <= 0)
@@ -760,11 +763,7 @@ send_vc(res_state statp,
 		}
 		return (0);
 	}
-#ifdef _STRING_ARCH_unaligned
-	resplen = ntohs (*(uint16_t *) ans);
-#else
-	resplen = ns_get16(ans);
-#endif
+	int rlen = ntohs (rlen16);
 
 	int *thisanssizp;
 	u_char **thisansp;
@@ -795,11 +794,11 @@ send_vc(res_state statp,
 	}
 	anhp = (HEADER *) *thisansp;
 
-	*thisresplenp = resplen;
-	if (resplen > *thisanssizp) {
+	*thisresplenp = rlen;
+	if (rlen > *thisanssizp) {
 		/* Yes, we test ANSCP here.  If we have two buffers
 		   both will be allocatable.  */
-		if (anscp) {
+		if (__builtin_expect (anscp != NULL, 1)) {
 			u_char *newp = malloc (MAXPACKET);
 			if (newp == NULL) {
 				*terrno = ENOMEM;
@@ -809,7 +808,7 @@ send_vc(res_state statp,
 			*thisanssizp = MAXPACKET;
 			*thisansp = newp;
 			anhp = (HEADER *) newp;
-			len = resplen;
+			len = rlen;
 		} else {
 			Dprint(statp->options & RES_DEBUG,
 				(stdout, ";; response truncated\n")
@@ -818,9 +817,9 @@ send_vc(res_state statp,
 			len = *thisanssizp;
 		}
 	} else
-		len = resplen;
+		len = rlen;
 
-	if (len < HFIXEDSZ) {
+	if (__builtin_expect (len < HFIXEDSZ, 0)) {
 		/*
 		 * Undersized message.
 		 */
@@ -836,18 +835,18 @@ send_vc(res_state statp,
 		cp += n;
 		len -= n;
 	}
-	if (n <= 0) {
+	if (__builtin_expect (n <= 0, 0)) {
 		*terrno = errno;
 		Perror(statp, stderr, "read(vc)", errno);
 		__res_iclose(statp, false);
 		return (0);
 	}
-	if (truncating) {
+	if (__builtin_expect (truncating, 0)) {
 		/*
 		 * Flush rest of answer so connection stays in synch.
 		 */
 		anhp->tc = 1;
-		len = resplen - *thisanssizp;
+		len = rlen - *thisanssizp;
 		while (len != 0) {
 			char junk[PACKETSZ];
 
@@ -872,7 +871,7 @@ send_vc(res_state statp,
 			(statp->pfcode & RES_PRF_REPLY),
 			(stdout, ";; old answer (unexpected):\n"),
 			*thisansp,
-			(resplen > *thisanssiz) ? *thisanssiz: resplen);
+			(rlen > *thisanssiz) ? *thisanssiz: rlen);
 		goto read_len;
 	}
 
@@ -889,7 +888,7 @@ send_vc(res_state statp,
 	 * All is well, or the error is fatal.  Signal that the
 	 * next nameserver ought not be tried.
 	 */
-	return (resplen);
+	return resplen;
 }
 
 static int
@@ -1084,7 +1083,7 @@ send_dg(res_state statp,
 		*thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp,
 					 *thisanssizp, 0,
 					(struct sockaddr *)&from, &fromlen);
-		if (*thisresplenp <= 0) {
+		if (__builtin_expect (*thisresplenp <= 0, 0)) {
 			if (errno == EINTR || errno == EAGAIN) {
 				need_recompute = 1;
 				goto wait;
@@ -1093,7 +1092,7 @@ send_dg(res_state statp,
 			goto err_out;
 		}
 		*gotsomewhere = 1;
-		if (*thisresplenp < HFIXEDSZ) {
+		if (__builtin_expect (*thisresplenp < HFIXEDSZ, 0)) {
 			/*
 			 * Undersized message.
 			 */