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