quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

ares_init.c (16632B)


      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 {
     69   return ares_init_options(channelptr, NULL, 0);
     70 }
     71 
     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 
     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 
    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 
    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     channel->tries = DEFAULT_TRIES;
    146   }
    147 
    148   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     if (channel->flags & ARES_FLAG_NO_DFLT_SVR) {
    153       rc = ARES_ENOSERVER;
    154       goto error;
    155     }
    156 
    157     addr.family            = AF_INET;
    158     addr.addr.addr4.s_addr = htonl(INADDR_LOOPBACK);
    159 
    160     rc = ares_sconfig_append(channel, &sconfig, &addr, 0, 0, NULL);
    161     if (rc != ARES_SUCCESS) {
    162       goto error; /* LCOV_EXCL_LINE: OutOfMemory */
    163     }
    164 
    165     rc = ares_servers_update(channel, sconfig, ARES_FALSE);
    166     ares_llist_destroy(sconfig);
    167 
    168     if (rc != ARES_SUCCESS) {
    169       goto error;
    170     }
    171   }
    172 
    173   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     size_t len        = 256;
    181     channel->ndomains = 0; /* default to none */
    182 
    183     hostname = ares_malloc(len);
    184     if (!hostname) {
    185       rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    186       goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
    187     }
    188 
    189     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       *hostname = '\0';
    193     }
    194 
    195     dot = strchr(hostname, '.');
    196     if (dot) {
    197       /* a dot was found */
    198       channel->domains = ares_malloc(sizeof(char *));
    199       if (!channel->domains) {
    200         rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    201         goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
    202       }
    203       channel->domains[0] = ares_strdup(dot + 1);
    204       if (!channel->domains[0]) {
    205         rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    206         goto error;       /* LCOV_EXCL_LINE: OutOfMemory */
    207       }
    208       channel->ndomains = 1;
    209     }
    210 #endif
    211   }
    212 
    213   if (channel->nsort == 0) {
    214     channel->sortlist = NULL;
    215   }
    216 
    217   if (!channel->lookups) {
    218     channel->lookups = ares_strdup("fb");
    219     if (!channel->lookups) {
    220       rc = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    221     }
    222   }
    223 
    224   /* Set default fields for server failover behavior */
    225   if (!(channel->optmask & ARES_OPT_SERVER_FAILOVER)) {
    226     channel->server_retry_chance = DEFAULT_SERVER_RETRY_CHANCE;
    227     channel->server_retry_delay  = DEFAULT_SERVER_RETRY_DELAY;
    228   }
    229 
    230 error:
    231   if (hostname) {
    232     ares_free(hostname);
    233   }
    234 
    235   return rc;
    236 }
    237 
    238 int ares_init_options(ares_channel_t           **channelptr,
    239                       const struct ares_options *options, int optmask)
    240 {
    241   ares_channel_t *channel;
    242   ares_status_t   status = ARES_SUCCESS;
    243 
    244   if (ares_library_initialized() != ARES_SUCCESS) {
    245     return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
    246   }
    247 
    248   channel = ares_malloc_zero(sizeof(*channel));
    249   if (!channel) {
    250     *channelptr = NULL;
    251     return ARES_ENOMEM;
    252   }
    253 
    254   /* We are in a good state */
    255   channel->sys_up = ARES_TRUE;
    256 
    257   /* One option where zero is valid, so set default value here */
    258   channel->ndots = 1;
    259 
    260   status = ares_channel_threading_init(channel);
    261   if (status != ARES_SUCCESS) {
    262     goto done;
    263   }
    264 
    265   /* Generate random key */
    266   channel->rand_state = ares_init_rand_state();
    267   if (channel->rand_state == NULL) {
    268     status = ARES_ENOMEM;
    269     DEBUGF(fprintf(stderr, "Error: init_id_key failed: %s\n",
    270                    ares_strerror(status)));
    271     goto done;
    272   }
    273 
    274   /* Initialize Server List */
    275   channel->servers =
    276     ares_slist_create(channel->rand_state, server_sort_cb, server_destroy_cb);
    277   if (channel->servers == NULL) {
    278     status = ARES_ENOMEM;
    279     goto done;
    280   }
    281 
    282   /* Initialize our lists of queries */
    283   channel->all_queries = ares_llist_create(NULL);
    284   if (channel->all_queries == NULL) {
    285     status = ARES_ENOMEM;
    286     goto done;
    287   }
    288 
    289   channel->queries_by_qid = ares_htable_szvp_create(NULL);
    290   if (channel->queries_by_qid == NULL) {
    291     status = ARES_ENOMEM;
    292     goto done;
    293   }
    294 
    295   channel->queries_by_timeout =
    296     ares_slist_create(channel->rand_state, ares_query_timeout_cmp_cb, NULL);
    297   if (channel->queries_by_timeout == NULL) {
    298     status = ARES_ENOMEM;
    299     goto done;
    300   }
    301 
    302   channel->connnode_by_socket = ares_htable_asvp_create(NULL);
    303   if (channel->connnode_by_socket == NULL) {
    304     status = ARES_ENOMEM;
    305     goto done;
    306   }
    307 
    308   /* Initialize configuration by each of the four sources, from highest
    309    * precedence to lowest.
    310    */
    311 
    312   status = ares_init_by_options(channel, options, optmask);
    313   if (status != ARES_SUCCESS) {
    314     DEBUGF(fprintf(stderr, "Error: init_by_options failed: %s\n",
    315                    ares_strerror(status)));
    316     /* If we fail to apply user-specified options, fail the whole init process
    317      */
    318     goto done;
    319   }
    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   status = ares_qcache_create(channel->rand_state, channel->qcache_max_ttl,
    325                               &channel->qcache);
    326   if (status != ARES_SUCCESS) {
    327     goto done; /* LCOV_EXCL_LINE: OutOfMemory */
    328   }
    329 
    330   if (status == ARES_SUCCESS) {
    331     status = ares_init_by_sysconfig(channel);
    332     if (status != ARES_SUCCESS) {
    333       DEBUGF(fprintf(stderr, "Error: init_by_sysconfig failed: %s\n",
    334                      ares_strerror(status)));
    335     }
    336   }
    337 
    338   /*
    339    * No matter what failed or succeeded, seed defaults to provide
    340    * useful behavior for things that we missed.
    341    */
    342   status = init_by_defaults(channel);
    343   if (status != ARES_SUCCESS) {
    344     DEBUGF(fprintf(stderr, "Error: init_by_defaults failed: %s\n",
    345                    ares_strerror(status)));
    346     goto done;
    347   }
    348 
    349   ares_set_socket_functions_def(channel);
    350 
    351   /* Initialize the event thread */
    352   if (channel->optmask & ARES_OPT_EVENT_THREAD) {
    353     ares_event_thread_t *e = NULL;
    354 
    355     status = ares_event_thread_init(channel);
    356     if (status != ARES_SUCCESS) {
    357       goto done; /* LCOV_EXCL_LINE: UntestablePath */
    358     }
    359 
    360     /* Initialize monitor for configuration changes.  In some rare cases,
    361      * ARES_ENOTIMP may occur (OpenWatcom), ignore this. */
    362     e      = channel->sock_state_cb_data;
    363     status = ares_event_configchg_init(&e->configchg, e);
    364     if (status != ARES_SUCCESS && status != ARES_ENOTIMP) {
    365       goto done; /* LCOV_EXCL_LINE: UntestablePath */
    366     }
    367     status = ARES_SUCCESS;
    368   }
    369 
    370 done:
    371   if (status != ARES_SUCCESS) {
    372     ares_destroy(channel);
    373     return (int)status;
    374   }
    375 
    376   *channelptr = channel;
    377   return ARES_SUCCESS;
    378 }
    379 
    380 static void *ares_reinit_thread(void *arg)
    381 {
    382   ares_channel_t *channel = arg;
    383   ares_status_t   status;
    384 
    385   /* ares_init_by_sysconfig() will lock when applying the config, but not
    386    * when retrieving. */
    387   status = ares_init_by_sysconfig(channel);
    388   if (status != ARES_SUCCESS) {
    389     DEBUGF(fprintf(stderr, "Error: init_by_sysconfig failed: %s\n",
    390                    ares_strerror(status)));
    391   }
    392 
    393   ares_channel_lock(channel);
    394 
    395   /* Flush cached queries on reinit */
    396   if (status == ARES_SUCCESS && channel->qcache) {
    397     ares_qcache_flush(channel->qcache);
    398   }
    399 
    400   channel->reinit_pending = ARES_FALSE;
    401   ares_channel_unlock(channel);
    402 
    403   return NULL;
    404 }
    405 
    406 ares_status_t ares_reinit(ares_channel_t *channel)
    407 {
    408   ares_status_t status = ARES_SUCCESS;
    409 
    410   if (channel == NULL) {
    411     return ARES_EFORMERR;
    412   }
    413 
    414   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   if (!channel->sys_up || channel->reinit_pending) {
    419     ares_channel_unlock(channel);
    420     return ARES_SUCCESS;
    421   }
    422   channel->reinit_pending = ARES_TRUE;
    423   ares_channel_unlock(channel);
    424 
    425   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     if (channel->reinit_thread != NULL) {
    429       void *rv;
    430       ares_thread_join(channel->reinit_thread, &rv);
    431       channel->reinit_thread = NULL;
    432     }
    433 
    434     /* Spawn a new thread */
    435     status =
    436       ares_thread_create(&channel->reinit_thread, ares_reinit_thread, channel);
    437     if (status != ARES_SUCCESS) {
    438       /* LCOV_EXCL_START: UntestablePath */
    439       ares_channel_lock(channel);
    440       channel->reinit_pending = ARES_FALSE;
    441       ares_channel_unlock(channel);
    442       /* LCOV_EXCL_STOP */
    443     }
    444   } else {
    445     /* Threading support not available, call directly */
    446     ares_reinit_thread(channel);
    447   }
    448 
    449   return status;
    450 }
    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 {
    456   struct ares_options opts;
    457   ares_status_t       rc;
    458   int                 optmask;
    459 
    460   if (dest == NULL || src == NULL) {
    461     return ARES_EFORMERR;
    462   }
    463 
    464   *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   rc = (ares_status_t)ares_save_options(src, &opts, &optmask);
    469   if (rc != ARES_SUCCESS) {
    470     ares_destroy_options(&opts);
    471     goto done;
    472   }
    473 
    474   /* Then create the new channel with those options */
    475   rc = (ares_status_t)ares_init_options(dest, &opts, optmask);
    476 
    477   /* destroy the options copy to not leak any memory */
    478   ares_destroy_options(&opts);
    479 
    480   if (rc != ARES_SUCCESS) {
    481     goto done;
    482   }
    483 
    484   ares_channel_lock(src);
    485   /* Now clone the options that ares_save_options() doesn't support, but are
    486    * user-provided */
    487   (*dest)->sock_create_cb            = src->sock_create_cb;
    488   (*dest)->sock_create_cb_data       = src->sock_create_cb_data;
    489   (*dest)->sock_config_cb            = src->sock_config_cb;
    490   (*dest)->sock_config_cb_data       = src->sock_config_cb_data;
    491   memcpy(&(*dest)->sock_funcs, &(src->sock_funcs), sizeof((*dest)->sock_funcs));
    492   (*dest)->sock_func_cb_data         = src->sock_func_cb_data;
    493   (*dest)->legacy_sock_funcs         = src->legacy_sock_funcs;
    494   (*dest)->legacy_sock_funcs_cb_data = src->legacy_sock_funcs_cb_data;
    495   (*dest)->server_state_cb           = src->server_state_cb;
    496   (*dest)->server_state_cb_data      = src->server_state_cb_data;
    497 
    498   ares_strcpy((*dest)->local_dev_name, src->local_dev_name,
    499               sizeof((*dest)->local_dev_name));
    500   (*dest)->local_ip4 = src->local_ip4;
    501   memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6));
    502   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   if (optmask & ARES_OPT_SERVERS) {
    515     char *csv = ares_get_servers_csv(src);
    516     if (csv == NULL) {
    517       /* LCOV_EXCL_START: OutOfMemory */
    518       ares_destroy(*dest);
    519       *dest = NULL;
    520       rc    = ARES_ENOMEM;
    521       goto done;
    522       /* LCOV_EXCL_STOP */
    523     }
    524 
    525     rc = (ares_status_t)ares_set_servers_ports_csv(*dest, csv);
    526     ares_free_string(csv);
    527     if (rc != ARES_SUCCESS) {
    528       /* LCOV_EXCL_START: OutOfMemory */
    529       ares_destroy(*dest);
    530       *dest = NULL;
    531       goto done;
    532       /* LCOV_EXCL_STOP */
    533     }
    534   }
    535 
    536   rc = ARES_SUCCESS;
    537 done:
    538   return (int)rc; /* everything went fine */
    539 }
    540 
    541 void ares_set_local_ip4(ares_channel_t *channel, unsigned int local_ip)
    542 {
    543   if (channel == NULL) {
    544     return;
    545   }
    546   ares_channel_lock(channel);
    547   channel->local_ip4 = local_ip;
    548   ares_channel_unlock(channel);
    549 }
    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 {
    554   if (channel == NULL) {
    555     return;
    556   }
    557   ares_channel_lock(channel);
    558   memcpy(&channel->local_ip6, local_ip6, sizeof(channel->local_ip6));
    559   ares_channel_unlock(channel);
    560 }
    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 {
    565   if (channel == NULL) {
    566     return;
    567   }
    568 
    569   ares_channel_lock(channel);
    570   ares_strcpy(channel->local_dev_name, local_dev_name,
    571               sizeof(channel->local_dev_name));
    572   channel->local_dev_name[sizeof(channel->local_dev_name) - 1] = 0;
    573   ares_channel_unlock(channel);
    574 }
    575 
    576 int ares_set_sortlist(ares_channel_t *channel, const char *sortstr)
    577 {
    578   size_t           nsort    = 0;
    579   struct apattern *sortlist = NULL;
    580   ares_status_t    status;
    581 
    582   if (!channel) {
    583     return ARES_ENODATA;
    584   }
    585   ares_channel_lock(channel);
    586 
    587   status = ares_parse_sortlist(&sortlist, &nsort, sortstr);
    588   if (status == ARES_SUCCESS && sortlist) {
    589     if (channel->sortlist) {
    590       ares_free(channel->sortlist);
    591     }
    592     channel->sortlist = sortlist;
    593     channel->nsort    = nsort;
    594 
    595     /* Save sortlist as if it was passed in as an option */
    596     channel->optmask |= ARES_OPT_SORTLIST;
    597   }
    598   ares_channel_unlock(channel);
    599   return (int)status;
    600 }