• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* MIT License
2  *
3  * Copyright (c) 1998 Massachusetts Institute of Technology
4  * Copyright (c) 2007 Daniel Stenberg
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  *
25  * SPDX-License-Identifier: MIT
26  */
27 
28 #include "ares_setup.h"
29 
30 #ifdef HAVE_SYS_PARAM_H
31 #  include <sys/param.h>
32 #endif
33 
34 #ifdef HAVE_NETINET_IN_H
35 #  include <netinet/in.h>
36 #endif
37 
38 #ifdef HAVE_NETDB_H
39 #  include <netdb.h>
40 #endif
41 
42 #ifdef HAVE_ARPA_INET_H
43 #  include <arpa/inet.h>
44 #endif
45 
46 #include "ares_nameser.h"
47 
48 #if defined(ANDROID) || defined(__ANDROID__)
49 #  include <sys/system_properties.h>
50 #  include "ares_android.h"
51 /* From the Bionic sources */
52 #  define DNS_PROP_NAME_PREFIX "net.dns"
53 #  define MAX_DNS_PROPERTIES   8
54 #endif
55 
56 #if defined(CARES_USE_LIBRESOLV)
57 #  include <resolv.h>
58 #endif
59 
60 #if defined(USE_WINSOCK) && defined(HAVE_IPHLPAPI_H)
61 #  include <iphlpapi.h>
62 #endif
63 
64 #include "ares.h"
65 #include "ares_inet_net_pton.h"
66 #include "ares_platform.h"
67 #include "ares_private.h"
68 
69 #ifdef WATT32
70 #  undef WIN32 /* Redefined in MingW/MSVC headers */
71 #endif
72 
73 
ares_init(ares_channel_t ** channelptr)74 int ares_init(ares_channel_t **channelptr)
75 {
76   return ares_init_options(channelptr, NULL, 0);
77 }
78 
ares_query_timeout_cmp_cb(const void * arg1,const void * arg2)79 static int ares_query_timeout_cmp_cb(const void *arg1, const void *arg2)
80 {
81   const struct query *q1 = arg1;
82   const struct query *q2 = arg2;
83 
84   if (q1->timeout.tv_sec > q2->timeout.tv_sec) {
85     return 1;
86   }
87   if (q1->timeout.tv_sec < q2->timeout.tv_sec) {
88     return -1;
89   }
90 
91   if (q1->timeout.tv_usec > q2->timeout.tv_usec) {
92     return 1;
93   }
94   if (q1->timeout.tv_usec < q2->timeout.tv_usec) {
95     return -1;
96   }
97 
98   return 0;
99 }
100 
server_sort_cb(const void * data1,const void * data2)101 static int server_sort_cb(const void *data1, const void *data2)
102 {
103   const struct server_state *s1 = data1;
104   const struct server_state *s2 = data2;
105 
106   if (s1->consec_failures < s2->consec_failures) {
107     return -1;
108   }
109   if (s1->consec_failures > s2->consec_failures) {
110     return 1;
111   }
112   if (s1->idx < s2->idx) {
113     return -1;
114   }
115   if (s1->idx > s2->idx) {
116     return 1;
117   }
118   return 0;
119 }
120 
server_destroy_cb(void * data)121 static void server_destroy_cb(void *data)
122 {
123   if (data == NULL) {
124     return;
125   }
126   ares__destroy_server(data);
127 }
128 
init_by_defaults(ares_channel_t * channel)129 static ares_status_t init_by_defaults(ares_channel_t *channel)
130 {
131   char         *hostname = NULL;
132   ares_status_t rc       = ARES_SUCCESS;
133 #ifdef HAVE_GETHOSTNAME
134   const char *dot;
135 #endif
136   struct ares_addr addr;
137   ares__llist_t   *sconfig = NULL;
138 
139   /* Enable EDNS by default */
140   if (!(channel->optmask & ARES_OPT_FLAGS)) {
141     channel->flags = ARES_FLAG_EDNS;
142   }
143   if (channel->ednspsz == 0) {
144     channel->ednspsz = EDNSPACKETSZ;
145   }
146 
147   if (channel->timeout == 0) {
148     channel->timeout = DEFAULT_TIMEOUT;
149   }
150 
151   if (channel->tries == 0) {
152     channel->tries = DEFAULT_TRIES;
153   }
154 
155   if (channel->ndots == 0) {
156     channel->ndots = 1;
157   }
158 
159   if (ares__slist_len(channel->servers) == 0) {
160     /* Add a default local named server to the channel unless configured not
161      * to (in which case return an error).
162      */
163     if (channel->flags & ARES_FLAG_NO_DFLT_SVR) {
164       rc = ARES_ENOSERVER;
165       goto error;
166     }
167 
168     addr.family            = AF_INET;
169     addr.addr.addr4.s_addr = htonl(INADDR_LOOPBACK);
170 
171     rc = ares__sconfig_append(&sconfig, &addr, 0, 0, NULL);
172     if (rc != ARES_SUCCESS) {
173       goto error;
174     }
175 
176     rc = ares__servers_update(channel, sconfig, ARES_FALSE);
177     ares__llist_destroy(sconfig);
178 
179     if (rc != ARES_SUCCESS) {
180       goto error;
181     }
182   }
183 
184 #if defined(USE_WINSOCK)
185 #  define toolong(x) (x == -1) && (SOCKERRNO == WSAEFAULT)
186 #elif defined(ENAMETOOLONG)
187 #  define toolong(x) \
188     (x == -1) && ((SOCKERRNO == ENAMETOOLONG) || (SOCKERRNO == EINVAL))
189 #else
190 #  define toolong(x) (x == -1) && (SOCKERRNO == EINVAL)
191 #endif
192 
193   if (channel->ndomains == 0) {
194     /* Derive a default domain search list from the kernel hostname,
195      * or set it to empty if the hostname isn't helpful.
196      */
197 #ifndef HAVE_GETHOSTNAME
198     channel->ndomains = 0; /* default to none */
199 #else
200     GETHOSTNAME_TYPE_ARG2 lenv = 64;
201     size_t                len  = 64;
202     int                   res;
203     channel->ndomains = 0; /* default to none */
204 
205     hostname = ares_malloc(len);
206     if (!hostname) {
207       rc = ARES_ENOMEM;
208       goto error;
209     }
210 
211     do {
212       res = gethostname(hostname, lenv);
213 
214       if (toolong(res)) {
215         char *p;
216         len  *= 2;
217         lenv *= 2;
218         p     = ares_realloc(hostname, len);
219         if (!p) {
220           rc = ARES_ENOMEM;
221           goto error;
222         }
223         hostname = p;
224         continue;
225       } else if (res) {
226         /* Lets not treat a gethostname failure as critical, since we
227          * are ok if gethostname doesn't even exist */
228         *hostname = '\0';
229         break;
230       }
231 
232     } while (res != 0);
233 
234     dot = strchr(hostname, '.');
235     if (dot) {
236       /* a dot was found */
237       channel->domains = ares_malloc(sizeof(char *));
238       if (!channel->domains) {
239         rc = ARES_ENOMEM;
240         goto error;
241       }
242       channel->domains[0] = ares_strdup(dot + 1);
243       if (!channel->domains[0]) {
244         rc = ARES_ENOMEM;
245         goto error;
246       }
247       channel->ndomains = 1;
248     }
249 #endif
250   }
251 
252   if (channel->nsort == 0) {
253     channel->sortlist = NULL;
254   }
255 
256   if (!channel->lookups) {
257     channel->lookups = ares_strdup("fb");
258     if (!channel->lookups) {
259       rc = ARES_ENOMEM;
260     }
261   }
262 
263 error:
264   if (rc) {
265     if (channel->domains && channel->domains[0]) {
266       ares_free(channel->domains[0]);
267     }
268     if (channel->domains) {
269       ares_free(channel->domains);
270       channel->domains = NULL;
271     }
272 
273     if (channel->lookups) {
274       ares_free(channel->lookups);
275       channel->lookups = NULL;
276     }
277 
278     if (channel->resolvconf_path) {
279       ares_free(channel->resolvconf_path);
280       channel->resolvconf_path = NULL;
281     }
282 
283     if (channel->hosts_path) {
284       ares_free(channel->hosts_path);
285       channel->hosts_path = NULL;
286     }
287   }
288 
289   if (hostname) {
290     ares_free(hostname);
291   }
292 
293   return rc;
294 }
295 
ares_init_options(ares_channel_t ** channelptr,const struct ares_options * options,int optmask)296 int ares_init_options(ares_channel_t           **channelptr,
297                       const struct ares_options *options, int optmask)
298 {
299   ares_channel_t *channel;
300   ares_status_t   status = ARES_SUCCESS;
301 
302   if (ares_library_initialized() != ARES_SUCCESS) {
303     return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
304   }
305 
306   channel = ares_malloc_zero(sizeof(*channel));
307   if (!channel) {
308     *channelptr = NULL;
309     return ARES_ENOMEM;
310   }
311 
312   status = ares__channel_threading_init(channel);
313   if (status != ARES_SUCCESS) {
314     goto done;
315   }
316 
317   /* Generate random key */
318   channel->rand_state = ares__init_rand_state();
319   if (channel->rand_state == NULL) {
320     status = ARES_ENOMEM;
321     DEBUGF(fprintf(stderr, "Error: init_id_key failed: %s\n",
322                    ares_strerror(status)));
323     goto done;
324   }
325 
326   /* Initialize Server List */
327   channel->servers =
328     ares__slist_create(channel->rand_state, server_sort_cb, server_destroy_cb);
329   if (channel->servers == NULL) {
330     status = ARES_ENOMEM;
331     goto done;
332   }
333 
334   /* Initialize our lists of queries */
335   channel->all_queries = ares__llist_create(NULL);
336   if (channel->all_queries == NULL) {
337     status = ARES_ENOMEM;
338     goto done;
339   }
340 
341   channel->queries_by_qid = ares__htable_szvp_create(NULL);
342   if (channel->queries_by_qid == NULL) {
343     status = ARES_ENOMEM;
344     goto done;
345   }
346 
347   channel->queries_by_timeout =
348     ares__slist_create(channel->rand_state, ares_query_timeout_cmp_cb, NULL);
349   if (channel->queries_by_timeout == NULL) {
350     status = ARES_ENOMEM;
351     goto done;
352   }
353 
354   channel->connnode_by_socket = ares__htable_asvp_create(NULL);
355   if (channel->connnode_by_socket == NULL) {
356     status = ARES_ENOMEM;
357     goto done;
358   }
359 
360   /* Initialize configuration by each of the four sources, from highest
361    * precedence to lowest.
362    */
363 
364   status = ares__init_by_options(channel, options, optmask);
365   if (status != ARES_SUCCESS) {
366     DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n",
367                    ares_strerror(status)));
368     /* If we fail to apply user-specified options, fail the whole init process
369      */
370     goto done;
371   }
372 
373   if (channel->qcache_max_ttl > 0) {
374     status = ares__qcache_create(channel->rand_state, channel->qcache_max_ttl,
375                                  &channel->qcache);
376     if (status != ARES_SUCCESS) {
377       goto done;
378     }
379   }
380 
381   if (status == ARES_SUCCESS) {
382     status = ares__init_by_sysconfig(channel);
383     if (status != ARES_SUCCESS) {
384       DEBUGF(fprintf(stderr, "Error: init_by_sysconfig failed: %s\n",
385                      ares_strerror(status)));
386     }
387   }
388 
389   /*
390    * No matter what failed or succeeded, seed defaults to provide
391    * useful behavior for things that we missed.
392    */
393   status = init_by_defaults(channel);
394   if (status != ARES_SUCCESS) {
395     DEBUGF(fprintf(stderr, "Error: init_by_defaults failed: %s\n",
396                    ares_strerror(status)));
397     goto done;
398   }
399 
400   /* Initialize the event thread */
401   if (channel->optmask & ARES_OPT_EVENT_THREAD) {
402     status = ares_event_thread_init(channel);
403     if (status != ARES_SUCCESS) {
404       goto done;
405     }
406   }
407 
408 done:
409   if (status != ARES_SUCCESS) {
410     ares_destroy(channel);
411     return (int)status;
412   }
413 
414   *channelptr = channel;
415   return ARES_SUCCESS;
416 }
417 
ares_reinit(ares_channel_t * channel)418 ares_status_t ares_reinit(ares_channel_t *channel)
419 {
420   ares_status_t status;
421 
422   if (channel == NULL) {
423     return ARES_EFORMERR;
424   }
425 
426   ares__channel_lock(channel);
427 
428   status = ares__init_by_sysconfig(channel);
429   if (status != ARES_SUCCESS) {
430     DEBUGF(fprintf(stderr, "Error: init_by_sysconfig failed: %s\n",
431                    ares_strerror(status)));
432   }
433 
434   /* Flush cached queries on reinit */
435   if (channel->qcache) {
436     ares__qcache_flush(channel->qcache);
437   }
438 
439   ares__channel_unlock(channel);
440 
441   return status;
442 }
443 
444 /* ares_dup() duplicates a channel handle with all its options and returns a
445    new channel handle */
ares_dup(ares_channel_t ** dest,ares_channel_t * src)446 int ares_dup(ares_channel_t **dest, ares_channel_t *src)
447 {
448   struct ares_options opts;
449   ares_status_t       rc;
450   int                 optmask;
451 
452   if (dest == NULL || src == NULL) {
453     return ARES_EFORMERR;
454   }
455 
456   *dest = NULL; /* in case of failure return NULL explicitly */
457 
458   ares__channel_lock(src);
459   /* First get the options supported by the old ares_save_options() function,
460      which is most of them */
461   rc = (ares_status_t)ares_save_options(src, &opts, &optmask);
462   if (rc != ARES_SUCCESS) {
463     ares_destroy_options(&opts);
464     goto done;
465   }
466 
467   /* Then create the new channel with those options */
468   rc = (ares_status_t)ares_init_options(dest, &opts, optmask);
469 
470   /* destroy the options copy to not leak any memory */
471   ares_destroy_options(&opts);
472 
473   if (rc != ARES_SUCCESS) {
474     goto done;
475   }
476 
477   /* Now clone the options that ares_save_options() doesn't support, but are
478    * user-provided */
479   (*dest)->sock_create_cb      = src->sock_create_cb;
480   (*dest)->sock_create_cb_data = src->sock_create_cb_data;
481   (*dest)->sock_config_cb      = src->sock_config_cb;
482   (*dest)->sock_config_cb_data = src->sock_config_cb_data;
483   (*dest)->sock_funcs          = src->sock_funcs;
484   (*dest)->sock_func_cb_data   = src->sock_func_cb_data;
485 
486   ares_strcpy((*dest)->local_dev_name, src->local_dev_name,
487               sizeof((*dest)->local_dev_name));
488   (*dest)->local_ip4 = src->local_ip4;
489   memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6));
490 
491 
492   /* Servers are a bit unique as ares_init_options() only allows ipv4 servers
493    * and not a port per server, but there are other user specified ways, that
494    * too will toggle the optmask ARES_OPT_SERVERS to let us know.  If that's
495    * the case, pull them in.
496    *
497    * We don't want to clone system-configuration servers though.
498    *
499    * We must use the "csv" format to get things like link-local address support
500    */
501 
502   if (optmask & ARES_OPT_SERVERS) {
503     char *csv = ares_get_servers_csv(src);
504     if (csv == NULL) {
505       ares_destroy(*dest);
506       *dest = NULL;
507       rc    = ARES_ENOMEM;
508       goto done;
509     }
510 
511     rc = (ares_status_t)ares_set_servers_ports_csv(*dest, csv);
512     ares_free_string(csv);
513     if (rc != ARES_SUCCESS) {
514       ares_destroy(*dest);
515       *dest = NULL;
516       goto done;
517     }
518   }
519 
520   rc = ARES_SUCCESS;
521 done:
522   ares__channel_unlock(src);
523   return (int)rc; /* everything went fine */
524 }
525 
ares_set_local_ip4(ares_channel_t * channel,unsigned int local_ip)526 void ares_set_local_ip4(ares_channel_t *channel, unsigned int local_ip)
527 {
528   if (channel == NULL) {
529     return;
530   }
531   ares__channel_lock(channel);
532   channel->local_ip4 = local_ip;
533   ares__channel_unlock(channel);
534 }
535 
536 /* local_ip6 should be 16 bytes in length */
ares_set_local_ip6(ares_channel_t * channel,const unsigned char * local_ip6)537 void ares_set_local_ip6(ares_channel_t *channel, const unsigned char *local_ip6)
538 {
539   if (channel == NULL) {
540     return;
541   }
542   ares__channel_lock(channel);
543   memcpy(&channel->local_ip6, local_ip6, sizeof(channel->local_ip6));
544   ares__channel_unlock(channel);
545 }
546 
547 /* local_dev_name should be null terminated. */
ares_set_local_dev(ares_channel_t * channel,const char * local_dev_name)548 void ares_set_local_dev(ares_channel_t *channel, const char *local_dev_name)
549 {
550   if (channel == NULL) {
551     return;
552   }
553 
554   ares__channel_lock(channel);
555   ares_strcpy(channel->local_dev_name, local_dev_name,
556               sizeof(channel->local_dev_name));
557   channel->local_dev_name[sizeof(channel->local_dev_name) - 1] = 0;
558   ares__channel_unlock(channel);
559 }
560 
ares_set_sortlist(ares_channel_t * channel,const char * sortstr)561 int ares_set_sortlist(ares_channel_t *channel, const char *sortstr)
562 {
563   size_t           nsort    = 0;
564   struct apattern *sortlist = NULL;
565   ares_status_t    status;
566 
567   if (!channel) {
568     return ARES_ENODATA;
569   }
570   ares__channel_lock(channel);
571 
572   status = ares__parse_sortlist(&sortlist, &nsort, sortstr);
573   if (status == ARES_SUCCESS && sortlist) {
574     if (channel->sortlist) {
575       ares_free(channel->sortlist);
576     }
577     channel->sortlist = sortlist;
578     channel->nsort    = nsort;
579 
580     /* Save sortlist as if it was passed in as an option */
581     channel->optmask |= ARES_OPT_SORTLIST;
582   }
583   ares__channel_unlock(channel);
584   return (int)status;
585 }
586