1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25#include "curl_setup.h" 26 27/*********************************************************************** 28 * Only for ares-enabled builds 29 * And only for functions that fulfill the asynch resolver backend API 30 * as defined in asyn.h, nothing else belongs in this file! 31 **********************************************************************/ 32 33#ifdef CURLRES_ARES 34 35#include <limits.h> 36#ifdef HAVE_NETINET_IN_H 37#include <netinet/in.h> 38#endif 39#ifdef HAVE_NETDB_H 40#include <netdb.h> 41#endif 42#ifdef HAVE_ARPA_INET_H 43#include <arpa/inet.h> 44#endif 45#ifdef __VMS 46#include <in.h> 47#include <inet.h> 48#endif 49 50#include "urldata.h" 51#include "sendf.h" 52#include "hostip.h" 53#include "hash.h" 54#include "share.h" 55#include "url.h" 56#include "multiif.h" 57#include "inet_pton.h" 58#include "connect.h" 59#include "select.h" 60#include "progress.h" 61#include "timediff.h" 62 63#if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ 64 defined(_WIN32) 65# define CARES_STATICLIB 66#endif 67#include <ares.h> 68#include <ares_version.h> /* really old c-ares didn't include this by 69 itself */ 70 71#if ARES_VERSION >= 0x010500 72/* c-ares 1.5.0 or later, the callback proto is modified */ 73#define HAVE_CARES_CALLBACK_TIMEOUTS 1 74#endif 75 76#if ARES_VERSION >= 0x010601 77/* IPv6 supported since 1.6.1 */ 78#define HAVE_CARES_IPV6 1 79#endif 80 81#if ARES_VERSION >= 0x010704 82#define HAVE_CARES_SERVERS_CSV 1 83#define HAVE_CARES_LOCAL_DEV 1 84#define HAVE_CARES_SET_LOCAL 1 85#endif 86 87#if ARES_VERSION >= 0x010b00 88#define HAVE_CARES_PORTS_CSV 1 89#endif 90 91#if ARES_VERSION >= 0x011000 92/* 1.16.0 or later has ares_getaddrinfo */ 93#define HAVE_CARES_GETADDRINFO 1 94#endif 95 96/* The last 3 #include files should be in this order */ 97#include "curl_printf.h" 98#include "curl_memory.h" 99#include "memdebug.h" 100 101struct thread_data { 102 int num_pending; /* number of outstanding c-ares requests */ 103 struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares 104 parts */ 105 int last_status; 106#ifndef HAVE_CARES_GETADDRINFO 107 struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */ 108#endif 109 char hostname[1]; 110}; 111 112/* How long we are willing to wait for additional parallel responses after 113 obtaining a "definitive" one. For old c-ares without getaddrinfo. 114 115 This is intended to equal the c-ares default timeout. cURL always uses that 116 default value. Unfortunately, c-ares doesn't expose its default timeout in 117 its API, but it is officially documented as 5 seconds. 118 119 See query_completed_cb() for an explanation of how this is used. 120 */ 121#define HAPPY_EYEBALLS_DNS_TIMEOUT 5000 122 123#define CARES_TIMEOUT_PER_ATTEMPT 2000 124 125/* 126 * Curl_resolver_global_init() - the generic low-level asynchronous name 127 * resolve API. Called from curl_global_init() to initialize global resolver 128 * environment. Initializes ares library. 129 */ 130int Curl_resolver_global_init(void) 131{ 132#ifdef CARES_HAVE_ARES_LIBRARY_INIT 133 if(ares_library_init(ARES_LIB_INIT_ALL)) { 134 return CURLE_FAILED_INIT; 135 } 136#endif 137 return CURLE_OK; 138} 139 140/* 141 * Curl_resolver_global_cleanup() 142 * 143 * Called from curl_global_cleanup() to destroy global resolver environment. 144 * Deinitializes ares library. 145 */ 146void Curl_resolver_global_cleanup(void) 147{ 148#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP 149 ares_library_cleanup(); 150#endif 151} 152 153 154static void sock_state_cb(void *data, ares_socket_t socket_fd, 155 int readable, int writable) 156{ 157 struct Curl_easy *easy = data; 158 if(!readable && !writable) { 159 DEBUGASSERT(easy); 160 Curl_multi_closed(easy, socket_fd); 161 } 162} 163 164/* 165 * Curl_resolver_init() 166 * 167 * Called from curl_easy_init() -> Curl_open() to initialize resolver 168 * URL-state specific environment ('resolver' member of the UrlState 169 * structure). Fills the passed pointer by the initialized ares_channel. 170 */ 171CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver) 172{ 173 int status; 174 struct ares_options options; 175 int optmask = ARES_OPT_SOCK_STATE_CB; 176 static int ares_ver = 0; 177 options.sock_state_cb = sock_state_cb; 178 options.sock_state_cb_data = easy; 179 if(ares_ver == 0) 180 ares_version(&ares_ver); 181 182 if(ares_ver < 0x011400) { /* c-ares included similar change since 1.20.0 */ 183 options.timeout = CARES_TIMEOUT_PER_ATTEMPT; 184 optmask |= ARES_OPT_TIMEOUTMS; 185 } 186 187 /* 188 if c ares < 1.20.0: curl set timeout to CARES_TIMEOUT_PER_ATTEMPT (2s) 189 190 if c-ares >= 1.20.0 it already has the timeout to 2s, curl does not need 191 to set the timeout value; 192 193 if c-ares >= 1.24.0, user can set the timeout via /etc/resolv.conf to 194 overwrite c-ares' timeout. 195 */ 196 197 status = ares_init_options((ares_channel*)resolver, &options, optmask); 198 if(status != ARES_SUCCESS) { 199 if(status == ARES_ENOMEM) 200 return CURLE_OUT_OF_MEMORY; 201 else 202 return CURLE_FAILED_INIT; 203 } 204 return CURLE_OK; 205 /* make sure that all other returns from this function should destroy the 206 ares channel before returning error! */ 207} 208 209/* 210 * Curl_resolver_cleanup() 211 * 212 * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver 213 * URL-state specific environment ('resolver' member of the UrlState 214 * structure). Destroys the ares channel. 215 */ 216void Curl_resolver_cleanup(void *resolver) 217{ 218 ares_destroy((ares_channel)resolver); 219} 220 221/* 222 * Curl_resolver_duphandle() 223 * 224 * Called from curl_easy_duphandle() to duplicate resolver URL-state specific 225 * environment ('resolver' member of the UrlState structure). Duplicates the 226 * 'from' ares channel and passes the resulting channel to the 'to' pointer. 227 */ 228CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from) 229{ 230 (void)from; 231 /* 232 * it would be better to call ares_dup instead, but right now 233 * it is not possible to set 'sock_state_cb_data' outside of 234 * ares_init_options 235 */ 236 return Curl_resolver_init(easy, to); 237} 238 239static void destroy_async_data(struct Curl_async *async); 240 241/* 242 * Cancel all possibly still on-going resolves for this connection. 243 */ 244void Curl_resolver_cancel(struct Curl_easy *data) 245{ 246 DEBUGASSERT(data); 247 if(data->state.async.resolver) 248 ares_cancel((ares_channel)data->state.async.resolver); 249 destroy_async_data(&data->state.async); 250} 251 252/* 253 * We're equivalent to Curl_resolver_cancel() for the c-ares resolver. We 254 * never block. 255 */ 256void Curl_resolver_kill(struct Curl_easy *data) 257{ 258 /* We don't need to check the resolver state because we can be called safely 259 at any time and we always do the same thing. */ 260 Curl_resolver_cancel(data); 261} 262 263/* 264 * destroy_async_data() cleans up async resolver data. 265 */ 266static void destroy_async_data(struct Curl_async *async) 267{ 268 if(async->tdata) { 269 struct thread_data *res = async->tdata; 270 if(res) { 271 if(res->temp_ai) { 272 Curl_freeaddrinfo(res->temp_ai); 273 res->temp_ai = NULL; 274 } 275 free(res); 276 } 277 async->tdata = NULL; 278 } 279} 280 281/* 282 * Curl_resolver_getsock() is called when someone from the outside world 283 * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking 284 * with ares. The caller must make sure that this function is only called when 285 * we have a working ares channel. 286 * 287 * Returns: sockets-in-use-bitmap 288 */ 289 290int Curl_resolver_getsock(struct Curl_easy *data, 291 curl_socket_t *socks) 292{ 293 struct timeval maxtime; 294 struct timeval timebuf; 295 struct timeval *timeout; 296 long milli; 297 int max = ares_getsock((ares_channel)data->state.async.resolver, 298 (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE); 299 300 maxtime.tv_sec = CURL_TIMEOUT_RESOLVE; 301 maxtime.tv_usec = 0; 302 303 timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime, 304 &timebuf); 305 milli = (long)curlx_tvtoms(timeout); 306 if(milli == 0) 307 milli += 10; 308 Curl_expire(data, milli, EXPIRE_ASYNC_NAME); 309 310 return max; 311} 312 313/* 314 * waitperform() 315 * 316 * 1) Ask ares what sockets it currently plays with, then 317 * 2) wait for the timeout period to check for action on ares' sockets. 318 * 3) tell ares to act on all the sockets marked as "with action" 319 * 320 * return number of sockets it worked on, or -1 on error 321 */ 322 323static int waitperform(struct Curl_easy *data, timediff_t timeout_ms) 324{ 325 int nfds; 326 int bitmask; 327 ares_socket_t socks[ARES_GETSOCK_MAXNUM]; 328 struct pollfd pfd[ARES_GETSOCK_MAXNUM]; 329 int i; 330 int num = 0; 331 332 bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks, 333 ARES_GETSOCK_MAXNUM); 334 335 for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) { 336 pfd[i].events = 0; 337 pfd[i].revents = 0; 338 if(ARES_GETSOCK_READABLE(bitmask, i)) { 339 pfd[i].fd = socks[i]; 340 pfd[i].events |= POLLRDNORM|POLLIN; 341 } 342 if(ARES_GETSOCK_WRITABLE(bitmask, i)) { 343 pfd[i].fd = socks[i]; 344 pfd[i].events |= POLLWRNORM|POLLOUT; 345 } 346 if(pfd[i].events) 347 num++; 348 else 349 break; 350 } 351 352 if(num) { 353 nfds = Curl_poll(pfd, num, timeout_ms); 354 if(nfds < 0) 355 return -1; 356 } 357 else 358 nfds = 0; 359 360 if(!nfds) 361 /* Call ares_process() unconditionally here, even if we simply timed out 362 above, as otherwise the ares name resolve won't timeout! */ 363 ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD, 364 ARES_SOCKET_BAD); 365 else { 366 /* move through the descriptors and ask for processing on them */ 367 for(i = 0; i < num; i++) 368 ares_process_fd((ares_channel)data->state.async.resolver, 369 (pfd[i].revents & (POLLRDNORM|POLLIN))? 370 pfd[i].fd:ARES_SOCKET_BAD, 371 (pfd[i].revents & (POLLWRNORM|POLLOUT))? 372 pfd[i].fd:ARES_SOCKET_BAD); 373 } 374 return nfds; 375} 376 377/* 378 * Curl_resolver_is_resolved() is called repeatedly to check if a previous 379 * name resolve request has completed. It should also make sure to time-out if 380 * the operation seems to take too long. 381 * 382 * Returns normal CURLcode errors. 383 */ 384CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, 385 struct Curl_dns_entry **dns) 386{ 387 struct thread_data *res = data->state.async.tdata; 388 CURLcode result = CURLE_OK; 389 390 DEBUGASSERT(dns); 391 *dns = NULL; 392 393 if(waitperform(data, 0) < 0) 394 return CURLE_UNRECOVERABLE_POLL; 395 396#ifndef HAVE_CARES_GETADDRINFO 397 /* Now that we've checked for any last minute results above, see if there are 398 any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer 399 expires. */ 400 if(res 401 && res->num_pending 402 /* This is only set to non-zero if the timer was started. */ 403 && (res->happy_eyeballs_dns_time.tv_sec 404 || res->happy_eyeballs_dns_time.tv_usec) 405 && (Curl_timediff(Curl_now(), res->happy_eyeballs_dns_time) 406 >= HAPPY_EYEBALLS_DNS_TIMEOUT)) { 407 /* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer 408 running. */ 409 memset( 410 &res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time)); 411 412 /* Cancel the raw c-ares request, which will fire query_completed_cb() with 413 ARES_ECANCELLED synchronously for all pending responses. This will 414 leave us with res->num_pending == 0, which is perfect for the next 415 block. */ 416 ares_cancel((ares_channel)data->state.async.resolver); 417 DEBUGASSERT(res->num_pending == 0); 418 } 419#endif 420 421 if(res && !res->num_pending) { 422 (void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai); 423 /* temp_ai ownership is moved to the connection, so we need not free-up 424 them */ 425 res->temp_ai = NULL; 426 427 if(!data->state.async.dns) 428 result = Curl_resolver_error(data); 429 else 430 *dns = data->state.async.dns; 431 432 destroy_async_data(&data->state.async); 433 } 434 435 return result; 436} 437 438/* 439 * Curl_resolver_wait_resolv() 440 * 441 * Waits for a resolve to finish. This function should be avoided since using 442 * this risk getting the multi interface to "hang". 443 * 444 * 'entry' MUST be non-NULL. 445 * 446 * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, 447 * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors. 448 */ 449CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, 450 struct Curl_dns_entry **entry) 451{ 452 CURLcode result = CURLE_OK; 453 timediff_t timeout; 454 struct curltime now = Curl_now(); 455 456 DEBUGASSERT(entry); 457 *entry = NULL; /* clear on entry */ 458 459 timeout = Curl_timeleft(data, &now, TRUE); 460 if(timeout < 0) { 461 /* already expired! */ 462 connclose(data->conn, "Timed out before name resolve started"); 463 return CURLE_OPERATION_TIMEDOUT; 464 } 465 if(!timeout) 466 timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */ 467 468 /* Wait for the name resolve query to complete. */ 469 while(!result) { 470 struct timeval *tvp, tv, store; 471 int itimeout; 472 timediff_t timeout_ms; 473 474#if TIMEDIFF_T_MAX > INT_MAX 475 itimeout = (timeout > INT_MAX) ? INT_MAX : (int)timeout; 476#else 477 itimeout = (int)timeout; 478#endif 479 480 store.tv_sec = itimeout/1000; 481 store.tv_usec = (itimeout%1000)*1000; 482 483 tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv); 484 485 /* use the timeout period ares returned to us above if less than one 486 second is left, otherwise just use 1000ms to make sure the progress 487 callback gets called frequent enough */ 488 if(!tvp->tv_sec) 489 timeout_ms = (timediff_t)(tvp->tv_usec/1000); 490 else 491 timeout_ms = 1000; 492 493 if(waitperform(data, timeout_ms) < 0) 494 return CURLE_UNRECOVERABLE_POLL; 495 result = Curl_resolver_is_resolved(data, entry); 496 497 if(result || data->state.async.done) 498 break; 499 500 if(Curl_pgrsUpdate(data)) 501 result = CURLE_ABORTED_BY_CALLBACK; 502 else { 503 struct curltime now2 = Curl_now(); 504 timediff_t timediff = Curl_timediff(now2, now); /* spent time */ 505 if(timediff <= 0) 506 timeout -= 1; /* always deduct at least 1 */ 507 else if(timediff > timeout) 508 timeout = -1; 509 else 510 timeout -= timediff; 511 now = now2; /* for next loop */ 512 } 513 if(timeout < 0) 514 result = CURLE_OPERATION_TIMEDOUT; 515 } 516 if(result) 517 /* failure, so we cancel the ares operation */ 518 ares_cancel((ares_channel)data->state.async.resolver); 519 520 /* Operation complete, if the lookup was successful we now have the entry 521 in the cache. */ 522 if(entry) 523 *entry = data->state.async.dns; 524 525 if(result) 526 /* close the connection, since we can't return failure here without 527 cleaning up this connection properly. */ 528 connclose(data->conn, "c-ares resolve failed"); 529 530 return result; 531} 532 533#ifndef HAVE_CARES_GETADDRINFO 534 535/* Connects results to the list */ 536static void compound_results(struct thread_data *res, 537 struct Curl_addrinfo *ai) 538{ 539 if(!ai) 540 return; 541 542#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ 543 if(res->temp_ai && res->temp_ai->ai_family == PF_INET6) { 544 /* We have results already, put the new IPv6 entries at the head of the 545 list. */ 546 struct Curl_addrinfo *temp_ai_tail = res->temp_ai; 547 548 while(temp_ai_tail->ai_next) 549 temp_ai_tail = temp_ai_tail->ai_next; 550 551 temp_ai_tail->ai_next = ai; 552 } 553 else 554#endif /* CURLRES_IPV6 */ 555 { 556 /* Add the new results to the list of old results. */ 557 struct Curl_addrinfo *ai_tail = ai; 558 while(ai_tail->ai_next) 559 ai_tail = ai_tail->ai_next; 560 561 ai_tail->ai_next = res->temp_ai; 562 res->temp_ai = ai; 563 } 564} 565 566/* 567 * ares_query_completed_cb() is the callback that ares will call when 568 * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(), 569 * when using ares, is completed either successfully or with failure. 570 */ 571static void query_completed_cb(void *arg, /* (struct connectdata *) */ 572 int status, 573#ifdef HAVE_CARES_CALLBACK_TIMEOUTS 574 int timeouts, 575#endif 576 struct hostent *hostent) 577{ 578 struct Curl_easy *data = (struct Curl_easy *)arg; 579 struct thread_data *res; 580 581#ifdef HAVE_CARES_CALLBACK_TIMEOUTS 582 (void)timeouts; /* ignored */ 583#endif 584 585 if(ARES_EDESTRUCTION == status) 586 /* when this ares handle is getting destroyed, the 'arg' pointer may not 587 be valid so only defer it when we know the 'status' says its fine! */ 588 return; 589 590 res = data->state.async.tdata; 591 if(res) { 592 res->num_pending--; 593 594 if(CURL_ASYNC_SUCCESS == status) { 595 struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port); 596 if(ai) { 597 compound_results(res, ai); 598 } 599 } 600 /* A successful result overwrites any previous error */ 601 if(res->last_status != ARES_SUCCESS) 602 res->last_status = status; 603 604 /* If there are responses still pending, we presume they must be the 605 complementary IPv4 or IPv6 lookups that we started in parallel in 606 Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we've got a 607 "definitive" response from one of a set of parallel queries, we need to 608 think about how long we're willing to wait for more responses. */ 609 if(res->num_pending 610 /* Only these c-ares status values count as "definitive" for these 611 purposes. For example, ARES_ENODATA is what we expect when there is 612 no IPv6 entry for a domain name, and that's not a reason to get more 613 aggressive in our timeouts for the other response. Other errors are 614 either a result of bad input (which should affect all parallel 615 requests), local or network conditions, non-definitive server 616 responses, or us cancelling the request. */ 617 && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) { 618 /* Right now, there can only be up to two parallel queries, so don't 619 bother handling any other cases. */ 620 DEBUGASSERT(res->num_pending == 1); 621 622 /* It's possible that one of these parallel queries could succeed 623 quickly, but the other could always fail or timeout (when we're 624 talking to a pool of DNS servers that can only successfully resolve 625 IPv4 address, for example). 626 627 It's also possible that the other request could always just take 628 longer because it needs more time or only the second DNS server can 629 fulfill it successfully. But, to align with the philosophy of Happy 630 Eyeballs, we don't want to wait _too_ long or users will think 631 requests are slow when IPv6 lookups don't actually work (but IPv4 ones 632 do). 633 634 So, now that we have a usable answer (some IPv4 addresses, some IPv6 635 addresses, or "no such domain"), we start a timeout for the remaining 636 pending responses. Even though it is typical that this resolved 637 request came back quickly, that needn't be the case. It might be that 638 this completing request didn't get a result from the first DNS server 639 or even the first round of the whole DNS server pool. So it could 640 already be quite some time after we issued the DNS queries in the 641 first place. Without modifying c-ares, we can't know exactly where in 642 its retry cycle we are. We could guess based on how much time has 643 gone by, but it doesn't really matter. Happy Eyeballs tells us that, 644 given usable information in hand, we simply don't want to wait "too 645 much longer" after we get a result. 646 647 We simply wait an additional amount of time equal to the default 648 c-ares query timeout. That is enough time for a typical parallel 649 response to arrive without being "too long". Even on a network 650 where one of the two types of queries is failing or timing out 651 constantly, this will usually mean we wait a total of the default 652 c-ares timeout (5 seconds) plus the round trip time for the successful 653 request, which seems bearable. The downside is that c-ares might race 654 with us to issue one more retry just before we give up, but it seems 655 better to "waste" that request instead of trying to guess the perfect 656 timeout to prevent it. After all, we don't even know where in the 657 c-ares retry cycle each request is. 658 */ 659 res->happy_eyeballs_dns_time = Curl_now(); 660 Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT, 661 EXPIRE_HAPPY_EYEBALLS_DNS); 662 } 663 } 664} 665#else 666/* c-ares 1.16.0 or later */ 667 668/* 669 * ares2addr() converts an address list provided by c-ares to an internal 670 * libcurl compatible list 671 */ 672static struct Curl_addrinfo *ares2addr(struct ares_addrinfo_node *node) 673{ 674 /* traverse the ares_addrinfo_node list */ 675 struct ares_addrinfo_node *ai; 676 struct Curl_addrinfo *cafirst = NULL; 677 struct Curl_addrinfo *calast = NULL; 678 int error = 0; 679 680 for(ai = node; ai != NULL; ai = ai->ai_next) { 681 size_t ss_size; 682 struct Curl_addrinfo *ca; 683 /* ignore elements with unsupported address family, */ 684 /* settle family-specific sockaddr structure size. */ 685 if(ai->ai_family == AF_INET) 686 ss_size = sizeof(struct sockaddr_in); 687#ifdef ENABLE_IPV6 688 else if(ai->ai_family == AF_INET6) 689 ss_size = sizeof(struct sockaddr_in6); 690#endif 691 else 692 continue; 693 694 /* ignore elements without required address info */ 695 if(!ai->ai_addr || !(ai->ai_addrlen > 0)) 696 continue; 697 698 /* ignore elements with bogus address size */ 699 if((size_t)ai->ai_addrlen < ss_size) 700 continue; 701 702 ca = malloc(sizeof(struct Curl_addrinfo) + ss_size); 703 if(!ca) { 704 error = EAI_MEMORY; 705 break; 706 } 707 708 /* copy each structure member individually, member ordering, */ 709 /* size, or padding might be different for each platform. */ 710 711 ca->ai_flags = ai->ai_flags; 712 ca->ai_family = ai->ai_family; 713 ca->ai_socktype = ai->ai_socktype; 714 ca->ai_protocol = ai->ai_protocol; 715 ca->ai_addrlen = (curl_socklen_t)ss_size; 716 ca->ai_addr = NULL; 717 ca->ai_canonname = NULL; 718 ca->ai_next = NULL; 719 720 ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); 721 memcpy(ca->ai_addr, ai->ai_addr, ss_size); 722 723 /* if the return list is empty, this becomes the first element */ 724 if(!cafirst) 725 cafirst = ca; 726 727 /* add this element last in the return list */ 728 if(calast) 729 calast->ai_next = ca; 730 calast = ca; 731 } 732 733 /* if we failed, destroy the Curl_addrinfo list */ 734 if(error) { 735 Curl_freeaddrinfo(cafirst); 736 cafirst = NULL; 737 } 738 739 return cafirst; 740} 741 742static void addrinfo_cb(void *arg, int status, int timeouts, 743 struct ares_addrinfo *result) 744{ 745 struct Curl_easy *data = (struct Curl_easy *)arg; 746 struct thread_data *res = data->state.async.tdata; 747 (void)timeouts; 748 if(ARES_SUCCESS == status) { 749 res->temp_ai = ares2addr(result->nodes); 750 res->last_status = CURL_ASYNC_SUCCESS; 751 ares_freeaddrinfo(result); 752 } 753 res->num_pending--; 754} 755 756#endif 757/* 758 * Curl_resolver_getaddrinfo() - when using ares 759 * 760 * Returns name information about the given hostname and port number. If 761 * successful, the 'hostent' is returned and the fourth argument will point to 762 * memory we need to free after use. That memory *MUST* be freed with 763 * Curl_freeaddrinfo(), nothing else. 764 */ 765struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, 766 const char *hostname, 767 int port, 768 int *waitp) 769{ 770 struct thread_data *res = NULL; 771 size_t namelen = strlen(hostname); 772 *waitp = 0; /* default to synchronous response */ 773 774 res = calloc(1, sizeof(struct thread_data) + namelen); 775 if(res) { 776 strcpy(res->hostname, hostname); 777 data->state.async.hostname = res->hostname; 778 data->state.async.port = port; 779 data->state.async.done = FALSE; /* not done */ 780 data->state.async.status = 0; /* clear */ 781 data->state.async.dns = NULL; /* clear */ 782 data->state.async.tdata = res; 783 784 /* initial status - failed */ 785 res->last_status = ARES_ENOTFOUND; 786 787#ifdef HAVE_CARES_GETADDRINFO 788 { 789 struct ares_addrinfo_hints hints; 790 char service[12]; 791 int pf = PF_INET; 792 memset(&hints, 0, sizeof(hints)); 793#ifdef CURLRES_IPV6 794 if((data->conn->ip_version != CURL_IPRESOLVE_V4) && 795 Curl_ipv6works(data)) { 796 /* The stack seems to be IPv6-enabled */ 797 if(data->conn->ip_version == CURL_IPRESOLVE_V6) 798 pf = PF_INET6; 799 else 800 pf = PF_UNSPEC; 801 } 802#endif /* CURLRES_IPV6 */ 803 hints.ai_family = pf; 804 hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)? 805 SOCK_STREAM : SOCK_DGRAM; 806 /* Since the service is a numerical one, set the hint flags 807 * accordingly to save a call to getservbyname in inside C-Ares 808 */ 809 hints.ai_flags = ARES_AI_NUMERICSERV; 810 msnprintf(service, sizeof(service), "%d", port); 811 res->num_pending = 1; 812 ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname, 813 service, &hints, addrinfo_cb, data); 814 } 815#else 816 817#ifdef HAVE_CARES_IPV6 818 if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) { 819 /* The stack seems to be IPv6-enabled */ 820 res->num_pending = 2; 821 822 /* areschannel is already setup in the Curl_open() function */ 823 ares_gethostbyname((ares_channel)data->state.async.resolver, hostname, 824 PF_INET, query_completed_cb, data); 825 ares_gethostbyname((ares_channel)data->state.async.resolver, hostname, 826 PF_INET6, query_completed_cb, data); 827 } 828 else 829#endif 830 { 831 res->num_pending = 1; 832 833 /* areschannel is already setup in the Curl_open() function */ 834 ares_gethostbyname((ares_channel)data->state.async.resolver, 835 hostname, PF_INET, 836 query_completed_cb, data); 837 } 838#endif 839 *waitp = 1; /* expect asynchronous response */ 840 } 841 return NULL; /* no struct yet */ 842} 843 844CURLcode Curl_set_dns_servers(struct Curl_easy *data, 845 char *servers) 846{ 847 CURLcode result = CURLE_NOT_BUILT_IN; 848 int ares_result; 849 850 /* If server is NULL or empty, this would purge all DNS servers 851 * from ares library, which will cause any and all queries to fail. 852 * So, just return OK if none are configured and don't actually make 853 * any changes to c-ares. This lets c-ares use it's defaults, which 854 * it gets from the OS (for instance from /etc/resolv.conf on Linux). 855 */ 856 if(!(servers && servers[0])) 857 return CURLE_OK; 858 859#ifdef HAVE_CARES_SERVERS_CSV 860#ifdef HAVE_CARES_PORTS_CSV 861 ares_result = ares_set_servers_ports_csv(data->state.async.resolver, 862 servers); 863#else 864 ares_result = ares_set_servers_csv(data->state.async.resolver, servers); 865#endif 866 switch(ares_result) { 867 case ARES_SUCCESS: 868 result = CURLE_OK; 869 break; 870 case ARES_ENOMEM: 871 result = CURLE_OUT_OF_MEMORY; 872 break; 873 case ARES_ENOTINITIALIZED: 874 case ARES_ENODATA: 875 case ARES_EBADSTR: 876 default: 877 DEBUGF(infof(data, "bad servers set")); 878 result = CURLE_BAD_FUNCTION_ARGUMENT; 879 break; 880 } 881#else /* too old c-ares version! */ 882 (void)data; 883 (void)(ares_result); 884#endif 885 return result; 886} 887 888CURLcode Curl_set_dns_interface(struct Curl_easy *data, 889 const char *interf) 890{ 891#ifdef HAVE_CARES_LOCAL_DEV 892 if(!interf) 893 interf = ""; 894 895 ares_set_local_dev((ares_channel)data->state.async.resolver, interf); 896 897 return CURLE_OK; 898#else /* c-ares version too old! */ 899 (void)data; 900 (void)interf; 901 return CURLE_NOT_BUILT_IN; 902#endif 903} 904 905CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, 906 const char *local_ip4) 907{ 908#ifdef HAVE_CARES_SET_LOCAL 909 struct in_addr a4; 910 911 if((!local_ip4) || (local_ip4[0] == 0)) { 912 a4.s_addr = 0; /* disabled: do not bind to a specific address */ 913 } 914 else { 915 if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) { 916 DEBUGF(infof(data, "bad DNS IPv4 address")); 917 return CURLE_BAD_FUNCTION_ARGUMENT; 918 } 919 } 920 921 ares_set_local_ip4((ares_channel)data->state.async.resolver, 922 ntohl(a4.s_addr)); 923 924 return CURLE_OK; 925#else /* c-ares version too old! */ 926 (void)data; 927 (void)local_ip4; 928 return CURLE_NOT_BUILT_IN; 929#endif 930} 931 932CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, 933 const char *local_ip6) 934{ 935#if defined(HAVE_CARES_SET_LOCAL) && defined(ENABLE_IPV6) 936 unsigned char a6[INET6_ADDRSTRLEN]; 937 938 if((!local_ip6) || (local_ip6[0] == 0)) { 939 /* disabled: do not bind to a specific address */ 940 memset(a6, 0, sizeof(a6)); 941 } 942 else { 943 if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) { 944 DEBUGF(infof(data, "bad DNS IPv6 address")); 945 return CURLE_BAD_FUNCTION_ARGUMENT; 946 } 947 } 948 949 ares_set_local_ip6((ares_channel)data->state.async.resolver, a6); 950 951 return CURLE_OK; 952#else /* c-ares version too old! */ 953 (void)data; 954 (void)local_ip6; 955 return CURLE_NOT_BUILT_IN; 956#endif 957} 958#endif /* CURLRES_ARES */ 959