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