quickjs-tart

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

curl_addrinfo.c (16615B)


      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 #include <curl/curl.h>
     28 
     29 #ifdef HAVE_NETINET_IN_H
     30 #  include <netinet/in.h>
     31 #endif
     32 #ifdef HAVE_NETINET_IN6_H
     33 #  include <netinet/in6.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 #ifdef HAVE_SYS_UN_H
     42 #  include <sys/un.h>
     43 #endif
     44 
     45 #ifdef __VMS
     46 #  include <in.h>
     47 #  include <inet.h>
     48 #endif
     49 
     50 #include <stddef.h>
     51 
     52 #include "curl_addrinfo.h"
     53 #include "fake_addrinfo.h"
     54 #include "curlx/inet_pton.h"
     55 #include "curlx/warnless.h"
     56 /* The last 3 #include files should be in this order */
     57 #include "curl_printf.h"
     58 #include "curl_memory.h"
     59 #include "memdebug.h"
     60 
     61 /*
     62  * Curl_freeaddrinfo()
     63  *
     64  * This is used to free a linked list of Curl_addrinfo structs along
     65  * with all its associated allocated storage. This function should be
     66  * called once for each successful call to Curl_getaddrinfo_ex() or to
     67  * any function call which actually allocates a Curl_addrinfo struct.
     68  */
     69 
     70 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
     71     defined(__OPTIMIZE__) && defined(__unix__) &&  defined(__i386__)
     72   /* workaround icc 9.1 optimizer issue */
     73 # define vqualifier volatile
     74 #else
     75 # define vqualifier
     76 #endif
     77 
     78 void
     79 Curl_freeaddrinfo(struct Curl_addrinfo *cahead)
     80 {
     81   struct Curl_addrinfo *vqualifier canext;
     82   struct Curl_addrinfo *ca;
     83 
     84   for(ca = cahead; ca; ca = canext) {
     85     canext = ca->ai_next;
     86     free(ca);
     87   }
     88 }
     89 
     90 
     91 #ifdef HAVE_GETADDRINFO
     92 /*
     93  * Curl_getaddrinfo_ex()
     94  *
     95  * This is a wrapper function around system's getaddrinfo(), with
     96  * the only difference that instead of returning a linked list of
     97  * addrinfo structs this one returns a linked list of Curl_addrinfo
     98  * ones. The memory allocated by this function *MUST* be free'd with
     99  * Curl_freeaddrinfo(). For each successful call to this function
    100  * there must be an associated call later to Curl_freeaddrinfo().
    101  *
    102  * There should be no single call to system's getaddrinfo() in the
    103  * whole library, any such call should be 'routed' through this one.
    104  */
    105 
    106 int
    107 Curl_getaddrinfo_ex(const char *nodename,
    108                     const char *servname,
    109                     const struct addrinfo *hints,
    110                     struct Curl_addrinfo **result)
    111 {
    112   const struct addrinfo *ai;
    113   struct addrinfo *aihead;
    114   struct Curl_addrinfo *cafirst = NULL;
    115   struct Curl_addrinfo *calast = NULL;
    116   struct Curl_addrinfo *ca;
    117   size_t ss_size;
    118   int error;
    119 
    120   *result = NULL; /* assume failure */
    121 
    122   error = CURL_GETADDRINFO(nodename, servname, hints, &aihead);
    123   if(error)
    124     return error;
    125 
    126   /* traverse the addrinfo list */
    127 
    128   for(ai = aihead; ai != NULL; ai = ai->ai_next) {
    129     size_t namelen = ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0;
    130     /* ignore elements with unsupported address family, */
    131     /* settle family-specific sockaddr structure size.  */
    132     if(ai->ai_family == AF_INET)
    133       ss_size = sizeof(struct sockaddr_in);
    134 #ifdef USE_IPV6
    135     else if(ai->ai_family == AF_INET6)
    136       ss_size = sizeof(struct sockaddr_in6);
    137 #endif
    138     else
    139       continue;
    140 
    141     /* ignore elements without required address info */
    142     if(!ai->ai_addr || !(ai->ai_addrlen > 0))
    143       continue;
    144 
    145     /* ignore elements with bogus address size */
    146     if((size_t)ai->ai_addrlen < ss_size)
    147       continue;
    148 
    149     ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen);
    150     if(!ca) {
    151       error = EAI_MEMORY;
    152       break;
    153     }
    154 
    155     /* copy each structure member individually, member ordering, */
    156     /* size, or padding might be different for each platform.    */
    157 
    158     ca->ai_flags     = ai->ai_flags;
    159     ca->ai_family    = ai->ai_family;
    160     ca->ai_socktype  = ai->ai_socktype;
    161     ca->ai_protocol  = ai->ai_protocol;
    162     ca->ai_addrlen   = (curl_socklen_t)ss_size;
    163     ca->ai_addr      = NULL;
    164     ca->ai_canonname = NULL;
    165     ca->ai_next      = NULL;
    166 
    167     ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
    168     memcpy(ca->ai_addr, ai->ai_addr, ss_size);
    169 
    170     if(namelen) {
    171       ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
    172       memcpy(ca->ai_canonname, ai->ai_canonname, namelen);
    173     }
    174 
    175     /* if the return list is empty, this becomes the first element */
    176     if(!cafirst)
    177       cafirst = ca;
    178 
    179     /* add this element last in the return list */
    180     if(calast)
    181       calast->ai_next = ca;
    182     calast = ca;
    183 
    184   }
    185 
    186   /* destroy the addrinfo list */
    187   if(aihead)
    188     CURL_FREEADDRINFO(aihead);
    189 
    190   /* if we failed, also destroy the Curl_addrinfo list */
    191   if(error) {
    192     Curl_freeaddrinfo(cafirst);
    193     cafirst = NULL;
    194   }
    195   else if(!cafirst) {
    196 #ifdef EAI_NONAME
    197     /* rfc3493 conformant */
    198     error = EAI_NONAME;
    199 #else
    200     /* rfc3493 obsoleted */
    201     error = EAI_NODATA;
    202 #endif
    203 #ifdef USE_WINSOCK
    204     SET_SOCKERRNO(error);
    205 #endif
    206   }
    207 
    208   *result = cafirst;
    209 
    210   /* This is not a CURLcode */
    211   return error;
    212 }
    213 #endif /* HAVE_GETADDRINFO */
    214 
    215 
    216 /*
    217  * Curl_he2ai()
    218  *
    219  * This function returns a pointer to the first element of a newly allocated
    220  * Curl_addrinfo struct linked list filled with the data of a given hostent.
    221  * Curl_addrinfo is meant to work like the addrinfo struct does for an IPv6
    222  * stack, but usable also for IPv4, all hosts and environments.
    223  *
    224  * The memory allocated by this function *MUST* be free'd later on calling
    225  * Curl_freeaddrinfo(). For each successful call to this function there
    226  * must be an associated call later to Curl_freeaddrinfo().
    227  *
    228  *   Curl_addrinfo defined in "lib/curl_addrinfo.h"
    229  *
    230  *     struct Curl_addrinfo {
    231  *       int                   ai_flags;
    232  *       int                   ai_family;
    233  *       int                   ai_socktype;
    234  *       int                   ai_protocol;
    235  *       curl_socklen_t        ai_addrlen;   * Follow rfc3493 struct addrinfo *
    236  *       char                 *ai_canonname;
    237  *       struct sockaddr      *ai_addr;
    238  *       struct Curl_addrinfo *ai_next;
    239  *     };
    240  *
    241  *   hostent defined in <netdb.h>
    242  *
    243  *     struct hostent {
    244  *       char    *h_name;
    245  *       char    **h_aliases;
    246  *       int     h_addrtype;
    247  *       int     h_length;
    248  *       char    **h_addr_list;
    249  *     };
    250  *
    251  *   for backward compatibility:
    252  *
    253  *     #define h_addr  h_addr_list[0]
    254  */
    255 
    256 #if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE))
    257 struct Curl_addrinfo *
    258 Curl_he2ai(const struct hostent *he, int port)
    259 {
    260   struct Curl_addrinfo *ai;
    261   struct Curl_addrinfo *prevai = NULL;
    262   struct Curl_addrinfo *firstai = NULL;
    263   struct sockaddr_in *addr;
    264 #ifdef USE_IPV6
    265   struct sockaddr_in6 *addr6;
    266 #endif
    267   CURLcode result = CURLE_OK;
    268   int i;
    269   char *curr;
    270 
    271   if(!he)
    272     /* no input == no output! */
    273     return NULL;
    274 
    275   DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
    276 
    277   for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) {
    278     size_t ss_size;
    279     size_t namelen = strlen(he->h_name) + 1; /* include null-terminator */
    280 #ifdef USE_IPV6
    281     if(he->h_addrtype == AF_INET6)
    282       ss_size = sizeof(struct sockaddr_in6);
    283     else
    284 #endif
    285       ss_size = sizeof(struct sockaddr_in);
    286 
    287     /* allocate memory to hold the struct, the address and the name */
    288     ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + namelen);
    289     if(!ai) {
    290       result = CURLE_OUT_OF_MEMORY;
    291       break;
    292     }
    293     /* put the address after the struct */
    294     ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
    295     /* then put the name after the address */
    296     ai->ai_canonname = (char *)ai->ai_addr + ss_size;
    297     memcpy(ai->ai_canonname, he->h_name, namelen);
    298 
    299     if(!firstai)
    300       /* store the pointer we want to return from this function */
    301       firstai = ai;
    302 
    303     if(prevai)
    304       /* make the previous entry point to this */
    305       prevai->ai_next = ai;
    306 
    307     ai->ai_family = he->h_addrtype;
    308 
    309     /* we return all names as STREAM, so when using this address for TFTP
    310        the type must be ignored and conn->socktype be used instead! */
    311     ai->ai_socktype = SOCK_STREAM;
    312 
    313     ai->ai_addrlen = (curl_socklen_t)ss_size;
    314 
    315     /* leave the rest of the struct filled with zero */
    316 
    317     switch(ai->ai_family) {
    318     case AF_INET:
    319       addr = (void *)ai->ai_addr; /* storage area for this info */
    320 
    321       memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
    322       addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
    323       addr->sin_port = htons((unsigned short)port);
    324       break;
    325 
    326 #ifdef USE_IPV6
    327     case AF_INET6:
    328       addr6 = (void *)ai->ai_addr; /* storage area for this info */
    329 
    330       memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
    331       addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
    332       addr6->sin6_port = htons((unsigned short)port);
    333       break;
    334 #endif
    335     }
    336 
    337     prevai = ai;
    338   }
    339 
    340   if(result) {
    341     Curl_freeaddrinfo(firstai);
    342     firstai = NULL;
    343   }
    344 
    345   return firstai;
    346 }
    347 #endif
    348 
    349 /*
    350  * Curl_ip2addr()
    351  *
    352  * This function takes an Internet address, in binary form, as input parameter
    353  * along with its address family and the string version of the address, and it
    354  * returns a Curl_addrinfo chain filled in correctly with information for the
    355  * given address/host
    356  */
    357 
    358 struct Curl_addrinfo *
    359 Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
    360 {
    361   struct Curl_addrinfo *ai;
    362   size_t addrsize;
    363   size_t namelen;
    364   struct sockaddr_in *addr;
    365 #ifdef USE_IPV6
    366   struct sockaddr_in6 *addr6;
    367 #endif
    368 
    369   DEBUGASSERT(inaddr && hostname);
    370 
    371   namelen = strlen(hostname) + 1;
    372 
    373   if(af == AF_INET)
    374     addrsize = sizeof(struct sockaddr_in);
    375 #ifdef USE_IPV6
    376   else if(af == AF_INET6)
    377     addrsize = sizeof(struct sockaddr_in6);
    378 #endif
    379   else
    380     return NULL;
    381 
    382   /* allocate memory to hold the struct, the address and the name */
    383   ai = calloc(1, sizeof(struct Curl_addrinfo) + addrsize + namelen);
    384   if(!ai)
    385     return NULL;
    386   /* put the address after the struct */
    387   ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
    388   /* then put the name after the address */
    389   ai->ai_canonname = (char *)ai->ai_addr + addrsize;
    390   memcpy(ai->ai_canonname, hostname, namelen);
    391   ai->ai_family = af;
    392   ai->ai_socktype = SOCK_STREAM;
    393   ai->ai_addrlen = (curl_socklen_t)addrsize;
    394   /* leave the rest of the struct filled with zero */
    395 
    396   switch(af) {
    397   case AF_INET:
    398     addr = (void *)ai->ai_addr; /* storage area for this info */
    399 
    400     memcpy(&addr->sin_addr, inaddr, sizeof(struct in_addr));
    401 #ifdef __MINGW32__
    402     addr->sin_family = (short)af;
    403 #else
    404     addr->sin_family = (CURL_SA_FAMILY_T)af;
    405 #endif
    406     addr->sin_port = htons((unsigned short)port);
    407     break;
    408 
    409 #ifdef USE_IPV6
    410   case AF_INET6:
    411     addr6 = (void *)ai->ai_addr; /* storage area for this info */
    412 
    413     memcpy(&addr6->sin6_addr, inaddr, sizeof(struct in6_addr));
    414 #ifdef __MINGW32__
    415     addr6->sin6_family = (short)af;
    416 #else
    417     addr6->sin6_family = (CURL_SA_FAMILY_T)af;
    418 #endif
    419     addr6->sin6_port = htons((unsigned short)port);
    420     break;
    421 #endif
    422   }
    423 
    424   return ai;
    425 }
    426 
    427 /*
    428  * Given an IPv4 or IPv6 dotted string address, this converts it to a proper
    429  * allocated Curl_addrinfo struct and returns it.
    430  */
    431 struct Curl_addrinfo *Curl_str2addr(char *address, int port)
    432 {
    433   struct in_addr in;
    434   if(curlx_inet_pton(AF_INET, address, &in) > 0)
    435     /* This is a dotted IP address 123.123.123.123-style */
    436     return Curl_ip2addr(AF_INET, &in, address, port);
    437 #ifdef USE_IPV6
    438   {
    439     struct in6_addr in6;
    440     if(curlx_inet_pton(AF_INET6, address, &in6) > 0)
    441       /* This is a dotted IPv6 address ::1-style */
    442       return Curl_ip2addr(AF_INET6, &in6, address, port);
    443   }
    444 #endif
    445   return NULL; /* bad input format */
    446 }
    447 
    448 #ifdef USE_UNIX_SOCKETS
    449 /**
    450  * Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo
    451  * struct initialized with this path.
    452  * Set '*longpath' to TRUE if the error is a too long path.
    453  */
    454 struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
    455                                      bool abstract)
    456 {
    457   struct Curl_addrinfo *ai;
    458   struct sockaddr_un *sa_un;
    459   size_t path_len;
    460 
    461   *longpath = FALSE;
    462 
    463   ai = calloc(1, sizeof(struct Curl_addrinfo) + sizeof(struct sockaddr_un));
    464   if(!ai)
    465     return NULL;
    466   ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
    467 
    468   sa_un = (void *) ai->ai_addr;
    469   sa_un->sun_family = AF_UNIX;
    470 
    471   /* sun_path must be able to store the null-terminated path */
    472   path_len = strlen(path) + 1;
    473   if(path_len > sizeof(sa_un->sun_path)) {
    474     free(ai);
    475     *longpath = TRUE;
    476     return NULL;
    477   }
    478 
    479   ai->ai_family = AF_UNIX;
    480   ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */
    481   ai->ai_addrlen = (curl_socklen_t)
    482     ((offsetof(struct sockaddr_un, sun_path) + path_len) & 0x7FFFFFFF);
    483 
    484   /* Abstract Unix domain socket have NULL prefix instead of suffix */
    485   if(abstract)
    486     memcpy(sa_un->sun_path + 1, path, path_len - 1);
    487   else
    488     memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */
    489 
    490   return ai;
    491 }
    492 #endif
    493 
    494 #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) &&  \
    495   defined(HAVE_FREEADDRINFO)
    496 /*
    497  * curl_dbg_freeaddrinfo()
    498  *
    499  * This is strictly for memory tracing and are using the same style as the
    500  * family otherwise present in memdebug.c. I put these ones here since they
    501  * require a bunch of structs I did not want to include in memdebug.c
    502  */
    503 
    504 void
    505 curl_dbg_freeaddrinfo(struct addrinfo *freethis,
    506                       int line, const char *source)
    507 {
    508   curl_dbg_log("ADDR %s:%d freeaddrinfo(%p)\n",
    509                source, line, (void *)freethis);
    510 #ifdef USE_LWIPSOCK
    511   lwip_freeaddrinfo(freethis);
    512 #elif defined(USE_FAKE_GETADDRINFO)
    513   {
    514     const char *env = getenv("CURL_DNS_SERVER");
    515     if(env)
    516       r_freeaddrinfo(freethis);
    517     else
    518       freeaddrinfo(freethis);
    519   }
    520 #else
    521   freeaddrinfo(freethis);
    522 #endif
    523 }
    524 #endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
    525 
    526 
    527 #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
    528 /*
    529  * curl_dbg_getaddrinfo()
    530  *
    531  * This is strictly for memory tracing and are using the same style as the
    532  * family otherwise present in memdebug.c. I put these ones here since they
    533  * require a bunch of structs I did not want to include in memdebug.c
    534  */
    535 
    536 int
    537 curl_dbg_getaddrinfo(const char *hostname,
    538                      const char *service,
    539                      const struct addrinfo *hints,
    540                      struct addrinfo **result,
    541                      int line, const char *source)
    542 {
    543 #ifdef USE_LWIPSOCK
    544   int res = lwip_getaddrinfo(hostname, service, hints, result);
    545 #elif defined(USE_FAKE_GETADDRINFO)
    546   int res;
    547   const char *env = getenv("CURL_DNS_SERVER");
    548   if(env)
    549     res = r_getaddrinfo(hostname, service, hints, result);
    550   else
    551     res = getaddrinfo(hostname, service, hints, result);
    552 #else
    553   int res = getaddrinfo(hostname, service, hints, result);
    554 #endif
    555   if(0 == res)
    556     /* success */
    557     curl_dbg_log("ADDR %s:%d getaddrinfo() = %p\n",
    558                  source, line, (void *)*result);
    559   else
    560     curl_dbg_log("ADDR %s:%d getaddrinfo() failed\n",
    561                  source, line);
    562   return res;
    563 }
    564 #endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
    565 
    566 #if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS)
    567 /*
    568  * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and macOS
    569  * 10.11.5.
    570  */
    571 void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)
    572 {
    573   struct Curl_addrinfo *ca;
    574   struct sockaddr_in *addr;
    575 #ifdef USE_IPV6
    576   struct sockaddr_in6 *addr6;
    577 #endif
    578   for(ca = addrinfo; ca != NULL; ca = ca->ai_next) {
    579     switch(ca->ai_family) {
    580     case AF_INET:
    581       addr = (void *)ca->ai_addr; /* storage area for this info */
    582       addr->sin_port = htons((unsigned short)port);
    583       break;
    584 
    585 #ifdef USE_IPV6
    586     case AF_INET6:
    587       addr6 = (void *)ca->ai_addr; /* storage area for this info */
    588       addr6->sin6_port = htons((unsigned short)port);
    589       break;
    590 #endif
    591     }
    592   }
    593 }
    594 #endif