summaryrefslogtreecommitdiff
path: root/src/openvpn/tun.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/tun.h')
-rw-r--r--src/openvpn/tun.h234
1 files changed, 217 insertions, 17 deletions
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index 54e1dfa..99826cf 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -27,6 +27,8 @@
#ifdef _WIN32
#include <winioctl.h>
#include <tap-windows.h>
+#include <setupapi.h>
+#include <cfgmgr32.h>
#endif
#include "buffer.h"
@@ -36,6 +38,18 @@
#include "event.h"
#include "proto.h"
#include "misc.h"
+#include "networking.h"
+#include "ring_buffer.h"
+
+#ifdef _WIN32
+#define WINTUN_COMPONENT_ID "wintun"
+
+enum windows_driver_type {
+ WINDOWS_DRIVER_UNSPECIFIED,
+ WINDOWS_DRIVER_TAP_WINDOWS6,
+ WINDOWS_DRIVER_WINTUN
+};
+#endif
#if defined(_WIN32) || defined(TARGET_ANDROID)
@@ -98,6 +112,12 @@ struct tuntap_options {
in_addr_t nbdd[N_DHCP_ADDR];
int nbdd_len;
+#define N_SEARCH_LIST_LEN 10 /* Max # of entries in domin-search list */
+
+ /* SEARCH (119), MacOS, Linux, Win10 1809+ */
+ const char *domain_search_list[N_SEARCH_LIST_LEN];
+ int domain_search_list_len;
+
/* DISABLE_NBT (43, Vendor option 001) */
bool disable_nbt;
@@ -138,7 +158,6 @@ struct tuntap
bool did_ifconfig_setup;
bool did_ifconfig_ipv6_setup;
- bool did_ifconfig;
bool persistent_if; /* if existed before, keep on program end */
@@ -152,7 +171,6 @@ struct tuntap
/* ifconfig parameters */
in_addr_t local;
in_addr_t remote_netmask;
- in_addr_t broadcast;
struct in6_addr local_ipv6;
struct in6_addr remote_ipv6;
@@ -175,10 +193,16 @@ struct tuntap
* ~0 if undefined */
DWORD adapter_index;
+ enum windows_driver_type windows_driver;
int standby_iter;
+
+ HANDLE wintun_send_ring_handle;
+ HANDLE wintun_receive_ring_handle;
+ struct tun_ring *wintun_send_ring;
+ struct tun_ring *wintun_receive_ring;
#else /* ifdef _WIN32 */
int fd; /* file descriptor for TUN/TAP dev */
-#endif
+#endif /* ifdef _WIN32 */
#ifdef TARGET_SOLARIS
int ip_fd;
@@ -205,6 +229,20 @@ tuntap_defined(const struct tuntap *tt)
#endif
}
+#ifdef _WIN32
+static inline bool
+tuntap_is_wintun(struct tuntap *tt)
+{
+ return tt && tt->windows_driver == WINDOWS_DRIVER_WINTUN;
+}
+
+static inline bool
+tuntap_ring_empty(struct tuntap *tt)
+{
+ return tuntap_is_wintun(tt) && (tt->wintun_send_ring->head == tt->wintun_send_ring->tail);
+}
+#endif
+
/*
* Function prototypes
*/
@@ -212,7 +250,7 @@ tuntap_defined(const struct tuntap *tt)
void open_tun(const char *dev, const char *dev_type, const char *dev_node,
struct tuntap *tt);
-void close_tun(struct tuntap *tt);
+void close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx);
int write_tun(struct tuntap *tt, uint8_t *buf, int len);
@@ -220,7 +258,8 @@ 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,
- const char *groupname, const struct tuntap_options *options);
+ const char *groupname, const struct tuntap_options *options,
+ openvpn_net_ctx_t *ctx);
const char *guess_tuntap_dev(const char *dev,
const char *dev_type,
@@ -238,7 +277,8 @@ struct tuntap *init_tun(const char *dev, /* --dev option */
struct addrinfo *local_public,
struct addrinfo *remote_public,
const bool strict_warn,
- struct env_set *es);
+ struct env_set *es,
+ openvpn_net_ctx_t *ctx);
void init_tun_post(struct tuntap *tt,
const struct frame *frame,
@@ -247,10 +287,17 @@ void init_tun_post(struct tuntap *tt,
void do_ifconfig_setenv(const struct tuntap *tt,
struct env_set *es);
-void do_ifconfig(struct tuntap *tt,
- const char *actual, /* actual device name */
- int tun_mtu,
- const struct env_set *es);
+/**
+ * do_ifconfig - configure the tunnel interface
+ *
+ * @param tt the tuntap interface context
+ * @param ifname the human readable interface name
+ * @param mtu the MTU value to set the interface to
+ * @param es the environment to be used when executing the commands
+ * @param ctx the networking API opaque context
+ */
+void do_ifconfig(struct tuntap *tt, const char *ifname, int tun_mtu,
+ const struct env_set *es, openvpn_net_ctx_t *ctx);
bool is_dev_type(const char *dev, const char *dev_type, const char *match_type);
@@ -266,7 +313,7 @@ void check_subnet_conflict(const in_addr_t ip,
const in_addr_t netmask,
const char *prefix);
-void warn_on_use_of_common_subnets(void);
+void warn_on_use_of_common_subnets(openvpn_net_ctx_t *ctx);
/*
* Inline functions
@@ -327,11 +374,10 @@ route_order(void)
#ifdef _WIN32
-#define TUN_PASS_BUFFER
-
struct tap_reg
{
const char *guid;
+ enum windows_driver_type windows_driver;
struct tap_reg *next;
};
@@ -342,6 +388,13 @@ struct panel_reg
struct panel_reg *next;
};
+struct device_instance_id_interface
+{
+ const char *net_cfg_instance_id;
+ const char *device_interface_list;
+ struct device_instance_id_interface *next;
+};
+
int ascii2ipset(const char *name);
const char *ipset2ascii(int index);
@@ -457,10 +510,158 @@ read_tun_buffered(struct tuntap *tt, struct buffer *buf)
return tun_finalize(tt->hand, &tt->reads, buf);
}
+static inline ULONG
+wintun_ring_packet_align(ULONG size)
+{
+ return (size + (WINTUN_PACKET_ALIGN - 1)) & ~(WINTUN_PACKET_ALIGN - 1);
+}
+
+static inline ULONG
+wintun_ring_wrap(ULONG value)
+{
+ return value & (WINTUN_RING_CAPACITY - 1);
+}
+
+static inline void
+read_wintun(struct tuntap *tt, struct buffer *buf)
+{
+ struct tun_ring *ring = tt->wintun_send_ring;
+ ULONG head = ring->head;
+ ULONG tail = ring->tail;
+ ULONG content_len;
+ struct TUN_PACKET *packet;
+ ULONG aligned_packet_size;
+
+ *buf = tt->reads.buf_init;
+ buf->len = 0;
+
+ if ((head >= WINTUN_RING_CAPACITY) || (tail >= WINTUN_RING_CAPACITY))
+ {
+ msg(M_INFO, "Wintun: ring capacity exceeded");
+ buf->len = -1;
+ return;
+ }
+
+ if (head == tail)
+ {
+ /* nothing to read */
+ return;
+ }
+
+ content_len = wintun_ring_wrap(tail - head);
+ if (content_len < sizeof(struct TUN_PACKET_HEADER))
+ {
+ msg(M_INFO, "Wintun: incomplete packet header in send ring");
+ buf->len = -1;
+ return;
+ }
+
+ packet = (struct TUN_PACKET *) &ring->data[head];
+ if (packet->size > WINTUN_MAX_PACKET_SIZE)
+ {
+ msg(M_INFO, "Wintun: packet too big in send ring");
+ buf->len = -1;
+ return;
+ }
+
+ aligned_packet_size = wintun_ring_packet_align(sizeof(struct TUN_PACKET_HEADER) + packet->size);
+ if (aligned_packet_size > content_len)
+ {
+ msg(M_INFO, "Wintun: incomplete packet in send ring");
+ buf->len = -1;
+ return;
+ }
+
+ buf_write(buf, packet->data, packet->size);
+
+ head = wintun_ring_wrap(head + aligned_packet_size);
+ ring->head = head;
+}
+
+static inline bool
+is_ip_packet_valid(const struct buffer *buf)
+{
+ const struct openvpn_iphdr *ih = (const struct openvpn_iphdr *)BPTR(buf);
+
+ if (OPENVPN_IPH_GET_VER(ih->version_len) == 4)
+ {
+ if (BLEN(buf) < sizeof(struct openvpn_iphdr))
+ {
+ return false;
+ }
+ }
+ else if (OPENVPN_IPH_GET_VER(ih->version_len) == 6)
+ {
+ if (BLEN(buf) < sizeof(struct openvpn_ipv6hdr))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static inline int
+write_wintun(struct tuntap *tt, struct buffer *buf)
+{
+ struct tun_ring *ring = tt->wintun_receive_ring;
+ ULONG head = ring->head;
+ ULONG tail = ring->tail;
+ ULONG aligned_packet_size;
+ ULONG buf_space;
+ struct TUN_PACKET *packet;
+
+ /* wintun marks ring as corrupted (overcapacity) if it receives invalid IP packet */
+ if (!is_ip_packet_valid(buf))
+ {
+ msg(D_LOW, "write_wintun(): drop invalid IP packet");
+ return 0;
+ }
+
+ if ((head >= WINTUN_RING_CAPACITY) || (tail >= WINTUN_RING_CAPACITY))
+ {
+ msg(M_INFO, "write_wintun(): head/tail value is over capacity");
+ return -1;
+ }
+
+ aligned_packet_size = wintun_ring_packet_align(sizeof(struct TUN_PACKET_HEADER) + BLEN(buf));
+ buf_space = wintun_ring_wrap(head - tail - WINTUN_PACKET_ALIGN);
+ if (aligned_packet_size > buf_space)
+ {
+ msg(M_INFO, "write_wintun(): ring is full");
+ return 0;
+ }
+
+ /* copy packet size and data into ring */
+ packet = (struct TUN_PACKET * )&ring->data[tail];
+ packet->size = BLEN(buf);
+ memcpy(packet->data, BPTR(buf), BLEN(buf));
+
+ /* move ring tail */
+ ring->tail = wintun_ring_wrap(tail + aligned_packet_size);
+ if (ring->alertable != 0)
+ {
+ SetEvent(tt->rw_handle.write);
+ }
+
+ return BLEN(buf);
+}
+
static inline int
write_tun_buffered(struct tuntap *tt, struct buffer *buf)
{
- return tun_write_win32(tt, buf);
+ if (tt->windows_driver == WINDOWS_DRIVER_WINTUN)
+ {
+ return write_wintun(tt, buf);
+ }
+ else
+ {
+ return tun_write_win32(tt, buf);
+ }
}
#else /* ifdef _WIN32 */
@@ -504,7 +705,7 @@ tun_event_handle(const struct tuntap *tt)
#endif
}
-static inline unsigned int
+static inline void
tun_set(struct tuntap *tt,
struct event_set *es,
unsigned int rwflags,
@@ -523,14 +724,13 @@ tun_set(struct tuntap *tt,
}
}
#ifdef _WIN32
- if (rwflags & EVENT_READ)
+ if (tt->windows_driver == WINDOWS_DRIVER_TAP_WINDOWS6 && (rwflags & EVENT_READ))
{
tun_read_queue(tt, 0);
}
#endif
tt->rwflags_debug = rwflags;
}
- return rwflags;
}
const char *tun_stat(const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc);