ares_sysconfig.c (18132B)
1 /* MIT License 2 * 3 * Copyright (c) 1998 Massachusetts Institute of Technology 4 * Copyright (c) 2007 Daniel Stenberg 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * SPDX-License-Identifier: MIT 26 */ 27 28 #include "ares_private.h" 29 30 #ifdef HAVE_SYS_PARAM_H 31 # include <sys/param.h> 32 #endif 33 34 #ifdef HAVE_NETINET_IN_H 35 # include <netinet/in.h> 36 #endif 37 38 #ifdef HAVE_NETDB_H 39 # include <netdb.h> 40 #endif 41 42 #ifdef HAVE_ARPA_INET_H 43 # include <arpa/inet.h> 44 #endif 45 46 #if defined(ANDROID) || defined(__ANDROID__) 47 # include <sys/system_properties.h> 48 # include "ares_android.h" 49 /* From the Bionic sources */ 50 # define DNS_PROP_NAME_PREFIX "net.dns" 51 # define MAX_DNS_PROPERTIES 8 52 #endif 53 54 #if defined(CARES_USE_LIBRESOLV) 55 # include <resolv.h> 56 #endif 57 58 #include "ares_inet_net_pton.h" 59 60 61 #if defined(__MVS__) 62 static ares_status_t ares_init_sysconfig_mvs(const ares_channel_t *channel, 63 ares_sysconfig_t *sysconfig) 64 { 65 struct __res_state *res = 0; 66 size_t count4; 67 size_t count6; 68 int i; 69 __STATEEXTIPV6 *v6; 70 arse__llist_t *sconfig = NULL; 71 ares_status_t status; 72 73 if (0 == res) { 74 int rc = res_init(); 75 while (rc == -1 && h_errno == TRY_AGAIN) { 76 rc = res_init(); 77 } 78 if (rc == -1) { 79 return ARES_ENOMEM; 80 } 81 res = __res(); 82 } 83 84 v6 = res->__res_extIPv6; 85 if (res->nscount > 0) { 86 count4 = (size_t)res->nscount; 87 } 88 89 if (v6 && v6->__stat_nscount > 0) { 90 count6 = (size_t)v6->__stat_nscount; 91 } else { 92 count6 = 0; 93 } 94 95 for (i = 0; i < count4; i++) { 96 struct sockaddr_in *addr_in = &(res->nsaddr_list[i]); 97 struct ares_addr addr; 98 99 addr.addr.addr4.s_addr = addr_in->sin_addr.s_addr; 100 addr.family = AF_INET; 101 102 status = ares_sconfig_append(channel, &sysconfig->sconfig, &addr, 103 htons(addr_in->sin_port), 104 htons(addr_in->sin_port), NULL); 105 106 if (status != ARES_SUCCESS) { 107 return status; 108 } 109 } 110 111 for (i = 0; i < count6; i++) { 112 struct sockaddr_in6 *addr_in = &(v6->__stat_nsaddr_list[i]); 113 struct ares_addr addr; 114 115 addr.family = AF_INET6; 116 memcpy(&(addr.addr.addr6), &(addr_in->sin6_addr), 117 sizeof(addr_in->sin6_addr)); 118 119 status = ares_sconfig_append(channel, &sysconfig->sconfig, &addr, 120 htons(addr_in->sin_port), 121 htons(addr_in->sin_port), NULL); 122 123 if (status != ARES_SUCCESS) { 124 return status; 125 } 126 } 127 128 return ARES_SUCCESS; 129 } 130 #endif 131 132 #if defined(__riscos__) 133 static ares_status_t ares_init_sysconfig_riscos(const ares_channel_t *channel, 134 ares_sysconfig_t *sysconfig) 135 { 136 char *line; 137 ares_status_t status = ARES_SUCCESS; 138 139 /* Under RISC OS, name servers are listed in the 140 system variable Inet$Resolvers, space separated. */ 141 line = getenv("Inet$Resolvers"); 142 if (line) { 143 char *resolvers = ares_strdup(line); 144 char *pos; 145 char *space; 146 147 if (!resolvers) { 148 return ARES_ENOMEM; 149 } 150 151 pos = resolvers; 152 do { 153 space = strchr(pos, ' '); 154 if (space) { 155 *space = '\0'; 156 } 157 status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig, pos, 158 ARES_TRUE); 159 if (status != ARES_SUCCESS) { 160 break; 161 } 162 pos = space + 1; 163 } while (space); 164 165 ares_free(resolvers); 166 } 167 168 return status; 169 } 170 #endif 171 172 #if defined(WATT32) 173 static ares_status_t ares_init_sysconfig_watt32(const ares_channel_t *channel, 174 ares_sysconfig_t *sysconfig) 175 { 176 size_t i; 177 ares_status_t status; 178 179 sock_init(); 180 181 for (i = 0; def_nameservers[i]; i++) { 182 struct ares_addr addr; 183 184 addr.family = AF_INET; 185 addr.addr.addr4.s_addr = htonl(def_nameservers[i]); 186 187 status = 188 ares_sconfig_append(channel, &sysconfig->sconfig, &addr, 0, 0, NULL); 189 190 if (status != ARES_SUCCESS) { 191 return status; 192 } 193 } 194 195 return ARES_SUCCESS; 196 } 197 #endif 198 199 #if defined(ANDROID) || defined(__ANDROID__) 200 static ares_status_t ares_init_sysconfig_android(const ares_channel_t *channel, 201 ares_sysconfig_t *sysconfig) 202 { 203 size_t i; 204 char **dns_servers; 205 char *domains; 206 size_t num_servers; 207 ares_status_t status = ARES_EFILE; 208 209 /* Use the Android connectivity manager to get a list 210 * of DNS servers. As of Android 8 (Oreo) net.dns# 211 * system properties are no longer available. Google claims this 212 * improves privacy. Apps now need the ACCESS_NETWORK_STATE 213 * permission and must use the ConnectivityManager which 214 * is Java only. */ 215 dns_servers = ares_get_android_server_list(MAX_DNS_PROPERTIES, &num_servers); 216 if (dns_servers != NULL) { 217 for (i = 0; i < num_servers; i++) { 218 status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig, 219 dns_servers[i], ARES_TRUE); 220 if (status != ARES_SUCCESS) { 221 return status; 222 } 223 } 224 for (i = 0; i < num_servers; i++) { 225 ares_free(dns_servers[i]); 226 } 227 ares_free(dns_servers); 228 } 229 230 domains = ares_get_android_search_domains_list(); 231 sysconfig->domains = ares_strsplit(domains, ", ", &sysconfig->ndomains); 232 ares_free(domains); 233 234 # ifdef HAVE___SYSTEM_PROPERTY_GET 235 /* Old way using the system property still in place as 236 * a fallback. Older android versions can still use this. 237 * it's possible for older apps not not have added the new 238 * permission and we want to try to avoid breaking those. 239 * 240 * We'll only run this if we don't have any dns servers 241 * because this will get the same ones (if it works). */ 242 if (sysconfig->sconfig == NULL) { 243 char propname[PROP_NAME_MAX]; 244 char propvalue[PROP_VALUE_MAX] = ""; 245 for (i = 1; i <= MAX_DNS_PROPERTIES; i++) { 246 snprintf(propname, sizeof(propname), "%s%zu", DNS_PROP_NAME_PREFIX, i); 247 if (__system_property_get(propname, propvalue) < 1) { 248 break; 249 } 250 status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig, 251 propvalue, ARES_TRUE); 252 if (status != ARES_SUCCESS) { 253 return status; 254 } 255 } 256 } 257 # endif /* HAVE___SYSTEM_PROPERTY_GET */ 258 259 return status; 260 } 261 #endif 262 263 #if defined(__QNX__) 264 static ares_status_t 265 ares_init_sysconfig_qnx(const ares_channel_t *channel, 266 ares_sysconfig_t *sysconfig) 267 { 268 /* QNX: 269 * 1. use confstr(_CS_RESOLVE, ...) as primary resolv.conf data, replacing 270 * "_" with " ". If that is empty, then do normal /etc/resolv.conf 271 * processing. 272 * 2. We want to process /etc/nsswitch.conf as normal. 273 * 3. if confstr(_CS_DOMAIN, ...) this is the domain name. Use this as 274 * preference over anything else found. 275 */ 276 ares_buf_t *buf = ares_buf_create(); 277 unsigned char *data = NULL; 278 size_t data_size = 0; 279 ares_bool_t process_resolvconf = ARES_TRUE; 280 ares_status_t status = ARES_SUCCESS; 281 282 /* Prefer confstr(_CS_RESOLVE, ...) */ 283 buf = ares_buf_create(); 284 if (buf == NULL) { 285 status = ARES_ENOMEM; 286 goto done; 287 } 288 289 data_size = 1024; 290 data = ares_buf_append_start(buf, &data_size); 291 if (data == NULL) { 292 status = ARES_ENOMEM; 293 goto done; 294 } 295 296 data_size = confstr(_CS_RESOLVE, (char *)data, data_size); 297 if (data_size > 1) { 298 /* confstr returns byte for NULL terminator, strip */ 299 data_size--; 300 301 ares_buf_append_finish(buf, data_size); 302 /* Its odd, this uses _ instead of " " between keywords, otherwise the 303 * format is the same as resolv.conf, replace. */ 304 ares_buf_replace(buf, (const unsigned char *)"_", 1, 305 (const unsigned char *)" ", 1); 306 307 status = ares_sysconfig_process_buf(channel, sysconfig, buf, 308 ares_sysconfig_parse_resolv_line); 309 if (status != ARES_SUCCESS) { 310 /* ENOMEM is really the only error we'll get here */ 311 goto done; 312 } 313 314 /* don't read resolv.conf if we processed *any* nameservers */ 315 if (ares_llist_len(sysconfig->sconfig) != 0) { 316 process_resolvconf = ARES_FALSE; 317 } 318 } 319 320 /* Process files */ 321 status = ares_init_sysconfig_files(channel, sysconfig, process_resolvconf); 322 if (status != ARES_SUCCESS) { 323 goto done; 324 } 325 326 /* Read confstr(_CS_DOMAIN, ...), but if we had a search path specified with 327 * more than one domain, lets prefer that instead. Its not exactly clear 328 * the best way to handle this. */ 329 if (sysconfig->ndomains <= 1) { 330 char domain[256]; 331 size_t domain_len; 332 333 domain_len = confstr(_CS_DOMAIN, domain, sizeof(domain_len)); 334 if (domain_len != 0) { 335 ares_strsplit_free(sysconfig->domains, sysconfig->ndomains); 336 sysconfig->domains = ares_strsplit(domain, ", ", &sysconfig->ndomains); 337 if (sysconfig->domains == NULL) { 338 status = ARES_ENOMEM; 339 goto done; 340 } 341 } 342 } 343 344 done: 345 ares_buf_destroy(buf); 346 347 return status; 348 } 349 #endif 350 351 #if defined(CARES_USE_LIBRESOLV) 352 static ares_status_t 353 ares_init_sysconfig_libresolv(const ares_channel_t *channel, 354 ares_sysconfig_t *sysconfig) 355 { 356 struct __res_state res; 357 ares_status_t status = ARES_SUCCESS; 358 union res_sockaddr_union addr[MAXNS]; 359 int nscount; 360 size_t i; 361 size_t entries = 0; 362 ares_buf_t *ipbuf = NULL; 363 364 memset(&res, 0, sizeof(res)); 365 366 if (res_ninit(&res) != 0 || !(res.options & RES_INIT)) { 367 return ARES_EFILE; 368 } 369 370 nscount = res_getservers(&res, addr, MAXNS); 371 372 for (i = 0; i < (size_t)nscount; ++i) { 373 char ipaddr[INET6_ADDRSTRLEN] = ""; 374 char *ipstr = NULL; 375 unsigned short port = 0; 376 unsigned int ll_scope = 0; 377 378 sa_family_t family = addr[i].sin.sin_family; 379 if (family == AF_INET) { 380 ares_inet_ntop(family, &addr[i].sin.sin_addr, ipaddr, sizeof(ipaddr)); 381 port = ntohs(addr[i].sin.sin_port); 382 } else if (family == AF_INET6) { 383 ares_inet_ntop(family, &addr[i].sin6.sin6_addr, ipaddr, sizeof(ipaddr)); 384 port = ntohs(addr[i].sin6.sin6_port); 385 ll_scope = addr[i].sin6.sin6_scope_id; 386 } else { 387 continue; 388 } 389 390 391 /* [ip]:port%iface */ 392 ipbuf = ares_buf_create(); 393 if (ipbuf == NULL) { 394 status = ARES_ENOMEM; 395 goto done; 396 } 397 398 status = ares_buf_append_str(ipbuf, "["); 399 if (status != ARES_SUCCESS) { 400 goto done; 401 } 402 403 status = ares_buf_append_str(ipbuf, ipaddr); 404 if (status != ARES_SUCCESS) { 405 goto done; 406 } 407 408 status = ares_buf_append_str(ipbuf, "]"); 409 if (status != ARES_SUCCESS) { 410 goto done; 411 } 412 413 if (port) { 414 status = ares_buf_append_str(ipbuf, ":"); 415 if (status != ARES_SUCCESS) { 416 goto done; 417 } 418 status = ares_buf_append_num_dec(ipbuf, port, 0); 419 if (status != ARES_SUCCESS) { 420 goto done; 421 } 422 } 423 424 if (ll_scope) { 425 status = ares_buf_append_str(ipbuf, "%"); 426 if (status != ARES_SUCCESS) { 427 goto done; 428 } 429 status = ares_buf_append_num_dec(ipbuf, ll_scope, 0); 430 if (status != ARES_SUCCESS) { 431 goto done; 432 } 433 } 434 435 ipstr = ares_buf_finish_str(ipbuf, NULL); 436 ipbuf = NULL; 437 if (ipstr == NULL) { 438 status = ARES_ENOMEM; 439 goto done; 440 } 441 442 status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig, ipstr, 443 ARES_TRUE); 444 445 ares_free(ipstr); 446 if (status != ARES_SUCCESS) { 447 goto done; 448 } 449 } 450 451 while ((entries < MAXDNSRCH) && res.dnsrch[entries]) { 452 entries++; 453 } 454 455 if (entries) { 456 sysconfig->domains = ares_malloc_zero(entries * sizeof(char *)); 457 if (sysconfig->domains == NULL) { 458 status = ARES_ENOMEM; 459 goto done; 460 } else { 461 sysconfig->ndomains = entries; 462 for (i = 0; i < sysconfig->ndomains; i++) { 463 sysconfig->domains[i] = ares_strdup(res.dnsrch[i]); 464 if (sysconfig->domains[i] == NULL) { 465 status = ARES_ENOMEM; 466 goto done; 467 } 468 } 469 } 470 } 471 472 if (res.ndots >= 0) { 473 sysconfig->ndots = (size_t)res.ndots; 474 } 475 /* Apple does not allow configuration of retry, so this is a static dummy 476 * value, ignore */ 477 # ifndef __APPLE__ 478 if (res.retry > 0) { 479 sysconfig->tries = (size_t)res.retry; 480 } 481 # endif 482 if (res.options & RES_ROTATE) { 483 sysconfig->rotate = ARES_TRUE; 484 } 485 486 if (res.retrans > 0) { 487 /* Apple does not allow configuration of retrans, so this is a dummy value 488 * that is extremely high (5s) */ 489 # ifndef __APPLE__ 490 if (res.retrans > 0) { 491 sysconfig->timeout_ms = (unsigned int)res.retrans * 1000; 492 } 493 # endif 494 } 495 496 done: 497 ares_buf_destroy(ipbuf); 498 res_ndestroy(&res); 499 return status; 500 } 501 #endif 502 503 static void ares_sysconfig_free(ares_sysconfig_t *sysconfig) 504 { 505 ares_llist_destroy(sysconfig->sconfig); 506 ares_strsplit_free(sysconfig->domains, sysconfig->ndomains); 507 ares_free(sysconfig->sortlist); 508 ares_free(sysconfig->lookups); 509 memset(sysconfig, 0, sizeof(*sysconfig)); 510 } 511 512 static ares_status_t ares_sysconfig_apply(ares_channel_t *channel, 513 const ares_sysconfig_t *sysconfig) 514 { 515 ares_status_t status; 516 517 if (sysconfig->sconfig && !(channel->optmask & ARES_OPT_SERVERS)) { 518 status = ares_servers_update(channel, sysconfig->sconfig, ARES_FALSE); 519 if (status != ARES_SUCCESS) { 520 return status; 521 } 522 } 523 524 if (sysconfig->domains && !(channel->optmask & ARES_OPT_DOMAINS)) { 525 /* Make sure we duplicate first then replace so even if there is 526 * ARES_ENOMEM, the channel stays in a good state */ 527 char **temp = 528 ares_strsplit_duplicate(sysconfig->domains, sysconfig->ndomains); 529 if (temp == NULL) { 530 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 531 } 532 533 ares_strsplit_free(channel->domains, channel->ndomains); 534 channel->domains = temp; 535 channel->ndomains = sysconfig->ndomains; 536 } 537 538 if (sysconfig->lookups && !(channel->optmask & ARES_OPT_LOOKUPS)) { 539 char *temp = ares_strdup(sysconfig->lookups); 540 if (temp == NULL) { 541 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 542 } 543 544 ares_free(channel->lookups); 545 channel->lookups = temp; 546 } 547 548 if (sysconfig->sortlist && !(channel->optmask & ARES_OPT_SORTLIST)) { 549 struct apattern *temp = 550 ares_malloc(sizeof(*channel->sortlist) * sysconfig->nsortlist); 551 if (temp == NULL) { 552 return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */ 553 } 554 memcpy(temp, sysconfig->sortlist, 555 sizeof(*channel->sortlist) * sysconfig->nsortlist); 556 557 ares_free(channel->sortlist); 558 channel->sortlist = temp; 559 channel->nsort = sysconfig->nsortlist; 560 } 561 562 if (!(channel->optmask & ARES_OPT_NDOTS)) { 563 channel->ndots = sysconfig->ndots; 564 } 565 566 if (sysconfig->tries && !(channel->optmask & ARES_OPT_TRIES)) { 567 channel->tries = sysconfig->tries; 568 } 569 570 if (sysconfig->timeout_ms && !(channel->optmask & ARES_OPT_TIMEOUTMS)) { 571 channel->timeout = sysconfig->timeout_ms; 572 } 573 574 if (!(channel->optmask & (ARES_OPT_ROTATE | ARES_OPT_NOROTATE))) { 575 channel->rotate = sysconfig->rotate; 576 } 577 578 if (sysconfig->usevc) { 579 channel->flags |= ARES_FLAG_USEVC; 580 } 581 582 return ARES_SUCCESS; 583 } 584 585 ares_status_t ares_init_by_sysconfig(ares_channel_t *channel) 586 { 587 ares_status_t status; 588 ares_sysconfig_t sysconfig; 589 590 memset(&sysconfig, 0, sizeof(sysconfig)); 591 sysconfig.ndots = 1; /* Default value if not otherwise set */ 592 593 #if defined(USE_WINSOCK) 594 status = ares_init_sysconfig_windows(channel, &sysconfig); 595 #elif defined(__MVS__) 596 status = ares_init_sysconfig_mvs(channel, &sysconfig); 597 #elif defined(__riscos__) 598 status = ares_init_sysconfig_riscos(channel, &sysconfig); 599 #elif defined(WATT32) 600 status = ares_init_sysconfig_watt32(channel, &sysconfig); 601 #elif defined(ANDROID) || defined(__ANDROID__) 602 status = ares_init_sysconfig_android(channel, &sysconfig); 603 #elif defined(__APPLE__) 604 status = ares_init_sysconfig_macos(channel, &sysconfig); 605 #elif defined(CARES_USE_LIBRESOLV) 606 status = ares_init_sysconfig_libresolv(channel, &sysconfig); 607 #elif defined(__QNX__) 608 status = ares_init_sysconfig_qnx(channel, &sysconfig); 609 #else 610 status = ares_init_sysconfig_files(channel, &sysconfig, ARES_TRUE); 611 #endif 612 613 if (status != ARES_SUCCESS) { 614 goto done; 615 } 616 617 /* Environment is supposed to override sysconfig */ 618 status = ares_init_by_environment(&sysconfig); 619 if (status != ARES_SUCCESS) { 620 goto done; 621 } 622 623 /* Lock when applying the configuration to the channel. Don't need to 624 * lock prior to this. */ 625 626 ares_channel_lock(channel); 627 628 status = ares_sysconfig_apply(channel, &sysconfig); 629 ares_channel_unlock(channel); 630 631 if (status != ARES_SUCCESS) { 632 goto done; 633 } 634 635 done: 636 ares_sysconfig_free(&sysconfig); 637 638 return status; 639 }