From 97aa6b19f7d108061f0d21252bcce89725fa32d6 Mon Sep 17 00:00:00 2001 From: Dorian Craps Date: Thu, 4 Apr 2024 11:42:50 +0200 Subject: [PATCH] socket: linux: add MPTCP support Multipath TCP (MPTCP), standardized in RFC8684 [1], is a TCP extension that enables a TCP connection to use different paths. Multipath TCP has been used for several use cases. On smartphones, MPTCP enables seamless handovers between cellular and Wi-Fi networks while preserving established connections. This use-case is what pushed Apple to use MPTCP since 2013 in multiple applications [2]. On dual-stack hosts, Multipath TCP enables the TCP connection to automatically use the best performing path, either IPv4 or IPv6. If one path fails, MPTCP automatically uses the other path. To benefit from MPTCP, both the client and the server have to support it. Multipath TCP is a backward-compatible TCP extension that is enabled by default on recent Linux distributions (Debian, Ubuntu, Redhat, ...). Multipath TCP is included in the Linux kernel since version 5.6 [3]. To use it on Linux, an application must explicitly enable it when creating the socket. No need to change anything else in the application. This attached patch adds an --mptcp option which allows the creation of an MPTCP socket instead of TCP on Linux. If Multipath TCP is not supported on the system, an error will be reported. It is important to note that if the end server doesn't support MPTCP, the connection will continue after a seamless fallback to TCP. Link: https://www.rfc-editor.org/rfc/rfc8684.html [1] Link: https://www.tessares.net/apples-mptcp-story-so-far/ [2] Link: https://www.mptcp.dev [3] Co-developed-by: Dorian Craps (@CrapsDorian) Co-developed-by: Olivier Bonaventure (@obonaventure) Co-developed-by: Matthieu Baerts (@matttbe) Signed-off-by: Dorian Craps --- .github/scripts/spellcheck.words | 2 ++ docs/cmdline-opts/Makefile.inc | 1 + docs/cmdline-opts/mptcp.md | 41 ++++++++++++++++++++++ docs/options-in-versions | 1 + packages/vms/gnv_link_curl.com | 1 + src/Makefile.inc | 2 ++ src/tool_cb_soc.c | 58 ++++++++++++++++++++++++++++++++ src/tool_cb_soc.h | 36 ++++++++++++++++++++ src/tool_cfgable.h | 1 + src/tool_getparam.c | 5 +++ src/tool_listhelp.c | 3 ++ src/tool_operate.c | 5 +++ 12 files changed, 156 insertions(+) create mode 100644 docs/cmdline-opts/mptcp.md create mode 100644 src/tool_cb_soc.c create mode 100644 src/tool_cb_soc.h diff --git a/.github/scripts/spellcheck.words b/.github/scripts/spellcheck.words index 87b010ad7beb0f..3e95d1d7a3fa04 100644 --- a/.github/scripts/spellcheck.words +++ b/.github/scripts/spellcheck.words @@ -503,6 +503,7 @@ monospace MorphOS MPE MPL +MPTCP mprintf MQTT mqtt @@ -523,6 +524,7 @@ mTLS MUA multicwd multiparts +multipath MultiSSL mumbo musedev diff --git a/docs/cmdline-opts/Makefile.inc b/docs/cmdline-opts/Makefile.inc index deb4c7c326dc1c..75855f54572b81 100644 --- a/docs/cmdline-opts/Makefile.inc +++ b/docs/cmdline-opts/Makefile.inc @@ -161,6 +161,7 @@ DPAGES = \ max-redirs.md \ max-time.md \ metalink.md \ + mptcp.md \ negotiate.md \ netrc-file.md \ netrc-optional.md \ diff --git a/docs/cmdline-opts/mptcp.md b/docs/cmdline-opts/mptcp.md new file mode 100644 index 00000000000000..b9212bb8bbcebb --- /dev/null +++ b/docs/cmdline-opts/mptcp.md @@ -0,0 +1,41 @@ +--- +c: Copyright (C) Dorian Craps, +SPDX-License-Identifier: curl +Long: mptcp +Added: 8.9.0 +Help: Enable Multipath TCP +Category: connection +Multi: boolean +See-also: + - tcp-fastopen +Example: + - --mptcp $URL +--- + +# `--mptcp` + +Enables the use of Multipath TCP (MPTCP) for connections. MPTCP is an extension +to the standard TCP that allows multiple TCP streams over different network +paths between the same source and destination. This can enhance bandwidth and +improve reliability by using multiple paths simultaneously. + +MPTCP is beneficial in networks where multiple paths exist between clients and +servers, such as mobile networks where a device may switch between WiFi and +cellular data or in wired networks with multiple Internet Service Providers. + +## Usage + +To use MPTCP for your connections, add the `--mptcp` option when using `curl'. + +## Requirements + +This feature is currently only supported on Linux starting from kernel 5.6. Only +TCP connections are modified, hence this option does not effect HTTP/3 (QUIC) +connections. + +The server you are connecting to must also support MPTCP. If not, the connection +seamlessly falls back to TCP. + +## Availability + +The `--mptcp` option is available starting from `curl` version 8.9.0. diff --git a/docs/options-in-versions b/docs/options-in-versions index d3513ff119d7f6..33bde967e80674 100644 --- a/docs/options-in-versions +++ b/docs/options-in-versions @@ -126,6 +126,7 @@ --max-redirs 7.5 --max-time (-m) 4.0 --metalink 7.27.0 +--mptcp 8.9.0 --negotiate 7.10.6 --netrc (-n) 4.6 --netrc-file 7.21.5 diff --git a/packages/vms/gnv_link_curl.com b/packages/vms/gnv_link_curl.com index 247987ae874695..552d7d45dd7114 100644 --- a/packages/vms/gnv_link_curl.com +++ b/packages/vms/gnv_link_curl.com @@ -400,6 +400,7 @@ $ link'ldebug'/exe=[.src]curl.exe/dsf=[.src]curl.dsf - [.src]curl-tool_bname.o, [.src]curl-tool_cb_dbg.o, - [.src]curl-tool_cb_hdr.o, [.src]curl-tool_cb_prg.o, - [.src]curl-tool_cb_rea.o, [.src]curl-tool_cb_see.o, - + [.src]curl-tool_cb_soc.o, - [.src]curl-tool_cb_wrt.o, [.src]curl-tool_cfgable.o, - [.src]curl-tool_convert.o, [.src]curl-tool_dirhie.o, - [.src]curl-tool_doswin.o, [.src]curl-tool_easysrc.o, - diff --git a/src/Makefile.inc b/src/Makefile.inc index 92efa2756aff78..12737735de4672 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -67,6 +67,7 @@ CURL_CFILES = \ tool_cb_prg.c \ tool_cb_rea.c \ tool_cb_see.c \ + tool_cb_soc.c \ tool_cb_wrt.c \ tool_cfgable.c \ tool_dirhie.c \ @@ -112,6 +113,7 @@ CURL_HFILES = \ tool_cb_prg.h \ tool_cb_rea.h \ tool_cb_see.h \ + tool_cb_soc.h \ tool_cb_wrt.h \ tool_cfgable.h \ tool_dirhie.h \ diff --git a/src/tool_cb_soc.c b/src/tool_cb_soc.c new file mode 100644 index 00000000000000..22048ee6bbf95b --- /dev/null +++ b/src/tool_cb_soc.c @@ -0,0 +1,58 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +#ifdef HAVE_NETINET_IN_H +#include /* IPPROTO_TCP */ +#endif + +#include "tool_cb_soc.h" + +/* +** callback for CURLOPT_OPENSOCKETFUNCTION +** +** Notice that only Linux is supported for the moment. +*/ + +curl_socket_t tool_socket_open_mptcp_cb(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *addr) +{ + int protocol = addr->protocol; + + (void)clientp; + (void)purpose; + + if(protocol == IPPROTO_TCP) +#if defined(__linux__) +# ifndef IPPROTO_MPTCP +# define IPPROTO_MPTCP 262 +# endif + protocol = IPPROTO_MPTCP; +#else + return CURL_SOCKET_BAD; +#endif + + return socket(addr->family, addr->socktype, protocol); +} diff --git a/src/tool_cb_soc.h b/src/tool_cb_soc.h new file mode 100644 index 00000000000000..f02150aa8284d7 --- /dev/null +++ b/src/tool_cb_soc.h @@ -0,0 +1,36 @@ +#ifndef HEADER_CURL_TOOL_CB_SOC_H +#define HEADER_CURL_TOOL_CB_SOC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "tool_setup.h" + +/* +** callback for CURLOPT_OPENSOCKETFUNCTION +*/ + +curl_socket_t tool_socket_open_mptcp_cb(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *addr); + +#endif /* HEADER_CURL_TOOL_CB_SOC_H */ diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 5d99d605f3c7c3..c90190443e69d3 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -292,6 +292,7 @@ struct OperationConfig { CLOBBER_NEVER, /* If the file exists, always fail */ CLOBBER_ALWAYS /* If the file exists, always overwrite it */ } file_clobber_mode; + bool mptcp; /* enable MPTCP support */ struct GlobalConfig *global; struct OperationConfig *prev; struct OperationConfig *next; /* Always last in the struct */ diff --git a/src/tool_getparam.c b/src/tool_getparam.c index e3eb12fa0b0b8b..7410e5b4632de0 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -200,6 +200,7 @@ typedef enum { C_MAX_REDIRS, C_MAX_TIME, C_METALINK, + C_MPTCP, C_NEGOTIATE, C_NETRC, C_NETRC_FILE, @@ -482,6 +483,7 @@ static const struct LongShort aliases[]= { {"max-redirs", ARG_STRG, ' ', C_MAX_REDIRS}, {"max-time", ARG_STRG, 'm', C_MAX_TIME}, {"metalink", ARG_BOOL, ' ', C_METALINK}, + {"mptcp", ARG_BOOL, ' ', C_MPTCP}, {"negotiate", ARG_BOOL, ' ', C_NEGOTIATE}, {"netrc", ARG_BOOL, 'n', C_NETRC}, {"netrc-file", ARG_FILE, ' ', C_NETRC_FILE}, @@ -2793,6 +2795,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */ } } break; + case C_MPTCP: /* --mptcp */ + config->mptcp = TRUE; + break; default: /* unknown flag */ err = PARAM_OPTION_UNKNOWN; break; diff --git a/src/tool_listhelp.c b/src/tool_listhelp.c index df05de31c257da..d41788ecca521b 100644 --- a/src/tool_listhelp.c +++ b/src/tool_listhelp.c @@ -381,6 +381,9 @@ const struct helptxt helptext[] = { {" --metalink", "Process given URLs as metalink XML file", CURLHELP_MISC}, + {" --mptcp", + "Enable Multipath TCP", + CURLHELP_CONNECTION}, {" --negotiate", "Use HTTP Negotiate (SPNEGO) authentication", CURLHELP_AUTH | CURLHELP_HTTP}, diff --git a/src/tool_operate.c b/src/tool_operate.c index b5e7d4ccff43a2..a2b12001c16771 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -56,6 +56,7 @@ #include "tool_cb_prg.h" #include "tool_cb_rea.h" #include "tool_cb_see.h" +#include "tool_cb_soc.h" #include "tool_cb_wrt.h" #include "tool_dirhie.h" #include "tool_doswin.h" @@ -1289,6 +1290,10 @@ static CURLcode single_transfer(struct GlobalConfig *global, if(config->tcp_fastopen) my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L); + if(config->mptcp) + my_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, + tool_socket_open_mptcp_cb); + /* where to store */ my_setopt(curl, CURLOPT_WRITEDATA, per); my_setopt(curl, CURLOPT_INTERLEAVEDATA, per);