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 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 * 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 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 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 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 * 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 * 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 * 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. */ 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 * 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* 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* 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 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 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 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 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 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 * 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 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 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 * 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 * 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. 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 * 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 * 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 * 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 * 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 * 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* 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 * 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