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