quickjs-tart

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

ares_gethostbyaddr.c (7507B)


      1 /* MIT License
      2  *
      3  * Copyright (c) 1998 Massachusetts Institute of Technology
      4  * Copyright (c) The c-ares project and its contributors
      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_NETINET_IN_H
     31 #  include <netinet/in.h>
     32 #endif
     33 #ifdef HAVE_NETDB_H
     34 #  include <netdb.h>
     35 #endif
     36 #ifdef HAVE_ARPA_INET_H
     37 #  include <arpa/inet.h>
     38 #endif
     39 
     40 #include "ares_nameser.h"
     41 #include "ares_inet_net_pton.h"
     42 
     43 struct addr_query {
     44   /* Arguments passed to ares_gethostbyaddr() */
     45   ares_channel_t    *channel;
     46   struct ares_addr   addr;
     47   ares_host_callback callback;
     48   void              *arg;
     49   char       *lookups; /* duplicate memory from channel for ares_reinit() */
     50   const char *remaining_lookups;
     51   size_t      timeouts;
     52 };
     53 
     54 static void next_lookup(struct addr_query *aquery);
     55 static void addr_callback(void *arg, ares_status_t status, size_t timeouts,
     56                           const ares_dns_record_t *dnsrec);
     57 static void end_aquery(struct addr_query *aquery, ares_status_t status,
     58                        struct hostent *host);
     59 static ares_status_t file_lookup(ares_channel_t         *channel,
     60                                  const struct ares_addr *addr,
     61                                  struct hostent        **host);
     62 
     63 void ares_gethostbyaddr_nolock(ares_channel_t *channel, const void *addr,
     64                                int addrlen, int family,
     65                                ares_host_callback callback, void *arg)
     66 {
     67   struct addr_query *aquery;
     68 
     69   if (family != AF_INET && family != AF_INET6) {
     70     callback(arg, ARES_ENOTIMP, 0, NULL);
     71     return;
     72   }
     73 
     74   if ((family == AF_INET && addrlen != sizeof(aquery->addr.addr.addr4)) ||
     75       (family == AF_INET6 && addrlen != sizeof(aquery->addr.addr.addr6))) {
     76     callback(arg, ARES_ENOTIMP, 0, NULL);
     77     return;
     78   }
     79 
     80   aquery = ares_malloc(sizeof(struct addr_query));
     81   if (!aquery) {
     82     callback(arg, ARES_ENOMEM, 0, NULL);
     83     return;
     84   }
     85   aquery->lookups = ares_strdup(channel->lookups);
     86   if (aquery->lookups == NULL) {
     87     /* LCOV_EXCL_START: OutOfMemory */
     88     ares_free(aquery);
     89     callback(arg, ARES_ENOMEM, 0, NULL);
     90     return;
     91     /* LCOV_EXCL_STOP */
     92   }
     93   aquery->channel = channel;
     94   if (family == AF_INET) {
     95     memcpy(&aquery->addr.addr.addr4, addr, sizeof(aquery->addr.addr.addr4));
     96   } else {
     97     memcpy(&aquery->addr.addr.addr6, addr, sizeof(aquery->addr.addr.addr6));
     98   }
     99   aquery->addr.family       = family;
    100   aquery->callback          = callback;
    101   aquery->arg               = arg;
    102   aquery->remaining_lookups = aquery->lookups;
    103   aquery->timeouts          = 0;
    104 
    105   next_lookup(aquery);
    106 }
    107 
    108 void ares_gethostbyaddr(ares_channel_t *channel, const void *addr, int addrlen,
    109                         int family, ares_host_callback callback, void *arg)
    110 {
    111   if (channel == NULL) {
    112     return;
    113   }
    114   ares_channel_lock(channel);
    115   ares_gethostbyaddr_nolock(channel, addr, addrlen, family, callback, arg);
    116   ares_channel_unlock(channel);
    117 }
    118 
    119 static void next_lookup(struct addr_query *aquery)
    120 {
    121   const char     *p;
    122   ares_status_t   status;
    123   struct hostent *host = NULL;
    124   char           *name;
    125 
    126   for (p = aquery->remaining_lookups; *p; p++) {
    127     switch (*p) {
    128       case 'b':
    129         name = ares_dns_addr_to_ptr(&aquery->addr);
    130         if (name == NULL) {
    131           end_aquery(aquery, ARES_ENOMEM,
    132                      NULL); /* LCOV_EXCL_LINE: OutOfMemory */
    133           return;           /* LCOV_EXCL_LINE: OutOfMemory */
    134         }
    135         aquery->remaining_lookups = p + 1;
    136         ares_query_nolock(aquery->channel, name, ARES_CLASS_IN,
    137                           ARES_REC_TYPE_PTR, addr_callback, aquery, NULL);
    138         ares_free(name);
    139         return;
    140       case 'f':
    141         status = file_lookup(aquery->channel, &aquery->addr, &host);
    142 
    143         /* this status check below previously checked for !ARES_ENOTFOUND,
    144            but we should not assume that this single error code is the one
    145            that can occur, as that is in fact no longer the case */
    146         if (status == ARES_SUCCESS) {
    147           end_aquery(aquery, status, host);
    148           return;
    149         }
    150         break;
    151       default:
    152         break;
    153     }
    154   }
    155   end_aquery(aquery, ARES_ENOTFOUND, NULL);
    156 }
    157 
    158 static void addr_callback(void *arg, ares_status_t status, size_t timeouts,
    159                           const ares_dns_record_t *dnsrec)
    160 {
    161   struct addr_query *aquery = (struct addr_query *)arg;
    162   struct hostent    *host;
    163   size_t             addrlen;
    164 
    165   aquery->timeouts += timeouts;
    166   if (status == ARES_SUCCESS) {
    167     if (aquery->addr.family == AF_INET) {
    168       addrlen = sizeof(aquery->addr.addr.addr4);
    169       status  = ares_parse_ptr_reply_dnsrec(dnsrec, &aquery->addr.addr.addr4,
    170                                             (int)addrlen, AF_INET, &host);
    171     } else {
    172       addrlen = sizeof(aquery->addr.addr.addr6);
    173       status  = ares_parse_ptr_reply_dnsrec(dnsrec, &aquery->addr.addr.addr6,
    174                                             (int)addrlen, AF_INET6, &host);
    175     }
    176     end_aquery(aquery, status, host);
    177   } else if (status == ARES_EDESTRUCTION || status == ARES_ECANCELLED) {
    178     end_aquery(aquery, status, NULL);
    179   } else {
    180     next_lookup(aquery);
    181   }
    182 }
    183 
    184 static void end_aquery(struct addr_query *aquery, ares_status_t status,
    185                        struct hostent *host)
    186 {
    187   aquery->callback(aquery->arg, (int)status, (int)aquery->timeouts, host);
    188   if (host) {
    189     ares_free_hostent(host);
    190   }
    191   ares_free(aquery->lookups);
    192   ares_free(aquery);
    193 }
    194 
    195 static ares_status_t file_lookup(ares_channel_t         *channel,
    196                                  const struct ares_addr *addr,
    197                                  struct hostent        **host)
    198 {
    199   char                      ipaddr[INET6_ADDRSTRLEN];
    200   const void               *ptr = NULL;
    201   const ares_hosts_entry_t *entry;
    202   ares_status_t             status;
    203 
    204   if (addr->family == AF_INET) {
    205     ptr = &addr->addr.addr4;
    206   } else if (addr->family == AF_INET6) {
    207     ptr = &addr->addr.addr6;
    208   }
    209 
    210   if (ptr == NULL) {
    211     return ARES_ENOTFOUND;
    212   }
    213 
    214   if (!ares_inet_ntop(addr->family, ptr, ipaddr, sizeof(ipaddr))) {
    215     return ARES_ENOTFOUND;
    216   }
    217 
    218   status = ares_hosts_search_ipaddr(channel, ARES_FALSE, ipaddr, &entry);
    219   if (status != ARES_SUCCESS) {
    220     return status;
    221   }
    222 
    223   status = ares_hosts_entry_to_hostent(entry, addr->family, host);
    224   if (status != ARES_SUCCESS) {
    225     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    226   }
    227 
    228   return ARES_SUCCESS;
    229 }