1 | /***************************************************************************
|
---|
2 | * _ _ ____ _
|
---|
3 | * Project ___| | | | _ \| |
|
---|
4 | * / __| | | | |_) | |
|
---|
5 | * | (__| |_| | _ <| |___
|
---|
6 | * \___|\___/|_| \_\_____|
|
---|
7 | *
|
---|
8 | * Copyright (C) 1998 - 2018, Daniel Stenberg, <[email protected]>, 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 plain IPv4 builds
|
---|
27 | **********************************************************************/
|
---|
28 | #ifdef CURLRES_IPV4 /* plain IPv4 code coming up */
|
---|
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 | /* The last 3 #include files should be in this order */
|
---|
57 | #include "curl_printf.h"
|
---|
58 | #include "curl_memory.h"
|
---|
59 | #include "memdebug.h"
|
---|
60 |
|
---|
61 | /*
|
---|
62 | * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
|
---|
63 | * been set and returns TRUE if they are OK.
|
---|
64 | */
|
---|
65 | bool Curl_ipvalid(struct connectdata *conn)
|
---|
66 | {
|
---|
67 | if(conn->ip_version == CURL_IPRESOLVE_V6)
|
---|
68 | /* An IPv6 address was requested and we can't get/use one */
|
---|
69 | return FALSE;
|
---|
70 |
|
---|
71 | return TRUE; /* OK, proceed */
|
---|
72 | }
|
---|
73 |
|
---|
74 | #ifdef CURLRES_SYNCH
|
---|
75 |
|
---|
76 | /*
|
---|
77 | * Curl_getaddrinfo() - the IPv4 synchronous version.
|
---|
78 | *
|
---|
79 | * The original code to this function was from the Dancer source code, written
|
---|
80 | * by Bjorn Reese, it has since been patched and modified considerably.
|
---|
81 | *
|
---|
82 | * gethostbyname_r() is the thread-safe version of the gethostbyname()
|
---|
83 | * function. When we build for plain IPv4, we attempt to use this
|
---|
84 | * function. There are _three_ different gethostbyname_r() versions, and we
|
---|
85 | * detect which one this platform supports in the configure script and set up
|
---|
86 | * the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or
|
---|
87 | * HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME
|
---|
88 | * has the corresponding rules. This is primarily on *nix. Note that some unix
|
---|
89 | * flavours have thread-safe versions of the plain gethostbyname() etc.
|
---|
90 | *
|
---|
91 | */
|
---|
92 | Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
|
---|
93 | const char *hostname,
|
---|
94 | int port,
|
---|
95 | int *waitp)
|
---|
96 | {
|
---|
97 | Curl_addrinfo *ai = NULL;
|
---|
98 |
|
---|
99 | #ifdef CURL_DISABLE_VERBOSE_STRINGS
|
---|
100 | (void)conn;
|
---|
101 | #endif
|
---|
102 |
|
---|
103 | *waitp = 0; /* synchronous response only */
|
---|
104 |
|
---|
105 | ai = Curl_ipv4_resolve_r(hostname, port);
|
---|
106 | if(!ai)
|
---|
107 | infof(conn->data, "Curl_ipv4_resolve_r failed for %s\n", hostname);
|
---|
108 |
|
---|
109 | return ai;
|
---|
110 | }
|
---|
111 | #endif /* CURLRES_SYNCH */
|
---|
112 | #endif /* CURLRES_IPV4 */
|
---|
113 |
|
---|
114 | #if defined(CURLRES_IPV4) && !defined(CURLRES_ARES)
|
---|
115 |
|
---|
116 | /*
|
---|
117 | * Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function.
|
---|
118 | *
|
---|
119 | * This is used for both synchronous and asynchronous resolver builds,
|
---|
120 | * implying that only threadsafe code and function calls may be used.
|
---|
121 | *
|
---|
122 | */
|
---|
123 | Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
|
---|
124 | int port)
|
---|
125 | {
|
---|
126 | #if !defined(HAVE_GETADDRINFO_THREADSAFE) && defined(HAVE_GETHOSTBYNAME_R_3)
|
---|
127 | int res;
|
---|
128 | #endif
|
---|
129 | Curl_addrinfo *ai = NULL;
|
---|
130 | struct hostent *h = NULL;
|
---|
131 | struct in_addr in;
|
---|
132 | struct hostent *buf = NULL;
|
---|
133 |
|
---|
134 | if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
|
---|
135 | /* This is a dotted IP address 123.123.123.123-style */
|
---|
136 | return Curl_ip2addr(AF_INET, &in, hostname, port);
|
---|
137 |
|
---|
138 | #if defined(HAVE_GETADDRINFO_THREADSAFE)
|
---|
139 | else {
|
---|
140 | struct addrinfo hints;
|
---|
141 | char sbuf[12];
|
---|
142 | char *sbufptr = NULL;
|
---|
143 |
|
---|
144 | memset(&hints, 0, sizeof(hints));
|
---|
145 | hints.ai_family = PF_INET;
|
---|
146 | hints.ai_socktype = SOCK_STREAM;
|
---|
147 | if(port) {
|
---|
148 | msnprintf(sbuf, sizeof(sbuf), "%d", port);
|
---|
149 | sbufptr = sbuf;
|
---|
150 | }
|
---|
151 |
|
---|
152 | (void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai);
|
---|
153 |
|
---|
154 | #elif defined(HAVE_GETHOSTBYNAME_R)
|
---|
155 | /*
|
---|
156 | * gethostbyname_r() is the preferred resolve function for many platforms.
|
---|
157 | * Since there are three different versions of it, the following code is
|
---|
158 | * somewhat #ifdef-ridden.
|
---|
159 | */
|
---|
160 | else {
|
---|
161 | int h_errnop;
|
---|
162 |
|
---|
163 | buf = calloc(1, CURL_HOSTENT_SIZE);
|
---|
164 | if(!buf)
|
---|
165 | return NULL; /* major failure */
|
---|
166 | /*
|
---|
167 | * The clearing of the buffer is a workaround for a gethostbyname_r bug in
|
---|
168 | * qnx nto and it is also _required_ for some of these functions on some
|
---|
169 | * platforms.
|
---|
170 | */
|
---|
171 |
|
---|
172 | #if defined(HAVE_GETHOSTBYNAME_R_5)
|
---|
173 | /* Solaris, IRIX and more */
|
---|
174 | h = gethostbyname_r(hostname,
|
---|
175 | (struct hostent *)buf,
|
---|
176 | (char *)buf + sizeof(struct hostent),
|
---|
177 | CURL_HOSTENT_SIZE - sizeof(struct hostent),
|
---|
178 | &h_errnop);
|
---|
179 |
|
---|
180 | /* If the buffer is too small, it returns NULL and sets errno to
|
---|
181 | * ERANGE. The errno is thread safe if this is compiled with
|
---|
182 | * -D_REENTRANT as then the 'errno' variable is a macro defined to get
|
---|
183 | * used properly for threads.
|
---|
184 | */
|
---|
185 |
|
---|
186 | if(h) {
|
---|
187 | ;
|
---|
188 | }
|
---|
189 | else
|
---|
190 | #elif defined(HAVE_GETHOSTBYNAME_R_6)
|
---|
191 | /* Linux */
|
---|
192 |
|
---|
193 | (void)gethostbyname_r(hostname,
|
---|
194 | (struct hostent *)buf,
|
---|
195 | (char *)buf + sizeof(struct hostent),
|
---|
196 | CURL_HOSTENT_SIZE - sizeof(struct hostent),
|
---|
197 | &h, /* DIFFERENCE */
|
---|
198 | &h_errnop);
|
---|
199 | /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
|
---|
200 | * sudden this function returns EAGAIN if the given buffer size is too
|
---|
201 | * small. Previous versions are known to return ERANGE for the same
|
---|
202 | * problem.
|
---|
203 | *
|
---|
204 | * This wouldn't be such a big problem if older versions wouldn't
|
---|
205 | * sometimes return EAGAIN on a common failure case. Alas, we can't
|
---|
206 | * assume that EAGAIN *or* ERANGE means ERANGE for any given version of
|
---|
207 | * glibc.
|
---|
208 | *
|
---|
209 | * For now, we do that and thus we may call the function repeatedly and
|
---|
210 | * fail for older glibc versions that return EAGAIN, until we run out of
|
---|
211 | * buffer size (step_size grows beyond CURL_HOSTENT_SIZE).
|
---|
212 | *
|
---|
213 | * If anyone has a better fix, please tell us!
|
---|
214 | *
|
---|
215 | * -------------------------------------------------------------------
|
---|
216 | *
|
---|
217 | * On October 23rd 2003, Dan C dug up more details on the mysteries of
|
---|
218 | * gethostbyname_r() in glibc:
|
---|
219 | *
|
---|
220 | * In glibc 2.2.5 the interface is different (this has also been
|
---|
221 | * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
|
---|
222 | * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
|
---|
223 | * (shipped/upgraded by Redhat 7.2) don't show this behavior!
|
---|
224 | *
|
---|
225 | * In this "buggy" version, the return code is -1 on error and 'errno'
|
---|
226 | * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
|
---|
227 | * thread-safe variable.
|
---|
228 | */
|
---|
229 |
|
---|
230 | if(!h) /* failure */
|
---|
231 | #elif defined(HAVE_GETHOSTBYNAME_R_3)
|
---|
232 | /* AIX, Digital Unix/Tru64, HPUX 10, more? */
|
---|
233 |
|
---|
234 | /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
|
---|
235 | * the plain fact that it does not return unique full buffers on each
|
---|
236 | * call, but instead several of the pointers in the hostent structs will
|
---|
237 | * point to the same actual data! This have the unfortunate down-side that
|
---|
238 | * our caching system breaks down horribly. Luckily for us though, AIX 4.3
|
---|
239 | * and more recent versions have a "completely thread-safe"[*] libc where
|
---|
240 | * all the data is stored in thread-specific memory areas making calls to
|
---|
241 | * the plain old gethostbyname() work fine even for multi-threaded
|
---|
242 | * programs.
|
---|
243 | *
|
---|
244 | * This AIX 4.3 or later detection is all made in the configure script.
|
---|
245 | *
|
---|
246 | * Troels Walsted Hansen helped us work this out on March 3rd, 2003.
|
---|
247 | *
|
---|
248 | * [*] = much later we've found out that it isn't at all "completely
|
---|
249 | * thread-safe", but at least the gethostbyname() function is.
|
---|
250 | */
|
---|
251 |
|
---|
252 | if(CURL_HOSTENT_SIZE >=
|
---|
253 | (sizeof(struct hostent) + sizeof(struct hostent_data))) {
|
---|
254 |
|
---|
255 | /* August 22nd, 2000: Albert Chin-A-Young brought an updated version
|
---|
256 | * that should work! September 20: Richard Prescott worked on the buffer
|
---|
257 | * size dilemma.
|
---|
258 | */
|
---|
259 |
|
---|
260 | res = gethostbyname_r(hostname,
|
---|
261 | (struct hostent *)buf,
|
---|
262 | (struct hostent_data *)((char *)buf +
|
---|
263 | sizeof(struct hostent)));
|
---|
264 | h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */
|
---|
265 | }
|
---|
266 | else
|
---|
267 | res = -1; /* failure, too smallish buffer size */
|
---|
268 |
|
---|
269 | if(!res) { /* success */
|
---|
270 |
|
---|
271 | h = buf; /* result expected in h */
|
---|
272 |
|
---|
273 | /* This is the worst kind of the different gethostbyname_r() interfaces.
|
---|
274 | * Since we don't know how big buffer this particular lookup required,
|
---|
275 | * we can't realloc down the huge alloc without doing closer analysis of
|
---|
276 | * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
|
---|
277 | * name lookup. Fixing this would require an extra malloc() and then
|
---|
278 | * calling Curl_addrinfo_copy() that subsequent realloc()s down the new
|
---|
279 | * memory area to the actually used amount.
|
---|
280 | */
|
---|
281 | }
|
---|
282 | else
|
---|
283 | #endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */
|
---|
284 | {
|
---|
285 | h = NULL; /* set return code to NULL */
|
---|
286 | free(buf);
|
---|
287 | }
|
---|
288 | #else /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
|
---|
289 | /*
|
---|
290 | * Here is code for platforms that don't have a thread safe
|
---|
291 | * getaddrinfo() nor gethostbyname_r() function or for which
|
---|
292 | * gethostbyname() is the preferred one.
|
---|
293 | */
|
---|
294 | else {
|
---|
295 | h = gethostbyname((void *)hostname);
|
---|
296 | #endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
|
---|
297 | }
|
---|
298 |
|
---|
299 | if(h) {
|
---|
300 | ai = Curl_he2ai(h, port);
|
---|
301 |
|
---|
302 | if(buf) /* used a *_r() function */
|
---|
303 | free(buf);
|
---|
304 | }
|
---|
305 |
|
---|
306 | return ai;
|
---|
307 | }
|
---|
308 | #endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) */
|
---|