1/*	$NetBSD: res_send.c,v 1.9 2006/01/24 17:41:25 christos Exp $	*/
2
3/*
4 * Copyright 2008  Android Open Source Project (source port randomization)
5 * Copyright (c) 1985, 1989, 1993
6 *    The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 * 	This product includes software developed by the University of
19 * 	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37/*
38 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
39 *
40 * Permission to use, copy, modify, and distribute this software for any
41 * purpose with or without fee is hereby granted, provided that the above
42 * copyright notice and this permission notice appear in all copies, and that
43 * the name of Digital Equipment Corporation not be used in advertising or
44 * publicity pertaining to distribution of the document or software without
45 * specific, written prior permission.
46 *
47 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
48 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
49 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
50 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
51 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
52 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
53 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
54 * SOFTWARE.
55 */
56
57/*
58 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
59 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
60 *
61 * Permission to use, copy, modify, and distribute this software for any
62 * purpose with or without fee is hereby granted, provided that the above
63 * copyright notice and this permission notice appear in all copies.
64 *
65 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
66 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
67 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
68 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
69 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
70 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
71 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
72 */
73
74#include <sys/cdefs.h>
75#if defined(LIBC_SCCS) && !defined(lint)
76#ifdef notdef
77static const char sccsid[] = "@(#)res_send.c	8.1 (Berkeley) 6/4/93";
78static const char rcsid[] = "Id: res_send.c,v 1.5.2.2.4.5 2004/08/10 02:19:56 marka Exp";
79#else
80__RCSID("$NetBSD: res_send.c,v 1.9 2006/01/24 17:41:25 christos Exp $");
81#endif
82#endif /* LIBC_SCCS and not lint */
83
84/*
85 * Send query to name server and wait for reply.
86 */
87
88#include <sys/types.h>
89#include <sys/param.h>
90#include <sys/time.h>
91#include <sys/socket.h>
92#include <sys/uio.h>
93
94#include <netinet/in.h>
95#include <arpa/nameser.h>
96#include <arpa/inet.h>
97
98#include <errno.h>
99#include <fcntl.h>
100#include <netdb.h>
101#ifdef ANDROID_CHANGES
102#include "resolv_netid.h"
103#include "resolv_private.h"
104#else
105#include <resolv.h>
106#endif
107#include <signal.h>
108#include <stdio.h>
109#include <stdlib.h>
110#include <string.h>
111#include <time.h>
112#include <unistd.h>
113
114#include <isc/eventlib.h>
115
116#include <resolv_cache.h>
117
118#include "private/libc_logging.h"
119
120#ifndef DE_CONST
121#define DE_CONST(c,v)   v = ((c) ? \
122    strchr((const void *)(c), *(const char *)(const void *)(c)) : NULL)
123#endif
124
125/* Options.  Leave them on. */
126#ifndef DEBUG
127#define DEBUG
128#endif
129#include "res_debug.h"
130#include "res_private.h"
131#include "resolv_stats.h"
132
133#define EXT(res) ((res)->_u._ext)
134#define DBG 0
135
136static const int highestFD = FD_SETSIZE - 1;
137
138/* Forward. */
139
140static int		get_salen __P((const struct sockaddr *));
141static struct sockaddr * get_nsaddr __P((res_state, size_t));
142static int		send_vc(res_state, const u_char *, int,
143				u_char *, int, int *, int,
144				time_t *, int *, int *);
145static int		send_dg(res_state, const u_char *, int,
146				u_char *, int, int *, int,
147				int *, int *,
148				time_t *, int *, int *);
149static void		Aerror(const res_state, FILE *, const char *, int,
150			       const struct sockaddr *, int);
151static void		Perror(const res_state, FILE *, const char *, int);
152static int		sock_eq(struct sockaddr *, struct sockaddr *);
153#ifdef NEED_PSELECT
154static int		pselect(int, void *, void *, void *,
155				struct timespec *,
156				const sigset_t *);
157#endif
158void res_pquery(const res_state, const u_char *, int, FILE *);
159static int connect_with_timeout(int sock, const struct sockaddr *nsap,
160			socklen_t salen, int sec);
161static int retrying_select(const int sock, fd_set *readset, fd_set *writeset,
162			const struct timespec *finish);
163
164/* BIONIC-BEGIN: implement source port randomization */
165typedef union {
166    struct sockaddr      sa;
167    struct sockaddr_in   sin;
168    struct sockaddr_in6  sin6;
169} _sockaddr_union;
170
171static int
172random_bind( int  s, int  family )
173{
174    _sockaddr_union  u;
175    int              j;
176    socklen_t        slen;
177
178    /* clear all, this also sets the IP4/6 address to 'any' */
179    memset( &u, 0, sizeof u );
180
181    switch (family) {
182        case AF_INET:
183            u.sin.sin_family = family;
184            slen             = sizeof u.sin;
185            break;
186        case AF_INET6:
187            u.sin6.sin6_family = family;
188            slen               = sizeof u.sin6;
189            break;
190        default:
191            errno = EPROTO;
192            return -1;
193    }
194
195    /* first try to bind to a random source port a few times */
196    for (j = 0; j < 10; j++) {
197        /* find a random port between 1025 .. 65534 */
198        int  port = 1025 + (res_randomid() % (65535-1025));
199        if (family == AF_INET)
200            u.sin.sin_port = htons(port);
201        else
202            u.sin6.sin6_port = htons(port);
203
204        if ( !bind( s, &u.sa, slen ) )
205            return 0;
206    }
207
208    /* nothing after 10 tries, our network table is probably busy */
209    /* let the system decide which port is best */
210    if (family == AF_INET)
211        u.sin.sin_port = 0;
212    else
213        u.sin6.sin6_port = 0;
214
215    return bind( s, &u.sa, slen );
216}
217/* BIONIC-END */
218
219static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
220
221/* Public. */
222
223/* int
224 * res_isourserver(ina)
225 *	looks up "ina" in _res.ns_addr_list[]
226 * returns:
227 *	0  : not found
228 *	>0 : found
229 * author:
230 *	paul vixie, 29may94
231 */
232__LIBC_HIDDEN__ int
233res_ourserver_p(const res_state statp, const struct sockaddr *sa) {
234	const struct sockaddr_in *inp, *srv;
235	const struct sockaddr_in6 *in6p, *srv6;
236	int ns;
237
238	switch (sa->sa_family) {
239	case AF_INET:
240		inp = (const struct sockaddr_in *)(const void *)sa;
241		for (ns = 0;  ns < statp->nscount;  ns++) {
242			srv = (struct sockaddr_in *)(void *)get_nsaddr(statp, (size_t)ns);
243			if (srv->sin_family == inp->sin_family &&
244			    srv->sin_port == inp->sin_port &&
245			    (srv->sin_addr.s_addr == INADDR_ANY ||
246			     srv->sin_addr.s_addr == inp->sin_addr.s_addr))
247				return (1);
248		}
249		break;
250	case AF_INET6:
251		if (EXT(statp).ext == NULL)
252			break;
253		in6p = (const struct sockaddr_in6 *)(const void *)sa;
254		for (ns = 0;  ns < statp->nscount;  ns++) {
255			srv6 = (struct sockaddr_in6 *)(void *)get_nsaddr(statp, (size_t)ns);
256			if (srv6->sin6_family == in6p->sin6_family &&
257			    srv6->sin6_port == in6p->sin6_port &&
258#ifdef HAVE_SIN6_SCOPE_ID
259			    (srv6->sin6_scope_id == 0 ||
260			     srv6->sin6_scope_id == in6p->sin6_scope_id) &&
261#endif
262			    (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
263			     IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
264				return (1);
265		}
266		break;
267	default:
268		break;
269	}
270	return (0);
271}
272
273/* int
274 * res_nameinquery(name, type, class, buf, eom)
275 *	look for (name,type,class) in the query section of packet (buf,eom)
276 * requires:
277 *	buf + HFIXEDSZ <= eom
278 * returns:
279 *	-1 : format error
280 *	0  : not found
281 *	>0 : found
282 * author:
283 *	paul vixie, 29may94
284 */
285int
286res_nameinquery(const char *name, int type, int class,
287		const u_char *buf, const u_char *eom)
288{
289	const u_char *cp = buf + HFIXEDSZ;
290	int qdcount = ntohs(((const HEADER*)(const void *)buf)->qdcount);
291
292	while (qdcount-- > 0) {
293		char tname[MAXDNAME+1];
294		int n, ttype, tclass;
295
296		n = dn_expand(buf, eom, cp, tname, sizeof tname);
297		if (n < 0)
298			return (-1);
299		cp += n;
300		if (cp + 2 * INT16SZ > eom)
301			return (-1);
302		ttype = ns_get16(cp); cp += INT16SZ;
303		tclass = ns_get16(cp); cp += INT16SZ;
304		if (ttype == type && tclass == class &&
305		    ns_samename(tname, name) == 1)
306			return (1);
307	}
308	return (0);
309}
310
311/* int
312 * res_queriesmatch(buf1, eom1, buf2, eom2)
313 *	is there a 1:1 mapping of (name,type,class)
314 *	in (buf1,eom1) and (buf2,eom2)?
315 * returns:
316 *	-1 : format error
317 *	0  : not a 1:1 mapping
318 *	>0 : is a 1:1 mapping
319 * author:
320 *	paul vixie, 29may94
321 */
322int
323res_queriesmatch(const u_char *buf1, const u_char *eom1,
324		 const u_char *buf2, const u_char *eom2)
325{
326	const u_char *cp = buf1 + HFIXEDSZ;
327	int qdcount = ntohs(((const HEADER*)(const void *)buf1)->qdcount);
328
329	if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
330		return (-1);
331
332	/*
333	 * Only header section present in replies to
334	 * dynamic update packets.
335	 */
336	if ((((const HEADER *)(const void *)buf1)->opcode == ns_o_update) &&
337	    (((const HEADER *)(const void *)buf2)->opcode == ns_o_update))
338		return (1);
339
340	if (qdcount != ntohs(((const HEADER*)(const void *)buf2)->qdcount))
341		return (0);
342	while (qdcount-- > 0) {
343		char tname[MAXDNAME+1];
344		int n, ttype, tclass;
345
346		n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
347		if (n < 0)
348			return (-1);
349		cp += n;
350		if (cp + 2 * INT16SZ > eom1)
351			return (-1);
352		ttype = ns_get16(cp);	cp += INT16SZ;
353		tclass = ns_get16(cp); cp += INT16SZ;
354		if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
355			return (0);
356	}
357	return (1);
358}
359
360int
361res_nsend(res_state statp,
362	  const u_char *buf, int buflen, u_char *ans, int anssiz)
363{
364	int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
365	char abuf[NI_MAXHOST];
366	ResolvCacheStatus     cache_status = RESOLV_CACHE_UNSUPPORTED;
367
368	if (anssiz < HFIXEDSZ) {
369		errno = EINVAL;
370		return (-1);
371	}
372	DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
373		(stdout, ";; res_send()\n"), buf, buflen);
374	v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
375	gotsomewhere = 0;
376	terrno = ETIMEDOUT;
377
378	int  anslen = 0;
379	cache_status = _resolv_cache_lookup(
380			statp->netid, buf, buflen,
381			ans, anssiz, &anslen);
382
383	if (cache_status == RESOLV_CACHE_FOUND) {
384		return anslen;
385	} else if (cache_status != RESOLV_CACHE_UNSUPPORTED) {
386		// had a cache miss for a known network, so populate the thread private
387		// data so the normal resolve path can do its thing
388		_resolv_populate_res_for_net(statp);
389	}
390	if (statp->nscount == 0) {
391		// We have no nameservers configured, so there's no point trying.
392		// Tell the cache the query failed, or any retries and anyone else asking the same
393		// question will block for PENDING_REQUEST_TIMEOUT seconds instead of failing fast.
394		_resolv_cache_query_failed(statp->netid, buf, buflen);
395		errno = ESRCH;
396		return (-1);
397	}
398
399	/*
400	 * If the ns_addr_list in the resolver context has changed, then
401	 * invalidate our cached copy and the associated timing data.
402	 */
403	if (EXT(statp).nscount != 0) {
404		int needclose = 0;
405		struct sockaddr_storage peer;
406		socklen_t peerlen;
407
408		if (EXT(statp).nscount != statp->nscount) {
409			needclose++;
410		} else {
411			for (ns = 0; ns < statp->nscount; ns++) {
412				if (statp->nsaddr_list[ns].sin_family &&
413				    !sock_eq((struct sockaddr *)(void *)&statp->nsaddr_list[ns],
414					     (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[ns])) {
415					needclose++;
416					break;
417				}
418
419				if (EXT(statp).nssocks[ns] == -1)
420					continue;
421				peerlen = sizeof(peer);
422				if (getpeername(EXT(statp).nssocks[ns],
423				    (struct sockaddr *)(void *)&peer, &peerlen) < 0) {
424					needclose++;
425					break;
426				}
427				if (!sock_eq((struct sockaddr *)(void *)&peer,
428				    get_nsaddr(statp, (size_t)ns))) {
429					needclose++;
430					break;
431				}
432			}
433		}
434		if (needclose) {
435			res_nclose(statp);
436			EXT(statp).nscount = 0;
437		}
438	}
439
440	/*
441	 * Maybe initialize our private copy of the ns_addr_list.
442	 */
443	if (EXT(statp).nscount == 0) {
444		for (ns = 0; ns < statp->nscount; ns++) {
445			EXT(statp).nstimes[ns] = RES_MAXTIME;
446			EXT(statp).nssocks[ns] = -1;
447			if (!statp->nsaddr_list[ns].sin_family)
448				continue;
449			EXT(statp).ext->nsaddrs[ns].sin =
450				 statp->nsaddr_list[ns];
451		}
452		EXT(statp).nscount = statp->nscount;
453	}
454
455	/*
456	 * Some resolvers want to even out the load on their nameservers.
457	 * Note that RES_BLAST overrides RES_ROTATE.
458	 */
459	if ((statp->options & RES_ROTATE) != 0U &&
460	    (statp->options & RES_BLAST) == 0U) {
461		union res_sockaddr_union inu;
462		struct sockaddr_in ina;
463		int lastns = statp->nscount - 1;
464		int fd;
465		u_int16_t nstime;
466
467		if (EXT(statp).ext != NULL)
468			inu = EXT(statp).ext->nsaddrs[0];
469		ina = statp->nsaddr_list[0];
470		fd = EXT(statp).nssocks[0];
471		nstime = EXT(statp).nstimes[0];
472		for (ns = 0; ns < lastns; ns++) {
473			if (EXT(statp).ext != NULL)
474				EXT(statp).ext->nsaddrs[ns] =
475					EXT(statp).ext->nsaddrs[ns + 1];
476			statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
477			EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
478			EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
479		}
480		if (EXT(statp).ext != NULL)
481			EXT(statp).ext->nsaddrs[lastns] = inu;
482		statp->nsaddr_list[lastns] = ina;
483		EXT(statp).nssocks[lastns] = fd;
484		EXT(statp).nstimes[lastns] = nstime;
485	}
486
487	/*
488	 * Send request, RETRY times, or until successful.
489	 */
490	for (try = 0; try < statp->retry; try++) {
491	    struct __res_stats stats[MAXNS];
492	    struct __res_params params;
493	    int revision_id = _resolv_cache_get_resolver_stats(statp->netid, &params, stats);
494	    bool usable_servers[MAXNS];
495	    android_net_res_stats_get_usable_servers(&params, stats, statp->nscount,
496		    usable_servers);
497
498	    for (ns = 0; ns < statp->nscount; ns++) {
499		if (!usable_servers[ns]) continue;
500		struct sockaddr *nsap;
501		int nsaplen;
502		time_t now = 0;
503		int rcode = RCODE_INTERNAL_ERROR;
504		int delay = 0;
505		nsap = get_nsaddr(statp, (size_t)ns);
506		nsaplen = get_salen(nsap);
507		statp->_flags &= ~RES_F_LASTMASK;
508		statp->_flags |= (ns << RES_F_LASTSHIFT);
509
510 same_ns:
511		if (statp->qhook) {
512			int done = 0, loops = 0;
513
514			do {
515				res_sendhookact act;
516
517				act = (*statp->qhook)(&nsap, &buf, &buflen,
518						      ans, anssiz, &resplen);
519				switch (act) {
520				case res_goahead:
521					done = 1;
522					break;
523				case res_nextns:
524					res_nclose(statp);
525					goto next_ns;
526				case res_done:
527					return (resplen);
528				case res_modified:
529					/* give the hook another try */
530					if (++loops < 42) /*doug adams*/
531						break;
532					/*FALLTHROUGH*/
533				case res_error:
534					/*FALLTHROUGH*/
535				default:
536					goto fail;
537				}
538			} while (!done);
539		}
540
541		Dprint(((statp->options & RES_DEBUG) &&
542			getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf),
543				NULL, 0, niflags) == 0),
544				(stdout, ";; Querying server (# %d) address = %s\n",
545				ns + 1, abuf));
546
547
548		if (v_circuit) {
549			/* Use VC; at most one attempt per server. */
550			try = statp->retry;
551
552			n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
553				    ns, &now, &rcode, &delay);
554
555			/*
556			 * Only record stats the first time we try a query. This ensures that
557			 * queries that deterministically fail (e.g., a name that always returns
558			 * SERVFAIL or times out) do not unduly affect the stats.
559			 */
560			if (try == 0) {
561				struct __res_sample sample;
562				_res_stats_set_sample(&sample, now, rcode, delay);
563				_resolv_cache_add_resolver_stats_sample(statp->netid, revision_id,
564					ns, &sample, params.max_samples);
565			}
566
567			if (DBG) {
568				__libc_format_log(ANDROID_LOG_DEBUG, "libc",
569					"used send_vc %d\n", n);
570			}
571
572			if (n < 0)
573				goto fail;
574			if (n == 0)
575				goto next_ns;
576			resplen = n;
577		} else {
578			/* Use datagrams. */
579			if (DBG) {
580				__libc_format_log(ANDROID_LOG_DEBUG, "libc", "using send_dg\n");
581			}
582
583			n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
584				    ns, &v_circuit, &gotsomewhere, &now, &rcode, &delay);
585
586			/* Only record stats the first time we try a query. See above. */
587			if (try == 0) {
588				struct __res_sample sample;
589				_res_stats_set_sample(&sample, now, rcode, delay);
590				_resolv_cache_add_resolver_stats_sample(statp->netid, revision_id,
591					ns, &sample, params.max_samples);
592			}
593
594			if (DBG) {
595				__libc_format_log(ANDROID_LOG_DEBUG, "libc", "used send_dg %d\n",n);
596			}
597
598			if (n < 0)
599				goto fail;
600			if (n == 0)
601				goto next_ns;
602			if (DBG) {
603				__libc_format_log(ANDROID_LOG_DEBUG, "libc", "time=%ld\n",
604						  time(NULL));
605			}
606			if (v_circuit)
607				goto same_ns;
608			resplen = n;
609		}
610
611		Dprint((statp->options & RES_DEBUG) ||
612		       ((statp->pfcode & RES_PRF_REPLY) &&
613			(statp->pfcode & RES_PRF_HEAD1)),
614		       (stdout, ";; got answer:\n"));
615
616		DprintQ((statp->options & RES_DEBUG) ||
617			(statp->pfcode & RES_PRF_REPLY),
618			(stdout, "%s", ""),
619			ans, (resplen > anssiz) ? anssiz : resplen);
620
621		if (cache_status == RESOLV_CACHE_NOTFOUND) {
622		    _resolv_cache_add(statp->netid, buf, buflen,
623				      ans, resplen);
624		}
625		/*
626		 * If we have temporarily opened a virtual circuit,
627		 * or if we haven't been asked to keep a socket open,
628		 * close the socket.
629		 */
630		if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
631		    (statp->options & RES_STAYOPEN) == 0U) {
632			res_nclose(statp);
633		}
634		if (statp->rhook) {
635			int done = 0, loops = 0;
636
637			do {
638				res_sendhookact act;
639
640				act = (*statp->rhook)(nsap, buf, buflen,
641						      ans, anssiz, &resplen);
642				switch (act) {
643				case res_goahead:
644				case res_done:
645					done = 1;
646					break;
647				case res_nextns:
648					res_nclose(statp);
649					goto next_ns;
650				case res_modified:
651					/* give the hook another try */
652					if (++loops < 42) /*doug adams*/
653						break;
654					/*FALLTHROUGH*/
655				case res_error:
656					/*FALLTHROUGH*/
657				default:
658					goto fail;
659				}
660			} while (!done);
661
662		}
663		return (resplen);
664 next_ns: ;
665	   } /*foreach ns*/
666	} /*foreach retry*/
667	res_nclose(statp);
668	if (!v_circuit) {
669		if (!gotsomewhere)
670			errno = ECONNREFUSED;	/* no nameservers found */
671		else
672			errno = ETIMEDOUT;	/* no answer obtained */
673	} else
674		errno = terrno;
675
676	_resolv_cache_query_failed(statp->netid, buf, buflen);
677
678	return (-1);
679 fail:
680
681	_resolv_cache_query_failed(statp->netid, buf, buflen);
682	res_nclose(statp);
683	return (-1);
684}
685
686/* Private */
687
688static int
689get_salen(sa)
690	const struct sockaddr *sa;
691{
692
693#ifdef HAVE_SA_LEN
694	/* There are people do not set sa_len.  Be forgiving to them. */
695	if (sa->sa_len)
696		return (sa->sa_len);
697#endif
698
699	if (sa->sa_family == AF_INET)
700		return (sizeof(struct sockaddr_in));
701	else if (sa->sa_family == AF_INET6)
702		return (sizeof(struct sockaddr_in6));
703	else
704		return (0);	/* unknown, die on connect */
705}
706
707/*
708 * pick appropriate nsaddr_list for use.  see res_init() for initialization.
709 */
710static struct sockaddr *
711get_nsaddr(statp, n)
712	res_state statp;
713	size_t n;
714{
715
716	if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
717		/*
718		 * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
719		 *   than struct sockaddr, and
720		 * - user code did not update statp->nsaddr_list[n].
721		 */
722		return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
723	} else {
724		/*
725		 * - user code updated statp->nsaddr_list[n], or
726		 * - statp->nsaddr_list[n] has the same content as
727		 *   EXT(statp).ext->nsaddrs[n].
728		 */
729		return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
730	}
731}
732
733static int get_timeout(const res_state statp, const int ns)
734{
735	int timeout = (statp->retrans << ns);
736	if (ns > 0) {
737		timeout /= statp->nscount;
738	}
739	if (timeout <= 0) {
740		timeout = 1;
741	}
742	if (DBG) {
743		__libc_format_log(ANDROID_LOG_DEBUG, "libc", "using timeout of %d sec\n", timeout);
744	}
745
746	return timeout;
747}
748
749static int
750send_vc(res_state statp,
751	const u_char *buf, int buflen, u_char *ans, int anssiz,
752	int *terrno, int ns, time_t* at, int* rcode, int* delay)
753{
754	*at = time(NULL);
755	*rcode = RCODE_INTERNAL_ERROR;
756	*delay = 0;
757	const HEADER *hp = (const HEADER *)(const void *)buf;
758	HEADER *anhp = (HEADER *)(void *)ans;
759	struct sockaddr *nsap;
760	int nsaplen;
761	int truncating, connreset, resplen, n;
762	struct iovec iov[2];
763	u_short len;
764	u_char *cp;
765	void *tmp;
766
767	if (DBG) {
768		__libc_format_log(ANDROID_LOG_DEBUG, "libc", "using send_vc\n");
769	}
770
771	nsap = get_nsaddr(statp, (size_t)ns);
772	nsaplen = get_salen(nsap);
773
774	connreset = 0;
775 same_ns:
776	truncating = 0;
777
778	struct timespec now = evNowTime();
779
780	/* Are we still talking to whom we want to talk to? */
781	if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
782		struct sockaddr_storage peer;
783		socklen_t size = sizeof peer;
784		unsigned old_mark;
785		socklen_t mark_size = sizeof(old_mark);
786		if (getpeername(statp->_vcsock,
787				(struct sockaddr *)(void *)&peer, &size) < 0 ||
788		    !sock_eq((struct sockaddr *)(void *)&peer, nsap) ||
789			getsockopt(statp->_vcsock, SOL_SOCKET, SO_MARK, &old_mark, &mark_size) < 0 ||
790			old_mark != statp->_mark) {
791			res_nclose(statp);
792			statp->_flags &= ~RES_F_VC;
793		}
794	}
795
796	if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
797		if (statp->_vcsock >= 0)
798			res_nclose(statp);
799
800		statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
801		if (statp->_vcsock > highestFD) {
802			res_nclose(statp);
803			errno = ENOTSOCK;
804		}
805		if (statp->_vcsock < 0) {
806			switch (errno) {
807			case EPROTONOSUPPORT:
808#ifdef EPFNOSUPPORT
809			case EPFNOSUPPORT:
810#endif
811			case EAFNOSUPPORT:
812				Perror(statp, stderr, "socket(vc)", errno);
813				return (0);
814			default:
815				*terrno = errno;
816				Perror(statp, stderr, "socket(vc)", errno);
817				return (-1);
818			}
819		}
820		if (statp->_mark != MARK_UNSET) {
821			if (setsockopt(statp->_vcsock, SOL_SOCKET,
822				    SO_MARK, &statp->_mark, sizeof(statp->_mark)) < 0) {
823				*terrno = errno;
824				Perror(statp, stderr, "setsockopt", errno);
825				return -1;
826			}
827		}
828		errno = 0;
829		if (random_bind(statp->_vcsock,nsap->sa_family) < 0) {
830			*terrno = errno;
831			Aerror(statp, stderr, "bind/vc", errno, nsap,
832			    nsaplen);
833			res_nclose(statp);
834			return (0);
835		}
836		if (connect_with_timeout(statp->_vcsock, nsap, (socklen_t)nsaplen,
837				get_timeout(statp, ns)) < 0) {
838			*terrno = errno;
839			Aerror(statp, stderr, "connect/vc", errno, nsap,
840			    nsaplen);
841			res_nclose(statp);
842			/*
843			 * The way connect_with_timeout() is implemented prevents us from reliably
844			 * determining whether this was really a timeout or e.g. ECONNREFUSED. Since
845			 * currently both cases are handled in the same way, there is no need to
846			 * change this (yet). If we ever need to reliably distinguish between these
847			 * cases, both connect_with_timeout() and retrying_select() need to be
848			 * modified, though.
849			 */
850			*rcode = RCODE_TIMEOUT;
851			return (0);
852		}
853		statp->_flags |= RES_F_VC;
854	}
855
856	/*
857	 * Send length & message
858	 */
859	ns_put16((u_short)buflen, (u_char*)(void *)&len);
860	iov[0] = evConsIovec(&len, INT16SZ);
861	DE_CONST(buf, tmp);
862	iov[1] = evConsIovec(tmp, (size_t)buflen);
863	if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
864		*terrno = errno;
865		Perror(statp, stderr, "write failed", errno);
866		res_nclose(statp);
867		return (0);
868	}
869	/*
870	 * Receive length & response
871	 */
872 read_len:
873	cp = ans;
874	len = INT16SZ;
875	while ((n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0) {
876		cp += n;
877		if ((len -= n) == 0)
878			break;
879	}
880	if (n <= 0) {
881		*terrno = errno;
882		Perror(statp, stderr, "read failed", errno);
883		res_nclose(statp);
884		/*
885		 * A long running process might get its TCP
886		 * connection reset if the remote server was
887		 * restarted.  Requery the server instead of
888		 * trying a new one.  When there is only one
889		 * server, this means that a query might work
890		 * instead of failing.  We only allow one reset
891		 * per query to prevent looping.
892		 */
893		if (*terrno == ECONNRESET && !connreset) {
894			connreset = 1;
895			res_nclose(statp);
896			goto same_ns;
897		}
898		res_nclose(statp);
899		return (0);
900	}
901	resplen = ns_get16(ans);
902	if (resplen > anssiz) {
903		Dprint(statp->options & RES_DEBUG,
904		       (stdout, ";; response truncated\n")
905		       );
906		truncating = 1;
907		len = anssiz;
908	} else
909		len = resplen;
910	if (len < HFIXEDSZ) {
911		/*
912		 * Undersized message.
913		 */
914		Dprint(statp->options & RES_DEBUG,
915		       (stdout, ";; undersized: %d\n", len));
916		*terrno = EMSGSIZE;
917		res_nclose(statp);
918		return (0);
919	}
920	cp = ans;
921	while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0){
922		cp += n;
923		len -= n;
924	}
925	if (n <= 0) {
926		*terrno = errno;
927		Perror(statp, stderr, "read(vc)", errno);
928		res_nclose(statp);
929		return (0);
930	}
931
932	if (truncating) {
933		/*
934		 * Flush rest of answer so connection stays in synch.
935		 */
936		anhp->tc = 1;
937		len = resplen - anssiz;
938		while (len != 0) {
939			char junk[PACKETSZ];
940
941			n = read(statp->_vcsock, junk,
942				 (len > sizeof junk) ? sizeof junk : len);
943			if (n > 0)
944				len -= n;
945			else
946				break;
947		}
948	}
949	/*
950	 * If the calling applicating has bailed out of
951	 * a previous call and failed to arrange to have
952	 * the circuit closed or the server has got
953	 * itself confused, then drop the packet and
954	 * wait for the correct one.
955	 */
956	if (hp->id != anhp->id) {
957		DprintQ((statp->options & RES_DEBUG) ||
958			(statp->pfcode & RES_PRF_REPLY),
959			(stdout, ";; old answer (unexpected):\n"),
960			ans, (resplen > anssiz) ? anssiz: resplen);
961		goto read_len;
962	}
963
964	/*
965	 * All is well, or the error is fatal.  Signal that the
966	 * next nameserver ought not be tried.
967	 */
968	if (resplen > 0) {
969	    struct timespec done = evNowTime();
970	    *delay = _res_stats_calculate_rtt(&done, &now);
971	    *rcode = anhp->rcode;
972	}
973	return (resplen);
974}
975
976/* return -1 on error (errno set), 0 on success */
977static int
978connect_with_timeout(int sock, const struct sockaddr *nsap, socklen_t salen, int sec)
979{
980	int res, origflags;
981	fd_set rset, wset;
982	struct timespec now, timeout, finish;
983
984	origflags = fcntl(sock, F_GETFL, 0);
985	fcntl(sock, F_SETFL, origflags | O_NONBLOCK);
986
987	res = __connect(sock, nsap, salen);
988	if (res < 0 && errno != EINPROGRESS) {
989		res = -1;
990		goto done;
991	}
992	if (res != 0) {
993		now = evNowTime();
994		timeout = evConsTime((long)sec, 0L);
995		finish = evAddTime(now, timeout);
996		if (DBG) {
997			__libc_format_log(ANDROID_LOG_DEBUG, "libc", "  %d send_vc\n", sock);
998		}
999
1000		res = retrying_select(sock, &rset, &wset, &finish);
1001		if (res <= 0) {
1002			res = -1;
1003		}
1004	}
1005done:
1006	fcntl(sock, F_SETFL, origflags);
1007	if (DBG) {
1008		__libc_format_log(ANDROID_LOG_DEBUG, "libc",
1009			"  %d connect_with_timeout returning %d\n", sock, res);
1010	}
1011	return res;
1012}
1013
1014static int
1015retrying_select(const int sock, fd_set *readset, fd_set *writeset, const struct timespec *finish)
1016{
1017	struct timespec now, timeout;
1018	int n, error;
1019	socklen_t len;
1020
1021
1022retry:
1023	if (DBG) {
1024		__libc_format_log(ANDROID_LOG_DEBUG, "libc", "  %d retrying_select\n", sock);
1025	}
1026
1027	now = evNowTime();
1028	if (readset) {
1029		FD_ZERO(readset);
1030		FD_SET(sock, readset);
1031	}
1032	if (writeset) {
1033		FD_ZERO(writeset);
1034		FD_SET(sock, writeset);
1035	}
1036	if (evCmpTime(*finish, now) > 0)
1037		timeout = evSubTime(*finish, now);
1038	else
1039		timeout = evConsTime(0L, 0L);
1040
1041	n = pselect(sock + 1, readset, writeset, NULL, &timeout, NULL);
1042	if (n == 0) {
1043		if (DBG) {
1044			__libc_format_log(ANDROID_LOG_DEBUG, " libc",
1045				"  %d retrying_select timeout\n", sock);
1046		}
1047		errno = ETIMEDOUT;
1048		return 0;
1049	}
1050	if (n < 0) {
1051		if (errno == EINTR)
1052			goto retry;
1053		if (DBG) {
1054			__libc_format_log(ANDROID_LOG_DEBUG, "libc",
1055				"  %d retrying_select got error %d\n",sock, n);
1056		}
1057		return n;
1058	}
1059	if ((readset && FD_ISSET(sock, readset)) || (writeset && FD_ISSET(sock, writeset))) {
1060		len = sizeof(error);
1061		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error) {
1062			errno = error;
1063			if (DBG) {
1064				__libc_format_log(ANDROID_LOG_DEBUG, "libc",
1065					"  %d retrying_select dot error2 %d\n", sock, errno);
1066			}
1067
1068			return -1;
1069		}
1070	}
1071	if (DBG) {
1072		__libc_format_log(ANDROID_LOG_DEBUG, "libc",
1073			"  %d retrying_select returning %d\n",sock, n);
1074	}
1075
1076	return n;
1077}
1078
1079static int
1080send_dg(res_state statp,
1081	const u_char *buf, int buflen, u_char *ans, int anssiz,
1082	int *terrno, int ns, int *v_circuit, int *gotsomewhere,
1083	time_t *at, int *rcode, int* delay)
1084{
1085	*at = time(NULL);
1086	*rcode = RCODE_INTERNAL_ERROR;
1087	*delay = 0;
1088	const HEADER *hp = (const HEADER *)(const void *)buf;
1089	HEADER *anhp = (HEADER *)(void *)ans;
1090	const struct sockaddr *nsap;
1091	int nsaplen;
1092	struct timespec now, timeout, finish, done;
1093	fd_set dsmask;
1094	struct sockaddr_storage from;
1095	socklen_t fromlen;
1096	int resplen, seconds, n, s;
1097
1098	nsap = get_nsaddr(statp, (size_t)ns);
1099	nsaplen = get_salen(nsap);
1100	if (EXT(statp).nssocks[ns] == -1) {
1101		EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
1102		if (EXT(statp).nssocks[ns] > highestFD) {
1103			res_nclose(statp);
1104			errno = ENOTSOCK;
1105		}
1106		if (EXT(statp).nssocks[ns] < 0) {
1107			switch (errno) {
1108			case EPROTONOSUPPORT:
1109#ifdef EPFNOSUPPORT
1110			case EPFNOSUPPORT:
1111#endif
1112			case EAFNOSUPPORT:
1113				Perror(statp, stderr, "socket(dg)", errno);
1114				return (0);
1115			default:
1116				*terrno = errno;
1117				Perror(statp, stderr, "socket(dg)", errno);
1118				return (-1);
1119			}
1120		}
1121
1122		if (statp->_mark != MARK_UNSET) {
1123			if (setsockopt(EXT(statp).nssocks[ns], SOL_SOCKET,
1124					SO_MARK, &(statp->_mark), sizeof(statp->_mark)) < 0) {
1125				res_nclose(statp);
1126				return -1;
1127			}
1128		}
1129#ifndef CANNOT_CONNECT_DGRAM
1130		/*
1131		 * On a 4.3BSD+ machine (client and server,
1132		 * actually), sending to a nameserver datagram
1133		 * port with no nameserver will cause an
1134		 * ICMP port unreachable message to be returned.
1135		 * If our datagram socket is "connected" to the
1136		 * server, we get an ECONNREFUSED error on the next
1137		 * socket operation, and select returns if the
1138		 * error message is received.  We can thus detect
1139		 * the absence of a nameserver without timing out.
1140		 */
1141		if (random_bind(EXT(statp).nssocks[ns], nsap->sa_family) < 0) {
1142			Aerror(statp, stderr, "bind(dg)", errno, nsap,
1143			    nsaplen);
1144			res_nclose(statp);
1145			return (0);
1146		}
1147		if (__connect(EXT(statp).nssocks[ns], nsap, (socklen_t)nsaplen) < 0) {
1148			Aerror(statp, stderr, "connect(dg)", errno, nsap,
1149			    nsaplen);
1150			res_nclose(statp);
1151			return (0);
1152		}
1153#endif /* !CANNOT_CONNECT_DGRAM */
1154		Dprint(statp->options & RES_DEBUG,
1155		       (stdout, ";; new DG socket\n"))
1156
1157	}
1158	s = EXT(statp).nssocks[ns];
1159#ifndef CANNOT_CONNECT_DGRAM
1160	if (send(s, (const char*)buf, (size_t)buflen, 0) != buflen) {
1161		Perror(statp, stderr, "send", errno);
1162		res_nclose(statp);
1163		return (0);
1164	}
1165#else /* !CANNOT_CONNECT_DGRAM */
1166	if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
1167	{
1168		Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
1169		res_nclose(statp);
1170		return (0);
1171	}
1172#endif /* !CANNOT_CONNECT_DGRAM */
1173
1174	/*
1175	 * Wait for reply.
1176	 */
1177	seconds = get_timeout(statp, ns);
1178	now = evNowTime();
1179	timeout = evConsTime((long)seconds, 0L);
1180	finish = evAddTime(now, timeout);
1181retry:
1182	n = retrying_select(s, &dsmask, NULL, &finish);
1183
1184	if (n == 0) {
1185		*rcode = RCODE_TIMEOUT;
1186		Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
1187		*gotsomewhere = 1;
1188		return (0);
1189	}
1190	if (n < 0) {
1191		Perror(statp, stderr, "select", errno);
1192		res_nclose(statp);
1193		return (0);
1194	}
1195	errno = 0;
1196	fromlen = sizeof(from);
1197	resplen = recvfrom(s, (char*)ans, (size_t)anssiz,0,
1198			   (struct sockaddr *)(void *)&from, &fromlen);
1199	if (resplen <= 0) {
1200		Perror(statp, stderr, "recvfrom", errno);
1201		res_nclose(statp);
1202		return (0);
1203	}
1204	*gotsomewhere = 1;
1205	if (resplen < HFIXEDSZ) {
1206		/*
1207		 * Undersized message.
1208		 */
1209		Dprint(statp->options & RES_DEBUG,
1210		       (stdout, ";; undersized: %d\n",
1211			resplen));
1212		*terrno = EMSGSIZE;
1213		res_nclose(statp);
1214		return (0);
1215	}
1216	if (hp->id != anhp->id) {
1217		/*
1218		 * response from old query, ignore it.
1219		 * XXX - potential security hazard could
1220		 *	 be detected here.
1221		 */
1222#ifdef ANDROID_CHANGES
1223		__libc_android_log_event_uid(BIONIC_EVENT_RESOLVER_OLD_RESPONSE);
1224#endif
1225		DprintQ((statp->options & RES_DEBUG) ||
1226			(statp->pfcode & RES_PRF_REPLY),
1227			(stdout, ";; old answer:\n"),
1228			ans, (resplen > anssiz) ? anssiz : resplen);
1229		goto retry;
1230	}
1231	if (!(statp->options & RES_INSECURE1) &&
1232	    !res_ourserver_p(statp, (struct sockaddr *)(void *)&from)) {
1233		/*
1234		 * response from wrong server? ignore it.
1235		 * XXX - potential security hazard could
1236		 *	 be detected here.
1237		 */
1238#ifdef ANDROID_CHANGES
1239		__libc_android_log_event_uid(BIONIC_EVENT_RESOLVER_WRONG_SERVER);
1240#endif
1241		DprintQ((statp->options & RES_DEBUG) ||
1242			(statp->pfcode & RES_PRF_REPLY),
1243			(stdout, ";; not our server:\n"),
1244			ans, (resplen > anssiz) ? anssiz : resplen);
1245		goto retry;
1246	}
1247#ifdef RES_USE_EDNS0
1248	if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
1249		/*
1250		 * Do not retry if the server do not understand EDNS0.
1251		 * The case has to be captured here, as FORMERR packet do not
1252		 * carry query section, hence res_queriesmatch() returns 0.
1253		 */
1254		DprintQ(statp->options & RES_DEBUG,
1255			(stdout, "server rejected query with EDNS0:\n"),
1256			ans, (resplen > anssiz) ? anssiz : resplen);
1257		/* record the error */
1258		statp->_flags |= RES_F_EDNS0ERR;
1259		res_nclose(statp);
1260		return (0);
1261	}
1262#endif
1263	if (!(statp->options & RES_INSECURE2) &&
1264	    !res_queriesmatch(buf, buf + buflen,
1265			      ans, ans + anssiz)) {
1266		/*
1267		 * response contains wrong query? ignore it.
1268		 * XXX - potential security hazard could
1269		 *	 be detected here.
1270		 */
1271#ifdef ANDROID_CHANGES
1272		__libc_android_log_event_uid(BIONIC_EVENT_RESOLVER_WRONG_QUERY);
1273#endif
1274		DprintQ((statp->options & RES_DEBUG) ||
1275			(statp->pfcode & RES_PRF_REPLY),
1276			(stdout, ";; wrong query name:\n"),
1277			ans, (resplen > anssiz) ? anssiz : resplen);
1278		goto retry;;
1279	}
1280	done = evNowTime();
1281	*delay = _res_stats_calculate_rtt(&done, &now);
1282	if (anhp->rcode == SERVFAIL ||
1283	    anhp->rcode == NOTIMP ||
1284	    anhp->rcode == REFUSED) {
1285		DprintQ(statp->options & RES_DEBUG,
1286			(stdout, "server rejected query:\n"),
1287			ans, (resplen > anssiz) ? anssiz : resplen);
1288		res_nclose(statp);
1289		/* don't retry if called from dig */
1290		if (!statp->pfcode) {
1291			*rcode = anhp->rcode;
1292			return (0);
1293		}
1294	}
1295	if (!(statp->options & RES_IGNTC) && anhp->tc) {
1296		/*
1297		 * To get the rest of answer,
1298		 * use TCP with same server.
1299		 */
1300		Dprint(statp->options & RES_DEBUG,
1301		       (stdout, ";; truncated answer\n"));
1302		*v_circuit = 1;
1303		res_nclose(statp);
1304		return (1);
1305	}
1306	/*
1307	 * All is well, or the error is fatal.  Signal that the
1308	 * next nameserver ought not be tried.
1309	 */
1310	if (resplen > 0) {
1311		*rcode = anhp->rcode;
1312	}
1313	return (resplen);
1314}
1315
1316static void
1317Aerror(const res_state statp, FILE *file, const char *string, int error,
1318       const struct sockaddr *address, int alen)
1319{
1320	int save = errno;
1321	char hbuf[NI_MAXHOST];
1322	char sbuf[NI_MAXSERV];
1323
1324	if ((statp->options & RES_DEBUG) != 0U) {
1325		if (getnameinfo(address, (socklen_t)alen, hbuf, sizeof(hbuf),
1326		    sbuf, sizeof(sbuf), niflags)) {
1327			strncpy(hbuf, "?", sizeof(hbuf) - 1);
1328			hbuf[sizeof(hbuf) - 1] = '\0';
1329			strncpy(sbuf, "?", sizeof(sbuf) - 1);
1330			sbuf[sizeof(sbuf) - 1] = '\0';
1331		}
1332		fprintf(file, "res_send: %s ([%s].%s): %s\n",
1333			string, hbuf, sbuf, strerror(error));
1334	}
1335	errno = save;
1336}
1337
1338static void
1339Perror(const res_state statp, FILE *file, const char *string, int error) {
1340	int save = errno;
1341
1342	if ((statp->options & RES_DEBUG) != 0U)
1343		fprintf(file, "res_send: %s: %s\n",
1344			string, strerror(error));
1345	errno = save;
1346}
1347
1348static int
1349sock_eq(struct sockaddr *a, struct sockaddr *b) {
1350	struct sockaddr_in *a4, *b4;
1351	struct sockaddr_in6 *a6, *b6;
1352
1353	if (a->sa_family != b->sa_family)
1354		return 0;
1355	switch (a->sa_family) {
1356	case AF_INET:
1357		a4 = (struct sockaddr_in *)(void *)a;
1358		b4 = (struct sockaddr_in *)(void *)b;
1359		return a4->sin_port == b4->sin_port &&
1360		    a4->sin_addr.s_addr == b4->sin_addr.s_addr;
1361	case AF_INET6:
1362		a6 = (struct sockaddr_in6 *)(void *)a;
1363		b6 = (struct sockaddr_in6 *)(void *)b;
1364		return a6->sin6_port == b6->sin6_port &&
1365#ifdef HAVE_SIN6_SCOPE_ID
1366		    a6->sin6_scope_id == b6->sin6_scope_id &&
1367#endif
1368		    IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
1369	default:
1370		return 0;
1371	}
1372}
1373
1374#ifdef NEED_PSELECT
1375/* XXX needs to move to the porting library. */
1376static int
1377pselect(int nfds, void *rfds, void *wfds, void *efds,
1378	struct timespec *tsp, const sigset_t *sigmask)
1379{
1380	struct timeval tv, *tvp;
1381	sigset_t sigs;
1382	int n;
1383
1384	if (tsp) {
1385		tvp = &tv;
1386		tv = evTimeVal(*tsp);
1387	} else
1388		tvp = NULL;
1389	if (sigmask)
1390		sigprocmask(SIG_SETMASK, sigmask, &sigs);
1391	n = select(nfds, rfds, wfds, efds, tvp);
1392	if (sigmask)
1393		sigprocmask(SIG_SETMASK, &sigs, NULL);
1394	if (tsp)
1395		*tsp = evTimeSpec(tv);
1396	return (n);
1397}
1398#endif
1399