• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*	$NetBSD: gethnamaddr.c,v 1.91 2014/06/19 15:08:18 christos Exp $	*/
2 
3 /*
4  * ++Copyright++ 1985, 1988, 1993
5  * -
6  * Copyright (c) 1985, 1988, 1993
7  *    The Regents of the University of California.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  * -
33  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
34  *
35  * Permission to use, copy, modify, and distribute this software for any
36  * purpose with or without fee is hereby granted, provided that the above
37  * copyright notice and this permission notice appear in all copies, and that
38  * the name of Digital Equipment Corporation not be used in advertising or
39  * publicity pertaining to distribution of the document or software without
40  * specific, written prior permission.
41  *
42  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
43  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
44  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
45  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
46  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
47  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
48  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
49  * SOFTWARE.
50  * -
51  * --Copyright--
52  */
53 
54 #include <sys/cdefs.h>
55 #include <sys/types.h>
56 
57 #include <sys/param.h>
58 #include <sys/socket.h>
59 #include <sys/un.h>
60 #include <netinet/in.h>
61 #include <arpa/inet.h>
62 #include <arpa/nameser.h>
63 #include "NetdClientDispatch.h"
64 #include "resolv_netid.h"
65 #include "resolv_private.h"
66 #include "resolv_cache.h"
67 #include <assert.h>
68 #include <ctype.h>
69 #include <errno.h>
70 #include <netdb.h>
71 #include <stdarg.h>
72 #include <stdbool.h>
73 #include <stdio.h>
74 #include <strings.h>
75 #include <syslog.h>
76 #include <unistd.h>
77 
78 #define ALIGNBYTES (sizeof(uintptr_t) - 1)
79 #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
80 
81 #ifndef LOG_AUTH
82 # define LOG_AUTH 0
83 #endif
84 
85 #define MULTI_PTRS_ARE_ALIASES 1	/* XXX - experimental */
86 
87 #include "nsswitch.h"
88 #include <stdlib.h>
89 #include <string.h>
90 
91 #include "hostent.h"
92 
93 #define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \
94                                (ok)(nm) != 0)
95 #define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
96 #define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
97 
98 #define addalias(d, s, arr, siz) do {			\
99 	if (d >= &arr[siz]) {				\
100 		char **xptr = realloc(arr, (siz + 10) * sizeof(*arr)); \
101 		if (xptr == NULL)			\
102 			goto nospc;			\
103 		d = xptr + (d - arr);			\
104 		arr = xptr;				\
105 		siz += 10;				\
106 	}						\
107 	*d++ = s;					\
108 } while (/*CONSTCOND*/0)
109 
110 #define setup(arr, siz) do {				\
111 	arr = malloc((siz = 10) * sizeof(*arr)); 	\
112 	if (arr == NULL)				\
113 		goto nospc;				\
114 } while (/*CONSTCOND*/0)
115 
116 // This should be synchronized to ResponseCode.h
117 static const int DnsProxyQueryResult = 222;
118 
119 static const char AskedForGot[] =
120 			  "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
121 
122 static const struct android_net_context NETCONTEXT_UNSET = {
123 	.app_mark = MARK_UNSET,
124 	.app_netid = NETID_UNSET,
125 	.dns_mark = MARK_UNSET,
126 	.dns_netid = NETID_UNSET,
127 	.uid = NET_CONTEXT_INVALID_UID
128 };
129 
130 #define	MAXPACKET	(64*1024)
131 
132 typedef union {
133     HEADER hdr;
134     u_char buf[MAXPACKET];
135 } querybuf;
136 
137 typedef union {
138     int32_t al;
139     char ac;
140 } align;
141 
142 #ifdef DEBUG
143 static void debugprintf(const char *, res_state, ...)
144 	__attribute__((__format__(__printf__, 1, 3)));
145 #endif
146 static struct hostent *getanswer(const querybuf *, int, const char *, int,
147     res_state, struct hostent *, char *, size_t, int *);
148 static void map_v4v6_address(const char *, char *);
149 static void map_v4v6_hostent(struct hostent *, char **, char *);
150 static void addrsort(char **, int, res_state);
151 
152 void ht_sethostent(int);
153 void ht_endhostent(void);
154 struct hostent *ht_gethostbyname(char *);
155 struct hostent *ht_gethostbyaddr(const char *, int, int);
156 void dns_service(void);
157 #undef dn_skipname
158 int dn_skipname(const u_char *, const u_char *);
159 static int _dns_gethtbyaddr(void *, void *, va_list);
160 static int _dns_gethtbyname(void *, void *, va_list);
161 
162 static struct hostent *gethostbyname_internal(const char *, int, res_state,
163     struct hostent *, char *, size_t, int *, const struct android_net_context *);
164 static struct hostent* android_gethostbyaddrfornetcontext_proxy_internal(const void*, socklen_t,
165     int, struct hostent *, char *, size_t, int *, const struct android_net_context *);
166 
167 static const ns_src default_dns_files[] = {
168 	{ NSSRC_FILES, 	NS_SUCCESS },
169 	{ NSSRC_DNS, 	NS_SUCCESS },
170 	{ 0, 0 }
171 };
172 
173 
174 #ifdef DEBUG
175 static void
debugprintf(const char * msg,res_state res,...)176 debugprintf(const char *msg, res_state res, ...)
177 {
178 	_DIAGASSERT(msg != NULL);
179 
180 	if (res->options & RES_DEBUG) {
181 		int save = errno;
182 		va_list ap;
183 
184 		va_start (ap, res);
185 		vprintf(msg, ap);
186 		va_end (ap);
187 
188 		errno = save;
189 	}
190 }
191 #else
192 # define debugprintf(msg, res, num) /*nada*/
193 #endif
194 
195 #define BOUNDED_INCR(x) \
196 	do { \
197 		BOUNDS_CHECK(cp, x); \
198 		cp += (x); \
199 	} while (/*CONSTCOND*/0)
200 
201 #define BOUNDS_CHECK(ptr, count) \
202 	do { \
203 		if (eom - (ptr) < (count)) \
204 			goto no_recovery; \
205 	} while (/*CONSTCOND*/0)
206 
207 static struct hostent *
getanswer(const querybuf * answer,int anslen,const char * qname,int qtype,res_state res,struct hostent * hent,char * buf,size_t buflen,int * he)208 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
209     res_state res, struct hostent *hent, char *buf, size_t buflen, int *he)
210 {
211 	const HEADER *hp;
212 	const u_char *cp;
213 	int n;
214 	size_t qlen;
215 	const u_char *eom, *erdata;
216 	char *bp, **ap, **hap, *ep;
217 	int type, class, ancount, qdcount;
218 	int haveanswer, had_error;
219 	int toobig = 0;
220 	char tbuf[MAXDNAME];
221 	char **aliases;
222 	size_t maxaliases;
223 	char *addr_ptrs[MAXADDRS];
224 	const char *tname;
225 	int (*name_ok)(const char *);
226 
227 	_DIAGASSERT(answer != NULL);
228 	_DIAGASSERT(qname != NULL);
229 
230 	tname = qname;
231 	hent->h_name = NULL;
232 	eom = answer->buf + anslen;
233 	switch (qtype) {
234 	case T_A:
235 	case T_AAAA:
236 		name_ok = res_hnok;
237 		break;
238 	case T_PTR:
239 		name_ok = res_dnok;
240 		break;
241 	default:
242 	  *he = NO_RECOVERY;
243 		return NULL;	/* XXX should be abort(); */
244 	}
245 
246 	setup(aliases, maxaliases);
247 	/*
248 	 * find first satisfactory answer
249 	 */
250 	hp = &answer->hdr;
251 	ancount = ntohs(hp->ancount);
252 	qdcount = ntohs(hp->qdcount);
253 	bp = buf;
254 	ep = buf + buflen;
255 	cp = answer->buf;
256 	BOUNDED_INCR(HFIXEDSZ);
257 	if (qdcount != 1)
258 		goto no_recovery;
259 
260 	n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
261 	if ((n < 0) || !maybe_ok(res, bp, name_ok))
262 		goto no_recovery;
263 
264 	BOUNDED_INCR(n + QFIXEDSZ);
265 	if (qtype == T_A || qtype == T_AAAA) {
266 		/* res_send() has already verified that the query name is the
267 		 * same as the one we sent; this just gets the expanded name
268 		 * (i.e., with the succeeding search-domain tacked on).
269 		 */
270 		n = (int)strlen(bp) + 1;		/* for the \0 */
271 		if (n >= MAXHOSTNAMELEN)
272 			goto no_recovery;
273 		hent->h_name = bp;
274 		bp += n;
275 		/* The qname can be abbreviated, but h_name is now absolute. */
276 		qname = hent->h_name;
277 	}
278 	hent->h_aliases = ap = aliases;
279 	hent->h_addr_list = hap = addr_ptrs;
280 	*ap = NULL;
281 	*hap = NULL;
282 	haveanswer = 0;
283 	had_error = 0;
284 	while (ancount-- > 0 && cp < eom && !had_error) {
285 		n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
286 		if ((n < 0) || !maybe_ok(res, bp, name_ok)) {
287 			had_error++;
288 			continue;
289 		}
290 		cp += n;			/* name */
291 		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
292 		type = _getshort(cp);
293  		cp += INT16SZ;			/* type */
294 		class = _getshort(cp);
295  		cp += INT16SZ + INT32SZ;	/* class, TTL */
296 		n = _getshort(cp);
297 		cp += INT16SZ;			/* len */
298 		BOUNDS_CHECK(cp, n);
299 		erdata = cp + n;
300 		if (class != C_IN) {
301 			/* XXX - debug? syslog? */
302 			cp += n;
303 			continue;		/* XXX - had_error++ ? */
304 		}
305 		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
306 			n = dn_expand(answer->buf, eom, cp, tbuf,
307 			    (int)sizeof tbuf);
308 			if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) {
309 				had_error++;
310 				continue;
311 			}
312 			cp += n;
313 			if (cp != erdata)
314 				goto no_recovery;
315 			/* Store alias. */
316 			addalias(ap, bp, aliases, maxaliases);
317 			n = (int)strlen(bp) + 1;	/* for the \0 */
318 			if (n >= MAXHOSTNAMELEN) {
319 				had_error++;
320 				continue;
321 			}
322 			bp += n;
323 			/* Get canonical name. */
324 			n = (int)strlen(tbuf) + 1;	/* for the \0 */
325 			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
326 				had_error++;
327 				continue;
328 			}
329 			strlcpy(bp, tbuf, (size_t)(ep - bp));
330 			hent->h_name = bp;
331 			bp += n;
332 			continue;
333 		}
334 		if (qtype == T_PTR && type == T_CNAME) {
335 			n = dn_expand(answer->buf, eom, cp, tbuf,
336 			    (int)sizeof tbuf);
337 			if (n < 0 || !maybe_dnok(res, tbuf)) {
338 				had_error++;
339 				continue;
340 			}
341 			cp += n;
342 			if (cp != erdata)
343 				goto no_recovery;
344 			/* Get canonical name. */
345 			n = (int)strlen(tbuf) + 1;	/* for the \0 */
346 			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
347 				had_error++;
348 				continue;
349 			}
350 			strlcpy(bp, tbuf, (size_t)(ep - bp));
351 			tname = bp;
352 			bp += n;
353 			continue;
354 		}
355 		if (type != qtype) {
356 			if (type != T_KEY && type != T_SIG)
357 				syslog(LOG_NOTICE|LOG_AUTH,
358 	       "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
359 				       qname, p_class(C_IN), p_type(qtype),
360 				       p_type(type));
361 			cp += n;
362 			continue;		/* XXX - had_error++ ? */
363 		}
364 		switch (type) {
365 		case T_PTR:
366 			if (strcasecmp(tname, bp) != 0) {
367 				syslog(LOG_NOTICE|LOG_AUTH,
368 				       AskedForGot, qname, bp);
369 				cp += n;
370 				continue;	/* XXX - had_error++ ? */
371 			}
372 			n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
373 			if ((n < 0) || !maybe_hnok(res, bp)) {
374 				had_error++;
375 				break;
376 			}
377 #if MULTI_PTRS_ARE_ALIASES
378 			cp += n;
379 			if (cp != erdata)
380 				goto no_recovery;
381 			if (!haveanswer)
382 				hent->h_name = bp;
383 			else
384 				addalias(ap, bp, aliases, maxaliases);
385 			if (n != -1) {
386 				n = (int)strlen(bp) + 1;	/* for the \0 */
387 				if (n >= MAXHOSTNAMELEN) {
388 					had_error++;
389 					break;
390 				}
391 				bp += n;
392 			}
393 			break;
394 #else
395 			hent->h_name = bp;
396 			if (res->options & RES_USE_INET6) {
397 				n = strlen(bp) + 1;	/* for the \0 */
398 				if (n >= MAXHOSTNAMELEN) {
399 					had_error++;
400 					break;
401 				}
402 				bp += n;
403 				map_v4v6_hostent(hent, &bp, ep);
404 			}
405 			goto success;
406 #endif
407 		case T_A:
408 		case T_AAAA:
409 			if (strcasecmp(hent->h_name, bp) != 0) {
410 				syslog(LOG_NOTICE|LOG_AUTH,
411 				       AskedForGot, hent->h_name, bp);
412 				cp += n;
413 				continue;	/* XXX - had_error++ ? */
414 			}
415 			if (n != hent->h_length) {
416 				cp += n;
417 				continue;
418 			}
419 			if (type == T_AAAA) {
420 				struct in6_addr in6;
421 				memcpy(&in6, cp, NS_IN6ADDRSZ);
422 				if (IN6_IS_ADDR_V4MAPPED(&in6)) {
423 					cp += n;
424 					continue;
425 				}
426 			}
427 			if (!haveanswer) {
428 				int nn;
429 
430 				hent->h_name = bp;
431 				nn = (int)strlen(bp) + 1;	/* for the \0 */
432 				bp += nn;
433 			}
434 
435 			bp += sizeof(align) -
436 			    (size_t)((u_long)bp % sizeof(align));
437 
438 			if (bp + n >= ep) {
439 				debugprintf("size (%d) too big\n", res, n);
440 				had_error++;
441 				continue;
442 			}
443 			if (hap >= &addr_ptrs[MAXADDRS - 1]) {
444 				if (!toobig++) {
445 					debugprintf("Too many addresses (%d)\n",
446 						res, MAXADDRS);
447 				}
448 				cp += n;
449 				continue;
450 			}
451 			(void)memcpy(*hap++ = bp, cp, (size_t)n);
452 			bp += n;
453 			cp += n;
454 			if (cp != erdata)
455 				goto no_recovery;
456 			break;
457 		default:
458 			abort();
459 		}
460 		if (!had_error)
461 			haveanswer++;
462 	}
463 	if (haveanswer) {
464 		*ap = NULL;
465 		*hap = NULL;
466 		/*
467 		 * Note: we sort even if host can take only one address
468 		 * in its return structures - should give it the "best"
469 		 * address in that case, not some random one
470 		 */
471 		if (res->nsort && haveanswer > 1 && qtype == T_A)
472 			addrsort(addr_ptrs, haveanswer, res);
473 		if (!hent->h_name) {
474 			n = (int)strlen(qname) + 1;	/* for the \0 */
475 			if (n > ep - bp || n >= MAXHOSTNAMELEN)
476 				goto no_recovery;
477 			strlcpy(bp, qname, (size_t)(ep - bp));
478 			hent->h_name = bp;
479 			bp += n;
480 		}
481 		if (res->options & RES_USE_INET6)
482 			map_v4v6_hostent(hent, &bp, ep);
483 	  goto success;
484 	}
485 no_recovery:
486 	free(aliases);
487 	*he = NO_RECOVERY;
488 	return NULL;
489 success:
490 	bp = (char *)ALIGN(bp);
491 	n = (int)(ap - aliases);
492 	qlen = (n + 1) * sizeof(*hent->h_aliases);
493 	if ((size_t)(ep - bp) < qlen)
494 		goto nospc;
495 	hent->h_aliases = (void *)bp;
496 	memcpy(bp, aliases, qlen);
497 	free(aliases);
498 	aliases = NULL;
499 
500 	bp += qlen;
501 	n = (int)(hap - addr_ptrs);
502 	qlen = (n + 1) * sizeof(*hent->h_addr_list);
503 	if ((size_t)(ep - bp) < qlen)
504 		goto nospc;
505 	hent->h_addr_list = (void *)bp;
506 	memcpy(bp, addr_ptrs, qlen);
507 	*he = NETDB_SUCCESS;
508 	return hent;
509 nospc:
510 	free(aliases);
511 	errno = ENOSPC;
512 	*he = NETDB_INTERNAL;
513 	return NULL;
514 }
515 
516 /* The prototype of gethostbyname_r is from glibc, not that in netbsd. */
517 int
gethostbyname_r(const char * name,struct hostent * hp,char * buf,size_t buflen,struct hostent ** result,int * errorp)518 gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen,
519     struct hostent **result, int *errorp)
520 {
521 	res_state res = __res_get_state();
522 
523 	if (res == NULL) {
524 	  *result = NULL;
525 		*errorp = NETDB_INTERNAL;
526 		return -1;
527 	}
528 
529 	_DIAGASSERT(name != NULL);
530 
531 	if (res->options & RES_USE_INET6) {
532 		*result = gethostbyname_internal(name, AF_INET6, res, hp, buf, buflen, errorp,
533 		                                 &NETCONTEXT_UNSET);
534 		if (*result) {
535 			__res_put_state(res);
536 			return 0;
537 		}
538 	}
539 	*result = gethostbyname_internal(name, AF_INET, res, hp, buf, buflen, errorp,
540 	                                 &NETCONTEXT_UNSET);
541 	__res_put_state(res);
542 	if (!*result && errno == ENOSPC) {
543 	  errno = ERANGE;
544 	  return ERANGE; /* Return error as in linux manual page. */
545 	}
546 	return (*result) ? 0 : -1;
547 }
548 
549 /* The prototype of gethostbyname2_r is from glibc, not that in netbsd. */
550 int
gethostbyname2_r(const char * name,int af,struct hostent * hp,char * buf,size_t buflen,struct hostent ** result,int * errorp)551 gethostbyname2_r(const char *name, int af, struct hostent *hp, char *buf,
552     size_t buflen, struct hostent **result, int *errorp)
553 {
554 	res_state res = __res_get_state();
555 
556 	if (res == NULL) {
557 		*result = NULL;
558 		*errorp = NETDB_INTERNAL;
559 		return -1;
560 	}
561 	*result = gethostbyname_internal(name, af, res, hp, buf, buflen, errorp,
562 	                                 &NETCONTEXT_UNSET);
563 	__res_put_state(res);
564 	if (!*result && errno == ENOSPC) {
565 		errno = ERANGE;
566 		return ERANGE;
567 	}
568 	return (*result) ? 0 : -1;
569 }
570 
android_open_proxy()571 __LIBC_HIDDEN__ FILE* android_open_proxy() {
572 	const char* cache_mode = getenv("ANDROID_DNS_MODE");
573 	bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
574 	if (!use_proxy) {
575 		return NULL;
576 	}
577 
578 	int s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
579 	if (s == -1) {
580 		return NULL;
581 	}
582 
583 	const int one = 1;
584 	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
585 
586 	struct sockaddr_un proxy_addr;
587 	memset(&proxy_addr, 0, sizeof(proxy_addr));
588 	proxy_addr.sun_family = AF_UNIX;
589 	strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
590 
591 	if (TEMP_FAILURE_RETRY(connect(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
592 		close(s);
593 		return NULL;
594 	}
595 
596 	return fdopen(s, "r+");
597 }
598 
599 static struct hostent *
android_read_hostent(FILE * proxy,struct hostent * hp,char * hbuf,size_t hbuflen,int * he)600 android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen, int *he)
601 {
602 	uint32_t size;
603 	char buf[4];
604 	if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return NULL;
605 
606 	// This is reading serialized data from system/netd/server/DnsProxyListener.cpp
607 	// and changes here need to be matched there.
608 	int result_code = strtol(buf, NULL, 10);
609 	if (result_code != DnsProxyQueryResult) {
610 		fread(&size, 1, sizeof(size), proxy);
611 		*he = HOST_NOT_FOUND;
612 		return NULL;
613 	}
614 
615 	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
616 	size = ntohl(size);
617 
618 	memset(hp, 0, sizeof(*hp));
619 	char *ptr = hbuf;
620 	char *hbuf_end = hbuf + hbuflen;
621 
622 	if (ptr + size > hbuf_end) {
623 		goto nospc;
624 	}
625 	if (fread(ptr, 1, size, proxy) != size) return NULL;
626 	hp->h_name = ptr;
627 	ptr += size;
628 
629 	char *aliases_ptrs[MAXALIASES];
630 	char **aliases = &aliases_ptrs[0];
631 
632 	while (1) {
633 		if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
634 		size = ntohl(size);
635 
636 		if (size == 0) {
637 			*aliases = NULL;
638 			break;
639 		}
640 		if (ptr + size > hbuf_end) {
641 		  goto nospc;
642 		}
643 		if (fread(ptr, 1, size, proxy) != size) return NULL;
644 		if (aliases < &aliases_ptrs[MAXALIASES - 1]) {
645 		  *aliases++ = ptr;
646 		}
647 		ptr += size;
648 	}
649 
650 	// Fix alignment after variable-length data.
651 	ptr = (char*)ALIGN(ptr);
652 
653 	int aliases_len = ((int)(aliases - aliases_ptrs) + 1) * sizeof(*hp->h_aliases);
654 	if (ptr + aliases_len > hbuf_end) {
655 		goto nospc;
656 	}
657 	hp->h_aliases = (void*)ptr;
658 	memcpy(ptr, aliases_ptrs, aliases_len);
659 	ptr += aliases_len;
660 
661 	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
662 	hp->h_addrtype = ntohl(size);
663 
664 	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
665 	hp->h_length = ntohl(size);
666 
667 	char *addr_ptrs[MAXADDRS];
668 	char **addr_p = &addr_ptrs[0];
669 
670 	while (1) {
671 		if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
672 		size = ntohl(size);
673 		if (size == 0) {
674 			*addr_p = NULL;
675 			break;
676 		}
677 		if (ptr + size > hbuf_end) {
678 		  goto nospc;
679 		}
680 		if (fread(ptr, 1, size, proxy) != size) return NULL;
681 		if (addr_p < &addr_ptrs[MAXADDRS - 1]) {
682 		  *addr_p++ = ptr;
683 		}
684 		ptr += size;
685 	}
686 
687 	// Fix alignment after variable-length data.
688 	ptr = (char*)ALIGN(ptr);
689 
690 	int addrs_len = ((int)(addr_p - addr_ptrs) + 1) * sizeof(*hp->h_addr_list);
691 	if (ptr + addrs_len > hbuf_end) {
692 		goto nospc;
693 	}
694 	hp->h_addr_list = (void*)ptr;
695 	memcpy(ptr, addr_ptrs, addrs_len);
696 	*he = NETDB_SUCCESS;
697 	return hp;
698 
699 nospc:
700 	*he = NETDB_INTERNAL;
701 	errno = ENOSPC;
702 	return NULL;
703 }
704 
705 static struct hostent *
gethostbyname_internal_real(const char * name,int af,res_state res,struct hostent * hp,char * buf,size_t buflen,int * he)706 gethostbyname_internal_real(const char *name, int af, res_state res, struct hostent *hp, char *buf,
707                             size_t buflen, int *he)
708 {
709 	const char *cp;
710 	struct getnamaddr info;
711 	char hbuf[MAXHOSTNAMELEN];
712 	size_t size;
713 	static const ns_dtab dtab[] = {
714 		NS_FILES_CB(_hf_gethtbyname, NULL)
715 		{ NSSRC_DNS, _dns_gethtbyname, NULL },	/* force -DHESIOD */
716 		NS_NIS_CB(_yp_gethtbyname, NULL)
717 		NS_NULL_CB
718 	};
719 
720 	_DIAGASSERT(name != NULL);
721 
722 	switch (af) {
723 	case AF_INET:
724 		size = NS_INADDRSZ;
725 		break;
726 	case AF_INET6:
727 		size = NS_IN6ADDRSZ;
728 		break;
729 	default:
730 		*he = NETDB_INTERNAL;
731 		errno = EAFNOSUPPORT;
732 		return NULL;
733 	}
734 	if (buflen < size)
735 		goto nospc;
736 
737 	hp->h_addrtype = af;
738 	hp->h_length = (int)size;
739 
740 	/*
741 	 * if there aren't any dots, it could be a user-level alias.
742 	 * this is also done in res_nquery() since we are not the only
743 	 * function that looks up host names.
744 	 */
745 	if (!strchr(name, '.') && (cp = res_hostalias(res, name,
746 	    hbuf, sizeof(hbuf))))
747 		name = cp;
748 
749 	/*
750 	 * disallow names consisting only of digits/dots, unless
751 	 * they end in a dot.
752 	 */
753 	if (isdigit((u_char) name[0]))
754 		for (cp = name;; ++cp) {
755 			if (!*cp) {
756 				if (*--cp == '.')
757 					break;
758 				/*
759 				 * All-numeric, no dot at the end.
760 				 * Fake up a hostent as if we'd actually
761 				 * done a lookup.
762 				 */
763 				goto fake;
764 			}
765 			if (!isdigit((u_char) *cp) && *cp != '.')
766 				break;
767 		}
768 	if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) ||
769 	    name[0] == ':')
770 		for (cp = name;; ++cp) {
771 			if (!*cp) {
772 				if (*--cp == '.')
773 					break;
774 				/*
775 				 * All-IPv6-legal, no dot at the end.
776 				 * Fake up a hostent as if we'd actually
777 				 * done a lookup.
778 				 */
779 				goto fake;
780 			}
781 			if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
782 				break;
783 		}
784 
785 	*he = NETDB_INTERNAL;
786 	info.hp = hp;
787 	info.buf = buf;
788 	info.buflen = buflen;
789 	info.he = he;
790 	if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyname",
791 	    default_dns_files, name, strlen(name), af) != NS_SUCCESS)
792 		return NULL;
793 	*he = NETDB_SUCCESS;
794 	return hp;
795 nospc:
796 	*he = NETDB_INTERNAL;
797 	errno = ENOSPC;
798 	return NULL;
799 fake:
800 	HENT_ARRAY(hp->h_addr_list, 1, buf, buflen);
801 	HENT_ARRAY(hp->h_aliases, 0, buf, buflen);
802 
803 	hp->h_aliases[0] = NULL;
804 	if (size > buflen)
805 		goto nospc;
806 
807 	if (inet_pton(af, name, buf) <= 0) {
808 		*he = HOST_NOT_FOUND;
809 		return NULL;
810 	}
811 	hp->h_addr_list[0] = buf;
812 	hp->h_addr_list[1] = NULL;
813 	buf += size;
814 	buflen -= size;
815 	HENT_SCOPY(hp->h_name, name, buf, buflen);
816 	if (res->options & RES_USE_INET6)
817 		map_v4v6_hostent(hp, &buf, buf + buflen);
818 	*he = NETDB_SUCCESS;
819 	return hp;
820 }
821 
822 // very similar in proxy-ness to android_getaddrinfo_proxy
823 static struct hostent *
gethostbyname_internal(const char * name,int af,res_state res,struct hostent * hp,char * hbuf,size_t hbuflen,int * errorp,const struct android_net_context * netcontext)824 gethostbyname_internal(const char *name, int af, res_state res, struct hostent *hp, char *hbuf,
825                        size_t hbuflen, int *errorp, const struct android_net_context *netcontext)
826 {
827 	FILE* proxy = android_open_proxy();
828 	if (proxy == NULL) {
829 		// Either we're not supposed to be using the proxy or the proxy is unavailable.
830 		res_setnetcontext(res, netcontext);
831 		return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen, errorp);
832 	}
833 
834 	unsigned netid = __netdClientDispatch.netIdForResolv(netcontext->app_netid);
835 
836 	// This is writing to system/netd/server/DnsProxyListener.cpp and changes
837 	// here need to be matched there.
838 	if (fprintf(proxy, "gethostbyname %u %s %d",
839 			netid,
840 			name == NULL ? "^" : name,
841 			af) < 0) {
842 		fclose(proxy);
843 		return NULL;
844 	}
845 
846 	if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
847 		fclose(proxy);
848 		return NULL;
849 	}
850 
851 	struct hostent* result = android_read_hostent(proxy, hp, hbuf, hbuflen, errorp);
852 	fclose(proxy);
853 	return result;
854 }
855 
856 /* The prototype of gethostbyaddr_r is from glibc, not that in netbsd. */
gethostbyaddr_r(const void * addr,socklen_t len,int af,struct hostent * hp,char * buf,size_t buflen,struct hostent ** result,int * h_errnop)857 int gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp, char *buf,
858                     size_t buflen, struct hostent **result, int *h_errnop)
859 {
860 	*result = android_gethostbyaddrfornetcontext_proxy_internal(
861 		addr, len, af, hp, buf, buflen, h_errnop, &NETCONTEXT_UNSET);
862 	if (!*result && errno == ENOSPC) {
863 		errno = ERANGE;
864 		return ERANGE;
865 	}
866 	return (*result) ? 0 : -1;
867 }
868 
869 static struct hostent *
android_gethostbyaddrfornetcontext_real(const void * addr,socklen_t len,int af,struct hostent * hp,char * buf,size_t buflen,int * he,const struct android_net_context * netcontext)870 android_gethostbyaddrfornetcontext_real(const void *addr, socklen_t len, int af, struct hostent *hp,
871                                  char *buf, size_t buflen, int *he,
872 				 const struct android_net_context *netcontext)
873 {
874 	const u_char *uaddr = (const u_char *)addr;
875 	socklen_t size;
876 	struct getnamaddr info;
877 	static const ns_dtab dtab[] = {
878 		NS_FILES_CB(_hf_gethtbyaddr, NULL)
879 		{ NSSRC_DNS, _dns_gethtbyaddr, NULL },	/* force -DHESIOD */
880 		NS_NIS_CB(_yp_gethtbyaddr, NULL)
881 		NS_NULL_CB
882 	};
883 
884 	_DIAGASSERT(addr != NULL);
885 
886 	if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
887 	    (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) ||
888 	     IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) {
889 		*he = HOST_NOT_FOUND;
890 		return NULL;
891 	}
892 	if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
893 	    (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)addr) ||
894 	     IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)addr))) {
895 		/* Unmap. */
896 		uaddr += NS_IN6ADDRSZ - NS_INADDRSZ;
897 		addr = uaddr;
898 		af = AF_INET;
899 		len = NS_INADDRSZ;
900 	}
901 	switch (af) {
902 	case AF_INET:
903 		size = NS_INADDRSZ;
904 		break;
905 	case AF_INET6:
906 		size = NS_IN6ADDRSZ;
907 		break;
908 	default:
909 		errno = EAFNOSUPPORT;
910 		*he = NETDB_INTERNAL;
911 		return NULL;
912 	}
913 	if (size != len) {
914 		errno = EINVAL;
915 		*he = NETDB_INTERNAL;
916 		return NULL;
917 	}
918 	info.hp = hp;
919 	info.buf = buf;
920 	info.buflen = buflen;
921 	info.he = he;
922 	*he = NETDB_INTERNAL;
923 	if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyaddr",
924 	    default_dns_files, uaddr, len, af, netcontext) != NS_SUCCESS)
925 		return NULL;
926 	*he = NETDB_SUCCESS;
927 	return hp;
928 }
929 
930 static struct hostent*
android_gethostbyaddrfornetcontext_proxy_internal(const void * addr,socklen_t len,int af,struct hostent * hp,char * hbuf,size_t hbuflen,int * he,const struct android_net_context * netcontext)931 android_gethostbyaddrfornetcontext_proxy_internal(const void* addr, socklen_t len, int af,
932                              struct hostent *hp, char *hbuf, size_t hbuflen, int *he,
933                              const struct android_net_context *netcontext)
934 {
935 	FILE* proxy = android_open_proxy();
936 	if (proxy == NULL) {
937 		// Either we're not supposed to be using the proxy or the proxy is unavailable.
938 		return android_gethostbyaddrfornetcontext_real(addr,len, af, hp, hbuf, hbuflen, he, netcontext);
939 	}
940 
941 	char buf[INET6_ADDRSTRLEN];  //big enough for IPv4 and IPv6
942 	const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
943 	if (addrStr == NULL) {
944 		fclose(proxy);
945 		return NULL;
946 	}
947 
948 	unsigned netid = __netdClientDispatch.netIdForResolv(netcontext->app_netid);
949 
950 	if (fprintf(proxy, "gethostbyaddr %s %d %d %u",
951 			addrStr, len, af, netid) < 0) {
952 		fclose(proxy);
953 		return NULL;
954 	}
955 
956 	if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
957 		fclose(proxy);
958 		return NULL;
959 	}
960 
961 	struct hostent *result = android_read_hostent(proxy, hp, hbuf, hbuflen, he);
962 	fclose(proxy);
963 	return result;
964 }
965 
966 struct hostent*
netbsd_gethostent_r(FILE * hf,struct hostent * hent,char * buf,size_t buflen,int * he)967 netbsd_gethostent_r(FILE *hf, struct hostent *hent, char *buf, size_t buflen, int *he)
968 {
969 	char *p, *name;
970 	char *cp, **q;
971 	int af, len;
972 	size_t anum;
973 	char **aliases;
974 	size_t maxaliases;
975 	struct in6_addr host_addr;
976 
977 	if (hf == NULL) {
978 		*he = NETDB_INTERNAL;
979 		errno = EINVAL;
980 		return NULL;
981 	}
982 	p = NULL;
983 	setup(aliases, maxaliases);
984 
985 	/* Allocate a new space to read file lines like upstream does.
986 	 * To keep reentrancy we cannot use __res_get_static()->hostbuf here,
987 	 * as the buffer may be used to store content for a previous hostent
988 	 * returned by non-reentrant functions like gethostbyname().
989 	 */
990 	const size_t line_buf_size = sizeof(__res_get_static()->hostbuf);
991 	if ((p = malloc(line_buf_size)) == NULL) {
992 	  goto nospc;
993 	}
994 	for (;;) {
995 		if (!fgets(p, line_buf_size, hf)) {
996 			free(p);
997 			free(aliases);
998 			*he = HOST_NOT_FOUND;
999 			return NULL;
1000     		}
1001 		if (*p == '#') {
1002 			continue;
1003 		}
1004 		if (!(cp = strpbrk(p, "#\n"))) {
1005 			continue;
1006 		}
1007 		*cp = '\0';
1008 		if (!(cp = strpbrk(p, " \t")))
1009 			continue;
1010 		*cp++ = '\0';
1011 		if (inet_pton(AF_INET6, p, &host_addr) > 0) {
1012 			af = AF_INET6;
1013 			len = NS_IN6ADDRSZ;
1014 		} else {
1015 			if (inet_pton(AF_INET, p, &host_addr) <= 0)
1016 				continue;
1017 
1018 			res_state res = __res_get_state();
1019 			if (res == NULL)
1020 				goto nospc;
1021 			if (res->options & RES_USE_INET6) {
1022 				map_v4v6_address(buf, buf);
1023 				af = AF_INET6;
1024 				len = NS_IN6ADDRSZ;
1025 			} else {
1026 				af = AF_INET;
1027 				len = NS_INADDRSZ;
1028 			}
1029 			__res_put_state(res);
1030 		}
1031 
1032 		/* if this is not something we're looking for, skip it. */
1033 		if (hent->h_addrtype != 0 && hent->h_addrtype != af)
1034 			continue;
1035 		if (hent->h_length != 0 && hent->h_length != len)
1036 			continue;
1037 
1038 		while (*cp == ' ' || *cp == '\t')
1039 			cp++;
1040 		if ((cp = strpbrk(name = cp, " \t")) != NULL)
1041 			*cp++ = '\0';
1042 		q = aliases;
1043 		while (cp && *cp) {
1044 			if (*cp == ' ' || *cp == '\t') {
1045 				cp++;
1046 				continue;
1047 			}
1048 			addalias(q, cp, aliases, maxaliases);
1049 			if ((cp = strpbrk(cp, " \t")) != NULL)
1050 				*cp++ = '\0';
1051 		}
1052 		break;
1053 	}
1054 	hent->h_length = len;
1055 	hent->h_addrtype = af;
1056 	HENT_ARRAY(hent->h_addr_list, 1, buf, buflen);
1057 	anum = (size_t)(q - aliases);
1058 	HENT_ARRAY(hent->h_aliases, anum, buf, buflen);
1059 	HENT_COPY(hent->h_addr_list[0], &host_addr, hent->h_length, buf,
1060 	    buflen);
1061 	hent->h_addr_list[1] = NULL;
1062 
1063 	HENT_SCOPY(hent->h_name, name, buf, buflen);
1064 	for (size_t i = 0; i < anum; i++)
1065 		HENT_SCOPY(hent->h_aliases[i], aliases[i], buf, buflen);
1066 	hent->h_aliases[anum] = NULL;
1067 
1068 	*he = NETDB_SUCCESS;
1069 	free(p);
1070 	free(aliases);
1071 	return hent;
1072 nospc:
1073 	free(p);
1074 	free(aliases);
1075 	errno = ENOSPC;
1076 	*he = NETDB_INTERNAL;
1077 	return NULL;
1078 }
1079 
1080 static void
map_v4v6_address(const char * src,char * dst)1081 map_v4v6_address(const char *src, char *dst)
1082 {
1083 	u_char *p = (u_char *)dst;
1084 	char tmp[NS_INADDRSZ];
1085 	int i;
1086 
1087 	_DIAGASSERT(src != NULL);
1088 	_DIAGASSERT(dst != NULL);
1089 
1090 	/* Stash a temporary copy so our caller can update in place. */
1091 	(void)memcpy(tmp, src, NS_INADDRSZ);
1092 	/* Mark this ipv6 addr as a mapped ipv4. */
1093 	for (i = 0; i < 10; i++)
1094 		*p++ = 0x00;
1095 	*p++ = 0xff;
1096 	*p++ = 0xff;
1097 	/* Retrieve the saved copy and we're done. */
1098 	(void)memcpy(p, tmp, NS_INADDRSZ);
1099 }
1100 
1101 static void
map_v4v6_hostent(struct hostent * hp,char ** bpp,char * ep)1102 map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
1103 {
1104 	char **ap;
1105 
1106 	_DIAGASSERT(hp != NULL);
1107 	_DIAGASSERT(bpp != NULL);
1108 	_DIAGASSERT(ep != NULL);
1109 
1110 	if (hp->h_addrtype != AF_INET || hp->h_length != NS_INADDRSZ)
1111 		return;
1112 	hp->h_addrtype = AF_INET6;
1113 	hp->h_length = NS_IN6ADDRSZ;
1114 	for (ap = hp->h_addr_list; *ap; ap++) {
1115 		int i = (int)(sizeof(align) -
1116 		    (size_t)((u_long)*bpp % sizeof(align)));
1117 
1118 		if (ep - *bpp < (i + NS_IN6ADDRSZ)) {
1119 			/* Out of memory.  Truncate address list here.  XXX */
1120 			*ap = NULL;
1121 			return;
1122 		}
1123 		*bpp += i;
1124 		map_v4v6_address(*ap, *bpp);
1125 		*ap = *bpp;
1126 		*bpp += NS_IN6ADDRSZ;
1127 	}
1128 }
1129 
1130 static void
addrsort(char ** ap,int num,res_state res)1131 addrsort(char **ap, int num, res_state res)
1132 {
1133 	int i, j;
1134 	char **p;
1135 	short aval[MAXADDRS];
1136 	int needsort = 0;
1137 
1138 	_DIAGASSERT(ap != NULL);
1139 
1140 	p = ap;
1141 	for (i = 0; i < num; i++, p++) {
1142 	    for (j = 0 ; (unsigned)j < res->nsort; j++)
1143 		if (res->sort_list[j].addr.s_addr ==
1144 		    (((struct in_addr *)(void *)(*p))->s_addr &
1145 		    res->sort_list[j].mask))
1146 			break;
1147 	    aval[i] = j;
1148 	    if (needsort == 0 && i > 0 && j < aval[i-1])
1149 		needsort = i;
1150 	}
1151 	if (!needsort)
1152 	    return;
1153 
1154 	while (needsort < num) {
1155 	    for (j = needsort - 1; j >= 0; j--) {
1156 		if (aval[j] > aval[j+1]) {
1157 		    char *hp;
1158 
1159 		    i = aval[j];
1160 		    aval[j] = aval[j+1];
1161 		    aval[j+1] = i;
1162 
1163 		    hp = ap[j];
1164 		    ap[j] = ap[j+1];
1165 		    ap[j+1] = hp;
1166 		} else
1167 		    break;
1168 	    }
1169 	    needsort++;
1170 	}
1171 }
1172 
1173 /*ARGSUSED*/
1174 static int
_dns_gethtbyname(void * rv,void * cb_data,va_list ap)1175 _dns_gethtbyname(void *rv, void *cb_data, va_list ap)
1176 {
1177 	querybuf *buf;
1178 	int n, type;
1179 	struct hostent *hp;
1180 	const char *name;
1181 	res_state res;
1182 	struct getnamaddr *info = rv;
1183 
1184 	_DIAGASSERT(rv != NULL);
1185 
1186 	name = va_arg(ap, char *);
1187 	/* NOSTRICT skip string len */(void)va_arg(ap, int);
1188 	info->hp->h_addrtype = va_arg(ap, int);
1189 
1190 	switch (info->hp->h_addrtype) {
1191 	case AF_INET:
1192 		info->hp->h_length = NS_INADDRSZ;
1193 		type = T_A;
1194 		break;
1195 	case AF_INET6:
1196 		info->hp->h_length = NS_IN6ADDRSZ;
1197 		type = T_AAAA;
1198 		break;
1199 	default:
1200 		return NS_UNAVAIL;
1201 	}
1202 	buf = malloc(sizeof(*buf));
1203 	if (buf == NULL) {
1204 		*info->he = NETDB_INTERNAL;
1205 		return NS_NOTFOUND;
1206 	}
1207 	res = __res_get_state();
1208 	if (res == NULL) {
1209 		free(buf);
1210 		return NS_NOTFOUND;
1211 	}
1212 	n = res_nsearch(res, name, C_IN, type, buf->buf, (int)sizeof(buf->buf));
1213 	if (n < 0) {
1214 		free(buf);
1215 		debugprintf("res_nsearch failed (%d)\n", res, n);
1216 		__res_put_state(res);
1217 		return NS_NOTFOUND;
1218 	}
1219 	hp = getanswer(buf, n, name, type, res, info->hp, info->buf,
1220 	    info->buflen, info->he);
1221 	free(buf);
1222 	__res_put_state(res);
1223 	if (hp == NULL)
1224 		switch (*info->he) {
1225 		case HOST_NOT_FOUND:
1226 			return NS_NOTFOUND;
1227 		case TRY_AGAIN:
1228 			return NS_TRYAGAIN;
1229 		default:
1230 			return NS_UNAVAIL;
1231 		}
1232 	return NS_SUCCESS;
1233 }
1234 
1235 /*ARGSUSED*/
1236 static int
_dns_gethtbyaddr(void * rv,void * cb_data,va_list ap)1237 _dns_gethtbyaddr(void *rv, void	*cb_data, va_list ap)
1238 {
1239 	char qbuf[MAXDNAME + 1], *qp, *ep;
1240 	int n;
1241 	querybuf *buf;
1242 	struct hostent *hp;
1243 	const unsigned char *uaddr;
1244 	int advance;
1245 	res_state res;
1246 	char *bf;
1247 	size_t blen;
1248 	struct getnamaddr *info = rv;
1249 	const struct android_net_context *netcontext;
1250 
1251 	_DIAGASSERT(rv != NULL);
1252 
1253 	uaddr = va_arg(ap, unsigned char *);
1254 	info->hp->h_length = va_arg(ap, int);
1255 	info->hp->h_addrtype = va_arg(ap, int);
1256 	netcontext = va_arg(ap, const struct android_net_context *);
1257 
1258 	switch (info->hp->h_addrtype) {
1259 	case AF_INET:
1260 		(void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
1261 		    (uaddr[3] & 0xff), (uaddr[2] & 0xff),
1262 		    (uaddr[1] & 0xff), (uaddr[0] & 0xff));
1263 		break;
1264 
1265 	case AF_INET6:
1266 		qp = qbuf;
1267 		ep = qbuf + sizeof(qbuf) - 1;
1268 		for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) {
1269 			advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
1270 			    uaddr[n] & 0xf,
1271 			    ((unsigned int)uaddr[n] >> 4) & 0xf);
1272 			if (advance > 0 && qp + advance < ep)
1273 				qp += advance;
1274 			else {
1275 				*info->he = NETDB_INTERNAL;
1276 				return NS_NOTFOUND;
1277 			}
1278 		}
1279 		if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
1280 			*info->he = NETDB_INTERNAL;
1281 			return NS_NOTFOUND;
1282 		}
1283 		break;
1284 	default:
1285 		return NS_UNAVAIL;
1286 	}
1287 
1288 	buf = malloc(sizeof(*buf));
1289 	if (buf == NULL) {
1290 		*info->he = NETDB_INTERNAL;
1291 		return NS_NOTFOUND;
1292 	}
1293 	res = __res_get_state();
1294 	if (res == NULL) {
1295 		free(buf);
1296 		return NS_NOTFOUND;
1297 	}
1298 	res_setnetcontext(res, netcontext);
1299 	n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf));
1300 	if (n < 0) {
1301 		free(buf);
1302 		debugprintf("res_nquery failed (%d)\n", res, n);
1303 		__res_put_state(res);
1304 		return NS_NOTFOUND;
1305 	}
1306 	hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf,
1307 	    info->buflen, info->he);
1308 	free(buf);
1309 	if (hp == NULL) {
1310 		__res_put_state(res);
1311 		switch (*info->he) {
1312 		case HOST_NOT_FOUND:
1313 			return NS_NOTFOUND;
1314 		case TRY_AGAIN:
1315 			return NS_TRYAGAIN;
1316 		default:
1317 			return NS_UNAVAIL;
1318 		}
1319 	}
1320 
1321 	bf = (void *)(hp->h_addr_list + 2);
1322 	blen = (size_t)(bf - info->buf);
1323 	if (blen + info->hp->h_length > info->buflen)
1324 		goto nospc;
1325 	hp->h_addr_list[0] = bf;
1326 	hp->h_addr_list[1] = NULL;
1327 	(void)memcpy(bf, uaddr, (size_t)info->hp->h_length);
1328 	if (info->hp->h_addrtype == AF_INET && (res->options & RES_USE_INET6)) {
1329 		if (blen + NS_IN6ADDRSZ > info->buflen)
1330 			goto nospc;
1331 		map_v4v6_address(bf, bf);
1332 		hp->h_addrtype = AF_INET6;
1333 		hp->h_length = NS_IN6ADDRSZ;
1334 	}
1335 
1336 	__res_put_state(res);
1337 	*info->he = NETDB_SUCCESS;
1338 	return NS_SUCCESS;
1339 nospc:
1340 	errno = ENOSPC;
1341 	*info->he = NETDB_INTERNAL;
1342 	return NS_UNAVAIL;
1343 }
1344 
1345 #ifdef YP
1346 /*ARGSUSED*/
1347 static struct hostent *
_yp_hostent(char * line,int af,struct getnamaddr * info)1348 _yp_hostent(char *line, int af, struct getnamaddr *info)
1349 {
1350 	struct in6_addr host_addrs[MAXADDRS];
1351 	char **aliases;
1352 	size_t maxaliases;
1353 	char *p = line;
1354 	char *cp, **q, *ptr;
1355 	size_t len, anum, i;
1356 	int addrok;
1357 	int more;
1358 	size_t naddrs;
1359 	struct hostent *hp = info->hp;
1360 
1361 	_DIAGASSERT(line != NULL);
1362 
1363 	hp->h_name = NULL;
1364 	hp->h_addrtype = af;
1365 	switch (af) {
1366 	case AF_INET:
1367 		hp->h_length = NS_INADDRSZ;
1368 		break;
1369 	case AF_INET6:
1370 		hp->h_length = NS_IN6ADDRSZ;
1371 		break;
1372 	default:
1373 		return NULL;
1374 	}
1375 	setup(aliases, maxaliases);
1376 	naddrs = 0;
1377 	q = aliases;
1378 
1379 nextline:
1380 	/* check for host_addrs overflow */
1381 	if (naddrs >= __arraycount(host_addrs))
1382 		goto done;
1383 
1384 	more = 0;
1385 	cp = strpbrk(p, " \t");
1386 	if (cp == NULL)
1387 		goto done;
1388 	*cp++ = '\0';
1389 
1390 	/* p has should have an address */
1391 	addrok = inet_pton(af, p, &host_addrs[naddrs]);
1392 	if (addrok != 1) {
1393 		/* skip to the next line */
1394 		while (cp && *cp) {
1395 			if (*cp == '\n') {
1396 				cp++;
1397 				goto nextline;
1398 			}
1399 			cp++;
1400 		}
1401 		goto done;
1402 	}
1403 	naddrs++;
1404 
1405 	while (*cp == ' ' || *cp == '\t')
1406 		cp++;
1407 	p = cp;
1408 	cp = strpbrk(p, " \t\n");
1409 	if (cp != NULL) {
1410 		if (*cp == '\n')
1411 			more = 1;
1412 		*cp++ = '\0';
1413 	}
1414 	if (!hp->h_name)
1415 		hp->h_name = p;
1416 	else if (strcmp(hp->h_name, p) == 0)
1417 		;
1418 	else
1419 		addalias(q, p, aliases, maxaliases);
1420 	p = cp;
1421 	if (more)
1422 		goto nextline;
1423 
1424 	while (cp && *cp) {
1425 		if (*cp == ' ' || *cp == '\t') {
1426 			cp++;
1427 			continue;
1428 		}
1429 		if (*cp == '\n') {
1430 			cp++;
1431 			goto nextline;
1432 		}
1433 		addalias(q, cp, aliases, maxaliases);
1434 		cp = strpbrk(cp, " \t");
1435 		if (cp != NULL)
1436 			*cp++ = '\0';
1437 	}
1438 
1439 done:
1440 	if (hp->h_name == NULL) {
1441 		free(aliases);
1442 		return NULL;
1443 	}
1444 
1445 	ptr = info->buf;
1446 	len = info->buflen;
1447 
1448 	anum = (size_t)(q - aliases);
1449 	HENT_ARRAY(hp->h_addr_list, naddrs, ptr, len);
1450 	HENT_ARRAY(hp->h_aliases, anum, ptr, len);
1451 
1452 	for (i = 0; i < naddrs; i++)
1453 		HENT_COPY(hp->h_addr_list[i], &host_addrs[i], hp->h_length,
1454 		    ptr, len);
1455 	hp->h_addr_list[naddrs] = NULL;
1456 
1457 	HENT_SCOPY(hp->h_name, hp->h_name, ptr, len);
1458 
1459 	for (i = 0; i < anum; i++)
1460 		HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len);
1461 	hp->h_aliases[anum] = NULL;
1462 	free(aliases);
1463 
1464 	return hp;
1465 nospc:
1466 	free(aliases);
1467 	*info->he = NETDB_INTERNAL;
1468 	errno = ENOSPC;
1469 	return NULL;
1470 }
1471 
1472 /*ARGSUSED*/
1473 int
_yp_gethtbyaddr(void * rv,void * cb_data,va_list ap)1474 _yp_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1475 {
1476 	struct hostent *hp = NULL;
1477 	char *ypcurrent;
1478 	int ypcurrentlen, r;
1479 	char name[INET6_ADDRSTRLEN];	/* XXX enough? */
1480 	const unsigned char *uaddr;
1481 	int af;
1482 	const char *map;
1483 	struct getnamaddr *info = rv;
1484 
1485 	_DIAGASSERT(rv != NULL);
1486 
1487 	uaddr = va_arg(ap, unsigned char *);
1488 	/* NOSTRICT skip len */(void)va_arg(ap, int);
1489 	af = va_arg(ap, int);
1490 
1491 	if (!__ypdomain) {
1492 		if (_yp_check(&__ypdomain) == 0)
1493 			return NS_UNAVAIL;
1494 	}
1495 	/*
1496 	 * XXX unfortunately, we cannot support IPv6 extended scoped address
1497 	 * notation here.  gethostbyaddr() is not scope-aware.  too bad.
1498 	 */
1499 	if (inet_ntop(af, uaddr, name, (socklen_t)sizeof(name)) == NULL)
1500 		return NS_UNAVAIL;
1501 	switch (af) {
1502 	case AF_INET:
1503 		map = "hosts.byaddr";
1504 		break;
1505 	default:
1506 		map = "ipnodes.byaddr";
1507 		break;
1508 	}
1509 	ypcurrent = NULL;
1510 	r = yp_match(__ypdomain, map, name,
1511 		(int)strlen(name), &ypcurrent, &ypcurrentlen);
1512 	if (r == 0)
1513 		hp = _yp_hostent(ypcurrent, af, info);
1514 	else
1515 		hp = NULL;
1516 	free(ypcurrent);
1517 	if (hp == NULL) {
1518 		*info->he = HOST_NOT_FOUND;
1519 		return NS_NOTFOUND;
1520 	}
1521 	return NS_SUCCESS;
1522 }
1523 
1524 /*ARGSUSED*/
1525 int
_yp_gethtbyname(void * rv,void * cb_data,va_list ap)1526 _yp_gethtbyname(void *rv, void *cb_data, va_list ap)
1527 {
1528 	struct hostent *hp;
1529 	char *ypcurrent;
1530 	int ypcurrentlen, r;
1531 	const char *name;
1532 	int af;
1533 	const char *map;
1534 	struct getnamaddr *info = rv;
1535 
1536 	_DIAGASSERT(rv != NULL);
1537 
1538 	name = va_arg(ap, char *);
1539 	/* NOSTRICT skip string len */(void)va_arg(ap, int);
1540 	af = va_arg(ap, int);
1541 
1542 	if (!__ypdomain) {
1543 		if (_yp_check(&__ypdomain) == 0)
1544 			return NS_UNAVAIL;
1545 	}
1546 	switch (af) {
1547 	case AF_INET:
1548 		map = "hosts.byname";
1549 		break;
1550 	default:
1551 		map = "ipnodes.byname";
1552 		break;
1553 	}
1554 	ypcurrent = NULL;
1555 	r = yp_match(__ypdomain, map, name,
1556 		(int)strlen(name), &ypcurrent, &ypcurrentlen);
1557 	if (r == 0)
1558 		hp = _yp_hostent(ypcurrent, af, info);
1559 	else
1560 		hp = NULL;
1561 	free(ypcurrent);
1562 	if (hp == NULL) {
1563 		*info->he = HOST_NOT_FOUND;
1564 		return NS_NOTFOUND;
1565 	}
1566 	return NS_SUCCESS;
1567 }
1568 #endif
1569 
1570 /*
1571  * Non-reentrant versions.
1572  */
1573 
1574 struct hostent *
gethostbyname(const char * name)1575 gethostbyname(const char *name)
1576 {
1577 	struct hostent *result = NULL;
1578 	res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
1579 
1580 	gethostbyname_r(name, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno);
1581 	return result;
1582 }
1583 
1584 struct hostent *
gethostbyname2(const char * name,int af)1585 gethostbyname2(const char *name, int af)
1586 {
1587 	struct hostent *result = NULL;
1588 	res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
1589 
1590 	gethostbyname2_r(name, af, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno);
1591 	return result;
1592 }
1593 
1594 // android_gethostby*fornet can be called in two different contexts.
1595 //  - In the proxy client context (proxy != NULL), |netid| is |app_netid|.
1596 //  - In the proxy listener context (proxy == NULL), |netid| is |dns_netid|.
1597 // The netcontext is constructed before checking which context we are in.
1598 // Therefore, we have to populate both fields, and rely on the downstream code to check whether
1599 // |proxy == NULL|, and use that info to query the field that matches the caller's intent.
make_context(unsigned netid,unsigned mark)1600 static struct android_net_context make_context(unsigned netid, unsigned mark) {
1601 	struct android_net_context netcontext = NETCONTEXT_UNSET;
1602 	netcontext.app_netid = netid;
1603 	netcontext.app_mark = mark;
1604 	netcontext.dns_netid = netid;
1605 	netcontext.dns_mark = mark;
1606 	return netcontext;
1607 }
1608 
1609 struct hostent *
android_gethostbynamefornet(const char * name,int af,unsigned netid,unsigned mark)1610 android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark)
1611 {
1612 	const struct android_net_context netcontext = make_context(netid, mark);
1613 	return android_gethostbynamefornetcontext(name, af, &netcontext);
1614 }
1615 
1616 struct hostent *
android_gethostbynamefornetcontext(const char * name,int af,const struct android_net_context * netcontext)1617 android_gethostbynamefornetcontext(const char *name, int af,
1618 	const struct android_net_context *netcontext)
1619 {
1620 	struct hostent *hp;
1621 	res_state res = __res_get_state();
1622 	if (res == NULL)
1623 		return NULL;
1624 	res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
1625 	hp = gethostbyname_internal(name, af, res, &rs->host, rs->hostbuf, sizeof(rs->hostbuf),
1626 	                            &h_errno, netcontext);
1627 	__res_put_state(res);
1628 	return hp;
1629 }
1630 
1631 struct hostent *
gethostbyaddr(const void * addr,socklen_t len,int af)1632 gethostbyaddr(const void *addr, socklen_t len, int af)
1633 {
1634 	return android_gethostbyaddrfornetcontext_proxy(addr, len, af, &NETCONTEXT_UNSET);
1635 }
1636 
1637 struct hostent *
android_gethostbyaddrfornet(const void * addr,socklen_t len,int af,unsigned netid,unsigned mark)1638 android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark)
1639 {
1640 	const struct android_net_context netcontext = make_context(netid, mark);
1641 	return android_gethostbyaddrfornetcontext(addr, len, af, &netcontext);
1642 }
1643 
1644 struct hostent *
android_gethostbyaddrfornetcontext(const void * addr,socklen_t len,int af,const struct android_net_context * netcontext)1645 android_gethostbyaddrfornetcontext(const void *addr, socklen_t len, int af,
1646 	const struct android_net_context *netcontext)
1647 {
1648 	return android_gethostbyaddrfornetcontext_proxy(addr, len, af, netcontext);
1649 }
1650 
1651 __LIBC_HIDDEN__ struct hostent*
android_gethostbyaddrfornetcontext_proxy(const void * addr,socklen_t len,int af,const struct android_net_context * netcontext)1652 android_gethostbyaddrfornetcontext_proxy(const void* addr, socklen_t len, int af,
1653                                   const struct android_net_context *netcontext)
1654 {
1655 	res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
1656 	return android_gethostbyaddrfornetcontext_proxy_internal(addr, len, af, &rs->host, rs->hostbuf,
1657                                                     sizeof(rs->hostbuf), &h_errno, netcontext);
1658 }
1659 
1660 struct hostent *
gethostent(void)1661 gethostent(void)
1662 {
1663   res_static  rs = __res_get_static();
1664 	if (!rs->hostf) {
1665 	  sethostent_r(&rs->hostf);
1666 	  if (!rs->hostf) {
1667 	    h_errno = NETDB_INTERNAL;
1668 	    return NULL;
1669 	  }
1670 	}
1671 	memset(&rs->host, 0, sizeof(rs->host));
1672 	return netbsd_gethostent_r(rs->hostf, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &h_errno);
1673 }
1674