From 98d1cde1c6b04996c7e7b51d4c14b90cb31d4230 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     | 43 +++++++++++++++++++++++++------------------
 src/openvpn/tun.h     |  4 ++--
 5 files changed, 37 insertions(+), 23 deletions(-)

diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 1cdef315..00606ebd 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1012,7 +1012,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() implementaions may modify its arguments */
         options->dev = basename(dev_node);
@@ -1109,7 +1109,7 @@ do_persist_tuntap(const struct options *options)
                 "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);
         if (options->persist_mode && options->lladdr)
@@ -1777,7 +1777,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 f9518146..cfdfa7d6 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -790,6 +790,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;
@@ -5190,6 +5191,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 f3cafeaf..c7c9cbd1 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -218,6 +218,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 63f9d1bf..6bcb8c25 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];
@@ -1943,7 +1943,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;
 
@@ -1968,10 +1968,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
@@ -2050,6 +2056,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);
@@ -2060,7 +2067,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);
 }
@@ -2070,7 +2077,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun
 #ifdef ENABLE_FEATURE_TUN_PERSIST
 
 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)
+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)
 {
     struct tuntap *tt;
 
@@ -2078,7 +2085,7 @@ tuncfg(const char *dev, const char *dev_type, const char *dev_node, int persist_
     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);
@@ -2210,7 +2217,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;
@@ -2569,7 +2576,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);
 
@@ -2662,7 +2669,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);
 
@@ -2801,7 +2808,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);
 
@@ -2925,7 +2932,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);
 
@@ -3144,7 +3151,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 */
@@ -3252,7 +3259,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];
@@ -5707,7 +5714,7 @@ dhcp_masq_addr(const in_addr_t local, const in_addr_t netmask, const int offset)
 }
 
 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 gc_arena gc = gc_new();
     char device_path[256];
@@ -6414,7 +6421,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 6c57ad0d..e881fae5 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -209,7 +209,7 @@ tuntap_defined(const 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);
@@ -218,7 +218,7 @@ 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,
+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);
 
-- 
2.17.1

