gethnamaddr.c revision c20de902875dcaebde0ccd0b7a8351598f254d4c
1/*	$NetBSD: gethnamaddr.c,v 1.70 2006/03/22 00:03:51 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 "resolv_private.h"
64#include "resolv_cache.h"
65#include <assert.h>
66#include <ctype.h>
67#include <errno.h>
68#include <netdb.h>
69#include <stdarg.h>
70#include <stdio.h>
71#include <strings.h>
72#include <syslog.h>
73#include <unistd.h>
74
75#define ALIGNBYTES (sizeof(uintptr_t) - 1)
76#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
77
78#ifndef LOG_AUTH
79# define LOG_AUTH 0
80#endif
81
82#define MULTI_PTRS_ARE_ALIASES 1	/* XXX - experimental */
83
84#include "nsswitch.h"
85#include <stdlib.h>
86#include <string.h>
87
88// This should be synchronized to ResponseCode.h
89static const int DnsProxyQueryResult = 222;
90
91static const char const AskedForGot[] =
92			  "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
93
94#define	MAXPACKET	(64*1024)
95
96typedef union {
97    HEADER hdr;
98    u_char buf[MAXPACKET];
99} querybuf;
100
101typedef union {
102    int32_t al;
103    char ac;
104} align;
105
106#ifdef DEBUG
107static void dprintf(const char *, res_state, ...)
108	__attribute__((__format__(__printf__, 1, 3)));
109#endif
110static struct hostent *getanswer(const querybuf *, int, const char *, int,
111    res_state);
112static void map_v4v6_address(const char *, char *);
113static void map_v4v6_hostent(struct hostent *, char **, char *);
114static void addrsort(char **, int, res_state);
115
116static void _sethtent(int);
117static void _endhtent(void);
118static struct hostent *_gethtent(void);
119void ht_sethostent(int);
120void ht_endhostent(void);
121struct hostent *ht_gethostbyname(char *);
122struct hostent *ht_gethostbyaddr(const char *, int, int);
123void dns_service(void);
124#undef dn_skipname
125int dn_skipname(const u_char *, const u_char *);
126static int _gethtbyaddr(void *, void *, va_list);
127static int _gethtbyname(void *, void *, va_list);
128static struct hostent *_gethtbyname2(const char *, int);
129static int _dns_gethtbyaddr(void *, void *, va_list);
130static int _dns_gethtbyname(void *, void *, va_list);
131
132static struct hostent *gethostbyname_internal(const char *, int, res_state, const char *, int);
133
134static const ns_src default_dns_files[] = {
135	{ NSSRC_FILES, 	NS_SUCCESS },
136	{ NSSRC_DNS, 	NS_SUCCESS },
137	{ 0, 0 }
138};
139
140
141#ifdef DEBUG
142static void
143dprintf(const char *msg, res_state res, ...)
144{
145	assert(msg != NULL);
146
147	if (res->options & RES_DEBUG) {
148		int save = errno;
149		va_list ap;
150
151		va_start (ap, res);
152		vprintf(msg, ap);
153		va_end (ap);
154
155		errno = save;
156	}
157}
158#else
159# define dprintf(msg, res, num) ((void)0) /*nada*/
160#endif
161
162#define BOUNDED_INCR(x) \
163	do { \
164		cp += (x); \
165		if (cp > eom) { \
166			h_errno = NO_RECOVERY; \
167			return NULL; \
168		} \
169	} while (/*CONSTCOND*/0)
170
171#define BOUNDS_CHECK(ptr, count) \
172	do { \
173		if ((ptr) + (count) > eom) { \
174			h_errno = NO_RECOVERY; \
175			return NULL; \
176		} \
177	} while (/*CONSTCOND*/0)
178
179static struct hostent *
180getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
181    res_state res)
182{
183	const HEADER *hp;
184	const u_char *cp;
185	int n;
186	const u_char *eom, *erdata;
187	char *bp, **ap, **hap, *ep;
188	int type, class, ancount, qdcount;
189	int haveanswer, had_error;
190	int toobig = 0;
191	char tbuf[MAXDNAME];
192	const char *tname;
193	int (*name_ok)(const char *);
194	res_static  rs = __res_get_static();
195
196	assert(answer != NULL);
197	assert(qname != NULL);
198
199	tname = qname;
200	rs->host.h_name = NULL;
201	eom = answer->buf + anslen;
202	switch (qtype) {
203	case T_A:
204	case T_AAAA:
205		name_ok = res_hnok;
206		break;
207	case T_PTR:
208		name_ok = res_dnok;
209		break;
210	default:
211		return NULL;	/* XXX should be abort(); */
212	}
213	/*
214	 * find first satisfactory answer
215	 */
216	hp = &answer->hdr;
217	ancount = ntohs(hp->ancount);
218	qdcount = ntohs(hp->qdcount);
219	bp = rs->hostbuf;
220	ep = rs->hostbuf + sizeof rs->hostbuf;
221	cp = answer->buf;
222	BOUNDED_INCR(HFIXEDSZ);
223	if (qdcount != 1) {
224		h_errno = NO_RECOVERY;
225		return NULL;
226	}
227	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
228	if ((n < 0) || !(*name_ok)(bp)) {
229		h_errno = NO_RECOVERY;
230		return NULL;
231	}
232	BOUNDED_INCR(n + QFIXEDSZ);
233	if (qtype == T_A || qtype == T_AAAA) {
234		/* res_send() has already verified that the query name is the
235		 * same as the one we sent; this just gets the expanded name
236		 * (i.e., with the succeeding search-domain tacked on).
237		 */
238		n = strlen(bp) + 1;		/* for the \0 */
239		if (n >= MAXHOSTNAMELEN) {
240			h_errno = NO_RECOVERY;
241			return NULL;
242		}
243		rs->host.h_name = bp;
244		bp += n;
245		/* The qname can be abbreviated, but h_name is now absolute. */
246		qname = rs->host.h_name;
247	}
248	ap = rs->host_aliases;
249	*ap = NULL;
250	rs->host.h_aliases = rs->host_aliases;
251	hap = rs->h_addr_ptrs;
252	*hap = NULL;
253	rs->host.h_addr_list = rs->h_addr_ptrs;
254	haveanswer = 0;
255	had_error = 0;
256	while (ancount-- > 0 && cp < eom && !had_error) {
257		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
258		if ((n < 0) || !(*name_ok)(bp)) {
259			had_error++;
260			continue;
261		}
262		cp += n;			/* name */
263		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
264		type = _getshort(cp);
265 		cp += INT16SZ;			/* type */
266		class = _getshort(cp);
267 		cp += INT16SZ + INT32SZ;	/* class, TTL */
268		n = _getshort(cp);
269		cp += INT16SZ;			/* len */
270		BOUNDS_CHECK(cp, n);
271		erdata = cp + n;
272		if (class != C_IN) {
273			/* XXX - debug? syslog? */
274			cp += n;
275			continue;		/* XXX - had_error++ ? */
276		}
277		if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
278			if (ap >= &rs->host_aliases[MAXALIASES-1])
279				continue;
280			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
281			if ((n < 0) || !(*name_ok)(tbuf)) {
282				had_error++;
283				continue;
284			}
285			cp += n;
286			if (cp != erdata) {
287				h_errno = NO_RECOVERY;
288				return NULL;
289			}
290			/* Store alias. */
291			*ap++ = bp;
292			n = strlen(bp) + 1;	/* for the \0 */
293			if (n >= MAXHOSTNAMELEN) {
294				had_error++;
295				continue;
296			}
297			bp += n;
298			/* Get canonical name. */
299			n = strlen(tbuf) + 1;	/* for the \0 */
300			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
301				had_error++;
302				continue;
303			}
304			strlcpy(bp, tbuf, (size_t)(ep - bp));
305			rs->host.h_name = bp;
306			bp += n;
307			continue;
308		}
309		if (qtype == T_PTR && type == T_CNAME) {
310			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
311			if (n < 0 || !res_dnok(tbuf)) {
312				had_error++;
313				continue;
314			}
315			cp += n;
316			if (cp != erdata) {
317				h_errno = NO_RECOVERY;
318				return NULL;
319			}
320			/* Get canonical name. */
321			n = strlen(tbuf) + 1;	/* for the \0 */
322			if (n > ep - bp || n >= MAXHOSTNAMELEN) {
323				had_error++;
324				continue;
325			}
326			strlcpy(bp, tbuf, (size_t)(ep - bp));
327			tname = bp;
328			bp += n;
329			continue;
330		}
331		if (type != qtype) {
332			if (type != T_KEY && type != T_SIG)
333				syslog(LOG_NOTICE|LOG_AUTH,
334	       "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
335				       qname, p_class(C_IN), p_type(qtype),
336				       p_type(type));
337			cp += n;
338			continue;		/* XXX - had_error++ ? */
339		}
340		switch (type) {
341		case T_PTR:
342			if (strcasecmp(tname, bp) != 0) {
343				syslog(LOG_NOTICE|LOG_AUTH,
344				       AskedForGot, qname, bp);
345				cp += n;
346				continue;	/* XXX - had_error++ ? */
347			}
348			n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
349			if ((n < 0) || !res_hnok(bp)) {
350				had_error++;
351				break;
352			}
353#if MULTI_PTRS_ARE_ALIASES
354			cp += n;
355			if (cp != erdata) {
356				h_errno = NO_RECOVERY;
357				return NULL;
358			}
359			if (!haveanswer)
360				rs->host.h_name = bp;
361			else if (ap < &rs->host_aliases[MAXALIASES-1])
362				*ap++ = bp;
363			else
364				n = -1;
365			if (n != -1) {
366				n = strlen(bp) + 1;	/* for the \0 */
367				if (n >= MAXHOSTNAMELEN) {
368					had_error++;
369					break;
370				}
371				bp += n;
372			}
373			break;
374#else
375			rs->host.h_name = bp;
376			if (res->options & RES_USE_INET6) {
377				n = strlen(bp) + 1;	/* for the \0 */
378				if (n >= MAXHOSTNAMELEN) {
379					had_error++;
380					break;
381				}
382				bp += n;
383				map_v4v6_hostent(&rs->host, &bp, ep);
384			}
385			h_errno = NETDB_SUCCESS;
386			return &rs->host;
387#endif
388		case T_A:
389		case T_AAAA:
390			if (strcasecmp(rs->host.h_name, bp) != 0) {
391				syslog(LOG_NOTICE|LOG_AUTH,
392				       AskedForGot, rs->host.h_name, bp);
393				cp += n;
394				continue;	/* XXX - had_error++ ? */
395			}
396			if (n != rs->host.h_length) {
397				cp += n;
398				continue;
399			}
400			if (type == T_AAAA) {
401				struct in6_addr in6;
402				memcpy(&in6, cp, IN6ADDRSZ);
403				if (IN6_IS_ADDR_V4MAPPED(&in6)) {
404					cp += n;
405					continue;
406				}
407			}
408			if (!haveanswer) {
409				int nn;
410
411				rs->host.h_name = bp;
412				nn = strlen(bp) + 1;	/* for the \0 */
413				bp += nn;
414			}
415
416			bp += sizeof(align) -
417			    (size_t)((u_long)bp % sizeof(align));
418
419			if (bp + n >= &rs->hostbuf[sizeof rs->hostbuf]) {
420				dprintf("size (%d) too big\n", res, n);
421				had_error++;
422				continue;
423			}
424			if (hap >= &rs->h_addr_ptrs[MAXADDRS-1]) {
425				if (!toobig++)
426					dprintf("Too many addresses (%d)\n",
427						res, MAXADDRS);
428				cp += n;
429				continue;
430			}
431			(void)memcpy(*hap++ = bp, cp, (size_t)n);
432			bp += n;
433			cp += n;
434			if (cp != erdata) {
435				h_errno = NO_RECOVERY;
436				return NULL;
437			}
438			break;
439		default:
440			abort();
441		}
442		if (!had_error)
443			haveanswer++;
444	}
445	if (haveanswer) {
446		*ap = NULL;
447		*hap = NULL;
448		/*
449		 * Note: we sort even if host can take only one address
450		 * in its return structures - should give it the "best"
451		 * address in that case, not some random one
452		 */
453		if (res->nsort && haveanswer > 1 && qtype == T_A)
454			addrsort(rs->h_addr_ptrs, haveanswer, res);
455		if (!rs->host.h_name) {
456			n = strlen(qname) + 1;	/* for the \0 */
457			if (n > ep - bp || n >= MAXHOSTNAMELEN)
458				goto no_recovery;
459			strlcpy(bp, qname, (size_t)(ep - bp));
460			rs->host.h_name = bp;
461			bp += n;
462		}
463		if (res->options & RES_USE_INET6)
464			map_v4v6_hostent(&rs->host, &bp, ep);
465		h_errno = NETDB_SUCCESS;
466		return &rs->host;
467	}
468 no_recovery:
469	h_errno = NO_RECOVERY;
470	return NULL;
471}
472
473int
474gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen,
475    struct hostent**result, int *errorp)
476{
477        struct hostent *res;
478
479        res = gethostbyname(name);
480        *errorp = h_errno;
481        if (res == NULL) {
482                *result = NULL;
483                return -1;
484        }
485        memcpy(hp, res, sizeof *hp);
486        *result = hp;
487        return 0;
488}
489
490struct hostent *
491gethostbyname(const char *name)
492{
493	struct hostent *hp;
494	res_state res = __res_get_state();
495
496	if (res == NULL)
497		return NULL;
498
499	assert(name != NULL);
500
501	/* try IPv6 first - if that fails do IPv4 */
502	if (res->options & RES_USE_INET6) {
503		hp = gethostbyname_internal(name, AF_INET6, res, NULL, 0);
504		if (hp) {
505			__res_put_state(res);
506			return hp;
507		}
508	}
509	hp = gethostbyname_internal(name, AF_INET, res, NULL, 0);
510	__res_put_state(res);
511	return hp;
512}
513
514struct hostent *
515gethostbyname2(const char *name, int af)
516{
517	return android_gethostbynameforiface(name, af, NULL, 0);
518}
519
520struct hostent *
521android_gethostbynameforiface(const char *name, int af, const char *iface, int mark)
522{
523	struct hostent *hp;
524	res_state res = __res_get_state();
525
526	if (res == NULL)
527		return NULL;
528	hp = gethostbyname_internal(name, af, res, iface, mark);
529	__res_put_state(res);
530	return hp;
531}
532
533
534static FILE* android_open_proxy()
535{
536	int sock;
537	const int one = 1;
538	struct sockaddr_un proxy_addr;
539
540	sock = socket(AF_UNIX, SOCK_STREAM, 0);
541	if (sock < 0) {
542		return NULL;
543	}
544
545	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
546	memset(&proxy_addr, 0, sizeof(proxy_addr));
547	proxy_addr.sun_family = AF_UNIX;
548	strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
549	if (TEMP_FAILURE_RETRY(connect(sock,
550			(const struct sockaddr*) &proxy_addr,
551			sizeof(proxy_addr))) != 0) {
552		close(sock);
553		return NULL;
554	}
555
556	return fdopen(sock, "r+");
557}
558
559static struct hostent *
560android_read_hostent(FILE* proxy)
561{
562	uint32_t size;
563	char buf[4];
564	if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return NULL;
565
566	/* This is reading serialized data from system/netd/DnsProxyListener.cpp
567	 * and changes here need to be matched there */
568	int result_code = strtol(buf, NULL, 10);
569	if (result_code != DnsProxyQueryResult) {
570		fread(&size, 1, sizeof(size), proxy);
571		return NULL;
572	}
573
574	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
575	size = ntohl(size);
576	res_static rs = __res_get_static();
577	memset(&rs->host, 0, sizeof(rs->host));
578	char *ptr = rs->hostbuf;
579
580	if (fread(ptr, 1, size, proxy) != size) return NULL;
581	ptr += size;
582	rs->host.h_name = rs->hostbuf;
583
584	char **aliases = rs->host_aliases;
585	rs->host.h_aliases = rs->host_aliases;
586	while (1) {
587		if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
588		size = ntohl(size);
589
590		if (size == 0) {
591			*aliases = NULL;
592			break;
593		}
594		if (fread(ptr, 1, size, proxy) != size) return NULL;
595		*aliases++ = ptr;
596		ptr += size;
597	}
598
599	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
600	rs->host.h_addrtype = ntohl(size);
601
602	if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
603	rs->host.h_length = ntohl(size);
604
605	char **addrs = rs->h_addr_ptrs;
606	rs->host.h_addr_list = rs->h_addr_ptrs;
607	while (1) {
608		if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
609		size = ntohl(size);
610		if (size == 0) {
611			*addrs = NULL;
612			break;
613		}
614		if (fread(ptr, 1, size, proxy) != size) return NULL;
615		*addrs++ = ptr;
616		ptr += size;
617	}
618
619	return &rs->host;
620}
621
622
623static struct hostent *
624gethostbyname_internal_real(const char *name, int af, res_state res)
625{
626	const char *cp;
627	char *bp, *ep;
628	int size;
629	struct hostent *hp;
630	res_static rs = __res_get_static();
631
632	static const ns_dtab dtab[] = {
633		NS_FILES_CB(_gethtbyname, NULL)
634		{ NSSRC_DNS, _dns_gethtbyname, NULL },	/* force -DHESIOD */
635		{ 0, 0, 0 }
636	};
637
638	assert(name != NULL);
639
640	switch (af) {
641	case AF_INET:
642		size = INADDRSZ;
643		break;
644	case AF_INET6:
645		size = IN6ADDRSZ;
646		break;
647	default:
648		h_errno = NETDB_INTERNAL;
649		errno = EAFNOSUPPORT;
650		return NULL;
651	}
652
653	rs->host.h_addrtype = af;
654	rs->host.h_length = size;
655
656	/*
657	 * if there aren't any dots, it could be a user-level alias.
658	 * this is also done in res_nquery() since we are not the only
659	 * function that looks up host names.
660	 */
661	if (!strchr(name, '.') && (cp = __hostalias(name)))
662		name = cp;
663
664	/*
665	 * disallow names consisting only of digits/dots, unless
666	 * they end in a dot.
667	 */
668	if (isdigit((u_char) name[0]))
669		for (cp = name;; ++cp) {
670			if (!*cp) {
671				if (*--cp == '.')
672					break;
673				/*
674				 * All-numeric, no dot at the end.
675				 * Fake up a hostent as if we'd actually
676				 * done a lookup.
677				 */
678				if (inet_pton(af, name,
679				    (char *)(void *)rs->host_addr) <= 0) {
680					h_errno = HOST_NOT_FOUND;
681					return NULL;
682				}
683				strncpy(rs->hostbuf, name, MAXDNAME);
684				rs->hostbuf[MAXDNAME] = '\0';
685				bp = rs->hostbuf + MAXDNAME;
686				ep = rs->hostbuf + sizeof rs->hostbuf;
687				rs->host.h_name = rs->hostbuf;
688				rs->host.h_aliases = rs->host_aliases;
689				rs->host_aliases[0] = NULL;
690				rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
691				rs->h_addr_ptrs[1] = NULL;
692				rs->host.h_addr_list = rs->h_addr_ptrs;
693				if (res->options & RES_USE_INET6)
694					map_v4v6_hostent(&rs->host, &bp, ep);
695				h_errno = NETDB_SUCCESS;
696				return &rs->host;
697			}
698			if (!isdigit((u_char) *cp) && *cp != '.')
699				break;
700		}
701	if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) ||
702	    name[0] == ':')
703		for (cp = name;; ++cp) {
704			if (!*cp) {
705				if (*--cp == '.')
706					break;
707				/*
708				 * All-IPv6-legal, no dot at the end.
709				 * Fake up a hostent as if we'd actually
710				 * done a lookup.
711				 */
712				if (inet_pton(af, name,
713				    (char *)(void *)rs->host_addr) <= 0) {
714					h_errno = HOST_NOT_FOUND;
715					return NULL;
716				}
717				strncpy(rs->hostbuf, name, MAXDNAME);
718				rs->hostbuf[MAXDNAME] = '\0';
719				bp = rs->hostbuf + MAXDNAME;
720				ep = rs->hostbuf + sizeof rs->hostbuf;
721				rs->host.h_name = rs->hostbuf;
722				rs->host.h_aliases = rs->host_aliases;
723				rs->host_aliases[0] = NULL;
724				rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
725				rs->h_addr_ptrs[1] = NULL;
726				rs->host.h_addr_list = rs->h_addr_ptrs;
727				h_errno = NETDB_SUCCESS;
728				return &rs->host;
729			}
730			if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
731				break;
732		}
733
734	hp = NULL;
735	h_errno = NETDB_INTERNAL;
736	if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
737	    default_dns_files, name, strlen(name), af) != NS_SUCCESS) {
738		return NULL;
739	}
740	h_errno = NETDB_SUCCESS;
741	return hp;
742}
743
744
745// very similar in proxy-ness to android_getaddrinfo_proxy
746static struct hostent *
747gethostbyname_internal(const char *name, int af, res_state res, const char *iface, int mark)
748{
749	const char *cache_mode = getenv("ANDROID_DNS_MODE");
750	FILE* proxy = NULL;
751	struct hostent *result = NULL;
752
753	if (cache_mode != NULL && strcmp(cache_mode, "local") == 0) {
754		res_setiface(res, iface);
755		res_setmark(res, mark);
756		return gethostbyname_internal_real(name, af, res);
757	}
758
759	proxy = android_open_proxy();
760	if (proxy == NULL) goto exit;
761
762	/* This is writing to system/netd/DnsProxyListener.cpp and changes
763	 * here need to be matched there */
764	if (fprintf(proxy, "gethostbyname %s %s %d",
765			iface == NULL ? "^" : iface,
766			name == NULL ? "^" : name,
767			af) < 0) {
768		goto exit;
769	}
770
771	if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
772		goto exit;
773	}
774
775	result = android_read_hostent(proxy);
776
777exit:
778	if (proxy != NULL) {
779		fclose(proxy);
780	}
781	return result;
782}
783
784
785struct hostent *
786android_gethostbyaddrforiface_proxy(const void *addr,
787    socklen_t len, int af, const char* iface, int mark)
788{
789	struct hostent *result = NULL;
790	FILE* proxy = android_open_proxy();
791
792	if (proxy == NULL) goto exit;
793
794	char buf[INET6_ADDRSTRLEN];  //big enough for IPv4 and IPv6
795	const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
796	if (addrStr == NULL) goto exit;
797
798	if (fprintf(proxy, "gethostbyaddr %s %d %d %s",
799			addrStr, len, af, iface == NULL ? "^" : iface) < 0) {
800		goto exit;
801	}
802
803	if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
804		goto exit;
805	}
806
807	result = android_read_hostent(proxy);
808exit:
809	if (proxy != NULL) {
810		fclose(proxy);
811	}
812	return result;
813}
814
815struct hostent *
816android_gethostbyaddrforiface_real(const void *addr,
817    socklen_t len, int af, const char* iface, int mark)
818{
819	const u_char *uaddr = (const u_char *)addr;
820	socklen_t size;
821	struct hostent *hp;
822	static const ns_dtab dtab[] = {
823		NS_FILES_CB(_gethtbyaddr, NULL)
824		{ NSSRC_DNS, _dns_gethtbyaddr, NULL },	/* force -DHESIOD */
825		{ 0, 0, 0 }
826	};
827
828	assert(addr != NULL);
829
830	if (af == AF_INET6 && len == IN6ADDRSZ &&
831	    (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)(const void *)uaddr) ||
832	     IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)(const void *)uaddr))) {
833		h_errno = HOST_NOT_FOUND;
834		return NULL;
835	}
836	if (af == AF_INET6 && len == IN6ADDRSZ &&
837	    (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)(const void *)uaddr) ||
838	     IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)(const void *)uaddr))) {
839		/* Unmap. */
840		addr += IN6ADDRSZ - INADDRSZ;
841		uaddr += IN6ADDRSZ - INADDRSZ;
842		af = AF_INET;
843		len = INADDRSZ;
844	}
845	switch (af) {
846	case AF_INET:
847		size = INADDRSZ;
848		break;
849	case AF_INET6:
850		size = IN6ADDRSZ;
851		break;
852	default:
853		errno = EAFNOSUPPORT;
854		h_errno = NETDB_INTERNAL;
855		return NULL;
856	}
857	if (size != len) {
858		errno = EINVAL;
859		h_errno = NETDB_INTERNAL;
860		return NULL;
861	}
862	hp = NULL;
863	h_errno = NETDB_INTERNAL;
864	if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
865		default_dns_files, uaddr, len, af, iface, mark) != NS_SUCCESS)
866		return NULL;
867	h_errno = NETDB_SUCCESS;
868	return hp;
869}
870
871struct hostent *
872android_gethostbyaddrforiface(const void *addr, socklen_t len, int af, const char* iface, int mark)
873{
874	const char *cache_mode = getenv("ANDROID_DNS_MODE");
875
876	if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
877		return android_gethostbyaddrforiface_proxy(addr, len, af, iface, mark);
878	} else {
879		return android_gethostbyaddrforiface_real(addr,len, af, iface, mark);
880	}
881}
882
883struct hostent *
884gethostbyaddr(const void *addr, socklen_t len, int af)
885{
886	return android_gethostbyaddrforiface(addr, len, af, NULL, 0);
887}
888
889
890static void
891_sethtent(int f)
892{
893    res_static  rs = __res_get_static();
894    if (rs == NULL) return;
895	if (!rs->hostf)
896		rs->hostf = fopen(_PATH_HOSTS, "r" );
897	else
898		rewind(rs->hostf);
899	rs->stayopen = f;
900}
901
902static void
903_endhtent(void)
904{
905    res_static  rs = __res_get_static();
906    if (rs == NULL) return;
907
908	if (rs->hostf && !rs->stayopen) {
909		(void) fclose(rs->hostf);
910		rs->hostf = NULL;
911	}
912}
913
914static struct hostent *
915_gethtent(void)
916{
917	char *p;
918	char *cp, **q;
919	int af, len;
920	res_static  rs = __res_get_static();
921
922	if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "r" ))) {
923		h_errno = NETDB_INTERNAL;
924		return NULL;
925	}
926 again:
927	if (!(p = fgets(rs->hostbuf, sizeof rs->hostbuf, rs->hostf))) {
928		h_errno = HOST_NOT_FOUND;
929		return NULL;
930	}
931	if (*p == '#')
932		goto again;
933	if (!(cp = strpbrk(p, "#\n")))
934		goto again;
935	*cp = '\0';
936	if (!(cp = strpbrk(p, " \t")))
937		goto again;
938	*cp++ = '\0';
939	if (inet_pton(AF_INET6, p, (char *)(void *)rs->host_addr) > 0) {
940		af = AF_INET6;
941		len = IN6ADDRSZ;
942	} else if (inet_pton(AF_INET, p, (char *)(void *)rs->host_addr) > 0) {
943		res_state res = __res_get_state();
944		if (res == NULL)
945			return NULL;
946		if (res->options & RES_USE_INET6) {
947			map_v4v6_address((char *)(void *)rs->host_addr,
948			    (char *)(void *)rs->host_addr);
949			af = AF_INET6;
950			len = IN6ADDRSZ;
951		} else {
952			af = AF_INET;
953			len = INADDRSZ;
954		}
955		__res_put_state(res);
956	} else {
957		goto again;
958	}
959	/* if this is not something we're looking for, skip it. */
960	if (rs->host.h_addrtype != 0 && rs->host.h_addrtype != af)
961		goto again;
962	if (rs->host.h_length != 0 && rs->host.h_length != len)
963		goto again;
964	rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
965	rs->h_addr_ptrs[1] = NULL;
966	rs->host.h_addr_list = rs->h_addr_ptrs;
967	rs->host.h_length = len;
968	rs->host.h_addrtype = af;
969	while (*cp == ' ' || *cp == '\t')
970		cp++;
971	rs->host.h_name = cp;
972	q = rs->host.h_aliases = rs->host_aliases;
973	if ((cp = strpbrk(cp, " \t")) != NULL)
974		*cp++ = '\0';
975	while (cp && *cp) {
976		if (*cp == ' ' || *cp == '\t') {
977			cp++;
978			continue;
979		}
980		if (q < &rs->host_aliases[MAXALIASES - 1])
981			*q++ = cp;
982		if ((cp = strpbrk(cp, " \t")) != NULL)
983			*cp++ = '\0';
984	}
985	*q = NULL;
986	h_errno = NETDB_SUCCESS;
987	return &rs->host;
988}
989
990/*ARGSUSED*/
991int
992_gethtbyname(void *rv, void *cb_data, va_list ap)
993{
994	struct hostent *hp;
995	const char *name;
996	int af;
997
998	assert(rv != NULL);
999
1000	name = va_arg(ap, char *);
1001	/* NOSTRICT skip len */(void)va_arg(ap, int);
1002	af = va_arg(ap, int);
1003
1004	hp = NULL;
1005#if 0
1006	{
1007		res_state res = __res_get_state();
1008		if (res == NULL)
1009			return NS_NOTFOUND;
1010		if (res->options & RES_USE_INET6)
1011			hp = _gethtbyname2(name, AF_INET6);
1012		if (hp==NULL)
1013			hp = _gethtbyname2(name, AF_INET);
1014		__res_put_state(res);
1015	}
1016#else
1017	hp = _gethtbyname2(name, af);
1018#endif
1019	*((struct hostent **)rv) = hp;
1020	if (hp == NULL) {
1021		h_errno = HOST_NOT_FOUND;
1022		return NS_NOTFOUND;
1023	}
1024	return NS_SUCCESS;
1025}
1026
1027static struct hostent *
1028_gethtbyname2(const char *name, int af)
1029{
1030	struct hostent *p;
1031	char *tmpbuf, *ptr, **cp;
1032	int num;
1033	size_t len;
1034	res_static rs = __res_get_static();
1035
1036	assert(name != NULL);
1037
1038	_sethtent(rs->stayopen);
1039	ptr = tmpbuf = NULL;
1040	num = 0;
1041	while ((p = _gethtent()) != NULL && num < MAXADDRS) {
1042		if (p->h_addrtype != af)
1043			continue;
1044		if (strcasecmp(p->h_name, name) != 0) {
1045			for (cp = p->h_aliases; *cp != NULL; cp++)
1046				if (strcasecmp(*cp, name) == 0)
1047					break;
1048			if (*cp == NULL) continue;
1049		}
1050
1051		if (num == 0) {
1052			size_t bufsize;
1053			char *src;
1054
1055			bufsize = strlen(p->h_name) + 2 +
1056				  MAXADDRS * p->h_length +
1057				  ALIGNBYTES;
1058			for (cp = p->h_aliases; *cp != NULL; cp++)
1059				bufsize += strlen(*cp) + 1;
1060
1061			if ((tmpbuf = malloc(bufsize)) == NULL) {
1062				h_errno = NETDB_INTERNAL;
1063				return NULL;
1064			}
1065
1066			ptr = tmpbuf;
1067			src = p->h_name;
1068			while ((*ptr++ = *src++) != '\0');
1069			for (cp = p->h_aliases; *cp != NULL; cp++) {
1070				src = *cp;
1071				while ((*ptr++ = *src++) != '\0');
1072			}
1073			*ptr++ = '\0';
1074
1075			ptr = (char *)(void *)ALIGN(ptr);
1076		}
1077
1078		(void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length);
1079		ptr += p->h_length;
1080		num++;
1081	}
1082	_endhtent();
1083	if (num == 0) return NULL;
1084
1085	len = ptr - tmpbuf;
1086	if (len > (sizeof(rs->hostbuf) - ALIGNBYTES)) {
1087		free(tmpbuf);
1088		errno = ENOSPC;
1089		h_errno = NETDB_INTERNAL;
1090		return NULL;
1091	}
1092	ptr = memcpy((void *)ALIGN(rs->hostbuf), tmpbuf, len);
1093	free(tmpbuf);
1094
1095	rs->host.h_name = ptr;
1096	while (*ptr++);
1097
1098	cp = rs->host_aliases;
1099	while (*ptr) {
1100		*cp++ = ptr;
1101		while (*ptr++);
1102	}
1103	ptr++;
1104	*cp = NULL;
1105
1106	ptr = (char *)(void *)ALIGN(ptr);
1107	cp = rs->h_addr_ptrs;
1108	while (num--) {
1109		*cp++ = ptr;
1110		ptr += rs->host.h_length;
1111	}
1112	*cp = NULL;
1113
1114	return &rs->host;
1115}
1116
1117/*ARGSUSED*/
1118static int
1119_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1120{
1121	struct hostent *p;
1122	const unsigned char *addr;
1123	int len, af;
1124	res_static  rs = __res_get_static();
1125
1126	assert(rv != NULL);
1127
1128	addr = va_arg(ap, unsigned char *);
1129	len = va_arg(ap, int);
1130	af = va_arg(ap, int);
1131
1132	rs->host.h_length = len;
1133	rs->host.h_addrtype = af;
1134
1135	_sethtent(rs->stayopen);
1136	while ((p = _gethtent()) != NULL)
1137		if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
1138		    (size_t)len))
1139			break;
1140	_endhtent();
1141	*((struct hostent **)rv) = p;
1142	if (p==NULL) {
1143		h_errno = HOST_NOT_FOUND;
1144		return NS_NOTFOUND;
1145	}
1146	return NS_SUCCESS;
1147}
1148
1149static void
1150map_v4v6_address(const char *src, char *dst)
1151{
1152	u_char *p = (u_char *)dst;
1153	char tmp[INADDRSZ];
1154	int i;
1155
1156	assert(src != NULL);
1157	assert(dst != NULL);
1158
1159	/* Stash a temporary copy so our caller can update in place. */
1160	(void)memcpy(tmp, src, INADDRSZ);
1161	/* Mark this ipv6 addr as a mapped ipv4. */
1162	for (i = 0; i < 10; i++)
1163		*p++ = 0x00;
1164	*p++ = 0xff;
1165	*p++ = 0xff;
1166	/* Retrieve the saved copy and we're done. */
1167	(void)memcpy((void *)p, tmp, INADDRSZ);
1168}
1169
1170static void
1171map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
1172{
1173	char **ap;
1174
1175	assert(hp != NULL);
1176	assert(bpp != NULL);
1177	assert(ep != NULL);
1178
1179	if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
1180		return;
1181	hp->h_addrtype = AF_INET6;
1182	hp->h_length = IN6ADDRSZ;
1183	for (ap = hp->h_addr_list; *ap; ap++) {
1184		int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
1185
1186		if (ep - *bpp < (i + IN6ADDRSZ)) {
1187			/* Out of memory.  Truncate address list here.  XXX */
1188			*ap = NULL;
1189			return;
1190		}
1191		*bpp += i;
1192		map_v4v6_address(*ap, *bpp);
1193		*ap = *bpp;
1194		*bpp += IN6ADDRSZ;
1195	}
1196}
1197
1198static void
1199addrsort(char **ap, int num, res_state res)
1200{
1201	int i, j;
1202	char **p;
1203	short aval[MAXADDRS];
1204	int needsort = 0;
1205
1206	assert(ap != NULL);
1207
1208	p = ap;
1209	for (i = 0; i < num; i++, p++) {
1210	    for (j = 0 ; (unsigned)j < res->nsort; j++)
1211		if (res->sort_list[j].addr.s_addr ==
1212		    (((struct in_addr *)(void *)(*p))->s_addr &
1213		    res->sort_list[j].mask))
1214			break;
1215	    aval[i] = j;
1216	    if (needsort == 0 && i > 0 && j < aval[i-1])
1217		needsort = i;
1218	}
1219	if (!needsort)
1220	    return;
1221
1222	while (needsort < num) {
1223	    for (j = needsort - 1; j >= 0; j--) {
1224		if (aval[j] > aval[j+1]) {
1225		    char *hp;
1226
1227		    i = aval[j];
1228		    aval[j] = aval[j+1];
1229		    aval[j+1] = i;
1230
1231		    hp = ap[j];
1232		    ap[j] = ap[j+1];
1233		    ap[j+1] = hp;
1234		} else
1235		    break;
1236	    }
1237	    needsort++;
1238	}
1239}
1240
1241struct hostent *
1242gethostent(void)
1243{
1244    res_static  rs = __res_get_static();
1245	rs->host.h_addrtype = 0;
1246	rs->host.h_length = 0;
1247	return _gethtent();
1248}
1249
1250/*ARGSUSED*/
1251static int
1252_dns_gethtbyname(void *rv, void *cb_data, va_list ap)
1253{
1254	querybuf *buf;
1255	int n, type;
1256	struct hostent *hp;
1257	const char *name;
1258	int af;
1259	res_state res;
1260
1261	assert(rv != NULL);
1262
1263	name = va_arg(ap, char *);
1264	/* NOSTRICT skip len */(void)va_arg(ap, int);
1265	af = va_arg(ap, int);
1266
1267	switch (af) {
1268	case AF_INET:
1269		type = T_A;
1270		break;
1271	case AF_INET6:
1272		type = T_AAAA;
1273		break;
1274	default:
1275		return NS_UNAVAIL;
1276	}
1277	buf = malloc(sizeof(*buf));
1278	if (buf == NULL) {
1279		h_errno = NETDB_INTERNAL;
1280		return NS_NOTFOUND;
1281	}
1282	res = __res_get_state();
1283	if (res == NULL) {
1284		free(buf);
1285		return NS_NOTFOUND;
1286	}
1287	n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf));
1288	if (n < 0) {
1289		free(buf);
1290		dprintf("res_nsearch failed (%d)\n", res, n);
1291		__res_put_state(res);
1292		return NS_NOTFOUND;
1293	}
1294	hp = getanswer(buf, n, name, type, res);
1295	free(buf);
1296	__res_put_state(res);
1297	if (hp == NULL)
1298		switch (h_errno) {
1299		case HOST_NOT_FOUND:
1300			return NS_NOTFOUND;
1301		case TRY_AGAIN:
1302			return NS_TRYAGAIN;
1303		default:
1304			return NS_UNAVAIL;
1305		}
1306	*((struct hostent **)rv) = hp;
1307	return NS_SUCCESS;
1308}
1309
1310/*ARGSUSED*/
1311static int
1312_dns_gethtbyaddr(void *rv, void	*cb_data, va_list ap)
1313{
1314	char qbuf[MAXDNAME + 1], *qp, *ep;
1315	int n;
1316	querybuf *buf;
1317	struct hostent *hp;
1318	const unsigned char *uaddr;
1319	int len, af, advance;
1320	res_state res;
1321	const char* iface;
1322	int mark;
1323	res_static rs = __res_get_static();
1324
1325	assert(rv != NULL);
1326
1327	uaddr = va_arg(ap, unsigned char *);
1328	len = va_arg(ap, int);
1329	af = va_arg(ap, int);
1330	iface = va_arg(ap, char *);
1331	mark = va_arg(ap, int);
1332
1333	switch (af) {
1334	case AF_INET:
1335		(void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
1336		    (uaddr[3] & 0xff), (uaddr[2] & 0xff),
1337		    (uaddr[1] & 0xff), (uaddr[0] & 0xff));
1338		break;
1339
1340	case AF_INET6:
1341		qp = qbuf;
1342		ep = qbuf + sizeof(qbuf) - 1;
1343		for (n = IN6ADDRSZ - 1; n >= 0; n--) {
1344			advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
1345			    uaddr[n] & 0xf,
1346			    ((unsigned int)uaddr[n] >> 4) & 0xf);
1347			if (advance > 0 && qp + advance < ep)
1348				qp += advance;
1349			else {
1350				h_errno = NETDB_INTERNAL;
1351				return NS_NOTFOUND;
1352			}
1353		}
1354		if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
1355			h_errno = NETDB_INTERNAL;
1356			return NS_NOTFOUND;
1357		}
1358		break;
1359	default:
1360		abort();
1361	}
1362
1363	buf = malloc(sizeof(*buf));
1364	if (buf == NULL) {
1365		h_errno = NETDB_INTERNAL;
1366		return NS_NOTFOUND;
1367	}
1368	res = __res_get_state();
1369	if (res == NULL) {
1370		free(buf);
1371		return NS_NOTFOUND;
1372	}
1373	res_setiface(res, iface);
1374	res_setmark(res, mark);
1375	n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf));
1376	if (n < 0) {
1377		free(buf);
1378		dprintf("res_nquery failed (%d)\n", res, n);
1379		__res_put_state(res);
1380		return NS_NOTFOUND;
1381	}
1382	hp = getanswer(buf, n, qbuf, T_PTR, res);
1383	free(buf);
1384	if (hp == NULL) {
1385		__res_put_state(res);
1386		switch (h_errno) {
1387		case HOST_NOT_FOUND:
1388			return NS_NOTFOUND;
1389		case TRY_AGAIN:
1390			return NS_TRYAGAIN;
1391		default:
1392			return NS_UNAVAIL;
1393		}
1394	}
1395	hp->h_addrtype = af;
1396	hp->h_length = len;
1397	(void)memcpy(rs->host_addr, uaddr, (size_t)len);
1398	rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
1399	rs->h_addr_ptrs[1] = NULL;
1400	if (af == AF_INET && (res->options & RES_USE_INET6)) {
1401		map_v4v6_address((char *)(void *)rs->host_addr,
1402		    (char *)(void *)rs->host_addr);
1403		hp->h_addrtype = AF_INET6;
1404		hp->h_length = IN6ADDRSZ;
1405	}
1406
1407	__res_put_state(res);
1408	*((struct hostent **)rv) = hp;
1409	h_errno = NETDB_SUCCESS;
1410	return NS_SUCCESS;
1411}
1412