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