From patchwork Sun Dec 30 00:28:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 652 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director9.mail.ord1d.rsapps.net ([172.31.255.6]) by backend30.mail.ord1d.rsapps.net with LMTP id 6KogOJKsKFyAbwAAIUCqbw for ; Sun, 30 Dec 2018 06:31:31 -0500 Received: from proxy4.mail.iad3b.rsapps.net ([172.31.255.6]) by director9.mail.ord1d.rsapps.net with LMTP id CNagNZKsKFzZagAAalYnBA ; Sun, 30 Dec 2018 06:31:30 -0500 Received: from smtp8.gate.iad3b ([172.31.255.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy4.mail.iad3b.rsapps.net with LMTP id EOr4L5KsKFxSXgAA9crAow ; Sun, 30 Dec 2018 06:31:30 -0500 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp8.gate.iad3b.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dmarc=none (p=nil; dis=none) header.from=unstable.cc X-Suspicious-Flag: YES X-Classification-ID: 7377742e-0c26-11e9-8cdd-5254005eee35-1-1 Received: from [216.105.38.7] ([216.105.38.7:20212] helo=lists.sourceforge.net) by smtp8.gate.iad3b.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 78/12-21509-29CA82C5; Sun, 30 Dec 2018 06:31:30 -0500 Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1gdZIa-0003dy-PN; Sun, 30 Dec 2018 11:30:28 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1gdZIZ-0003de-Cn for openvpn-devel@lists.sourceforge.net; Sun, 30 Dec 2018 11:30:27 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=EcrMmZStxLRAElsNwrjMxLShNsudnS54t29TfkfV9MY=; b=PMwJSrMYJ20mCvMltMr0BP1StA k8u7lswtj/vSTBs9WXYS1sP9WWCmz0Vnc38ho5hT10JSlZkWui0iyN+n6QdNshFlvS+HH1RUS19EZ uSpx9nj351y8A9Mp6OpmMb+X/rXohCb3yVKIc9QWra/L1Bhj7yE7jh2KgC/4dWWuUVtw=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-Id: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=EcrMmZStxLRAElsNwrjMxLShNsudnS54t29TfkfV9MY=; b=iTd0/4J6yduuNK6f+DDI+G8KHH 3Yi2iNuztDa3cpPJ9XBBGDIr983T2f13cFWn2sxX6bp4yfZHb5JwDXgDUD3C4/qtEp7ArDvX10b4y +ciyTCRs9QNWjjt6TnVg9oK3typ2yaE0HDnAr5yH3mCQ/DKasZlxbOsxe4HQY/IC4nZ8=; Received: from s2.neomailbox.net ([5.148.176.60]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) id 1gdZIX-006XFG-BT for openvpn-devel@lists.sourceforge.net; Sun, 30 Dec 2018 11:30:27 +0000 From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Sun, 30 Dec 2018 21:28:59 +1000 Message-Id: <20181230112901.29241-3-a@unstable.cc> In-Reply-To: <20181230112901.29241-1-a@unstable.cc> References: <20181230112901.29241-1-a@unstable.cc> MIME-Version: 1.0 X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [5.148.176.60 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1gdZIX-006XFG-BT Subject: [Openvpn-devel] [PATCH 2/4] socket: introduce INDIRECT transport protocol abstraction X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: antonio@openvpn.net, Robin Tarsiger Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox From: Robin Tarsiger This new transport protocol is used to tell the core code that traffic should not be directly processed, but should rather be rerouted to a transport plugin. It is basically an abstraction as it does not say tell the code how to process the data, but simply forces its redirection to the external code. Signed-off-by: Robin Tarsiger [antonio@openvpn.net: refactored commits, restyled code] --- src/openvpn/forward.c | 5 ++ src/openvpn/socket.c | 146 ++++++++++++++++++++++++++++++++++++++-- src/openvpn/socket.h | 70 +++++++++++++++++++ src/openvpn/transport.h | 5 ++ 4 files changed, 222 insertions(+), 4 deletions(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 0a90fff0..a7092c7e 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -2150,6 +2150,11 @@ io_wait_dowork(struct context *c, const unsigned int flags) { int i; c->c2.event_set_status = 0; +#ifdef ENABLE_PLUGIN + c->c2.event_set_status |= + (socket_indirect_pump(c->c2.link_socket, esr, &status) & 3) + << socket_shift; +#endif for (i = 0; i < status; ++i) { const struct event_set_return *e = &esr[i]; diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index db944245..b548ab7a 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -41,6 +41,7 @@ #include "manage.h" #include "openvpn.h" #include "forward.h" +#include "transport.h" #include "memdbg.h" @@ -49,6 +50,9 @@ const int proto_overhead[] = { /* indexed by PROTO_x */ IPv4_UDP_HEADER_SIZE, /* IPv4 */ IPv4_TCP_HEADER_SIZE, IPv4_TCP_HEADER_SIZE, +#ifdef ENABLE_PLUGIN + INDIRECT_HEADER_SIZE, +#endif IPv6_UDP_HEADER_SIZE, /* IPv6 */ IPv6_TCP_HEADER_SIZE, IPv6_TCP_HEADER_SIZE, @@ -1103,9 +1107,46 @@ bind_local(struct link_socket *sock, const sa_family_t ai_family) } } +#ifdef ENABLE_PLUGIN + +static void +create_socket_indirect(struct link_socket *sock, sa_family_t ai_family) +{ + struct addrinfo *bind_addresses = NULL; + if (sock->bind_local) + { + bind_addresses = sock->info.lsa->bind_local; + } + + sock->indirect = transport_bind(sock->info.plugins, + sock->info.transport_plugin_argv, + ai_family, + bind_addresses); +} + +bool +proto_is_indirect(int proto) +{ + return proto == PROTO_INDIRECT; +} + +#else /* ifdef ENABLE_PLUGIN */ + +static void +create_socket_indirect(struct link_socket *sock, sa_family_t ai_family) +{ +} + +#endif /* ENABLE_PLUGIN */ + static void create_socket(struct link_socket *sock, struct addrinfo *addr) { + if (proto_is_indirect(sock->info.proto)) + { + create_socket_indirect(sock, addr->ai_family); + } + if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM) { sock->sd = create_socket_udp(addr, sock->sockflags); @@ -2279,7 +2320,11 @@ link_socket_init_phase2(struct link_socket *sock, } /* If socket has not already been created create it now */ - if (sock->sd == SOCKET_UNDEFINED) + if (sock->sd == SOCKET_UNDEFINED +#ifdef ENABLE_PLUGIN + && !sock->indirect +#endif + ) { /* If we have no --remote and have still not figured out the * protocol family to use we will use the first of the bind */ @@ -2300,7 +2345,11 @@ link_socket_init_phase2(struct link_socket *sock, } /* Socket still undefined, give a warning and abort connection */ - if (sock->sd == SOCKET_UNDEFINED) + if (sock->sd == SOCKET_UNDEFINED +#ifdef ENABLE_PLUGIN + && !sock->indirect +#endif + ) { msg(M_WARN, "Could not determine IPv4/IPv6 protocol"); sig_info->signal_received = SIGUSR1; @@ -2338,7 +2387,10 @@ link_socket_init_phase2(struct link_socket *sock, } } - phase2_set_socket_flags(sock); + if (sock->sd != SOCKET_UNDEFINED) + { + phase2_set_socket_flags(sock); + } linksock_print_addr(sock); done: @@ -2362,6 +2414,14 @@ link_socket_close(struct link_socket *sock) const int gremlin = 0; #endif +#ifdef ENABLE_PLUGIN + if (sock->indirect) + { + sock->indirect->vtab->close(sock->indirect); + sock->indirect = NULL; + } +#endif + if (socket_defined(sock->sd)) { #ifdef _WIN32 @@ -3143,16 +3203,25 @@ static const struct proto_names proto_names[] = { {"tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER}, {"tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT}, {"tcp", "TCP", AF_UNSPEC, PROTO_TCP}, +#ifdef ENABLE_PLUGIN + {"indirect", "INDIRECT", AF_UNSPEC, PROTO_INDIRECT}, +#endif /* force IPv4 */ {"udp4", "UDPv4", AF_INET, PROTO_UDP}, {"tcp4-server","TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER}, {"tcp4-client","TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT}, {"tcp4", "TCPv4", AF_INET, PROTO_TCP}, +#ifdef ENABLE_PLUGIN + {"indirect4", "INDIRECT_IPv4", AF_INET, PROTO_INDIRECT}, +#endif /* force IPv6 */ {"udp6","UDPv6", AF_INET6, PROTO_UDP}, {"tcp6-server","TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER}, {"tcp6-client","TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT}, {"tcp6","TCPv6", AF_INET6, PROTO_TCP}, +#ifdef ENABLE_PLUGIN + {"indirect6", "INDIRECT_IPv6", AF_INET6, PROTO_INDIRECT}, +#endif }; bool @@ -3167,6 +3236,10 @@ proto_is_net(int proto) bool proto_is_dgram(int proto) { + if (proto_is_indirect(proto)) + { + return true; + } return proto_is_udp(proto); } @@ -3301,6 +3374,18 @@ proto_remote(int proto, bool remote) return "TCPv4_CLIENT"; } +#ifdef ENABLE_PLUGIN + if (proto == PROTO_INDIRECT) + { + /* FIXME: the string reported here should match the actual transport + * protocol being used, however in this function we have no knowledge of + * what protocol is exactly being used by the transport-plugin. + * Therefore we simply return INDIRECT for now. + */ + return "INDIRECT"; + } +#endif + ASSERT(0); return ""; /* Make the compiler happy */ } @@ -3360,6 +3445,29 @@ link_socket_read_tcp(struct link_socket *sock, } } +#ifdef ENABLE_PLUGIN + +int +link_socket_read_indirect(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *from) +{ + ASSERT(sock->indirect); + socklen_t fromlen = sizeof(from->dest.addr); + socklen_t expectedlen = af_addr_size(sock->info.af); + addr_zero_host(&from->dest); + int len = transport_read(sock->indirect, buf, + &from->dest.addr.sa, &fromlen); + if (len >= 0 && expectedlen && fromlen != expectedlen) + { + bad_address_length(fromlen, expectedlen); + } + + return buf->len = len; +} + +#endif /* ENABLE_PLUGIN */ + #ifndef _WIN32 #if ENABLE_IP_PKTINFO @@ -3492,6 +3600,21 @@ link_socket_write_tcp(struct link_socket *sock, #endif } +#ifdef ENABLE_PLUGIN + +int +link_socket_write_indirect(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *to) +{ + ASSERT(sock->indirect); + struct sockaddr *addr = (struct sockaddr *) &to->dest.addr.sa; + socklen_t addrlen = (socklen_t) af_addr_size(to->dest.addr.sa.sa_family); + return transport_write(sock->indirect, buf, addr, addrlen); +} + +#endif /* ENABLE_PLUGIN */ + #if ENABLE_IP_PKTINFO size_t @@ -3580,6 +3703,12 @@ link_socket_write_udp_posix_sendmsg(struct link_socket *sock, int socket_recv_queue(struct link_socket *sock, int maxsize) { + if (proto_is_indirect(sock->info.proto)) + { + /* Indirect handler will take care of this, so do nothing. */ + return IOSTATE_QUEUED; + } + if (sock->reads.iostate == IOSTATE_INITIAL) { WSABUF wsabuf[1]; @@ -3952,7 +4081,16 @@ socket_set(struct link_socket *s, /* if persistent is defined, call event_ctl only if rwflags has changed since last call */ if (!persistent || *persistent != rwflags) { - event_ctl(es, socket_event_handle(s), rwflags, arg); +#ifdef ENABLE_PLUGIN + if (s->indirect) + { + transport_request_events(s->indirect, es, rwflags); + } + else +#endif + { + event_ctl(es, socket_event_handle(s), rwflags, arg); + } if (persistent) { *persistent = rwflags; diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index f49e6315..73a4ab6f 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -34,6 +34,7 @@ #include "proxy.h" #include "socks.h" #include "misc.h" +#include "transport.h" /* * OpenVPN's default port number as assigned by IANA. @@ -115,6 +116,7 @@ struct link_socket_info bool connection_established; const char *ipchange_command; const struct plugin_list *plugins; + const char **transport_plugin_argv; bool remote_float; int proto; /* Protocol (PROTO_x defined below) */ sa_family_t af; /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/ @@ -175,6 +177,11 @@ struct link_socket struct rw_handle listen_handle; /* For listening on TCP socket in server mode */ #endif +#ifdef ENABLE_PLUGIN + /* only valid when info.proto == PROTO_INDIRECT */ + openvpn_transport_socket_t indirect; +#endif + /* used for printing status info only */ unsigned int rwflags_debug; @@ -1049,12 +1056,53 @@ int link_socket_read_udp_posix(struct link_socket *sock, #endif +#ifdef ENABLE_PLUGIN + +int link_socket_read_indirect(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *from); + +int link_socket_write_indirect(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *from); + +bool proto_is_indirect(int proto); + +#else /* ifdef ENABLE_PLUGIN */ + +static int +link_socket_read_indirect(struct link_socket *sock, + struct buffer *buf, struct link_socket_actual *from) +{ + return -1; +} + +static int +link_socket_write_indirect(struct link_socket *sock, + struct buffer *buf, struct link_socket_actual *from) +{ + return -1; +} + +static bool +proto_is_indirect(int proto) +{ + return false; +} + +#endif /* ENABLE_PLUGIN */ + /* read a TCP or UDP packet from link */ static inline int link_socket_read(struct link_socket *sock, struct buffer *buf, struct link_socket_actual *from) { + if (proto_is_indirect(sock->info.proto)) + { + return link_socket_read_indirect(sock, buf, from); + } + if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ { int res; @@ -1169,6 +1217,11 @@ link_socket_write(struct link_socket *sock, struct buffer *buf, struct link_socket_actual *to) { + if (proto_is_indirect(sock->info.proto)) + { + return link_socket_write_indirect(sock, buf, to); + } + if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ { return link_socket_write_udp(sock, buf, to); @@ -1264,6 +1317,23 @@ socket_reset_listen_persistent(struct link_socket *s) #endif } +#ifdef ENABLE_PLUGIN + +static inline unsigned +socket_indirect_pump(struct link_socket *s, struct event_set_return *esr, int *esrlen) +{ + if (s->indirect) + { + return transport_pump(s->indirect, esr, esrlen); + } + else + { + return 0; + } +} + +#endif /* ENABLE_PLUGIN */ + const char *socket_stat(const struct link_socket *s, unsigned int rwflags, struct gc_arena *gc); #endif /* SOCKET_H */ diff --git a/src/openvpn/transport.h b/src/openvpn/transport.h index 344ce44b..37050eaf 100644 --- a/src/openvpn/transport.h +++ b/src/openvpn/transport.h @@ -27,6 +27,11 @@ #include "plugin.h" #include "openvpn-transport.h" +/* INDIRECT does not have any overhead per se, but it depends on what is + * implemented by the transport plugin + */ +#define INDIRECT_HEADER_SIZE 0 + /* Given a list of plugins and an argument list for a desired * transport plugin instance, prepare to bind new link sockets using * that transport plugin and args. If all succeeds, return true, and: