about summary refs log tree commit diff
path: root/resolv/res_send.c
diff options
context:
space:
mode:
Diffstat (limited to 'resolv/res_send.c')
-rw-r--r--resolv/res_send.c1502
1 files changed, 0 insertions, 1502 deletions
diff --git a/resolv/res_send.c b/resolv/res_send.c
deleted file mode 100644
index b7b8ecdfc4..0000000000
--- a/resolv/res_send.c
+++ /dev/null
@@ -1,1502 +0,0 @@
-/* Copyright (C) 2016-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-/*
- * Copyright (c) 1985, 1989, 1993
- *    The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * Portions Copyright (c) 1993 by Digital Equipment Corporation.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies, and that
- * the name of Digital Equipment Corporation not be used in advertising or
- * publicity pertaining to distribution of the document or software without
- * specific, written prior permission.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
-/*
- * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
-/*
- * Send query to name server and wait for reply.
- */
-
-#include <assert.h>
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/poll.h>
-
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <arpa/inet.h>
-#include <sys/ioctl.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <resolv/resolv-internal.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <kernel-features.h>
-#include <libc-diag.h>
-
-#if PACKETSZ > 65536
-#define MAXPACKET       PACKETSZ
-#else
-#define MAXPACKET       65536
-#endif
-
-/* From ev_streams.c.  */
-
-static inline void
-__attribute ((always_inline))
-evConsIovec(void *buf, size_t cnt, struct iovec *vec) {
-	memset(vec, 0xf5, sizeof (*vec));
-	vec->iov_base = buf;
-	vec->iov_len = cnt;
-}
-
-/* From ev_timers.c.  */
-
-#define BILLION 1000000000
-
-static inline void
-evConsTime(struct timespec *res, time_t sec, long nsec) {
-	res->tv_sec = sec;
-	res->tv_nsec = nsec;
-}
-
-static inline void
-evAddTime(struct timespec *res, const struct timespec *addend1,
-	  const struct timespec *addend2) {
-	res->tv_sec = addend1->tv_sec + addend2->tv_sec;
-	res->tv_nsec = addend1->tv_nsec + addend2->tv_nsec;
-	if (res->tv_nsec >= BILLION) {
-		res->tv_sec++;
-		res->tv_nsec -= BILLION;
-	}
-}
-
-static inline void
-evSubTime(struct timespec *res, const struct timespec *minuend,
-	  const struct timespec *subtrahend) {
-       res->tv_sec = minuend->tv_sec - subtrahend->tv_sec;
-	if (minuend->tv_nsec >= subtrahend->tv_nsec)
-		res->tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec;
-	else {
-		res->tv_nsec = (BILLION
-				- subtrahend->tv_nsec + minuend->tv_nsec);
-		res->tv_sec--;
-	}
-}
-
-static int
-evCmpTime(struct timespec a, struct timespec b) {
-	long x = a.tv_sec - b.tv_sec;
-
-	if (x == 0L)
-		x = a.tv_nsec - b.tv_nsec;
-	return (x < 0L ? (-1) : x > 0L ? (1) : (0));
-}
-
-static void
-evNowTime(struct timespec *res) {
-	struct timeval now;
-
-	if (gettimeofday(&now, NULL) < 0)
-		evConsTime(res, 0, 0);
-	else
-		TIMEVAL_TO_TIMESPEC (&now, res);
-}
-
-
-/* Options.  Leave them on. */
-/* #undef DEBUG */
-#include "res_debug.h"
-
-#define EXT(res) ((res)->_u._ext)
-
-/* Forward. */
-
-static struct sockaddr *get_nsaddr (res_state, int);
-static int		send_vc(res_state, const u_char *, int,
-				const u_char *, int,
-				u_char **, int *, int *, int, u_char **,
-				u_char **, int *, int *, int *);
-static int		send_dg(res_state, const u_char *, int,
-				const u_char *, int,
-				u_char **, int *, int *, int,
-				int *, int *, u_char **,
-				u_char **, int *, int *, int *);
-#ifdef DEBUG
-static void		Aerror(const res_state, FILE *, const char *, int,
-			       const struct sockaddr *);
-static void		Perror(const res_state, FILE *, const char *, int);
-#endif
-static int		sock_eq(struct sockaddr_in6 *, struct sockaddr_in6 *);
-
-/* Public. */
-
-/* int
- * res_isourserver(ina)
- *	looks up "ina" in _res.ns_addr_list[]
- * returns:
- *	0  : not found
- *	>0 : found
- * author:
- *	paul vixie, 29may94
- */
-int
-res_ourserver_p(const res_state statp, const struct sockaddr_in6 *inp)
-{
-	int ns;
-
-	if (inp->sin6_family == AF_INET) {
-	    struct sockaddr_in *in4p = (struct sockaddr_in *) inp;
-	    in_port_t port = in4p->sin_port;
-	    in_addr_t addr = in4p->sin_addr.s_addr;
-
-	    for (ns = 0;  ns < statp->nscount;  ns++) {
-		const struct sockaddr_in *srv =
-		    (struct sockaddr_in *) get_nsaddr (statp, ns);
-
-		if ((srv->sin_family == AF_INET) &&
-		    (srv->sin_port == port) &&
-		    (srv->sin_addr.s_addr == INADDR_ANY ||
-		     srv->sin_addr.s_addr == addr))
-		    return (1);
-	    }
-	} else if (inp->sin6_family == AF_INET6) {
-	    for (ns = 0;  ns < statp->nscount;  ns++) {
-		const struct sockaddr_in6 *srv
-		  = (struct sockaddr_in6 *) get_nsaddr (statp, ns);
-		if ((srv->sin6_family == AF_INET6) &&
-		    (srv->sin6_port == inp->sin6_port) &&
-		    !(memcmp(&srv->sin6_addr, &in6addr_any,
-			     sizeof (struct in6_addr)) &&
-		      memcmp(&srv->sin6_addr, &inp->sin6_addr,
-			     sizeof (struct in6_addr))))
-		    return (1);
-	    }
-	}
-	return (0);
-}
-
-/* int
- * res_nameinquery(name, type, class, buf, eom)
- *	look for (name,type,class) in the query section of packet (buf,eom)
- * requires:
- *	buf + HFIXEDSZ <= eom
- * returns:
- *	-1 : format error
- *	0  : not found
- *	>0 : found
- * author:
- *	paul vixie, 29may94
- */
-int
-res_nameinquery(const char *name, int type, int class,
-		const u_char *buf, const u_char *eom)
-{
-	const u_char *cp = buf + HFIXEDSZ;
-	int qdcount = ntohs(((HEADER*)buf)->qdcount);
-
-	while (qdcount-- > 0) {
-		char tname[MAXDNAME+1];
-		int n, ttype, tclass;
-
-		n = dn_expand(buf, eom, cp, tname, sizeof tname);
-		if (n < 0)
-			return (-1);
-		cp += n;
-		if (cp + 2 * INT16SZ > eom)
-			return (-1);
-		NS_GET16(ttype, cp);
-		NS_GET16(tclass, cp);
-		if (ttype == type && tclass == class &&
-		    ns_samename(tname, name) == 1)
-			return (1);
-	}
-	return (0);
-}
-libresolv_hidden_def (res_nameinquery)
-
-/* int
- * res_queriesmatch(buf1, eom1, buf2, eom2)
- *	is there a 1:1 mapping of (name,type,class)
- *	in (buf1,eom1) and (buf2,eom2)?
- * returns:
- *	-1 : format error
- *	0  : not a 1:1 mapping
- *	>0 : is a 1:1 mapping
- * author:
- *	paul vixie, 29may94
- */
-int
-res_queriesmatch(const u_char *buf1, const u_char *eom1,
-		 const u_char *buf2, const u_char *eom2)
-{
-	if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
-		return (-1);
-
-	/*
-	 * Only header section present in replies to
-	 * dynamic update packets.
-	 */
-	if ((((HEADER *)buf1)->opcode == ns_o_update) &&
-	    (((HEADER *)buf2)->opcode == ns_o_update))
-		return (1);
-
-	/* Note that we initially do not convert QDCOUNT to the host byte
-	   order.  We can compare it with the second buffer's QDCOUNT
-	   value without doing this.  */
-	int qdcount = ((HEADER*)buf1)->qdcount;
-	if (qdcount != ((HEADER*)buf2)->qdcount)
-		return (0);
-
-	qdcount = htons (qdcount);
-	const u_char *cp = buf1 + HFIXEDSZ;
-
-	while (qdcount-- > 0) {
-		char tname[MAXDNAME+1];
-		int n, ttype, tclass;
-
-		n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
-		if (n < 0)
-			return (-1);
-		cp += n;
-		if (cp + 2 * INT16SZ > eom1)
-			return (-1);
-		NS_GET16(ttype, cp);
-		NS_GET16(tclass, cp);
-		if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
-			return (0);
-	}
-	return (1);
-}
-libresolv_hidden_def (res_queriesmatch)
-
-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 *resplen2, int *ansp2_malloced)
-{
-  int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
-
-	if (statp->nscount == 0) {
-		__set_errno (ESRCH);
-		return (-1);
-	}
-
-	if (anssiz < (buf2 == NULL ? 1 : 2) * HFIXEDSZ) {
-		__set_errno (EINVAL);
-		return (-1);
-	}
-
-	DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
-		(stdout, ";; res_send()\n"), buf, buflen);
-	v_circuit = ((statp->options & RES_USEVC)
-		     || buflen > PACKETSZ
-		     || buflen2 > PACKETSZ);
-	gotsomewhere = 0;
-	terrno = ETIMEDOUT;
-
-	/*
-	 * If the ns_addr_list in the resolver context has changed, then
-	 * invalidate our cached copy and the associated timing data.
-	 */
-	if (EXT(statp).nscount != 0) {
-		int needclose = 0;
-
-		if (EXT(statp).nscount != statp->nscount)
-			needclose++;
-		else
-			for (ns = 0; ns < statp->nscount; ns++) {
-				if (statp->nsaddr_list[ns].sin_family != 0
-				    && !sock_eq((struct sockaddr_in6 *)
-						&statp->nsaddr_list[ns],
-						EXT(statp).nsaddrs[ns]))
-				{
-					needclose++;
-					break;
-				}
-			}
-		if (needclose) {
-			__res_iclose(statp, false);
-			EXT(statp).nscount = 0;
-		}
-	}
-
-	/*
-	 * Maybe initialize our private copy of the ns_addr_list.
-	 */
-	if (EXT(statp).nscount == 0) {
-		for (ns = 0; ns < statp->nscount; ns++) {
-			EXT(statp).nssocks[ns] = -1;
-			if (statp->nsaddr_list[ns].sin_family == 0)
-				continue;
-			if (EXT(statp).nsaddrs[ns] == NULL)
-				EXT(statp).nsaddrs[ns] =
-				    malloc(sizeof (struct sockaddr_in6));
-			if (EXT(statp).nsaddrs[ns] != NULL)
-				memset (mempcpy(EXT(statp).nsaddrs[ns],
-						&statp->nsaddr_list[ns],
-						sizeof (struct sockaddr_in)),
-					'\0',
-					sizeof (struct sockaddr_in6)
-					- sizeof (struct sockaddr_in));
-		}
-		EXT(statp).nscount = statp->nscount;
-	}
-
-	/*
-	 * Some resolvers want to even out the load on their nameservers.
-	 * Note that RES_BLAST overrides RES_ROTATE.
-	 */
-	if (__glibc_unlikely ((statp->options & RES_ROTATE) != 0)) {
-		struct sockaddr_in ina;
-		struct sockaddr_in6 *inp;
-		int lastns = statp->nscount - 1;
-		int fd;
-
-		inp = EXT(statp).nsaddrs[0];
-		ina = statp->nsaddr_list[0];
-		fd = EXT(statp).nssocks[0];
-		for (ns = 0; ns < lastns; ns++) {
-		    EXT(statp).nsaddrs[ns] = EXT(statp).nsaddrs[ns + 1];
-		    statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
-		    EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
-		}
-		EXT(statp).nsaddrs[lastns] = inp;
-		statp->nsaddr_list[lastns] = ina;
-		EXT(statp).nssocks[lastns] = fd;
-	}
-
-	/*
-	 * Send request, RETRY times, or until successful.
-	 */
-	for (try = 0; try < statp->retry; try++) {
-	    for (ns = 0; ns < statp->nscount; ns++)
-	    {
-#ifdef DEBUG
-		char tmpbuf[40];
-		struct sockaddr *nsap = get_nsaddr (statp, ns);
-#endif
-
-	    same_ns:
-		Dprint(statp->options & RES_DEBUG,
-		       (stdout, ";; Querying server (# %d) address = %s\n",
-			ns + 1, inet_ntop(nsap->sa_family,
-					  (nsap->sa_family == AF_INET6
-					   ? (void *) &((struct sockaddr_in6 *) nsap)->sin6_addr
-					   : (void *) &((struct sockaddr_in *) nsap)->sin_addr),
-					  tmpbuf, sizeof (tmpbuf))));
-
-		if (__glibc_unlikely (v_circuit))       {
-			/* Use VC; at most one attempt per server. */
-			try = statp->retry;
-			n = send_vc(statp, buf, buflen, buf2, buflen2,
-				    &ans, &anssiz, &terrno,
-				    ns, ansp, ansp2, nansp2, resplen2,
-				    ansp2_malloced);
-			if (n < 0)
-				return (-1);
-			if (n == 0 && (buf2 == NULL || *resplen2 == 0))
-				goto next_ns;
-		} else {
-			/* Use datagrams. */
-			n = send_dg(statp, buf, buflen, buf2, buflen2,
-				    &ans, &anssiz, &terrno,
-				    ns, &v_circuit, &gotsomewhere, ansp,
-				    ansp2, nansp2, resplen2, ansp2_malloced);
-			if (n < 0)
-				return (-1);
-			if (n == 0 && (buf2 == NULL || *resplen2 == 0))
-				goto next_ns;
-			if (v_circuit)
-			  // XXX Check whether both requests failed or
-			  // XXX whether one has been answered successfully
-				goto same_ns;
-		}
-
-		resplen = n;
-
-		Dprint((statp->options & RES_DEBUG) ||
-		       ((statp->pfcode & RES_PRF_REPLY) &&
-			(statp->pfcode & RES_PRF_HEAD1)),
-		       (stdout, ";; got answer:\n"));
-
-		DprintQ((statp->options & RES_DEBUG) ||
-			(statp->pfcode & RES_PRF_REPLY),
-			(stdout, "%s", ""),
-			ans, (resplen > anssiz) ? anssiz : resplen);
-		if (buf2 != NULL) {
-		  DprintQ((statp->options & RES_DEBUG) ||
-			  (statp->pfcode & RES_PRF_REPLY),
-			  (stdout, "%s", ""),
-			  *ansp2, (*resplen2 > *nansp2) ? *nansp2 : *resplen2);
-		}
-
-		/*
-		 * If we have temporarily opened a virtual circuit,
-		 * or if we haven't been asked to keep a socket open,
-		 * close the socket.
-		 */
-		if ((v_circuit && (statp->options & RES_USEVC) == 0) ||
-		    (statp->options & RES_STAYOPEN) == 0) {
-			__res_iclose(statp, false);
-		}
-		return (resplen);
- next_ns: ;
-	   } /*foreach ns*/
-	} /*foreach retry*/
-	__res_iclose(statp, false);
-	if (!v_circuit) {
-		if (!gotsomewhere)
-			__set_errno (ECONNREFUSED);	/* no nameservers found */
-		else
-			__set_errno (ETIMEDOUT);	/* no answer obtained */
-	} else
-		__set_errno (terrno);
-	return (-1);
-}
-
-int
-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);
-}
-libresolv_hidden_def (res_nsend)
-
-/* Private */
-
-static struct sockaddr *
-get_nsaddr (res_state statp, int n)
-{
-
-  if (statp->nsaddr_list[n].sin_family == 0 && EXT(statp).nsaddrs[n] != NULL)
-    /* EXT(statp).nsaddrs[n] holds an address that is larger than
-       struct sockaddr, and user code did not update
-       statp->nsaddr_list[n].  */
-    return (struct sockaddr *) EXT(statp).nsaddrs[n];
-  else
-    /* User code updated statp->nsaddr_list[n], or statp->nsaddr_list[n]
-       has the same content as EXT(statp).nsaddrs[n].  */
-    return (struct sockaddr *) (void *) &statp->nsaddr_list[n];
-}
-
-/* Close the resolver structure, assign zero to *RESPLEN2 if RESPLEN2
-   is not NULL, and return zero.  */
-static int
-__attribute__ ((warn_unused_result))
-close_and_return_error (res_state statp, int *resplen2)
-{
-  __res_iclose(statp, false);
-  if (resplen2 != NULL)
-    *resplen2 = 0;
-  return 0;
-}
-
-/* The send_vc function is responsible for sending a DNS query over TCP
-   to the nameserver numbered NS from the res_state STATP i.e.
-   EXT(statp).nssocks[ns].  The function supports sending both IPv4 and
-   IPv6 queries at the same serially on the same socket.
-
-   Please note that for TCP there is no way to disable sending both
-   queries, unlike UDP, which honours RES_SNGLKUP and RES_SNGLKUPREOP
-   and sends the queries serially and waits for the result after each
-   sent query.  This implementation should be corrected to honour these
-   options.
-
-   Please also note that for TCP we send both queries over the same
-   socket one after another.  This technically violates best practice
-   since the server is allowed to read the first query, respond, and
-   then close the socket (to service another client).  If the server
-   does this, then the remaining second query in the socket data buffer
-   will cause the server to send the client an RST which will arrive
-   asynchronously and the client's OS will likely tear down the socket
-   receive buffer resulting in a potentially short read and lost
-   response data.  This will force the client to retry the query again,
-   and this process may repeat until all servers and connection resets
-   are exhausted and then the query will fail.  It's not known if this
-   happens with any frequency in real DNS server implementations.  This
-   implementation should be corrected to use two sockets by default for
-   parallel queries.
-
-   The query stored in BUF of BUFLEN length is sent first followed by
-   the query stored in BUF2 of BUFLEN2 length.  Queries are sent
-   serially on the same socket.
-
-   Answers to the query are stored firstly in *ANSP up to a max of
-   *ANSSIZP bytes.  If more than *ANSSIZP bytes are needed and ANSCP
-   is non-NULL (to indicate that modifying the answer buffer is allowed)
-   then malloc is used to allocate a new response buffer and ANSCP and
-   ANSP will both point to the new buffer.  If more than *ANSSIZP bytes
-   are needed but ANSCP is NULL, then as much of the response as
-   possible is read into the buffer, but the results will be truncated.
-   When truncation happens because of a small answer buffer the DNS
-   packets header field TC will bet set to 1, indicating a truncated
-   message and the rest of the socket data will be read and discarded.
-
-   Answers to the query are stored secondly in *ANSP2 up to a max of
-   *ANSSIZP2 bytes, with the actual response length stored in
-   *RESPLEN2.  If more than *ANSSIZP bytes are needed and ANSP2
-   is non-NULL (required for a second query) then malloc is used to
-   allocate a new response buffer, *ANSSIZP2 is set to the new buffer
-   size and *ANSP2_MALLOCED is set to 1.
-
-   The ANSP2_MALLOCED argument will eventually be removed as the
-   change in buffer pointer can be used to detect the buffer has
-   changed and that the caller should use free on the new buffer.
-
-   Note that the answers may arrive in any order from the server and
-   therefore the first and second answer buffers may not correspond to
-   the first and second queries.
-
-   It is not supported to call this function with a non-NULL ANSP2
-   but a NULL ANSCP.  Put another way, you can call send_vc with a
-   single unmodifiable buffer or two modifiable buffers, but no other
-   combination is supported.
-
-   It is the caller's responsibility to free the malloc allocated
-   buffers by detecting that the pointers have changed from their
-   original values i.e. *ANSCP or *ANSP2 has changed.
-
-   If errors are encountered then *TERRNO is set to an appropriate
-   errno value and a zero result is returned for a recoverable error,
-   and a less-than zero result is returned for a non-recoverable error.
-
-   If no errors are encountered then *TERRNO is left unmodified and
-   a the length of the first response in bytes is returned.  */
-static int
-send_vc(res_state statp,
-	const u_char *buf, int buflen, const u_char *buf2, int buflen2,
-	u_char **ansp, int *anssizp,
-	int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
-	int *resplen2, int *ansp2_malloced)
-{
-	const HEADER *hp = (HEADER *) buf;
-	const HEADER *hp2 = (HEADER *) buf2;
-	HEADER *anhp = (HEADER *) *ansp;
-	struct sockaddr *nsap = get_nsaddr (statp, ns);
-	int truncating, connreset, n;
-	/* On some architectures compiler might emit a warning indicating
-	   'resplen' may be used uninitialized.  However if buf2 == NULL
-	   then this code won't be executed; if buf2 != NULL, then first
-	   time round the loop recvresp1 and recvresp2 will be 0 so this
-	   code won't be executed but "thisresplenp = &resplen;" followed
-	   by "*thisresplenp = rlen;" will be executed so that subsequent
-	   times round the loop resplen has been initialized.  So this is
-	   a false-positive.
-	 */
-	DIAG_PUSH_NEEDS_COMMENT;
-	DIAG_IGNORE_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
-	int resplen;
-	DIAG_POP_NEEDS_COMMENT;
-	struct iovec iov[4];
-	u_short len;
-	u_short len2;
-	u_char *cp;
-
-	connreset = 0;
- same_ns:
-	truncating = 0;
-
-	/* Are we still talking to whom we want to talk to? */
-	if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
-		struct sockaddr_in6 peer;
-		socklen_t size = sizeof peer;
-
-		if (getpeername(statp->_vcsock,
-				(struct sockaddr *)&peer, &size) < 0 ||
-		    !sock_eq(&peer, (struct sockaddr_in6 *) nsap)) {
-			__res_iclose(statp, false);
-			statp->_flags &= ~RES_F_VC;
-		}
-	}
-
-	if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
-		if (statp->_vcsock >= 0)
-		  __res_iclose(statp, false);
-
-		statp->_vcsock = socket
-		  (nsap->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
-		if (statp->_vcsock < 0) {
-			*terrno = errno;
-			Perror(statp, stderr, "socket(vc)", errno);
-			if (resplen2 != NULL)
-			  *resplen2 = 0;
-			return (-1);
-		}
-		__set_errno (0);
-		if (connect(statp->_vcsock, nsap,
-			    nsap->sa_family == AF_INET
-			    ? sizeof (struct sockaddr_in)
-			    : sizeof (struct sockaddr_in6)) < 0) {
-			*terrno = errno;
-			Aerror(statp, stderr, "connect/vc", errno, nsap);
-			return close_and_return_error (statp, resplen2);
-		}
-		statp->_flags |= RES_F_VC;
-	}
-
-	/*
-	 * Send length & message
-	 */
-	len = htons ((u_short) buflen);
-	evConsIovec(&len, INT16SZ, &iov[0]);
-	evConsIovec((void*)buf, buflen, &iov[1]);
-	int niov = 2;
-	ssize_t explen = INT16SZ + buflen;
-	if (buf2 != NULL) {
-		len2 = htons ((u_short) buflen2);
-		evConsIovec(&len2, INT16SZ, &iov[2]);
-		evConsIovec((void*)buf2, buflen2, &iov[3]);
-		niov = 4;
-		explen += INT16SZ + buflen2;
-	}
-	if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
-		*terrno = errno;
-		Perror(statp, stderr, "write failed", errno);
-		return close_and_return_error (statp, resplen2);
-	}
-	/*
-	 * Receive length & response
-	 */
-	int recvresp1 = 0;
-	/* Skip the second response if there is no second query.
-	   To do that we mark the second response as received.  */
-	int recvresp2 = buf2 == NULL;
-	uint16_t rlen16;
- read_len:
-	cp = (u_char *)&rlen16;
-	len = sizeof(rlen16);
-	while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, cp,
-					     (int)len))) > 0) {
-		cp += n;
-		if ((len -= n) <= 0)
-			break;
-	}
-	if (n <= 0) {
-		*terrno = errno;
-		Perror(statp, stderr, "read failed", errno);
-		/*
-		 * A long running process might get its TCP
-		 * connection reset if the remote server was
-		 * restarted.  Requery the server instead of
-		 * trying a new one.  When there is only one
-		 * server, this means that a query might work
-		 * instead of failing.  We only allow one reset
-		 * per query to prevent looping.
-		 */
-		if (*terrno == ECONNRESET && !connreset)
-		  {
-		    __res_iclose (statp, false);
-		    connreset = 1;
-		    goto same_ns;
-		  }
-		return close_and_return_error (statp, resplen2);
-	}
-	int rlen = ntohs (rlen16);
-
-	int *thisanssizp;
-	u_char **thisansp;
-	int *thisresplenp;
-	if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
-		/* We have not received any responses
-		   yet or we only have one response to
-		   receive.  */
-		thisanssizp = anssizp;
-		thisansp = anscp ?: ansp;
-		assert (anscp != NULL || ansp2 == NULL);
-		thisresplenp = &resplen;
-	} else {
-		thisanssizp = anssizp2;
-		thisansp = ansp2;
-		thisresplenp = resplen2;
-	}
-	anhp = (HEADER *) *thisansp;
-
-	*thisresplenp = rlen;
-	/* Is the answer buffer too small?  */
-	if (*thisanssizp < rlen) {
-		/* If the current buffer is not the the static
-		   user-supplied buffer then we can reallocate
-		   it.  */
-		if (thisansp != NULL && thisansp != ansp) {
-			/* Always allocate MAXPACKET, callers expect
-			   this specific size.  */
-			u_char *newp = malloc (MAXPACKET);
-			if (newp == NULL)
-			  {
-			    *terrno = ENOMEM;
-			    return close_and_return_error (statp, resplen2);
-			  }
-			*thisanssizp = MAXPACKET;
-			*thisansp = newp;
-			if (thisansp == ansp2)
-			  *ansp2_malloced = 1;
-			anhp = (HEADER *) newp;
-			/* A uint16_t can't be larger than MAXPACKET
-			   thus it's safe to allocate MAXPACKET but
-			   read RLEN bytes instead.  */
-			len = rlen;
-		} else {
-			Dprint(statp->options & RES_DEBUG,
-				(stdout, ";; response truncated\n")
-			);
-			truncating = 1;
-			len = *thisanssizp;
-		}
-	} else
-		len = rlen;
-
-	if (__glibc_unlikely (len < HFIXEDSZ))       {
-		/*
-		 * Undersized message.
-		 */
-		Dprint(statp->options & RES_DEBUG,
-		       (stdout, ";; undersized: %d\n", len));
-		*terrno = EMSGSIZE;
-		return close_and_return_error (statp, resplen2);
-	}
-
-	cp = *thisansp;
-	while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
-		cp += n;
-		len -= n;
-	}
-	if (__glibc_unlikely (n <= 0))       {
-		*terrno = errno;
-		Perror(statp, stderr, "read(vc)", errno);
-		return close_and_return_error (statp, resplen2);
-	}
-	if (__glibc_unlikely (truncating))       {
-		/*
-		 * Flush rest of answer so connection stays in synch.
-		 */
-		anhp->tc = 1;
-		len = rlen - *thisanssizp;
-		while (len != 0) {
-			char junk[PACKETSZ];
-
-			n = read(statp->_vcsock, junk,
-				 (len > sizeof junk) ? sizeof junk : len);
-			if (n > 0)
-				len -= n;
-			else
-				break;
-		}
-	}
-	/*
-	 * If the calling application has bailed out of
-	 * a previous call and failed to arrange to have
-	 * the circuit closed or the server has got
-	 * itself confused, then drop the packet and
-	 * wait for the correct one.
-	 */
-	if ((recvresp1 || hp->id != anhp->id)
-	    && (recvresp2 || hp2->id != anhp->id)) {
-		DprintQ((statp->options & RES_DEBUG) ||
-			(statp->pfcode & RES_PRF_REPLY),
-			(stdout, ";; old answer (unexpected):\n"),
-			*thisansp,
-			(rlen > *thisanssizp) ? *thisanssizp: rlen);
-		goto read_len;
-	}
-
-	/* Mark which reply we received.  */
-	if (recvresp1 == 0 && hp->id == anhp->id)
-	  recvresp1 = 1;
-	else
-	  recvresp2 = 1;
-	/* Repeat waiting if we have a second answer to arrive.  */
-	if ((recvresp1 & recvresp2) == 0)
-		goto read_len;
-
-	/*
-	 * All is well, or the error is fatal.  Signal that the
-	 * next nameserver ought not be tried.
-	 */
-	return resplen;
-}
-
-static int
-reopen (res_state statp, int *terrno, int ns)
-{
-	if (EXT(statp).nssocks[ns] == -1) {
-		struct sockaddr *nsap = get_nsaddr (statp, ns);
-		socklen_t slen;
-
-		/* only try IPv6 if IPv6 NS and if not failed before */
-		if (nsap->sa_family == AF_INET6 && !statp->ipv6_unavail) {
-			EXT(statp).nssocks[ns] = socket
-			  (PF_INET6,
-			   SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
-			if (EXT(statp).nssocks[ns] < 0)
-			    statp->ipv6_unavail = errno == EAFNOSUPPORT;
-			slen = sizeof (struct sockaddr_in6);
-		} else if (nsap->sa_family == AF_INET) {
-			EXT(statp).nssocks[ns] = socket
-			  (PF_INET,
-			   SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
-			slen = sizeof (struct sockaddr_in);
-		}
-		if (EXT(statp).nssocks[ns] < 0) {
-			*terrno = errno;
-			Perror(statp, stderr, "socket(dg)", errno);
-			return (-1);
-		}
-
-		/*
-		 * On a 4.3BSD+ machine (client and server,
-		 * actually), sending to a nameserver datagram
-		 * port with no nameserver will cause an
-		 * ICMP port unreachable message to be returned.
-		 * If our datagram socket is "connected" to the
-		 * server, we get an ECONNREFUSED error on the next
-		 * socket operation, and select returns if the
-		 * error message is received.  We can thus detect
-		 * the absence of a nameserver without timing out.
-		 */
-		/* With GCC 5.3 when compiling with -Os the compiler
-		   emits a warning that slen may be used uninitialized,
-		   but that is never true.  Both slen and
-		   EXT(statp).nssocks[ns] are initialized together or
-		   the function return -1 before control flow reaches
-		   the call to connect with slen.  */
-		DIAG_PUSH_NEEDS_COMMENT;
-		DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
-		if (connect(EXT(statp).nssocks[ns], nsap, slen) < 0) {
-		DIAG_POP_NEEDS_COMMENT;
-			Aerror(statp, stderr, "connect(dg)", errno, nsap);
-			__res_iclose(statp, false);
-			return (0);
-		}
-	}
-
-	return 1;
-}
-
-/* The send_dg function is responsible for sending a DNS query over UDP
-   to the nameserver numbered NS from the res_state STATP i.e.
-   EXT(statp).nssocks[ns].  The function supports IPv4 and IPv6 queries
-   along with the ability to send the query in parallel for both stacks
-   (default) or serially (RES_SINGLKUP).  It also supports serial lookup
-   with a close and reopen of the socket used to talk to the server
-   (RES_SNGLKUPREOP) to work around broken name servers.
-
-   The query stored in BUF of BUFLEN length is sent first followed by
-   the query stored in BUF2 of BUFLEN2 length.  Queries are sent
-   in parallel (default) or serially (RES_SINGLKUP or RES_SNGLKUPREOP).
-
-   Answers to the query are stored firstly in *ANSP up to a max of
-   *ANSSIZP bytes.  If more than *ANSSIZP bytes are needed and ANSCP
-   is non-NULL (to indicate that modifying the answer buffer is allowed)
-   then malloc is used to allocate a new response buffer and ANSCP and
-   ANSP will both point to the new buffer.  If more than *ANSSIZP bytes
-   are needed but ANSCP is NULL, then as much of the response as
-   possible is read into the buffer, but the results will be truncated.
-   When truncation happens because of a small answer buffer the DNS
-   packets header field TC will bet set to 1, indicating a truncated
-   message, while the rest of the UDP packet is discarded.
-
-   Answers to the query are stored secondly in *ANSP2 up to a max of
-   *ANSSIZP2 bytes, with the actual response length stored in
-   *RESPLEN2.  If more than *ANSSIZP bytes are needed and ANSP2
-   is non-NULL (required for a second query) then malloc is used to
-   allocate a new response buffer, *ANSSIZP2 is set to the new buffer
-   size and *ANSP2_MALLOCED is set to 1.
-
-   The ANSP2_MALLOCED argument will eventually be removed as the
-   change in buffer pointer can be used to detect the buffer has
-   changed and that the caller should use free on the new buffer.
-
-   Note that the answers may arrive in any order from the server and
-   therefore the first and second answer buffers may not correspond to
-   the first and second queries.
-
-   It is not supported to call this function with a non-NULL ANSP2
-   but a NULL ANSCP.  Put another way, you can call send_vc with a
-   single unmodifiable buffer or two modifiable buffers, but no other
-   combination is supported.
-
-   It is the caller's responsibility to free the malloc allocated
-   buffers by detecting that the pointers have changed from their
-   original values i.e. *ANSCP or *ANSP2 has changed.
-
-   If an answer is truncated because of UDP datagram DNS limits then
-   *V_CIRCUIT is set to 1 and the return value non-zero to indicate to
-   the caller to retry with TCP.  The value *GOTSOMEWHERE is set to 1
-   if any progress was made reading a response from the nameserver and
-   is used by the caller to distinguish between ECONNREFUSED and
-   ETIMEDOUT (the latter if *GOTSOMEWHERE is 1).
-
-   If errors are encountered then *TERRNO is set to an appropriate
-   errno value and a zero result is returned for a recoverable error,
-   and a less-than zero result is returned for a non-recoverable error.
-
-   If no errors are encountered then *TERRNO is left unmodified and
-   a the length of the first response in bytes is returned.  */
-static int
-send_dg(res_state statp,
-	const u_char *buf, int buflen, const u_char *buf2, int buflen2,
-	u_char **ansp, int *anssizp,
-	int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
-	u_char **ansp2, int *anssizp2, int *resplen2, int *ansp2_malloced)
-{
-	const HEADER *hp = (HEADER *) buf;
-	const HEADER *hp2 = (HEADER *) buf2;
-	struct timespec now, timeout, finish;
-	struct pollfd pfd[1];
-	int ptimeout;
-	struct sockaddr_in6 from;
-	int resplen = 0;
-	int n;
-
-	/*
-	 * Compute time for the total operation.
-	 */
-	int seconds = (statp->retrans << ns);
-	if (ns > 0)
-		seconds /= statp->nscount;
-	if (seconds <= 0)
-		seconds = 1;
-	bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0;
-	bool single_request = (((statp->options & RES_SNGLKUP) != 0)
-			       | single_request_reopen);
-	int save_gotsomewhere = *gotsomewhere;
-
-	int retval;
- retry_reopen:
-	retval = reopen (statp, terrno, ns);
-	if (retval <= 0)
-	  {
-	    if (resplen2 != NULL)
-	      *resplen2 = 0;
-	    return retval;
-	  }
- retry:
-	evNowTime(&now);
-	evConsTime(&timeout, seconds, 0);
-	evAddTime(&finish, &now, &timeout);
-	int need_recompute = 0;
-	int nwritten = 0;
-	int recvresp1 = 0;
-	/* Skip the second response if there is no second query.
-	   To do that we mark the second response as received.  */
-	int recvresp2 = buf2 == NULL;
-	pfd[0].fd = EXT(statp).nssocks[ns];
-	pfd[0].events = POLLOUT;
- wait:
-	if (need_recompute) {
-	recompute_resend:
-		evNowTime(&now);
-		if (evCmpTime(finish, now) <= 0) {
-		poll_err_out:
-			Perror(statp, stderr, "poll", errno);
-			return close_and_return_error (statp, resplen2);
-		}
-		evSubTime(&timeout, &finish, &now);
-		need_recompute = 0;
-	}
-	/* Convert struct timespec in milliseconds.  */
-	ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
-
-	n = 0;
-	if (nwritten == 0)
-	  n = __poll (pfd, 1, 0);
-	if (__glibc_unlikely (n == 0))       {
-		n = __poll (pfd, 1, ptimeout);
-		need_recompute = 1;
-	}
-	if (n == 0) {
-		Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
-		if (resplen > 1 && (recvresp1 || (buf2 != NULL && recvresp2)))
-		  {
-		    /* There are quite a few broken name servers out
-		       there which don't handle two outstanding
-		       requests from the same source.  There are also
-		       broken firewall settings.  If we time out after
-		       having received one answer switch to the mode
-		       where we send the second request only once we
-		       have received the first answer.  */
-		    if (!single_request)
-		      {
-			statp->options |= RES_SNGLKUP;
-			single_request = true;
-			*gotsomewhere = save_gotsomewhere;
-			goto retry;
-		      }
-		    else if (!single_request_reopen)
-		      {
-			statp->options |= RES_SNGLKUPREOP;
-			single_request_reopen = true;
-			*gotsomewhere = save_gotsomewhere;
-			__res_iclose (statp, false);
-			goto retry_reopen;
-		      }
-
-		    *resplen2 = 1;
-		    return resplen;
-		  }
-
-		*gotsomewhere = 1;
-		if (resplen2 != NULL)
-		  *resplen2 = 0;
-		return 0;
-	}
-	if (n < 0) {
-		if (errno == EINTR)
-			goto recompute_resend;
-
-		goto poll_err_out;
-	}
-	__set_errno (0);
-	if (pfd[0].revents & POLLOUT) {
-#ifndef __ASSUME_SENDMMSG
-		static int have_sendmmsg;
-#else
-# define have_sendmmsg 1
-#endif
-		if (have_sendmmsg >= 0 && nwritten == 0 && buf2 != NULL
-		    && !single_request)
-		  {
-		    struct iovec iov[2];
-		    struct mmsghdr reqs[2];
-		    reqs[0].msg_hdr.msg_name = NULL;
-		    reqs[0].msg_hdr.msg_namelen = 0;
-		    reqs[0].msg_hdr.msg_iov = &iov[0];
-		    reqs[0].msg_hdr.msg_iovlen = 1;
-		    iov[0].iov_base = (void *) buf;
-		    iov[0].iov_len = buflen;
-		    reqs[0].msg_hdr.msg_control = NULL;
-		    reqs[0].msg_hdr.msg_controllen = 0;
-
-		    reqs[1].msg_hdr.msg_name = NULL;
-		    reqs[1].msg_hdr.msg_namelen = 0;
-		    reqs[1].msg_hdr.msg_iov = &iov[1];
-		    reqs[1].msg_hdr.msg_iovlen = 1;
-		    iov[1].iov_base = (void *) buf2;
-		    iov[1].iov_len = buflen2;
-		    reqs[1].msg_hdr.msg_control = NULL;
-		    reqs[1].msg_hdr.msg_controllen = 0;
-
-		    int ndg = __sendmmsg (pfd[0].fd, reqs, 2, MSG_NOSIGNAL);
-		    if (__glibc_likely (ndg == 2))
-		      {
-			if (reqs[0].msg_len != buflen
-			    || reqs[1].msg_len != buflen2)
-			  goto fail_sendmmsg;
-
-			pfd[0].events = POLLIN;
-			nwritten += 2;
-		      }
-		    else if (ndg == 1 && reqs[0].msg_len == buflen)
-		      goto just_one;
-		    else if (ndg < 0 && (errno == EINTR || errno == EAGAIN))
-		      goto recompute_resend;
-		    else
-		      {
-#ifndef __ASSUME_SENDMMSG
-			if (__glibc_unlikely (have_sendmmsg == 0))
-			  {
-			    if (ndg < 0 && errno == ENOSYS)
-			      {
-				have_sendmmsg = -1;
-				goto try_send;
-			      }
-			    have_sendmmsg = 1;
-			  }
-#endif
-
-		      fail_sendmmsg:
-			Perror(statp, stderr, "sendmmsg", errno);
-			return close_and_return_error (statp, resplen2);
-		      }
-		  }
-		else
-		  {
-		    ssize_t sr;
-#ifndef __ASSUME_SENDMMSG
-		  try_send:
-#endif
-		    if (nwritten != 0)
-		      sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL);
-		    else
-		      sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL);
-
-		    if (sr != (nwritten != 0 ? buflen2 : buflen)) {
-		      if (errno == EINTR || errno == EAGAIN)
-			goto recompute_resend;
-		      Perror(statp, stderr, "send", errno);
-		      return close_and_return_error (statp, resplen2);
-		    }
-		  just_one:
-		    if (nwritten != 0 || buf2 == NULL || single_request)
-		      pfd[0].events = POLLIN;
-		    else
-		      pfd[0].events = POLLIN | POLLOUT;
-		    ++nwritten;
-		  }
-		goto wait;
-	} else if (pfd[0].revents & POLLIN) {
-		int *thisanssizp;
-		u_char **thisansp;
-		int *thisresplenp;
-
-		if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
-			/* We have not received any responses
-			   yet or we only have one response to
-			   receive.  */
-			thisanssizp = anssizp;
-			thisansp = anscp ?: ansp;
-			assert (anscp != NULL || ansp2 == NULL);
-			thisresplenp = &resplen;
-		} else {
-			thisanssizp = anssizp2;
-			thisansp = ansp2;
-			thisresplenp = resplen2;
-		}
-
-		if (*thisanssizp < MAXPACKET
-		    /* If the current buffer is not the the static
-		       user-supplied buffer then we can reallocate
-		       it.  */
-		    && (thisansp != NULL && thisansp != ansp)
-#ifdef FIONREAD
-		    /* Is the size too small?  */
-		    && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
-			|| *thisanssizp < *thisresplenp)
-#endif
-                    ) {
-			/* Always allocate MAXPACKET, callers expect
-			   this specific size.  */
-			u_char *newp = malloc (MAXPACKET);
-			if (newp != NULL) {
-				*thisanssizp = MAXPACKET;
-				*thisansp = newp;
-				if (thisansp == ansp2)
-				  *ansp2_malloced = 1;
-			}
-		}
-		/* We could end up with truncation if anscp was NULL
-		   (not allowed to change caller's buffer) and the
-		   response buffer size is too small.  This isn't a
-		   reliable way to detect truncation because the ioctl
-		   may be an inaccurate report of the UDP message size.
-		   Therefore we use this only to issue debug output.
-		   To do truncation accurately with UDP we need
-		   MSG_TRUNC which is only available on Linux.  We
-		   can abstract out the Linux-specific feature in the
-		   future to detect truncation.  */
-		if (__glibc_unlikely (*thisanssizp < *thisresplenp)) {
-			Dprint(statp->options & RES_DEBUG,
-			       (stdout, ";; response may be truncated (UDP)\n")
-			);
-		}
-
-		HEADER *anhp = (HEADER *) *thisansp;
-		socklen_t fromlen = sizeof(struct sockaddr_in6);
-		assert (sizeof(from) <= fromlen);
-		*thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp,
-					 *thisanssizp, 0,
-					(struct sockaddr *)&from, &fromlen);
-		if (__glibc_unlikely (*thisresplenp <= 0))       {
-			if (errno == EINTR || errno == EAGAIN) {
-				need_recompute = 1;
-				goto wait;
-			}
-			Perror(statp, stderr, "recvfrom", errno);
-			return close_and_return_error (statp, resplen2);
-		}
-		*gotsomewhere = 1;
-		if (__glibc_unlikely (*thisresplenp < HFIXEDSZ))       {
-			/*
-			 * Undersized message.
-			 */
-			Dprint(statp->options & RES_DEBUG,
-			       (stdout, ";; undersized: %d\n",
-				*thisresplenp));
-			*terrno = EMSGSIZE;
-			return close_and_return_error (statp, resplen2);
-		}
-		if ((recvresp1 || hp->id != anhp->id)
-		    && (recvresp2 || hp2->id != anhp->id)) {
-			/*
-			 * response from old query, ignore it.
-			 * XXX - potential security hazard could
-			 *	 be detected here.
-			 */
-			DprintQ((statp->options & RES_DEBUG) ||
-				(statp->pfcode & RES_PRF_REPLY),
-				(stdout, ";; old answer:\n"),
-				*thisansp,
-				(*thisresplenp > *thisanssizp)
-				? *thisanssizp : *thisresplenp);
-			goto wait;
-		}
-		if (!(statp->options & RES_INSECURE1) &&
-		    !res_ourserver_p(statp, &from)) {
-			/*
-			 * response from wrong server? ignore it.
-			 * XXX - potential security hazard could
-			 *	 be detected here.
-			 */
-			DprintQ((statp->options & RES_DEBUG) ||
-				(statp->pfcode & RES_PRF_REPLY),
-				(stdout, ";; not our server:\n"),
-				*thisansp,
-				(*thisresplenp > *thisanssizp)
-				? *thisanssizp : *thisresplenp);
-			goto wait;
-		}
-		if (!(statp->options & RES_INSECURE2)
-		    && (recvresp1 || !res_queriesmatch(buf, buf + buflen,
-						       *thisansp,
-						       *thisansp
-						       + *thisanssizp))
-		    && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
-						       *thisansp,
-						       *thisansp
-						       + *thisanssizp))) {
-			/*
-			 * response contains wrong query? ignore it.
-			 * XXX - potential security hazard could
-			 *	 be detected here.
-			 */
-			DprintQ((statp->options & RES_DEBUG) ||
-				(statp->pfcode & RES_PRF_REPLY),
-				(stdout, ";; wrong query name:\n"),
-				*thisansp,
-				(*thisresplenp > *thisanssizp)
-				? *thisanssizp : *thisresplenp);
-			goto wait;
-		}
-		if (anhp->rcode == SERVFAIL ||
-		    anhp->rcode == NOTIMP ||
-		    anhp->rcode == REFUSED) {
-			DprintQ(statp->options & RES_DEBUG,
-				(stdout, "server rejected query:\n"),
-				*thisansp,
-				(*thisresplenp > *thisanssizp)
-				? *thisanssizp : *thisresplenp);
-
-		next_ns:
-			if (recvresp1 || (buf2 != NULL && recvresp2)) {
-			  *resplen2 = 0;
-			  return resplen;
-			}
-			if (buf2 != NULL)
-			  {
-			    /* No data from the first reply.  */
-			    resplen = 0;
-			    /* We are waiting for a possible second reply.  */
-			    if (hp->id == anhp->id)
-			      recvresp1 = 1;
-			    else
-			      recvresp2 = 1;
-
-			    goto wait;
-			  }
-
-			/* don't retry if called from dig */
-			if (!statp->pfcode)
-			  return close_and_return_error (statp, resplen2);
-			__res_iclose(statp, false);
-		}
-		if (anhp->rcode == NOERROR && anhp->ancount == 0
-		    && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
-			DprintQ(statp->options & RES_DEBUG,
-				(stdout, "referred query:\n"),
-				*thisansp,
-				(*thisresplenp > *thisanssizp)
-				? *thisanssizp : *thisresplenp);
-			goto next_ns;
-		}
-		if (!(statp->options & RES_IGNTC) && anhp->tc) {
-			/*
-			 * To get the rest of answer,
-			 * use TCP with same server.
-			 */
-			Dprint(statp->options & RES_DEBUG,
-			       (stdout, ";; truncated answer\n"));
-			*v_circuit = 1;
-			__res_iclose(statp, false);
-			// XXX if we have received one reply we could
-			// XXX use it and not repeat it over TCP...
-			if (resplen2 != NULL)
-			  *resplen2 = 0;
-			return (1);
-		}
-		/* Mark which reply we received.  */
-		if (recvresp1 == 0 && hp->id == anhp->id)
-			recvresp1 = 1;
-		else
-			recvresp2 = 1;
-		/* Repeat waiting if we have a second answer to arrive.  */
-		if ((recvresp1 & recvresp2) == 0) {
-			if (single_request) {
-				pfd[0].events = POLLOUT;
-				if (single_request_reopen) {
-					__res_iclose (statp, false);
-					retval = reopen (statp, terrno, ns);
-					if (retval <= 0)
-					  {
-					    if (resplen2 != NULL)
-					      *resplen2 = 0;
-					    return retval;
-					  }
-					pfd[0].fd = EXT(statp).nssocks[ns];
-				}
-			}
-			goto wait;
-		}
-		/* All is well.  We have received both responses (if
-		   two responses were requested).  */
-		return (resplen);
-	} else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))
-	  /* Something went wrong.  We can stop trying.  */
-	  return close_and_return_error (statp, resplen2);
-	else {
-		/* poll should not have returned > 0 in this case.  */
-		abort ();
-	}
-}
-
-#ifdef DEBUG
-static void
-Aerror(const res_state statp, FILE *file, const char *string, int error,
-       const struct sockaddr *address)
-{
-	int save = errno;
-
-	if ((statp->options & RES_DEBUG) != 0) {
-		char tmp[sizeof "xxxx.xxxx.xxxx.255.255.255.255"];
-
-		fprintf(file, "res_send: %s ([%s].%u): %s\n",
-			string,
-			(address->sa_family == AF_INET
-			 ? inet_ntop(address->sa_family,
-				     &((const struct sockaddr_in *) address)->sin_addr,
-				     tmp, sizeof tmp)
-			 : inet_ntop(address->sa_family,
-				     &((const struct sockaddr_in6 *) address)->sin6_addr,
-				     tmp, sizeof tmp)),
-			(address->sa_family == AF_INET
-			 ? ntohs(((struct sockaddr_in *) address)->sin_port)
-			 : address->sa_family == AF_INET6
-			 ? ntohs(((struct sockaddr_in6 *) address)->sin6_port)
-			 : 0),
-			strerror(error));
-	}
-	__set_errno (save);
-}
-
-static void
-Perror(const res_state statp, FILE *file, const char *string, int error) {
-	int save = errno;
-
-	if ((statp->options & RES_DEBUG) != 0)
-		fprintf(file, "res_send: %s: %s\n",
-			string, strerror(error));
-	__set_errno (save);
-}
-#endif
-
-static int
-sock_eq(struct sockaddr_in6 *a1, struct sockaddr_in6 *a2) {
-	if (a1->sin6_family == a2->sin6_family) {
-		if (a1->sin6_family == AF_INET)
-			return ((((struct sockaddr_in *)a1)->sin_port ==
-				 ((struct sockaddr_in *)a2)->sin_port) &&
-				(((struct sockaddr_in *)a1)->sin_addr.s_addr ==
-				 ((struct sockaddr_in *)a2)->sin_addr.s_addr));
-		else
-			return ((a1->sin6_port == a2->sin6_port) &&
-				!memcmp(&a1->sin6_addr, &a2->sin6_addr,
-					sizeof (struct in6_addr)));
-	}
-	if (a1->sin6_family == AF_INET) {
-		struct sockaddr_in6 *sap = a1;
-		a1 = a2;
-		a2 = sap;
-	} /* assumes that AF_INET and AF_INET6 are the only possibilities */
-	return ((a1->sin6_port == ((struct sockaddr_in *)a2)->sin_port) &&
-		IN6_IS_ADDR_V4MAPPED(&a1->sin6_addr) &&
-		(a1->sin6_addr.s6_addr32[3] ==
-		 ((struct sockaddr_in *)a2)->sin_addr.s_addr));
-}