cernekee / ocproxy

OpenConnect proxy
Other
366 stars 39 forks source link

mirror openvpn patches #19

Closed s1341 closed 3 years ago

s1341 commented 3 years ago

Hi,

I'm interested in implementing a package for nixos, but cannot find your patchset for openvpn.

Can you mirror the patchset here please?

Thanks, s1341

michaelblyons commented 3 years ago

Is this thread what you're looking for?

Patch 1/3

Allow the tunneled traffic to be handled by an external program rather than by a real tun/tap kernel device. This allows non-root users to connect to a VPN through a userland TCP/IP stack.

Signed-off-by: Kevin Cernekee ***@gmail.com


doc/openvpn.8 | 29 +++++++++++++-- src/openvpn/init.c | 12 +++++-- src/openvpn/tun.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++---- src/openvpn/tun.h | 2 ++ 4 files changed, 132 insertions(+), 11 deletions(-)

Expand for full diff

``` diff diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 3a58317..00efeb8 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -709,17 +709,42 @@ peers which will be initiating connections by using the option. .\"********************************************************* .TP -.B \-\-dev tunX | tapX | null +.B \-\-dev tunX | tapX | null | TUN/TAP virtual network device ( .B X can be omitted for a dynamic device.) +.B tunX +or +.B tapX +is the name of a network interface that openvpn will create. + +.B null +is a special value used for testing only. It will not pass traffic. + +.B +is the full path to an executable, such as +.B |/usr/bin/ocproxy, +which will pass traffic to and from openvpn over a socketpair. This is an +alternative to using a tun/tap interface to pass traffic to and from the +OS kernel; unlike tun/tap it does not require any special privileges. The +path must start with a `|' (pipe) character. This works with either +.B \-\-dev-type tun +or +.B \-\-dev-type tap. +If left unspecified, it will default to tun. + See examples section below for an example on setting up a TUN device. You must use either tun devices on both ends of the connection or tap devices on both ends. You cannot mix them, as they -represent different underlying network layers. +represent different underlying network layers. Similarly, endpoints using +device type +.B null +will only interoperate with other +.B null +endpoints. .B tun devices encapsulate IPv4 or IPv6 (OSI Layer 3) while diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 139c625..1158ad0 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1326,7 +1326,9 @@ do_route (const struct options *options, const struct plugin_list *plugins, struct env_set *es) { - if (!options->route_noexec && ( route_list || route_ipv6_list ) ) + if (!options->route_noexec && + !tt->is_pipe && + ( route_list || route_ipv6_list ) ) { add_routes (route_list, route_ipv6_list, tt, ROUTE_OPTION_FLAGS (options), es); setenv_int (es, "redirect_gateway", route_did_redirect_default_gateway(route_list)); @@ -1450,6 +1452,7 @@ do_open_tun (struct context *c) /* do ifconfig */ c->c1.tuntap->mtu = TUN_MTU_SIZE (&c->c2.frame); if (!c->options.ifconfig_noexec + && !c->c1.tuntap->is_pipe && ifconfig_order () == IFCONFIG_BEFORE_TUN_OPEN) { /* guess actual tun/tap unit number that will be returned @@ -1462,7 +1465,8 @@ do_open_tun (struct context *c) } /* possibly add routes */ - if (route_order() == ROUTE_BEFORE_TUN) { + if (route_order() == ROUTE_BEFORE_TUN + && !c->c1.tuntap->is_pipe) { /* Ignore route_delay, would cause ROUTE_BEFORE_TUN to be ignored */ do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list, c->c1.tuntap, c->plugins, c->c2.es); @@ -1476,11 +1480,13 @@ do_open_tun (struct context *c) c->c1.tuntap); /* set the hardware address */ - if (c->options.lladdr) + if (c->options.lladdr + && !c->c1.tuntap->is_pipe) set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es); /* do ifconfig */ if (!c->options.ifconfig_noexec + && !c->c1.tuntap->is_pipe && ifconfig_order () == IFCONFIG_AFTER_TUN_OPEN) { do_ifconfig (c->c1.tuntap, c->c1.tuntap->actual_name, c->c2.es); diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 31bb583..c832528 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -103,6 +103,8 @@ dev_type_enum (const char *dev, const char *dev_type) return DEV_TYPE_TAP; else if (is_dev_type (dev, dev_type, "null")) return DEV_TYPE_NULL; + else if (dev && *dev == '|') + return DEV_TYPE_TUN; else return DEV_TYPE_UNDEF; } @@ -425,6 +427,9 @@ init_tun (const char *dev, /* --dev option */ tt->type = dev_type_enum (dev, dev_type); tt->topology = topology; + if (dev && *dev == '|') + tt->is_pipe = true; + if (ifconfig_local_parm && ifconfig_remote_netmask_parm) { bool tun = false; @@ -1290,6 +1295,67 @@ open_null (struct tuntap *tt) tt->actual_name = string_alloc ("null", NULL); } +static void +set_vpnc_vars (struct env_set *es, struct tuntap *tt) +{ + struct gc_arena gc = gc_new (); + + setenv_str (es, "INTERNAL_IP4_ADDRESS", print_in_addr_t (tt->local, 0, &gc)); + setenv_int (es, "INTERNAL_IP4_MTU", tt->mtu); + + if (tt->ipv6 && tt->did_ifconfig_ipv6_setup) + { + const char *ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); + struct buffer out6 = alloc_buf_gc (64, &gc); + + buf_printf (&out6, "%s/%d", ifconfig_ipv6_local, tt->netbits_ipv6); + setenv_str (es, "INTERNAL_IP6_NETMASK", buf_bptr (&out6)); + } + + gc_free (&gc); +} + +static void +open_pipe (const char *dev, struct tuntap *tt) +{ + struct argv argv; + struct env_set *es; + int fds[2], pid; + + if (socketpair (AF_UNIX, SOCK_DGRAM, 0, fds) == -1) + { + msg (M_FATAL | M_ERRNO, "ERROR: socketpair call failed"); + } + + tt->fd = fds[0]; + tt->actual_name = string_alloc ("pipe", NULL); + + set_nonblock (tt->fd); + set_cloexec (tt->fd); + + es = env_set_create (NULL); + setenv_int (es, "VPNFD", fds[1]); + set_vpnc_vars (es, tt); + + argv_init (&argv); + /* dev looks like: "|/path/to/program " */ + argv_printf (&argv, "/bin/sh -c %s", &dev[1]); + pid = openvpn_execve (&argv, es, S_SCRIPT | S_NOWAIT | S_SETPGRP); + argv_reset (&argv); + env_set_destroy (es); + close (fds[1]); + + /* + * This doesn't detect errors in the subprocess, but hopefully we'll notice + * if the other side of the socketpair gets closed. + */ + if (pid <= 0) + { + msg (M_FATAL, "ERROR: unable to start subprocess"); + } + tt->pipe_pid = (pid_t)pid; +} + #if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H) @@ -1385,7 +1451,11 @@ open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, if ( tt->ipv6 && ! ipv6_explicitly_supported ) msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS"); - if (tt->type == DEV_TYPE_NULL) + if (tt->is_pipe) + { + open_pipe (dev, tt); + } + else if (tt->type == DEV_TYPE_NULL) { open_null (tt); } @@ -1486,6 +1556,8 @@ close_tun_generic (struct tuntap *tt) close (tt->fd); if (tt->actual_name) free (tt->actual_name); + if (tt->pipe_pid) + kill (-tt->pipe_pid, SIGHUP); clear_tuntap (tt); } @@ -1579,11 +1651,15 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu { struct ifreq ifr; - /* - * We handle --dev null specially, we do not open /dev/null for this. - */ - if (tt->type == DEV_TYPE_NULL) + if (tt->is_pipe) { + open_pipe (dev, tt); + } + else if (tt->type == DEV_TYPE_NULL) + { + /* + * We handle --dev null specially, we do not open /dev/null for this. + */ open_null (tt); } else @@ -1880,6 +1956,12 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu */ CLEAR(ifr); + if (tt->is_pipe) + { + open_pipe (dev, tt); + return; + } + if (tt->type == DEV_TYPE_NULL) { open_null (tt); @@ -4849,7 +4931,13 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu msg( M_INFO, "open_tun, tt->ipv6=%d", tt->ipv6 ); - if (tt->type == DEV_TYPE_NULL) + if (tt->is_pipe) + { + open_pipe (dev, tt); + gc_free (&gc); + return; + } + else if (tt->type == DEV_TYPE_NULL) { open_null (tt); gc_free (&gc); diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 1b510d0..0c93a1d 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -131,6 +131,8 @@ struct tuntap # define TUNNEL_TOPOLOGY(tt) ((tt) ? ((tt)->topology) : TOP_UNDEF) int topology; /* one of the TOP_x values */ + bool is_pipe; + pid_t pipe_pid; bool did_ifconfig_setup; bool did_ifconfig_ipv6_setup; bool did_ifconfig; ```

Patch 2/3

This is to let openvpn_execve be used to create a process that runs in the background, and return its PID so that its process group can be nuked on exit.

Signed-off-by: Kevin Cernekee ***@gmail.com


src/openvpn/misc.c | 9 ++++++++- src/openvpn/misc.h | 6 ++++-- 2 files changed, 12 insertions(+), 3 deletions(-)

Expand for full diff

``` diff diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 7483184..a8018ff 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -308,6 +308,11 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i pid = fork (); if (pid == (pid_t)0) /* child side */ { + if (flags & S_SETPGRP) + { + if (setpgid (0, getpid ()) == -1) + msg (M_WARN | M_ERRNO, "openvpn_execve: setpgid failed"); + } execve (cmd, argv, envp); exit (127); } @@ -315,7 +320,9 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i msg (M_ERR, "openvpn_execve: unable to fork"); else /* parent side */ { - if (waitpid (pid, &ret, 0) != pid) + if (flags & S_NOWAIT) + ret = (int)pid; + else if (waitpid (pid, &ret, 0) != pid) ret = -1; } } diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index 41748bd..5b7aeee 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -86,8 +86,10 @@ void write_pid (const struct pid_state *state); void warn_if_group_others_accessible(const char* filename); /* system flags */ -#define S_SCRIPT (1<<0) -#define S_FATAL (1<<1) +#define S_SCRIPT (1<<0) +#define S_FATAL (1<<1) +#define S_NOWAIT (1<<2) +#define S_SETPGRP (1<<3) const char *system_error_message (int, struct gc_arena *gc); ```

Patch 3/3

open_tun() will need to access this value, so we'll store it alongside the IP/netmask addresses.

Signed-off-by: Kevin Cernekee ***@gmail.com


src/openvpn/init.c | 5 +++-- src/openvpn/tun.c | 2 +- src/openvpn/tun.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-)

Expand for full diff

``` diff diff --git a/src/openvpn/init.c b/src/openvpn/init.c index c2907cd..139c625 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1448,6 +1448,7 @@ do_open_tun (struct context *c) do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, false, c->c2.es); /* do ifconfig */ + c->c1.tuntap->mtu = TUN_MTU_SIZE (&c->c2.frame); if (!c->options.ifconfig_noexec && ifconfig_order () == IFCONFIG_BEFORE_TUN_OPEN) { @@ -1457,7 +1458,7 @@ do_open_tun (struct context *c) c->options.dev_type, c->options.dev_node, &gc); - do_ifconfig (c->c1.tuntap, guess, TUN_MTU_SIZE (&c->c2.frame), c->c2.es); + do_ifconfig (c->c1.tuntap, guess, c->c2.es); } /* possibly add routes */ @@ -1482,7 +1483,7 @@ do_open_tun (struct context *c) if (!c->options.ifconfig_noexec && ifconfig_order () == IFCONFIG_AFTER_TUN_OPEN) { - do_ifconfig (c->c1.tuntap, c->c1.tuntap->actual_name, TUN_MTU_SIZE (&c->c2.frame), c->c2.es); + do_ifconfig (c->c1.tuntap, c->c1.tuntap->actual_name, c->c2.es); } /* run the up script */ diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 4df271d..31bb583 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -631,10 +631,10 @@ void delete_route_connected_v6_net(struct tuntap * tt, void do_ifconfig (struct tuntap *tt, const char *actual, /* actual device name */ - int tun_mtu, const struct env_set *es) { struct gc_arena gc = gc_new (); + int tun_mtu = tt->mtu; if (tt->did_ifconfig_setup) { diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 631b53c..1b510d0 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -150,6 +150,7 @@ struct tuntap in_addr_t local; in_addr_t remote_netmask; in_addr_t broadcast; + int mtu; struct in6_addr local_ipv6; struct in6_addr remote_ipv6; @@ -243,7 +244,6 @@ void init_tun_post (struct tuntap *tt, void do_ifconfig (struct tuntap *tt, const char *actual, /* actual device name */ - int tun_mtu, const struct env_set *es); bool is_dev_type (const char *dev, const char *dev_type, const char *match_type); ```

cernekee commented 3 years ago

From time to time I rebase the patchset on a new openvpn release, and those can be found in my Ubuntu PPA. For instance, try:

dget -u https://launchpad.net/~cernekee/+archive/ubuntu/ppa/+sourcefiles/openvpn/2.4.3-9ppa2~artful/openvpn_2.4.3-9ppa2~artful.dsc

and then look in the openvpn-2.4.3/debian/patches/ directory.

s1341 commented 3 years ago

thanks @cernekee After further research, I found the https://github.com/crasm/vpnshift.sh tool. Which (with some patches in my fork: https://github.com/s1341/vpnshift.sh) works very well, and doesn't require patches to openvpn. I'm using that for now.