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