Am 30.12.18 um 12:28 schrieb Antonio Quartulli:
> From: Robin Tarsiger <rtt@dasyatidae.com>
>
> 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 <rtt@dasyatidae.com>
> [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)
The & 3 looks like some defined should be used instead.
> 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
> + )
Better use the inline funtcion proto_is_indirect (or similar
sock_is_indirect) that always returns false here and ifdef in header
than to add the ifdefs inline in the code.
> 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);
> }
I think here need to be a good explaination why indirect is dgram but
not udp and also proto_is_dgram and proto_is_udp need to get some
comment to explain their difference in usage as this is now different.
>
> @@ -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
From reading the code this function is only used in creating the string
in options_string which needs to match between peers. As the plugin
emulates UDP/DGRAM behaviour I think we should instead return here the
same as a real UDP protocol.
>
> +#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);
> +
This prototype definition looks a bit weird here. I see not reason why
the real proto_is_indirect cannot be here
> +#else /* ifdef ENABLE_PLUGIN */
> +
> +static int
> +link_socket_read_indirect(struct link_socket *sock,
> +
> +static int
> +link_socket_write_indirect(struct link_socket *sock,
> +static bool
> +proto_is_indirect(int proto)
I think functions implemented in the header should have the inline
keyword. At least the rest of the header files do it that way.
Arne
Hi,
On 23/01/2019 03:22, Arne Schwabe wrote:
> Am 30.12.18 um 12:28 schrieb Antonio Quartulli:
>> From: Robin Tarsiger <rtt@dasyatidae.com>
>>
>> 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 <rtt@dasyatidae.com>
>> [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)
>
> The & 3 looks like some defined should be used instead.
I think this is simply about fetching the last two bits..not much fuzz
here..this is mostly because of how event_set_status works. But will see
if I find a meaningful name.
>
>
>
>> 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
>> + )
>
> Better use the inline funtcion proto_is_indirect (or similar
> sock_is_indirect) that always returns false here and ifdef in header
> than to add the ifdefs inline in the code.
agreed! I am all for that! will change
>
>
>> 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);
>> }
>
> I think here need to be a good explaination why indirect is dgram but
> not udp and also proto_is_dgram and proto_is_udp need to get some
> comment to explain their difference in usage as this is now different.
I wouldn't say is_udp and is_dgram are now different, but is_dgram has
been extended to account for the indirect case as well.
>
>>
>> @@ -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
>
> From reading the code this function is only used in creating the string
> in options_string which needs to match between peers. As the plugin
> emulates UDP/DGRAM behaviour I think we should instead return here the
> same as a real UDP protocol.
well, the problem here is that if I use transport-plugin1 and you use
transport-plugin2 these strings will match between client and server
even though they should not (because the protocols being used are
actually different).
I don't think INDIRECT is UDP only. That is just how it prefers to be
treated, but could be non-UDP as well, I think. (need to double check)
>
>>
>> +#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);
>> +
>
> This prototype definition looks a bit weird here. I see not reason why
> the real proto_is_indirect cannot be here
you mean the proto_is_indirect() implementation should be here in the
header? Why?
>
>> +#else /* ifdef ENABLE_PLUGIN */
>> +
>> +static int
>> +link_socket_read_indirect(struct link_socket *sock,
>> +
>> +static int
>> +link_socket_write_indirect(struct link_socket *sock,
>
>> +static bool
>> +proto_is_indirect(int proto)
>
> I think functions implemented in the header should have the inline
> keyword. At least the rest of the header files do it that way.
yeah they should. will fix that.
>
>
> Arne
>
@@ -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];
@@ -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;
@@ -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 */
@@ -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: