1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 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.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 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25 #include "curl_setup.h"
26
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
29 #endif
30 #ifdef HAVE_SYS_UN_H
31 #include <sys/un.h> /* for sockaddr_un */
32 #endif
33 #ifdef HAVE_LINUX_TCP_H
34 #include <linux/tcp.h>
35 #elif defined(HAVE_NETINET_TCP_H)
36 #include <netinet/tcp.h>
37 #endif
38 #ifdef HAVE_NETINET_UDP_H
39 #include <netinet/udp.h>
40 #endif
41 #ifdef HAVE_SYS_IOCTL_H
42 #include <sys/ioctl.h>
43 #endif
44 #ifdef HAVE_NETDB_H
45 #include <netdb.h>
46 #endif
47 #ifdef HAVE_FCNTL_H
48 #include <fcntl.h>
49 #endif
50 #ifdef HAVE_ARPA_INET_H
51 #include <arpa/inet.h>
52 #endif
53
54 #ifdef __VMS
55 #include <in.h>
56 #include <inet.h>
57 #endif
58
59 #ifdef __DragonFly__
60 /* Required for __DragonFly_version */
61 #include <sys/param.h>
62 #endif
63
64 #include "urldata.h"
65 #include "bufq.h"
66 #include "sendf.h"
67 #include "if2ip.h"
68 #include "strerror.h"
69 #include "cfilters.h"
70 #include "cf-socket.h"
71 #include "connect.h"
72 #include "select.h"
73 #include "url.h" /* for Curl_safefree() */
74 #include "multiif.h"
75 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
76 #include "inet_ntop.h"
77 #include "inet_pton.h"
78 #include "progress.h"
79 #include "warnless.h"
80 #include "conncache.h"
81 #include "multihandle.h"
82 #include "rand.h"
83 #include "share.h"
84 #include "strdup.h"
85 #include "version_win32.h"
86
87 /* The last 3 #include files should be in this order */
88 #include "curl_printf.h"
89 #include "curl_memory.h"
90 #include "memdebug.h"
91
92
93 #if defined(USE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
94 /* It makes support for IPv4-mapped IPv6 addresses.
95 * Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
96 * Windows Vista and later: default is on;
97 * DragonFly BSD: acts like off, and dummy setting;
98 * OpenBSD and earlier Windows: unsupported.
99 * Linux: controlled by /proc/sys/net/ipv6/bindv6only.
100 */
set_ipv6_v6only(curl_socket_t sockfd,int on)101 static void set_ipv6_v6only(curl_socket_t sockfd, int on)
102 {
103 (void)setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on));
104 }
105 #else
106 #define set_ipv6_v6only(x,y)
107 #endif
108
tcpnodelay(struct Curl_easy * data,curl_socket_t sockfd)109 static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
110 {
111 #if defined(TCP_NODELAY)
112 curl_socklen_t onoff = (curl_socklen_t) 1;
113 int level = IPPROTO_TCP;
114 char buffer[STRERROR_LEN];
115
116 if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
117 sizeof(onoff)) < 0)
118 infof(data, "Could not set TCP_NODELAY: %s",
119 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
120 #else
121 (void)data;
122 (void)sockfd;
123 #endif
124 }
125
126 #ifdef SO_NOSIGPIPE
127 /* The preferred method on macOS (10.2 and later) to prevent SIGPIPEs when
128 sending data to a dead peer (instead of relying on the 4th argument to send
129 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
130 systems? */
nosigpipe(struct Curl_easy * data,curl_socket_t sockfd)131 static void nosigpipe(struct Curl_easy *data,
132 curl_socket_t sockfd)
133 {
134 int onoff = 1;
135 (void)data;
136 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
137 sizeof(onoff)) < 0) {
138 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
139 char buffer[STRERROR_LEN];
140 infof(data, "Could not set SO_NOSIGPIPE: %s",
141 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
142 #endif
143 }
144 }
145 #else
146 #define nosigpipe(x,y) Curl_nop_stmt
147 #endif
148
149 #if defined(USE_WINSOCK) && \
150 defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
151 /* Win 10, v 1709 (10.0.16299) and later can use SetSockOpt TCP_KEEP____
152 * so should use seconds */
153 #define CURL_WINSOCK_KEEP_SSO
154 #define KEEPALIVE_FACTOR(x)
155 #elif defined(USE_WINSOCK) || \
156 (defined(__sun) && !defined(TCP_KEEPIDLE)) || \
157 (defined(__DragonFly__) && __DragonFly_version < 500702) || \
158 (defined(_WIN32) && !defined(TCP_KEEPIDLE))
159 /* Solaris < 11.4, DragonFlyBSD < 500702 and Windows < 10.0.16299
160 * use millisecond units. */
161 #define KEEPALIVE_FACTOR(x) (x *= 1000)
162 #else
163 #define KEEPALIVE_FACTOR(x)
164 #endif
165
166 #if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS)
167 #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
168
169 struct tcp_keepalive {
170 u_long onoff;
171 u_long keepalivetime;
172 u_long keepaliveinterval;
173 };
174 #endif
175
176 static void
tcpkeepalive(struct Curl_easy * data,curl_socket_t sockfd)177 tcpkeepalive(struct Curl_easy *data,
178 curl_socket_t sockfd)
179 {
180 int optval = data->set.tcp_keepalive ? 1 : 0;
181
182 /* only set IDLE and INTVL if setting KEEPALIVE is successful */
183 if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
184 (void *)&optval, sizeof(optval)) < 0) {
185 infof(data, "Failed to set SO_KEEPALIVE on fd "
186 "%" FMT_SOCKET_T ": errno %d",
187 sockfd, SOCKERRNO);
188 }
189 else {
190 #if defined(SIO_KEEPALIVE_VALS) /* Windows */
191 /* Windows 10, version 1709 (10.0.16299) and later versions */
192 #if defined(CURL_WINSOCK_KEEP_SSO)
193 optval = curlx_sltosi(data->set.tcp_keepidle);
194 KEEPALIVE_FACTOR(optval);
195 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
196 (const char *)&optval, sizeof(optval)) < 0) {
197 infof(data, "Failed to set TCP_KEEPIDLE on fd "
198 "%" FMT_SOCKET_T ": errno %d",
199 sockfd, SOCKERRNO);
200 }
201 optval = curlx_sltosi(data->set.tcp_keepintvl);
202 KEEPALIVE_FACTOR(optval);
203 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
204 (const char *)&optval, sizeof(optval)) < 0) {
205 infof(data, "Failed to set TCP_KEEPINTVL on fd "
206 "%" FMT_SOCKET_T ": errno %d",
207 sockfd, SOCKERRNO);
208 }
209 optval = curlx_sltosi(data->set.tcp_keepcnt);
210 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
211 (const char *)&optval, sizeof(optval)) < 0) {
212 infof(data, "Failed to set TCP_KEEPCNT on fd "
213 "%" FMT_SOCKET_T ": errno %d",
214 sockfd, SOCKERRNO);
215 }
216 #else /* Windows < 10.0.16299 */
217 struct tcp_keepalive vals;
218 DWORD dummy;
219 vals.onoff = 1;
220 optval = curlx_sltosi(data->set.tcp_keepidle);
221 KEEPALIVE_FACTOR(optval);
222 vals.keepalivetime = (u_long)optval;
223 optval = curlx_sltosi(data->set.tcp_keepintvl);
224 KEEPALIVE_FACTOR(optval);
225 vals.keepaliveinterval = (u_long)optval;
226 if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
227 NULL, 0, &dummy, NULL, NULL) != 0) {
228 infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd "
229 "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
230 }
231 #endif
232 #else /* !Windows */
233 #ifdef TCP_KEEPIDLE
234 optval = curlx_sltosi(data->set.tcp_keepidle);
235 KEEPALIVE_FACTOR(optval);
236 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
237 (void *)&optval, sizeof(optval)) < 0) {
238 infof(data, "Failed to set TCP_KEEPIDLE on fd "
239 "%" FMT_SOCKET_T ": errno %d",
240 sockfd, SOCKERRNO);
241 }
242 #elif defined(TCP_KEEPALIVE)
243 /* macOS style */
244 optval = curlx_sltosi(data->set.tcp_keepidle);
245 KEEPALIVE_FACTOR(optval);
246 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
247 (void *)&optval, sizeof(optval)) < 0) {
248 infof(data, "Failed to set TCP_KEEPALIVE on fd "
249 "%" FMT_SOCKET_T ": errno %d",
250 sockfd, SOCKERRNO);
251 }
252 #elif defined(TCP_KEEPALIVE_THRESHOLD)
253 /* Solaris <11.4 style */
254 optval = curlx_sltosi(data->set.tcp_keepidle);
255 KEEPALIVE_FACTOR(optval);
256 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
257 (void *)&optval, sizeof(optval)) < 0) {
258 infof(data, "Failed to set TCP_KEEPALIVE_THRESHOLD on fd "
259 "%" FMT_SOCKET_T ": errno %d",
260 sockfd, SOCKERRNO);
261 }
262 #endif
263 #ifdef TCP_KEEPINTVL
264 optval = curlx_sltosi(data->set.tcp_keepintvl);
265 KEEPALIVE_FACTOR(optval);
266 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
267 (void *)&optval, sizeof(optval)) < 0) {
268 infof(data, "Failed to set TCP_KEEPINTVL on fd "
269 "%" FMT_SOCKET_T ": errno %d",
270 sockfd, SOCKERRNO);
271 }
272 #elif defined(TCP_KEEPALIVE_ABORT_THRESHOLD)
273 /* Solaris <11.4 style */
274 /* TCP_KEEPALIVE_ABORT_THRESHOLD should equal to
275 * TCP_KEEPCNT * TCP_KEEPINTVL on other platforms.
276 * The default value of TCP_KEEPCNT is 9 on Linux,
277 * 8 on *BSD/macOS, 5 or 10 on Windows. We use the
278 * default config for Solaris <11.4 because there is
279 * no default value for TCP_KEEPCNT on Solaris 11.4.
280 *
281 * Note that the consequent probes will not be sent
282 * at equal intervals on Solaris, but will be sent
283 * using the exponential backoff algorithm. */
284 optval = curlx_sltosi(data->set.tcp_keepcnt) *
285 curlx_sltosi(data->set.tcp_keepintvl);
286 KEEPALIVE_FACTOR(optval);
287 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD,
288 (void *)&optval, sizeof(optval)) < 0) {
289 infof(data, "Failed to set TCP_KEEPALIVE_ABORT_THRESHOLD on fd "
290 "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
291 }
292 #endif
293 #ifdef TCP_KEEPCNT
294 optval = curlx_sltosi(data->set.tcp_keepcnt);
295 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
296 (void *)&optval, sizeof(optval)) < 0) {
297 infof(data, "Failed to set TCP_KEEPCNT on fd "
298 "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
299 }
300 #endif
301 #endif
302 }
303 }
304
305 /**
306 * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
307 * set the transport used.
308 */
Curl_sock_assign_addr(struct Curl_sockaddr_ex * dest,const struct Curl_addrinfo * ai,int transport)309 void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
310 const struct Curl_addrinfo *ai,
311 int transport)
312 {
313 /*
314 * The Curl_sockaddr_ex structure is basically libcurl's external API
315 * curl_sockaddr structure with enough space available to directly hold
316 * any protocol-specific address structures. The variable declared here
317 * will be used to pass / receive data to/from the fopensocket callback
318 * if this has been set, before that, it is initialized from parameters.
319 */
320 dest->family = ai->ai_family;
321 switch(transport) {
322 case TRNSPRT_TCP:
323 dest->socktype = SOCK_STREAM;
324 dest->protocol = IPPROTO_TCP;
325 break;
326 case TRNSPRT_UNIX:
327 dest->socktype = SOCK_STREAM;
328 dest->protocol = IPPROTO_IP;
329 break;
330 default: /* UDP and QUIC */
331 dest->socktype = SOCK_DGRAM;
332 dest->protocol = IPPROTO_UDP;
333 break;
334 }
335 dest->addrlen = (unsigned int)ai->ai_addrlen;
336
337 if(dest->addrlen > sizeof(struct Curl_sockaddr_storage))
338 dest->addrlen = sizeof(struct Curl_sockaddr_storage);
339 memcpy(&dest->curl_sa_addr, ai->ai_addr, dest->addrlen);
340 }
341
socket_open(struct Curl_easy * data,struct Curl_sockaddr_ex * addr,curl_socket_t * sockfd)342 static CURLcode socket_open(struct Curl_easy *data,
343 struct Curl_sockaddr_ex *addr,
344 curl_socket_t *sockfd)
345 {
346 DEBUGASSERT(data);
347 DEBUGASSERT(data->conn);
348 if(data->set.fopensocket) {
349 /*
350 * If the opensocket callback is set, all the destination address
351 * information is passed to the callback. Depending on this information the
352 * callback may opt to abort the connection, this is indicated returning
353 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
354 * the callback returns a valid socket the destination address information
355 * might have been changed and this 'new' address will actually be used
356 * here to connect.
357 */
358 Curl_set_in_callback(data, TRUE);
359 *sockfd = data->set.fopensocket(data->set.opensocket_client,
360 CURLSOCKTYPE_IPCXN,
361 (struct curl_sockaddr *)addr);
362 Curl_set_in_callback(data, FALSE);
363 }
364 else {
365 /* opensocket callback not set, so simply create the socket now */
366 *sockfd = socket(addr->family, addr->socktype, addr->protocol);
367 }
368
369 if(*sockfd == CURL_SOCKET_BAD)
370 /* no socket, no connection */
371 return CURLE_COULDNT_CONNECT;
372
373 #if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
374 if(data->conn->scope_id && (addr->family == AF_INET6)) {
375 struct sockaddr_in6 * const sa6 = (void *)&addr->curl_sa_addr;
376 sa6->sin6_scope_id = data->conn->scope_id;
377 }
378 #endif
379 return CURLE_OK;
380 }
381
382 /*
383 * Create a socket based on info from 'conn' and 'ai'.
384 *
385 * 'addr' should be a pointer to the correct struct to get data back, or NULL.
386 * 'sockfd' must be a pointer to a socket descriptor.
387 *
388 * If the open socket callback is set, used that!
389 *
390 */
Curl_socket_open(struct Curl_easy * data,const struct Curl_addrinfo * ai,struct Curl_sockaddr_ex * addr,int transport,curl_socket_t * sockfd)391 CURLcode Curl_socket_open(struct Curl_easy *data,
392 const struct Curl_addrinfo *ai,
393 struct Curl_sockaddr_ex *addr,
394 int transport,
395 curl_socket_t *sockfd)
396 {
397 struct Curl_sockaddr_ex dummy;
398
399 if(!addr)
400 /* if the caller does not want info back, use a local temp copy */
401 addr = &dummy;
402
403 Curl_sock_assign_addr(addr, ai, transport);
404 return socket_open(data, addr, sockfd);
405 }
406
socket_close(struct Curl_easy * data,struct connectdata * conn,int use_callback,curl_socket_t sock)407 static int socket_close(struct Curl_easy *data, struct connectdata *conn,
408 int use_callback, curl_socket_t sock)
409 {
410 if(CURL_SOCKET_BAD == sock)
411 return 0;
412
413 if(use_callback && conn && conn->fclosesocket) {
414 int rc;
415 Curl_multi_closed(data, sock);
416 Curl_set_in_callback(data, TRUE);
417 rc = conn->fclosesocket(conn->closesocket_client, sock);
418 Curl_set_in_callback(data, FALSE);
419 return rc;
420 }
421
422 if(conn)
423 /* tell the multi-socket code about this */
424 Curl_multi_closed(data, sock);
425
426 sclose(sock);
427
428 return 0;
429 }
430
431 /*
432 * Close a socket.
433 *
434 * 'conn' can be NULL, beware!
435 */
Curl_socket_close(struct Curl_easy * data,struct connectdata * conn,curl_socket_t sock)436 int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
437 curl_socket_t sock)
438 {
439 return socket_close(data, conn, FALSE, sock);
440 }
441
442 #ifdef USE_WINSOCK
443 /* When you run a program that uses the Windows Sockets API, you may
444 experience slow performance when you copy data to a TCP server.
445
446 https://support.microsoft.com/kb/823764
447
448 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
449 Buffer Size
450
451 The problem described in this knowledge-base is applied only to pre-Vista
452 Windows. Following function trying to detect OS version and skips
453 SO_SNDBUF adjustment for Windows Vista and above.
454 */
455 #define DETECT_OS_NONE 0
456 #define DETECT_OS_PREVISTA 1
457 #define DETECT_OS_VISTA_OR_LATER 2
458
Curl_sndbuf_init(curl_socket_t sockfd)459 void Curl_sndbuf_init(curl_socket_t sockfd)
460 {
461 int val = CURL_MAX_WRITE_SIZE + 32;
462 int curval = 0;
463 int curlen = sizeof(curval);
464
465 static int detectOsState = DETECT_OS_NONE;
466
467 if(detectOsState == DETECT_OS_NONE) {
468 if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
469 VERSION_GREATER_THAN_EQUAL))
470 detectOsState = DETECT_OS_VISTA_OR_LATER;
471 else
472 detectOsState = DETECT_OS_PREVISTA;
473 }
474
475 if(detectOsState == DETECT_OS_VISTA_OR_LATER)
476 return;
477
478 if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
479 if(curval > val)
480 return;
481
482 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
483 }
484 #endif /* USE_WINSOCK */
485
486 /*
487 * Curl_parse_interface()
488 *
489 * This is used to parse interface argument in the following formats.
490 * In all the examples, `host` can be an IP address or a hostname.
491 *
492 * <iface_or_host> - can be either an interface name or a host.
493 * if!<iface> - interface name.
494 * host!<host> - hostname.
495 * ifhost!<iface>!<host> - interface name and hostname.
496 *
497 * Parameters:
498 *
499 * input [in] - input string.
500 * len [in] - length of the input string.
501 * dev [in/out] - address where a pointer to newly allocated memory
502 * holding the interface-or-host will be stored upon
503 * completion.
504 * iface [in/out] - address where a pointer to newly allocated memory
505 * holding the interface will be stored upon completion.
506 * host [in/out] - address where a pointer to newly allocated memory
507 * holding the host will be stored upon completion.
508 *
509 * Returns CURLE_OK on success.
510 */
Curl_parse_interface(const char * input,char ** dev,char ** iface,char ** host)511 CURLcode Curl_parse_interface(const char *input,
512 char **dev, char **iface, char **host)
513 {
514 static const char if_prefix[] = "if!";
515 static const char host_prefix[] = "host!";
516 static const char if_host_prefix[] = "ifhost!";
517 size_t len;
518
519 DEBUGASSERT(dev);
520 DEBUGASSERT(iface);
521 DEBUGASSERT(host);
522
523 len = strlen(input);
524 if(len > 512)
525 return CURLE_BAD_FUNCTION_ARGUMENT;
526
527 if(!strncmp(if_prefix, input, strlen(if_prefix))) {
528 input += strlen(if_prefix);
529 if(!*input)
530 return CURLE_BAD_FUNCTION_ARGUMENT;
531 *iface = Curl_memdup0(input, len - strlen(if_prefix));
532 return *iface ? CURLE_OK : CURLE_OUT_OF_MEMORY;
533 }
534 else if(!strncmp(host_prefix, input, strlen(host_prefix))) {
535 input += strlen(host_prefix);
536 if(!*input)
537 return CURLE_BAD_FUNCTION_ARGUMENT;
538 *host = Curl_memdup0(input, len - strlen(host_prefix));
539 return *host ? CURLE_OK : CURLE_OUT_OF_MEMORY;
540 }
541 else if(!strncmp(if_host_prefix, input, strlen(if_host_prefix))) {
542 const char *host_part;
543 input += strlen(if_host_prefix);
544 len -= strlen(if_host_prefix);
545 host_part = memchr(input, '!', len);
546 if(!host_part || !*(host_part + 1))
547 return CURLE_BAD_FUNCTION_ARGUMENT;
548 *iface = Curl_memdup0(input, host_part - input);
549 if(!*iface)
550 return CURLE_OUT_OF_MEMORY;
551 ++host_part;
552 *host = Curl_memdup0(host_part, len - (host_part - input));
553 if(!*host) {
554 free(*iface);
555 *iface = NULL;
556 return CURLE_OUT_OF_MEMORY;
557 }
558 return CURLE_OK;
559 }
560
561 if(!*input)
562 return CURLE_BAD_FUNCTION_ARGUMENT;
563 *dev = Curl_memdup0(input, len);
564 return *dev ? CURLE_OK : CURLE_OUT_OF_MEMORY;
565 }
566
567 #ifndef CURL_DISABLE_BINDLOCAL
bindlocal(struct Curl_easy * data,struct connectdata * conn,curl_socket_t sockfd,int af,unsigned int scope)568 static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
569 curl_socket_t sockfd, int af, unsigned int scope)
570 {
571 struct Curl_sockaddr_storage sa;
572 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
573 curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
574 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
575 #ifdef USE_IPV6
576 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
577 #endif
578
579 struct Curl_dns_entry *h = NULL;
580 unsigned short port = data->set.localport; /* use this port number, 0 for
581 "random" */
582 /* how many port numbers to try to bind to, increasing one at a time */
583 int portnum = data->set.localportrange;
584 const char *dev = data->set.str[STRING_DEVICE];
585 const char *iface_input = data->set.str[STRING_INTERFACE];
586 const char *host_input = data->set.str[STRING_BINDHOST];
587 const char *iface = iface_input ? iface_input : dev;
588 const char *host = host_input ? host_input : dev;
589 int error;
590 #ifdef IP_BIND_ADDRESS_NO_PORT
591 int on = 1;
592 #endif
593 #ifndef USE_IPV6
594 (void)scope;
595 #endif
596
597 /*************************************************************
598 * Select device to bind socket to
599 *************************************************************/
600 if(!iface && !host && !port)
601 /* no local kind of binding was requested */
602 return CURLE_OK;
603
604 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
605
606 if(iface && (strlen(iface) < 255) ) {
607 char myhost[256] = "";
608 int done = 0; /* -1 for error, 1 for address found */
609 if2ip_result_t if2ip_result = IF2IP_NOT_FOUND;
610
611 /* interface */
612 #ifdef SO_BINDTODEVICE
613 /*
614 * This binds the local socket to a particular interface. This will
615 * force even requests to other local interfaces to go out the external
616 * interface. Only bind to the interface when specified as interface,
617 * not just as a hostname or ip address.
618 *
619 * The interface might be a VRF, eg: vrf-blue, which means it cannot be
620 * converted to an IP address and would fail Curl_if2ip. Simply try to
621 * use it straight away.
622 */
623 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
624 iface, (curl_socklen_t)strlen(iface) + 1) == 0) {
625 /* This is often "errno 1, error: Operation not permitted" if you are
626 * not running as root or another suitable privileged user. If it
627 * succeeds it means the parameter was a valid interface and not an IP
628 * address. Return immediately.
629 */
630 if(!host_input) {
631 infof(data, "socket successfully bound to interface '%s'", iface);
632 return CURLE_OK;
633 }
634 }
635 #endif
636 if(!host_input) {
637 /* Discover IP from input device, then bind to it */
638 if2ip_result = Curl_if2ip(af,
639 #ifdef USE_IPV6
640 scope, conn->scope_id,
641 #endif
642 iface, myhost, sizeof(myhost));
643 }
644 switch(if2ip_result) {
645 case IF2IP_NOT_FOUND:
646 if(iface_input && !host_input) {
647 /* Do not fall back to treating it as a hostname */
648 char buffer[STRERROR_LEN];
649 data->state.os_errno = error = SOCKERRNO;
650 failf(data, "Couldn't bind to interface '%s' with errno %d: %s",
651 iface, error, Curl_strerror(error, buffer, sizeof(buffer)));
652 return CURLE_INTERFACE_FAILED;
653 }
654 break;
655 case IF2IP_AF_NOT_SUPPORTED:
656 /* Signal the caller to try another address family if available */
657 return CURLE_UNSUPPORTED_PROTOCOL;
658 case IF2IP_FOUND:
659 /*
660 * We now have the numerical IP address in the 'myhost' buffer
661 */
662 host = myhost;
663 infof(data, "Local Interface %s is ip %s using address family %i",
664 iface, host, af);
665 done = 1;
666 break;
667 }
668 if(!iface_input || host_input) {
669 /*
670 * This was not an interface, resolve the name as a hostname
671 * or IP number
672 *
673 * Temporarily force name resolution to use only the address type
674 * of the connection. The resolve functions should really be changed
675 * to take a type parameter instead.
676 */
677 unsigned char ipver = conn->ip_version;
678 int rc;
679
680 if(af == AF_INET)
681 conn->ip_version = CURL_IPRESOLVE_V4;
682 #ifdef USE_IPV6
683 else if(af == AF_INET6)
684 conn->ip_version = CURL_IPRESOLVE_V6;
685 #endif
686
687 rc = Curl_resolv(data, host, 80, FALSE, &h);
688 if(rc == CURLRESOLV_PENDING)
689 (void)Curl_resolver_wait_resolv(data, &h);
690 conn->ip_version = ipver;
691
692 if(h) {
693 int h_af = h->addr->ai_family;
694 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
695 Curl_printable_address(h->addr, myhost, sizeof(myhost));
696 infof(data, "Name '%s' family %i resolved to '%s' family %i",
697 host, af, myhost, h_af);
698 Curl_resolv_unlink(data, &h); /* this will NULL, potential free h */
699 if(af != h_af) {
700 /* bad IP version combo, signal the caller to try another address
701 family if available */
702 return CURLE_UNSUPPORTED_PROTOCOL;
703 }
704 done = 1;
705 }
706 else {
707 /*
708 * provided dev was no interface (or interfaces are not supported
709 * e.g. Solaris) no ip address and no domain we fail here
710 */
711 done = -1;
712 }
713 }
714
715 if(done > 0) {
716 #ifdef USE_IPV6
717 /* IPv6 address */
718 if(af == AF_INET6) {
719 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
720 char *scope_ptr = strchr(myhost, '%');
721 if(scope_ptr)
722 *(scope_ptr++) = '\0';
723 #endif
724 if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
725 si6->sin6_family = AF_INET6;
726 si6->sin6_port = htons(port);
727 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
728 if(scope_ptr) {
729 /* The "myhost" string either comes from Curl_if2ip or from
730 Curl_printable_address. The latter returns only numeric scope
731 IDs and the former returns none at all. So the scope ID, if
732 present, is known to be numeric */
733 unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
734 if(scope_id > UINT_MAX)
735 return CURLE_UNSUPPORTED_PROTOCOL;
736
737 si6->sin6_scope_id = (unsigned int)scope_id;
738 }
739 #endif
740 }
741 sizeof_sa = sizeof(struct sockaddr_in6);
742 }
743 else
744 #endif
745 /* IPv4 address */
746 if((af == AF_INET) &&
747 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
748 si4->sin_family = AF_INET;
749 si4->sin_port = htons(port);
750 sizeof_sa = sizeof(struct sockaddr_in);
751 }
752 }
753
754 if(done < 1) {
755 /* errorbuf is set false so failf will overwrite any message already in
756 the error buffer, so the user receives this error message instead of a
757 generic resolve error. */
758 char buffer[STRERROR_LEN];
759 data->state.errorbuf = FALSE;
760 data->state.os_errno = error = SOCKERRNO;
761 failf(data, "Couldn't bind to '%s' with errno %d: %s",
762 host, error, Curl_strerror(error, buffer, sizeof(buffer)));
763 return CURLE_INTERFACE_FAILED;
764 }
765 }
766 else {
767 /* no device was given, prepare sa to match af's needs */
768 #ifdef USE_IPV6
769 if(af == AF_INET6) {
770 si6->sin6_family = AF_INET6;
771 si6->sin6_port = htons(port);
772 sizeof_sa = sizeof(struct sockaddr_in6);
773 }
774 else
775 #endif
776 if(af == AF_INET) {
777 si4->sin_family = AF_INET;
778 si4->sin_port = htons(port);
779 sizeof_sa = sizeof(struct sockaddr_in);
780 }
781 }
782 #ifdef IP_BIND_ADDRESS_NO_PORT
783 (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
784 #endif
785 for(;;) {
786 if(bind(sockfd, sock, sizeof_sa) >= 0) {
787 /* we succeeded to bind */
788 infof(data, "Local port: %hu", port);
789 conn->bits.bound = TRUE;
790 return CURLE_OK;
791 }
792
793 if(--portnum > 0) {
794 port++; /* try next port */
795 if(port == 0)
796 break;
797 infof(data, "Bind to local port %d failed, trying next", port - 1);
798 /* We reuse/clobber the port variable here below */
799 if(sock->sa_family == AF_INET)
800 si4->sin_port = ntohs(port);
801 #ifdef USE_IPV6
802 else
803 si6->sin6_port = ntohs(port);
804 #endif
805 }
806 else
807 break;
808 }
809 {
810 char buffer[STRERROR_LEN];
811 data->state.os_errno = error = SOCKERRNO;
812 failf(data, "bind failed with errno %d: %s",
813 error, Curl_strerror(error, buffer, sizeof(buffer)));
814 }
815
816 return CURLE_INTERFACE_FAILED;
817 }
818 #endif
819
820 /*
821 * verifyconnect() returns TRUE if the connect really has happened.
822 */
verifyconnect(curl_socket_t sockfd,int * error)823 static bool verifyconnect(curl_socket_t sockfd, int *error)
824 {
825 bool rc = TRUE;
826 #ifdef SO_ERROR
827 int err = 0;
828 curl_socklen_t errSize = sizeof(err);
829
830 #ifdef _WIN32
831 /*
832 * In October 2003 we effectively nullified this function on Windows due to
833 * problems with it using all CPU in multi-threaded cases.
834 *
835 * In May 2004, we bring it back to offer more info back on connect failures.
836 * Gisle Vanem could reproduce the former problems with this function, but
837 * could avoid them by adding this SleepEx() call below:
838 *
839 * "I do not have Rational Quantify, but the hint from his post was
840 * ntdll::NtRemoveIoCompletion(). I would assume the SleepEx (or maybe
841 * just Sleep(0) would be enough?) would release whatever
842 * mutex/critical-section the ntdll call is waiting on.
843 *
844 * Someone got to verify this on Win-NT 4.0, 2000."
845 */
846
847 #ifdef _WIN32_WCE
848 Sleep(0);
849 #else
850 SleepEx(0, FALSE);
851 #endif
852
853 #endif
854
855 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
856 err = SOCKERRNO;
857 #ifdef _WIN32_WCE
858 /* Old Windows CE versions do not support SO_ERROR */
859 if(WSAENOPROTOOPT == err) {
860 SET_SOCKERRNO(0);
861 err = 0;
862 }
863 #endif
864 #if defined(EBADIOCTL) && defined(__minix)
865 /* Minix 3.1.x does not support getsockopt on UDP sockets */
866 if(EBADIOCTL == err) {
867 SET_SOCKERRNO(0);
868 err = 0;
869 }
870 #endif
871 if((0 == err) || (EISCONN == err))
872 /* we are connected, awesome! */
873 rc = TRUE;
874 else
875 /* This was not a successful connect */
876 rc = FALSE;
877 if(error)
878 *error = err;
879 #else
880 (void)sockfd;
881 if(error)
882 *error = SOCKERRNO;
883 #endif
884 return rc;
885 }
886
887 /**
888 * Determine the curl code for a socket connect() == -1 with errno.
889 */
socket_connect_result(struct Curl_easy * data,const char * ipaddress,int error)890 static CURLcode socket_connect_result(struct Curl_easy *data,
891 const char *ipaddress, int error)
892 {
893 switch(error) {
894 case EINPROGRESS:
895 case EWOULDBLOCK:
896 #if defined(EAGAIN)
897 #if (EAGAIN) != (EWOULDBLOCK)
898 /* On some platforms EAGAIN and EWOULDBLOCK are the
899 * same value, and on others they are different, hence
900 * the odd #if
901 */
902 case EAGAIN:
903 #endif
904 #endif
905 return CURLE_OK;
906
907 default:
908 /* unknown error, fallthrough and try another address! */
909 #ifdef CURL_DISABLE_VERBOSE_STRINGS
910 (void)ipaddress;
911 #else
912 {
913 char buffer[STRERROR_LEN];
914 infof(data, "Immediate connect fail for %s: %s",
915 ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
916 }
917 #endif
918 data->state.os_errno = error;
919 /* connect failed */
920 return CURLE_COULDNT_CONNECT;
921 }
922 }
923
924 /* We have a recv buffer to enhance reads with len < NW_SMALL_READS.
925 * This happens often on TLS connections where the TLS implementation
926 * tries to read the head of a TLS record, determine the length of the
927 * full record and then make a subsequent read for that.
928 * On large reads, we will not fill the buffer to avoid the double copy. */
929 #define NW_RECV_CHUNK_SIZE (64 * 1024)
930 #define NW_RECV_CHUNKS 1
931 #define NW_SMALL_READS (1024)
932
933 struct cf_socket_ctx {
934 int transport;
935 struct Curl_sockaddr_ex addr; /* address to connect to */
936 curl_socket_t sock; /* current attempt socket */
937 struct ip_quadruple ip; /* The IP quadruple 2x(addr+port) */
938 struct curltime started_at; /* when socket was created */
939 struct curltime connected_at; /* when socket connected/got first byte */
940 struct curltime first_byte_at; /* when first byte was recvd */
941 #ifdef USE_WINSOCK
942 struct curltime last_sndbuf_query_at; /* when SO_SNDBUF last queried */
943 ULONG sndbuf_size; /* the last set SO_SNDBUF size */
944 #endif
945 int error; /* errno of last failure or 0 */
946 #ifdef DEBUGBUILD
947 int wblock_percent; /* percent of writes doing EAGAIN */
948 int wpartial_percent; /* percent of bytes written in send */
949 int rblock_percent; /* percent of reads doing EAGAIN */
950 size_t recv_max; /* max enforced read size */
951 #endif
952 BIT(got_first_byte); /* if first byte was received */
953 BIT(listening); /* socket is listening */
954 BIT(accepted); /* socket was accepted, not connected */
955 BIT(sock_connected); /* socket is "connected", e.g. in UDP */
956 BIT(active);
957 };
958
cf_socket_ctx_init(struct cf_socket_ctx * ctx,const struct Curl_addrinfo * ai,int transport)959 static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
960 const struct Curl_addrinfo *ai,
961 int transport)
962 {
963 memset(ctx, 0, sizeof(*ctx));
964 ctx->sock = CURL_SOCKET_BAD;
965 ctx->transport = transport;
966 Curl_sock_assign_addr(&ctx->addr, ai, transport);
967 #ifdef DEBUGBUILD
968 {
969 char *p = getenv("CURL_DBG_SOCK_WBLOCK");
970 if(p) {
971 long l = strtol(p, NULL, 10);
972 if(l >= 0 && l <= 100)
973 ctx->wblock_percent = (int)l;
974 }
975 p = getenv("CURL_DBG_SOCK_WPARTIAL");
976 if(p) {
977 long l = strtol(p, NULL, 10);
978 if(l >= 0 && l <= 100)
979 ctx->wpartial_percent = (int)l;
980 }
981 p = getenv("CURL_DBG_SOCK_RBLOCK");
982 if(p) {
983 long l = strtol(p, NULL, 10);
984 if(l >= 0 && l <= 100)
985 ctx->rblock_percent = (int)l;
986 }
987 p = getenv("CURL_DBG_SOCK_RMAX");
988 if(p) {
989 long l = strtol(p, NULL, 10);
990 if(l >= 0)
991 ctx->recv_max = (size_t)l;
992 }
993 }
994 #endif
995 }
996
cf_socket_close(struct Curl_cfilter * cf,struct Curl_easy * data)997 static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
998 {
999 struct cf_socket_ctx *ctx = cf->ctx;
1000
1001 if(ctx && CURL_SOCKET_BAD != ctx->sock) {
1002 CURL_TRC_CF(data, cf, "cf_socket_close(%" FMT_SOCKET_T ")", ctx->sock);
1003 if(ctx->sock == cf->conn->sock[cf->sockindex])
1004 cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
1005 socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
1006 ctx->sock = CURL_SOCKET_BAD;
1007 if(ctx->active && cf->sockindex == FIRSTSOCKET)
1008 cf->conn->remote_addr = NULL;
1009 ctx->active = FALSE;
1010 memset(&ctx->started_at, 0, sizeof(ctx->started_at));
1011 memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
1012 }
1013
1014 cf->connected = FALSE;
1015 }
1016
cf_socket_shutdown(struct Curl_cfilter * cf,struct Curl_easy * data,bool * done)1017 static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
1018 struct Curl_easy *data,
1019 bool *done)
1020 {
1021 if(cf->connected) {
1022 struct cf_socket_ctx *ctx = cf->ctx;
1023
1024 CURL_TRC_CF(data, cf, "cf_socket_shutdown(%" FMT_SOCKET_T ")", ctx->sock);
1025 /* On TCP, and when the socket looks well and non-blocking mode
1026 * can be enabled, receive dangling bytes before close to avoid
1027 * entering RST states unnecessarily. */
1028 if(ctx->sock != CURL_SOCKET_BAD &&
1029 ctx->transport == TRNSPRT_TCP &&
1030 (curlx_nonblock(ctx->sock, TRUE) >= 0)) {
1031 unsigned char buf[1024];
1032 (void)sread(ctx->sock, buf, sizeof(buf));
1033 }
1034 }
1035 *done = TRUE;
1036 return CURLE_OK;
1037 }
1038
cf_socket_destroy(struct Curl_cfilter * cf,struct Curl_easy * data)1039 static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
1040 {
1041 struct cf_socket_ctx *ctx = cf->ctx;
1042
1043 cf_socket_close(cf, data);
1044 CURL_TRC_CF(data, cf, "destroy");
1045 free(ctx);
1046 cf->ctx = NULL;
1047 }
1048
set_local_ip(struct Curl_cfilter * cf,struct Curl_easy * data)1049 static CURLcode set_local_ip(struct Curl_cfilter *cf,
1050 struct Curl_easy *data)
1051 {
1052 struct cf_socket_ctx *ctx = cf->ctx;
1053
1054 #ifdef HAVE_GETSOCKNAME
1055 if((ctx->sock != CURL_SOCKET_BAD) &&
1056 !(data->conn->handler->protocol & CURLPROTO_TFTP)) {
1057 /* TFTP does not connect, so it cannot get the IP like this */
1058
1059 char buffer[STRERROR_LEN];
1060 struct Curl_sockaddr_storage ssloc;
1061 curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage);
1062
1063 memset(&ssloc, 0, sizeof(ssloc));
1064 if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) {
1065 int error = SOCKERRNO;
1066 failf(data, "getsockname() failed with errno %d: %s",
1067 error, Curl_strerror(error, buffer, sizeof(buffer)));
1068 return CURLE_FAILED_INIT;
1069 }
1070 if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
1071 ctx->ip.local_ip, &ctx->ip.local_port)) {
1072 failf(data, "ssloc inet_ntop() failed with errno %d: %s",
1073 errno, Curl_strerror(errno, buffer, sizeof(buffer)));
1074 return CURLE_FAILED_INIT;
1075 }
1076 }
1077 #else
1078 (void)data;
1079 ctx->ip.local_ip[0] = 0;
1080 ctx->ip.local_port = -1;
1081 #endif
1082 return CURLE_OK;
1083 }
1084
set_remote_ip(struct Curl_cfilter * cf,struct Curl_easy * data)1085 static CURLcode set_remote_ip(struct Curl_cfilter *cf,
1086 struct Curl_easy *data)
1087 {
1088 struct cf_socket_ctx *ctx = cf->ctx;
1089
1090 /* store remote address and port used in this connection attempt */
1091 if(!Curl_addr2string(&ctx->addr.curl_sa_addr,
1092 (curl_socklen_t)ctx->addr.addrlen,
1093 ctx->ip.remote_ip, &ctx->ip.remote_port)) {
1094 char buffer[STRERROR_LEN];
1095
1096 ctx->error = errno;
1097 /* malformed address or bug in inet_ntop, try next address */
1098 failf(data, "curl_sa_addr inet_ntop() failed with errno %d: %s",
1099 errno, Curl_strerror(errno, buffer, sizeof(buffer)));
1100 return CURLE_FAILED_INIT;
1101 }
1102 return CURLE_OK;
1103 }
1104
cf_socket_open(struct Curl_cfilter * cf,struct Curl_easy * data)1105 static CURLcode cf_socket_open(struct Curl_cfilter *cf,
1106 struct Curl_easy *data)
1107 {
1108 struct cf_socket_ctx *ctx = cf->ctx;
1109 int error = 0;
1110 bool isconnected = FALSE;
1111 CURLcode result = CURLE_COULDNT_CONNECT;
1112 bool is_tcp;
1113
1114 (void)data;
1115 DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
1116 ctx->started_at = Curl_now();
1117 #ifdef SOCK_NONBLOCK
1118 /* Do not tuck SOCK_NONBLOCK into socktype when opensocket callback is set
1119 * because we would not know how socketype is about to be used in the
1120 * callback, SOCK_NONBLOCK might get factored out before calling socket().
1121 */
1122 if(!data->set.fopensocket)
1123 ctx->addr.socktype |= SOCK_NONBLOCK;
1124 #endif
1125 result = socket_open(data, &ctx->addr, &ctx->sock);
1126 #ifdef SOCK_NONBLOCK
1127 /* Restore the socktype after the socket is created. */
1128 if(!data->set.fopensocket)
1129 ctx->addr.socktype &= ~SOCK_NONBLOCK;
1130 #endif
1131 if(result)
1132 goto out;
1133
1134 result = set_remote_ip(cf, data);
1135 if(result)
1136 goto out;
1137
1138 #ifdef USE_IPV6
1139 if(ctx->addr.family == AF_INET6) {
1140 set_ipv6_v6only(ctx->sock, 0);
1141 infof(data, " Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
1142 }
1143 else
1144 #endif
1145 infof(data, " Trying %s:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
1146
1147 #ifdef USE_IPV6
1148 is_tcp = (ctx->addr.family == AF_INET
1149 || ctx->addr.family == AF_INET6) &&
1150 ctx->addr.socktype == SOCK_STREAM;
1151 #else
1152 is_tcp = (ctx->addr.family == AF_INET) &&
1153 ctx->addr.socktype == SOCK_STREAM;
1154 #endif
1155 if(is_tcp && data->set.tcp_nodelay)
1156 tcpnodelay(data, ctx->sock);
1157
1158 nosigpipe(data, ctx->sock);
1159
1160 Curl_sndbuf_init(ctx->sock);
1161
1162 if(is_tcp && data->set.tcp_keepalive)
1163 tcpkeepalive(data, ctx->sock);
1164
1165 if(data->set.fsockopt) {
1166 /* activate callback for setting socket options */
1167 Curl_set_in_callback(data, TRUE);
1168 error = data->set.fsockopt(data->set.sockopt_client,
1169 ctx->sock,
1170 CURLSOCKTYPE_IPCXN);
1171 Curl_set_in_callback(data, FALSE);
1172
1173 if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
1174 isconnected = TRUE;
1175 else if(error) {
1176 result = CURLE_ABORTED_BY_CALLBACK;
1177 goto out;
1178 }
1179 }
1180
1181 #ifndef CURL_DISABLE_BINDLOCAL
1182 /* possibly bind the local end to an IP, interface or port */
1183 if(ctx->addr.family == AF_INET
1184 #ifdef USE_IPV6
1185 || ctx->addr.family == AF_INET6
1186 #endif
1187 ) {
1188 result = bindlocal(data, cf->conn, ctx->sock, ctx->addr.family,
1189 Curl_ipv6_scope(&ctx->addr.curl_sa_addr));
1190 if(result) {
1191 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
1192 /* The address family is not supported on this interface.
1193 We can continue trying addresses */
1194 result = CURLE_COULDNT_CONNECT;
1195 }
1196 goto out;
1197 }
1198 }
1199 #endif
1200
1201 #ifndef SOCK_NONBLOCK
1202 /* Set socket non-blocking, must be a non-blocking socket for
1203 * a non-blocking connect. */
1204 error = curlx_nonblock(ctx->sock, TRUE);
1205 if(error < 0) {
1206 result = CURLE_UNSUPPORTED_PROTOCOL;
1207 ctx->error = SOCKERRNO;
1208 goto out;
1209 }
1210 #else
1211 if(data->set.fopensocket) {
1212 /* Set socket non-blocking, must be a non-blocking socket for
1213 * a non-blocking connect. */
1214 error = curlx_nonblock(ctx->sock, TRUE);
1215 if(error < 0) {
1216 result = CURLE_UNSUPPORTED_PROTOCOL;
1217 ctx->error = SOCKERRNO;
1218 goto out;
1219 }
1220 }
1221 #endif
1222 ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
1223 out:
1224 if(result) {
1225 if(ctx->sock != CURL_SOCKET_BAD) {
1226 socket_close(data, cf->conn, TRUE, ctx->sock);
1227 ctx->sock = CURL_SOCKET_BAD;
1228 }
1229 }
1230 else if(isconnected) {
1231 set_local_ip(cf, data);
1232 ctx->connected_at = Curl_now();
1233 cf->connected = TRUE;
1234 }
1235 CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" FMT_SOCKET_T,
1236 result, ctx->sock);
1237 return result;
1238 }
1239
do_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool is_tcp_fastopen)1240 static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
1241 bool is_tcp_fastopen)
1242 {
1243 struct cf_socket_ctx *ctx = cf->ctx;
1244 #ifdef TCP_FASTOPEN_CONNECT
1245 int optval = 1;
1246 #endif
1247 int rc = -1;
1248
1249 (void)data;
1250 if(is_tcp_fastopen) {
1251 #if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
1252 # if defined(HAVE_BUILTIN_AVAILABLE)
1253 /* while connectx function is available since macOS 10.11 / iOS 9,
1254 it did not have the interface declared correctly until
1255 Xcode 9 / macOS SDK 10.13 */
1256 if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
1257 sa_endpoints_t endpoints;
1258 endpoints.sae_srcif = 0;
1259 endpoints.sae_srcaddr = NULL;
1260 endpoints.sae_srcaddrlen = 0;
1261 endpoints.sae_dstaddr = &ctx->addr.curl_sa_addr;
1262 endpoints.sae_dstaddrlen = ctx->addr.addrlen;
1263
1264 rc = connectx(ctx->sock, &endpoints, SAE_ASSOCID_ANY,
1265 CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
1266 NULL, 0, NULL, NULL);
1267 }
1268 else {
1269 rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1270 }
1271 # else
1272 rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1273 # endif /* HAVE_BUILTIN_AVAILABLE */
1274 #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
1275 if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
1276 (void *)&optval, sizeof(optval)) < 0)
1277 infof(data, "Failed to enable TCP Fast Open on fd %" FMT_SOCKET_T,
1278 ctx->sock);
1279
1280 rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1281 #elif defined(MSG_FASTOPEN) /* old Linux */
1282 if(cf->conn->given->flags & PROTOPT_SSL)
1283 rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1284 else
1285 rc = 0; /* Do nothing */
1286 #endif
1287 }
1288 else {
1289 rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
1290 (curl_socklen_t)ctx->addr.addrlen);
1291 }
1292 return rc;
1293 }
1294
cf_tcp_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1295 static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
1296 struct Curl_easy *data,
1297 bool blocking, bool *done)
1298 {
1299 struct cf_socket_ctx *ctx = cf->ctx;
1300 CURLcode result = CURLE_COULDNT_CONNECT;
1301 int rc = 0;
1302
1303 (void)data;
1304 if(cf->connected) {
1305 *done = TRUE;
1306 return CURLE_OK;
1307 }
1308
1309 /* TODO: need to support blocking connect? */
1310 if(blocking)
1311 return CURLE_UNSUPPORTED_PROTOCOL;
1312
1313 *done = FALSE; /* a negative world view is best */
1314 if(ctx->sock == CURL_SOCKET_BAD) {
1315 int error;
1316
1317 result = cf_socket_open(cf, data);
1318 if(result)
1319 goto out;
1320
1321 if(cf->connected) {
1322 *done = TRUE;
1323 return CURLE_OK;
1324 }
1325
1326 /* Connect TCP socket */
1327 rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
1328 error = SOCKERRNO;
1329 set_local_ip(cf, data);
1330 CURL_TRC_CF(data, cf, "local address %s port %d...",
1331 ctx->ip.local_ip, ctx->ip.local_port);
1332 if(-1 == rc) {
1333 result = socket_connect_result(data, ctx->ip.remote_ip, error);
1334 goto out;
1335 }
1336 }
1337
1338 #ifdef mpeix
1339 /* Call this function once now, and ignore the results. We do this to
1340 "clear" the error state on the socket so that we can later read it
1341 reliably. This is reported necessary on the MPE/iX operating
1342 system. */
1343 (void)verifyconnect(ctx->sock, NULL);
1344 #endif
1345 /* check socket for connect */
1346 rc = SOCKET_WRITABLE(ctx->sock, 0);
1347
1348 if(rc == 0) { /* no connection yet */
1349 CURL_TRC_CF(data, cf, "not connected yet");
1350 return CURLE_OK;
1351 }
1352 else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
1353 if(verifyconnect(ctx->sock, &ctx->error)) {
1354 /* we are connected with TCP, awesome! */
1355 ctx->connected_at = Curl_now();
1356 set_local_ip(cf, data);
1357 *done = TRUE;
1358 cf->connected = TRUE;
1359 CURL_TRC_CF(data, cf, "connected");
1360 return CURLE_OK;
1361 }
1362 }
1363 else if(rc & CURL_CSELECT_ERR) {
1364 (void)verifyconnect(ctx->sock, &ctx->error);
1365 result = CURLE_COULDNT_CONNECT;
1366 }
1367
1368 out:
1369 if(result) {
1370 if(ctx->error) {
1371 set_local_ip(cf, data);
1372 data->state.os_errno = ctx->error;
1373 SET_SOCKERRNO(ctx->error);
1374 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1375 {
1376 char buffer[STRERROR_LEN];
1377 infof(data, "connect to %s port %u from %s port %d failed: %s",
1378 ctx->ip.remote_ip, ctx->ip.remote_port,
1379 ctx->ip.local_ip, ctx->ip.local_port,
1380 Curl_strerror(ctx->error, buffer, sizeof(buffer)));
1381 }
1382 #endif
1383 }
1384 if(ctx->sock != CURL_SOCKET_BAD) {
1385 socket_close(data, cf->conn, TRUE, ctx->sock);
1386 ctx->sock = CURL_SOCKET_BAD;
1387 }
1388 *done = FALSE;
1389 }
1390 return result;
1391 }
1392
cf_socket_get_host(struct Curl_cfilter * cf,struct Curl_easy * data,const char ** phost,const char ** pdisplay_host,int * pport)1393 static void cf_socket_get_host(struct Curl_cfilter *cf,
1394 struct Curl_easy *data,
1395 const char **phost,
1396 const char **pdisplay_host,
1397 int *pport)
1398 {
1399 struct cf_socket_ctx *ctx = cf->ctx;
1400 (void)data;
1401 *phost = cf->conn->host.name;
1402 *pdisplay_host = cf->conn->host.dispname;
1403 *pport = ctx->ip.remote_port;
1404 }
1405
cf_socket_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)1406 static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
1407 struct Curl_easy *data,
1408 struct easy_pollset *ps)
1409 {
1410 struct cf_socket_ctx *ctx = cf->ctx;
1411
1412 if(ctx->sock != CURL_SOCKET_BAD) {
1413 /* A listening socket filter needs to be connected before the accept
1414 * for some weird FTP interaction. This should be rewritten, so that
1415 * FTP no longer does the socket checks and accept calls and delegates
1416 * all that to the filter. TODO. */
1417 if(ctx->listening) {
1418 Curl_pollset_set_in_only(data, ps, ctx->sock);
1419 CURL_TRC_CF(data, cf, "adjust_pollset, listening, POLLIN fd=%"
1420 FMT_SOCKET_T, ctx->sock);
1421 }
1422 else if(!cf->connected) {
1423 Curl_pollset_set_out_only(data, ps, ctx->sock);
1424 CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
1425 FMT_SOCKET_T, ctx->sock);
1426 }
1427 else if(!ctx->active) {
1428 Curl_pollset_add_in(data, ps, ctx->sock);
1429 CURL_TRC_CF(data, cf, "adjust_pollset, !active, POLLIN fd=%"
1430 FMT_SOCKET_T, ctx->sock);
1431 }
1432 }
1433 }
1434
cf_socket_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)1435 static bool cf_socket_data_pending(struct Curl_cfilter *cf,
1436 const struct Curl_easy *data)
1437 {
1438 struct cf_socket_ctx *ctx = cf->ctx;
1439 int readable;
1440
1441 (void)data;
1442 readable = SOCKET_READABLE(ctx->sock, 0);
1443 return (readable > 0 && (readable & CURL_CSELECT_IN));
1444 }
1445
1446 #ifdef USE_WINSOCK
1447
1448 #ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
1449 #define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
1450 #endif
1451
win_update_sndbuf_size(struct cf_socket_ctx * ctx)1452 static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
1453 {
1454 ULONG ideal;
1455 DWORD ideallen;
1456 struct curltime n = Curl_now();
1457
1458 if(Curl_timediff(n, ctx->last_sndbuf_query_at) > 1000) {
1459 if(!WSAIoctl(ctx->sock, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
1460 &ideal, sizeof(ideal), &ideallen, 0, 0) &&
1461 ideal != ctx->sndbuf_size &&
1462 !setsockopt(ctx->sock, SOL_SOCKET, SO_SNDBUF,
1463 (const char *)&ideal, sizeof(ideal))) {
1464 ctx->sndbuf_size = ideal;
1465 }
1466 ctx->last_sndbuf_query_at = n;
1467 }
1468 }
1469
1470 #endif /* USE_WINSOCK */
1471
cf_socket_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,bool eos,CURLcode * err)1472 static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1473 const void *buf, size_t len, bool eos,
1474 CURLcode *err)
1475 {
1476 struct cf_socket_ctx *ctx = cf->ctx;
1477 curl_socket_t fdsave;
1478 ssize_t nwritten;
1479 size_t orig_len = len;
1480
1481 (void)eos; /* unused */
1482 *err = CURLE_OK;
1483 fdsave = cf->conn->sock[cf->sockindex];
1484 cf->conn->sock[cf->sockindex] = ctx->sock;
1485
1486 #ifdef DEBUGBUILD
1487 /* simulate network blocking/partial writes */
1488 if(ctx->wblock_percent > 0) {
1489 unsigned char c = 0;
1490 Curl_rand_bytes(data, FALSE, &c, 1);
1491 if(c >= ((100-ctx->wblock_percent)*256/100)) {
1492 CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
1493 *err = CURLE_AGAIN;
1494 nwritten = -1;
1495 cf->conn->sock[cf->sockindex] = fdsave;
1496 return nwritten;
1497 }
1498 }
1499 if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) {
1500 len = len * ctx->wpartial_percent / 100;
1501 if(!len)
1502 len = 1;
1503 CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE partial write of %zu bytes",
1504 orig_len, len);
1505 }
1506 #endif
1507
1508 #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
1509 if(cf->conn->bits.tcp_fastopen) {
1510 nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
1511 &cf->conn->remote_addr->curl_sa_addr,
1512 cf->conn->remote_addr->addrlen);
1513 cf->conn->bits.tcp_fastopen = FALSE;
1514 }
1515 else
1516 #endif
1517 nwritten = swrite(ctx->sock, buf, len);
1518
1519 if(-1 == nwritten) {
1520 int sockerr = SOCKERRNO;
1521
1522 if(
1523 #ifdef WSAEWOULDBLOCK
1524 /* This is how Windows does it */
1525 (WSAEWOULDBLOCK == sockerr)
1526 #else
1527 /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
1528 due to its inability to send off data without blocking. We therefore
1529 treat both error codes the same here */
1530 (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) ||
1531 (EINPROGRESS == sockerr)
1532 #endif
1533 ) {
1534 /* this is just a case of EWOULDBLOCK */
1535 *err = CURLE_AGAIN;
1536 }
1537 else {
1538 char buffer[STRERROR_LEN];
1539 failf(data, "Send failure: %s",
1540 Curl_strerror(sockerr, buffer, sizeof(buffer)));
1541 data->state.os_errno = sockerr;
1542 *err = CURLE_SEND_ERROR;
1543 }
1544 }
1545
1546 #if defined(USE_WINSOCK)
1547 if(!*err)
1548 win_update_sndbuf_size(ctx);
1549 #endif
1550
1551 CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
1552 orig_len, (int)nwritten, *err);
1553 cf->conn->sock[cf->sockindex] = fdsave;
1554 return nwritten;
1555 }
1556
cf_socket_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)1557 static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1558 char *buf, size_t len, CURLcode *err)
1559 {
1560 struct cf_socket_ctx *ctx = cf->ctx;
1561 ssize_t nread;
1562
1563 *err = CURLE_OK;
1564
1565 #ifdef DEBUGBUILD
1566 /* simulate network blocking/partial reads */
1567 if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
1568 unsigned char c = 0;
1569 Curl_rand(data, &c, 1);
1570 if(c >= ((100-ctx->rblock_percent)*256/100)) {
1571 CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
1572 *err = CURLE_AGAIN;
1573 return -1;
1574 }
1575 }
1576 if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
1577 size_t orig_len = len;
1578 len = ctx->recv_max;
1579 CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes",
1580 orig_len, len);
1581 }
1582 #endif
1583
1584 *err = CURLE_OK;
1585 nread = sread(ctx->sock, buf, len);
1586
1587 if(-1 == nread) {
1588 int sockerr = SOCKERRNO;
1589
1590 if(
1591 #ifdef WSAEWOULDBLOCK
1592 /* This is how Windows does it */
1593 (WSAEWOULDBLOCK == sockerr)
1594 #else
1595 /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
1596 due to its inability to send off data without blocking. We therefore
1597 treat both error codes the same here */
1598 (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
1599 #endif
1600 ) {
1601 /* this is just a case of EWOULDBLOCK */
1602 *err = CURLE_AGAIN;
1603 }
1604 else {
1605 char buffer[STRERROR_LEN];
1606
1607 failf(data, "Recv failure: %s",
1608 Curl_strerror(sockerr, buffer, sizeof(buffer)));
1609 data->state.os_errno = sockerr;
1610 *err = CURLE_RECV_ERROR;
1611 }
1612 }
1613
1614 CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
1615 *err);
1616 if(nread > 0 && !ctx->got_first_byte) {
1617 ctx->first_byte_at = Curl_now();
1618 ctx->got_first_byte = TRUE;
1619 }
1620 return nread;
1621 }
1622
cf_socket_update_data(struct Curl_cfilter * cf,struct Curl_easy * data)1623 static void cf_socket_update_data(struct Curl_cfilter *cf,
1624 struct Curl_easy *data)
1625 {
1626 /* Update the IP info held in the transfer, if we have that. */
1627 if(cf->connected && (cf->sockindex == FIRSTSOCKET)) {
1628 struct cf_socket_ctx *ctx = cf->ctx;
1629 data->info.primary = ctx->ip;
1630 /* not sure if this is redundant... */
1631 data->info.conn_remote_port = cf->conn->remote_port;
1632 }
1633 }
1634
cf_socket_active(struct Curl_cfilter * cf,struct Curl_easy * data)1635 static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
1636 {
1637 struct cf_socket_ctx *ctx = cf->ctx;
1638
1639 /* use this socket from now on */
1640 cf->conn->sock[cf->sockindex] = ctx->sock;
1641 set_local_ip(cf, data);
1642 if(cf->sockindex == FIRSTSOCKET) {
1643 cf->conn->primary = ctx->ip;
1644 cf->conn->remote_addr = &ctx->addr;
1645 #ifdef USE_IPV6
1646 cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6);
1647 #endif
1648 }
1649 else {
1650 cf->conn->secondary = ctx->ip;
1651 }
1652 ctx->active = TRUE;
1653 }
1654
cf_socket_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)1655 static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
1656 struct Curl_easy *data,
1657 int event, int arg1, void *arg2)
1658 {
1659 struct cf_socket_ctx *ctx = cf->ctx;
1660
1661 (void)arg1;
1662 (void)arg2;
1663 switch(event) {
1664 case CF_CTRL_CONN_INFO_UPDATE:
1665 cf_socket_active(cf, data);
1666 cf_socket_update_data(cf, data);
1667 break;
1668 case CF_CTRL_DATA_SETUP:
1669 cf_socket_update_data(cf, data);
1670 break;
1671 case CF_CTRL_FORGET_SOCKET:
1672 ctx->sock = CURL_SOCKET_BAD;
1673 break;
1674 }
1675 return CURLE_OK;
1676 }
1677
cf_socket_conn_is_alive(struct Curl_cfilter * cf,struct Curl_easy * data,bool * input_pending)1678 static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
1679 struct Curl_easy *data,
1680 bool *input_pending)
1681 {
1682 struct cf_socket_ctx *ctx = cf->ctx;
1683 struct pollfd pfd[1];
1684 int r;
1685
1686 *input_pending = FALSE;
1687 (void)data;
1688 if(!ctx || ctx->sock == CURL_SOCKET_BAD)
1689 return FALSE;
1690
1691 /* Check with 0 timeout if there are any events pending on the socket */
1692 pfd[0].fd = ctx->sock;
1693 pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
1694 pfd[0].revents = 0;
1695
1696 r = Curl_poll(pfd, 1, 0);
1697 if(r < 0) {
1698 CURL_TRC_CF(data, cf, "is_alive: poll error, assume dead");
1699 return FALSE;
1700 }
1701 else if(r == 0) {
1702 CURL_TRC_CF(data, cf, "is_alive: poll timeout, assume alive");
1703 return TRUE;
1704 }
1705 else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) {
1706 CURL_TRC_CF(data, cf, "is_alive: err/hup/etc events, assume dead");
1707 return FALSE;
1708 }
1709
1710 CURL_TRC_CF(data, cf, "is_alive: valid events, looks alive");
1711 *input_pending = TRUE;
1712 return TRUE;
1713 }
1714
cf_socket_query(struct Curl_cfilter * cf,struct Curl_easy * data,int query,int * pres1,void * pres2)1715 static CURLcode cf_socket_query(struct Curl_cfilter *cf,
1716 struct Curl_easy *data,
1717 int query, int *pres1, void *pres2)
1718 {
1719 struct cf_socket_ctx *ctx = cf->ctx;
1720
1721 switch(query) {
1722 case CF_QUERY_SOCKET:
1723 DEBUGASSERT(pres2);
1724 *((curl_socket_t *)pres2) = ctx->sock;
1725 return CURLE_OK;
1726 case CF_QUERY_CONNECT_REPLY_MS:
1727 if(ctx->got_first_byte) {
1728 timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
1729 *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
1730 }
1731 else
1732 *pres1 = -1;
1733 return CURLE_OK;
1734 case CF_QUERY_TIMER_CONNECT: {
1735 struct curltime *when = pres2;
1736 switch(ctx->transport) {
1737 case TRNSPRT_UDP:
1738 case TRNSPRT_QUIC:
1739 /* Since UDP connected sockets work different from TCP, we use the
1740 * time of the first byte from the peer as the "connect" time. */
1741 if(ctx->got_first_byte) {
1742 *when = ctx->first_byte_at;
1743 break;
1744 }
1745 FALLTHROUGH();
1746 default:
1747 *when = ctx->connected_at;
1748 break;
1749 }
1750 return CURLE_OK;
1751 }
1752 case CF_QUERY_IP_INFO:
1753 #ifdef USE_IPV6
1754 *pres1 = (ctx->addr.family == AF_INET6);
1755 #else
1756 *pres1 = FALSE;
1757 #endif
1758 *(struct ip_quadruple *)pres2 = ctx->ip;
1759 return CURLE_OK;
1760 default:
1761 break;
1762 }
1763 return cf->next ?
1764 cf->next->cft->query(cf->next, data, query, pres1, pres2) :
1765 CURLE_UNKNOWN_OPTION;
1766 }
1767
1768 struct Curl_cftype Curl_cft_tcp = {
1769 "TCP",
1770 CF_TYPE_IP_CONNECT,
1771 CURL_LOG_LVL_NONE,
1772 cf_socket_destroy,
1773 cf_tcp_connect,
1774 cf_socket_close,
1775 cf_socket_shutdown,
1776 cf_socket_get_host,
1777 cf_socket_adjust_pollset,
1778 cf_socket_data_pending,
1779 cf_socket_send,
1780 cf_socket_recv,
1781 cf_socket_cntrl,
1782 cf_socket_conn_is_alive,
1783 Curl_cf_def_conn_keep_alive,
1784 cf_socket_query,
1785 };
1786
Curl_cf_tcp_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1787 CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
1788 struct Curl_easy *data,
1789 struct connectdata *conn,
1790 const struct Curl_addrinfo *ai,
1791 int transport)
1792 {
1793 struct cf_socket_ctx *ctx = NULL;
1794 struct Curl_cfilter *cf = NULL;
1795 CURLcode result;
1796
1797 (void)data;
1798 (void)conn;
1799 DEBUGASSERT(transport == TRNSPRT_TCP);
1800 ctx = calloc(1, sizeof(*ctx));
1801 if(!ctx) {
1802 result = CURLE_OUT_OF_MEMORY;
1803 goto out;
1804 }
1805 cf_socket_ctx_init(ctx, ai, transport);
1806
1807 result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx);
1808
1809 out:
1810 *pcf = (!result) ? cf : NULL;
1811 if(result) {
1812 Curl_safefree(cf);
1813 Curl_safefree(ctx);
1814 }
1815
1816 return result;
1817 }
1818
cf_udp_setup_quic(struct Curl_cfilter * cf,struct Curl_easy * data)1819 static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
1820 struct Curl_easy *data)
1821 {
1822 struct cf_socket_ctx *ctx = cf->ctx;
1823 int rc;
1824 int one = 1;
1825
1826 (void)one;
1827
1828 /* QUIC needs a connected socket, nonblocking */
1829 DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
1830
1831 rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
1832 (curl_socklen_t)ctx->addr.addrlen);
1833 if(-1 == rc) {
1834 return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
1835 }
1836 ctx->sock_connected = TRUE;
1837 set_local_ip(cf, data);
1838 CURL_TRC_CF(data, cf, "%s socket %" FMT_SOCKET_T
1839 " connected: [%s:%d] -> [%s:%d]",
1840 (ctx->transport == TRNSPRT_QUIC) ? "QUIC" : "UDP",
1841 ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
1842 ctx->ip.remote_ip, ctx->ip.remote_port);
1843
1844 /* Currently, cf->ctx->sock is always non-blocking because the only
1845 * caller to cf_udp_setup_quic() is cf_udp_connect() that passes the
1846 * non-blocking socket created by cf_socket_open() to it. Thus, we
1847 * do not need to call curlx_nonblock() in cf_udp_setup_quic() anymore.
1848 */
1849 switch(ctx->addr.family) {
1850 #if defined(__linux__) && defined(IP_MTU_DISCOVER)
1851 case AF_INET: {
1852 int val = IP_PMTUDISC_DO;
1853 (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
1854 sizeof(val));
1855 break;
1856 }
1857 #endif
1858 #if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
1859 case AF_INET6: {
1860 int val = IPV6_PMTUDISC_DO;
1861 (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
1862 sizeof(val));
1863 break;
1864 }
1865 #endif
1866 }
1867
1868 #if defined(__linux__) && defined(UDP_GRO) && \
1869 (defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)) && \
1870 ((defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_QUICHE))
1871 (void)setsockopt(ctx->sock, IPPROTO_UDP, UDP_GRO, &one,
1872 (socklen_t)sizeof(one));
1873 #endif
1874
1875 return CURLE_OK;
1876 }
1877
cf_udp_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1878 static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
1879 struct Curl_easy *data,
1880 bool blocking, bool *done)
1881 {
1882 struct cf_socket_ctx *ctx = cf->ctx;
1883 CURLcode result = CURLE_COULDNT_CONNECT;
1884
1885 (void)blocking;
1886 if(cf->connected) {
1887 *done = TRUE;
1888 return CURLE_OK;
1889 }
1890 *done = FALSE;
1891 if(ctx->sock == CURL_SOCKET_BAD) {
1892 result = cf_socket_open(cf, data);
1893 if(result) {
1894 CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d", result);
1895 goto out;
1896 }
1897
1898 if(ctx->transport == TRNSPRT_QUIC) {
1899 result = cf_udp_setup_quic(cf, data);
1900 if(result)
1901 goto out;
1902 CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1903 FMT_SOCKET_T " (%s:%d)",
1904 ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
1905 }
1906 else {
1907 CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1908 FMT_SOCKET_T " (unconnected)", ctx->sock);
1909 }
1910 *done = TRUE;
1911 cf->connected = TRUE;
1912 }
1913 out:
1914 return result;
1915 }
1916
1917 struct Curl_cftype Curl_cft_udp = {
1918 "UDP",
1919 CF_TYPE_IP_CONNECT,
1920 CURL_LOG_LVL_NONE,
1921 cf_socket_destroy,
1922 cf_udp_connect,
1923 cf_socket_close,
1924 cf_socket_shutdown,
1925 cf_socket_get_host,
1926 cf_socket_adjust_pollset,
1927 cf_socket_data_pending,
1928 cf_socket_send,
1929 cf_socket_recv,
1930 cf_socket_cntrl,
1931 cf_socket_conn_is_alive,
1932 Curl_cf_def_conn_keep_alive,
1933 cf_socket_query,
1934 };
1935
Curl_cf_udp_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1936 CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
1937 struct Curl_easy *data,
1938 struct connectdata *conn,
1939 const struct Curl_addrinfo *ai,
1940 int transport)
1941 {
1942 struct cf_socket_ctx *ctx = NULL;
1943 struct Curl_cfilter *cf = NULL;
1944 CURLcode result;
1945
1946 (void)data;
1947 (void)conn;
1948 DEBUGASSERT(transport == TRNSPRT_UDP || transport == TRNSPRT_QUIC);
1949 ctx = calloc(1, sizeof(*ctx));
1950 if(!ctx) {
1951 result = CURLE_OUT_OF_MEMORY;
1952 goto out;
1953 }
1954 cf_socket_ctx_init(ctx, ai, transport);
1955
1956 result = Curl_cf_create(&cf, &Curl_cft_udp, ctx);
1957
1958 out:
1959 *pcf = (!result) ? cf : NULL;
1960 if(result) {
1961 Curl_safefree(cf);
1962 Curl_safefree(ctx);
1963 }
1964
1965 return result;
1966 }
1967
1968 /* this is the TCP filter which can also handle this case */
1969 struct Curl_cftype Curl_cft_unix = {
1970 "UNIX",
1971 CF_TYPE_IP_CONNECT,
1972 CURL_LOG_LVL_NONE,
1973 cf_socket_destroy,
1974 cf_tcp_connect,
1975 cf_socket_close,
1976 cf_socket_shutdown,
1977 cf_socket_get_host,
1978 cf_socket_adjust_pollset,
1979 cf_socket_data_pending,
1980 cf_socket_send,
1981 cf_socket_recv,
1982 cf_socket_cntrl,
1983 cf_socket_conn_is_alive,
1984 Curl_cf_def_conn_keep_alive,
1985 cf_socket_query,
1986 };
1987
Curl_cf_unix_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1988 CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
1989 struct Curl_easy *data,
1990 struct connectdata *conn,
1991 const struct Curl_addrinfo *ai,
1992 int transport)
1993 {
1994 struct cf_socket_ctx *ctx = NULL;
1995 struct Curl_cfilter *cf = NULL;
1996 CURLcode result;
1997
1998 (void)data;
1999 (void)conn;
2000 DEBUGASSERT(transport == TRNSPRT_UNIX);
2001 ctx = calloc(1, sizeof(*ctx));
2002 if(!ctx) {
2003 result = CURLE_OUT_OF_MEMORY;
2004 goto out;
2005 }
2006 cf_socket_ctx_init(ctx, ai, transport);
2007
2008 result = Curl_cf_create(&cf, &Curl_cft_unix, ctx);
2009
2010 out:
2011 *pcf = (!result) ? cf : NULL;
2012 if(result) {
2013 Curl_safefree(cf);
2014 Curl_safefree(ctx);
2015 }
2016
2017 return result;
2018 }
2019
cf_tcp_accept_timeleft(struct Curl_cfilter * cf,struct Curl_easy * data)2020 static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf,
2021 struct Curl_easy *data)
2022 {
2023 struct cf_socket_ctx *ctx = cf->ctx;
2024 timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
2025 timediff_t other;
2026 struct curltime now;
2027
2028 #ifndef CURL_DISABLE_FTP
2029 if(data->set.accepttimeout > 0)
2030 timeout_ms = data->set.accepttimeout;
2031 #endif
2032
2033 now = Curl_now();
2034 /* check if the generic timeout possibly is set shorter */
2035 other = Curl_timeleft(data, &now, FALSE);
2036 if(other && (other < timeout_ms))
2037 /* note that this also works fine for when other happens to be negative
2038 due to it already having elapsed */
2039 timeout_ms = other;
2040 else {
2041 /* subtract elapsed time */
2042 timeout_ms -= Curl_timediff(now, ctx->started_at);
2043 if(!timeout_ms)
2044 /* avoid returning 0 as that means no timeout! */
2045 timeout_ms = -1;
2046 }
2047 return timeout_ms;
2048 }
2049
cf_tcp_set_accepted_remote_ip(struct Curl_cfilter * cf,struct Curl_easy * data)2050 static void cf_tcp_set_accepted_remote_ip(struct Curl_cfilter *cf,
2051 struct Curl_easy *data)
2052 {
2053 struct cf_socket_ctx *ctx = cf->ctx;
2054 #ifdef HAVE_GETPEERNAME
2055 char buffer[STRERROR_LEN];
2056 struct Curl_sockaddr_storage ssrem;
2057 curl_socklen_t plen;
2058
2059 ctx->ip.remote_ip[0] = 0;
2060 ctx->ip.remote_port = 0;
2061 plen = sizeof(ssrem);
2062 memset(&ssrem, 0, plen);
2063 if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
2064 int error = SOCKERRNO;
2065 failf(data, "getpeername() failed with errno %d: %s",
2066 error, Curl_strerror(error, buffer, sizeof(buffer)));
2067 return;
2068 }
2069 if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
2070 ctx->ip.remote_ip, &ctx->ip.remote_port)) {
2071 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
2072 errno, Curl_strerror(errno, buffer, sizeof(buffer)));
2073 return;
2074 }
2075 #else
2076 ctx->ip.remote_ip[0] = 0;
2077 ctx->ip.remote_port = 0;
2078 (void)data;
2079 #endif
2080 }
2081
cf_tcp_accept_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)2082 static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
2083 struct Curl_easy *data,
2084 bool blocking, bool *done)
2085 {
2086 struct cf_socket_ctx *ctx = cf->ctx;
2087 #ifdef USE_IPV6
2088 struct Curl_sockaddr_storage add;
2089 #else
2090 struct sockaddr_in add;
2091 #endif
2092 curl_socklen_t size = (curl_socklen_t) sizeof(add);
2093 curl_socket_t s_accepted = CURL_SOCKET_BAD;
2094 timediff_t timeout_ms;
2095 int socketstate = 0;
2096 bool incoming = FALSE;
2097
2098 /* we start accepted, if we ever close, we cannot go on */
2099 (void)data;
2100 (void)blocking;
2101 if(cf->connected) {
2102 *done = TRUE;
2103 return CURLE_OK;
2104 }
2105
2106 timeout_ms = cf_tcp_accept_timeleft(cf, data);
2107 if(timeout_ms < 0) {
2108 /* if a timeout was already reached, bail out */
2109 failf(data, "Accept timeout occurred while waiting server connect");
2110 return CURLE_FTP_ACCEPT_TIMEOUT;
2111 }
2112
2113 CURL_TRC_CF(data, cf, "Checking for incoming on fd=%" FMT_SOCKET_T
2114 " ip=%s:%d", ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
2115 socketstate = Curl_socket_check(ctx->sock, CURL_SOCKET_BAD,
2116 CURL_SOCKET_BAD, 0);
2117 CURL_TRC_CF(data, cf, "socket_check -> %x", socketstate);
2118 switch(socketstate) {
2119 case -1: /* error */
2120 /* let's die here */
2121 failf(data, "Error while waiting for server connect");
2122 return CURLE_FTP_ACCEPT_FAILED;
2123 default:
2124 if(socketstate & CURL_CSELECT_IN) {
2125 infof(data, "Ready to accept data connection from server");
2126 incoming = TRUE;
2127 }
2128 break;
2129 }
2130
2131 if(!incoming) {
2132 CURL_TRC_CF(data, cf, "nothing heard from the server yet");
2133 *done = FALSE;
2134 return CURLE_OK;
2135 }
2136
2137 if(0 == getsockname(ctx->sock, (struct sockaddr *) &add, &size)) {
2138 size = sizeof(add);
2139 s_accepted = accept(ctx->sock, (struct sockaddr *) &add, &size);
2140 }
2141
2142 if(CURL_SOCKET_BAD == s_accepted) {
2143 failf(data, "Error accept()ing server connect");
2144 return CURLE_FTP_PORT_FAILED;
2145 }
2146
2147 infof(data, "Connection accepted from server");
2148 (void)curlx_nonblock(s_accepted, TRUE); /* enable non-blocking */
2149 /* Replace any filter on SECONDARY with one listening on this socket */
2150 ctx->listening = FALSE;
2151 ctx->accepted = TRUE;
2152 socket_close(data, cf->conn, TRUE, ctx->sock);
2153 ctx->sock = s_accepted;
2154
2155 cf->conn->sock[cf->sockindex] = ctx->sock;
2156 cf_tcp_set_accepted_remote_ip(cf, data);
2157 set_local_ip(cf, data);
2158 ctx->active = TRUE;
2159 ctx->connected_at = Curl_now();
2160 cf->connected = TRUE;
2161 CURL_TRC_CF(data, cf, "accepted_set(sock=%" FMT_SOCKET_T
2162 ", remote=%s port=%d)",
2163 ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
2164
2165 if(data->set.fsockopt) {
2166 int error = 0;
2167
2168 /* activate callback for setting socket options */
2169 Curl_set_in_callback(data, true);
2170 error = data->set.fsockopt(data->set.sockopt_client,
2171 ctx->sock, CURLSOCKTYPE_ACCEPT);
2172 Curl_set_in_callback(data, false);
2173
2174 if(error)
2175 return CURLE_ABORTED_BY_CALLBACK;
2176 }
2177 return CURLE_OK;
2178 }
2179
2180 struct Curl_cftype Curl_cft_tcp_accept = {
2181 "TCP-ACCEPT",
2182 CF_TYPE_IP_CONNECT,
2183 CURL_LOG_LVL_NONE,
2184 cf_socket_destroy,
2185 cf_tcp_accept_connect,
2186 cf_socket_close,
2187 cf_socket_shutdown,
2188 cf_socket_get_host, /* TODO: not accurate */
2189 cf_socket_adjust_pollset,
2190 cf_socket_data_pending,
2191 cf_socket_send,
2192 cf_socket_recv,
2193 cf_socket_cntrl,
2194 cf_socket_conn_is_alive,
2195 Curl_cf_def_conn_keep_alive,
2196 cf_socket_query,
2197 };
2198
Curl_conn_tcp_listen_set(struct Curl_easy * data,struct connectdata * conn,int sockindex,curl_socket_t * s)2199 CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
2200 struct connectdata *conn,
2201 int sockindex, curl_socket_t *s)
2202 {
2203 CURLcode result;
2204 struct Curl_cfilter *cf = NULL;
2205 struct cf_socket_ctx *ctx = NULL;
2206
2207 /* replace any existing */
2208 Curl_conn_cf_discard_all(data, conn, sockindex);
2209 DEBUGASSERT(conn->sock[sockindex] == CURL_SOCKET_BAD);
2210
2211 ctx = calloc(1, sizeof(*ctx));
2212 if(!ctx) {
2213 result = CURLE_OUT_OF_MEMORY;
2214 goto out;
2215 }
2216 ctx->transport = conn->transport;
2217 ctx->sock = *s;
2218 ctx->listening = TRUE;
2219 ctx->accepted = FALSE;
2220 result = Curl_cf_create(&cf, &Curl_cft_tcp_accept, ctx);
2221 if(result)
2222 goto out;
2223 Curl_conn_cf_add(data, conn, sockindex, cf);
2224
2225 ctx->started_at = Curl_now();
2226 conn->sock[sockindex] = ctx->sock;
2227 set_local_ip(cf, data);
2228 CURL_TRC_CF(data, cf, "set filter for listen socket fd=%" FMT_SOCKET_T
2229 " ip=%s:%d", ctx->sock,
2230 ctx->ip.local_ip, ctx->ip.local_port);
2231
2232 out:
2233 if(result) {
2234 Curl_safefree(cf);
2235 Curl_safefree(ctx);
2236 }
2237 return result;
2238 }
2239
Curl_conn_is_tcp_listen(struct Curl_easy * data,int sockindex)2240 bool Curl_conn_is_tcp_listen(struct Curl_easy *data,
2241 int sockindex)
2242 {
2243 struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
2244 while(cf) {
2245 if(cf->cft == &Curl_cft_tcp_accept)
2246 return TRUE;
2247 cf = cf->next;
2248 }
2249 return FALSE;
2250 }
2251
2252 /**
2253 * Return TRUE iff `cf` is a socket filter.
2254 */
cf_is_socket(struct Curl_cfilter * cf)2255 static bool cf_is_socket(struct Curl_cfilter *cf)
2256 {
2257 return cf && (cf->cft == &Curl_cft_tcp ||
2258 cf->cft == &Curl_cft_udp ||
2259 cf->cft == &Curl_cft_unix ||
2260 cf->cft == &Curl_cft_tcp_accept);
2261 }
2262
Curl_cf_socket_peek(struct Curl_cfilter * cf,struct Curl_easy * data,curl_socket_t * psock,const struct Curl_sockaddr_ex ** paddr,struct ip_quadruple * pip)2263 CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
2264 struct Curl_easy *data,
2265 curl_socket_t *psock,
2266 const struct Curl_sockaddr_ex **paddr,
2267 struct ip_quadruple *pip)
2268 {
2269 (void)data;
2270 if(cf_is_socket(cf) && cf->ctx) {
2271 struct cf_socket_ctx *ctx = cf->ctx;
2272
2273 if(psock)
2274 *psock = ctx->sock;
2275 if(paddr)
2276 *paddr = &ctx->addr;
2277 if(pip)
2278 *pip = ctx->ip;
2279 return CURLE_OK;
2280 }
2281 return CURLE_FAILED_INIT;
2282 }
2283