blob: fb3ad0c084e2c00170468eb0148b5d8299aa8af4 [file] [log] [blame]
Kristian Monsen5ab50182010-05-14 18:53:44 +01001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2010, 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 wanna 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_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
113 * been set and returns TRUE if they are OK.
114 */
115bool Curl_ipvalid(struct SessionHandle *data)
116{
117 if(data->set.ip_version == CURL_IPRESOLVE_V6) {
118 /* see if we have an IPv6 stack */
119 curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
120 if(s == CURL_SOCKET_BAD)
121 /* an ipv6 address was requested and we can't get/use one */
122 return FALSE;
123 sclose(s);
124 }
125 return TRUE;
126}
127
128#if defined(CURLRES_SYNCH)
129
130#ifdef DEBUG_ADDRINFO
131static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
132{
133 printf("dump_addrinfo:\n");
134 for ( ; ai; ai = ai->ai_next) {
135 char buf[INET6_ADDRSTRLEN];
136
137 printf(" fam %2d, CNAME %s, ",
138 ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
139 if(Curl_printable_address(ai, buf, sizeof(buf)))
140 printf("%s\n", buf);
141 else
142 printf("failed; %s\n", Curl_strerror(conn, SOCKERRNO));
143 }
144}
145#else
146#define dump_addrinfo(x,y)
147#endif
148
149/*
150 * Curl_getaddrinfo() when built ipv6-enabled (non-threading and
151 * non-ares version).
152 *
153 * Returns name information about the given hostname and port number. If
154 * successful, the 'addrinfo' is returned and the forth argument will point to
155 * memory we need to free after use. That memory *MUST* be freed with
156 * Curl_freeaddrinfo(), nothing else.
157 */
158Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
159 const char *hostname,
160 int port,
161 int *waitp)
162{
163 struct addrinfo hints;
164 Curl_addrinfo *res;
165 int error;
166 char sbuf[NI_MAXSERV];
167 char *sbufptr = NULL;
168 char addrbuf[128];
169 int pf;
170 struct SessionHandle *data = conn->data;
171
172 *waitp = 0; /* synchronous response only */
173
174 /*
175 * Check if a limited name resolve has been requested.
176 */
177 switch(data->set.ip_version) {
178 case CURL_IPRESOLVE_V4:
179 pf = PF_INET;
180 break;
181 case CURL_IPRESOLVE_V6:
182 pf = PF_INET6;
183 break;
184 default:
185 pf = PF_UNSPEC;
186 break;
187 }
188
189 if (pf != PF_INET) {
190 /* see if we have an IPv6 stack */
191 curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
192 if(s == CURL_SOCKET_BAD) {
193 /* Some non-IPv6 stacks have been found to make very slow name resolves
194 * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
195 * the stack seems to be a non-ipv6 one. */
196
197 pf = PF_INET;
198 }
199 else {
200 /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
201 * possible checks. And close the socket again.
202 */
203 sclose(s);
204 }
205 }
206
207 memset(&hints, 0, sizeof(hints));
208 hints.ai_family = pf;
209 hints.ai_socktype = conn->socktype;
210
211 if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) ||
212 (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) {
213 /* the given address is numerical only, prevent a reverse lookup */
214 hints.ai_flags = AI_NUMERICHOST;
215 }
216#ifdef HAVE_GSSAPI
217 if(conn->data->set.krb)
218 /* if krb is used, we (might) need the canonical host name */
219 hints.ai_flags |= AI_CANONNAME;
220#endif
221
222 if(port) {
223 snprintf(sbuf, sizeof(sbuf), "%d", port);
224 sbufptr=sbuf;
225 }
226 error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);
227 if(error) {
228 infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
229 return NULL;
230 }
231
232 dump_addrinfo(conn, res);
233
234 return res;
235}
236#endif /* CURLRES_SYNCH */
237#endif /* CURLRES_IPV6 */
238