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