• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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