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