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 "gethnamaddr.h" 55 56 #include <android-base/logging.h> 57 #include <arpa/inet.h> 58 #include <arpa/nameser.h> 59 #include <assert.h> 60 #include <ctype.h> 61 #include <errno.h> 62 #include <netdb.h> 63 #include <netinet/in.h> 64 #include <stdarg.h> 65 #include <stdbool.h> 66 #include <stdlib.h> 67 #include <string.h> 68 #include <sys/param.h> 69 #include <sys/socket.h> 70 #include <sys/un.h> 71 #include <unistd.h> 72 #include <functional> 73 #include <vector> 74 75 #include "hostent.h" 76 #include "netd_resolv/resolv.h" 77 #include "res_comp.h" 78 #include "res_debug.h" // p_class(), p_type() 79 #include "resolv_cache.h" 80 #include "resolv_private.h" 81 #include "stats.pb.h" 82 83 using android::net::NetworkDnsEventReported; 84 85 // NetBSD uses _DIAGASSERT to null-check arguments and the like, 86 // but it's clear from the number of mistakes in their assertions 87 // that they don't actually test or ship with this. 88 #define _DIAGASSERT(e) /* nothing */ 89 90 // TODO: unify macro ALIGNBYTES and ALIGN for all possible data type alignment of hostent 91 // buffer. 92 #define ALIGNBYTES (sizeof(uintptr_t) - 1) 93 #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) & ~ALIGNBYTES) 94 95 constexpr int MAXADDRS = 35; 96 97 typedef union { 98 HEADER hdr; 99 uint8_t buf[MAXPACKET]; 100 } querybuf; 101 102 typedef union { 103 int32_t al; 104 char ac; 105 } align; 106 107 static void convert_v4v6_hostent(struct hostent* hp, char** bpp, char* ep, 108 const std::function<void(struct hostent* hp)>& mapping_param, 109 const std::function<void(char* src, char* dst)>& mapping_addr); 110 static void pad_v4v6_hostent(struct hostent* hp, char** bpp, char* ep); 111 112 static int dns_gethtbyaddr(const unsigned char* uaddr, int len, int af, 113 const android_net_context* netcontext, getnamaddr* info, 114 NetworkDnsEventReported* event); 115 static int dns_gethtbyname(ResState* res, const char* name, int af, getnamaddr* info); 116 117 #define BOUNDED_INCR(x) \ 118 do { \ 119 BOUNDS_CHECK(cp, x); \ 120 cp += (x); \ 121 } while (0) 122 123 #define BOUNDS_CHECK(ptr, count) \ 124 do { \ 125 if (eom - (ptr) < (count)) goto no_recovery; \ 126 } while (0) 127 128 static struct hostent* getanswer(const querybuf* answer, int anslen, const char* qname, int qtype, 129 struct hostent* hent, char* buf, size_t buflen, int* he) { 130 const HEADER* hp; 131 const uint8_t* cp; 132 int n; 133 size_t qlen; 134 const uint8_t *eom, *erdata; 135 char *bp, **hap, *ep; 136 int ancount, qdcount; 137 int haveanswer, had_error; 138 int toobig = 0; 139 char tbuf[MAXDNAME]; 140 char* addr_ptrs[MAXADDRS]; 141 const char* tname; 142 std::vector<char*> aliases; 143 144 _DIAGASSERT(answer != NULL); 145 _DIAGASSERT(qname != NULL); 146 147 tname = qname; 148 hent->h_name = NULL; 149 eom = answer->buf + anslen; 150 151 bool (*name_ok)(const char* dn); 152 switch (qtype) { 153 case T_A: 154 case T_AAAA: 155 name_ok = res_hnok; 156 break; 157 case T_PTR: 158 name_ok = res_dnok; 159 break; 160 default: 161 *he = NO_RECOVERY; 162 return NULL; /* XXX should be abort(); */ 163 } 164 165 /* 166 * find first satisfactory answer 167 */ 168 hp = &answer->hdr; 169 ancount = ntohs(hp->ancount); 170 qdcount = ntohs(hp->qdcount); 171 bp = buf; 172 ep = buf + buflen; 173 cp = answer->buf; 174 BOUNDED_INCR(HFIXEDSZ); 175 if (qdcount != 1) goto no_recovery; 176 177 n = dn_expand(answer->buf, eom, cp, bp, (int) (ep - bp)); 178 if ((n < 0) || !name_ok(bp)) goto no_recovery; 179 180 BOUNDED_INCR(n + QFIXEDSZ); 181 if (qtype == T_A || qtype == T_AAAA) { 182 /* res_send() has already verified that the query name is the 183 * same as the one we sent; this just gets the expanded name 184 * (i.e., with the succeeding search-domain tacked on). 185 */ 186 n = (int) strlen(bp) + 1; /* for the \0 */ 187 if (n >= MAXHOSTNAMELEN) goto no_recovery; 188 hent->h_name = bp; 189 bp += n; 190 /* The qname can be abbreviated, but h_name is now absolute. */ 191 qname = hent->h_name; 192 } 193 hent->h_addr_list = hap = addr_ptrs; 194 *hap = NULL; 195 haveanswer = 0; 196 had_error = 0; 197 while (ancount-- > 0 && cp < eom && !had_error) { 198 n = dn_expand(answer->buf, eom, cp, bp, (int) (ep - bp)); 199 if ((n < 0) || !name_ok(bp)) { 200 had_error++; 201 continue; 202 } 203 cp += n; /* name */ 204 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ); 205 int type = ntohs(*reinterpret_cast<const uint16_t*>(cp)); 206 cp += INT16SZ; /* type */ 207 int cl = ntohs(*reinterpret_cast<const uint16_t*>(cp)); 208 cp += INT16SZ + INT32SZ; /* class, TTL */ 209 n = ntohs(*reinterpret_cast<const uint16_t*>(cp)); 210 cp += INT16SZ; /* len */ 211 BOUNDS_CHECK(cp, n); 212 erdata = cp + n; 213 if (cl != C_IN) { 214 /* XXX - debug? syslog? */ 215 cp += n; 216 continue; /* XXX - had_error++ ? */ 217 } 218 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { 219 n = dn_expand(answer->buf, eom, cp, tbuf, (int) sizeof tbuf); 220 if ((n < 0) || !name_ok(tbuf)) { 221 had_error++; 222 continue; 223 } 224 cp += n; 225 if (cp != erdata) goto no_recovery; 226 /* Store alias. */ 227 aliases.push_back(bp); 228 n = (int) strlen(bp) + 1; /* for the \0 */ 229 if (n >= MAXHOSTNAMELEN) { 230 had_error++; 231 continue; 232 } 233 bp += n; 234 /* Get canonical name. */ 235 n = (int) strlen(tbuf) + 1; /* for the \0 */ 236 if (n > ep - bp || n >= MAXHOSTNAMELEN) { 237 had_error++; 238 continue; 239 } 240 strlcpy(bp, tbuf, (size_t)(ep - bp)); 241 hent->h_name = bp; 242 bp += n; 243 continue; 244 } 245 if (qtype == T_PTR && type == T_CNAME) { 246 n = dn_expand(answer->buf, eom, cp, tbuf, (int) sizeof tbuf); 247 if (n < 0 || !res_dnok(tbuf)) { 248 had_error++; 249 continue; 250 } 251 cp += n; 252 if (cp != erdata) goto no_recovery; 253 /* Get canonical name. */ 254 n = (int) strlen(tbuf) + 1; /* for the \0 */ 255 if (n > ep - bp || n >= MAXHOSTNAMELEN) { 256 had_error++; 257 continue; 258 } 259 strlcpy(bp, tbuf, (size_t)(ep - bp)); 260 tname = bp; 261 bp += n; 262 continue; 263 } 264 if (type != qtype) { 265 if (type != T_KEY && type != T_SIG) 266 LOG(DEBUG) << __func__ << ": asked for \"" << qname << " " << p_class(C_IN) << " " 267 << p_type(qtype) << "\", got type \"" << p_type(type) << "\""; 268 cp += n; 269 continue; /* XXX - had_error++ ? */ 270 } 271 switch (type) { 272 case T_PTR: 273 if (strcasecmp(tname, bp) != 0) { 274 LOG(DEBUG) << __func__ << ": asked for \"" << qname << "\", got \"" << bp 275 << "\""; 276 cp += n; 277 continue; /* XXX - had_error++ ? */ 278 } 279 n = dn_expand(answer->buf, eom, cp, bp, (int) (ep - bp)); 280 if ((n < 0) || !res_hnok(bp)) { 281 had_error++; 282 break; 283 } 284 cp += n; 285 if (cp != erdata) goto no_recovery; 286 if (!haveanswer) 287 hent->h_name = bp; 288 else 289 aliases.push_back(bp); 290 if (n != -1) { 291 n = (int) strlen(bp) + 1; /* for the \0 */ 292 if (n >= MAXHOSTNAMELEN) { 293 had_error++; 294 break; 295 } 296 bp += n; 297 } 298 break; 299 case T_A: 300 case T_AAAA: 301 if (strcasecmp(hent->h_name, bp) != 0) { 302 LOG(DEBUG) << __func__ << ": asked for \"" << hent->h_name << "\", got \"" << bp 303 << "\""; 304 cp += n; 305 continue; /* XXX - had_error++ ? */ 306 } 307 if (n != hent->h_length) { 308 cp += n; 309 continue; 310 } 311 if (type == T_AAAA) { 312 struct in6_addr in6; 313 memcpy(&in6, cp, NS_IN6ADDRSZ); 314 if (IN6_IS_ADDR_V4MAPPED(&in6)) { 315 cp += n; 316 continue; 317 } 318 } 319 if (!haveanswer) { 320 int nn; 321 322 hent->h_name = bp; 323 nn = (int) strlen(bp) + 1; /* for the \0 */ 324 bp += nn; 325 } 326 327 bp += sizeof(align) - (size_t)((uintptr_t)bp % sizeof(align)); 328 329 if (bp + n >= ep) { 330 LOG(DEBUG) << __func__ << ": size (" << n << ") too big"; 331 had_error++; 332 continue; 333 } 334 if (hap >= &addr_ptrs[MAXADDRS - 1]) { 335 if (!toobig++) { 336 LOG(DEBUG) << __func__ << ": Too many addresses (" << MAXADDRS << ")"; 337 } 338 cp += n; 339 continue; 340 } 341 (void) memcpy(*hap++ = bp, cp, (size_t) n); 342 bp += n; 343 cp += n; 344 if (cp != erdata) goto no_recovery; 345 break; 346 default: 347 abort(); 348 } 349 if (!had_error) haveanswer++; 350 } 351 if (haveanswer) { 352 *hap = NULL; 353 if (!hent->h_name) { 354 n = (int) strlen(qname) + 1; /* for the \0 */ 355 if (n > ep - bp || n >= MAXHOSTNAMELEN) goto no_recovery; 356 strlcpy(bp, qname, (size_t)(ep - bp)); 357 hent->h_name = bp; 358 bp += n; 359 } 360 if (hent->h_addrtype == AF_INET) pad_v4v6_hostent(hent, &bp, ep); 361 goto success; 362 } 363 no_recovery: 364 *he = NO_RECOVERY; 365 return NULL; 366 success: 367 bp = (char*) ALIGN(bp); 368 aliases.push_back(nullptr); 369 qlen = aliases.size() * sizeof(*hent->h_aliases); 370 if ((size_t)(ep - bp) < qlen) goto nospc; 371 hent->h_aliases = (char**) bp; 372 memcpy(bp, aliases.data(), qlen); 373 374 bp += qlen; 375 n = (int) (hap - addr_ptrs); 376 qlen = (n + 1) * sizeof(*hent->h_addr_list); 377 if ((size_t)(ep - bp) < qlen) goto nospc; 378 hent->h_addr_list = (char**) bp; 379 memcpy(bp, addr_ptrs, qlen); 380 *he = NETDB_SUCCESS; 381 return hent; 382 nospc: 383 errno = ENOSPC; 384 *he = NETDB_INTERNAL; 385 return NULL; 386 } 387 388 int resolv_gethostbyname(const char* name, int af, hostent* hp, char* buf, size_t buflen, 389 const android_net_context* netcontext, hostent** result, 390 NetworkDnsEventReported* event) { 391 if (name == nullptr || hp == nullptr) { 392 return EAI_SYSTEM; 393 } 394 395 getnamaddr info; 396 ResState res(netcontext, event); 397 398 size_t size; 399 switch (af) { 400 case AF_INET: 401 size = NS_INADDRSZ; 402 break; 403 case AF_INET6: 404 size = NS_IN6ADDRSZ; 405 break; 406 default: 407 return EAI_FAMILY; 408 } 409 if (buflen < size) goto nospc; 410 411 hp->h_addrtype = af; 412 hp->h_length = (int) size; 413 414 /* 415 * disallow names consisting only of digits/dots, unless 416 * they end in a dot. 417 */ 418 if (isdigit((uint8_t)name[0])) { 419 for (const char* cp = name;; ++cp) { 420 if (!*cp) { 421 if (*--cp == '.') break; 422 /* 423 * All-numeric, no dot at the end. 424 * Fake up a hostent as if we'd actually 425 * done a lookup. 426 */ 427 goto fake; 428 } 429 if (!isdigit((uint8_t)*cp) && *cp != '.') break; 430 } 431 } 432 if ((isxdigit((uint8_t)name[0]) && strchr(name, ':') != NULL) || name[0] == ':') { 433 for (const char* cp = name;; ++cp) { 434 if (!*cp) { 435 if (*--cp == '.') break; 436 /* 437 * All-IPv6-legal, no dot at the end. 438 * Fake up a hostent as if we'd actually 439 * done a lookup. 440 */ 441 goto fake; 442 } 443 if (!isxdigit((uint8_t)*cp) && *cp != ':' && *cp != '.') break; 444 } 445 } 446 447 info.hp = hp; 448 info.buf = buf; 449 info.buflen = buflen; 450 if (_hf_gethtbyname2(name, af, &info)) { 451 int error = dns_gethtbyname(&res, name, af, &info); 452 if (error != 0) return error; 453 } 454 *result = hp; 455 return 0; 456 nospc: 457 return EAI_MEMORY; 458 fake: 459 HENT_ARRAY(hp->h_addr_list, 1, buf, buflen); 460 HENT_ARRAY(hp->h_aliases, 0, buf, buflen); 461 462 hp->h_aliases[0] = NULL; 463 if (size > buflen) goto nospc; 464 465 if (inet_pton(af, name, buf) <= 0) { 466 return EAI_NODATA; 467 } 468 hp->h_addr_list[0] = buf; 469 hp->h_addr_list[1] = NULL; 470 buf += size; 471 buflen -= size; 472 HENT_SCOPY(hp->h_name, name, buf, buflen); 473 *result = hp; 474 return 0; 475 } 476 477 int resolv_gethostbyaddr(const void* addr, socklen_t len, int af, hostent* hp, char* buf, 478 size_t buflen, const struct android_net_context* netcontext, 479 hostent** result, NetworkDnsEventReported* event) { 480 const uint8_t* uaddr = (const uint8_t*)addr; 481 socklen_t size; 482 struct getnamaddr info; 483 484 _DIAGASSERT(addr != NULL); 485 486 if (af == AF_INET6 && len == NS_IN6ADDRSZ && 487 (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr*) addr) || 488 IN6_IS_ADDR_SITELOCAL((const struct in6_addr*) addr))) { 489 return EAI_NODATA; 490 } 491 if (af == AF_INET6 && len == NS_IN6ADDRSZ && 492 (IN6_IS_ADDR_V4MAPPED((const struct in6_addr*) addr) || 493 IN6_IS_ADDR_V4COMPAT((const struct in6_addr*) addr))) { 494 /* Unmap. */ 495 uaddr += NS_IN6ADDRSZ - NS_INADDRSZ; 496 addr = uaddr; 497 af = AF_INET; 498 len = NS_INADDRSZ; 499 } 500 switch (af) { 501 case AF_INET: 502 size = NS_INADDRSZ; 503 break; 504 case AF_INET6: 505 size = NS_IN6ADDRSZ; 506 break; 507 default: 508 return EAI_FAMILY; 509 } 510 if (size != len) { 511 // TODO: Consider converting to a private extended EAI_* error code. 512 // Currently, the EAI_* value has no corresponding error code for invalid argument socket 513 // length. In order to not rely on errno, convert the original error code pair, EAI_SYSTEM 514 // and EINVAL, to EAI_FAIL. 515 return EAI_FAIL; 516 } 517 info.hp = hp; 518 info.buf = buf; 519 info.buflen = buflen; 520 if (_hf_gethtbyaddr(uaddr, len, af, &info)) { 521 int error = dns_gethtbyaddr(uaddr, len, af, netcontext, &info, event); 522 if (error != 0) return error; 523 } 524 *result = hp; 525 return 0; 526 } 527 528 // TODO: Consider leaving function without returning error code as _gethtent() does because 529 // the error code of the caller does not currently return to netd. 530 struct hostent* netbsd_gethostent_r(FILE* hf, struct hostent* hent, char* buf, size_t buflen, 531 int* he) { 532 char *name; 533 char* cp; 534 int af, len; 535 size_t anum; 536 struct in6_addr host_addr; 537 std::vector<char*> aliases; 538 539 if (hf == NULL) { 540 *he = NETDB_INTERNAL; 541 errno = EINVAL; 542 return NULL; 543 } 544 char* p = NULL; 545 546 // Allocate a new space to read file lines like upstream does. 547 const size_t line_buf_size = MAXPACKET; 548 if ((p = (char*) malloc(line_buf_size)) == NULL) { 549 goto nospc; 550 } 551 for (;;) { 552 if (!fgets(p, line_buf_size, hf)) { 553 free(p); 554 *he = HOST_NOT_FOUND; 555 return NULL; 556 } 557 if (*p == '#') { 558 continue; 559 } 560 if (!(cp = strpbrk(p, "#\n"))) { 561 continue; 562 } 563 *cp = '\0'; 564 if (!(cp = strpbrk(p, " \t"))) continue; 565 *cp++ = '\0'; 566 if (inet_pton(AF_INET6, p, &host_addr) > 0) { 567 af = AF_INET6; 568 len = NS_IN6ADDRSZ; 569 } else { 570 if (inet_pton(AF_INET, p, &host_addr) <= 0) continue; 571 af = AF_INET; 572 len = NS_INADDRSZ; 573 } 574 575 /* if this is not something we're looking for, skip it. */ 576 if (hent->h_addrtype != 0 && hent->h_addrtype != af) continue; 577 if (hent->h_length != 0 && hent->h_length != len) continue; 578 579 while (*cp == ' ' || *cp == '\t') cp++; 580 if ((cp = strpbrk(name = cp, " \t")) != NULL) *cp++ = '\0'; 581 while (cp && *cp) { 582 if (*cp == ' ' || *cp == '\t') { 583 cp++; 584 continue; 585 } 586 aliases.push_back(cp); 587 if ((cp = strpbrk(cp, " \t")) != NULL) *cp++ = '\0'; 588 } 589 break; 590 } 591 hent->h_length = len; 592 hent->h_addrtype = af; 593 HENT_ARRAY(hent->h_addr_list, 1, buf, buflen); 594 anum = aliases.size(); 595 HENT_ARRAY(hent->h_aliases, anum, buf, buflen); 596 HENT_COPY(hent->h_addr_list[0], &host_addr, hent->h_length, buf, buflen); 597 hent->h_addr_list[1] = NULL; 598 599 /* Reserve space for mapping IPv4 address to IPv6 address in place */ 600 if (hent->h_addrtype == AF_INET) { 601 HENT_COPY(buf, NAT64_PAD, sizeof(NAT64_PAD), buf, buflen); 602 } 603 604 HENT_SCOPY(hent->h_name, name, buf, buflen); 605 for (size_t i = 0; i < anum; i++) HENT_SCOPY(hent->h_aliases[i], aliases[i], buf, buflen); 606 hent->h_aliases[anum] = NULL; 607 *he = NETDB_SUCCESS; 608 free(p); 609 return hent; 610 nospc: 611 free(p); 612 errno = ENOSPC; 613 *he = NETDB_INTERNAL; 614 return NULL; 615 } 616 617 static void convert_v4v6_hostent(struct hostent* hp, char** bpp, char* ep, 618 const std::function<void(struct hostent* hp)>& map_param, 619 const std::function<void(char* src, char* dst)>& map_addr) { 620 _DIAGASSERT(hp != NULL); 621 _DIAGASSERT(bpp != NULL); 622 _DIAGASSERT(ep != NULL); 623 624 if (hp->h_addrtype != AF_INET || hp->h_length != NS_INADDRSZ) return; 625 map_param(hp); 626 for (char** ap = hp->h_addr_list; *ap; ap++) { 627 int i = (int)(sizeof(align) - (size_t)((uintptr_t)*bpp % sizeof(align))); 628 629 if (ep - *bpp < (i + NS_IN6ADDRSZ)) { 630 /* Out of memory. Truncate address list here. XXX */ 631 *ap = NULL; 632 return; 633 } 634 *bpp += i; 635 map_addr(*ap, *bpp); 636 *ap = *bpp; 637 *bpp += NS_IN6ADDRSZ; 638 } 639 } 640 641 /* Reserve space for mapping IPv4 address to IPv6 address in place */ 642 static void pad_v4v6_hostent(struct hostent* hp, char** bpp, char* ep) { 643 convert_v4v6_hostent(hp, bpp, ep, 644 [](struct hostent* hp) { 645 (void) hp; /* unused */ 646 }, 647 [](char* src, char* dst) { 648 memcpy(dst, src, NS_INADDRSZ); 649 memcpy(dst + NS_INADDRSZ, NAT64_PAD, sizeof(NAT64_PAD)); 650 }); 651 } 652 653 static int dns_gethtbyname(ResState* res, const char* name, int addr_type, getnamaddr* info) { 654 int n, type; 655 info->hp->h_addrtype = addr_type; 656 657 switch (info->hp->h_addrtype) { 658 case AF_INET: 659 info->hp->h_length = NS_INADDRSZ; 660 type = T_A; 661 break; 662 case AF_INET6: 663 info->hp->h_length = NS_IN6ADDRSZ; 664 type = T_AAAA; 665 break; 666 default: 667 return EAI_FAMILY; 668 } 669 auto buf = std::make_unique<querybuf>(); 670 671 int he; 672 n = res_nsearch(res, name, C_IN, type, buf->buf, (int)sizeof(buf->buf), &he); 673 if (n < 0) { 674 LOG(DEBUG) << __func__ << ": res_nsearch failed (" << n << ")"; 675 // Return h_errno (he) to catch more detailed errors rather than EAI_NODATA. 676 // Note that res_nsearch() doesn't set the pair NETDB_INTERNAL and errno. 677 // See also herrnoToAiErrno(). 678 return herrnoToAiErrno(he); 679 } 680 hostent* hp = getanswer(buf.get(), n, name, type, info->hp, info->buf, info->buflen, &he); 681 if (hp == NULL) return herrnoToAiErrno(he); 682 683 return 0; 684 } 685 686 static int dns_gethtbyaddr(const unsigned char* uaddr, int len, int af, 687 const android_net_context* netcontext, getnamaddr* info, 688 NetworkDnsEventReported* event) { 689 char qbuf[MAXDNAME + 1], *qp, *ep; 690 int n; 691 int advance; 692 693 info->hp->h_length = len; 694 info->hp->h_addrtype = af; 695 696 switch (info->hp->h_addrtype) { 697 case AF_INET: 698 (void) snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff), 699 (uaddr[2] & 0xff), (uaddr[1] & 0xff), (uaddr[0] & 0xff)); 700 break; 701 702 case AF_INET6: 703 qp = qbuf; 704 ep = qbuf + sizeof(qbuf) - 1; 705 for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) { 706 advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.", uaddr[n] & 0xf, 707 ((unsigned int) uaddr[n] >> 4) & 0xf); 708 if (advance > 0 && qp + advance < ep) 709 qp += advance; 710 else { 711 // TODO: Consider converting to a private extended EAI_* error code. 712 // Currently, the EAI_* value has no corresponding error code for an internal 713 // out of buffer space. In order to not rely on errno, convert the original 714 // error code EAI_SYSTEM to EAI_MEMORY. 715 return EAI_MEMORY; 716 } 717 } 718 if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) { 719 // TODO: Consider converting to a private extended EAI_* error code. 720 // Currently, the EAI_* value has no corresponding error code for an internal 721 // out of buffer space. In order to not rely on errno, convert the original 722 // error code EAI_SYSTEM to EAI_MEMORY. 723 return EAI_MEMORY; 724 } 725 break; 726 default: 727 return EAI_FAMILY; 728 } 729 730 auto buf = std::make_unique<querybuf>(); 731 732 ResState res(netcontext, event); 733 int he; 734 n = res_nquery(&res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf), &he); 735 if (n < 0) { 736 LOG(DEBUG) << __func__ << ": res_nquery failed (" << n << ")"; 737 // Note that res_nquery() doesn't set the pair NETDB_INTERNAL and errno. 738 // Return h_errno (he) to catch more detailed errors rather than EAI_NODATA. 739 // See also herrnoToAiErrno(). 740 return herrnoToAiErrno(he); 741 } 742 hostent* hp = getanswer(buf.get(), n, qbuf, T_PTR, info->hp, info->buf, info->buflen, &he); 743 if (hp == NULL) return herrnoToAiErrno(he); 744 745 char* bf = (char*) (hp->h_addr_list + 2); 746 size_t blen = (size_t)(bf - info->buf); 747 if (blen + info->hp->h_length > info->buflen) goto nospc; 748 hp->h_addr_list[0] = bf; 749 hp->h_addr_list[1] = NULL; 750 memcpy(bf, uaddr, (size_t) info->hp->h_length); 751 752 /* Reserve enough space for mapping IPv4 address to IPv6 address in place */ 753 if (info->hp->h_addrtype == AF_INET) { 754 if (blen + NS_IN6ADDRSZ > info->buflen) goto nospc; 755 // Pad zero to the unused address space 756 memcpy(bf + NS_INADDRSZ, NAT64_PAD, sizeof(NAT64_PAD)); 757 } 758 759 return 0; 760 761 nospc: 762 return EAI_MEMORY; 763 } 764 765 int herrnoToAiErrno(int he) { 766 switch (he) { 767 // extended h_errno 768 case NETD_RESOLV_H_ERRNO_EXT_TIMEOUT: 769 return NETD_RESOLV_TIMEOUT; 770 // legacy h_errno 771 case NETDB_SUCCESS: 772 return 0; 773 case HOST_NOT_FOUND: // TODO: Perhaps convert HOST_NOT_FOUND to EAI_NONAME instead 774 case NO_DATA: // NO_ADDRESS 775 return EAI_NODATA; 776 case TRY_AGAIN: 777 return EAI_AGAIN; 778 case NETDB_INTERNAL: 779 // TODO: Remove ENOSPC and call abort() immediately whenever any allocation fails. 780 if (errno == ENOSPC) return EAI_MEMORY; 781 // Theoretically, this should not happen. Leave this here just in case. 782 // Currently, getanswer() of {gethnamaddr, getaddrinfo}.cpp, res_nsearch() and 783 // res_searchN() use this function to convert error code. Only getanswer() 784 // of gethnamaddr.cpp may return the error code pair, herrno NETDB_INTERNAL and 785 // errno ENOSPC, which has already converted to EAI_MEMORY. The remaining functions 786 // don't set the pair herrno and errno. 787 return EAI_SYSTEM; // see errno for detail 788 case NO_RECOVERY: 789 default: 790 return EAI_FAIL; // TODO: Perhaps convert default to EAI_MAX (unknown error) instead 791 } 792 } 793