diff --git a/configure.ac b/configure.ac index 2f5f6bc7..d15c0910 100644 --- a/configure.ac +++ b/configure.ac @@ -293,6 +293,12 @@ AC_ARG_WITH( [with_openssl_engine="auto"] ) +AC_ARG_WITH(mptcp, + [AS_HELP_STRING([--without-mptcp],[Disable Multipath TCP support])], + [enable_mptcp=no], + [enable_mptcp=yes] +) + AC_ARG_VAR([PLUGINDIR], [Path of plug-in directory @<:@default=LIBDIR/openvpn/plugins@:>@]) if test -n "${PLUGINDIR}"; then plugindir="${PLUGINDIR}" @@ -846,6 +852,22 @@ PKG_CHECK_MODULES( [] ) +dnl +dnl Checking Multipath TCP support on Linux +dnl +case "$host" in + *-*-linux*) + AC_MSG_CHECKING([Multipath TCP support ]) + AS_IF([test "x$enable_mptcp" != xno], + [AC_DEFINE([ENABLE_MPTCP], [1], + [AC_MSG_RESULT([Multipath TCP is enabled on this system])] )], + [ AC_MSG_RESULT([Multipath TCP is not enabled. On Linux, you need a kernel >= 5.15 and ensure that sysctl.net.mptcp_enabled is set to 1]) ], + ) + ;; +esac + + + if test "${with_crypto_library}" = "openssl"; then AC_ARG_VAR([OPENSSL_CFLAGS], [C compiler flags for OpenSSL]) AC_ARG_VAR([OPENSSL_LIBS], [linker flags for OpenSSL]) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index be8ff80f..b4fe11e2 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -3449,6 +3449,9 @@ do_init_socket_1(struct context *c, const int mode) c->c1.socks_proxy, #ifdef ENABLE_DEBUG c->options.gremlin, +#endif +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) + c->options.enable_mptcp, #endif c->options.ce.bind_local, c->options.ce.remote_float, diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 20d1273f..3222fda6 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -130,6 +130,9 @@ static const char usage_message[] = " udp6, tcp6-server, tcp6-client\n" "--proto-force p : only consider protocol p in list of connection profiles.\n" " p = udp or tcp\n" +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) + "--mptcp : Enable Multipath TCP on the TCP connections.\n" +#endif "--connect-retry n [m] : For client, number of seconds to wait between\n" " connection retries (default=%d). On repeated retries\n" " the wait time is exponentially increased to a maximum of m\n" @@ -903,6 +906,11 @@ init_options(struct options *o, const bool init_gc) } #endif /* _WIN32 */ o->allow_recursive_routing = false; + +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) + o->enable_mptcp = false; +#endif + } void @@ -8834,6 +8842,18 @@ add_option(struct options *options, goto err; } } +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) + else if (streq(p[0], "mptcp")) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + if (p[1]) + { + msg(msglevel, "--mptcp does not accept any parameters"); + goto err; + } + options->enable_mptcp = true; + } +#endif else { int i; diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 37220904..465eff52 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -430,6 +430,9 @@ struct options #define SF_NO_PUSH_ROUTE_GATEWAY (1<<2) unsigned int server_flags; +#ifdef ENABLE_MPTCP + bool enable_mptcp; +#endif bool server_bridge_proxy_dhcp; bool server_bridge_defined; diff --git a/src/openvpn/ps.c b/src/openvpn/ps.c index e79cb0d3..754cdfc5 100644 --- a/src/openvpn/ps.c +++ b/src/openvpn/ps.c @@ -39,6 +39,14 @@ #include "memdbg.h" + +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) +#ifndef IPPROTO_MPTCP +#define IPPROTO_MPTCP 262 +#endif +#endif + + struct port_share *port_share = NULL; /* GLOBAL */ /* size of i/o buffers */ @@ -427,7 +435,11 @@ proxy_entry_new(struct proxy_connection **list, struct proxy_connection *cp; /* connect to port share server */ +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) + if ((sd_server = socket(PF_INET, SOCK_STREAM, IPPROTO_MPTCP)) < 0) +#else if ((sd_server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) +#endif { msg(M_WARN|M_ERRNO, "PORT SHARE PROXY: cannot create socket"); return false; diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 28fabe76..e7242020 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -55,6 +55,12 @@ const int proto_overhead[] = { /* indexed by PROTO_x */ IPv6_TCP_HEADER_SIZE, }; +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) +#ifndef IPPROTO_MPTCP +#define IPPROTO_MPTCP 262 +#endif +#endif + /* * Convert sockflags/getaddr_flags into getaddr_flags */ @@ -1093,6 +1099,39 @@ create_socket_udp(struct addrinfo *addrinfo, const unsigned int flags) return sd; } +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) +socket_descriptor_t +create_socket_mptcp(struct addrinfo *addrinfo) +{ + socket_descriptor_t sd; + + ASSERT(addrinfo); + ASSERT(addrinfo->ai_socktype == SOCK_STREAM); + addrinfo->ai_protocol = IPPROTO_MPTCP; + if ((sd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0) + { + msg(M_ERR, "Cannot create MPTCP socket"); + } + + { + int on = 1; + if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, + (void *) &on, sizeof(on)) < 0) + { + msg(M_ERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP socket"); + } + } + + /* set socket file descriptor to not pass across execs, so that + * scripts don't have access to it */ + set_cloexec(sd); + + return sd; +} + +#endif + + static void bind_local(struct link_socket *sock, const sa_family_t ai_family) { @@ -1136,6 +1175,21 @@ create_socket(struct link_socket *sock, struct addrinfo *addr) } else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM) { +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) + if(sock->info.multipath) + { + sock->sd = create_socket_mptcp(addr); + // Multipath TCP could fail because it is not enabled on this host + // Try regular TCP + if(sock->sd == -1) + { + + msg(M_NONFATAL, "Can't resolve MPTCP socket, fallback to TCP !"); + sock->sd = create_socket_tcp(addr); + } + } + else +#endif sock->sd = create_socket_tcp(addr); } else @@ -1891,6 +1945,9 @@ link_socket_init_phase1(struct link_socket *sock, struct socks_proxy_info *socks_proxy, #ifdef ENABLE_DEBUG int gremlin, +#endif +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) + bool enable_mptcp, #endif bool bind_local, bool remote_float, @@ -1920,7 +1977,11 @@ link_socket_init_phase1(struct link_socket *sock, sock->inetd = inetd; sock->resolve_retry_seconds = resolve_retry_seconds; sock->mtu_discover_type = mtu_discover_type; - + +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) + sock->info.multipath = enable_mptcp; +#endif + #ifdef ENABLE_DEBUG sock->gremlin = gremlin; #endif @@ -2305,7 +2366,7 @@ link_socket_init_phase2(struct link_socket *sock, /* If a valid remote has been found, create the socket with its addrinfo */ if (sock->info.lsa->current_remote) { - create_socket(sock, sock->info.lsa->current_remote); + create_socket(sock, sock->info.lsa->current_remote); } /* If socket has not already been created create it now */ diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 2ad6155f..0dcb0655 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -120,6 +120,9 @@ struct link_socket_info sa_family_t af; /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/ bool bind_ipv6_only; int mtu_changed; /* Set to true when mtu value is changed */ +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) + bool multipath; +#endif }; /* @@ -315,6 +318,9 @@ link_socket_init_phase1(struct link_socket *sock, struct socks_proxy_info *socks_proxy, #ifdef ENABLE_DEBUG int gremlin, +#endif +#if defined(TARGET_LINUX) && defined(ENABLE_MPTCP) + bool enable_mptcp, #endif bool bind_local, bool remote_float, @@ -476,6 +482,10 @@ bool ipv6_addr_safe(const char *ipv6_text_addr); socket_descriptor_t create_socket_tcp(struct addrinfo *); +#ifdef ENABLE_MPTCP +socket_descriptor_t create_socket_mptcp(struct addrinfo *); +#endif + socket_descriptor_t socket_do_accept(socket_descriptor_t sd, struct link_socket_actual *act, const bool nowait);