xref: /third_party/node/deps/cares/src/lib/ares_init.c (revision 1cb0ef41)
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
74int ares_init(ares_channel_t **channelptr)
75{
76  return ares_init_options(channelptr, NULL, 0);
77}
78
79static 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
101static 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
121static void server_destroy_cb(void *data)
122{
123  if (data == NULL) {
124    return;
125  }
126  ares__destroy_server(data);
127}
128
129static 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
263error:
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
296int 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
408done:
409  if (status != ARES_SUCCESS) {
410    ares_destroy(channel);
411    return (int)status;
412  }
413
414  *channelptr = channel;
415  return ARES_SUCCESS;
416}
417
418ares_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 */
446int 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;
521done:
522  ares__channel_unlock(src);
523  return (int)rc; /* everything went fine */
524}
525
526void 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 */
537void 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. */
548void 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
561int 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