ares: Curl_resolver_wait_resolv: clear *entry first in function
[platform/upstream/curl.git] / lib / asyn-ares.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2017, 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 #ifdef HAVE_LIMITS_H
26 #include <limits.h>
27 #endif
28 #ifdef HAVE_NETINET_IN_H
29 #include <netinet/in.h>
30 #endif
31 #ifdef HAVE_NETDB_H
32 #include <netdb.h>
33 #endif
34 #ifdef HAVE_ARPA_INET_H
35 #include <arpa/inet.h>
36 #endif
37 #ifdef __VMS
38 #include <in.h>
39 #include <inet.h>
40 #endif
41
42 #ifdef HAVE_PROCESS_H
43 #include <process.h>
44 #endif
45
46 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
47 #undef in_addr_t
48 #define in_addr_t unsigned long
49 #endif
50
51 /***********************************************************************
52  * Only for ares-enabled builds
53  * And only for functions that fulfill the asynch resolver backend API
54  * as defined in asyn.h, nothing else belongs in this file!
55  **********************************************************************/
56
57 #ifdef CURLRES_ARES
58
59 #include "urldata.h"
60 #include "sendf.h"
61 #include "hostip.h"
62 #include "hash.h"
63 #include "share.h"
64 #include "strerror.h"
65 #include "url.h"
66 #include "multiif.h"
67 #include "inet_pton.h"
68 #include "connect.h"
69 #include "select.h"
70 #include "progress.h"
71
72 #  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
73      (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
74 #    define CARES_STATICLIB
75 #  endif
76 #  include <ares.h>
77 #  include <ares_version.h> /* really old c-ares didn't include this by
78                                itself */
79
80 #if ARES_VERSION >= 0x010500
81 /* c-ares 1.5.0 or later, the callback proto is modified */
82 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
83 #endif
84
85 /* The last 3 #include files should be in this order */
86 #include "curl_printf.h"
87 #include "curl_memory.h"
88 #include "memdebug.h"
89
90 struct ResolverResults {
91   int num_pending; /* number of ares_gethostbyname() requests */
92   Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */
93   int last_status;
94 };
95
96 /*
97  * Curl_resolver_global_init() - the generic low-level asynchronous name
98  * resolve API.  Called from curl_global_init() to initialize global resolver
99  * environment.  Initializes ares library.
100  */
101 int Curl_resolver_global_init(void)
102 {
103 #ifdef CARES_HAVE_ARES_LIBRARY_INIT
104   if(ares_library_init(ARES_LIB_INIT_ALL)) {
105     return CURLE_FAILED_INIT;
106   }
107 #endif
108   return CURLE_OK;
109 }
110
111 /*
112  * Curl_resolver_global_cleanup()
113  *
114  * Called from curl_global_cleanup() to destroy global resolver environment.
115  * Deinitializes ares library.
116  */
117 void Curl_resolver_global_cleanup(void)
118 {
119 #ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
120   ares_library_cleanup();
121 #endif
122 }
123
124 /*
125  * Curl_resolver_init()
126  *
127  * Called from curl_easy_init() -> Curl_open() to initialize resolver
128  * URL-state specific environment ('resolver' member of the UrlState
129  * structure).  Fills the passed pointer by the initialized ares_channel.
130  */
131 CURLcode Curl_resolver_init(void **resolver)
132 {
133   int status = ares_init((ares_channel*)resolver);
134   if(status != ARES_SUCCESS) {
135     if(status == ARES_ENOMEM)
136       return CURLE_OUT_OF_MEMORY;
137     else
138       return CURLE_FAILED_INIT;
139   }
140   return CURLE_OK;
141   /* make sure that all other returns from this function should destroy the
142      ares channel before returning error! */
143 }
144
145 /*
146  * Curl_resolver_cleanup()
147  *
148  * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
149  * URL-state specific environment ('resolver' member of the UrlState
150  * structure).  Destroys the ares channel.
151  */
152 void Curl_resolver_cleanup(void *resolver)
153 {
154   ares_destroy((ares_channel)resolver);
155 }
156
157 /*
158  * Curl_resolver_duphandle()
159  *
160  * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
161  * environment ('resolver' member of the UrlState structure).  Duplicates the
162  * 'from' ares channel and passes the resulting channel to the 'to' pointer.
163  */
164 int Curl_resolver_duphandle(void **to, void *from)
165 {
166   /* Clone the ares channel for the new handle */
167   if(ARES_SUCCESS != ares_dup((ares_channel*)to, (ares_channel)from))
168     return CURLE_FAILED_INIT;
169   return CURLE_OK;
170 }
171
172 static void destroy_async_data (struct Curl_async *async);
173
174 /*
175  * Cancel all possibly still on-going resolves for this connection.
176  */
177 void Curl_resolver_cancel(struct connectdata *conn)
178 {
179   if(conn->data && conn->data->state.resolver)
180     ares_cancel((ares_channel)conn->data->state.resolver);
181   destroy_async_data(&conn->async);
182 }
183
184 /*
185  * destroy_async_data() cleans up async resolver data.
186  */
187 static void destroy_async_data (struct Curl_async *async)
188 {
189   free(async->hostname);
190
191   if(async->os_specific) {
192     struct ResolverResults *res = (struct ResolverResults *)async->os_specific;
193     if(res) {
194       if(res->temp_ai) {
195         Curl_freeaddrinfo(res->temp_ai);
196         res->temp_ai = NULL;
197       }
198       free(res);
199     }
200     async->os_specific = NULL;
201   }
202
203   async->hostname = NULL;
204 }
205
206 /*
207  * Curl_resolver_getsock() is called when someone from the outside world
208  * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking
209  * with ares. The caller must make sure that this function is only called when
210  * we have a working ares channel.
211  *
212  * Returns: sockets-in-use-bitmap
213  */
214
215 int Curl_resolver_getsock(struct connectdata *conn,
216                           curl_socket_t *socks,
217                           int numsocks)
218
219 {
220   struct timeval maxtime;
221   struct timeval timebuf;
222   struct timeval *timeout;
223   long milli;
224   int max = ares_getsock((ares_channel)conn->data->state.resolver,
225                          (ares_socket_t *)socks, numsocks);
226
227   maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
228   maxtime.tv_usec = 0;
229
230   timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime,
231                          &timebuf);
232   milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000);
233   if(milli == 0)
234     milli += 10;
235   Curl_expire_latest(conn->data, milli);
236
237   return max;
238 }
239
240 /*
241  * waitperform()
242  *
243  * 1) Ask ares what sockets it currently plays with, then
244  * 2) wait for the timeout period to check for action on ares' sockets.
245  * 3) tell ares to act on all the sockets marked as "with action"
246  *
247  * return number of sockets it worked on
248  */
249
250 static int waitperform(struct connectdata *conn, int timeout_ms)
251 {
252   struct Curl_easy *data = conn->data;
253   int nfds;
254   int bitmask;
255   ares_socket_t socks[ARES_GETSOCK_MAXNUM];
256   struct pollfd pfd[ARES_GETSOCK_MAXNUM];
257   int i;
258   int num = 0;
259
260   bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
261                          ARES_GETSOCK_MAXNUM);
262
263   for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
264     pfd[i].events = 0;
265     pfd[i].revents = 0;
266     if(ARES_GETSOCK_READABLE(bitmask, i)) {
267       pfd[i].fd = socks[i];
268       pfd[i].events |= POLLRDNORM|POLLIN;
269     }
270     if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
271       pfd[i].fd = socks[i];
272       pfd[i].events |= POLLWRNORM|POLLOUT;
273     }
274     if(pfd[i].events != 0)
275       num++;
276     else
277       break;
278   }
279
280   if(num)
281     nfds = Curl_poll(pfd, num, timeout_ms);
282   else
283     nfds = 0;
284
285   if(!nfds)
286     /* Call ares_process() unconditonally here, even if we simply timed out
287        above, as otherwise the ares name resolve won't timeout! */
288     ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD,
289                     ARES_SOCKET_BAD);
290   else {
291     /* move through the descriptors and ask for processing on them */
292     for(i=0; i < num; i++)
293       ares_process_fd((ares_channel)data->state.resolver,
294                       pfd[i].revents & (POLLRDNORM|POLLIN)?
295                       pfd[i].fd:ARES_SOCKET_BAD,
296                       pfd[i].revents & (POLLWRNORM|POLLOUT)?
297                       pfd[i].fd:ARES_SOCKET_BAD);
298   }
299   return nfds;
300 }
301
302 /*
303  * Curl_resolver_is_resolved() is called repeatedly to check if a previous
304  * name resolve request has completed. It should also make sure to time-out if
305  * the operation seems to take too long.
306  *
307  * Returns normal CURLcode errors.
308  */
309 CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
310                                    struct Curl_dns_entry **dns)
311 {
312   struct Curl_easy *data = conn->data;
313   struct ResolverResults *res = (struct ResolverResults *)
314     conn->async.os_specific;
315   CURLcode result = CURLE_OK;
316
317   *dns = NULL;
318
319   waitperform(conn, 0);
320
321   if(res && !res->num_pending) {
322     (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
323     /* temp_ai ownership is moved to the connection, so we need not free-up
324        them */
325     res->temp_ai = NULL;
326     if(!conn->async.dns) {
327       failf(data, "Could not resolve: %s (%s)",
328             conn->async.hostname, ares_strerror(conn->async.status));
329       result = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
330         CURLE_COULDNT_RESOLVE_HOST;
331     }
332     else
333       *dns = conn->async.dns;
334
335     destroy_async_data(&conn->async);
336   }
337
338   return result;
339 }
340
341 /*
342  * Curl_resolver_wait_resolv()
343  *
344  * waits for a resolve to finish. This function should be avoided since using
345  * this risk getting the multi interface to "hang".
346  *
347  * If 'entry' is non-NULL, make it point to the resolved dns entry
348  *
349  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
350  * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
351  */
352 CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
353                                    struct Curl_dns_entry **entry)
354 {
355   CURLcode result = CURLE_OK;
356   struct Curl_easy *data = conn->data;
357   long timeout;
358   struct timeval now = Curl_tvnow();
359   struct Curl_dns_entry *temp_entry;
360
361   if(entry)
362     *entry = NULL; /* clear on entry */
363
364   timeout = Curl_timeleft(data, &now, TRUE);
365   if(timeout < 0) {
366     /* already expired! */
367     connclose(conn, "Timed out before name resolve started");
368     return CURLE_OPERATION_TIMEDOUT;
369   }
370   if(!timeout)
371     timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
372
373   /* Wait for the name resolve query to complete. */
374   while(!result) {
375     struct timeval *tvp, tv, store;
376     long timediff;
377     int itimeout;
378     int timeout_ms;
379
380     itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
381
382     store.tv_sec = itimeout/1000;
383     store.tv_usec = (itimeout%1000)*1000;
384
385     tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv);
386
387     /* use the timeout period ares returned to us above if less than one
388        second is left, otherwise just use 1000ms to make sure the progress
389        callback gets called frequent enough */
390     if(!tvp->tv_sec)
391       timeout_ms = (int)(tvp->tv_usec/1000);
392     else
393       timeout_ms = 1000;
394
395     waitperform(conn, timeout_ms);
396     result = Curl_resolver_is_resolved(conn, &temp_entry);
397
398     if(result || conn->async.done)
399       break;
400
401     if(Curl_pgrsUpdate(conn))
402       result = CURLE_ABORTED_BY_CALLBACK;
403     else {
404       struct timeval now2 = Curl_tvnow();
405       timediff = Curl_tvdiff(now2, now); /* spent time */
406       timeout -= timediff?timediff:1; /* always deduct at least 1 */
407       now = now2; /* for next loop */
408     }
409     if(timeout < 0)
410       result = CURLE_OPERATION_TIMEDOUT;
411   }
412   if(result)
413     /* failure, so we cancel the ares operation */
414     ares_cancel((ares_channel)data->state.resolver);
415
416   /* Operation complete, if the lookup was successful we now have the entry
417      in the cache. */
418   if(entry)
419     *entry = conn->async.dns;
420
421   if(result)
422     /* close the connection, since we can't return failure here without
423        cleaning up this connection properly.
424        TODO: remove this action from here, it is not a name resolver decision.
425     */
426     connclose(conn, "c-ares resolve failed");
427
428   return result;
429 }
430
431 /* Connects results to the list */
432 static void compound_results(struct ResolverResults *res,
433                              Curl_addrinfo *ai)
434 {
435   Curl_addrinfo *ai_tail;
436   if(!ai)
437     return;
438   ai_tail = ai;
439
440   while(ai_tail->ai_next)
441     ai_tail = ai_tail->ai_next;
442
443   /* Add the new results to the list of old results. */
444   ai_tail->ai_next = res->temp_ai;
445   res->temp_ai = ai;
446 }
447
448 /*
449  * ares_query_completed_cb() is the callback that ares will call when
450  * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
451  * when using ares, is completed either successfully or with failure.
452  */
453 static void query_completed_cb(void *arg,  /* (struct connectdata *) */
454                                int status,
455 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
456                                int timeouts,
457 #endif
458                                struct hostent *hostent)
459 {
460   struct connectdata *conn = (struct connectdata *)arg;
461   struct ResolverResults *res;
462
463 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
464   (void)timeouts; /* ignored */
465 #endif
466
467   if(ARES_EDESTRUCTION == status)
468     /* when this ares handle is getting destroyed, the 'arg' pointer may not
469        be valid so only defer it when we know the 'status' says its fine! */
470     return;
471
472   res = (struct ResolverResults *)conn->async.os_specific;
473   res->num_pending--;
474
475   if(CURL_ASYNC_SUCCESS == status) {
476     Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
477     if(ai) {
478       compound_results(res, ai);
479     }
480   }
481   /* A successful result overwrites any previous error */
482   if(res->last_status != ARES_SUCCESS)
483     res->last_status = status;
484 }
485
486 /*
487  * Curl_resolver_getaddrinfo() - when using ares
488  *
489  * Returns name information about the given hostname and port number. If
490  * successful, the 'hostent' is returned and the forth argument will point to
491  * memory we need to free after use. That memory *MUST* be freed with
492  * Curl_freeaddrinfo(), nothing else.
493  */
494 Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
495                                          const char *hostname,
496                                          int port,
497                                          int *waitp)
498 {
499   char *bufp;
500   struct Curl_easy *data = conn->data;
501   struct in_addr in;
502   int family = PF_INET;
503 #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
504   struct in6_addr in6;
505 #endif /* CURLRES_IPV6 */
506
507   *waitp = 0; /* default to synchronous response */
508
509   /* First check if this is an IPv4 address string */
510   if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
511     /* This is a dotted IP address 123.123.123.123-style */
512     return Curl_ip2addr(AF_INET, &in, hostname, port);
513   }
514
515 #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
516   /* Otherwise, check if this is an IPv6 address string */
517   if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0)
518     /* This must be an IPv6 address literal.  */
519     return Curl_ip2addr(AF_INET6, &in6, hostname, port);
520
521   switch(conn->ip_version) {
522   default:
523 #if ARES_VERSION >= 0x010601
524     family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
525                            c-ares versions this just falls through and defaults
526                            to PF_INET */
527     break;
528 #endif
529   case CURL_IPRESOLVE_V4:
530     family = PF_INET;
531     break;
532   case CURL_IPRESOLVE_V6:
533     family = PF_INET6;
534     break;
535   }
536 #endif /* CURLRES_IPV6 */
537
538   bufp = strdup(hostname);
539   if(bufp) {
540     struct ResolverResults *res = NULL;
541     free(conn->async.hostname);
542     conn->async.hostname = bufp;
543     conn->async.port = port;
544     conn->async.done = FALSE;   /* not done */
545     conn->async.status = 0;     /* clear */
546     conn->async.dns = NULL;     /* clear */
547     res = calloc(sizeof(struct ResolverResults), 1);
548     if(!res) {
549       free(conn->async.hostname);
550       conn->async.hostname = NULL;
551       return NULL;
552     }
553     conn->async.os_specific = res;
554
555     /* initial status - failed */
556     res->last_status = ARES_ENOTFOUND;
557 #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
558     if(family == PF_UNSPEC) {
559       if(Curl_ipv6works()) {
560         res->num_pending = 2;
561
562         /* areschannel is already setup in the Curl_open() function */
563         ares_gethostbyname((ares_channel)data->state.resolver, hostname,
564                             PF_INET, query_completed_cb, conn);
565         ares_gethostbyname((ares_channel)data->state.resolver, hostname,
566                             PF_INET6, query_completed_cb, conn);
567       }
568       else {
569         res->num_pending = 1;
570
571         /* areschannel is already setup in the Curl_open() function */
572         ares_gethostbyname((ares_channel)data->state.resolver, hostname,
573                             PF_INET, query_completed_cb, conn);
574       }
575     }
576     else
577 #endif /* CURLRES_IPV6 */
578     {
579       res->num_pending = 1;
580
581       /* areschannel is already setup in the Curl_open() function */
582       ares_gethostbyname((ares_channel)data->state.resolver, hostname, family,
583                          query_completed_cb, conn);
584     }
585
586     *waitp = 1; /* expect asynchronous response */
587   }
588   return NULL; /* no struct yet */
589 }
590
591 CURLcode Curl_set_dns_servers(struct Curl_easy *data,
592                               char *servers)
593 {
594   CURLcode result = CURLE_NOT_BUILT_IN;
595   int ares_result;
596
597   /* If server is NULL or empty, this would purge all DNS servers
598    * from ares library, which will cause any and all queries to fail.
599    * So, just return OK if none are configured and don't actually make
600    * any changes to c-ares.  This lets c-ares use it's defaults, which
601    * it gets from the OS (for instance from /etc/resolv.conf on Linux).
602    */
603   if(!(servers && servers[0]))
604     return CURLE_OK;
605
606 #if (ARES_VERSION >= 0x010704)
607   ares_result = ares_set_servers_csv(data->state.resolver, servers);
608   switch(ares_result) {
609   case ARES_SUCCESS:
610     result = CURLE_OK;
611     break;
612   case ARES_ENOMEM:
613     result = CURLE_OUT_OF_MEMORY;
614     break;
615   case ARES_ENOTINITIALIZED:
616   case ARES_ENODATA:
617   case ARES_EBADSTR:
618   default:
619     result = CURLE_BAD_FUNCTION_ARGUMENT;
620     break;
621   }
622 #else /* too old c-ares version! */
623   (void)data;
624   (void)(ares_result);
625 #endif
626   return result;
627 }
628
629 CURLcode Curl_set_dns_interface(struct Curl_easy *data,
630                                 const char *interf)
631 {
632 #if (ARES_VERSION >= 0x010704)
633   if(!interf)
634     interf = "";
635
636   ares_set_local_dev((ares_channel)data->state.resolver, interf);
637
638   return CURLE_OK;
639 #else /* c-ares version too old! */
640   (void)data;
641   (void)interf;
642   return CURLE_NOT_BUILT_IN;
643 #endif
644 }
645
646 CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
647                                 const char *local_ip4)
648 {
649 #if (ARES_VERSION >= 0x010704)
650   struct in_addr a4;
651
652   if((!local_ip4) || (local_ip4[0] == 0)) {
653     a4.s_addr = 0; /* disabled: do not bind to a specific address */
654   }
655   else {
656     if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) {
657       return CURLE_BAD_FUNCTION_ARGUMENT;
658     }
659   }
660
661   ares_set_local_ip4((ares_channel)data->state.resolver, ntohl(a4.s_addr));
662
663   return CURLE_OK;
664 #else /* c-ares version too old! */
665   (void)data;
666   (void)local_ip4;
667   return CURLE_NOT_BUILT_IN;
668 #endif
669 }
670
671 CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
672                                 const char *local_ip6)
673 {
674 #if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6)
675   unsigned char a6[INET6_ADDRSTRLEN];
676
677   if((!local_ip6) || (local_ip6[0] == 0)) {
678     /* disabled: do not bind to a specific address */
679     memset(a6, 0, sizeof(a6));
680   }
681   else {
682     if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) {
683       return CURLE_BAD_FUNCTION_ARGUMENT;
684     }
685   }
686
687   ares_set_local_ip6((ares_channel)data->state.resolver, a6);
688
689   return CURLE_OK;
690 #else /* c-ares version too old! */
691   (void)data;
692   (void)local_ip6;
693   return CURLE_NOT_BUILT_IN;
694 #endif
695 }
696 #endif /* CURLRES_ARES */