quickjs-tart

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

if2ip.c (7532B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 
     25 #include "curl_setup.h"
     26 
     27 #ifdef HAVE_NETINET_IN_H
     28 #  include <netinet/in.h>
     29 #endif
     30 #ifdef HAVE_ARPA_INET_H
     31 #  include <arpa/inet.h>
     32 #endif
     33 #ifdef HAVE_NET_IF_H
     34 #  include <net/if.h>
     35 #endif
     36 #ifdef HAVE_SYS_IOCTL_H
     37 #  include <sys/ioctl.h>
     38 #endif
     39 #ifdef HAVE_NETDB_H
     40 #  include <netdb.h>
     41 #endif
     42 #ifdef HAVE_SYS_SOCKIO_H
     43 #  include <sys/sockio.h>
     44 #endif
     45 #ifdef HAVE_IFADDRS_H
     46 #  include <ifaddrs.h>
     47 #endif
     48 #ifdef HAVE_STROPTS_H
     49 #  include <stropts.h>
     50 #endif
     51 #ifdef __VMS
     52 #  include <inet.h>
     53 #endif
     54 
     55 #include "curlx/inet_ntop.h"
     56 #include "if2ip.h"
     57 /* The last 3 #include files should be in this order */
     58 #include "curl_printf.h"
     59 #include "curl_memory.h"
     60 #include "memdebug.h"
     61 
     62 /* ------------------------------------------------------------------ */
     63 
     64 #ifdef USE_IPV6
     65 /* Return the scope of the given address. */
     66 unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
     67 {
     68   if(sa->sa_family == AF_INET6) {
     69     const struct sockaddr_in6 * sa6 =
     70       (const struct sockaddr_in6 *)(const void *) sa;
     71     const unsigned char *b = sa6->sin6_addr.s6_addr;
     72     unsigned short w = (unsigned short) ((b[0] << 8) | b[1]);
     73 
     74     if((b[0] & 0xFE) == 0xFC) /* Handle ULAs */
     75       return IPV6_SCOPE_UNIQUELOCAL;
     76     switch(w & 0xFFC0) {
     77     case 0xFE80:
     78       return IPV6_SCOPE_LINKLOCAL;
     79     case 0xFEC0:
     80       return IPV6_SCOPE_SITELOCAL;
     81     case 0x0000:
     82       w = b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7] | b[8] | b[9] |
     83           b[10] | b[11] | b[12] | b[13] | b[14];
     84       if(w || b[15] != 0x01)
     85         break;
     86       return IPV6_SCOPE_NODELOCAL;
     87     default:
     88       break;
     89     }
     90   }
     91   return IPV6_SCOPE_GLOBAL;
     92 }
     93 #endif
     94 
     95 #if !defined(CURL_DISABLE_BINDLOCAL) || !defined(CURL_DISABLE_FTP)
     96 
     97 #if defined(HAVE_GETIFADDRS)
     98 
     99 if2ip_result_t Curl_if2ip(int af,
    100 #ifdef USE_IPV6
    101                           unsigned int remote_scope,
    102                           unsigned int local_scope_id,
    103 #endif
    104                           const char *interf,
    105                           char *buf, size_t buf_size)
    106 {
    107   struct ifaddrs *iface, *head;
    108   if2ip_result_t res = IF2IP_NOT_FOUND;
    109 
    110 #if defined(USE_IPV6) && \
    111     !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
    112   (void) local_scope_id;
    113 #endif
    114 
    115   if(getifaddrs(&head) >= 0) {
    116     for(iface = head; iface != NULL; iface = iface->ifa_next) {
    117       if(iface->ifa_addr) {
    118         if(iface->ifa_addr->sa_family == af) {
    119           if(curl_strequal(iface->ifa_name, interf)) {
    120             void *addr;
    121             const char *ip;
    122             char scope[12] = "";
    123             char ipstr[64];
    124 #ifdef USE_IPV6
    125             if(af == AF_INET6) {
    126 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
    127               unsigned int scopeid = 0;
    128 #endif
    129               unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr);
    130 
    131               if(ifscope != remote_scope) {
    132                 /* We are interested only in interface addresses whose scope
    133                    matches the remote address we want to connect to: global
    134                    for global, link-local for link-local, etc... */
    135                 if(res == IF2IP_NOT_FOUND)
    136                   res = IF2IP_AF_NOT_SUPPORTED;
    137                 continue;
    138               }
    139 
    140               addr =
    141                 &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr;
    142 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
    143               /* Include the scope of this interface as part of the address */
    144               scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr)
    145                             ->sin6_scope_id;
    146 
    147               /* If given, scope id should match. */
    148               if(local_scope_id && scopeid != local_scope_id) {
    149                 if(res == IF2IP_NOT_FOUND)
    150                   res = IF2IP_AF_NOT_SUPPORTED;
    151 
    152                 continue;
    153               }
    154 
    155               if(scopeid)
    156                 msnprintf(scope, sizeof(scope), "%%%u", scopeid);
    157 #endif
    158             }
    159             else
    160 #endif
    161               addr =
    162                 &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
    163             res = IF2IP_FOUND;
    164             ip = curlx_inet_ntop(af, addr, ipstr, sizeof(ipstr));
    165             msnprintf(buf, buf_size, "%s%s", ip, scope);
    166             break;
    167           }
    168         }
    169         else if((res == IF2IP_NOT_FOUND) &&
    170                 curl_strequal(iface->ifa_name, interf)) {
    171           res = IF2IP_AF_NOT_SUPPORTED;
    172         }
    173       }
    174     }
    175 
    176     freeifaddrs(head);
    177   }
    178 
    179   return res;
    180 }
    181 
    182 #elif defined(HAVE_IOCTL_SIOCGIFADDR)
    183 
    184 if2ip_result_t Curl_if2ip(int af,
    185 #ifdef USE_IPV6
    186                           unsigned int remote_scope,
    187                           unsigned int local_scope_id,
    188 #endif
    189                           const char *interf,
    190                           char *buf, size_t buf_size)
    191 {
    192   struct ifreq req;
    193   struct in_addr in;
    194   struct sockaddr_in *s;
    195   curl_socket_t dummy;
    196   size_t len;
    197   const char *r;
    198 
    199 #ifdef USE_IPV6
    200   (void)remote_scope;
    201   (void)local_scope_id;
    202 #endif
    203 
    204   if(!interf || (af != AF_INET))
    205     return IF2IP_NOT_FOUND;
    206 
    207   len = strlen(interf);
    208   if(len >= sizeof(req.ifr_name))
    209     return IF2IP_NOT_FOUND;
    210 
    211   dummy = socket(AF_INET, SOCK_STREAM, 0);
    212   if(CURL_SOCKET_BAD == dummy)
    213     return IF2IP_NOT_FOUND;
    214 
    215   memset(&req, 0, sizeof(req));
    216   memcpy(req.ifr_name, interf, len + 1);
    217   req.ifr_addr.sa_family = AF_INET;
    218 
    219 #if defined(__GNUC__) && defined(_AIX)
    220 /* Suppress warning inside system headers */
    221 #pragma GCC diagnostic push
    222 #pragma GCC diagnostic ignored "-Wshift-sign-overflow"
    223 #endif
    224   if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
    225 #if defined(__GNUC__) && defined(_AIX)
    226 #pragma GCC diagnostic pop
    227 #endif
    228     sclose(dummy);
    229     /* With SIOCGIFADDR, we cannot tell the difference between an interface
    230        that does not exist and an interface that has no address of the
    231        correct family. Assume the interface does not exist */
    232     return IF2IP_NOT_FOUND;
    233   }
    234 
    235   s = (struct sockaddr_in *)(void *)&req.ifr_addr;
    236   memcpy(&in, &s->sin_addr, sizeof(in));
    237   r = curlx_inet_ntop(s->sin_family, &in, buf, buf_size);
    238 
    239   sclose(dummy);
    240   if(!r)
    241     return IF2IP_NOT_FOUND;
    242   return IF2IP_FOUND;
    243 }
    244 
    245 #else
    246 
    247 if2ip_result_t Curl_if2ip(int af,
    248 #ifdef USE_IPV6
    249                           unsigned int remote_scope,
    250                           unsigned int local_scope_id,
    251 #endif
    252                           const char *interf,
    253                           char *buf, size_t buf_size)
    254 {
    255     (void) af;
    256 #ifdef USE_IPV6
    257     (void) remote_scope;
    258     (void) local_scope_id;
    259 #endif
    260     (void) interf;
    261     (void) buf;
    262     (void) buf_size;
    263     return IF2IP_NOT_FOUND;
    264 }
    265 
    266 #endif
    267 
    268 #endif /* CURL_DISABLE_BINDLOCAL && CURL_DISABLE_FTP */