Hello all,
I wrote this back in the openvpn-2.2-beta3 days and always wanted to
submit the code but never got to it---so here it is! I used it with a
userspace slirp-stdio implementation to get a tunnel without root
priveleges.
--dev-pipe /usr/local/bin/some_script arg1 arg2 ... arg15
Fork a program (such as /usr/local/bin/some_script ) and use
its stdio for network frames. OpenVPN will not open a
TUN/TAP device, thus root privelege is not required.
You must specify tun or tap as your --device-type if --dev
does not provide auto-detection of the device type. (The
--dev device you specify will not be used.) Note that tun
and tap use different network frames: The tun interface
excludes the Ethernet frame header, and is not suitable for
use with programs like SLiRP. The tap interface uses a com‐
plete Ethernet frame.
I just forward-ported to 2.3.9 if anyone would like to test it and merge
it in upstream (2.4 changed files around, it seems, so not sure about
porting beyond 2.3.9). Tested and working in 2.2-beta3, compile-only
tested in 2.3.9.
Cheers,
--
Eric Wheeler
https://www.linuxglobal.com
>From 8cb721c4e76f4606f4452fd20a9c4d9bffc7685e Mon Sep 17 00:00:00 2001
From: Eric Wheeler <g...@linux.ewheeler.net>
Date: Fri, 17 Feb 2017 14:18:40 -0800
Subject: [PATCH] Added --dev-pipe
---
doc/openvpn.8 | 33 +++++++++++++++++++
src/openvpn/init.c | 91 +++++++++++++++++++++++++++++++++++++--------------
src/openvpn/options.c | 10 ++++++
src/openvpn/options.h | 2 ++
4 files changed, 112 insertions(+), 24 deletions(-)
diff --git a/doc/openvpn.8 b/doc/openvpn.8
index d302baa..285ac39 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -739,6 +739,39 @@ or
.B tap.
.\"*********************************************************
.TP
+.B \-\-dev\-pipe /usr/local/bin/some_script arg1 arg2 ... arg15
+Fork a program (such as
+.B /usr/local/bin/some_script
+) and use its
+.B stdio
+for network frames. OpenVPN will not open a TUN/TAP device, thus root
+privelege is not required.
+
+You must specify
+.B tun
+or
+.B tap
+as your
+.B \-\-device\-type
+if
+.B \-\-dev
+does not provide auto-detection of the device type.
+(The
+.B \-\-dev
+device you specify will not be used.) Note that
+.B tun
+and
+.B tap
+use different network frames: The
+.B tun
+interface excludes the Ethernet frame header, and is not suitable for use with
+programs like
+.B SLiRP.
+The
+.B tap
+interface uses a complete Ethernet frame.
+.\"*********************************************************
+.TP
.B \-\-topology mode
Configure virtual addressing topology when running in
.B \-\-dev tun
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 2148777..1097709 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1425,33 +1425,76 @@ do_open_tun (struct context *c)
if (c->options.routes_ipv6 && c->c1.route_ipv6_list )
do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, false,
c->c2.es);
- /* do ifconfig */
- if (!c->options.ifconfig_noexec
- && ifconfig_order () == IFCONFIG_BEFORE_TUN_OPEN)
- {
- /* guess actual tun/tap unit number that will be returned
- by open_tun */
- const char *guess = guess_tuntap_dev (c->options.dev,
- c->options.dev_type,
- c->options.dev_node,
- &gc);
- do_ifconfig (c->c1.tuntap, guess, TUN_MTU_SIZE (&c->c2.frame),
c->c2.es);
- }
+ if (!c->options.dev_pipe[0])
+ {
+ /* do ifconfig */
+ if (!c->options.ifconfig_noexec
+ && ifconfig_order () == IFCONFIG_BEFORE_TUN_OPEN)
+ {
+ /* guess actual tun/tap unit number that will be returned
+ by open_tun */
+ &gc);
+ do_ifconfig (c->c1.tuntap, guess, TUN_MTU_SIZE (&c->c2.frame),
c->c2.es);
+ }
- /* open the tun device */
- open_tun (c->options.dev, c->options.dev_type, c->options.dev_node,
- c->c1.tuntap);
+ /* open the tun device */
+ open_tun (c->options.dev, c->options.dev_type, c->options.dev_node,
+ c->c1.tuntap);
- /* set the hardware address */
- if (c->options.lladdr)
- set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es);
+ /* set the hardware address */
+ if (c->options.lladdr)
+ set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es);
- /* do ifconfig */
- 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 */
+ 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);
+ }
+ }
+ else if (c->options.dev_pipe[0])
+ {
+ int pair[2];
+ int child_pid;
+ if (socketpair(PF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+ msg (M_FATAL, "Cannot allocate a socket pair.");
+
+ msg (M_INFO, "pair[0]=%d pair[1]=%d", pair[0], pair[1]);
+
+ if ((child_pid = fork()) == -1)
+ msg (M_FATAL, "Cannot fork!");
+ else if (child_pid != 0)
+ { /* parent */
+ msg (M_INFO, "PARENT: child=%d pair[0]=%d pair[1]=%d",
child_pid, pair[0], pair[1]);
+ close(pair[0]);
+ c->c1.tuntap->fd = pair[1];
+ c->c1.tuntap->actual_name = string_alloc(
c->options.dev_pipe[0] , NULL );
+ }
+ else
+ { /* child */
+ close(pair[1]);
+
+ if (pair[0] != STDIN_FILENO) { /*Redirect standard input to
socketpair*/
+ if (dup2(pair[0], STDIN_FILENO) != STDIN_FILENO) {
+ msg (M_INFO, "Cannot dup2 stdin");
+ exit(0);
+ }
+ }
+ if (pair[0] != STDOUT_FILENO) { /*Redirect standard output to
socketpair*/
+ if (dup2(pair[0], STDOUT_FILENO) != STDOUT_FILENO) {
+ msg (M_INFO, "Cannot dup2 stdout");
+ exit(0);
+ }
+ }
+
+ execv(c->options.dev_pipe[0], c->options.dev_pipe);
+ msg (M_FATAL, "Exec failed execing %s!", c->options.dev_pipe[0]);
+ exit(1);
+ }
+ }
/* run the up script */
run_up_down (c->options.up_script,
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 1832bc5..d3b70df 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -178,6 +178,8 @@ static const char usage_message[] =
"--dev-type dt : Which device type are we using? (dt = tun or tap) Use\n"
" this option only if the tun/tap device used with --dev\n"
" does not begin with \"tun\" or \"tap\".\n"
+ "--dev-pipe prog : Use `prog`'s stdio for network frames instead of
tun/tap\n"
+ " This does not need root since it will not open a device\n"
"--dev-node node : Explicitly set the device node rather than using\n"
" /dev/net/tun, /dev/tun, /dev/tap, etc.\n"
"--lladdr hw : Set the link layer address of the tap device.\n"
@@ -1450,6 +1452,7 @@ show_settings (const struct options *o)
SHOW_STR (dev);
SHOW_STR (dev_type);
SHOW_STR (dev_node);
+ SHOW_STR (dev_pipe[0]);
SHOW_STR (lladdr);
SHOW_INT (topology);
SHOW_BOOL (tun_ipv6);
@@ -4440,6 +4443,13 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL);
options->dev_type = p[1];
}
+ else if (streq (p[0], "dev-pipe") && p[1])
+ {
+ int i;
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ for (i = 1; i < MAX_PARMS && p[i]; i++)
+ options->dev_pipe[i-1] = p[i];
+ }
else if (streq (p[0], "dev-node") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index 622706a..b9cde96 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -598,6 +598,8 @@ struct options
bool use_peer_id;
uint32_t peer_id;
+
+ char *dev_pipe[MAX_PARMS];
};
#define streq(x, y) (!strcmp((x), (y)))
--
1.8.3.1
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
_______________________________________________
Openvpn-devel mailing list
Openvpn-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openvpn-devel