quickjs-tart

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

ares_sysconfig.c (18132B)


      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 #if defined(ANDROID) || defined(__ANDROID__)
     47 #  include <sys/system_properties.h>
     48 #  include "ares_android.h"
     49 /* From the Bionic sources */
     50 #  define DNS_PROP_NAME_PREFIX "net.dns"
     51 #  define MAX_DNS_PROPERTIES   8
     52 #endif
     53 
     54 #if defined(CARES_USE_LIBRESOLV)
     55 #  include <resolv.h>
     56 #endif
     57 
     58 #include "ares_inet_net_pton.h"
     59 
     60 
     61 #if defined(__MVS__)
     62 static ares_status_t ares_init_sysconfig_mvs(const ares_channel_t *channel,
     63                                              ares_sysconfig_t     *sysconfig)
     64 {
     65   struct __res_state *res = 0;
     66   size_t              count4;
     67   size_t              count6;
     68   int                 i;
     69   __STATEEXTIPV6     *v6;
     70   arse__llist_t      *sconfig = NULL;
     71   ares_status_t       status;
     72 
     73   if (0 == res) {
     74     int rc = res_init();
     75     while (rc == -1 && h_errno == TRY_AGAIN) {
     76       rc = res_init();
     77     }
     78     if (rc == -1) {
     79       return ARES_ENOMEM;
     80     }
     81     res = __res();
     82   }
     83 
     84   v6 = res->__res_extIPv6;
     85   if (res->nscount > 0) {
     86     count4 = (size_t)res->nscount;
     87   }
     88 
     89   if (v6 && v6->__stat_nscount > 0) {
     90     count6 = (size_t)v6->__stat_nscount;
     91   } else {
     92     count6 = 0;
     93   }
     94 
     95   for (i = 0; i < count4; i++) {
     96     struct sockaddr_in *addr_in = &(res->nsaddr_list[i]);
     97     struct ares_addr    addr;
     98 
     99     addr.addr.addr4.s_addr = addr_in->sin_addr.s_addr;
    100     addr.family            = AF_INET;
    101 
    102     status = ares_sconfig_append(channel, &sysconfig->sconfig, &addr,
    103                                  htons(addr_in->sin_port),
    104                                  htons(addr_in->sin_port), NULL);
    105 
    106     if (status != ARES_SUCCESS) {
    107       return status;
    108     }
    109   }
    110 
    111   for (i = 0; i < count6; i++) {
    112     struct sockaddr_in6 *addr_in = &(v6->__stat_nsaddr_list[i]);
    113     struct ares_addr     addr;
    114 
    115     addr.family = AF_INET6;
    116     memcpy(&(addr.addr.addr6), &(addr_in->sin6_addr),
    117            sizeof(addr_in->sin6_addr));
    118 
    119     status = ares_sconfig_append(channel, &sysconfig->sconfig, &addr,
    120                                  htons(addr_in->sin_port),
    121                                  htons(addr_in->sin_port), NULL);
    122 
    123     if (status != ARES_SUCCESS) {
    124       return status;
    125     }
    126   }
    127 
    128   return ARES_SUCCESS;
    129 }
    130 #endif
    131 
    132 #if defined(__riscos__)
    133 static ares_status_t ares_init_sysconfig_riscos(const ares_channel_t *channel,
    134                                                 ares_sysconfig_t     *sysconfig)
    135 {
    136   char         *line;
    137   ares_status_t status = ARES_SUCCESS;
    138 
    139   /* Under RISC OS, name servers are listed in the
    140      system variable Inet$Resolvers, space separated. */
    141   line = getenv("Inet$Resolvers");
    142   if (line) {
    143     char *resolvers = ares_strdup(line);
    144     char *pos;
    145     char *space;
    146 
    147     if (!resolvers) {
    148       return ARES_ENOMEM;
    149     }
    150 
    151     pos = resolvers;
    152     do {
    153       space = strchr(pos, ' ');
    154       if (space) {
    155         *space = '\0';
    156       }
    157       status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig, pos,
    158                                            ARES_TRUE);
    159       if (status != ARES_SUCCESS) {
    160         break;
    161       }
    162       pos = space + 1;
    163     } while (space);
    164 
    165     ares_free(resolvers);
    166   }
    167 
    168   return status;
    169 }
    170 #endif
    171 
    172 #if defined(WATT32)
    173 static ares_status_t ares_init_sysconfig_watt32(const ares_channel_t *channel,
    174                                                 ares_sysconfig_t     *sysconfig)
    175 {
    176   size_t        i;
    177   ares_status_t status;
    178 
    179   sock_init();
    180 
    181   for (i = 0; def_nameservers[i]; i++) {
    182     struct ares_addr addr;
    183 
    184     addr.family            = AF_INET;
    185     addr.addr.addr4.s_addr = htonl(def_nameservers[i]);
    186 
    187     status =
    188       ares_sconfig_append(channel, &sysconfig->sconfig, &addr, 0, 0, NULL);
    189 
    190     if (status != ARES_SUCCESS) {
    191       return status;
    192     }
    193   }
    194 
    195   return ARES_SUCCESS;
    196 }
    197 #endif
    198 
    199 #if defined(ANDROID) || defined(__ANDROID__)
    200 static ares_status_t ares_init_sysconfig_android(const ares_channel_t *channel,
    201                                                  ares_sysconfig_t *sysconfig)
    202 {
    203   size_t        i;
    204   char        **dns_servers;
    205   char         *domains;
    206   size_t        num_servers;
    207   ares_status_t status = ARES_EFILE;
    208 
    209   /* Use the Android connectivity manager to get a list
    210    * of DNS servers. As of Android 8 (Oreo) net.dns#
    211    * system properties are no longer available. Google claims this
    212    * improves privacy. Apps now need the ACCESS_NETWORK_STATE
    213    * permission and must use the ConnectivityManager which
    214    * is Java only. */
    215   dns_servers = ares_get_android_server_list(MAX_DNS_PROPERTIES, &num_servers);
    216   if (dns_servers != NULL) {
    217     for (i = 0; i < num_servers; i++) {
    218       status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig,
    219                                            dns_servers[i], ARES_TRUE);
    220       if (status != ARES_SUCCESS) {
    221         return status;
    222       }
    223     }
    224     for (i = 0; i < num_servers; i++) {
    225       ares_free(dns_servers[i]);
    226     }
    227     ares_free(dns_servers);
    228   }
    229 
    230   domains            = ares_get_android_search_domains_list();
    231   sysconfig->domains = ares_strsplit(domains, ", ", &sysconfig->ndomains);
    232   ares_free(domains);
    233 
    234 #  ifdef HAVE___SYSTEM_PROPERTY_GET
    235   /* Old way using the system property still in place as
    236    * a fallback. Older android versions can still use this.
    237    * it's possible for older apps not not have added the new
    238    * permission and we want to try to avoid breaking those.
    239    *
    240    * We'll only run this if we don't have any dns servers
    241    * because this will get the same ones (if it works). */
    242   if (sysconfig->sconfig == NULL) {
    243     char propname[PROP_NAME_MAX];
    244     char propvalue[PROP_VALUE_MAX] = "";
    245     for (i = 1; i <= MAX_DNS_PROPERTIES; i++) {
    246       snprintf(propname, sizeof(propname), "%s%zu", DNS_PROP_NAME_PREFIX, i);
    247       if (__system_property_get(propname, propvalue) < 1) {
    248         break;
    249       }
    250       status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig,
    251                                            propvalue, ARES_TRUE);
    252       if (status != ARES_SUCCESS) {
    253         return status;
    254       }
    255     }
    256   }
    257 #  endif /* HAVE___SYSTEM_PROPERTY_GET */
    258 
    259   return status;
    260 }
    261 #endif
    262 
    263 #if defined(__QNX__)
    264 static ares_status_t
    265   ares_init_sysconfig_qnx(const ares_channel_t *channel,
    266                           ares_sysconfig_t     *sysconfig)
    267 {
    268   /* QNX:
    269    *   1. use confstr(_CS_RESOLVE, ...) as primary resolv.conf data, replacing
    270    *      "_" with " ".  If that is empty, then do normal /etc/resolv.conf
    271    *      processing.
    272    *   2. We want to process /etc/nsswitch.conf as normal.
    273    *   3. if confstr(_CS_DOMAIN, ...) this is the domain name.  Use this as
    274    *      preference over anything else found.
    275    */
    276   ares_buf_t    *buf                = ares_buf_create();
    277   unsigned char *data               = NULL;
    278   size_t         data_size          = 0;
    279   ares_bool_t    process_resolvconf = ARES_TRUE;
    280   ares_status_t  status             = ARES_SUCCESS;
    281 
    282   /* Prefer confstr(_CS_RESOLVE, ...) */
    283   buf = ares_buf_create();
    284   if (buf == NULL) {
    285     status = ARES_ENOMEM;
    286     goto done;
    287   }
    288 
    289   data_size = 1024;
    290   data      = ares_buf_append_start(buf, &data_size);
    291   if (data == NULL) {
    292     status = ARES_ENOMEM;
    293     goto done;
    294   }
    295 
    296   data_size = confstr(_CS_RESOLVE, (char *)data, data_size);
    297   if (data_size > 1) {
    298     /* confstr returns byte for NULL terminator, strip */
    299     data_size--;
    300 
    301     ares_buf_append_finish(buf, data_size);
    302     /* Its odd, this uses _ instead of " " between keywords, otherwise the
    303      * format is the same as resolv.conf, replace. */
    304     ares_buf_replace(buf, (const unsigned char *)"_", 1,
    305                      (const unsigned char *)" ", 1);
    306 
    307     status = ares_sysconfig_process_buf(channel, sysconfig, buf,
    308                                         ares_sysconfig_parse_resolv_line);
    309     if (status != ARES_SUCCESS) {
    310       /* ENOMEM is really the only error we'll get here */
    311       goto done;
    312     }
    313 
    314     /* don't read resolv.conf if we processed *any* nameservers */
    315     if (ares_llist_len(sysconfig->sconfig) != 0) {
    316       process_resolvconf = ARES_FALSE;
    317     }
    318   }
    319 
    320   /* Process files */
    321   status = ares_init_sysconfig_files(channel, sysconfig, process_resolvconf);
    322   if (status != ARES_SUCCESS) {
    323     goto done;
    324   }
    325 
    326   /* Read confstr(_CS_DOMAIN, ...), but if we had a search path specified with
    327    * more than one domain, lets prefer that instead.  Its not exactly clear
    328    * the best way to handle this. */
    329   if (sysconfig->ndomains <= 1) {
    330     char   domain[256];
    331     size_t domain_len;
    332 
    333     domain_len = confstr(_CS_DOMAIN, domain, sizeof(domain_len));
    334     if (domain_len != 0) {
    335       ares_strsplit_free(sysconfig->domains, sysconfig->ndomains);
    336       sysconfig->domains = ares_strsplit(domain, ", ", &sysconfig->ndomains);
    337       if (sysconfig->domains == NULL) {
    338         status = ARES_ENOMEM;
    339         goto done;
    340       }
    341     }
    342   }
    343 
    344 done:
    345   ares_buf_destroy(buf);
    346 
    347   return status;
    348 }
    349 #endif
    350 
    351 #if defined(CARES_USE_LIBRESOLV)
    352 static ares_status_t
    353   ares_init_sysconfig_libresolv(const ares_channel_t *channel,
    354                                 ares_sysconfig_t     *sysconfig)
    355 {
    356   struct __res_state       res;
    357   ares_status_t            status = ARES_SUCCESS;
    358   union res_sockaddr_union addr[MAXNS];
    359   int                      nscount;
    360   size_t                   i;
    361   size_t                   entries = 0;
    362   ares_buf_t              *ipbuf   = NULL;
    363 
    364   memset(&res, 0, sizeof(res));
    365 
    366   if (res_ninit(&res) != 0 || !(res.options & RES_INIT)) {
    367     return ARES_EFILE;
    368   }
    369 
    370   nscount = res_getservers(&res, addr, MAXNS);
    371 
    372   for (i = 0; i < (size_t)nscount; ++i) {
    373     char           ipaddr[INET6_ADDRSTRLEN] = "";
    374     char          *ipstr                    = NULL;
    375     unsigned short port                     = 0;
    376     unsigned int   ll_scope                 = 0;
    377 
    378     sa_family_t    family = addr[i].sin.sin_family;
    379     if (family == AF_INET) {
    380       ares_inet_ntop(family, &addr[i].sin.sin_addr, ipaddr, sizeof(ipaddr));
    381       port = ntohs(addr[i].sin.sin_port);
    382     } else if (family == AF_INET6) {
    383       ares_inet_ntop(family, &addr[i].sin6.sin6_addr, ipaddr, sizeof(ipaddr));
    384       port     = ntohs(addr[i].sin6.sin6_port);
    385       ll_scope = addr[i].sin6.sin6_scope_id;
    386     } else {
    387       continue;
    388     }
    389 
    390 
    391     /* [ip]:port%iface */
    392     ipbuf = ares_buf_create();
    393     if (ipbuf == NULL) {
    394       status = ARES_ENOMEM;
    395       goto done;
    396     }
    397 
    398     status = ares_buf_append_str(ipbuf, "[");
    399     if (status != ARES_SUCCESS) {
    400       goto done;
    401     }
    402 
    403     status = ares_buf_append_str(ipbuf, ipaddr);
    404     if (status != ARES_SUCCESS) {
    405       goto done;
    406     }
    407 
    408     status = ares_buf_append_str(ipbuf, "]");
    409     if (status != ARES_SUCCESS) {
    410       goto done;
    411     }
    412 
    413     if (port) {
    414       status = ares_buf_append_str(ipbuf, ":");
    415       if (status != ARES_SUCCESS) {
    416         goto done;
    417       }
    418       status = ares_buf_append_num_dec(ipbuf, port, 0);
    419       if (status != ARES_SUCCESS) {
    420         goto done;
    421       }
    422     }
    423 
    424     if (ll_scope) {
    425       status = ares_buf_append_str(ipbuf, "%");
    426       if (status != ARES_SUCCESS) {
    427         goto done;
    428       }
    429       status = ares_buf_append_num_dec(ipbuf, ll_scope, 0);
    430       if (status != ARES_SUCCESS) {
    431         goto done;
    432       }
    433     }
    434 
    435     ipstr = ares_buf_finish_str(ipbuf, NULL);
    436     ipbuf = NULL;
    437     if (ipstr == NULL) {
    438       status = ARES_ENOMEM;
    439       goto done;
    440     }
    441 
    442     status = ares_sconfig_append_fromstr(channel, &sysconfig->sconfig, ipstr,
    443                                          ARES_TRUE);
    444 
    445     ares_free(ipstr);
    446     if (status != ARES_SUCCESS) {
    447       goto done;
    448     }
    449   }
    450 
    451   while ((entries < MAXDNSRCH) && res.dnsrch[entries]) {
    452     entries++;
    453   }
    454 
    455   if (entries) {
    456     sysconfig->domains = ares_malloc_zero(entries * sizeof(char *));
    457     if (sysconfig->domains == NULL) {
    458       status = ARES_ENOMEM;
    459       goto done;
    460     } else {
    461       sysconfig->ndomains = entries;
    462       for (i = 0; i < sysconfig->ndomains; i++) {
    463         sysconfig->domains[i] = ares_strdup(res.dnsrch[i]);
    464         if (sysconfig->domains[i] == NULL) {
    465           status = ARES_ENOMEM;
    466           goto done;
    467         }
    468       }
    469     }
    470   }
    471 
    472   if (res.ndots >= 0) {
    473     sysconfig->ndots = (size_t)res.ndots;
    474   }
    475 /* Apple does not allow configuration of retry, so this is a static dummy
    476  * value, ignore */
    477 #  ifndef __APPLE__
    478   if (res.retry > 0) {
    479     sysconfig->tries = (size_t)res.retry;
    480   }
    481 #  endif
    482   if (res.options & RES_ROTATE) {
    483     sysconfig->rotate = ARES_TRUE;
    484   }
    485 
    486   if (res.retrans > 0) {
    487 /* Apple does not allow configuration of retrans, so this is a dummy value
    488  * that is extremely high (5s) */
    489 #  ifndef __APPLE__
    490     if (res.retrans > 0) {
    491       sysconfig->timeout_ms = (unsigned int)res.retrans * 1000;
    492     }
    493 #  endif
    494   }
    495 
    496 done:
    497   ares_buf_destroy(ipbuf);
    498   res_ndestroy(&res);
    499   return status;
    500 }
    501 #endif
    502 
    503 static void ares_sysconfig_free(ares_sysconfig_t *sysconfig)
    504 {
    505   ares_llist_destroy(sysconfig->sconfig);
    506   ares_strsplit_free(sysconfig->domains, sysconfig->ndomains);
    507   ares_free(sysconfig->sortlist);
    508   ares_free(sysconfig->lookups);
    509   memset(sysconfig, 0, sizeof(*sysconfig));
    510 }
    511 
    512 static ares_status_t ares_sysconfig_apply(ares_channel_t         *channel,
    513                                           const ares_sysconfig_t *sysconfig)
    514 {
    515   ares_status_t status;
    516 
    517   if (sysconfig->sconfig && !(channel->optmask & ARES_OPT_SERVERS)) {
    518     status = ares_servers_update(channel, sysconfig->sconfig, ARES_FALSE);
    519     if (status != ARES_SUCCESS) {
    520       return status;
    521     }
    522   }
    523 
    524   if (sysconfig->domains && !(channel->optmask & ARES_OPT_DOMAINS)) {
    525     /* Make sure we duplicate first then replace so even if there is
    526      * ARES_ENOMEM, the channel stays in a good state */
    527     char **temp =
    528       ares_strsplit_duplicate(sysconfig->domains, sysconfig->ndomains);
    529     if (temp == NULL) {
    530       return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    531     }
    532 
    533     ares_strsplit_free(channel->domains, channel->ndomains);
    534     channel->domains  = temp;
    535     channel->ndomains = sysconfig->ndomains;
    536   }
    537 
    538   if (sysconfig->lookups && !(channel->optmask & ARES_OPT_LOOKUPS)) {
    539     char *temp = ares_strdup(sysconfig->lookups);
    540     if (temp == NULL) {
    541       return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    542     }
    543 
    544     ares_free(channel->lookups);
    545     channel->lookups = temp;
    546   }
    547 
    548   if (sysconfig->sortlist && !(channel->optmask & ARES_OPT_SORTLIST)) {
    549     struct apattern *temp =
    550       ares_malloc(sizeof(*channel->sortlist) * sysconfig->nsortlist);
    551     if (temp == NULL) {
    552       return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
    553     }
    554     memcpy(temp, sysconfig->sortlist,
    555            sizeof(*channel->sortlist) * sysconfig->nsortlist);
    556 
    557     ares_free(channel->sortlist);
    558     channel->sortlist = temp;
    559     channel->nsort    = sysconfig->nsortlist;
    560   }
    561 
    562   if (!(channel->optmask & ARES_OPT_NDOTS)) {
    563     channel->ndots = sysconfig->ndots;
    564   }
    565 
    566   if (sysconfig->tries && !(channel->optmask & ARES_OPT_TRIES)) {
    567     channel->tries = sysconfig->tries;
    568   }
    569 
    570   if (sysconfig->timeout_ms && !(channel->optmask & ARES_OPT_TIMEOUTMS)) {
    571     channel->timeout = sysconfig->timeout_ms;
    572   }
    573 
    574   if (!(channel->optmask & (ARES_OPT_ROTATE | ARES_OPT_NOROTATE))) {
    575     channel->rotate = sysconfig->rotate;
    576   }
    577 
    578   if (sysconfig->usevc) {
    579     channel->flags |= ARES_FLAG_USEVC;
    580   }
    581 
    582   return ARES_SUCCESS;
    583 }
    584 
    585 ares_status_t ares_init_by_sysconfig(ares_channel_t *channel)
    586 {
    587   ares_status_t    status;
    588   ares_sysconfig_t sysconfig;
    589 
    590   memset(&sysconfig, 0, sizeof(sysconfig));
    591   sysconfig.ndots = 1; /* Default value if not otherwise set */
    592 
    593 #if defined(USE_WINSOCK)
    594   status = ares_init_sysconfig_windows(channel, &sysconfig);
    595 #elif defined(__MVS__)
    596   status = ares_init_sysconfig_mvs(channel, &sysconfig);
    597 #elif defined(__riscos__)
    598   status = ares_init_sysconfig_riscos(channel, &sysconfig);
    599 #elif defined(WATT32)
    600   status = ares_init_sysconfig_watt32(channel, &sysconfig);
    601 #elif defined(ANDROID) || defined(__ANDROID__)
    602   status = ares_init_sysconfig_android(channel, &sysconfig);
    603 #elif defined(__APPLE__)
    604   status = ares_init_sysconfig_macos(channel, &sysconfig);
    605 #elif defined(CARES_USE_LIBRESOLV)
    606   status = ares_init_sysconfig_libresolv(channel, &sysconfig);
    607 #elif defined(__QNX__)
    608   status = ares_init_sysconfig_qnx(channel, &sysconfig);
    609 #else
    610   status = ares_init_sysconfig_files(channel, &sysconfig, ARES_TRUE);
    611 #endif
    612 
    613   if (status != ARES_SUCCESS) {
    614     goto done;
    615   }
    616 
    617   /* Environment is supposed to override sysconfig */
    618   status = ares_init_by_environment(&sysconfig);
    619   if (status != ARES_SUCCESS) {
    620     goto done;
    621   }
    622 
    623   /* Lock when applying the configuration to the channel.  Don't need to
    624    * lock prior to this. */
    625 
    626   ares_channel_lock(channel);
    627 
    628   status = ares_sysconfig_apply(channel, &sysconfig);
    629   ares_channel_unlock(channel);
    630 
    631   if (status != ARES_SUCCESS) {
    632     goto done;
    633   }
    634 
    635 done:
    636   ares_sysconfig_free(&sysconfig);
    637 
    638   return status;
    639 }