quickjs-tart

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

ares_options.c (14719B)


      1 /* MIT License
      2  *
      3  * Copyright (c) 1998 Massachusetts Institute of Technology
      4  * Copyright (c) 2008 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_ARPA_INET_H
     31 #  include <arpa/inet.h>
     32 #endif
     33 
     34 #include "ares_data.h"
     35 #include "ares_inet_net_pton.h"
     36 
     37 void ares_destroy_options(struct ares_options *options)
     38 {
     39   int i;
     40 
     41   ares_free(options->servers);
     42 
     43   for (i = 0; options->domains && i < options->ndomains; i++) {
     44     ares_free(options->domains[i]);
     45   }
     46 
     47   ares_free(options->domains);
     48   ares_free(options->sortlist);
     49   ares_free(options->lookups);
     50   ares_free(options->resolvconf_path);
     51   ares_free(options->hosts_path);
     52 }
     53 
     54 static struct in_addr *ares_save_opt_servers(const ares_channel_t *channel,
     55                                              int                  *nservers)
     56 {
     57   ares_slist_node_t *snode;
     58   struct in_addr    *out =
     59     ares_malloc_zero(ares_slist_len(channel->servers) * sizeof(*out));
     60 
     61   *nservers = 0;
     62 
     63   if (out == NULL) {
     64     return NULL;
     65   }
     66 
     67   for (snode = ares_slist_node_first(channel->servers); snode != NULL;
     68        snode = ares_slist_node_next(snode)) {
     69     const ares_server_t *server = ares_slist_node_val(snode);
     70 
     71     if (server->addr.family != AF_INET) {
     72       continue;
     73     }
     74 
     75     memcpy(&out[*nservers], &server->addr.addr.addr4, sizeof(*out));
     76     (*nservers)++;
     77   }
     78 
     79   return out;
     80 }
     81 
     82 /* Save options from initialized channel */
     83 int ares_save_options(const ares_channel_t *channel,
     84                       struct ares_options *options, int *optmask)
     85 {
     86   size_t i;
     87 
     88   /* NOTE: We can't zero the whole thing out, this is because the size of the
     89    *       struct ares_options changes over time, so if someone compiled
     90    *       with an older version, their struct size might be smaller and
     91    *       we might overwrite their memory! So using the optmask is critical
     92    *       here, as they could have only set options they knew about.
     93    *
     94    *       Unfortunately ares_destroy_options() doesn't take an optmask, so
     95    *       there are a few pointers we *must* zero out otherwise we won't
     96    *       know if they were allocated or not
     97    */
     98   options->servers         = NULL;
     99   options->domains         = NULL;
    100   options->sortlist        = NULL;
    101   options->lookups         = NULL;
    102   options->resolvconf_path = NULL;
    103   options->hosts_path      = NULL;
    104 
    105   if (!ARES_CONFIG_CHECK(channel)) {
    106     return ARES_ENODATA;
    107   }
    108 
    109   if (channel->optmask & ARES_OPT_FLAGS) {
    110     options->flags = (int)channel->flags;
    111   }
    112 
    113   /* We convert ARES_OPT_TIMEOUT to ARES_OPT_TIMEOUTMS in
    114    * ares_init_by_options() */
    115   if (channel->optmask & ARES_OPT_TIMEOUTMS) {
    116     options->timeout = (int)channel->timeout;
    117   }
    118 
    119   if (channel->optmask & ARES_OPT_TRIES) {
    120     options->tries = (int)channel->tries;
    121   }
    122 
    123   if (channel->optmask & ARES_OPT_NDOTS) {
    124     options->ndots = (int)channel->ndots;
    125   }
    126 
    127   if (channel->optmask & ARES_OPT_MAXTIMEOUTMS) {
    128     options->maxtimeout = (int)channel->maxtimeout;
    129   }
    130 
    131   if (channel->optmask & ARES_OPT_UDP_PORT) {
    132     options->udp_port = channel->udp_port;
    133   }
    134   if (channel->optmask & ARES_OPT_TCP_PORT) {
    135     options->tcp_port = channel->tcp_port;
    136   }
    137 
    138   if (channel->optmask & ARES_OPT_SOCK_STATE_CB) {
    139     options->sock_state_cb      = channel->sock_state_cb;
    140     options->sock_state_cb_data = channel->sock_state_cb_data;
    141   }
    142 
    143   if (channel->optmask & ARES_OPT_SERVERS) {
    144     options->servers = ares_save_opt_servers(channel, &options->nservers);
    145     if (options->servers == NULL) {
    146       return ARES_ENOMEM;
    147     }
    148   }
    149 
    150   if (channel->optmask & ARES_OPT_DOMAINS) {
    151     options->domains = NULL;
    152     if (channel->ndomains) {
    153       options->domains = ares_malloc(channel->ndomains * sizeof(char *));
    154       if (!options->domains) {
    155         return ARES_ENOMEM;
    156       }
    157 
    158       for (i = 0; i < channel->ndomains; i++) {
    159         options->domains[i] = ares_strdup(channel->domains[i]);
    160         if (!options->domains[i]) {
    161           options->ndomains = (int)i;
    162           return ARES_ENOMEM;
    163         }
    164       }
    165     }
    166     options->ndomains = (int)channel->ndomains;
    167   }
    168 
    169   if (channel->optmask & ARES_OPT_LOOKUPS) {
    170     options->lookups = ares_strdup(channel->lookups);
    171     if (!options->lookups && channel->lookups) {
    172       return ARES_ENOMEM;
    173     }
    174   }
    175 
    176   if (channel->optmask & ARES_OPT_SORTLIST) {
    177     options->sortlist = NULL;
    178     if (channel->nsort) {
    179       options->sortlist = ares_malloc(channel->nsort * sizeof(struct apattern));
    180       if (!options->sortlist) {
    181         return ARES_ENOMEM;
    182       }
    183       for (i = 0; i < channel->nsort; i++) {
    184         options->sortlist[i] = channel->sortlist[i];
    185       }
    186     }
    187     options->nsort = (int)channel->nsort;
    188   }
    189 
    190   if (channel->optmask & ARES_OPT_RESOLVCONF) {
    191     options->resolvconf_path = ares_strdup(channel->resolvconf_path);
    192     if (!options->resolvconf_path) {
    193       return ARES_ENOMEM;
    194     }
    195   }
    196 
    197   if (channel->optmask & ARES_OPT_HOSTS_FILE) {
    198     options->hosts_path = ares_strdup(channel->hosts_path);
    199     if (!options->hosts_path) {
    200       return ARES_ENOMEM;
    201     }
    202   }
    203 
    204   if (channel->optmask & ARES_OPT_SOCK_SNDBUF &&
    205       channel->socket_send_buffer_size > 0) {
    206     options->socket_send_buffer_size = channel->socket_send_buffer_size;
    207   }
    208 
    209   if (channel->optmask & ARES_OPT_SOCK_RCVBUF &&
    210       channel->socket_receive_buffer_size > 0) {
    211     options->socket_receive_buffer_size = channel->socket_receive_buffer_size;
    212   }
    213 
    214   if (channel->optmask & ARES_OPT_EDNSPSZ) {
    215     options->ednspsz = (int)channel->ednspsz;
    216   }
    217 
    218   if (channel->optmask & ARES_OPT_UDP_MAX_QUERIES) {
    219     options->udp_max_queries = (int)channel->udp_max_queries;
    220   }
    221 
    222   if (channel->optmask & ARES_OPT_QUERY_CACHE) {
    223     options->qcache_max_ttl = channel->qcache_max_ttl;
    224   }
    225 
    226   if (channel->optmask & ARES_OPT_EVENT_THREAD) {
    227     options->evsys = channel->evsys;
    228   }
    229 
    230   /* Set options for server failover behavior */
    231   if (channel->optmask & ARES_OPT_SERVER_FAILOVER) {
    232     options->server_failover_opts.retry_chance = channel->server_retry_chance;
    233     options->server_failover_opts.retry_delay  = channel->server_retry_delay;
    234   }
    235 
    236   *optmask = (int)channel->optmask;
    237 
    238   return ARES_SUCCESS;
    239 }
    240 
    241 static ares_status_t ares_init_options_servers(ares_channel_t       *channel,
    242                                                const struct in_addr *servers,
    243                                                size_t                nservers)
    244 {
    245   ares_llist_t *slist = NULL;
    246   ares_status_t status;
    247 
    248   status = ares_in_addr_to_sconfig_llist(servers, nservers, &slist);
    249   if (status != ARES_SUCCESS) {
    250     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    251   }
    252 
    253   status = ares_servers_update(channel, slist, ARES_TRUE);
    254 
    255   ares_llist_destroy(slist);
    256 
    257   return status;
    258 }
    259 
    260 ares_status_t ares_init_by_options(ares_channel_t            *channel,
    261                                    const struct ares_options *options,
    262                                    int                        optmask)
    263 {
    264   size_t i;
    265 
    266   if (channel == NULL) {
    267     return ARES_ENODATA; /* LCOV_EXCL_LINE: DefensiveCoding */
    268   }
    269 
    270   if (options == NULL) {
    271     if (optmask != 0) {
    272       return ARES_ENODATA; /* LCOV_EXCL_LINE: DefensiveCoding */
    273     }
    274     return ARES_SUCCESS;
    275   }
    276 
    277   /* Easy stuff. */
    278 
    279   /* Event Thread requires threading support and is incompatible with socket
    280    * state callbacks */
    281   if (optmask & ARES_OPT_EVENT_THREAD) {
    282     if (!ares_threadsafety()) {
    283       return ARES_ENOTIMP;
    284     }
    285     if (optmask & ARES_OPT_SOCK_STATE_CB) {
    286       return ARES_EFORMERR;
    287     }
    288     channel->evsys = options->evsys;
    289   }
    290 
    291   if (optmask & ARES_OPT_FLAGS) {
    292     channel->flags = (unsigned int)options->flags;
    293   }
    294 
    295   if (optmask & ARES_OPT_TIMEOUTMS) {
    296     /* Apparently some integrations were passing -1 to tell c-ares to use
    297      * the default instead of just omitting the optmask */
    298     if (options->timeout <= 0) {
    299       optmask &= ~(ARES_OPT_TIMEOUTMS);
    300     } else {
    301       channel->timeout = (unsigned int)options->timeout;
    302     }
    303   } else if (optmask & ARES_OPT_TIMEOUT) {
    304     optmask &= ~(ARES_OPT_TIMEOUT);
    305     /* Apparently some integrations were passing -1 to tell c-ares to use
    306      * the default instead of just omitting the optmask */
    307     if (options->timeout > 0) {
    308       /* Convert to milliseconds */
    309       optmask          |= ARES_OPT_TIMEOUTMS;
    310       channel->timeout  = (unsigned int)options->timeout * 1000;
    311     }
    312   }
    313 
    314   if (optmask & ARES_OPT_TRIES) {
    315     if (options->tries <= 0) {
    316       optmask &= ~(ARES_OPT_TRIES);
    317     } else {
    318       channel->tries = (size_t)options->tries;
    319     }
    320   }
    321 
    322   if (optmask & ARES_OPT_NDOTS) {
    323     if (options->ndots < 0) {
    324       optmask &= ~(ARES_OPT_NDOTS);
    325     } else {
    326       channel->ndots = (size_t)options->ndots;
    327     }
    328   }
    329 
    330   if (optmask & ARES_OPT_MAXTIMEOUTMS) {
    331     if (options->maxtimeout <= 0) {
    332       optmask &= ~(ARES_OPT_MAXTIMEOUTMS);
    333     } else {
    334       channel->maxtimeout = (size_t)options->maxtimeout;
    335     }
    336   }
    337 
    338   if (optmask & ARES_OPT_ROTATE) {
    339     channel->rotate = ARES_TRUE;
    340   }
    341 
    342   if (optmask & ARES_OPT_NOROTATE) {
    343     channel->rotate = ARES_FALSE;
    344   }
    345 
    346   if (optmask & ARES_OPT_UDP_PORT) {
    347     channel->udp_port = options->udp_port;
    348   }
    349 
    350   if (optmask & ARES_OPT_TCP_PORT) {
    351     channel->tcp_port = options->tcp_port;
    352   }
    353 
    354   if (optmask & ARES_OPT_SOCK_STATE_CB) {
    355     channel->sock_state_cb      = options->sock_state_cb;
    356     channel->sock_state_cb_data = options->sock_state_cb_data;
    357   }
    358 
    359   if (optmask & ARES_OPT_SOCK_SNDBUF) {
    360     if (options->socket_send_buffer_size <= 0) {
    361       optmask &= ~(ARES_OPT_SOCK_SNDBUF);
    362     } else {
    363       channel->socket_send_buffer_size = options->socket_send_buffer_size;
    364     }
    365   }
    366 
    367   if (optmask & ARES_OPT_SOCK_RCVBUF) {
    368     if (options->socket_receive_buffer_size <= 0) {
    369       optmask &= ~(ARES_OPT_SOCK_RCVBUF);
    370     } else {
    371       channel->socket_receive_buffer_size = options->socket_receive_buffer_size;
    372     }
    373   }
    374 
    375   if (optmask & ARES_OPT_EDNSPSZ) {
    376     if (options->ednspsz <= 0) {
    377       optmask &= ~(ARES_OPT_EDNSPSZ);
    378     } else {
    379       channel->ednspsz = (size_t)options->ednspsz;
    380     }
    381   }
    382 
    383   /* Copy the domains, if given.  Keep channel->ndomains consistent so
    384    * we can clean up in case of error.
    385    */
    386   if (optmask & ARES_OPT_DOMAINS && options->ndomains > 0) {
    387     channel->domains =
    388       ares_malloc_zero((size_t)options->ndomains * sizeof(char *));
    389     if (!channel->domains) {
    390       return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    391     }
    392     channel->ndomains = (size_t)options->ndomains;
    393     for (i = 0; i < (size_t)options->ndomains; i++) {
    394       channel->domains[i] = ares_strdup(options->domains[i]);
    395       if (!channel->domains[i]) {
    396         return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    397       }
    398     }
    399   }
    400 
    401   /* Set lookups, if given. */
    402   if (optmask & ARES_OPT_LOOKUPS) {
    403     if (options->lookups == NULL) {
    404       optmask &= ~(ARES_OPT_LOOKUPS);
    405     } else {
    406       channel->lookups = ares_strdup(options->lookups);
    407       if (!channel->lookups) {
    408         return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    409       }
    410     }
    411   }
    412 
    413   /* copy sortlist */
    414   if (optmask & ARES_OPT_SORTLIST && options->nsort > 0) {
    415     channel->nsort = (size_t)options->nsort;
    416     channel->sortlist =
    417       ares_malloc((size_t)options->nsort * sizeof(struct apattern));
    418     if (!channel->sortlist) {
    419       return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    420     }
    421     for (i = 0; i < (size_t)options->nsort; i++) {
    422       channel->sortlist[i] = options->sortlist[i];
    423     }
    424   }
    425 
    426   /* Set path for resolv.conf file, if given. */
    427   if (optmask & ARES_OPT_RESOLVCONF) {
    428     if (options->resolvconf_path == NULL) {
    429       optmask &= ~(ARES_OPT_RESOLVCONF);
    430     } else {
    431       channel->resolvconf_path = ares_strdup(options->resolvconf_path);
    432       if (channel->resolvconf_path == NULL) {
    433         return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    434       }
    435     }
    436   }
    437 
    438   /* Set path for hosts file, if given. */
    439   if (optmask & ARES_OPT_HOSTS_FILE) {
    440     if (options->hosts_path == NULL) {
    441       optmask &= ~(ARES_OPT_HOSTS_FILE);
    442     } else {
    443       channel->hosts_path = ares_strdup(options->hosts_path);
    444       if (channel->hosts_path == NULL) {
    445         return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    446       }
    447     }
    448   }
    449 
    450   if (optmask & ARES_OPT_UDP_MAX_QUERIES) {
    451     if (options->udp_max_queries <= 0) {
    452       optmask &= ~(ARES_OPT_UDP_MAX_QUERIES);
    453     } else {
    454       channel->udp_max_queries = (size_t)options->udp_max_queries;
    455     }
    456   }
    457 
    458   /* As of c-ares 1.31.0, the Query Cache is on by default.  The only way to
    459    * disable it is to set options->qcache_max_ttl = 0 while specifying the
    460    * ARES_OPT_QUERY_CACHE which will actually disable it completely. */
    461   if (optmask & ARES_OPT_QUERY_CACHE) {
    462     /* qcache_max_ttl is unsigned unlike the others */
    463     channel->qcache_max_ttl = options->qcache_max_ttl;
    464   } else {
    465     optmask                 |= ARES_OPT_QUERY_CACHE;
    466     channel->qcache_max_ttl  = 3600;
    467   }
    468 
    469   /* Initialize the ipv4 servers if provided */
    470   if (optmask & ARES_OPT_SERVERS) {
    471     if (options->nservers <= 0) {
    472       optmask &= ~(ARES_OPT_SERVERS);
    473     } else {
    474       ares_status_t status;
    475       status = ares_init_options_servers(channel, options->servers,
    476                                          (size_t)options->nservers);
    477       if (status != ARES_SUCCESS) {
    478         return status; /* LCOV_EXCL_LINE: OutOfMemory */
    479       }
    480     }
    481   }
    482 
    483   /* Set fields for server failover behavior */
    484   if (optmask & ARES_OPT_SERVER_FAILOVER) {
    485     channel->server_retry_chance = options->server_failover_opts.retry_chance;
    486     channel->server_retry_delay  = options->server_failover_opts.retry_delay;
    487   }
    488 
    489   channel->optmask = (unsigned int)optmask;
    490 
    491   return ARES_SUCCESS;
    492 }