blob: 674b3cbecf52aed79b6ad478d89e786fbe45b5fd [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
Elliott Hughes68c27552014-07-07 09:44:17 -070093static const char AskedForGot[] =
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080094 "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 { \
Elliott Hughes0e441f02016-11-14 13:56:32 -0800166 BOUNDS_CHECK(cp, (x)); \
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800167 cp += (x); \
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800168 } while (/*CONSTCOND*/0)
169
170#define BOUNDS_CHECK(ptr, count) \
171 do { \
Elliott Hughes0e441f02016-11-14 13:56:32 -0800172 if (eom - (ptr) < (count)) { \
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800173 h_errno = NO_RECOVERY; \
174 return NULL; \
175 } \
176 } while (/*CONSTCOND*/0)
177
178static struct hostent *
179getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
180 res_state res)
181{
182 const HEADER *hp;
183 const u_char *cp;
184 int n;
185 const u_char *eom, *erdata;
186 char *bp, **ap, **hap, *ep;
187 int type, class, ancount, qdcount;
188 int haveanswer, had_error;
189 int toobig = 0;
190 char tbuf[MAXDNAME];
191 const char *tname;
192 int (*name_ok)(const char *);
193 res_static rs = __res_get_static();
194
195 assert(answer != NULL);
196 assert(qname != NULL);
197
198 tname = qname;
199 rs->host.h_name = NULL;
200 eom = answer->buf + anslen;
201 switch (qtype) {
202 case T_A:
203 case T_AAAA:
204 name_ok = res_hnok;
205 break;
206 case T_PTR:
207 name_ok = res_dnok;
208 break;
209 default:
210 return NULL; /* XXX should be abort(); */
211 }
212 /*
213 * find first satisfactory answer
214 */
215 hp = &answer->hdr;
216 ancount = ntohs(hp->ancount);
217 qdcount = ntohs(hp->qdcount);
218 bp = rs->hostbuf;
219 ep = rs->hostbuf + sizeof rs->hostbuf;
220 cp = answer->buf;
221 BOUNDED_INCR(HFIXEDSZ);
222 if (qdcount != 1) {
223 h_errno = NO_RECOVERY;
224 return NULL;
225 }
226 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
227 if ((n < 0) || !(*name_ok)(bp)) {
228 h_errno = NO_RECOVERY;
229 return NULL;
230 }
231 BOUNDED_INCR(n + QFIXEDSZ);
232 if (qtype == T_A || qtype == T_AAAA) {
233 /* res_send() has already verified that the query name is the
234 * same as the one we sent; this just gets the expanded name
235 * (i.e., with the succeeding search-domain tacked on).
236 */
237 n = strlen(bp) + 1; /* for the \0 */
238 if (n >= MAXHOSTNAMELEN) {
239 h_errno = NO_RECOVERY;
240 return NULL;
241 }
242 rs->host.h_name = bp;
243 bp += n;
244 /* The qname can be abbreviated, but h_name is now absolute. */
245 qname = rs->host.h_name;
246 }
247 ap = rs->host_aliases;
248 *ap = NULL;
249 rs->host.h_aliases = rs->host_aliases;
250 hap = rs->h_addr_ptrs;
251 *hap = NULL;
252 rs->host.h_addr_list = rs->h_addr_ptrs;
253 haveanswer = 0;
254 had_error = 0;
255 while (ancount-- > 0 && cp < eom && !had_error) {
256 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
257 if ((n < 0) || !(*name_ok)(bp)) {
258 had_error++;
259 continue;
260 }
261 cp += n; /* name */
262 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
263 type = _getshort(cp);
264 cp += INT16SZ; /* type */
265 class = _getshort(cp);
266 cp += INT16SZ + INT32SZ; /* class, TTL */
267 n = _getshort(cp);
268 cp += INT16SZ; /* len */
269 BOUNDS_CHECK(cp, n);
270 erdata = cp + n;
271 if (class != C_IN) {
272 /* XXX - debug? syslog? */
273 cp += n;
274 continue; /* XXX - had_error++ ? */
275 }
276 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
277 if (ap >= &rs->host_aliases[MAXALIASES-1])
278 continue;
279 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
280 if ((n < 0) || !(*name_ok)(tbuf)) {
281 had_error++;
282 continue;
283 }
284 cp += n;
285 if (cp != erdata) {
286 h_errno = NO_RECOVERY;
287 return NULL;
288 }
289 /* Store alias. */
290 *ap++ = bp;
291 n = strlen(bp) + 1; /* for the \0 */
292 if (n >= MAXHOSTNAMELEN) {
293 had_error++;
294 continue;
295 }
296 bp += n;
297 /* Get canonical name. */
298 n = strlen(tbuf) + 1; /* for the \0 */
299 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
300 had_error++;
301 continue;
302 }
303 strlcpy(bp, tbuf, (size_t)(ep - bp));
304 rs->host.h_name = bp;
305 bp += n;
306 continue;
307 }
308 if (qtype == T_PTR && type == T_CNAME) {
309 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
310 if (n < 0 || !res_dnok(tbuf)) {
311 had_error++;
312 continue;
313 }
314 cp += n;
315 if (cp != erdata) {
316 h_errno = NO_RECOVERY;
317 return NULL;
318 }
319 /* Get canonical name. */
320 n = strlen(tbuf) + 1; /* for the \0 */
321 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
322 had_error++;
323 continue;
324 }
325 strlcpy(bp, tbuf, (size_t)(ep - bp));
326 tname = bp;
327 bp += n;
328 continue;
329 }
330 if (type != qtype) {
331 if (type != T_KEY && type != T_SIG)
332 syslog(LOG_NOTICE|LOG_AUTH,
333 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
334 qname, p_class(C_IN), p_type(qtype),
335 p_type(type));
336 cp += n;
337 continue; /* XXX - had_error++ ? */
338 }
339 switch (type) {
340 case T_PTR:
341 if (strcasecmp(tname, bp) != 0) {
342 syslog(LOG_NOTICE|LOG_AUTH,
343 AskedForGot, qname, bp);
344 cp += n;
345 continue; /* XXX - had_error++ ? */
346 }
347 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
348 if ((n < 0) || !res_hnok(bp)) {
349 had_error++;
350 break;
351 }
352#if MULTI_PTRS_ARE_ALIASES
353 cp += n;
354 if (cp != erdata) {
355 h_errno = NO_RECOVERY;
356 return NULL;
357 }
358 if (!haveanswer)
359 rs->host.h_name = bp;
360 else if (ap < &rs->host_aliases[MAXALIASES-1])
361 *ap++ = bp;
362 else
363 n = -1;
364 if (n != -1) {
365 n = strlen(bp) + 1; /* for the \0 */
366 if (n >= MAXHOSTNAMELEN) {
367 had_error++;
368 break;
369 }
370 bp += n;
371 }
372 break;
373#else
374 rs->host.h_name = bp;
375 if (res->options & RES_USE_INET6) {
376 n = strlen(bp) + 1; /* for the \0 */
377 if (n >= MAXHOSTNAMELEN) {
378 had_error++;
379 break;
380 }
381 bp += n;
382 map_v4v6_hostent(&rs->host, &bp, ep);
383 }
384 h_errno = NETDB_SUCCESS;
385 return &rs->host;
386#endif
387 case T_A:
388 case T_AAAA:
389 if (strcasecmp(rs->host.h_name, bp) != 0) {
390 syslog(LOG_NOTICE|LOG_AUTH,
391 AskedForGot, rs->host.h_name, bp);
392 cp += n;
393 continue; /* XXX - had_error++ ? */
394 }
395 if (n != rs->host.h_length) {
396 cp += n;
397 continue;
398 }
399 if (type == T_AAAA) {
400 struct in6_addr in6;
401 memcpy(&in6, cp, IN6ADDRSZ);
402 if (IN6_IS_ADDR_V4MAPPED(&in6)) {
403 cp += n;
404 continue;
405 }
406 }
407 if (!haveanswer) {
408 int nn;
409
410 rs->host.h_name = bp;
411 nn = strlen(bp) + 1; /* for the \0 */
412 bp += nn;
413 }
414
415 bp += sizeof(align) -
416 (size_t)((u_long)bp % sizeof(align));
417
418 if (bp + n >= &rs->hostbuf[sizeof rs->hostbuf]) {
419 dprintf("size (%d) too big\n", res, n);
420 had_error++;
421 continue;
422 }
423 if (hap >= &rs->h_addr_ptrs[MAXADDRS-1]) {
424 if (!toobig++)
425 dprintf("Too many addresses (%d)\n",
426 res, MAXADDRS);
427 cp += n;
428 continue;
429 }
430 (void)memcpy(*hap++ = bp, cp, (size_t)n);
431 bp += n;
432 cp += n;
433 if (cp != erdata) {
434 h_errno = NO_RECOVERY;
435 return NULL;
436 }
437 break;
438 default:
439 abort();
440 }
441 if (!had_error)
442 haveanswer++;
443 }
444 if (haveanswer) {
445 *ap = NULL;
446 *hap = NULL;
447 /*
448 * Note: we sort even if host can take only one address
449 * in its return structures - should give it the "best"
450 * address in that case, not some random one
451 */
452 if (res->nsort && haveanswer > 1 && qtype == T_A)
453 addrsort(rs->h_addr_ptrs, haveanswer, res);
454 if (!rs->host.h_name) {
455 n = strlen(qname) + 1; /* for the \0 */
456 if (n > ep - bp || n >= MAXHOSTNAMELEN)
457 goto no_recovery;
458 strlcpy(bp, qname, (size_t)(ep - bp));
459 rs->host.h_name = bp;
460 bp += n;
461 }
462 if (res->options & RES_USE_INET6)
463 map_v4v6_hostent(&rs->host, &bp, ep);
464 h_errno = NETDB_SUCCESS;
465 return &rs->host;
466 }
467 no_recovery:
468 h_errno = NO_RECOVERY;
469 return NULL;
470}
471
472int
473gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen,
474 struct hostent**result, int *errorp)
475{
476 struct hostent *res;
477
478 res = gethostbyname(name);
479 *errorp = h_errno;
480 if (res == NULL) {
481 *result = NULL;
482 return -1;
483 }
484 memcpy(hp, res, sizeof *hp);
485 *result = hp;
486 return 0;
487}
488
489struct hostent *
490gethostbyname(const char *name)
491{
492 struct hostent *hp;
493 res_state res = __res_get_state();
494
495 if (res == NULL)
496 return NULL;
497
498 assert(name != NULL);
499
Mattias Falkc63e5902011-08-23 14:34:14 +0200500 /* try IPv6 first - if that fails do IPv4 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800501 if (res->options & RES_USE_INET6) {
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500502 hp = gethostbyname_internal(name, AF_INET6, res, NETID_UNSET, MARK_UNSET);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800503 if (hp) {
504 __res_put_state(res);
505 return hp;
506 }
507 }
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500508 hp = gethostbyname_internal(name, AF_INET, res, NETID_UNSET, MARK_UNSET);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800509 __res_put_state(res);
510 return hp;
511}
512
513struct hostent *
514gethostbyname2(const char *name, int af)
515{
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500516 return android_gethostbynamefornet(name, af, NETID_UNSET, MARK_UNSET);
Mattias Falkc63e5902011-08-23 14:34:14 +0200517}
518
519struct hostent *
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500520android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark)
Mattias Falkc63e5902011-08-23 14:34:14 +0200521{
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800522 struct hostent *hp;
523 res_state res = __res_get_state();
524
525 if (res == NULL)
526 return NULL;
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500527 hp = gethostbyname_internal(name, af, res, netid, mark);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800528 __res_put_state(res);
529 return hp;
530}
531
Mattias Falkc63e5902011-08-23 14:34:14 +0200532
533static FILE* android_open_proxy()
534{
535 int sock;
536 const int one = 1;
537 struct sockaddr_un proxy_addr;
538
Nick Kralevich1781ed72014-06-29 20:46:17 -0700539 sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
Mattias Falkc63e5902011-08-23 14:34:14 +0200540 if (sock < 0) {
541 return NULL;
542 }
543
544 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
545 memset(&proxy_addr, 0, sizeof(proxy_addr));
546 proxy_addr.sun_family = AF_UNIX;
547 strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
548 if (TEMP_FAILURE_RETRY(connect(sock,
549 (const struct sockaddr*) &proxy_addr,
550 sizeof(proxy_addr))) != 0) {
551 close(sock);
552 return NULL;
553 }
554
555 return fdopen(sock, "r+");
556}
557
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800558static struct hostent *
Mattias Falkc63e5902011-08-23 14:34:14 +0200559android_read_hostent(FILE* proxy)
560{
561 uint32_t size;
562 char buf[4];
563 if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return NULL;
564
Sreeram Ramachandran2582f022014-07-20 14:10:45 -0700565 /* This is reading serialized data from system/netd/server/DnsProxyListener.cpp
Mattias Falkc63e5902011-08-23 14:34:14 +0200566 * and changes here need to be matched there */
567 int result_code = strtol(buf, NULL, 10);
568 if (result_code != DnsProxyQueryResult) {
569 fread(&size, 1, sizeof(size), proxy);
570 return NULL;
571 }
572
573 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
574 size = ntohl(size);
575 res_static rs = __res_get_static();
576 memset(&rs->host, 0, sizeof(rs->host));
577 char *ptr = rs->hostbuf;
578
579 if (fread(ptr, 1, size, proxy) != size) return NULL;
580 ptr += size;
581 rs->host.h_name = rs->hostbuf;
582
583 char **aliases = rs->host_aliases;
584 rs->host.h_aliases = rs->host_aliases;
585 while (1) {
586 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
587 size = ntohl(size);
588
589 if (size == 0) {
590 *aliases = NULL;
591 break;
592 }
593 if (fread(ptr, 1, size, proxy) != size) return NULL;
594 *aliases++ = ptr;
595 ptr += size;
596 }
597
598 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
599 rs->host.h_addrtype = ntohl(size);
600
601 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
602 rs->host.h_length = ntohl(size);
603
604 char **addrs = rs->h_addr_ptrs;
605 rs->host.h_addr_list = rs->h_addr_ptrs;
606 while (1) {
607 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
608 size = ntohl(size);
609 if (size == 0) {
610 *addrs = NULL;
611 break;
612 }
613 if (fread(ptr, 1, size, proxy) != size) return NULL;
614 *addrs++ = ptr;
615 ptr += size;
616 }
617
618 return &rs->host;
619}
620
621
622static struct hostent *
623gethostbyname_internal_real(const char *name, int af, res_state res)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800624{
625 const char *cp;
626 char *bp, *ep;
627 int size;
628 struct hostent *hp;
Mattias Falkc63e5902011-08-23 14:34:14 +0200629 res_static rs = __res_get_static();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800630
631 static const ns_dtab dtab[] = {
632 NS_FILES_CB(_gethtbyname, NULL)
633 { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */
634 { 0, 0, 0 }
635 };
636
637 assert(name != NULL);
638
639 switch (af) {
640 case AF_INET:
641 size = INADDRSZ;
642 break;
643 case AF_INET6:
644 size = IN6ADDRSZ;
645 break;
646 default:
647 h_errno = NETDB_INTERNAL;
648 errno = EAFNOSUPPORT;
649 return NULL;
650 }
651
652 rs->host.h_addrtype = af;
653 rs->host.h_length = size;
654
655 /*
656 * if there aren't any dots, it could be a user-level alias.
657 * this is also done in res_nquery() since we are not the only
658 * function that looks up host names.
659 */
660 if (!strchr(name, '.') && (cp = __hostalias(name)))
661 name = cp;
662
663 /*
664 * disallow names consisting only of digits/dots, unless
665 * they end in a dot.
666 */
667 if (isdigit((u_char) name[0]))
668 for (cp = name;; ++cp) {
669 if (!*cp) {
670 if (*--cp == '.')
671 break;
672 /*
673 * All-numeric, no dot at the end.
674 * Fake up a hostent as if we'd actually
675 * done a lookup.
676 */
677 if (inet_pton(af, name,
678 (char *)(void *)rs->host_addr) <= 0) {
679 h_errno = HOST_NOT_FOUND;
680 return NULL;
681 }
682 strncpy(rs->hostbuf, name, MAXDNAME);
683 rs->hostbuf[MAXDNAME] = '\0';
684 bp = rs->hostbuf + MAXDNAME;
685 ep = rs->hostbuf + sizeof rs->hostbuf;
686 rs->host.h_name = rs->hostbuf;
687 rs->host.h_aliases = rs->host_aliases;
688 rs->host_aliases[0] = NULL;
689 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
690 rs->h_addr_ptrs[1] = NULL;
691 rs->host.h_addr_list = rs->h_addr_ptrs;
692 if (res->options & RES_USE_INET6)
693 map_v4v6_hostent(&rs->host, &bp, ep);
694 h_errno = NETDB_SUCCESS;
695 return &rs->host;
696 }
697 if (!isdigit((u_char) *cp) && *cp != '.')
698 break;
699 }
700 if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) ||
701 name[0] == ':')
702 for (cp = name;; ++cp) {
703 if (!*cp) {
704 if (*--cp == '.')
705 break;
706 /*
707 * All-IPv6-legal, no dot at the end.
708 * Fake up a hostent as if we'd actually
709 * done a lookup.
710 */
711 if (inet_pton(af, name,
712 (char *)(void *)rs->host_addr) <= 0) {
713 h_errno = HOST_NOT_FOUND;
714 return NULL;
715 }
716 strncpy(rs->hostbuf, name, MAXDNAME);
717 rs->hostbuf[MAXDNAME] = '\0';
718 bp = rs->hostbuf + MAXDNAME;
719 ep = rs->hostbuf + sizeof rs->hostbuf;
720 rs->host.h_name = rs->hostbuf;
721 rs->host.h_aliases = rs->host_aliases;
722 rs->host_aliases[0] = NULL;
723 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
724 rs->h_addr_ptrs[1] = NULL;
725 rs->host.h_addr_list = rs->h_addr_ptrs;
726 h_errno = NETDB_SUCCESS;
727 return &rs->host;
728 }
729 if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
730 break;
731 }
732
733 hp = NULL;
734 h_errno = NETDB_INTERNAL;
735 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
736 default_dns_files, name, strlen(name), af) != NS_SUCCESS) {
737 return NULL;
Mattias Falkc63e5902011-08-23 14:34:14 +0200738 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800739 h_errno = NETDB_SUCCESS;
740 return hp;
741}
742
Mattias Falkc63e5902011-08-23 14:34:14 +0200743
744// very similar in proxy-ness to android_getaddrinfo_proxy
745static struct hostent *
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500746gethostbyname_internal(const char *name, int af, res_state res, unsigned netid, unsigned mark)
Mattias Falkc63e5902011-08-23 14:34:14 +0200747{
748 const char *cache_mode = getenv("ANDROID_DNS_MODE");
749 FILE* proxy = NULL;
750 struct hostent *result = NULL;
751
752 if (cache_mode != NULL && strcmp(cache_mode, "local") == 0) {
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500753 res_setnetid(res, netid);
Chad Brubakerc39214e2013-06-20 10:36:56 -0700754 res_setmark(res, mark);
Mattias Falkc63e5902011-08-23 14:34:14 +0200755 return gethostbyname_internal_real(name, af, res);
756 }
757
758 proxy = android_open_proxy();
Nick Kralevicha6b24b72013-02-21 20:10:41 -0800759 if (proxy == NULL) goto exit;
Mattias Falkc63e5902011-08-23 14:34:14 +0200760
Paul Jensen5240b562014-05-15 14:43:07 -0400761 netid = __netdClientDispatch.netIdForResolv(netid);
762
Sreeram Ramachandran2582f022014-07-20 14:10:45 -0700763 /* This is writing to system/netd/server/DnsProxyListener.cpp and changes
Mattias Falkc63e5902011-08-23 14:34:14 +0200764 * here need to be matched there */
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500765 if (fprintf(proxy, "gethostbyname %u %s %d",
766 netid,
Mattias Falkc63e5902011-08-23 14:34:14 +0200767 name == NULL ? "^" : name,
768 af) < 0) {
769 goto exit;
770 }
771
772 if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
773 goto exit;
774 }
775
776 result = android_read_hostent(proxy);
777
778exit:
779 if (proxy != NULL) {
780 fclose(proxy);
781 }
782 return result;
783}
784
785
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800786struct hostent *
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500787android_gethostbyaddrfornet_proxy(const void *addr,
788 socklen_t len, int af, unsigned netid)
Mattias Falkc63e5902011-08-23 14:34:14 +0200789{
790 struct hostent *result = NULL;
791 FILE* proxy = android_open_proxy();
792
793 if (proxy == NULL) goto exit;
794
795 char buf[INET6_ADDRSTRLEN]; //big enough for IPv4 and IPv6
796 const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
797 if (addrStr == NULL) goto exit;
798
Paul Jensen5240b562014-05-15 14:43:07 -0400799 netid = __netdClientDispatch.netIdForResolv(netid);
800
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500801 if (fprintf(proxy, "gethostbyaddr %s %d %d %u",
802 addrStr, len, af, netid) < 0) {
Mattias Falkc63e5902011-08-23 14:34:14 +0200803 goto exit;
804 }
805
806 if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
807 goto exit;
808 }
809
810 result = android_read_hostent(proxy);
811exit:
812 if (proxy != NULL) {
813 fclose(proxy);
814 }
815 return result;
816}
817
818struct hostent *
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500819android_gethostbyaddrfornet_real(const void *addr,
820 socklen_t len, int af, unsigned netid, unsigned mark)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800821{
822 const u_char *uaddr = (const u_char *)addr;
823 socklen_t size;
824 struct hostent *hp;
825 static const ns_dtab dtab[] = {
826 NS_FILES_CB(_gethtbyaddr, NULL)
827 { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */
828 { 0, 0, 0 }
829 };
830
831 assert(addr != NULL);
832
Elliott Hughes3e5f0c92014-05-06 11:23:40 -0700833 if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
834 (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) ||
835 IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800836 h_errno = HOST_NOT_FOUND;
837 return NULL;
838 }
Elliott Hughes3e5f0c92014-05-06 11:23:40 -0700839 if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
840 (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)addr) ||
841 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)addr))) {
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800842 /* Unmap. */
Elliott Hughes3e5f0c92014-05-06 11:23:40 -0700843 uaddr += NS_IN6ADDRSZ - NS_INADDRSZ;
844 addr = uaddr;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800845 af = AF_INET;
Elliott Hughes3e5f0c92014-05-06 11:23:40 -0700846 len = NS_INADDRSZ;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800847 }
848 switch (af) {
849 case AF_INET:
Elliott Hughes3e5f0c92014-05-06 11:23:40 -0700850 size = NS_INADDRSZ;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800851 break;
852 case AF_INET6:
Elliott Hughes3e5f0c92014-05-06 11:23:40 -0700853 size = NS_IN6ADDRSZ;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800854 break;
855 default:
856 errno = EAFNOSUPPORT;
857 h_errno = NETDB_INTERNAL;
858 return NULL;
859 }
860 if (size != len) {
861 errno = EINVAL;
862 h_errno = NETDB_INTERNAL;
863 return NULL;
864 }
865 hp = NULL;
866 h_errno = NETDB_INTERNAL;
867 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500868 default_dns_files, uaddr, len, af, netid, mark) != NS_SUCCESS)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800869 return NULL;
870 h_errno = NETDB_SUCCESS;
871 return hp;
872}
873
Mattias Falkc63e5902011-08-23 14:34:14 +0200874struct hostent *
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500875android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark)
Mattias Falkc63e5902011-08-23 14:34:14 +0200876{
877 const char *cache_mode = getenv("ANDROID_DNS_MODE");
878
879 if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500880 return android_gethostbyaddrfornet_proxy(addr, len, af, netid);
Mattias Falkc63e5902011-08-23 14:34:14 +0200881 } else {
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500882 return android_gethostbyaddrfornet_real(addr,len, af, netid, mark);
Mattias Falkc63e5902011-08-23 14:34:14 +0200883 }
884}
885
886struct hostent *
887gethostbyaddr(const void *addr, socklen_t len, int af)
888{
Szymon Jakubczakea9bf672014-02-14 17:07:23 -0500889 return android_gethostbyaddrfornet(addr, len, af, NETID_UNSET, MARK_UNSET);
Mattias Falkc63e5902011-08-23 14:34:14 +0200890}
891
892
Jim Huange5c35e02010-09-27 23:37:10 +0800893static void
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800894_sethtent(int f)
895{
896 res_static rs = __res_get_static();
897 if (rs == NULL) return;
898 if (!rs->hostf)
899 rs->hostf = fopen(_PATH_HOSTS, "r" );
900 else
901 rewind(rs->hostf);
902 rs->stayopen = f;
903}
904
Jim Huange5c35e02010-09-27 23:37:10 +0800905static void
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800906_endhtent(void)
907{
908 res_static rs = __res_get_static();
909 if (rs == NULL) return;
910
911 if (rs->hostf && !rs->stayopen) {
912 (void) fclose(rs->hostf);
913 rs->hostf = NULL;
914 }
915}
916
Jim Huange5c35e02010-09-27 23:37:10 +0800917static struct hostent *
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800918_gethtent(void)
919{
920 char *p;
921 char *cp, **q;
922 int af, len;
923 res_static rs = __res_get_static();
924
925 if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "r" ))) {
926 h_errno = NETDB_INTERNAL;
927 return NULL;
928 }
929 again:
930 if (!(p = fgets(rs->hostbuf, sizeof rs->hostbuf, rs->hostf))) {
931 h_errno = HOST_NOT_FOUND;
932 return NULL;
933 }
934 if (*p == '#')
935 goto again;
936 if (!(cp = strpbrk(p, "#\n")))
937 goto again;
938 *cp = '\0';
939 if (!(cp = strpbrk(p, " \t")))
940 goto again;
941 *cp++ = '\0';
942 if (inet_pton(AF_INET6, p, (char *)(void *)rs->host_addr) > 0) {
943 af = AF_INET6;
944 len = IN6ADDRSZ;
945 } else if (inet_pton(AF_INET, p, (char *)(void *)rs->host_addr) > 0) {
946 res_state res = __res_get_state();
947 if (res == NULL)
948 return NULL;
949 if (res->options & RES_USE_INET6) {
950 map_v4v6_address((char *)(void *)rs->host_addr,
951 (char *)(void *)rs->host_addr);
952 af = AF_INET6;
953 len = IN6ADDRSZ;
954 } else {
955 af = AF_INET;
956 len = INADDRSZ;
957 }
958 __res_put_state(res);
959 } else {
960 goto again;
961 }
962 /* if this is not something we're looking for, skip it. */
963 if (rs->host.h_addrtype != 0 && rs->host.h_addrtype != af)
964 goto again;
965 if (rs->host.h_length != 0 && rs->host.h_length != len)
966 goto again;
967 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
968 rs->h_addr_ptrs[1] = NULL;
969 rs->host.h_addr_list = rs->h_addr_ptrs;
970 rs->host.h_length = len;
971 rs->host.h_addrtype = af;
972 while (*cp == ' ' || *cp == '\t')
973 cp++;
974 rs->host.h_name = cp;
975 q = rs->host.h_aliases = rs->host_aliases;
976 if ((cp = strpbrk(cp, " \t")) != NULL)
977 *cp++ = '\0';
978 while (cp && *cp) {
979 if (*cp == ' ' || *cp == '\t') {
980 cp++;
981 continue;
982 }
983 if (q < &rs->host_aliases[MAXALIASES - 1])
984 *q++ = cp;
985 if ((cp = strpbrk(cp, " \t")) != NULL)
986 *cp++ = '\0';
987 }
988 *q = NULL;
989 h_errno = NETDB_SUCCESS;
990 return &rs->host;
991}
992
993/*ARGSUSED*/
994int
995_gethtbyname(void *rv, void *cb_data, va_list ap)
996{
997 struct hostent *hp;
998 const char *name;
999 int af;
1000
1001 assert(rv != NULL);
1002
1003 name = va_arg(ap, char *);
1004 /* NOSTRICT skip len */(void)va_arg(ap, int);
1005 af = va_arg(ap, int);
1006
1007 hp = NULL;
1008#if 0
1009 {
1010 res_state res = __res_get_state();
1011 if (res == NULL)
1012 return NS_NOTFOUND;
1013 if (res->options & RES_USE_INET6)
1014 hp = _gethtbyname2(name, AF_INET6);
1015 if (hp==NULL)
1016 hp = _gethtbyname2(name, AF_INET);
1017 __res_put_state(res);
1018 }
1019#else
1020 hp = _gethtbyname2(name, af);
1021#endif
1022 *((struct hostent **)rv) = hp;
1023 if (hp == NULL) {
1024 h_errno = HOST_NOT_FOUND;
1025 return NS_NOTFOUND;
1026 }
1027 return NS_SUCCESS;
1028}
1029
Jim Huange5c35e02010-09-27 23:37:10 +08001030static struct hostent *
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001031_gethtbyname2(const char *name, int af)
1032{
1033 struct hostent *p;
1034 char *tmpbuf, *ptr, **cp;
1035 int num;
1036 size_t len;
1037 res_static rs = __res_get_static();
1038
1039 assert(name != NULL);
1040
1041 _sethtent(rs->stayopen);
1042 ptr = tmpbuf = NULL;
1043 num = 0;
1044 while ((p = _gethtent()) != NULL && num < MAXADDRS) {
1045 if (p->h_addrtype != af)
1046 continue;
1047 if (strcasecmp(p->h_name, name) != 0) {
1048 for (cp = p->h_aliases; *cp != NULL; cp++)
1049 if (strcasecmp(*cp, name) == 0)
1050 break;
1051 if (*cp == NULL) continue;
1052 }
1053
1054 if (num == 0) {
1055 size_t bufsize;
1056 char *src;
1057
1058 bufsize = strlen(p->h_name) + 2 +
1059 MAXADDRS * p->h_length +
1060 ALIGNBYTES;
1061 for (cp = p->h_aliases; *cp != NULL; cp++)
1062 bufsize += strlen(*cp) + 1;
1063
1064 if ((tmpbuf = malloc(bufsize)) == NULL) {
1065 h_errno = NETDB_INTERNAL;
1066 return NULL;
1067 }
1068
1069 ptr = tmpbuf;
1070 src = p->h_name;
1071 while ((*ptr++ = *src++) != '\0');
1072 for (cp = p->h_aliases; *cp != NULL; cp++) {
1073 src = *cp;
1074 while ((*ptr++ = *src++) != '\0');
1075 }
1076 *ptr++ = '\0';
1077
1078 ptr = (char *)(void *)ALIGN(ptr);
1079 }
1080
1081 (void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length);
1082 ptr += p->h_length;
1083 num++;
1084 }
1085 _endhtent();
1086 if (num == 0) return NULL;
1087
1088 len = ptr - tmpbuf;
1089 if (len > (sizeof(rs->hostbuf) - ALIGNBYTES)) {
1090 free(tmpbuf);
1091 errno = ENOSPC;
1092 h_errno = NETDB_INTERNAL;
1093 return NULL;
1094 }
1095 ptr = memcpy((void *)ALIGN(rs->hostbuf), tmpbuf, len);
1096 free(tmpbuf);
1097
1098 rs->host.h_name = ptr;
1099 while (*ptr++);
1100
1101 cp = rs->host_aliases;
1102 while (*ptr) {
1103 *cp++ = ptr;
1104 while (*ptr++);
1105 }
1106 ptr++;
1107 *cp = NULL;
1108
1109 ptr = (char *)(void *)ALIGN(ptr);
1110 cp = rs->h_addr_ptrs;
1111 while (num--) {
1112 *cp++ = ptr;
1113 ptr += rs->host.h_length;
1114 }
1115 *cp = NULL;
1116
1117 return &rs->host;
1118}
1119
1120/*ARGSUSED*/
Jim Huange5c35e02010-09-27 23:37:10 +08001121static int
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001122_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1123{
1124 struct hostent *p;
1125 const unsigned char *addr;
1126 int len, af;
1127 res_static rs = __res_get_static();
1128
1129 assert(rv != NULL);
1130
1131 addr = va_arg(ap, unsigned char *);
1132 len = va_arg(ap, int);
1133 af = va_arg(ap, int);
1134
1135 rs->host.h_length = len;
1136 rs->host.h_addrtype = af;
1137
1138 _sethtent(rs->stayopen);
1139 while ((p = _gethtent()) != NULL)
1140 if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
1141 (size_t)len))
1142 break;
1143 _endhtent();
1144 *((struct hostent **)rv) = p;
1145 if (p==NULL) {
1146 h_errno = HOST_NOT_FOUND;
1147 return NS_NOTFOUND;
1148 }
1149 return NS_SUCCESS;
1150}
1151
1152static void
1153map_v4v6_address(const char *src, char *dst)
1154{
1155 u_char *p = (u_char *)dst;
1156 char tmp[INADDRSZ];
1157 int i;
1158
1159 assert(src != NULL);
1160 assert(dst != NULL);
1161
1162 /* Stash a temporary copy so our caller can update in place. */
1163 (void)memcpy(tmp, src, INADDRSZ);
1164 /* Mark this ipv6 addr as a mapped ipv4. */
1165 for (i = 0; i < 10; i++)
1166 *p++ = 0x00;
1167 *p++ = 0xff;
1168 *p++ = 0xff;
1169 /* Retrieve the saved copy and we're done. */
1170 (void)memcpy((void *)p, tmp, INADDRSZ);
1171}
1172
1173static void
1174map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
1175{
1176 char **ap;
1177
1178 assert(hp != NULL);
1179 assert(bpp != NULL);
1180 assert(ep != NULL);
1181
1182 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
1183 return;
1184 hp->h_addrtype = AF_INET6;
1185 hp->h_length = IN6ADDRSZ;
1186 for (ap = hp->h_addr_list; *ap; ap++) {
1187 int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
1188
1189 if (ep - *bpp < (i + IN6ADDRSZ)) {
1190 /* Out of memory. Truncate address list here. XXX */
1191 *ap = NULL;
1192 return;
1193 }
1194 *bpp += i;
1195 map_v4v6_address(*ap, *bpp);
1196 *ap = *bpp;
1197 *bpp += IN6ADDRSZ;
1198 }
1199}
1200
1201static void
1202addrsort(char **ap, int num, res_state res)
1203{
1204 int i, j;
1205 char **p;
1206 short aval[MAXADDRS];
1207 int needsort = 0;
1208
1209 assert(ap != NULL);
1210
1211 p = ap;
1212 for (i = 0; i < num; i++, p++) {
1213 for (j = 0 ; (unsigned)j < res->nsort; j++)
1214 if (res->sort_list[j].addr.s_addr ==
1215 (((struct in_addr *)(void *)(*p))->s_addr &
1216 res->sort_list[j].mask))
1217 break;
1218 aval[i] = j;
1219 if (needsort == 0 && i > 0 && j < aval[i-1])
1220 needsort = i;
1221 }
1222 if (!needsort)
1223 return;
1224
1225 while (needsort < num) {
1226 for (j = needsort - 1; j >= 0; j--) {
1227 if (aval[j] > aval[j+1]) {
1228 char *hp;
1229
1230 i = aval[j];
1231 aval[j] = aval[j+1];
1232 aval[j+1] = i;
1233
1234 hp = ap[j];
1235 ap[j] = ap[j+1];
1236 ap[j+1] = hp;
1237 } else
1238 break;
1239 }
1240 needsort++;
1241 }
1242}
1243
1244struct hostent *
1245gethostent(void)
1246{
1247 res_static rs = __res_get_static();
1248 rs->host.h_addrtype = 0;
1249 rs->host.h_length = 0;
1250 return _gethtent();
1251}
1252
1253/*ARGSUSED*/
Jim Huange5c35e02010-09-27 23:37:10 +08001254static int
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001255_dns_gethtbyname(void *rv, void *cb_data, va_list ap)
1256{
1257 querybuf *buf;
1258 int n, type;
1259 struct hostent *hp;
1260 const char *name;
1261 int af;
1262 res_state res;
1263
1264 assert(rv != NULL);
1265
1266 name = va_arg(ap, char *);
1267 /* NOSTRICT skip len */(void)va_arg(ap, int);
1268 af = va_arg(ap, int);
1269
1270 switch (af) {
1271 case AF_INET:
1272 type = T_A;
1273 break;
1274 case AF_INET6:
1275 type = T_AAAA;
1276 break;
1277 default:
1278 return NS_UNAVAIL;
1279 }
1280 buf = malloc(sizeof(*buf));
1281 if (buf == NULL) {
1282 h_errno = NETDB_INTERNAL;
1283 return NS_NOTFOUND;
1284 }
1285 res = __res_get_state();
1286 if (res == NULL) {
1287 free(buf);
1288 return NS_NOTFOUND;
1289 }
1290 n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf));
1291 if (n < 0) {
1292 free(buf);
1293 dprintf("res_nsearch failed (%d)\n", res, n);
1294 __res_put_state(res);
1295 return NS_NOTFOUND;
1296 }
1297 hp = getanswer(buf, n, name, type, res);
1298 free(buf);
1299 __res_put_state(res);
1300 if (hp == NULL)
1301 switch (h_errno) {
1302 case HOST_NOT_FOUND:
1303 return NS_NOTFOUND;
1304 case TRY_AGAIN:
1305 return NS_TRYAGAIN;
1306 default:
1307 return NS_UNAVAIL;
1308 }
1309 *((struct hostent **)rv) = hp;
1310 return NS_SUCCESS;
1311}
1312
1313/*ARGSUSED*/
Jim Huange5c35e02010-09-27 23:37:10 +08001314static int
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001315_dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1316{
1317 char qbuf[MAXDNAME + 1], *qp, *ep;
1318 int n;
1319 querybuf *buf;
1320 struct hostent *hp;
1321 const unsigned char *uaddr;
1322 int len, af, advance;
1323 res_state res;
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05001324 unsigned netid, mark;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001325 res_static rs = __res_get_static();
1326
1327 assert(rv != NULL);
1328
1329 uaddr = va_arg(ap, unsigned char *);
1330 len = va_arg(ap, int);
1331 af = va_arg(ap, int);
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05001332 netid = va_arg(ap, unsigned);
1333 mark = va_arg(ap, unsigned);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001334
1335 switch (af) {
1336 case AF_INET:
1337 (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
1338 (uaddr[3] & 0xff), (uaddr[2] & 0xff),
1339 (uaddr[1] & 0xff), (uaddr[0] & 0xff));
1340 break;
1341
1342 case AF_INET6:
1343 qp = qbuf;
1344 ep = qbuf + sizeof(qbuf) - 1;
1345 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
1346 advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
1347 uaddr[n] & 0xf,
1348 ((unsigned int)uaddr[n] >> 4) & 0xf);
1349 if (advance > 0 && qp + advance < ep)
1350 qp += advance;
1351 else {
1352 h_errno = NETDB_INTERNAL;
1353 return NS_NOTFOUND;
1354 }
1355 }
1356 if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
1357 h_errno = NETDB_INTERNAL;
1358 return NS_NOTFOUND;
1359 }
1360 break;
1361 default:
1362 abort();
1363 }
1364
1365 buf = malloc(sizeof(*buf));
1366 if (buf == NULL) {
1367 h_errno = NETDB_INTERNAL;
1368 return NS_NOTFOUND;
1369 }
1370 res = __res_get_state();
1371 if (res == NULL) {
1372 free(buf);
1373 return NS_NOTFOUND;
1374 }
Szymon Jakubczakea9bf672014-02-14 17:07:23 -05001375 res_setnetid(res, netid);
Chad Brubakerc39214e2013-06-20 10:36:56 -07001376 res_setmark(res, mark);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001377 n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf));
1378 if (n < 0) {
1379 free(buf);
1380 dprintf("res_nquery failed (%d)\n", res, n);
1381 __res_put_state(res);
1382 return NS_NOTFOUND;
1383 }
1384 hp = getanswer(buf, n, qbuf, T_PTR, res);
1385 free(buf);
1386 if (hp == NULL) {
1387 __res_put_state(res);
1388 switch (h_errno) {
1389 case HOST_NOT_FOUND:
1390 return NS_NOTFOUND;
1391 case TRY_AGAIN:
1392 return NS_TRYAGAIN;
1393 default:
1394 return NS_UNAVAIL;
1395 }
1396 }
1397 hp->h_addrtype = af;
1398 hp->h_length = len;
1399 (void)memcpy(rs->host_addr, uaddr, (size_t)len);
1400 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
1401 rs->h_addr_ptrs[1] = NULL;
1402 if (af == AF_INET && (res->options & RES_USE_INET6)) {
1403 map_v4v6_address((char *)(void *)rs->host_addr,
1404 (char *)(void *)rs->host_addr);
1405 hp->h_addrtype = AF_INET6;
1406 hp->h_length = IN6ADDRSZ;
1407 }
1408
1409 __res_put_state(res);
1410 *((struct hostent **)rv) = hp;
1411 h_errno = NETDB_SUCCESS;
1412 return NS_SUCCESS;
1413}