#include "syshead.h"
+#include "openvpn.h"
#include "tun.h"
#include "fdmisc.h"
#include "common.h"
return has_digit(dev);
}
+#if defined(TARGET_LINUX)
+static bool
+tun_dco_enabled(struct tuntap *tt)
+{
+ return !tt->options.disable_dco;
+}
+#endif
+
+
#if !(defined(_WIN32) || defined(TARGET_LINUX))
static void
open_tun_generic(const char *dev, const char *dev_type, const char *dev_node,
}
#endif /* !_WIN32 && !TARGET_LINUX */
+#if defined(TARGET_LINUX)
+static void
+open_tun_dco_generic(const char *dev, const char *dev_type,
+ struct tuntap *tt, openvpn_net_ctx_t *ctx)
+{
+ char dynamic_name[256];
+ bool dynamic_opened = false;
+
+ if (tt->type == DEV_TYPE_NULL)
+ {
+ open_null(tt);
+ return;
+ }
+
+ /*
+ * dynamic open is indicated by --dev specified without
+ * explicit unit number. Try opening DCO device named "[dev]n"
+ * where n = [0, 255].
+ */
+
+ if (!tun_name_is_fixed(dev))
+ {
+ for (int i = 0; i < 256; ++i)
+ {
+ openvpn_snprintf(dynamic_name, sizeof(dynamic_name),
+ "%s%d", dev, i);
+ if (open_tun_dco(tt, ctx, dynamic_name) == 0)
+ {
+ dynamic_opened = true;
+ msg(M_INFO, "DCO device %s opened", dynamic_name);
+ break;
+ }
+ msg(D_READ_WRITE | M_ERRNO, "Tried opening %s (failed)", dynamic_name);
+ }
+ if (!dynamic_opened)
+ {
+ msg(M_FATAL, "Cannot allocate DCO dev dynamically");
+ }
+ /* tt->actual_name is passed to up and down scripts and used as
+ * the ifconfig dev name */
+ tt->actual_name = string_alloc(dynamic_name, NULL);
+ }
+ /*
+ * explicit unit number specified
+ */
+ else
+ {
+ int ret = open_tun_dco(tt, ctx, dev);
+ if (ret == -EEXIST)
+ {
+ msg(M_INFO, "DCO device %s already exists, won't be destroyed at shutdown",
+ dev);
+ tt->persistent_if = true;
+ }
+ else if (ret < 0)
+ {
+ msg(M_ERR, "Cannot open DCO device %s: %s (%d)", dev,
+ strerror(-ret), ret);
+ }
+ else
+ {
+ msg(M_INFO, "DCO device %s opened", dev);
+ }
+
+ /* tt->actual_name is passed to up and down scripts and used as the ifconfig dev name */
+ tt->actual_name = string_alloc(dev, NULL);
+ }
+}
+#endif /* TARGET_LINUX */
+
#if !defined(_WIN32)
static void
close_tun_generic(struct tuntap *tt)
#if defined (TARGET_ANDROID)
void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt,
+ openvpn_net_ctx_t *ctx)
{
#define ANDROID_TUNNAME "vpnservice-tun"
struct user_pass up;
#if !PEDANTIC
void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt,
+ openvpn_net_ctx_t *ctx)
{
struct ifreq ifr;
{
open_null(tt);
}
+ else if (tun_dco_enabled(tt))
+ {
+ open_tun_dco_generic(dev, dev_type, tt, ctx);
+ }
else
{
/*
#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, const char *dev_type, const char *dev_node, struct tuntap *tt,
+ openvpn_net_ctx_t *ctx)
{
ASSERT(0);
}
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_type, dev_node, tt, ctx);
if (ioctl(tt->fd, TUNSETPERSIST, persist_mode) < 0)
{
msg(M_ERR, "Cannot ioctl TUNSETPERSIST(%d) %s", persist_mode, dev);
net_ctx_reset(ctx);
}
+#ifdef TARGET_LINUX
+ if (tun_dco_enabled(tt))
+ {
+ close_tun_dco(tt, ctx);
+ }
+#endif
close_tun_generic(tt);
free(tt);
}
#endif
void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt,
+ openvpn_net_ctx_t *ctx)
{
int if_fd, ip_muxid, arp_muxid, arp_fd, ppa = -1;
struct lifreq ifr;
#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, const char *dev_type, const char *dev_node, struct tuntap *tt,
+ openvpn_net_ctx_t *ctx)
{
open_tun_generic(dev, dev_type, dev_node, true, tt);
*/
void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt,
+ openvpn_net_ctx_t *ctx)
{
open_tun_generic(dev, dev_type, dev_node, true, tt);
}
void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt,
+ openvpn_net_ctx_t *ctx)
{
open_tun_generic(dev, dev_type, dev_node, true, tt);
}
void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt,
+ openvpn_net_ctx_t *ctx)
{
open_tun_generic(dev, dev_type, dev_node, true, tt);
#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, const char *dev_type, const char *dev_node, struct tuntap *tt,
+ openvpn_net_ctx_t *ctx)
{
#ifdef HAVE_NET_IF_UTUN_H
/* If dev_node does not start start with utun assume regular tun/tap */
#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, const char *dev_type, const char *dev_node, struct tuntap *tt,
+ openvpn_net_ctx_t *ctx)
{
char tunname[256];
char dynamic_name[20];
}
void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt,
+ openvpn_net_ctx_t *ctx)
{
const char *device_guid = NULL;
#else /* generic */
void
-open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt,
+ openvpn_net_ctx_t *ctx)
{
open_tun_generic(dev, dev_type, dev_node, true, tt);
}