Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2017, 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 /***********************************************************************
     26  * Only for IPv6-enabled builds
     27  **********************************************************************/
     28 #ifdef CURLRES_IPV6
     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 #ifdef __VMS
     40 #include <in.h>
     41 #include <inet.h>
     42 #endif
     43 
     44 #ifdef HAVE_PROCESS_H
     45 #include <process.h>
     46 #endif
     47 
     48 #include "urldata.h"
     49 #include "sendf.h"
     50 #include "hostip.h"
     51 #include "hash.h"
     52 #include "share.h"
     53 #include "strerror.h"
     54 #include "url.h"
     55 #include "inet_pton.h"
     56 #include "connect.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 #if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
     63 /* These are strictly for memory tracing and are using the same style as the
     64  * family otherwise present in memdebug.c. I put these ones here since they
     65  * require a bunch of structs I didn't want to include in memdebug.c
     66  */
     67 
     68 /*
     69  * For CURLRES_ARS, this should be written using ares_gethostbyaddr()
     70  * (ignoring the fact c-ares doesn't return 'serv').
     71  */
     72 
     73 int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
     74                        GETNAMEINFO_TYPE_ARG2 salen,
     75                        char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
     76                        char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
     77                        GETNAMEINFO_TYPE_ARG7 flags,
     78                        int line, const char *source)
     79 {
     80   int res = (getnameinfo)(sa, salen,
     81                           host, hostlen,
     82                           serv, servlen,
     83                           flags);
     84   if(0 == res)
     85     /* success */
     86     curl_memlog("GETNAME %s:%d getnameinfo()\n",
     87                 source, line);
     88   else
     89     curl_memlog("GETNAME %s:%d getnameinfo() failed = %d\n",
     90                 source, line, res);
     91   return res;
     92 }
     93 #endif /* defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) */
     94 
     95 /*
     96  * Curl_ipv6works() returns TRUE if IPv6 seems to work.
     97  */
     98 bool Curl_ipv6works(void)
     99 {
    100   /* the nature of most system is that IPv6 status doesn't come and go
    101      during a program's lifetime so we only probe the first time and then we
    102      have the info kept for fast re-use */
    103   static int ipv6_works = -1;
    104   if(-1 == ipv6_works) {
    105     /* probe to see if we have a working IPv6 stack */
    106     curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
    107     if(s == CURL_SOCKET_BAD)
    108       /* an IPv6 address was requested but we can't get/use one */
    109       ipv6_works = 0;
    110     else {
    111       ipv6_works = 1;
    112       Curl_closesocket(NULL, s);
    113     }
    114   }
    115   return (ipv6_works>0)?TRUE:FALSE;
    116 }
    117 
    118 /*
    119  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
    120  * been set and returns TRUE if they are OK.
    121  */
    122 bool Curl_ipvalid(struct connectdata *conn)
    123 {
    124   if(conn->ip_version == CURL_IPRESOLVE_V6)
    125     return Curl_ipv6works();
    126 
    127   return TRUE;
    128 }
    129 
    130 #if defined(CURLRES_SYNCH)
    131 
    132 #ifdef DEBUG_ADDRINFO
    133 static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
    134 {
    135   printf("dump_addrinfo:\n");
    136   for(; ai; ai = ai->ai_next) {
    137     char  buf[INET6_ADDRSTRLEN];
    138 
    139     printf("    fam %2d, CNAME %s, ",
    140            ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
    141     if(Curl_printable_address(ai, buf, sizeof(buf)))
    142       printf("%s\n", buf);
    143     else
    144       printf("failed; %s\n", Curl_strerror(conn, SOCKERRNO));
    145   }
    146 }
    147 #else
    148 #define dump_addrinfo(x,y) Curl_nop_stmt
    149 #endif
    150 
    151 /*
    152  * Curl_getaddrinfo() when built IPv6-enabled (non-threading and
    153  * non-ares version).
    154  *
    155  * Returns name information about the given hostname and port number. If
    156  * successful, the 'addrinfo' is returned and the forth argument will point to
    157  * memory we need to free after use. That memory *MUST* be freed with
    158  * Curl_freeaddrinfo(), nothing else.
    159  */
    160 Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
    161                                 const char *hostname,
    162                                 int port,
    163                                 int *waitp)
    164 {
    165   struct addrinfo hints;
    166   Curl_addrinfo *res;
    167   int error;
    168   char sbuf[12];
    169   char *sbufptr = NULL;
    170 #ifndef USE_RESOLVE_ON_IPS
    171   char addrbuf[128];
    172 #endif
    173   int pf;
    174 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
    175   struct Curl_easy *data = conn->data;
    176 #endif
    177 
    178   *waitp = 0; /* synchronous response only */
    179 
    180   /* Check if a limited name resolve has been requested */
    181   switch(conn->ip_version) {
    182   case CURL_IPRESOLVE_V4:
    183     pf = PF_INET;
    184     break;
    185   case CURL_IPRESOLVE_V6:
    186     pf = PF_INET6;
    187     break;
    188   default:
    189     pf = PF_UNSPEC;
    190     break;
    191   }
    192 
    193   if((pf != PF_INET) && !Curl_ipv6works())
    194     /* The stack seems to be a non-IPv6 one */
    195     pf = PF_INET;
    196 
    197   memset(&hints, 0, sizeof(hints));
    198   hints.ai_family = pf;
    199   hints.ai_socktype = conn->socktype;
    200 
    201 #ifndef USE_RESOLVE_ON_IPS
    202   /*
    203    * The AI_NUMERICHOST must not be set to get synthesized IPv6 address from
    204    * an IPv4 address on iOS and Mac OS X.
    205    */
    206   if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) ||
    207      (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) {
    208     /* the given address is numerical only, prevent a reverse lookup */
    209     hints.ai_flags = AI_NUMERICHOST;
    210   }
    211 #endif
    212 
    213   if(port) {
    214     snprintf(sbuf, sizeof(sbuf), "%d", port);
    215     sbufptr = sbuf;
    216   }
    217 
    218   error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);
    219   if(error) {
    220     infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
    221     return NULL;
    222   }
    223 
    224   if(port) {
    225     Curl_addrinfo_set_port(res, port);
    226   }
    227 
    228   dump_addrinfo(conn, res);
    229 
    230   return res;
    231 }
    232 #endif /* CURLRES_SYNCH */
    233 
    234 #endif /* CURLRES_IPV6 */
    235