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