blob: 2234c7ce3b65ca0554150b162b5f7adb4ff44c84 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/* $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>
Mattias Falkc63e5902011-08-23 14:34:14 +020059#include <sys/un.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080060#include <netinet/in.h>
61#include <arpa/inet.h>
Calin Juravle569fb982014-03-04 15:01:29 +000062#include <arpa/nameser.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080063#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>
Carl Shapiro2cc2b2b2011-03-21 20:01:03 -070071#include <strings.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080072#include <syslog.h>
Mattias Falkc63e5902011-08-23 14:34:14 +020073#include <unistd.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080074
Calin Juravlec20de902014-03-20 15:21:32 +000075#define ALIGNBYTES (sizeof(uintptr_t) - 1)
76#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
77
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080078#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
Mattias Falkc63e5902011-08-23 14:34:14 +020088// This should be synchronized to ResponseCode.h
89static const int DnsProxyQueryResult = 222;
90
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080091static 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
Jim Huange5c35e02010-09-27 23:37:10 +0800116static void _sethtent(int);
117static void _endhtent(void);
118static struct hostent *_gethtent(void);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800119void 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 *);
Jim Huange5c35e02010-09-27 23:37:10 +0800126static 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);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800131
Chad Brubakerc39214e2013-06-20 10:36:56 -0700132static struct hostent *gethostbyname_internal(const char *, int, res_state, const char *, int);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800133
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
Mattias Falkc63e5902011-08-23 14:34:14 +0200501 /* try IPv6 first - if that fails do IPv4 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800502 if (res->options & RES_USE_INET6) {
Chad Brubakerc39214e2013-06-20 10:36:56 -0700503 hp = gethostbyname_internal(name, AF_INET6, res, NULL, 0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800504 if (hp) {
505 __res_put_state(res);
506 return hp;
507 }
508 }
Chad Brubakerc39214e2013-06-20 10:36:56 -0700509 hp = gethostbyname_internal(name, AF_INET, res, NULL, 0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800510 __res_put_state(res);
511 return hp;
512}
513
514struct hostent *
515gethostbyname2(const char *name, int af)
516{
Chad Brubakerc39214e2013-06-20 10:36:56 -0700517 return android_gethostbynameforiface(name, af, NULL, 0);
Mattias Falkc63e5902011-08-23 14:34:14 +0200518}
519
520struct hostent *
Chad Brubakerc39214e2013-06-20 10:36:56 -0700521android_gethostbynameforiface(const char *name, int af, const char *iface, int mark)
Mattias Falkc63e5902011-08-23 14:34:14 +0200522{
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800523 struct hostent *hp;
524 res_state res = __res_get_state();
525
526 if (res == NULL)
527 return NULL;
Chad Brubakerc39214e2013-06-20 10:36:56 -0700528 hp = gethostbyname_internal(name, af, res, iface, mark);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800529 __res_put_state(res);
530 return hp;
531}
532
Mattias Falkc63e5902011-08-23 14:34:14 +0200533
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
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800559static struct hostent *
Mattias Falkc63e5902011-08-23 14:34:14 +0200560android_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)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800625{
626 const char *cp;
627 char *bp, *ep;
628 int size;
629 struct hostent *hp;
Mattias Falkc63e5902011-08-23 14:34:14 +0200630 res_static rs = __res_get_static();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800631
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;
Mattias Falkc63e5902011-08-23 14:34:14 +0200739 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800740 h_errno = NETDB_SUCCESS;
741 return hp;
742}
743
Mattias Falkc63e5902011-08-23 14:34:14 +0200744
745// very similar in proxy-ness to android_getaddrinfo_proxy
746static struct hostent *
Chad Brubakerc39214e2013-06-20 10:36:56 -0700747gethostbyname_internal(const char *name, int af, res_state res, const char *iface, int mark)
Mattias Falkc63e5902011-08-23 14:34:14 +0200748{
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);
Chad Brubakerc39214e2013-06-20 10:36:56 -0700755 res_setmark(res, mark);
Mattias Falkc63e5902011-08-23 14:34:14 +0200756 return gethostbyname_internal_real(name, af, res);
757 }
758
759 proxy = android_open_proxy();
Nick Kralevicha6b24b72013-02-21 20:10:41 -0800760 if (proxy == NULL) goto exit;
Mattias Falkc63e5902011-08-23 14:34:14 +0200761
762 /* This is writing to system/netd/DnsProxyListener.cpp and changes
763 * here need to be matched there */
Nick Kralevichbfe06402013-02-21 21:22:54 -0800764 if (fprintf(proxy, "gethostbyname %s %s %d",
Mattias Falkc63e5902011-08-23 14:34:14 +0200765 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
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800785struct hostent *
Mattias Falkc63e5902011-08-23 14:34:14 +0200786android_gethostbyaddrforiface_proxy(const void *addr,
Chad Brubakerc39214e2013-06-20 10:36:56 -0700787 socklen_t len, int af, const char* iface, int mark)
Mattias Falkc63e5902011-08-23 14:34:14 +0200788{
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
Nick Kralevichbfe06402013-02-21 21:22:54 -0800798 if (fprintf(proxy, "gethostbyaddr %s %d %d %s",
799 addrStr, len, af, iface == NULL ? "^" : iface) < 0) {
Mattias Falkc63e5902011-08-23 14:34:14 +0200800 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,
Chad Brubakerc39214e2013-06-20 10:36:56 -0700817 socklen_t len, int af, const char* iface, int mark)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800818{
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",
Chad Brubakerc39214e2013-06-20 10:36:56 -0700865 default_dns_files, uaddr, len, af, iface, mark) != NS_SUCCESS)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800866 return NULL;
867 h_errno = NETDB_SUCCESS;
868 return hp;
869}
870
Mattias Falkc63e5902011-08-23 14:34:14 +0200871struct hostent *
Chad Brubakerc39214e2013-06-20 10:36:56 -0700872android_gethostbyaddrforiface(const void *addr, socklen_t len, int af, const char* iface, int mark)
Mattias Falkc63e5902011-08-23 14:34:14 +0200873{
874 const char *cache_mode = getenv("ANDROID_DNS_MODE");
875
876 if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
Chad Brubakerc39214e2013-06-20 10:36:56 -0700877 return android_gethostbyaddrforiface_proxy(addr, len, af, iface, mark);
Mattias Falkc63e5902011-08-23 14:34:14 +0200878 } else {
Chad Brubakerc39214e2013-06-20 10:36:56 -0700879 return android_gethostbyaddrforiface_real(addr,len, af, iface, mark);
Mattias Falkc63e5902011-08-23 14:34:14 +0200880 }
881}
882
883struct hostent *
884gethostbyaddr(const void *addr, socklen_t len, int af)
885{
Chad Brubakerc39214e2013-06-20 10:36:56 -0700886 return android_gethostbyaddrforiface(addr, len, af, NULL, 0);
Mattias Falkc63e5902011-08-23 14:34:14 +0200887}
888
889
Jim Huange5c35e02010-09-27 23:37:10 +0800890static void
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800891_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
Jim Huange5c35e02010-09-27 23:37:10 +0800902static void
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800903_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
Jim Huange5c35e02010-09-27 23:37:10 +0800914static struct hostent *
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800915_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
Jim Huange5c35e02010-09-27 23:37:10 +08001027static struct hostent *
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001028_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*/
Jim Huange5c35e02010-09-27 23:37:10 +08001118static int
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001119_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*/
Jim Huange5c35e02010-09-27 23:37:10 +08001251static int
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001252_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*/
Jim Huange5c35e02010-09-27 23:37:10 +08001311static int
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001312_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;
Mattias Falkc63e5902011-08-23 14:34:14 +02001321 const char* iface;
Chad Brubakerc39214e2013-06-20 10:36:56 -07001322 int mark;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001323 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);
Mattias Falkc63e5902011-08-23 14:34:14 +02001330 iface = va_arg(ap, char *);
Chad Brubakerc39214e2013-06-20 10:36:56 -07001331 mark = va_arg(ap, int);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001332
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 }
Mattias Falkc63e5902011-08-23 14:34:14 +02001373 res_setiface(res, iface);
Chad Brubakerc39214e2013-06-20 10:36:56 -07001374 res_setmark(res, mark);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001375 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}