1/* MIT License 2 * 3 * Copyright (c) 2023 Brad House 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 * SPDX-License-Identifier: MIT 25 */ 26#include "ares_setup.h" 27#include "ares.h" 28#include "ares_private.h" 29#ifdef HAVE_SYS_TYPES_H 30# include <sys/types.h> 31#endif 32#ifdef HAVE_SYS_STAT_H 33# include <sys/stat.h> 34#endif 35#ifdef HAVE_NETINET_IN_H 36# include <netinet/in.h> 37#endif 38#ifdef HAVE_NETDB_H 39# include <netdb.h> 40#endif 41#ifdef HAVE_ARPA_INET_H 42# include <arpa/inet.h> 43#endif 44#include <time.h> 45#include "ares_platform.h" 46 47/* HOSTS FILE PROCESSING OVERVIEW 48 * ============================== 49 * The hosts file on the system contains static entries to be processed locally 50 * rather than querying the nameserver. Each row is an IP address followed by 51 * a list of space delimited hostnames that match the ip address. This is used 52 * for both forward and reverse lookups. 53 * 54 * We are caching the entire parsed hosts file for performance reasons. Some 55 * files may be quite sizable and as per Issue #458 can approach 1/2MB in size, 56 * and the parse overhead on a rapid succession of queries can be quite large. 57 * The entries are stored in forwards and backwards hashtables so we can get 58 * O(1) performance on lookup. The file is cached until the file modification 59 * timestamp changes. 60 * 61 * The hosts file processing is quite unique. It has to merge all related hosts 62 * and ips into a single entry due to file formatting requirements. For 63 * instance take the below: 64 * 65 * 127.0.0.1 localhost.localdomain localhost 66 * ::1 localhost.localdomain localhost 67 * 192.168.1.1 host.example.com host 68 * 192.168.1.5 host.example.com host 69 * 2620:1234::1 host.example.com host6.example.com host6 host 70 * 71 * This will yield 2 entries. 72 * 1) ips: 127.0.0.1,::1 73 * hosts: localhost.localdomain,localhost 74 * 2) ips: 192.168.1.1,192.168.1.5,2620:1234::1 75 * hosts: host.example.com,host,host6.example.com,host6 76 * 77 * It could be argued that if searching for 192.168.1.1 that the 'host6' 78 * hostnames should not be returned, but this implementation will return them 79 * since they are related. It is unlikely this will matter in the real world. 80 */ 81 82struct ares_hosts_file { 83 time_t ts; 84 /*! cache the filename so we know if the filename changes it automatically 85 * invalidates the cache */ 86 char *filename; 87 /*! iphash is the owner of the 'entry' object as there is only ever a single 88 * match to the object. */ 89 ares__htable_strvp_t *iphash; 90 /*! hosthash does not own the entry so won't free on destruction */ 91 ares__htable_strvp_t *hosthash; 92}; 93 94struct ares_hosts_entry { 95 size_t refcnt; /*! If the entry is stored multiple times in the 96 * ip address hash, we have to reference count it */ 97 ares__llist_t *ips; 98 ares__llist_t *hosts; 99}; 100 101static ares_status_t ares__read_file_into_buf(const char *filename, 102 ares__buf_t *buf) 103{ 104 FILE *fp = NULL; 105 unsigned char *ptr = NULL; 106 size_t len = 0; 107 size_t ptr_len = 0; 108 long ftell_len = 0; 109 ares_status_t status; 110 111 if (filename == NULL || buf == NULL) { 112 return ARES_EFORMERR; 113 } 114 115 fp = fopen(filename, "rb"); 116 if (fp == NULL) { 117 int error = ERRNO; 118 switch (error) { 119 case ENOENT: 120 case ESRCH: 121 status = ARES_ENOTFOUND; 122 goto done; 123 default: 124 DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", error, 125 strerror(error))); 126 DEBUGF(fprintf(stderr, "Error opening file: %s\n", filename)); 127 status = ARES_EFILE; 128 goto done; 129 } 130 } 131 132 /* Get length portably, fstat() is POSIX, not C */ 133 if (fseek(fp, 0, SEEK_END) != 0) { 134 status = ARES_EFILE; 135 goto done; 136 } 137 138 ftell_len = ftell(fp); 139 if (ftell_len < 0) { 140 status = ARES_EFILE; 141 goto done; 142 } 143 len = (size_t)ftell_len; 144 145 if (fseek(fp, 0, SEEK_SET) != 0) { 146 status = ARES_EFILE; 147 goto done; 148 } 149 150 if (len == 0) { 151 status = ARES_SUCCESS; 152 goto done; 153 } 154 155 /* Read entire data into buffer */ 156 ptr_len = len; 157 ptr = ares__buf_append_start(buf, &ptr_len); 158 if (ptr == NULL) { 159 status = ARES_ENOMEM; 160 goto done; 161 } 162 163 ptr_len = fread(ptr, 1, len, fp); 164 if (ptr_len != len) { 165 status = ARES_EFILE; 166 goto done; 167 } 168 169 ares__buf_append_finish(buf, len); 170 status = ARES_SUCCESS; 171 172done: 173 if (fp != NULL) { 174 fclose(fp); 175 } 176 return status; 177} 178 179static ares_bool_t ares__is_hostname(const char *str) 180{ 181 size_t i; 182 for (i = 0; str[i] != 0; i++) { 183 if (!ares__is_hostnamech(str[i])) { 184 return ARES_FALSE; 185 } 186 } 187 return ARES_TRUE; 188} 189 190const void *ares_dns_pton(const char *ipaddr, struct ares_addr *addr, 191 size_t *out_len) 192{ 193 const void *ptr = NULL; 194 size_t ptr_len = 0; 195 196 if (ipaddr == NULL || addr == NULL || out_len == NULL) { 197 return NULL; 198 } 199 200 *out_len = 0; 201 202 if (addr->family == AF_INET && 203 ares_inet_pton(AF_INET, ipaddr, &addr->addr.addr4) > 0) { 204 ptr = &addr->addr.addr4; 205 ptr_len = sizeof(addr->addr.addr4); 206 } else if (addr->family == AF_INET6 && 207 ares_inet_pton(AF_INET6, ipaddr, &addr->addr.addr6) > 0) { 208 ptr = &addr->addr.addr6; 209 ptr_len = sizeof(addr->addr.addr6); 210 } else if (addr->family == AF_UNSPEC) { 211 if (ares_inet_pton(AF_INET, ipaddr, &addr->addr.addr4) > 0) { 212 addr->family = AF_INET; 213 ptr = &addr->addr.addr4; 214 ptr_len = sizeof(addr->addr.addr4); 215 } else if (ares_inet_pton(AF_INET6, ipaddr, &addr->addr.addr6) > 0) { 216 addr->family = AF_INET6; 217 ptr = &addr->addr.addr6; 218 ptr_len = sizeof(addr->addr.addr6); 219 } 220 } 221 222 *out_len = ptr_len; 223 return ptr; 224} 225 226static ares_bool_t ares__normalize_ipaddr(const char *ipaddr, char *out, 227 size_t out_len) 228{ 229 struct ares_addr data; 230 const void *addr; 231 size_t addr_len = 0; 232 233 memset(&data, 0, sizeof(data)); 234 data.family = AF_UNSPEC; 235 236 addr = ares_dns_pton(ipaddr, &data, &addr_len); 237 if (addr == NULL) { 238 return ARES_FALSE; 239 } 240 241 if (!ares_inet_ntop(data.family, addr, out, (ares_socklen_t)out_len)) { 242 return ARES_FALSE; 243 } 244 245 return ARES_TRUE; 246} 247 248static void ares__hosts_entry_destroy(ares_hosts_entry_t *entry) 249{ 250 if (entry == NULL) { 251 return; 252 } 253 254 /* Honor reference counting */ 255 if (entry->refcnt != 0) { 256 entry->refcnt--; 257 } 258 259 if (entry->refcnt > 0) { 260 return; 261 } 262 263 ares__llist_destroy(entry->hosts); 264 ares__llist_destroy(entry->ips); 265 ares_free(entry); 266} 267 268static void ares__hosts_entry_destroy_cb(void *entry) 269{ 270 ares__hosts_entry_destroy(entry); 271} 272 273void ares__hosts_file_destroy(ares_hosts_file_t *hf) 274{ 275 if (hf == NULL) { 276 return; 277 } 278 279 ares_free(hf->filename); 280 ares__htable_strvp_destroy(hf->hosthash); 281 ares__htable_strvp_destroy(hf->iphash); 282 ares_free(hf); 283} 284 285static ares_hosts_file_t *ares__hosts_file_create(const char *filename) 286{ 287 ares_hosts_file_t *hf = ares_malloc_zero(sizeof(*hf)); 288 if (hf == NULL) { 289 goto fail; 290 } 291 292 hf->ts = time(NULL); 293 294 hf->filename = ares_strdup(filename); 295 if (hf->filename == NULL) { 296 goto fail; 297 } 298 299 hf->iphash = ares__htable_strvp_create(ares__hosts_entry_destroy_cb); 300 if (hf->iphash == NULL) { 301 goto fail; 302 } 303 304 hf->hosthash = ares__htable_strvp_create(NULL); 305 if (hf->hosthash == NULL) { 306 goto fail; 307 } 308 309 return hf; 310 311fail: 312 ares__hosts_file_destroy(hf); 313 return NULL; 314} 315 316typedef enum { 317 ARES_MATCH_NONE = 0, 318 ARES_MATCH_IPADDR = 1, 319 ARES_MATCH_HOST = 2 320} ares_hosts_file_match_t; 321 322static ares_status_t ares__hosts_file_merge_entry( 323 const ares_hosts_file_t *hf, ares_hosts_entry_t *existing, 324 ares_hosts_entry_t *entry, ares_hosts_file_match_t matchtype) 325{ 326 ares__llist_node_t *node; 327 328 /* If we matched on IP address, we know there can only be 1, so there's no 329 * reason to do anything */ 330 if (matchtype != ARES_MATCH_IPADDR) { 331 while ((node = ares__llist_node_first(entry->ips)) != NULL) { 332 const char *ipaddr = ares__llist_node_val(node); 333 334 if (ares__htable_strvp_get_direct(hf->iphash, ipaddr) != NULL) { 335 ares__llist_node_destroy(node); 336 continue; 337 } 338 339 ares__llist_node_move_parent_last(node, existing->ips); 340 } 341 } 342 343 344 while ((node = ares__llist_node_first(entry->hosts)) != NULL) { 345 const char *hostname = ares__llist_node_val(node); 346 347 if (ares__htable_strvp_get_direct(hf->hosthash, hostname) != NULL) { 348 ares__llist_node_destroy(node); 349 continue; 350 } 351 352 ares__llist_node_move_parent_last(node, existing->hosts); 353 } 354 355 ares__hosts_entry_destroy(entry); 356 return ARES_SUCCESS; 357} 358 359static ares_hosts_file_match_t 360 ares__hosts_file_match(const ares_hosts_file_t *hf, ares_hosts_entry_t *entry, 361 ares_hosts_entry_t **match) 362{ 363 ares__llist_node_t *node; 364 *match = NULL; 365 366 for (node = ares__llist_node_first(entry->ips); node != NULL; 367 node = ares__llist_node_next(node)) { 368 const char *ipaddr = ares__llist_node_val(node); 369 *match = ares__htable_strvp_get_direct(hf->iphash, ipaddr); 370 if (*match != NULL) { 371 return ARES_MATCH_IPADDR; 372 } 373 } 374 375 for (node = ares__llist_node_first(entry->hosts); node != NULL; 376 node = ares__llist_node_next(node)) { 377 const char *host = ares__llist_node_val(node); 378 *match = ares__htable_strvp_get_direct(hf->hosthash, host); 379 if (*match != NULL) { 380 return ARES_MATCH_HOST; 381 } 382 } 383 384 return ARES_MATCH_NONE; 385} 386 387/*! entry is invalidated upon calling this function, always, even on error */ 388static ares_status_t ares__hosts_file_add(ares_hosts_file_t *hosts, 389 ares_hosts_entry_t *entry) 390{ 391 ares_hosts_entry_t *match = NULL; 392 ares_status_t status = ARES_SUCCESS; 393 ares__llist_node_t *node; 394 ares_hosts_file_match_t matchtype; 395 size_t num_hostnames; 396 397 /* Record the number of hostnames in this entry file. If we merge into an 398 * existing record, these will be *appended* to the entry, so we'll count 399 * backwards when adding to the hosts hashtable */ 400 num_hostnames = ares__llist_len(entry->hosts); 401 402 matchtype = ares__hosts_file_match(hosts, entry, &match); 403 404 if (matchtype != ARES_MATCH_NONE) { 405 status = ares__hosts_file_merge_entry(hosts, match, entry, matchtype); 406 if (status != ARES_SUCCESS) { 407 ares__hosts_entry_destroy(entry); 408 return status; 409 } 410 /* entry was invalidated above by merging */ 411 entry = match; 412 } 413 414 if (matchtype != ARES_MATCH_IPADDR) { 415 const char *ipaddr = ares__llist_last_val(entry->ips); 416 417 if (!ares__htable_strvp_get(hosts->iphash, ipaddr, NULL)) { 418 if (!ares__htable_strvp_insert(hosts->iphash, ipaddr, entry)) { 419 ares__hosts_entry_destroy(entry); 420 return ARES_ENOMEM; 421 } 422 entry->refcnt++; 423 } 424 } 425 426 /* Go backwards, on a merge, hostnames are appended. Breakout once we've 427 * consumed all the hosts that we appended */ 428 for (node = ares__llist_node_last(entry->hosts); node != NULL; 429 node = ares__llist_node_prev(node)) { 430 const char *val = ares__llist_node_val(node); 431 432 if (num_hostnames == 0) { 433 break; 434 } 435 436 num_hostnames--; 437 438 /* first hostname match wins. If we detect a duplicate hostname for another 439 * ip it will automatically be added to the same entry */ 440 if (ares__htable_strvp_get(hosts->hosthash, val, NULL)) { 441 continue; 442 } 443 444 if (!ares__htable_strvp_insert(hosts->hosthash, val, entry)) { 445 return ARES_ENOMEM; 446 } 447 } 448 449 return ARES_SUCCESS; 450} 451 452static ares_bool_t ares__hosts_entry_isdup(ares_hosts_entry_t *entry, 453 const char *host) 454{ 455 ares__llist_node_t *node; 456 457 for (node = ares__llist_node_first(entry->ips); node != NULL; 458 node = ares__llist_node_next(node)) { 459 const char *myhost = ares__llist_node_val(node); 460 if (strcasecmp(myhost, host) == 0) { 461 return ARES_TRUE; 462 } 463 } 464 465 return ARES_FALSE; 466} 467 468static ares_status_t ares__parse_hosts_hostnames(ares__buf_t *buf, 469 ares_hosts_entry_t *entry) 470{ 471 entry->hosts = ares__llist_create(ares_free); 472 if (entry->hosts == NULL) { 473 return ARES_ENOMEM; 474 } 475 476 /* Parse hostnames and aliases */ 477 while (ares__buf_len(buf)) { 478 char hostname[256]; 479 char *temp; 480 ares_status_t status; 481 unsigned char comment = '#'; 482 483 ares__buf_consume_whitespace(buf, ARES_FALSE); 484 485 if (ares__buf_len(buf) == 0) { 486 break; 487 } 488 489 /* See if it is a comment, if so stop processing */ 490 if (ares__buf_begins_with(buf, &comment, 1)) { 491 break; 492 } 493 494 ares__buf_tag(buf); 495 496 /* Must be at end of line */ 497 if (ares__buf_consume_nonwhitespace(buf) == 0) { 498 break; 499 } 500 501 status = ares__buf_tag_fetch_string(buf, hostname, sizeof(hostname)); 502 if (status != ARES_SUCCESS) { 503 /* Bad entry, just ignore as long as its not the first. If its the first, 504 * it must be valid */ 505 if (ares__llist_len(entry->hosts) == 0) { 506 return ARES_EBADSTR; 507 } 508 509 continue; 510 } 511 512 /* Validate it is a valid hostname characterset */ 513 if (!ares__is_hostname(hostname)) { 514 continue; 515 } 516 517 /* Don't add a duplicate to the same entry */ 518 if (ares__hosts_entry_isdup(entry, hostname)) { 519 continue; 520 } 521 522 /* Add to list */ 523 temp = ares_strdup(hostname); 524 if (temp == NULL) { 525 return ARES_ENOMEM; 526 } 527 528 if (ares__llist_insert_last(entry->hosts, temp) == NULL) { 529 ares_free(temp); 530 return ARES_ENOMEM; 531 } 532 } 533 534 /* Must have at least 1 entry */ 535 if (ares__llist_len(entry->hosts) == 0) { 536 return ARES_EBADSTR; 537 } 538 539 return ARES_SUCCESS; 540} 541 542static ares_status_t ares__parse_hosts_ipaddr(ares__buf_t *buf, 543 ares_hosts_entry_t **entry_out) 544{ 545 char addr[INET6_ADDRSTRLEN]; 546 char *temp; 547 ares_hosts_entry_t *entry = NULL; 548 ares_status_t status; 549 550 *entry_out = NULL; 551 552 ares__buf_tag(buf); 553 ares__buf_consume_nonwhitespace(buf); 554 status = ares__buf_tag_fetch_string(buf, addr, sizeof(addr)); 555 if (status != ARES_SUCCESS) { 556 return status; 557 } 558 559 /* Validate and normalize the ip address format */ 560 if (!ares__normalize_ipaddr(addr, addr, sizeof(addr))) { 561 return ARES_EBADSTR; 562 } 563 564 entry = ares_malloc_zero(sizeof(*entry)); 565 if (entry == NULL) { 566 return ARES_ENOMEM; 567 } 568 569 entry->ips = ares__llist_create(ares_free); 570 if (entry->ips == NULL) { 571 ares__hosts_entry_destroy(entry); 572 return ARES_ENOMEM; 573 } 574 575 temp = ares_strdup(addr); 576 if (temp == NULL) { 577 ares__hosts_entry_destroy(entry); 578 return ARES_ENOMEM; 579 } 580 581 if (ares__llist_insert_first(entry->ips, temp) == NULL) { 582 ares_free(temp); 583 ares__hosts_entry_destroy(entry); 584 return ARES_ENOMEM; 585 } 586 587 *entry_out = entry; 588 589 return ARES_SUCCESS; 590} 591 592static ares_status_t ares__parse_hosts(const char *filename, 593 ares_hosts_file_t **out) 594{ 595 ares__buf_t *buf = NULL; 596 ares_status_t status = ARES_EBADRESP; 597 ares_hosts_file_t *hf = NULL; 598 ares_hosts_entry_t *entry = NULL; 599 600 *out = NULL; 601 602 buf = ares__buf_create(); 603 if (buf == NULL) { 604 status = ARES_ENOMEM; 605 goto done; 606 } 607 608 status = ares__read_file_into_buf(filename, buf); 609 if (status != ARES_SUCCESS) { 610 goto done; 611 } 612 613 hf = ares__hosts_file_create(filename); 614 if (hf == NULL) { 615 status = ARES_ENOMEM; 616 goto done; 617 } 618 619 while (ares__buf_len(buf)) { 620 unsigned char comment = '#'; 621 622 /* -- Start of new line here -- */ 623 624 /* Consume any leading whitespace */ 625 ares__buf_consume_whitespace(buf, ARES_FALSE); 626 627 if (ares__buf_len(buf) == 0) { 628 break; 629 } 630 631 /* See if it is a comment, if so, consume remaining line */ 632 if (ares__buf_begins_with(buf, &comment, 1)) { 633 ares__buf_consume_line(buf, ARES_TRUE); 634 continue; 635 } 636 637 /* Pull off ip address */ 638 status = ares__parse_hosts_ipaddr(buf, &entry); 639 if (status == ARES_ENOMEM) { 640 goto done; 641 } 642 if (status != ARES_SUCCESS) { 643 /* Bad line, consume and go onto next */ 644 ares__buf_consume_line(buf, ARES_TRUE); 645 continue; 646 } 647 648 /* Parse of the hostnames */ 649 status = ares__parse_hosts_hostnames(buf, entry); 650 if (status == ARES_ENOMEM) { 651 goto done; 652 } else if (status != ARES_SUCCESS) { 653 /* Bad line, consume and go onto next */ 654 ares__hosts_entry_destroy(entry); 655 entry = NULL; 656 ares__buf_consume_line(buf, ARES_TRUE); 657 continue; 658 } 659 660 /* Append the successful entry to the hosts file */ 661 status = ares__hosts_file_add(hf, entry); 662 entry = NULL; /* is always invalidated by this function, even on error */ 663 if (status != ARES_SUCCESS) { 664 goto done; 665 } 666 667 /* Go to next line */ 668 ares__buf_consume_line(buf, ARES_TRUE); 669 } 670 671 status = ARES_SUCCESS; 672 673done: 674 ares__hosts_entry_destroy(entry); 675 ares__buf_destroy(buf); 676 if (status != ARES_SUCCESS) { 677 ares__hosts_file_destroy(hf); 678 } else { 679 *out = hf; 680 } 681 return status; 682} 683 684static ares_bool_t ares__hosts_expired(const char *filename, 685 const ares_hosts_file_t *hf) 686{ 687 time_t mod_ts = 0; 688 689#ifdef HAVE_STAT 690 struct stat st; 691 if (stat(filename, &st) == 0) { 692 mod_ts = st.st_mtime; 693 } 694#elif defined(_WIN32) 695 struct _stat st; 696 if (_stat(filename, &st) == 0) { 697 mod_ts = st.st_mtime; 698 } 699#else 700 (void)filename; 701#endif 702 703 if (hf == NULL) { 704 return ARES_TRUE; 705 } 706 707 /* Expire every 60s if we can't get a time */ 708 if (mod_ts == 0) { 709 mod_ts = time(NULL) - 60; 710 } 711 712 /* If filenames are different, its expired */ 713 if (strcasecmp(hf->filename, filename) != 0) { 714 return ARES_TRUE; 715 } 716 717 if (hf->ts <= mod_ts) { 718 return ARES_TRUE; 719 } 720 721 return ARES_FALSE; 722} 723 724static ares_status_t ares__hosts_path(const ares_channel_t *channel, 725 ares_bool_t use_env, char **path) 726{ 727 char *path_hosts = NULL; 728 729 *path = NULL; 730 731 if (channel->hosts_path) { 732 path_hosts = ares_strdup(channel->hosts_path); 733 if (!path_hosts) { 734 return ARES_ENOMEM; 735 } 736 } 737 738 if (use_env) { 739 if (path_hosts) { 740 ares_free(path_hosts); 741 } 742 743 path_hosts = ares_strdup(getenv("CARES_HOSTS")); 744 if (!path_hosts) { 745 return ARES_ENOMEM; 746 } 747 } 748 749 if (!path_hosts) { 750#ifdef WIN32 751 char PATH_HOSTS[MAX_PATH] = ""; 752 char tmp[MAX_PATH]; 753 HKEY hkeyHosts; 754 DWORD dwLength = sizeof(tmp); 755 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ, 756 &hkeyHosts) != ERROR_SUCCESS) { 757 return ARES_ENOTFOUND; 758 } 759 RegQueryValueExA(hkeyHosts, DATABASEPATH, NULL, NULL, (LPBYTE)tmp, 760 &dwLength); 761 ExpandEnvironmentStringsA(tmp, PATH_HOSTS, MAX_PATH); 762 RegCloseKey(hkeyHosts); 763 strcat(PATH_HOSTS, WIN_PATH_HOSTS); 764#elif defined(WATT32) 765 const char *PATH_HOSTS = _w32_GetHostsFile(); 766 767 if (!PATH_HOSTS) { 768 return ARES_ENOTFOUND; 769 } 770#endif 771 path_hosts = ares_strdup(PATH_HOSTS); 772 if (!path_hosts) { 773 return ARES_ENOMEM; 774 } 775 } 776 777 *path = path_hosts; 778 return ARES_SUCCESS; 779} 780 781static ares_status_t ares__hosts_update(ares_channel_t *channel, 782 ares_bool_t use_env) 783{ 784 ares_status_t status; 785 char *filename = NULL; 786 787 status = ares__hosts_path(channel, use_env, &filename); 788 if (status != ARES_SUCCESS) { 789 return status; 790 } 791 792 if (!ares__hosts_expired(filename, channel->hf)) { 793 ares_free(filename); 794 return ARES_SUCCESS; 795 } 796 797 ares__hosts_file_destroy(channel->hf); 798 channel->hf = NULL; 799 800 status = ares__parse_hosts(filename, &channel->hf); 801 ares_free(filename); 802 return status; 803} 804 805ares_status_t ares__hosts_search_ipaddr(ares_channel_t *channel, 806 ares_bool_t use_env, const char *ipaddr, 807 const ares_hosts_entry_t **entry) 808{ 809 ares_status_t status; 810 char addr[INET6_ADDRSTRLEN]; 811 812 *entry = NULL; 813 814 status = ares__hosts_update(channel, use_env); 815 if (status != ARES_SUCCESS) { 816 return status; 817 } 818 819 if (channel->hf == NULL) { 820 return ARES_ENOTFOUND; 821 } 822 823 if (!ares__normalize_ipaddr(ipaddr, addr, sizeof(addr))) { 824 return ARES_EBADNAME; 825 } 826 827 *entry = ares__htable_strvp_get_direct(channel->hf->iphash, addr); 828 if (*entry == NULL) { 829 return ARES_ENOTFOUND; 830 } 831 832 return ARES_SUCCESS; 833} 834 835ares_status_t ares__hosts_search_host(ares_channel_t *channel, 836 ares_bool_t use_env, const char *host, 837 const ares_hosts_entry_t **entry) 838{ 839 ares_status_t status; 840 841 *entry = NULL; 842 843 status = ares__hosts_update(channel, use_env); 844 if (status != ARES_SUCCESS) { 845 return status; 846 } 847 848 if (channel->hf == NULL) { 849 return ARES_ENOTFOUND; 850 } 851 852 *entry = ares__htable_strvp_get_direct(channel->hf->hosthash, host); 853 if (*entry == NULL) { 854 return ARES_ENOTFOUND; 855 } 856 857 return ARES_SUCCESS; 858} 859 860ares_status_t ares__hosts_entry_to_hostent(const ares_hosts_entry_t *entry, 861 int family, struct hostent **hostent) 862{ 863 ares_status_t status; 864 size_t naliases; 865 ares__llist_node_t *node; 866 size_t idx; 867 868 *hostent = ares_malloc_zero(sizeof(**hostent)); 869 if (*hostent == NULL) { 870 status = ARES_ENOMEM; 871 goto fail; 872 } 873 874 (*hostent)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)family; 875 876 /* Copy IP addresses that match the address family */ 877 idx = 0; 878 for (node = ares__llist_node_first(entry->ips); node != NULL; 879 node = ares__llist_node_next(node)) { 880 struct ares_addr addr; 881 const void *ptr = NULL; 882 size_t ptr_len = 0; 883 const char *ipaddr = ares__llist_node_val(node); 884 char **temp = NULL; 885 886 memset(&addr, 0, sizeof(addr)); 887 888 addr.family = family; 889 ptr = ares_dns_pton(ipaddr, &addr, &ptr_len); 890 if (ptr == NULL) { 891 continue; 892 } 893 894 /* If family == AF_UNSPEC, then we want to inherit this for future 895 * conversions as we can only support a single address class */ 896 if (family == AF_UNSPEC) { 897 family = addr.family; 898 (*hostent)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)addr.family; 899 } 900 901 temp = ares_realloc_zero((*hostent)->h_addr_list, 902 (idx + 1) * sizeof(*(*hostent)->h_addr_list), 903 (idx + 2) * sizeof(*(*hostent)->h_addr_list)); 904 if (temp == NULL) { 905 status = ARES_ENOMEM; 906 goto fail; 907 } 908 909 (*hostent)->h_addr_list = temp; 910 911 (*hostent)->h_addr_list[idx] = ares_malloc(ptr_len); 912 if ((*hostent)->h_addr_list[idx] == NULL) { 913 status = ARES_ENOMEM; 914 goto fail; 915 } 916 917 memcpy((*hostent)->h_addr_list[idx], ptr, ptr_len); 918 idx++; 919 (*hostent)->h_length = (HOSTENT_LENGTH_TYPE)ptr_len; 920 } 921 922 /* entry didn't match address class */ 923 if (idx == 0) { 924 status = ARES_ENOTFOUND; 925 goto fail; 926 } 927 928 /* Copy main hostname */ 929 (*hostent)->h_name = ares_strdup(ares__llist_first_val(entry->hosts)); 930 if ((*hostent)->h_name == NULL) { 931 status = ARES_ENOMEM; 932 goto fail; 933 } 934 935 /* Copy aliases */ 936 naliases = ares__llist_len(entry->hosts) - 1; 937 938 /* Cap at 100, some people use https://github.com/StevenBlack/hosts and we 939 * don't need 200k+ aliases */ 940 if (naliases > 100) { 941 naliases = 100; 942 } 943 944 (*hostent)->h_aliases = 945 ares_malloc_zero((naliases + 1) * sizeof(*(*hostent)->h_aliases)); 946 if ((*hostent)->h_aliases == NULL) { 947 status = ARES_ENOMEM; 948 goto fail; 949 } 950 951 /* Copy all entries to the alias except the first */ 952 idx = 0; 953 node = ares__llist_node_first(entry->hosts); 954 node = ares__llist_node_next(node); 955 while (node != NULL) { 956 (*hostent)->h_aliases[idx] = ares_strdup(ares__llist_node_val(node)); 957 if ((*hostent)->h_aliases[idx] == NULL) { 958 status = ARES_ENOMEM; 959 goto fail; 960 } 961 idx++; 962 963 /* Break out if artificially capped */ 964 if (idx == naliases) { 965 break; 966 } 967 node = ares__llist_node_next(node); 968 } 969 970 return ARES_SUCCESS; 971 972fail: 973 ares_free_hostent(*hostent); 974 *hostent = NULL; 975 return status; 976} 977 978static ares_status_t 979 ares__hosts_ai_append_cnames(const ares_hosts_entry_t *entry, 980 struct ares_addrinfo_cname **cnames_out) 981{ 982 struct ares_addrinfo_cname *cname = NULL; 983 struct ares_addrinfo_cname *cnames = NULL; 984 const char *primaryhost; 985 ares__llist_node_t *node; 986 ares_status_t status; 987 size_t cnt = 0; 988 989 node = ares__llist_node_first(entry->hosts); 990 primaryhost = ares__llist_node_val(node); 991 /* Skip to next node to start with aliases */ 992 node = ares__llist_node_next(node); 993 994 while (node != NULL) { 995 const char *host = ares__llist_node_val(node); 996 997 /* Cap at 100 entries. , some people use 998 * https://github.com/StevenBlack/hosts and we don't need 200k+ aliases */ 999 cnt++; 1000 if (cnt > 100) { 1001 break; 1002 } 1003 1004 cname = ares__append_addrinfo_cname(&cnames); 1005 if (cname == NULL) { 1006 status = ARES_ENOMEM; 1007 goto done; 1008 } 1009 1010 cname->alias = ares_strdup(host); 1011 if (cname->alias == NULL) { 1012 status = ARES_ENOMEM; 1013 goto done; 1014 } 1015 1016 cname->name = ares_strdup(primaryhost); 1017 if (cname->name == NULL) { 1018 status = ARES_ENOMEM; 1019 goto done; 1020 } 1021 1022 node = ares__llist_node_next(node); 1023 } 1024 1025 /* No entries, add only primary */ 1026 if (cnames == NULL) { 1027 cname = ares__append_addrinfo_cname(&cnames); 1028 if (cname == NULL) { 1029 status = ARES_ENOMEM; 1030 goto done; 1031 } 1032 1033 cname->name = ares_strdup(primaryhost); 1034 if (cname->name == NULL) { 1035 status = ARES_ENOMEM; 1036 goto done; 1037 } 1038 } 1039 status = ARES_SUCCESS; 1040 1041done: 1042 if (status != ARES_SUCCESS) { 1043 ares__freeaddrinfo_cnames(cnames); 1044 return status; 1045 } 1046 1047 *cnames_out = cnames; 1048 return ARES_SUCCESS; 1049} 1050 1051ares_status_t ares__hosts_entry_to_addrinfo(const ares_hosts_entry_t *entry, 1052 const char *name, int family, 1053 unsigned short port, 1054 ares_bool_t want_cnames, 1055 struct ares_addrinfo *ai) 1056{ 1057 ares_status_t status; 1058 struct ares_addrinfo_cname *cnames = NULL; 1059 struct ares_addrinfo_node *ainodes = NULL; 1060 ares__llist_node_t *node; 1061 1062 switch (family) { 1063 case AF_INET: 1064 case AF_INET6: 1065 case AF_UNSPEC: 1066 break; 1067 default: 1068 return ARES_EBADFAMILY; 1069 } 1070 1071 ai->name = ares_strdup(name); 1072 if (ai->name == NULL) { 1073 status = ARES_ENOMEM; 1074 goto done; 1075 } 1076 1077 for (node = ares__llist_node_first(entry->ips); node != NULL; 1078 node = ares__llist_node_next(node)) { 1079 struct ares_addr addr; 1080 const void *ptr = NULL; 1081 size_t ptr_len = 0; 1082 const char *ipaddr = ares__llist_node_val(node); 1083 1084 memset(&addr, 0, sizeof(addr)); 1085 addr.family = family; 1086 ptr = ares_dns_pton(ipaddr, &addr, &ptr_len); 1087 1088 if (ptr == NULL) { 1089 continue; 1090 } 1091 1092 status = ares_append_ai_node(addr.family, port, 0, ptr, &ainodes); 1093 if (status != ARES_SUCCESS) { 1094 goto done; 1095 } 1096 } 1097 1098 if (want_cnames) { 1099 status = ares__hosts_ai_append_cnames(entry, &cnames); 1100 if (status != ARES_SUCCESS) { 1101 goto done; 1102 } 1103 } 1104 1105 status = ARES_SUCCESS; 1106 1107done: 1108 if (status != ARES_SUCCESS) { 1109 ares__freeaddrinfo_cnames(cnames); 1110 ares__freeaddrinfo_nodes(ainodes); 1111 ares_free(ai->name); 1112 ai->name = NULL; 1113 return status; 1114 } 1115 ares__addrinfo_cat_cnames(&ai->cnames, cnames); 1116 ares__addrinfo_cat_nodes(&ai->nodes, ainodes); 1117 1118 return status; 1119} 1120