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