quickjs-tart

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

ares_addrinfo2hostent.c (8908B)


      1 /* MIT License
      2  *
      3  * Copyright (c) 1998 Massachusetts Institute of Technology
      4  * Copyright (c) 2005 Dominick Meglio
      5  * Copyright (c) 2019 Andrew Selivanov
      6  * Copyright (c) 2021 Brad House
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a copy
      9  * of this software and associated documentation files (the "Software"), to deal
     10  * in the Software without restriction, including without limitation the rights
     11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     12  * copies of the Software, and to permit persons to whom the Software is
     13  * furnished to do so, subject to the following conditions:
     14  *
     15  * The above copyright notice and this permission notice (including the next
     16  * paragraph) shall be included in all copies or substantial portions of the
     17  * Software.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     25  * SOFTWARE.
     26  *
     27  * SPDX-License-Identifier: MIT
     28  */
     29 
     30 #include "ares_private.h"
     31 
     32 #ifdef HAVE_NETINET_IN_H
     33 #  include <netinet/in.h>
     34 #endif
     35 #ifdef HAVE_NETDB_H
     36 #  include <netdb.h>
     37 #endif
     38 #ifdef HAVE_ARPA_INET_H
     39 #  include <arpa/inet.h>
     40 #endif
     41 
     42 #ifdef HAVE_STRINGS_H
     43 #  include <strings.h>
     44 #endif
     45 
     46 #ifdef HAVE_LIMITS_H
     47 #  include <limits.h>
     48 #endif
     49 
     50 static size_t hostent_nalias(const struct hostent *host)
     51 {
     52   size_t i;
     53   for (i=0; host->h_aliases != NULL && host->h_aliases[i] != NULL; i++)
     54     ;
     55 
     56   return i;
     57 }
     58 
     59 static size_t ai_nalias(const struct ares_addrinfo *ai)
     60 {
     61   const struct ares_addrinfo_cname *cname;
     62   size_t                            i     = 0;
     63 
     64   for (cname = ai->cnames; cname != NULL; cname=cname->next) {
     65     i++;
     66   }
     67 
     68   return i;
     69 }
     70 
     71 static size_t hostent_naddr(const struct hostent *host)
     72 {
     73   size_t i;
     74   for (i=0; host->h_addr_list != NULL && host->h_addr_list[i] != NULL; i++)
     75     ;
     76 
     77   return i;
     78 }
     79 
     80 static size_t ai_naddr(const struct ares_addrinfo *ai, int af)
     81 {
     82   const struct ares_addrinfo_node *node;
     83   size_t                           i     = 0;
     84 
     85   for (node = ai->nodes; node != NULL; node=node->ai_next) {
     86     if (af != AF_UNSPEC && af != node->ai_family)
     87       continue;
     88     i++;
     89   }
     90 
     91   return i;
     92 }
     93 
     94 ares_status_t ares_addrinfo2hostent(const struct ares_addrinfo *ai, int family,
     95                                     struct hostent **host)
     96 {
     97   struct ares_addrinfo_node  *next;
     98   char                      **aliases  = NULL;
     99   char                      **addrs    = NULL;
    100   size_t                      naliases = 0;
    101   size_t                      naddrs   = 0;
    102   size_t                      i;
    103   size_t                      ealiases = 0;
    104   size_t                      eaddrs   = 0;
    105 
    106   if (ai == NULL || host == NULL) {
    107     return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
    108   }
    109 
    110   /* Use either the host set in the passed in hosts to be filled in, or the
    111    * first node of the response as the family, since hostent can only
    112    * represent one family.  We assume getaddrinfo() returned a sorted list if
    113    * the user requested AF_UNSPEC. */
    114   if (family == AF_UNSPEC) {
    115     if (*host != NULL && (*host)->h_addrtype != AF_UNSPEC) {
    116       family = (*host)->h_addrtype;
    117     } else if (ai->nodes != NULL) {
    118       family = ai->nodes->ai_family;
    119     }
    120   }
    121 
    122   if (family != AF_INET && family != AF_INET6) {
    123     return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
    124   }
    125 
    126   if (*host == NULL) {
    127     *host = ares_malloc_zero(sizeof(**host));
    128     if (!(*host)) {
    129       goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
    130     }
    131   }
    132 
    133   (*host)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)family;
    134   if (family == AF_INET) {
    135     (*host)->h_length = sizeof(struct in_addr);
    136   } else if (family == AF_INET6) {
    137     (*host)->h_length = sizeof(struct ares_in6_addr);
    138   }
    139 
    140   if ((*host)->h_name == NULL) {
    141     if (ai->cnames) {
    142       (*host)->h_name = ares_strdup(ai->cnames->name);
    143       if ((*host)->h_name == NULL && ai->cnames->name) {
    144         goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
    145       }
    146     } else {
    147       (*host)->h_name = ares_strdup(ai->name);
    148       if ((*host)->h_name == NULL && ai->name) {
    149         goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
    150       }
    151     }
    152   }
    153 
    154   naliases = ai_nalias(ai);
    155   ealiases = hostent_nalias(*host);
    156   aliases  = ares_realloc_zero((*host)->h_aliases,
    157                                ealiases * sizeof(char *),
    158                                (naliases + ealiases + 1) * sizeof(char *));
    159   if (!aliases) {
    160     goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
    161   }
    162   (*host)->h_aliases = aliases;
    163 
    164   if (naliases) {
    165     const struct ares_addrinfo_cname *cname;
    166     i = ealiases;
    167     for (cname = ai->cnames; cname != NULL; cname = cname->next) {
    168       if (cname->alias == NULL) {
    169         continue;
    170       }
    171       (*host)->h_aliases[i] = ares_strdup(cname->alias);
    172       if ((*host)->h_aliases[i] == NULL) {
    173         goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
    174       }
    175       i++;
    176     }
    177   }
    178 
    179   naddrs = ai_naddr(ai, family);
    180   eaddrs = hostent_naddr(*host);
    181   addrs  = ares_realloc_zero((*host)->h_addr_list, eaddrs * sizeof(char *),
    182                              (naddrs + eaddrs + 1) * sizeof(char *));
    183   if (addrs == NULL) {
    184     goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
    185   }
    186   (*host)->h_addr_list = addrs;
    187 
    188   if (naddrs) {
    189     i = eaddrs;
    190     for (next = ai->nodes; next != NULL; next = next->ai_next) {
    191       if (next->ai_family != family) {
    192         continue;
    193       }
    194       (*host)->h_addr_list[i] = ares_malloc_zero((size_t)(*host)->h_length);
    195       if ((*host)->h_addr_list[i] == NULL) {
    196         goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
    197       }
    198       if (family == AF_INET6) {
    199         memcpy((*host)->h_addr_list[i],
    200                &(CARES_INADDR_CAST(const struct sockaddr_in6 *, next->ai_addr)
    201                    ->sin6_addr),
    202                (size_t)(*host)->h_length);
    203       }
    204       if (family == AF_INET) {
    205         memcpy((*host)->h_addr_list[i],
    206                &(CARES_INADDR_CAST(const struct sockaddr_in *, next->ai_addr)
    207                    ->sin_addr),
    208                (size_t)(*host)->h_length);
    209       }
    210       i++;
    211     }
    212   }
    213 
    214   if (naddrs + eaddrs == 0 && naliases + ealiases == 0) {
    215     ares_free_hostent(*host);
    216     *host = NULL;
    217     return ARES_ENODATA;
    218   }
    219 
    220   return ARES_SUCCESS;
    221 
    222 /* LCOV_EXCL_START: OutOfMemory */
    223 enomem:
    224   ares_free_hostent(*host);
    225   *host = NULL;
    226   return ARES_ENOMEM;
    227   /* LCOV_EXCL_STOP */
    228 }
    229 
    230 ares_status_t ares_addrinfo2addrttl(const struct ares_addrinfo *ai, int family,
    231                                     size_t                req_naddrttls,
    232                                     struct ares_addrttl  *addrttls,
    233                                     struct ares_addr6ttl *addr6ttls,
    234                                     size_t               *naddrttls)
    235 {
    236   struct ares_addrinfo_node  *next;
    237   struct ares_addrinfo_cname *next_cname;
    238   int                         cname_ttl = INT_MAX;
    239 
    240   if (family != AF_INET && family != AF_INET6) {
    241     return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
    242   }
    243 
    244   if (ai == NULL || naddrttls == NULL) {
    245     return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
    246   }
    247 
    248   if (family == AF_INET && addrttls == NULL) {
    249     return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
    250   }
    251 
    252   if (family == AF_INET6 && addr6ttls == NULL) {
    253     return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
    254   }
    255 
    256   if (req_naddrttls == 0) {
    257     return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
    258   }
    259 
    260   *naddrttls = 0;
    261 
    262   next_cname = ai->cnames;
    263   while (next_cname) {
    264     if (next_cname->ttl < cname_ttl) {
    265       cname_ttl = next_cname->ttl;
    266     }
    267     next_cname = next_cname->next;
    268   }
    269 
    270   for (next = ai->nodes; next != NULL; next = next->ai_next) {
    271     if (next->ai_family != family) {
    272       continue;
    273     }
    274 
    275     if (*naddrttls >= req_naddrttls) {
    276       break;
    277     }
    278 
    279     if (family == AF_INET6) {
    280       if (next->ai_ttl > cname_ttl) {
    281         addr6ttls[*naddrttls].ttl = cname_ttl;
    282       } else {
    283         addr6ttls[*naddrttls].ttl = next->ai_ttl;
    284       }
    285 
    286       memcpy(&addr6ttls[*naddrttls].ip6addr,
    287              &(CARES_INADDR_CAST(const struct sockaddr_in6 *, next->ai_addr)
    288                  ->sin6_addr),
    289              sizeof(struct ares_in6_addr));
    290     } else {
    291       if (next->ai_ttl > cname_ttl) {
    292         addrttls[*naddrttls].ttl = cname_ttl;
    293       } else {
    294         addrttls[*naddrttls].ttl = next->ai_ttl;
    295       }
    296       memcpy(&addrttls[*naddrttls].ipaddr,
    297              &(CARES_INADDR_CAST(const struct sockaddr_in *, next->ai_addr)
    298                  ->sin_addr),
    299              sizeof(struct in_addr));
    300     }
    301     (*naddrttls)++;
    302   }
    303 
    304   return ARES_SUCCESS;
    305 }