• 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_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