From 58c7f3e45e6d073d858aff2a0e307063e7748272 Mon Sep 17 00:00:00 2001
From: Maxime Bizon <mbizon@freebox.fr>
Date: Wed, 23 Oct 2019 13:37:05 +0200
Subject: [PATCH 1/4] allow using already open tun device from fd given in
 config

---
 src/openvpn/init.c    |  6 +++---
 src/openvpn/options.c |  6 ++++++
 src/openvpn/options.h |  1 +
 src/openvpn/tun.c     | 48 +++++++++++++++++++++++++------------------
 src/openvpn/tun.h     |  6 +++---
 5 files changed, 41 insertions(+), 26 deletions(-)

diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 31ecadcc..ad51f6b7 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1050,7 +1050,7 @@ init_verb_mute(struct context *c, unsigned int flags)
 void
 init_options_dev(struct options *options)
 {
-    if (!options->dev && options->dev_node)
+	if (!options->dev && options->dev_from_fd == -1 && options->dev_node)
     {
         char *dev_node = string_alloc(options->dev_node, NULL); /* POSIX basename() implementations may modify its arguments */
         options->dev = basename(dev_node);
@@ -1196,7 +1196,7 @@ do_persist_tuntap(const struct options *options, openvpn_net_ctx_t *ctx)
                 "options --mktun or --rmtun should only be used together with --dev");
         }
 #ifdef ENABLE_FEATURE_TUN_PERSIST
-        tuncfg(options->dev, options->dev_type, options->dev_node,
+        tuncfg(options->dev, options->dev_from_fd, options->dev_type, options->dev_node,
                options->persist_mode,
                options->username, options->groupname, &options->tuntap_options,
                ctx);
@@ -1868,7 +1868,7 @@ do_open_tun(struct context *c)
     c->c1.tuntap->fd = oldtunfd;
 #endif
     /* open the tun device */
-    open_tun(c->options.dev, c->options.dev_type, c->options.dev_node,
+    open_tun(c->options.dev, c->options.dev_from_fd, c->options.dev_type, c->options.dev_node,
              c->c1.tuntap);
 
     /* set the hardware address */
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 658ca53f..70cf355d 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -799,6 +799,7 @@ init_options(struct options *o, const bool init_gc)
         gc_init(&o->gc);
         o->gc_owned = true;
     }
+    o->dev_from_fd = -1;
     o->mode = MODE_POINT_TO_POINT;
     o->topology = TOP_NET30;
     o->ce.proto = PROTO_UDP;
@@ -5504,6 +5505,11 @@ add_option(struct options *options,
         VERIFY_PERMISSION(OPT_P_GENERAL);
         options->dev = p[1];
     }
+    else if (streq (p[0], "dev-from-fd") && p[1])
+    {
+        VERIFY_PERMISSION (OPT_P_GENERAL);
+        options->dev_from_fd = positive_atoi(p[1]);
+    }
     else if (streq(p[0], "dev-type") && p[1] && !p[2])
     {
         VERIFY_PERMISSION(OPT_P_GENERAL);
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index 877e9396..c65a1ae4 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -245,6 +245,7 @@ struct options
     bool remote_random;
     const char *ipchange;
     const char *dev;
+    int dev_from_fd;
     const char *dev_type;
     const char *dev_node;
     const char *lladdr;
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 8315a426..df921baf 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -1721,7 +1721,7 @@ read_tun_header(struct tuntap *tt, uint8_t *buf, int len)
 
 #if !(defined(_WIN32) || defined(TARGET_LINUX))
 static void
-open_tun_generic(const char *dev, const char *dev_type, const char *dev_node,
+open_tun_generic(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node,
                  bool dynamic, struct tuntap *tt)
 {
     char tunname[256];
@@ -1942,7 +1942,7 @@ read_tun(struct tuntap *tt, uint8_t *buf, int len)
 #if !PEDANTIC
 
 void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node, struct tuntap *tt)
 {
     struct ifreq ifr;
 
@@ -1967,10 +1967,16 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
         /*
          * Open the interface
          */
-        if ((tt->fd = open(node, O_RDWR)) < 0)
-        {
-            msg(M_ERR, "ERROR: Cannot open TUN/TAP dev %s", node);
-        }
+	if (dev_from_fd >= 0) {
+		tt->fd = dup(dev_from_fd);
+		strncpynt (ifr.ifr_name, dev, IFNAMSIZ);
+		goto done;
+	} else {
+		if ((tt->fd = open (node, O_RDWR)) < 0)
+		{
+			msg (M_ERR, "ERROR: Cannot open TUN/TAP dev %s", node);
+		}
+	}
 
         /*
          * Process --tun-ipv6
@@ -2049,6 +2055,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
         }
 #endif /* if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN) */
 
+    done:
         set_nonblock(tt->fd);
         set_cloexec(tt->fd);
         tt->actual_name = string_alloc(ifr.ifr_name, NULL);
@@ -2059,7 +2066,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
 #else  /* if !PEDANTIC */
 
 void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node, struct tuntap *tt)
 {
     ASSERT(0);
 }
@@ -2074,9 +2081,10 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
 #endif
 
 void
-tuncfg(const char *dev, const char *dev_type, const char *dev_node,
-       int persist_mode, const char *username, const char *groupname,
-       const struct tuntap_options *options, openvpn_net_ctx_t *ctx)
+tuncfg(const char *dev, int dev_from_fd, const char *dev_type,
+       const char *dev_node, int persist_mode, const char *username,
+       const char *groupname, const struct tuntap_options *options,
+       openvpn_net_ctx_t *ctx)
 {
     struct tuntap *tt;
 
@@ -2084,7 +2092,7 @@ tuncfg(const char *dev, const char *dev_type, const char *dev_node,
     clear_tuntap(tt);
     tt->type = dev_type_enum(dev, dev_type);
     tt->options = *options;
-    open_tun(dev, dev_type, dev_node, tt);
+    open_tun(dev, dev_from_fd, dev_type, dev_node, tt);
     if (ioctl(tt->fd, TUNSETPERSIST, persist_mode) < 0)
     {
         msg(M_ERR, "Cannot ioctl TUNSETPERSIST(%d) %s", persist_mode, dev);
@@ -2225,7 +2233,7 @@ read_tun(struct tuntap *tt, uint8_t *buf, int len)
 #endif
 
 void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node, struct tuntap *tt)
 {
     int if_fd, ip_muxid, arp_muxid, arp_fd, ppa = -1;
     struct lifreq ifr;
@@ -2580,7 +2588,7 @@ read_tun(struct tuntap *tt, uint8_t *buf, int len)
 #elif defined(TARGET_OPENBSD)
 
 void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node, struct tuntap *tt)
 {
     open_tun_generic(dev, dev_type, dev_node, true, tt);
 
@@ -2674,7 +2682,7 @@ read_tun(struct tuntap *tt, uint8_t *buf, int len)
  */
 
 void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node, struct tuntap *tt)
 {
     open_tun_generic(dev, dev_type, dev_node, true, tt);
 
@@ -2814,7 +2822,7 @@ freebsd_modify_read_write_return(int len)
 }
 
 void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node, struct tuntap *tt)
 {
     open_tun_generic(dev, dev_type, dev_node, true, tt);
 
@@ -2942,7 +2950,7 @@ dragonfly_modify_read_write_return(int len)
 }
 
 void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node, struct tuntap *tt)
 {
     open_tun_generic(dev, dev_type, dev_node, true, tt);
 
@@ -3170,7 +3178,7 @@ open_darwin_utun(const char *dev, const char *dev_type, const char *dev_node, st
 #endif /* ifdef HAVE_NET_IF_UTUN_H */
 
 void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node, struct tuntap *tt)
 {
 #ifdef HAVE_NET_IF_UTUN_H
     /* If dev_node does not start start with utun assume regular tun/tap */
@@ -3277,7 +3285,7 @@ read_tun(struct tuntap *tt, uint8_t *buf, int len)
 #elif defined(TARGET_AIX)
 
 void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node, struct tuntap *tt)
 {
     char tunname[256];
     char dynamic_name[20];
@@ -6685,7 +6693,7 @@ tuntap_post_open(struct tuntap *tt, const char *device_guid)
 }
 
 void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node, struct tuntap *tt)
 {
     const char *device_guid = NULL;
 
@@ -6989,7 +6997,7 @@ ipset2ascii_all(struct gc_arena *gc)
 #else /* generic */
 
 void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node, struct tuntap *tt)
 {
     open_tun_generic(dev, dev_type, dev_node, true, tt);
 }
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index 99826cf7..549dc3b0 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -247,7 +247,7 @@ tuntap_ring_empty(struct tuntap *tt)
  * Function prototypes
  */
 
-void open_tun(const char *dev, const char *dev_type, const char *dev_node,
+void open_tun(const char *dev, int dev_from_fd, const char *dev_type, const char *dev_node,
               struct tuntap *tt);
 
 void close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx);
@@ -256,8 +256,8 @@ int write_tun(struct tuntap *tt, uint8_t *buf, int len);
 
 int read_tun(struct tuntap *tt, uint8_t *buf, int len);
 
-void tuncfg(const char *dev, const char *dev_type, const char *dev_node,
-            int persist_mode, const char *username,
+void tuncfg(const char *dev, int dev_from_fd, const char *dev_type,
+            const char *dev_node, int persist_mode, const char *username,
             const char *groupname, const struct tuntap_options *options,
             openvpn_net_ctx_t *ctx);
 
-- 
2.17.1

