Coverage Report

Created: 2025-05-09 06:05

/src/c-ares/src/lib/ares_init.c
Line
Count
Source (jump to first uncovered line)
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_private.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_inet_net_pton.h"
65
#include "event/ares_event.h"
66
67
int ares_init(ares_channel_t **channelptr)
68
4.32k
{
69
4.32k
  return ares_init_options(channelptr, NULL, 0);
70
4.32k
}
71
72
static int ares_query_timeout_cmp_cb(const void *arg1, const void *arg2)
73
0
{
74
0
  const ares_query_t *q1 = arg1;
75
0
  const ares_query_t *q2 = arg2;
76
77
0
  if (q1->timeout.sec > q2->timeout.sec) {
78
0
    return 1;
79
0
  }
80
0
  if (q1->timeout.sec < q2->timeout.sec) {
81
0
    return -1;
82
0
  }
83
84
0
  if (q1->timeout.usec > q2->timeout.usec) {
85
0
    return 1;
86
0
  }
87
0
  if (q1->timeout.usec < q2->timeout.usec) {
88
0
    return -1;
89
0
  }
90
91
0
  return 0;
92
0
}
93
94
static int server_sort_cb(const void *data1, const void *data2)
95
109k
{
96
109k
  const ares_server_t *s1 = data1;
97
109k
  const ares_server_t *s2 = data2;
98
99
109k
  if (s1->consec_failures < s2->consec_failures) {
100
0
    return -1;
101
0
  }
102
109k
  if (s1->consec_failures > s2->consec_failures) {
103
0
    return 1;
104
0
  }
105
109k
  if (s1->idx < s2->idx) {
106
0
    return -1;
107
0
  }
108
109k
  if (s1->idx > s2->idx) {
109
108k
    return 1;
110
108k
  }
111
997
  return 0;
112
109k
}
113
114
static void server_destroy_cb(void *data)
115
1.08k
{
116
1.08k
  if (data == NULL) {
117
0
    return; /* LCOV_EXCL_LINE: DefensiveCoding */
118
0
  }
119
1.08k
  ares_destroy_server(data);
120
1.08k
}
121
122
static ares_status_t init_by_defaults(ares_channel_t *channel)
123
4.32k
{
124
4.32k
  char         *hostname = NULL;
125
4.32k
  ares_status_t rc       = ARES_SUCCESS;
126
4.32k
#ifdef HAVE_GETHOSTNAME
127
4.32k
  const char *dot;
128
4.32k
#endif
129
4.32k
  struct ares_addr addr;
130
4.32k
  ares_llist_t    *sconfig = NULL;
131
132
  /* Enable EDNS by default */
133
4.32k
  if (!(channel->optmask & ARES_OPT_FLAGS)) {
134
4.32k
    channel->flags = ARES_FLAG_EDNS;
135
4.32k
  }
136
4.32k
  if (channel->ednspsz == 0) {
137
4.32k
    channel->ednspsz = EDNSPACKETSZ;
138
4.32k
  }
139
140
4.32k
  if (channel->timeout == 0) {
141
4.32k
    channel->timeout = DEFAULT_TIMEOUT;
142
4.32k
  }
143
144
4.32k
  if (channel->tries == 0) {
145
4.32k
    channel->tries = DEFAULT_TRIES;
146
4.32k
  }
147
148
4.32k
  if (ares_slist_len(channel->servers) == 0) {
149
    /* Add a default local named server to the channel unless configured not
150
     * to (in which case return an error).
151
     */
152
0
    if (channel->flags & ARES_FLAG_NO_DFLT_SVR) {
153
0
      rc = ARES_ENOSERVER;
154
0
      goto error;
155
0
    }
156
157
0
    addr.family            = AF_INET;
158
0
    addr.addr.addr4.s_addr = htonl(INADDR_LOOPBACK);
159
160
0
    rc = ares_sconfig_append(channel, &sconfig, &addr, 0, 0, NULL);
161
0
    if (rc != ARES_SUCCESS) {
162
0
      goto error; /* LCOV_EXCL_LINE: OutOfMemory */
163
0
    }
164
165
0
    rc = ares_servers_update(channel, sconfig, ARES_FALSE);
166
0
    ares_llist_destroy(sconfig);
167
168
0
    if (rc != ARES_SUCCESS) {
169
0
      goto error;
170
0
    }
171
0
  }
172
173
4.32k
  if (channel->ndomains == 0) {
174
    /* Derive a default domain search list from the kernel hostname,
175
     * or set it to empty if the hostname isn't helpful.
176
     */
177
#ifndef HAVE_GETHOSTNAME
178
    channel->ndomains = 0; /* default to none */
179
#else
180
0
    size_t len        = 256;
181
0
    channel->ndomains = 0; /* default to none */
182
183
0
    hostname = ares_malloc(len);
184
0
    if (!hostname) {
185
0
      rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
186
0
      goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
187
0
    }
188
189
0
    if (gethostname(hostname, (GETHOSTNAME_TYPE_ARG2)len) != 0) {
190
      /* Lets not treat a gethostname failure as critical, since we
191
       * are ok if gethostname doesn't even exist */
192
0
      *hostname = '\0';
193
0
    }
194
195
0
    dot = strchr(hostname, '.');
196
0
    if (dot) {
197
      /* a dot was found */
198
0
      channel->domains = ares_malloc(sizeof(char *));
199
0
      if (!channel->domains) {
200
0
        rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
201
0
        goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
202
0
      }
203
0
      channel->domains[0] = ares_strdup(dot + 1);
204
0
      if (!channel->domains[0]) {
205
0
        rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
206
0
        goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
207
0
      }
208
0
      channel->ndomains = 1;
209
0
    }
210
0
#endif
211
0
  }
212
213
4.32k
  if (channel->nsort == 0) {
214
4.32k
    channel->sortlist = NULL;
215
4.32k
  }
216
217
4.32k
  if (!channel->lookups) {
218
0
    channel->lookups = ares_strdup("fb");
219
0
    if (!channel->lookups) {
220
0
      rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
221
0
    }
222
0
  }
223
224
  /* Set default fields for server failover behavior */
225
4.32k
  if (!(channel->optmask & ARES_OPT_SERVER_FAILOVER)) {
226
4.32k
    channel->server_retry_chance = DEFAULT_SERVER_RETRY_CHANCE;
227
4.32k
    channel->server_retry_delay  = DEFAULT_SERVER_RETRY_DELAY;
228
4.32k
  }
229
230
4.32k
error:
231
4.32k
  if (hostname) {
232
0
    ares_free(hostname);
233
0
  }
234
235
4.32k
  return rc;
236
4.32k
}
237
238
int ares_init_options(ares_channel_t           **channelptr,
239
                      const struct ares_options *options, int optmask)
240
4.32k
{
241
4.32k
  ares_channel_t *channel;
242
4.32k
  ares_status_t   status = ARES_SUCCESS;
243
244
4.32k
  if (ares_library_initialized() != ARES_SUCCESS) {
245
0
    return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
246
0
  }
247
248
4.32k
  channel = ares_malloc_zero(sizeof(*channel));
249
4.32k
  if (!channel) {
250
0
    *channelptr = NULL;
251
0
    return ARES_ENOMEM;
252
0
  }
253
254
  /* We are in a good state */
255
4.32k
  channel->sys_up = ARES_TRUE;
256
257
  /* One option where zero is valid, so set default value here */
258
4.32k
  channel->ndots = 1;
259
260
4.32k
  status = ares_channel_threading_init(channel);
261
4.32k
  if (status != ARES_SUCCESS) {
262
0
    goto done;
263
0
  }
264
265
  /* Generate random key */
266
4.32k
  channel->rand_state = ares_init_rand_state();
267
4.32k
  if (channel->rand_state == NULL) {
268
0
    status = ARES_ENOMEM;
269
0
    DEBUGF(fprintf(stderr, "Error: init_id_key failed: %s\n",
270
0
                   ares_strerror(status)));
271
0
    goto done;
272
0
  }
273
274
  /* Initialize Server List */
275
4.32k
  channel->servers =
276
4.32k
    ares_slist_create(channel->rand_state, server_sort_cb, server_destroy_cb);
277
4.32k
  if (channel->servers == NULL) {
278
0
    status = ARES_ENOMEM;
279
0
    goto done;
280
0
  }
281
282
  /* Initialize our lists of queries */
283
4.32k
  channel->all_queries = ares_llist_create(NULL);
284
4.32k
  if (channel->all_queries == NULL) {
285
0
    status = ARES_ENOMEM;
286
0
    goto done;
287
0
  }
288
289
4.32k
  channel->queries_by_qid = ares_htable_szvp_create(NULL);
290
4.32k
  if (channel->queries_by_qid == NULL) {
291
0
    status = ARES_ENOMEM;
292
0
    goto done;
293
0
  }
294
295
4.32k
  channel->queries_by_timeout =
296
4.32k
    ares_slist_create(channel->rand_state, ares_query_timeout_cmp_cb, NULL);
297
4.32k
  if (channel->queries_by_timeout == NULL) {
298
0
    status = ARES_ENOMEM;
299
0
    goto done;
300
0
  }
301
302
4.32k
  channel->connnode_by_socket = ares_htable_asvp_create(NULL);
303
4.32k
  if (channel->connnode_by_socket == NULL) {
304
0
    status = ARES_ENOMEM;
305
0
    goto done;
306
0
  }
307
308
  /* Initialize configuration by each of the four sources, from highest
309
   * precedence to lowest.
310
   */
311
312
4.32k
  status = ares_init_by_options(channel, options, optmask);
313
4.32k
  if (status != ARES_SUCCESS) {
314
0
    DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n",
315
0
                   ares_strerror(status)));
316
    /* If we fail to apply user-specified options, fail the whole init process
317
     */
318
0
    goto done;
319
0
  }
320
321
  /* Go ahead and let it initialize the query cache even if the ttl is 0 and
322
   * completely unused.  This reduces the number of different code paths that
323
   * might be followed even if there is a minor performance hit. */
324
4.32k
  status = ares_qcache_create(channel->rand_state, channel->qcache_max_ttl,
325
4.32k
                              &channel->qcache);
326
4.32k
  if (status != ARES_SUCCESS) {
327
0
    goto done; /* LCOV_EXCL_LINE: OutOfMemory */
328
0
  }
329
330
4.32k
  if (status == ARES_SUCCESS) {
331
4.32k
    status = ares_init_by_sysconfig(channel);
332
4.32k
    if (status != ARES_SUCCESS) {
333
0
      DEBUGF(fprintf(stderr, "Error: init_by_sysconfig failed: %s\n",
334
0
                     ares_strerror(status)));
335
0
    }
336
4.32k
  }
337
338
  /*
339
   * No matter what failed or succeeded, seed defaults to provide
340
   * useful behavior for things that we missed.
341
   */
342
4.32k
  status = init_by_defaults(channel);
343
4.32k
  if (status != ARES_SUCCESS) {
344
0
    DEBUGF(fprintf(stderr, "Error: init_by_defaults failed: %s\n",
345
0
                   ares_strerror(status)));
346
0
    goto done;
347
0
  }
348
349
4.32k
  ares_set_socket_functions_def(channel);
350
351
  /* Initialize the event thread */
352
4.32k
  if (channel->optmask & ARES_OPT_EVENT_THREAD) {
353
0
    ares_event_thread_t *e = NULL;
354
355
0
    status = ares_event_thread_init(channel);
356
0
    if (status != ARES_SUCCESS) {
357
0
      goto done; /* LCOV_EXCL_LINE: UntestablePath */
358
0
    }
359
360
    /* Initialize monitor for configuration changes.  In some rare cases,
361
     * ARES_ENOTIMP may occur (OpenWatcom), ignore this. */
362
0
    e      = channel->sock_state_cb_data;
363
0
    status = ares_event_configchg_init(&e->configchg, e);
364
0
    if (status != ARES_SUCCESS && status != ARES_ENOTIMP) {
365
0
      goto done; /* LCOV_EXCL_LINE: UntestablePath */
366
0
    }
367
0
    status = ARES_SUCCESS;
368
0
  }
369
370
4.32k
done:
371
4.32k
  if (status != ARES_SUCCESS) {
372
0
    ares_destroy(channel);
373
0
    return (int)status;
374
0
  }
375
376
4.32k
  *channelptr = channel;
377
4.32k
  return ARES_SUCCESS;
378
4.32k
}
379
380
static void *ares_reinit_thread(void *arg)
381
0
{
382
0
  ares_channel_t *channel = arg;
383
0
  ares_status_t   status;
384
385
  /* ares_init_by_sysconfig() will lock when applying the config, but not
386
   * when retrieving. */
387
0
  status = ares_init_by_sysconfig(channel);
388
0
  if (status != ARES_SUCCESS) {
389
0
    DEBUGF(fprintf(stderr, "Error: init_by_sysconfig failed: %s\n",
390
0
                   ares_strerror(status)));
391
0
  }
392
393
0
  ares_channel_lock(channel);
394
395
  /* Flush cached queries on reinit */
396
0
  if (status == ARES_SUCCESS && channel->qcache) {
397
0
    ares_qcache_flush(channel->qcache);
398
0
  }
399
400
0
  channel->reinit_pending = ARES_FALSE;
401
0
  ares_channel_unlock(channel);
402
403
0
  return NULL;
404
0
}
405
406
ares_status_t ares_reinit(ares_channel_t *channel)
407
0
{
408
0
  ares_status_t status = ARES_SUCCESS;
409
410
0
  if (channel == NULL) {
411
0
    return ARES_EFORMERR;
412
0
  }
413
414
0
  ares_channel_lock(channel);
415
416
  /* If a reinit is already in process, lets not do it again. Or if we are
417
   * shutting down, skip. */
418
0
  if (!channel->sys_up || channel->reinit_pending) {
419
0
    ares_channel_unlock(channel);
420
0
    return ARES_SUCCESS;
421
0
  }
422
0
  channel->reinit_pending = ARES_TRUE;
423
0
  ares_channel_unlock(channel);
424
425
0
  if (ares_threadsafety()) {
426
    /* clean up the prior reinit process's thread.  We know the thread isn't
427
     * running since reinit_pending was false */
428
0
    if (channel->reinit_thread != NULL) {
429
0
      void *rv;
430
0
      ares_thread_join(channel->reinit_thread, &rv);
431
0
      channel->reinit_thread = NULL;
432
0
    }
433
434
    /* Spawn a new thread */
435
0
    status =
436
0
      ares_thread_create(&channel->reinit_thread, ares_reinit_thread, channel);
437
0
    if (status != ARES_SUCCESS) {
438
      /* LCOV_EXCL_START: UntestablePath */
439
0
      ares_channel_lock(channel);
440
0
      channel->reinit_pending = ARES_FALSE;
441
0
      ares_channel_unlock(channel);
442
      /* LCOV_EXCL_STOP */
443
0
    }
444
0
  } else {
445
    /* Threading support not available, call directly */
446
0
    ares_reinit_thread(channel);
447
0
  }
448
449
0
  return status;
450
0
}
451
452
/* ares_dup() duplicates a channel handle with all its options and returns a
453
   new channel handle */
454
int ares_dup(ares_channel_t **dest, const ares_channel_t *src)
455
0
{
456
0
  struct ares_options opts;
457
0
  ares_status_t       rc;
458
0
  int                 optmask;
459
460
0
  if (dest == NULL || src == NULL) {
461
0
    return ARES_EFORMERR;
462
0
  }
463
464
0
  *dest = NULL; /* in case of failure return NULL explicitly */
465
466
  /* First get the options supported by the old ares_save_options() function,
467
     which is most of them */
468
0
  rc = (ares_status_t)ares_save_options(src, &opts, &optmask);
469
0
  if (rc != ARES_SUCCESS) {
470
0
    ares_destroy_options(&opts);
471
0
    goto done;
472
0
  }
473
474
  /* Then create the new channel with those options */
475
0
  rc = (ares_status_t)ares_init_options(dest, &opts, optmask);
476
477
  /* destroy the options copy to not leak any memory */
478
0
  ares_destroy_options(&opts);
479
480
0
  if (rc != ARES_SUCCESS) {
481
0
    goto done;
482
0
  }
483
484
0
  ares_channel_lock(src);
485
  /* Now clone the options that ares_save_options() doesn't support, but are
486
   * user-provided */
487
0
  (*dest)->sock_create_cb            = src->sock_create_cb;
488
0
  (*dest)->sock_create_cb_data       = src->sock_create_cb_data;
489
0
  (*dest)->sock_config_cb            = src->sock_config_cb;
490
0
  (*dest)->sock_config_cb_data       = src->sock_config_cb_data;
491
0
  memcpy(&(*dest)->sock_funcs, &(src->sock_funcs), sizeof((*dest)->sock_funcs));
492
0
  (*dest)->sock_func_cb_data         = src->sock_func_cb_data;
493
0
  (*dest)->legacy_sock_funcs         = src->legacy_sock_funcs;
494
0
  (*dest)->legacy_sock_funcs_cb_data = src->legacy_sock_funcs_cb_data;
495
0
  (*dest)->server_state_cb           = src->server_state_cb;
496
0
  (*dest)->server_state_cb_data      = src->server_state_cb_data;
497
498
0
  ares_strcpy((*dest)->local_dev_name, src->local_dev_name,
499
0
              sizeof((*dest)->local_dev_name));
500
0
  (*dest)->local_ip4 = src->local_ip4;
501
0
  memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6));
502
0
  ares_channel_unlock(src);
503
504
  /* Servers are a bit unique as ares_init_options() only allows ipv4 servers
505
   * and not a port per server, but there are other user specified ways, that
506
   * too will toggle the optmask ARES_OPT_SERVERS to let us know.  If that's
507
   * the case, pull them in.
508
   *
509
   * We don't want to clone system-configuration servers though.
510
   *
511
   * We must use the "csv" format to get things like link-local address support
512
   */
513
514
0
  if (optmask & ARES_OPT_SERVERS) {
515
0
    char *csv = ares_get_servers_csv(src);
516
0
    if (csv == NULL) {
517
      /* LCOV_EXCL_START: OutOfMemory */
518
0
      ares_destroy(*dest);
519
0
      *dest = NULL;
520
0
      rc    = ARES_ENOMEM;
521
0
      goto done;
522
      /* LCOV_EXCL_STOP */
523
0
    }
524
525
0
    rc = (ares_status_t)ares_set_servers_ports_csv(*dest, csv);
526
0
    ares_free_string(csv);
527
0
    if (rc != ARES_SUCCESS) {
528
      /* LCOV_EXCL_START: OutOfMemory */
529
0
      ares_destroy(*dest);
530
0
      *dest = NULL;
531
0
      goto done;
532
      /* LCOV_EXCL_STOP */
533
0
    }
534
0
  }
535
536
0
  rc = ARES_SUCCESS;
537
0
done:
538
0
  return (int)rc; /* everything went fine */
539
0
}
540
541
void ares_set_local_ip4(ares_channel_t *channel, unsigned int local_ip)
542
0
{
543
0
  if (channel == NULL) {
544
0
    return;
545
0
  }
546
0
  ares_channel_lock(channel);
547
0
  channel->local_ip4 = local_ip;
548
0
  ares_channel_unlock(channel);
549
0
}
550
551
/* local_ip6 should be 16 bytes in length */
552
void ares_set_local_ip6(ares_channel_t *channel, const unsigned char *local_ip6)
553
0
{
554
0
  if (channel == NULL) {
555
0
    return;
556
0
  }
557
0
  ares_channel_lock(channel);
558
0
  memcpy(&channel->local_ip6, local_ip6, sizeof(channel->local_ip6));
559
0
  ares_channel_unlock(channel);
560
0
}
561
562
/* local_dev_name should be null terminated. */
563
void ares_set_local_dev(ares_channel_t *channel, const char *local_dev_name)
564
0
{
565
0
  if (channel == NULL) {
566
0
    return;
567
0
  }
568
569
0
  ares_channel_lock(channel);
570
0
  ares_strcpy(channel->local_dev_name, local_dev_name,
571
0
              sizeof(channel->local_dev_name));
572
0
  channel->local_dev_name[sizeof(channel->local_dev_name) - 1] = 0;
573
0
  ares_channel_unlock(channel);
574
0
}
575
576
int ares_set_sortlist(ares_channel_t *channel, const char *sortstr)
577
0
{
578
0
  size_t           nsort    = 0;
579
0
  struct apattern *sortlist = NULL;
580
0
  ares_status_t    status;
581
582
0
  if (!channel) {
583
0
    return ARES_ENODATA;
584
0
  }
585
0
  ares_channel_lock(channel);
586
587
0
  status = ares_parse_sortlist(&sortlist, &nsort, sortstr);
588
0
  if (status == ARES_SUCCESS && sortlist) {
589
0
    if (channel->sortlist) {
590
0
      ares_free(channel->sortlist);
591
0
    }
592
0
    channel->sortlist = sortlist;
593
0
    channel->nsort    = nsort;
594
595
    /* Save sortlist as if it was passed in as an option */
596
0
    channel->optmask |= ARES_OPT_SORTLIST;
597
0
  }
598
0
  ares_channel_unlock(channel);
599
0
  return (int)status;
600
0
}