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