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