Hello list,

I implemented support for the TAP-Windows6 driver, which is used by openvpn to 
support
Windows.
I developed it on top of commit 1dabd0fb1cfdb5b3381d45a39a7cb134651b72a9.

The diff attached to this email contains the following:
*support to manage IPs with kernel-iph on top of Martin Willi's branch win-vip.
 It contains changes to honor charon.install_virtual_ip and 
charon.install_virtual_ip_on.
*changes to kernel-libipsec and libipsec to work on Windows correctly
 handle_plain is implemented with asynchronous IO on top of 
WaitForMultipleObjects() and events.
*support to open and configure TAP devices on Windows in libstrongswan
*IPv4 and IPv6 support

My changes are under the MIT-X11 license where required. The repo "strongswan" 
on my Github account[1]
contains all the required changes.

The performance of the driver is limited to 60 Mbit/s. The TAP-Windows6 driver 
is known to be quite slow,
so I do not think that is an issue that can be fixed by changes to my code. You 
might reach higher speeds
if you use a faster test environment than me.
My test environment is a host with the Intel(R) Core(TM) i7-3820 CPU CPU with 
four cores at 3.60 GHz.
Windows ran in a VirtualBox VM with 3 cores. The test was performed using 
iperf3 over a tunnel with 60 seconds.
The server was on the VM host. The client was on the VM guest.
In my test, about 90% of the CPU was maxed out.

To make use of the TAP-Windows6 driver, it needs to be patched with the changes 
that can be found in the
fork on my Github account[2]. It implements an option to disable the ARP source 
check in the ARP
handling code of the driver. The patch is already known by OpenVPN Tech, which 
developed and maintains the driver, and should be applied in the next months.
It is tracked under #721 on the openvpn bug tracker[3]. The TAP-Windows6 
support that I implemented does
not work without it. It theoretically could, but that requires that the driver 
handles ARP requests for all
IP addresses that the Windows host tries to reach over it and fills up the 
neighbor table.

Please take a look at it and tell me what is required to get this merged into 
the master branch of strongSwan.

[1] https://github.com/Thermi/strongswan
[2] https://github.com/Thermi/tap-windows6
[3] https://community.openvpn.net/openvpn/ticket/721

-- 

Mit freundlichen Grüßen/Kind Regards,
Noel Kuntze

GPG Key ID: 0x63EC6658
Fingerprint: 23CA BB60 2146 05E7 7278 6592 3839 298F 63EC 6658

diff --git a/scripts/test.sh b/scripts/test.sh
index a8c2e3e..b71c7e4 100755
--- a/scripts/test.sh
+++ b/scripts/test.sh
@@ -60,7 +60,7 @@ win*)
 			--enable-updown --enable-ext-auth
 			--enable-tnccs-20 --enable-imc-attestation --enable-imv-attestation
 			--enable-imc-os --enable-imv-os --enable-tnc-imv --enable-tnc-imc
-			--enable-pki --enable-swanctl --enable-socket-win"
+			--enable-pki --enable-swanctl --enable-socket-win --enable-kernel-libipsec --enable-libipsec"
 	# no make check for Windows binaries
 	TARGET=
 	CFLAGS="$CFLAGS -mno-ms-bitfields"
diff --git a/src/libcharon/plugins/kernel_iph/kernel_iph_net.c b/src/libcharon/plugins/kernel_iph/kernel_iph_net.c
index 3633213..11a634a 100644
--- a/src/libcharon/plugins/kernel_iph/kernel_iph_net.c
+++ b/src/libcharon/plugins/kernel_iph/kernel_iph_net.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2013 Martin Willi
  * Copyright (C) 2013 revosec AG
+ * Copyright (C) 2016 Noel Kuntze
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -74,9 +75,40 @@ struct private_kernel_iph_net_t {
 	 * Roam event due to address change?
 	 */
 	bool roam_address;
+
+        /**
+         * Whether to install virtual IPs
+         */
+        bool install_virtual_ip;
+
+        /**
+         * Where to install virtual IPs
+         */
+
+        char *install_virtual_ip_on;
 };
 
 /**
+ * Interface address entry
+ */
+typedef struct {
+	/** address */
+	host_t *ip;
+	/** is virtual installed by us? */
+	bool virtual;
+} addr_t;
+
+/**
+ * Clean up an addr_t
+ */
+CALLBACK(addr_destroy, void,
+	addr_t *this)
+{
+	this->ip->destroy(this->ip);
+	free(this);
+}
+
+/**
  * Interface entry
  */
 typedef struct  {
@@ -90,7 +122,7 @@ typedef struct  {
 	DWORD iftype;
 	/** interface status */
 	IF_OPER_STATUS status;
-	/** list of known addresses, as host_t */
+	/** list of known addresses, as addr_t */
 	linked_list_t *addrs;
 } iface_t;
 
@@ -99,11 +131,18 @@ typedef struct  {
  */
 static void iface_destroy(iface_t *this)
 {
-	this->addrs->destroy_offset(this->addrs, offsetof(host_t, destroy));
+	this->addrs->destroy_function(this->addrs, addr_destroy);
 	free(this->ifname);
 	free(this->ifdesc);
 	free(this);
 }
+/**
+ * find an interface entry by name
+ */
+static bool iface_by_name(iface_t *this, char *ifname)
+{
+	return streq(this->ifname, ifname);
+}
 
 /**
  * Enum names for Windows IF_OPER_STATUS
@@ -155,6 +194,70 @@ static void fire_roam_event(private_kernel_iph_net_t *this, bool address)
 }
 
 /**
+ * Add an address entry to a named interface, return ifindex
+ */
+static DWORD add_addr(private_kernel_iph_net_t *this, char *name, host_t *ip,
+					  bool virtual)
+{
+	enumerator_t *enumerator;
+	addr_t *addr;
+	iface_t *iface;
+	DWORD ifindex = 0;
+
+	this->mutex->lock(this->mutex);
+	enumerator = this->ifaces->create_enumerator(this->ifaces);
+	while (enumerator->enumerate(enumerator, &iface))
+	{
+		if (streq(name, iface->ifname))
+		{
+			INIT(addr,
+				.ip = ip->clone(ip),
+				.virtual = virtual,
+			);
+			iface->addrs->insert_last(iface->addrs, addr);
+			ifindex = iface->ifindex;
+			break;
+		}
+	}
+	enumerator->destroy(enumerator);
+	this->mutex->unlock(this->mutex);
+
+	return ifindex;
+}
+
+/**
+ * Remove address entry from named interface, return ifindex
+ */
+static DWORD remove_addr(private_kernel_iph_net_t *this, host_t *ip)
+{
+	enumerator_t *ifaces, *addrs;
+	iface_t *iface;
+	addr_t *addr;
+	DWORD ifindex = 0;
+
+	this->mutex->lock(this->mutex);
+	ifaces = this->ifaces->create_enumerator(this->ifaces);
+	while (!ifindex && ifaces->enumerate(ifaces, &iface))
+	{
+		addrs = iface->addrs->create_enumerator(iface->addrs);
+		while (!ifindex && addrs->enumerate(addrs, &addr))
+		{
+			if (ip->ip_equals(ip, addr->ip))
+			{
+				iface->addrs->remove_at(iface->addrs, addrs);
+				addr_destroy(addr);
+				ifindex = iface->ifindex;
+			}
+		}
+		addrs->destroy(addrs);
+	}
+	ifaces->destroy(ifaces);
+	this->mutex->unlock(this->mutex);
+
+	return ifindex;
+}
+
+/**
  * Update addresses for an iface entry
  */
 static void update_addrs(private_kernel_iph_net_t *this, iface_t *entry,
@@ -163,7 +266,8 @@ static void update_addrs(private_kernel_iph_net_t *this, iface_t *entry,
 	IP_ADAPTER_UNICAST_ADDRESS *current;
 	enumerator_t *enumerator;
 	linked_list_t *list;
-	host_t *host, *old;
+	host_t *host;
+	addr_t *aentry;
 	bool changes = FALSE;
 
 	list = entry->addrs;
@@ -185,21 +289,27 @@ static void update_addrs(private_kernel_iph_net_t *this, iface_t *entry,
 		host = host_create_from_sockaddr(current->Address.lpSockaddr);
 		if (host)
 		{
-			bool found = FALSE;
+			addr_t *found = FALSE;
 
 			enumerator = list->create_enumerator(list);
-			while (enumerator->enumerate(enumerator, &old))
+			while (enumerator->enumerate(enumerator, &aentry))
 			{
-				if (host->ip_equals(host, old))
+				if (host->ip_equals(host, aentry->ip))
 				{
 					list->remove_at(list, enumerator);
-					old->destroy(old);
-					found = TRUE;
+					found = aentry;
+					break;
 				}
 			}
 			enumerator->destroy(enumerator);
 
-			entry->addrs->insert_last(entry->addrs, host);
+			if (!found)
+			{
+				INIT(found,
+					.ip = host->clone(host),
+				);
+			}
+			entry->addrs->insert_last(entry->addrs, found);
 
 			if (!found && log)
 			{
@@ -207,18 +317,19 @@ static void update_addrs(private_kernel_iph_net_t *this, iface_t *entry,
 					 host, entry->ifindex, entry->ifdesc);
 				changes = TRUE;
 			}
+			host->destroy(host);
 		}
 	}
 
-	while (list->remove_first(list, (void**)&old) == SUCCESS)
+	while (list->remove_first(list, (void**)&aentry) == SUCCESS)
 	{
 		if (log)
 		{
 			DBG1(DBG_KNL, "%H disappeared from interface %u '%s'",
-				 old, entry->ifindex, entry->ifdesc);
+				 aentry->ip, entry->ifindex, entry->ifdesc);
 			changes = TRUE;
 		}
-		old->destroy(old);
+		addr_destroy(aentry);
 	}
 	list->destroy(list);
 
@@ -413,15 +524,15 @@ static iface_t* address2entry(private_kernel_iph_net_t *this, host_t *ip)
 {
 	enumerator_t *ifaces, *addrs;
 	iface_t *entry, *found = NULL;
-	host_t *host;
+	addr_t *addr;
 
 	ifaces = this->ifaces->create_enumerator(this->ifaces);
 	while (!found && ifaces->enumerate(ifaces, &entry))
 	{
 		addrs = entry->addrs->create_enumerator(entry->addrs);
-		while (!found && addrs->enumerate(addrs, &host))
+		while (!found && addrs->enumerate(addrs, &addr))
 		{
-			if (host->ip_equals(host, ip))
+			if (ip->ip_equals(ip, addr->ip))
 			{
 				found = entry;
 			}
@@ -433,6 +544,31 @@ static iface_t* address2entry(private_kernel_iph_net_t *this, host_t *ip)
 	return found;
 }
 
+/**
+ * Find an interface index by interface name
+ */
+static DWORD ifname2index(private_kernel_iph_net_t *this, char *name)
+{
+	enumerator_t *enumerator;
+	iface_t *entry;
+	DWORD ifindex = 0;
+
+	this->mutex->lock(this->mutex);
+	enumerator = this->ifaces->create_enumerator(this->ifaces);
+	while (enumerator->enumerate(enumerator, &entry))
+	{
+		if (streq(name, entry->ifname))
+		{
+			ifindex = entry->ifindex;
+			break;
+		}
+	}
+	enumerator->destroy(enumerator);
+	this->mutex->unlock(this->mutex);
+
+	return ifindex;
+}
+
 METHOD(kernel_net_t, get_interface_name, bool,
 	private_kernel_iph_net_t *this, host_t* ip, char **name)
 {
@@ -466,9 +602,11 @@ typedef struct {
 } addr_enumerator_t;
 
 METHOD(enumerator_t, addr_enumerate, bool,
+
 	addr_enumerator_t *this, host_t **host)
 {
 	iface_t *entry;
+	addr_t *addr;
 
 	while (TRUE)
 	{
@@ -490,8 +628,13 @@ METHOD(enumerator_t, addr_enumerate, bool,
 			}
 			this->addrs = entry->addrs->create_enumerator(entry->addrs);
 		}
-		if (this->addrs->enumerate(this->addrs, host))
+		if (this->addrs->enumerate(this->addrs, &addr))
 		{
+			if (addr->virtual && (this->which & ADDR_TYPE_REGULAR))
+			{
+				continue;
+			}
+			*host = addr->ip;
 			return TRUE;
 		}
 		this->addrs->destroy(this->addrs);
@@ -499,7 +642,7 @@ METHOD(enumerator_t, addr_enumerate, bool,
 	}
 }
 
-METHOD(enumerator_t, addr_destroy, void,
+METHOD(enumerator_t, addr_enumerator_destroy, void,
 	addr_enumerator_t *this)
 {
 	DESTROY_IF(this->addrs);
@@ -513,18 +656,12 @@ METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
 {
 	addr_enumerator_t *enumerator;
 
-	if (!(which & ADDR_TYPE_REGULAR))
-	{
-		/* we currently have no virtual, but regular IPs only */
-		return enumerator_create_empty();
-	}
-
 	this->mutex->lock(this->mutex);
 
 	INIT(enumerator,
 		.public = {
 			.enumerate = (void*)_addr_enumerate,
-			.destroy = _addr_destroy,
+			.destroy = _addr_enumerator_destroy,
 		},
 		.which = which,
 		.ifaces = this->ifaces->create_enumerator(this->ifaces),
@@ -599,18 +736,107 @@ METHOD(kernel_net_t, get_nexthop, host_t*,
 	return NULL;
 }
 
+
+/**
+ * Create a MIB unicast row from a host
+ */
+static void host2unicast(host_t *host, int prefix, MIB_UNICASTIPADDRESS_ROW *row)
+{
+	InitializeUnicastIpAddressEntry(row);
+
+	row->Address.si_family = host->get_family(host);
+	memcpy(&row->Address, host->get_sockaddr(host),
+		   *host->get_sockaddr_len(host));
+
+	row->PrefixOrigin = IpPrefixOriginOther;
+	row->SuffixOrigin = IpSuffixOriginOther;
+	/* don't change the default route to this address */
+	row->SkipAsSource = FALSE;
+	if (prefix == -1)
+	{
+		if (row->Address.si_family == AF_INET)
+		{
+			row->OnLinkPrefixLength = 32;
+		}
+		else
+		{
+			row->OnLinkPrefixLength = 128;
+		}
+	}
+	else
+	{
+		row->OnLinkPrefixLength = prefix;
+	}
+}
+
 METHOD(kernel_net_t, add_ip, status_t,
-	private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix,
-	char *iface_name)
+	private_kernel_iph_net_t *this, host_t *vip, int prefix, char *name)
 {
-	return NOT_SUPPORTED;
+	if (!this->install_virtual_ip)
+	{	/* disabled by config */
+		return SUCCESS;
+	}
+	MIB_UNICASTIPADDRESS_ROW row;
+	u_long status;
+        iface_t *iface = NULL;
+
+	/* name of the MS Loopback adapter */
+        if (!this->install_virtual_ip_on || this->ifaces->find_first(this->ifaces, (void*)iface_by_name,
+						(void**)&iface, this->install_virtual_ip_on) != SUCCESS)
+        {
+            name = "{DB2C49B1-7C90-4253-9E61-8C6A881194ED}";
+        }
+        else
+        {
+            name = this->install_virtual_ip_on;
+        }
+	host2unicast(vip, prefix, &row);
+
+	row.InterfaceIndex = add_addr(this, name, vip, TRUE);
+	if (!row.InterfaceIndex)
+	{
+		DBG1(DBG_KNL, "interface '%s' not found", name);
+		return NOT_FOUND;
+	}
+
+	status = CreateUnicastIpAddressEntry(&row);
+	if (status != NO_ERROR)
+	{
+		DBG1(DBG_KNL, "creating IPH address entry failed: %lu", status);
+		remove_addr(this, vip);
+		return FAILED;
+	}
+	return SUCCESS;
 }
 
 METHOD(kernel_net_t, del_ip, status_t,
-	private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix,
-	bool wait)
+	private_kernel_iph_net_t *this, host_t *vip, int prefix, bool wait)
 {
-	return NOT_SUPPORTED;
+        if (!this->install_virtual_ip)
+	{	/* disabled by config */
+		return SUCCESS;
+	}
+
+	MIB_UNICASTIPADDRESS_ROW row;
+	u_long status;
+
+	host2unicast(vip, prefix, &row);
+
+	row.InterfaceIndex = remove_addr(this, vip);
+	if (!row.InterfaceIndex)
+	{
+		DBG1(DBG_KNL, "virtual IP %H not found", vip);
+		return NOT_FOUND;
+	}
+
+	status = DeleteUnicastIpAddressEntry(&row);
+	if (status != NO_ERROR)
+	{
+		DBG1(DBG_KNL, "deleting IPH address entry failed: %lu", status);
+		return FAILED;
+	}
+
+	return SUCCESS;
 }
 
 /**
@@ -629,23 +855,30 @@ static status_t manage_route(private_kernel_iph_net_t *this, bool add,
 		.Metric = 10,
 		.Protocol = MIB_IPPROTO_NETMGMT,
 	};
-	enumerator_t *enumerator;
-	iface_t *entry;
 	ULONG ret;
 
-	this->mutex->lock(this->mutex);
-	enumerator = this->ifaces->create_enumerator(this->ifaces);
-	while (enumerator->enumerate(enumerator, &entry))
+	/* if route is 0.0.0.0/0, we can't install it, as it would
+	 * overwrite the default route. Instead, we add two routes:
+	 * 0.0.0.0/1 and 128.0.0.0/1 */
+	if (prefixlen == 0)
 	{
-		if (streq(name, entry->ifname))
+		chunk_t half;
+		status_t status;
+
+		half = chunk_alloca(dst.len);
+		memset(half.ptr, 0, half.len);
+		prefixlen = 1;
+
+		status = manage_route(this, add, half, prefixlen, gtw, name);
+		if (status == SUCCESS)
 		{
-			row.InterfaceIndex = entry->ifindex;
-			break;
+			half.ptr[0] |= 0x80;
+			status = manage_route(this, add, half, prefixlen, gtw, name);
 		}
+		return status;
 	}
-	enumerator->destroy(enumerator);
-	this->mutex->unlock(this->mutex);
 
+	row.InterfaceIndex = ifname2index(this, name);
 	if (!row.InterfaceIndex)
 	{
 		return NOT_FOUND;
@@ -758,6 +991,10 @@ kernel_iph_net_t *kernel_iph_net_create()
 		},
 		.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
 		.ifaces = linked_list_create(),
+		.install_virtual_ip = lib->settings->get_bool(lib->settings,
+						"%s.install_virtual_ip", TRUE, lib->ns),
+		.install_virtual_ip_on = lib->settings->get_str(lib->settings,
+						"%s.install_virtual_ip_on", NULL, lib->ns),
 	);
 	/* PIPINTERFACE_CHANGE_CALLBACK is not using WINAPI in MinGW, which seems
 	 * to be wrong. Force a cast to our WINAPI call */
diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
index f134032..8e8c4df 100644
--- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
+++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
@@ -12,6 +12,28 @@
  * for more details.
  */
 
+/*
+ * Copyright (C) 2016 Noel Kuntze
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
 #include "kernel_libipsec_ipsec.h"
 #include "kernel_libipsec_router.h"
 
@@ -382,6 +404,9 @@ static bool install_route(private_kernel_libipsec_ipsec_t *this,
 	host_t *src, host_t *dst, traffic_selector_t *src_ts,
 	traffic_selector_t *dst_ts, policy_entry_t *policy)
 {
+#ifdef WIN32
+        uint16_t family;
+#endif
 	route_entry_t *route, *old;
 	host_t *src_ip;
 	bool is_virtual;
@@ -432,7 +457,31 @@ static bool install_route(private_kernel_libipsec_ipsec_t *this,
 		.dst_net = chunk_clone(policy->dst.net->get_address(policy->dst.net)),
 		.prefixlen = policy->dst.mask,
 	);
-#ifndef __linux__
+#ifdef __linux__
+#elif defined(WIN32)
+        /* Set out special gateway */
+        family = route->src_ip->get_family(route->src_ip);
+        switch(family)
+        {
+            case AF_INET:
+            {
+                /* For IPv4, the nxt hop is 169.254.128.128 (Configured next hop) */
+                host_t *gw = host_create_from_string("169.254.128.128", 0);
+                route->gateway = gw;
+                break;
+            }
+            case AF_INET6:
+            {
+                /* For IPv6, the next hop is fe80::8 (TAP-Windows6 magic router gw) */
+                host_t *gw = host_create_from_string("fe80::8", 0);
+                route->gateway = gw;
+                break;
+            }
+            default:
+                DBG2(DBG_ESP, "Unknown Protocol family %d encountered. Not setting a next hop.", family);
+                break;
+        }
+#else
 	/* on Linux we cant't install a gateway */
 	route->gateway = charon->kernel->get_nexthop(charon->kernel, dst, -1, src);
 #endif
@@ -475,10 +524,13 @@ static bool install_route(private_kernel_libipsec_ipsec_t *this,
 		/* add exclude route for peer */
 		add_exclude_route(this, route, src, dst);
 	}
-
+#ifdef WIN32
+        DBG1(DBG_KNL, "installing route %R src %H gateway %H dev %s",
+                dst_ts, route->src_ip, route->gateway, route->if_name);
+#else
 	DBG2(DBG_KNL, "installing route: %R src %H dev %s",
 		 dst_ts, route->src_ip, route->if_name);
-
+#endif
 	switch (charon->kernel->add_route(charon->kernel, route->dst_net,
 									  route->prefixlen, route->gateway,
 									  route->src_ip, route->if_name))
diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c
index 66141ad..debecee 100644
--- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c
+++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_router.c
@@ -13,9 +13,35 @@
  * for more details.
  */
 
+/*
+ * Copyright (C) 2016 Noel Kuntze
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
 #include <unistd.h>
 #include <fcntl.h>
 
+#ifdef WIN32
+#include <signal.h>
+#endif
+
 #include "kernel_libipsec_router.h"
 
 #include <daemon.h>
@@ -35,11 +61,22 @@ typedef struct {
 	/** virtual IP (points to internal data of tun) */
 	host_t *addr;
 	/** underlying TUN file descriptor (cached from tun) */
+#ifdef WIN32
+        HANDLE handle;
+#else
 	int fd;
+#endif /* WIN32 */
 	/** TUN device */
 	tun_device_t *tun;
 } tun_entry_t;
 
+#ifdef WIN32
+typedef struct {
+    HANDLE fileHandle;
+    OVERLAPPED *overlapped;
+    chunk_t buffer;
+} handle_overlapped_buffer_t;
+#endif
 /**
  * Single instance of the router
  */
@@ -61,7 +98,7 @@ struct private_kernel_libipsec_router_t {
 	 */
 	tun_entry_t tun;
 
-	/**
+        /**
 	 * Hashtable that maps virtual IPs to TUN devices (tun_entry_t).
 	 */
 	hashtable_t *tuns;
@@ -70,11 +107,17 @@ struct private_kernel_libipsec_router_t {
 	 * Lock for TUN device map
 	 */
 	rwlock_t *lock;
-
+#ifdef WIN32
+        /**
+         * Event we use to signal handle_plain() about changes regarding tun devices
+         */
+        HANDLE event;
+#else
 	/**
 	 * Pipe to signal handle_plain() about changes regarding TUN devices
 	 */
 	int notify[2];
+#endif
 };
 
 /**
@@ -132,6 +175,7 @@ static void deliver_plain(private_kernel_libipsec_router_t *this,
 /**
  * Read and process outbound plaintext packet for the given TUN device
  */
+#if !defined(WIN32)
 static void process_plain(tun_device_t *tun)
 {
 	chunk_t raw;
@@ -168,12 +212,316 @@ static int find_revents(struct pollfd *pfd, int count, int fd)
 	}
 	return 0;
 }
+#else
+/*
+ * Formats an error message based on error. Takes info from system.
+ * @return formatted error message
+ */
+static char* format_error(DWORD error)
+{
+            char *lpMsgBuf = NULL;
+            FormatMessage(
+                FORMAT_MESSAGE_FROM_SYSTEM |
+                FORMAT_MESSAGE_IGNORE_INSERTS,
+                NULL,
+                error,
+                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                (LPTSTR) &lpMsgBuf,
+                0,
+                NULL);
+            return lpMsgBuf;
+}
 
+/*
+ * Enqueue a Read operation on the given handle with the given struct
+ * @return: bool
+ */
+static BOOL start_read(handle_overlapped_buffer_t *structure, HANDLE event)
+{
+        DWORD error;
+        BOOL status;
+        /* Initialise read with the allocate overwrite structure */
+        status = ReadFile(structure->fileHandle, structure->buffer.ptr,
+                structure->buffer.len, NULL, structure->overlapped);
+        error = GetLastError();
+        if (status)
+        {
+            /* Read returned immediately */
+            /* We need to signal the event ourselves */
+            SetEvent(event);
+            return TRUE;
+        }
+        else
+        {
+
+            switch(error)
+            {
+                case ERROR_SUCCESS:
+                case ERROR_IO_PENDING:
+                {
+                    /* all fine */
+                    return TRUE;
+                    break;
+                }
+                default:
+                {
+                    char *error_message = format_error(error);
+                    DBG2(DBG_ESP, "Error %d.", format_error);
+                    free(error_message);
+                    return FALSE;
+                    break;
+                }
+            }
+
+        }
+}
+#endif /* WIN32 */
 /**
  * Job handling outbound plaintext packets
  */
 static job_requeue_t handle_plain(private_kernel_libipsec_router_t *this)
 {
+#ifdef WIN32
+        void **key = NULL;
+        bool oldstate;
+        uint32_t length, event_status = 0, i = 0, j = 0, offset;
+        handle_overlapped_buffer_t *bundle_array = NULL, dummy, tun_device_handle_overlapped_buffer;
+        OVERLAPPED *overlapped = NULL;
+        HANDLE *event_array = NULL, tun_device_event;
+        tun_device_t *tun_device = this->tun.tun;
+        enumerator_t *tuns_enumerator;
+
+        memset(&tun_device_handle_overlapped_buffer, 0, sizeof(handle_overlapped_buffer_t));
+        /* Reset synchronisation event */
+        ResetEvent(this->event);
+
+        length = this->tuns->get_count(this->tuns);
+
+        this->lock->read_lock(this->lock);
+        /* Read event for this->tun */
+
+        /* allocate arrays for all the structs we need */
+        /* events, overlapped structures and bundles. */
+        /* event_array holds all the HANDLE structures for the events that are
+         * used for notifying the thread of finished reads and writes.
+         */
+
+        overlapped = alloca((length+2)*sizeof(OVERLAPPED));
+        event_array = alloca((length+2)*sizeof(HANDLE));
+        bundle_array = alloca((length+2)*sizeof(handle_overlapped_buffer_t));
+
+        memset(overlapped, 0, (length+2)*sizeof(OVERLAPPED));
+        memset(bundle_array, 0, (length+2)*sizeof(handle_overlapped_buffer_t));
+
+        /* These are the arrays we're going to work with */
+
+        /* first position is the event we use for synchronisation  */
+        /* Insert notification event */
+        event_array[i] = this->event;
+        /* Insert dummy structure */
+        bundle_array[i] = dummy;
+        i++;
+
+        /* second position is this->tun */
+        /* insert event object for this->tun device */
+        tun_device_event = CreateEvent(NULL, FALSE, FALSE, FALSE);
+        if (!tun_device_event)
+        {
+            char *error_message = format_error(GetLastError());
+            free(error_message);
+            return JOB_REQUEUE_FAIR;
+        }
+        event_array[i] = tun_device_event;
+        ResetEvent(event_array[i]);
+        /* bundle for the read on this->tun */
+        /* Reserve memory for the buffer*/
+        tun_device_handle_overlapped_buffer.buffer = chunk_alloca(tun_device->get_mtu(tun_device));
+        /* Initialise the buffer */
+        memset(tun_device_handle_overlapped_buffer.buffer.ptr, 0, tun_device_handle_overlapped_buffer.buffer.len);
+
+        tun_device_handle_overlapped_buffer.fileHandle = tun_device->get_handle(tun_device);
+        tun_device_handle_overlapped_buffer.overlapped = overlapped;
+
+        tun_device_handle_overlapped_buffer.overlapped->hEvent= tun_device_event;
+
+        bundle_array[i] = tun_device_handle_overlapped_buffer;
+
+        i++;
+
+        /* Start ReadFile for this->tun.handle */
+        if (!start_read(&tun_device_handle_overlapped_buffer, tun_device_handle_overlapped_buffer.overlapped->hEvent))
+        {
+                // TODO: Cleanup heap
+                this->lock->unlock(this->lock);
+                return JOB_REQUEUE_FAIR;
+        }
+        /* pad bundle_array with two empty structures */
+        /* iterate over all our tun devices, create event handles, reset them, queue read operations on all handles */
+
+
+        tuns_enumerator = this->tuns->create_enumerator(this->tuns);
+        while(tuns_enumerator->enumerate(tuns_enumerator, key, &tun_device))
+        {
+            /* Allocate structure and buffer */
+
+            bundle_array[i].buffer = chunk_alloca(tun_device->get_mtu(tun_device));
+            memset(bundle_array[i].buffer.ptr, 0, bundle_array[i].buffer.len);
+            bundle_array[i].fileHandle = tun_device->get_handle(tun_device);
+            /* Allocate and initialise OVERLAPPED structure */
+            bundle_array[i].overlapped = alloca(sizeof(OVERLAPPED));
+            (*bundle_array[i].overlapped) = overlapped[i];
+            memset(&bundle_array[i].overlapped, 0, sizeof(OVERLAPPED));
+            /* Create unique name for that event. */
+            /* Create unique event for read accesses on that device
+             * No security attributes, no manual reset, initial state is unsignaled,
+             * name is the special name we created
+             */
+            bundle_array[i].overlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, FALSE);
+            // event_array[i] = OpenEvent(EVENT_ALL_ACCESS, FALSE, tun_device->get_read_event_name(tun_device));
+            event_array[i] = bundle_array[i].overlapped->hEvent;
+
+            if (event_array[i] == NULL)
+            {
+                char *error_message = format_error(GetLastError());
+                free(error_message);
+                return JOB_REQUEUE_FAIR;
+            }
+            i++;
+
+            /* Initialise read with the allocate overwrite structure */
+            DBG2(DBG_ESP, "Reading on %s", tun_device->get_name(tun_device));
+            if (!start_read(&bundle_array[i], bundle_array[i].overlapped->hEvent))
+            {
+                    // TODO: Cleanup heap
+                    this->lock->unlock(this->lock);
+                    return JOB_REQUEUE_FAIR;
+            }
+            i++;
+        }
+        tuns_enumerator->destroy(tuns_enumerator);
+
+        while (TRUE)
+        {
+            /* Wait for a handle to be signaled */
+            /* In the mingw64 sources, MAXIMUM_WAIT_OBJECTS is defined as 64. That means we can wait for a maximum of 64 event handles.
+             * This translates to 63 tun devices. I think this is sufficiently high to not have to implement a mechanism for waiting for more
+             * events /support more TUN devices */
+            oldstate = thread_cancelability(FALSE);
+            event_status = WaitForMultipleObjects(i, event_array, FALSE, INFINITE);
+            thread_cancelability(oldstate);
+            offset = event_status - WAIT_OBJECT_0;
+
+            /* A handle was signaled. Find the tun handle whose read was successful */
+
+            /* We can only use the event_status of indication for the first completed IO operation.
+             * After the event was signaled, we need to test the OVERLAPPED structure in the other array
+             * to find out what event was signaled.
+             */
+            /*
+             * Probably broken?
+             */
+            /* Check if an event in the array was signaled. (That is the case if
+             * the event_status is between WAIT_OBJECT_0 and WAIT_OBJECT_0 + nCount -1)
+             */
+            if ((WAIT_OBJECT_0 < event_status) && event_status < ((WAIT_OBJECT_0 + length - 1)))
+            {
+                /* the event at event_array[event_status - WAIT_OBJECT_0] has been signaled */
+                /* It is possible that more than one event was signalled. In that case, (event_status - WAIT_OBJECT_0)
+                 * is the index with the lowest event that was signalled. More signalled events can be found higher
+                 *
+                 * According to the documentation, WAIT_OBJECT_0 is defined as 0
+                 */
+                if (offset == 0)
+                {
+                    /* Notification about changes regarding the tun devices.
+                     * Or the object is destroyed.
+                     * We need to rebuild the array. So exit and rebuild. */
+                    /* Cleanup
+                     *  Starts with 1 to skip over the dummy
+                     */
+                    for(j=1;j<i;j++)
+                    {
+                        /* stop all asynchronous IO */
+                        CancelIo(bundle_array[j].fileHandle);
+                        CloseHandle(bundle_array[j].overlapped->hEvent);
+                        memset(bundle_array[j].buffer.ptr, 0, bundle_array[j].buffer.len);
+                        free(bundle_array[j].buffer.ptr);
+                        ResetEvent(event_array[j]);
+                        CloseHandle(event_array[j]);
+                    }
+                    /* exit */
+                    return JOB_REQUEUE_DIRECT;
+                }
+                /* The arrays have the same length and the same positioning of the elements.
+                 * Therefore, if event_array[j] is signaled, the read on bundle_array[i].fileHandle has succeeded
+                 * and bundle_array[j].buffer has our data now.
+                 */
+
+                char foo[(bundle_array[offset].buffer.len *4)/3 + 1];
+                memset(foo, 0, (bundle_array[offset].buffer.len *4)/3 + 1);
+                chunk_to_base64(bundle_array[offset].buffer, foo);
+
+                ip_packet_t *packet;
+                /* clone the buffer */
+                chunk_t buffer_clone = chunk_clone (bundle_array[offset].buffer);
+                packet = ip_packet_create(buffer_clone);
+                if (packet)
+                {
+                        ipsec->processor->queue_outbound(ipsec->processor, packet);
+                }
+                else
+                {
+                        DBG2(DBG_ESP, "invalid IP packet read from TUN device");
+                }
+                /* Reset the overlapped structure, event and buffer */
+                /* Print out the package for debugging */
+                /* Don't leak packets */
+                memset(bundle_array[offset].buffer.ptr, 0, bundle_array[offset].buffer.len);
+                memset(bundle_array[offset].overlapped, 0, sizeof(OVERLAPPED));
+
+                if (!start_read(&bundle_array[offset], bundle_array[offset].overlapped->hEvent))
+                {
+                   /* Cleanup
+                    *  Starts with 1 to skip over the dummy
+                    */
+                    for(j=1;j<i;j++)
+                    {
+                        /* stop all asynchronous IO */
+                        CancelIo(bundle_array[j].fileHandle);
+                        CloseHandle(bundle_array[j].overlapped->hEvent);
+                        memset(bundle_array[j].buffer.ptr, 0, bundle_array[j].buffer.len);
+                        free(bundle_array[j].buffer.ptr);
+                    }
+                    this->lock->unlock(this->lock);
+                    return JOB_REQUEUE_FAIR;
+                }
+            }
+            /* Function failed */
+            else
+            {
+                DBG2(DBG_ESP, "waiting for events on the tun device reads failed.");
+
+                /* Cleanup
+                 *  Starts with 1 to skip over the dummy
+                 */
+                for(j=1;j<i;j++)
+                {
+                    /* stop all asynchronous IO */
+                    CancelIo(bundle_array[j].fileHandle);
+                    CloseHandle(bundle_array[j].overlapped->hEvent);
+                    memset(bundle_array[j].buffer.ptr, 0, bundle_array[j].buffer.len);
+                    free(bundle_array[j].buffer.ptr);
+                    ResetEvent(event_array[j]);
+                    CloseHandle(event_array[j]);
+                }
+                this->lock->unlock(this->lock);
+                return JOB_REQUEUE_FAIR;
+
+            }
+        }
+        this->lock->unlock(this->lock);
+        return JOB_REQUEUE_DIRECT;
+#else
 	enumerator_t *enumerator;
 	tun_entry_t *entry;
 	bool oldstate;
@@ -237,20 +585,28 @@ static job_requeue_t handle_plain(private_kernel_libipsec_router_t *this)
 	this->lock->unlock(this->lock);
 
 	return JOB_REQUEUE_DIRECT;
+#endif /* WIN32 */
 }
 
+
 METHOD(kernel_listener_t, tun, bool,
 	private_kernel_libipsec_router_t *this, tun_device_t *tun, bool created)
 {
 	tun_entry_t *entry, lookup;
+#if !defined(WIN32)
 	char buf[] = {0x01};
+#endif
 
 	this->lock->write_lock(this->lock);
 	if (created)
 	{
 		INIT(entry,
 			.addr = tun->get_address(tun, NULL),
+#ifdef WIN32
+                        .handle = tun->get_handle(tun),
+#else
 			.fd = tun->get_fd(tun),
+#endif /* WIN32 */
 			.tun = tun,
 		);
 		this->tuns->put(this->tuns, entry, entry);
@@ -261,8 +617,13 @@ METHOD(kernel_listener_t, tun, bool,
 		entry = this->tuns->remove(this->tuns, &lookup);
 		free(entry);
 	}
+
+#ifdef WIN32
+        SetEvent(this->event);
+#else
 	/* notify handler thread to recreate FD set */
 	ignore_result(write(this->notify[1], buf, sizeof(buf)));
+#endif
 	this->lock->unlock(this->lock);
 	return TRUE;
 }
@@ -292,7 +653,7 @@ METHOD(kernel_libipsec_router_t, destroy, void,
 	private_kernel_libipsec_router_t *this)
 {
 	charon->receiver->del_esp_cb(charon->receiver,
-								(receiver_esp_cb_t)receiver_esp_cb);
+							 (receiver_esp_cb_t)receiver_esp_cb);
 	ipsec->processor->unregister_outbound(ipsec->processor,
 										 (ipsec_outbound_cb_t)send_esp);
 	ipsec->processor->unregister_inbound(ipsec->processor,
@@ -300,8 +661,16 @@ METHOD(kernel_libipsec_router_t, destroy, void,
 	charon->kernel->remove_listener(charon->kernel, &this->public.listener);
 	this->lock->destroy(this->lock);
 	this->tuns->destroy(this->tuns);
+#ifdef WIN32
+        SetEvent(this->event);
+        CloseHandle(this->tun.handle);
+        CloseHandle(this->event);
+        /* Remove all other handles we might have */
+        /* TODO: Create enumerator, enumerate over tuns, close all those handles */
+#else
 	close(this->notify[0]);
 	close(this->notify[1]);
+#endif
 	router = NULL;
 	free(this);
 }
@@ -309,12 +678,13 @@ METHOD(kernel_libipsec_router_t, destroy, void,
 /**
  * Set O_NONBLOCK on the given socket.
  */
+#if !defined(WIN32)
 static bool set_nonblock(int socket)
 {
 	int flags = fcntl(socket, F_GETFL);
 	return flags != -1 && fcntl(socket, F_SETFL, flags | O_NONBLOCK) != -1;
 }
-
+#endif
 /*
  * See header file
  */
@@ -334,7 +704,10 @@ kernel_libipsec_router_t *kernel_libipsec_router_create()
 			.tun = lib->get(lib, "kernel-libipsec-tun"),
 		}
 	);
-
+#ifdef WIN32
+	this->tun.handle = this->tun.tun->get_handle(this->tun.tun);
+        this->event = CreateEvent(NULL, FALSE, FALSE, FALSE);
+#else
 	if (pipe(this->notify) != 0 ||
 		!set_nonblock(this->notify[0]) || !set_nonblock(this->notify[1]))
 	{
@@ -344,6 +717,7 @@ kernel_libipsec_router_t *kernel_libipsec_router_create()
 	}
 
 	this->tun.fd = this->tun.tun->get_fd(this->tun.tun);
+#endif /* WIN32 */
 
 	this->tuns = hashtable_create((hashtable_hash_t)tun_entry_hash,
 								  (hashtable_equals_t)tun_entry_equals, 4);
diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c
index c12d384..7fcbfa4 100644
--- a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c
+++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c
@@ -25,9 +25,6 @@
 #include <collections/hashtable.h>
 #include <processing/jobs/callback_job.h>
 
-#define IPPROTO_IPIP 4
-#define IPPROTO_IPV6 41
-
 typedef struct private_kernel_wfp_ipsec_t private_kernel_wfp_ipsec_t;
 
 struct private_kernel_wfp_ipsec_t {
diff --git a/src/libipsec/Makefile.am b/src/libipsec/Makefile.am
index 90b4561..1558609 100644
--- a/src/libipsec/Makefile.am
+++ b/src/libipsec/Makefile.am
@@ -16,6 +16,10 @@ ipsec_sa_mgr.c ipsec_sa_mgr.h
 libipsec_la_LIBADD = \
 	$(top_builddir)/src/libstrongswan/libstrongswan.la
 
+if USE_WINDOWS
+    libipsec_la_LIBADD += -lws2_32 -lpsapi
+endif
+
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/libstrongswan
 
diff --git a/src/libipsec/esp_packet.c b/src/libipsec/esp_packet.c
index 50bc8b4..2c52177 100644
--- a/src/libipsec/esp_packet.c
+++ b/src/libipsec/esp_packet.c
@@ -25,7 +25,9 @@
 #include <bio/bio_reader.h>
 #include <bio/bio_writer.h>
 
+#ifndef WIN32
 #include <netinet/in.h>
+#endif
 
 typedef struct private_esp_packet_t private_esp_packet_t;
 
diff --git a/src/libipsec/ip_packet.c b/src/libipsec/ip_packet.c
index 0fdd5d3..5f9ea3f 100644
--- a/src/libipsec/ip_packet.c
+++ b/src/libipsec/ip_packet.c
@@ -20,12 +20,44 @@
 #include <utils/debug.h>
 
 #include <sys/types.h>
+#ifndef WIN32
 #include <netinet/in.h>
 #include <netinet/ip.h>
 #ifdef HAVE_NETINET_IP6_H
 #include <netinet/ip6.h>
 #endif
+#else
+
+struct ip
+  {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    unsigned int ip_hl:4;
+    unsigned int ip_v:4;
+#elif __BYTE__PORDER == __BIG_ENDIAN
+    unsigned int ip_v:4;
+    unsigned int ip_hl:4;
+#endif
+    uint8_t ip_tos;
+    uint16_t ip_len;
+    uint16_t ip_id;
+    uint16_t ip_off;
+    uint8_t ip_ttl;
+    uint8_t ip_p;
+    uint16_t ip_sum;
+    struct in_addr ip_src, ip_dst;
+  };
+
+struct ip6_hdr
+{
+        uint32_t ip6_flow;   /* 4 bits version, 8 bits TC, 20 bit flow label */
+        uint16_t ip6_plen;
+        uint8_t  ip6_nxt;
+        uint8_t  ip6_hlim;
+        struct in6_addr ip6_src, ip6_dst;
+};
+#define HAVE_NETINET_IP6_H /* not really, but we only need the struct above */
 
+#endif
 /**
  * TCP header, defined here because platforms disagree regarding member names
  * and unfortunately Android does not define a variant with BSD names.
@@ -235,7 +267,7 @@ ip_packet_t *ip_packet_create(chunk_t packet)
 			next_header = ip->ip_p;
 			break;
 		}
-#ifdef HAVE_NETINET_IP6_H
+#if defined(HAVE_NETINET_IP6_H) || defined(WIN32)
 		case 6:
 		{
 			struct ip6_hdr *ip;
diff --git a/src/libstrongswan/networking/tun_device.c b/src/libstrongswan/networking/tun_device.c
index de92555..f2d2b5f 100644
--- a/src/libstrongswan/networking/tun_device.c
+++ b/src/libstrongswan/networking/tun_device.c
@@ -16,12 +16,34 @@
  * for more details.
  */
 
+/*
+ * Copyright (C) 2016 Noel Kuntze
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
 #include "tun_device.h"
 
 #include <utils/debug.h>
 #include <threading/thread.h>
 
-#if !defined(__APPLE__) && !defined(__linux__) && !defined(HAVE_NET_IF_TUN_H)
+#if !defined(__APPLE__) && !defined(__linux__) && !defined(HAVE_NET_IF_TUN_H) && defined(W32)
 
 tun_device_t *tun_device_create(const char *name_tmpl)
 {
@@ -33,14 +55,18 @@ tun_device_t *tun_device_create(const char *name_tmpl)
 
 #include <errno.h>
 #include <fcntl.h>
+#if !defined(WIN32)
 #include <netinet/in.h>
-#include <string.h>
 #include <sys/ioctl.h>
-#include <sys/types.h>
 #include <sys/socket.h>
+#include <net/if.h>
+#endif
+#include <string.h>
+
+#include <sys/types.h>
+
 #include <sys/stat.h>
 #include <unistd.h>
-#include <net/if.h>
 
 #ifdef __APPLE__
 #include <net/if_utun.h>
@@ -53,6 +79,10 @@ tun_device_t *tun_device_create(const char *name_tmpl)
 #include <net/if_tun.h>
 #include <net/if_var.h>
 #include <netinet/in_var.h>
+#elif defined(WIN32)
+#include <winioctl.h>
+#include <collections/linked_list.h>
+#include "win32.h"
 #else
 #include <net/if_tun.h>
 #endif
@@ -67,12 +97,21 @@ struct private_tun_device_t {
 	 * Public interface
 	 */
 	tun_device_t public;
-
+#ifdef WIN32
+        /**
+         * The TUN device's file handle
+         */
+        HANDLE tunhandle;
+
+        /**
+         * Name of the TUN device
+         */
+        char if_name[256];
+#else
 	/**
 	 * The TUN device's file descriptor
 	 */
 	int tunfd;
-
 	/**
 	 * Name of the TUN device
 	 */
@@ -82,6 +121,7 @@ struct private_tun_device_t {
 	 * Socket used for ioctl() to set interface addr, ...
 	 */
 	int sock;
+#endif /* WIN32 */
 
 	/**
 	 * The current MTU
@@ -99,6 +139,130 @@ struct private_tun_device_t {
 	uint8_t netmask;
 };
 
+#ifdef WIN32
+/*
+ * Searches through the registry for suitable TAP driver interfaces
+ * On Windows, the TAP interface metadata is stored and described in the registry.
+ * It returns a linked list that contains all found guids. The guids describe the interfaces.
+ */
+
+linked_list_t *find_tap_devices()
+{
+    char enum_name[256], unit_string[256],
+    instance_id[256], component_id[256],
+    component_id_string[] = "ComponentId",
+    instance_id_string[] = "NetCfgInstanceId";
+    LONG status;
+    uint32_t i = 0;
+    DWORD len, type;
+    HKEY adapter_key, unit_key;
+    linked_list_t *list = linked_list_create();
+
+    /*
+     * Open parent key. It contains all other keys that
+     * describe any possible interfaces.
+     */
+    status = RegOpenKeyEx(
+            HKEY_LOCAL_MACHINE,
+            ADAPTER_KEY,
+            0,
+            KEY_READ,
+            &adapter_key);
+
+    if (status == ERROR_SUCCESS)
+    {
+        while (TRUE)
+        {
+            len = sizeof (enum_name);
+            status = RegEnumKeyEx(
+                    adapter_key,
+                    i,
+                    enum_name,
+                    &len,
+                    NULL,
+                    NULL,
+                    NULL,
+                    NULL);
+            if (status == ERROR_SUCCESS)
+            {
+                snprintf(unit_string, sizeof (unit_string), "%s\\%s",
+                        ADAPTER_KEY, enum_name);
+
+                status = RegOpenKeyEx(
+                        HKEY_LOCAL_MACHINE,
+                        unit_string,
+                        0,
+                        KEY_READ,
+                        &unit_key);
+
+                if (status == ERROR_SUCCESS)
+                {
+                    len = sizeof (component_id);
+                    status = RegQueryValueEx(
+                            unit_key,
+                            component_id_string,
+                            NULL,
+                            &type,
+                            component_id,
+                            &len);
+
+                    if (status == ERROR_SUCCESS && type == REG_SZ)
+                    {
+                        len = sizeof (instance_id);
+                        status = RegQueryValueEx(
+                                unit_key,
+                                instance_id_string,
+                                NULL,
+                                &type,
+                                instance_id,
+                                &len);
+
+                        if (status == ERROR_SUCCESS && type == REG_SZ)
+                        {
+                            if (!strcmp(component_id, TAP_WIN_COMPONENT_ID))
+                            {
+                                /* That thing is a valid interface key */
+                                /* link into return list */
+                                char *guid = malloc(sizeof(instance_id));
+                                memcpy(guid, instance_id, sizeof(instance_id));
+                                list->insert_last(list, guid);
+                            }
+                        }
+                    }
+                    else
+                    {
+                        DBG2(DBG_LIB, "Error opening registry key: %s\\%s",
+                                unit_string, component_id_string);
+                    }
+                    RegCloseKey(unit_key);
+                }
+                else if (status != ERROR_SUCCESS)
+                {
+                    DBG2(DBG_LIB, "Error opening registry key: %s", unit_string);
+                }
+                i++;
+            }
+            else if (status == ERROR_NO_MORE_ITEMS)
+            {
+                break;
+            }
+            else
+            {
+                DBG2(DBG_LIB, "Error enumerating registry subkeys of key: %s",
+                        ADAPTER_KEY);
+            }
+        }
+    }
+    else
+    {
+        DBG2(DBG_LIB, "Error opening registry key: %s", ADAPTER_KEY);
+    }
+
+    RegCloseKey(adapter_key);
+    return list;
+}
+
+#endif /* WIN32 */
 /**
  * FreeBSD 10 deprecated the SIOCSIFADDR etc. commands.
  */
@@ -165,8 +329,18 @@ static bool set_address_impl(private_tun_device_t *this, host_t *addr,
 	return TRUE;
 }
 
-#else /* __FreeBSD__ */
+#elif defined(WIN32)
+        /* method definitions for Windows */
+/**
+ * Set the address using registry and fileIO shennanigans on Windows.
+ */
+static bool set_address_impl(private_tun_device_t *this, host_t *addr,
+							 uint8_t netmask)
+{
+    return TRUE;
+}
 
+#else /* __FreeBSD__ */
 /**
  * Set the address using the classic SIOCSIFADDR etc. commands on other systems.
  */
@@ -239,10 +413,21 @@ METHOD(tun_device_t, get_address, host_t*,
 	}
 	return this->address;
 }
-
+/* Fix for WIN32 */
 METHOD(tun_device_t, up, bool,
 	private_tun_device_t *this)
 {
+#ifdef WIN32
+        ULONG status = TRUE;
+        DWORD len;
+        if (!DeviceIoControl (this->tunhandle, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
+			  &status, sizeof (status),
+			  &status, sizeof (status), &len, NULL))
+        {
+            DBG1(DBG_LIB, "failed to set the interface %s to up", this->if_name);
+            return FALSE;
+        }
+#else
 	struct ifreq ifr;
 
 	memset(&ifr, 0, sizeof(ifr));
@@ -263,12 +448,143 @@ METHOD(tun_device_t, up, bool,
 			 strerror(errno));
 		return FALSE;
 	}
+#endif /* WIN32 */
 	return TRUE;
 }
 
 METHOD(tun_device_t, set_mtu, bool,
 	private_tun_device_t *this, int mtu)
 {
+#ifdef WIN32
+        /* Access registry */
+        char enum_name[256], unit_string[256],
+        instance_id[256],
+        instance_id_string[] = "NetCfgInstanceId",
+        mtu_string[256];
+        LONG status;
+        uint32_t i = 0;
+        DWORD len, type;
+        HKEY adapter_key, unit_key, write_key;
+
+        /* The MTU is encoded as a string. */
+        snprintf(mtu_string, sizeof(mtu_string), "%d", mtu);
+        /*
+         * Open parent key. It contains all other keys that
+         * describe any possible interfaces.
+         */
+        status = RegOpenKeyEx(
+                HKEY_LOCAL_MACHINE,
+                ADAPTER_KEY,
+                0,
+                KEY_READ,
+                &adapter_key);
+
+        if (status != ERROR_SUCCESS)
+        {
+            DBG2(DBG_LIB, "Error opening registry key: %s", ADAPTER_KEY);
+        }
+
+        /* Iterate over all the interfaces in the registry key. They're enumerated from 1
+         * to n.
+         */
+        while (TRUE)
+        {
+            len = sizeof (enum_name);
+            status = RegEnumKeyEx(
+                    adapter_key,
+                    i,
+                    enum_name,
+                    &len,
+                    NULL,
+                    NULL,
+                    NULL,
+                    NULL);
+            if (status == ERROR_NO_MORE_ITEMS)
+            {
+                break;
+            }
+            else if (status != ERROR_SUCCESS)
+            {
+                DBG2(DBG_LIB, "Error enumerating registry subkeys of key: %s",
+                        ADAPTER_KEY);
+            }
+
+            snprintf(unit_string, sizeof (unit_string), "%s\\%s",
+                    ADAPTER_KEY, enum_name);
+
+            status = RegOpenKeyEx(
+                    HKEY_LOCAL_MACHINE,
+                    unit_string,
+                    0,
+                    KEY_READ,
+                    &unit_key);
+
+            if (status!= ERROR_SUCCESS)
+            {
+                DBG2(DBG_LIB, "Error opening registry key: %s", unit_string);
+            }
+            else
+            {
+                len = sizeof (instance_id);
+                status = RegQueryValueEx(
+                        unit_key,
+                        instance_id_string,
+                        NULL,
+                        &type,
+                        instance_id,
+                        &len);
+
+                if (status != ERROR_SUCCESS || type != REG_SZ)
+                {
+                    DBG2(DBG_LIB, "Error opening registry key: %s\\%s",
+                            unit_string, instance_id_string);
+                }
+                else
+                {
+                    DBG2(DBG_LIB, "Trying to match %s", instance_id);
+                    if (!strcmp(instance_id, this->if_name))
+                    {
+                        /* Open the registry key for write access */
+                        status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit_string, 0, KEY_WRITE, &write_key);
+                        if (status != ERROR_SUCCESS)
+                        {
+                            DBG2(DBG_LIB, "Failed to open the registry key %s with write access: %d", unit_string, status);
+                        }
+                        else
+                        {
+                            len= sizeof(mtu_string);
+                            status = RegSetValueEx(
+                                write_key,
+                                "MTU",
+                                0,
+                                REG_SZ,
+                                mtu_string,
+                                len);
+                            RegCloseKey(unit_key);
+                            RegCloseKey(write_key);
+                            RegCloseKey(adapter_key);
+                            if (status == ERROR_SUCCESS)
+                            {
+                                DBG2(DBG_LIB, "MTU set to %s", mtu_string);
+                                return TRUE;
+                            }
+                            else
+                            {
+                                DBG1(DBG_LIB, "Failed (error %d) to set the MTU to %d", status, mtu);
+                                return FALSE;
+                            }
+                        }
+                    }
+                }
+                RegCloseKey(unit_key);
+            }
+            ++i;
+        }
+
+        RegCloseKey(adapter_key);
+        DBG1(DBG_LIB, "Failed to set the MTU to %d", mtu);
+        return FALSE;
+#else
 	struct ifreq ifr;
 
 	memset(&ifr, 0, sizeof(ifr));
@@ -283,11 +599,22 @@ METHOD(tun_device_t, set_mtu, bool,
 	}
 	this->mtu = mtu;
 	return TRUE;
+#endif
 }
 
 METHOD(tun_device_t, get_mtu, int,
 	private_tun_device_t *this)
 {
+#ifdef WIN32
+        ULONG mtu;
+        DWORD len;
+        if (DeviceIoControl (this->tunhandle, TAP_WIN_IOCTL_GET_MTU,
+			 &mtu, sizeof (mtu),
+			 &mtu, sizeof (mtu), &len, NULL))
+        {
+            this->mtu = (int) mtu;
+        }
+#else
 	struct ifreq ifr;
 
 	if (this->mtu > 0)
@@ -303,6 +630,7 @@ METHOD(tun_device_t, get_mtu, int,
 	{
 		this->mtu = ifr.ifr_mtu;
 	}
+#endif /* WIN32 */
 	return this->mtu;
 }
 
@@ -312,6 +640,141 @@ METHOD(tun_device_t, get_name, char*,
 	return this->if_name;
 }
 
+#ifdef WIN32
+METHOD(tun_device_t, get_handle, HANDLE,
+        private_tun_device_t *this)
+{
+        return this->tunhandle;
+}
+
+METHOD(tun_device_t, write_packet, bool,
+	private_tun_device_t *this, chunk_t packet)
+{
+        bool status;
+        DWORD error;
+        OVERLAPPED overlapped;
+        HANDLE write_event;
+
+        write_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+        error = GetLastError();
+        if (error != ERROR_SUCCESS)
+        {
+           DBG1(DBG_LIB, "creating an event to write to the TUN device %s failed: %d",
+                   this->if_name, error);
+           return FALSE;
+        }
+
+
+        memset(&overlapped, 0, sizeof(OVERLAPPED));
+
+        overlapped.hEvent = write_event;
+
+        status = WriteFile(
+                this->tunhandle,
+                packet.ptr,
+                packet.len,
+                NULL,
+                &overlapped
+                );
+        error = GetLastError();
+
+        if (status) {
+            /* Read returned immediately. */
+            SetEvent(write_event);
+        }
+        else
+        {
+            switch(error)
+            {
+                case ERROR_SUCCESS:
+                case ERROR_IO_PENDING:
+                    /* all fine */
+                    break;
+                default:
+                    DBG1(DBG_LIB, "writing to TUN device %s failed: %u",
+                            this->if_name, error);
+                    CloseHandle(write_event);
+                    return FALSE;
+                    break;
+            }
+         }
+        WaitForSingleObject(write_event, INFINITE);
+
+        CloseHandle(write_event);
+
+        return TRUE;
+}
+
+METHOD(tun_device_t, read_packet, bool,
+	private_tun_device_t *this, chunk_t *packet)
+{
+	bool old, status;
+        DWORD error;
+        OVERLAPPED overlapped;
+	chunk_t data;
+        HANDLE read_event = CreateEvent(NULL, FALSE, FALSE, FALSE);
+
+        ResetEvent(read_event);
+
+        error = GetLastError();
+        switch(error)
+        {
+            case ERROR_SUCCESS:
+                break;
+            default:
+                /* Just fine. Don't do anything. */
+                break;
+        }
+
+        memset(&overlapped, 0, sizeof(OVERLAPPED));
+
+        overlapped.hEvent = read_event;
+
+	data = chunk_alloca(get_mtu(this));
+
+        /* Read chunk from handle */
+        status = ReadFile(this->tunhandle,
+                    &data.ptr,
+                    data.len,
+                    NULL,
+                    &overlapped);
+        error = GetLastError();
+
+        if (status)
+        {
+            /* Read returned immediately. */
+            SetEvent(read_event);
+        }
+        else
+        {
+            switch(error)
+            {
+                case ERROR_SUCCESS:
+                case ERROR_IO_PENDING:
+                    /* all fine */
+                    break;
+                default:
+                    DBG1(DBG_LIB, "reading from TUN device %s failed: %u", this->if_name,
+                       error);
+                    CloseHandle(read_event);
+                    return FALSE;
+                    break;
+            }
+        }
+	old = thread_cancelability(TRUE);
+
+        WaitForSingleObject(read_event, INFINITE);
+
+	thread_cancelability(old);
+
+	*packet = chunk_clone(data);
+
+        CloseHandle(read_event);
+        return TRUE;
+}
+
+#else
+
 METHOD(tun_device_t, get_fd, int,
 	private_tun_device_t *this)
 {
@@ -321,14 +784,13 @@ METHOD(tun_device_t, get_fd, int,
 METHOD(tun_device_t, write_packet, bool,
 	private_tun_device_t *this, chunk_t packet)
 {
-	ssize_t s;
-
 #ifdef __APPLE__
 	/* UTUN's expect the packets to be prepended by a 32-bit protocol number
 	 * instead of parsing the packet again, we assume IPv4 for now */
 	uint32_t proto = htonl(AF_INET);
 	packet = chunk_cata("cc", chunk_from_thing(proto), packet);
-#endif
+#endif /* __APPLE__ */
+        ssize_t s;
 	s = write(this->tunfd, packet.ptr, packet.len);
 	if (s < 0)
 	{
@@ -340,6 +802,7 @@ METHOD(tun_device_t, write_packet, bool,
 	{
 		return FALSE;
 	}
+
 	return TRUE;
 }
 
@@ -347,12 +810,12 @@ METHOD(tun_device_t, read_packet, bool,
 	private_tun_device_t *this, chunk_t *packet)
 {
 	chunk_t data;
-	ssize_t len;
 	bool old;
 
 	data = chunk_alloca(get_mtu(this));
 
 	old = thread_cancelability(TRUE);
+	ssize_t len;
 	len = read(this->tunfd, data.ptr, data.len);
 	thread_cancelability(old);
 	if (len < 0)
@@ -362,6 +825,7 @@ METHOD(tun_device_t, read_packet, bool,
 		return FALSE;
 	}
 	data.len = len;
+
 #ifdef __APPLE__
 	/* UTUN's prepend packets with a 32-bit protocol number */
 	data = chunk_skip(data, sizeof(uint32_t));
@@ -369,10 +833,15 @@ METHOD(tun_device_t, read_packet, bool,
 	*packet = chunk_clone(data);
 	return TRUE;
 }
+#endif /* WIN32 */
 
 METHOD(tun_device_t, destroy, void,
 	private_tun_device_t *this)
 {
+#ifdef WIN32
+        /* close file handle, destroy interface */
+        CloseHandle(this->tunhandle);
+#else
 	if (this->tunfd > 0)
 	{
 		close(this->tunfd);
@@ -389,12 +858,13 @@ METHOD(tun_device_t, destroy, void,
 			DBG1(DBG_LIB, "failed to destroy %s: %s", this->if_name,
 				 strerror(errno));
 		}
-#endif /* __FreeBSD__ */
+#endif
 	}
 	if (this->sock > 0)
 	{
 		close(this->sock);
 	}
+#endif
 	DESTROY_IF(this->address);
 	free(this);
 }
@@ -451,7 +921,127 @@ static bool init_tun(private_tun_device_t *this, const char *name_tmpl)
 		return FALSE;
 	}
 	return TRUE;
-
+#elif defined(WIN32)
+        enumerator_t *enumerator;
+        char *guid;
+        BOOL success = FALSE;
+        /* Get all existing TAP devices */
+        linked_list_t *possible_devices = find_tap_devices();
+        memset(this->if_name, 0, sizeof(this->if_name));
+
+        /* Iterate over list */
+        enumerator = possible_devices->create_enumerator(possible_devices);
+        /* Try to open that device */
+        while(enumerator->enumerate(enumerator, &guid))
+        {
+            if (!success){
+                /* Set mode */
+                char device_path[256];
+                /* Translate dev name to guid */
+                /* TODO: Fix. device_guid should be */
+                snprintf (device_path, sizeof(device_path), "%s%s%s", USERMODEDEVICEDIR, guid, TAP_WIN_SUFFIX);
+
+                this->tunhandle = CreateFile(device_path, GENERIC_READ | GENERIC_WRITE, 0,
+                    0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
+                if (this->tunhandle == INVALID_HANDLE_VALUE)
+                {
+                    DBG1(DBG_LIB, "could not create TUN device %s", device_path);
+                }
+                else
+                {
+                    memcpy(this->if_name, guid, strlen(guid));
+                    success = TRUE;
+                }
+            }
+            else
+            {
+                break;
+            }
+            /* device has been examined or used, free it */
+            free(guid);
+        }
+
+        /* possible_devices has been freed while going over the enumerator.
+         * Therefore it is not necessary to free the elements in the list now.
+         */
+        enumerator->destroy(enumerator);
+        possible_devices->destroy(possible_devices);
+        /* If we didn't find one or could open one, we need to bail out.
+         * We currently can not create new devices.
+         */
+        if (!success)
+        {
+            return FALSE;
+        }
+        /* set correct mode */
+        /* We set a fake gateway of 169.254.254.128 that we route packets over
+         The TAP driver strips the Ethernet header and trailer of the Ethernet frames
+         before sending them back to the application that listens on the handle */
+	struct in_addr ep[3];
+        ULONG status = TRUE;
+        DWORD len;
+        /* Local address (just fake one): 169.254.128.127 */
+	ep[0].S_un.S_un_b.s_b1 = 169;
+        ep[0].S_un.S_un_b.s_b2 = 254;
+        ep[0].S_un.S_un_b.s_b3 = 128;
+        ep[0].S_un.S_un_b.s_b4 = 127;
+        /*
+         * Remote network. The tap driver validates it by masking it with the remote_netmask
+         * and then comparing hte result against the remote network (this value here).
+         * If it does not match, an error is logged and initialization fails.
+         * (local & remote_netmask ? local)
+         * The driver does proxy arp for this network and the local address.
+         */
+        /* We need to integrate support for IPv6, too. */
+        /* Just fake a link local address for now (169.254.128.128) */
+	ep[1].S_un.S_un_b.s_b1 = 169;
+        ep[1].S_un.S_un_b.s_b2 = 254;
+        ep[1].S_un.S_un_b.s_b3 = 128;
+        ep[1].S_un.S_un_b.s_b4 = 128;
+        /* Remote netmask (255.255.255.255) */
+	ep[2].S_un.S_un_b.s_b1 = 255;
+        ep[2].S_un.S_un_b.s_b2 = 255;
+        ep[2].S_un.S_un_b.s_b3 = 255;
+        ep[2].S_un.S_un_b.s_b4 = 255;
+
+        if(!DeviceIoControl (this->tunhandle, TAP_WIN_IOCTL_CONFIG_TUN,
+		    ep, sizeof (ep),
+		    ep, sizeof (ep), &len, NULL))
+        {
+            DBG1 (DBG_LIB, "WARNING: The TAP-Windows driver rejected a TAP_WIN_IOCTL_CONFIG_TUN DeviceIoControl call.");
+        }
+
+        ULONG disable_src_check = FALSE;
+        if(!DeviceIoControl(this->tunhandle, TAP_WIN_IOCTL_CONFIG_SET_SRC_CHECK,
+                    &disable_src_check, sizeof(disable_src_check),
+                    &disable_src_check, sizeof(disable_src_check), &len, NULL))
+        {
+            DBG1 (DBG_LIB, "WARNING: The TAP-Windows driver rejected a TAP_WIN_IOCTL_CONFIG_SET_SRC_CHECK DeviceIoControl call.");
+        }
+        ULONG driverVersion[3] = {0 , 0, 0};
+        if(!DeviceIoControl(this->tunhandle, TAP_WIN_IOCTL_GET_VERSION,
+                    &driverVersion, sizeof(driverVersion),
+                    &driverVersion, sizeof(driverVersion), &len, NULL))
+        {
+            DBG1(DBG_LIB, "WARNING: The TAP-Windows driver rejected a TAP_WIN_IOCTL_GET_VERSION DeviceIoControl call.");
+        }
+        else
+        {
+            DBG1(DBG_LIB, "TAP-Windows driver version %d.%d available.", driverVersion[0], driverVersion[1]);
+        }
+        /* Set device to up */
+
+        if (!DeviceIoControl (this->tunhandle, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
+  			  &status, sizeof (status),
+                            &status, sizeof (status), &len, NULL))
+        {
+            DBG1 (DBG_LIB, "WARNING: The TAP-Windows driver rejected a TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call.");
+        }
+
+            /* Give the adapter 2 seconds to come up */
+
+        sleep(2);
+        return TRUE;
 #elif defined(IFF_TUN)
 
 	struct ifreq ifr;
@@ -527,14 +1117,24 @@ tun_device_t *tun_device_create(const char *name_tmpl)
 			.get_mtu = _get_mtu,
 			.set_mtu = _set_mtu,
 			.get_name = _get_name,
+                        /* For WIN32, that's a handle. */
+#ifdef WIN32
+                        .get_handle = _get_handle,
+#else
 			.get_fd = _get_fd,
+#endif /* WIN32 */
 			.set_address = _set_address,
 			.get_address = _get_address,
 			.up = _up,
 			.destroy = _destroy,
 		},
-		.tunfd = -1,
-		.sock = -1,
+#ifdef WIN32
+                .tunhandle = NULL,
+#else
+
+                .tunfd = -1,
+                .sock = -1,
+#endif /* WIN32 */
 	);
 
 	if (!init_tun(this, name_tmpl))
@@ -542,6 +1142,9 @@ tun_device_t *tun_device_create(const char *name_tmpl)
 		free(this);
 		return NULL;
 	}
+#ifdef WIN32
+	DBG1(DBG_LIB, "opened TUN device: %s", this->if_name);
+#else
 	DBG1(DBG_LIB, "created TUN device: %s", this->if_name);
 
 	this->sock = socket(AF_INET, SOCK_DGRAM, 0);
@@ -551,6 +1154,7 @@ tun_device_t *tun_device_create(const char *name_tmpl)
 		destroy(this);
 		return NULL;
 	}
+#endif /* WIN32 */
 	return &this->public;
 }
 
diff --git a/src/libstrongswan/networking/tun_device.h b/src/libstrongswan/networking/tun_device.h
index 4f9eacb..e7d99a4 100644
--- a/src/libstrongswan/networking/tun_device.h
+++ b/src/libstrongswan/networking/tun_device.h
@@ -15,6 +15,28 @@
  * for more details.
  */
 
+/*
+ * Copyright (C) 2016 Noel Kuntze
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
 /**
  * @defgroup tun_device tun_device
  * @{ @ingroup networking
@@ -25,6 +47,11 @@
 
 #include <networking/host.h>
 
+/**
+ * OpenVPN TAP driver constants for registry and file locations
+ */
+
+
 typedef struct tun_device_t tun_device_t;
 
 /**
@@ -98,7 +125,15 @@ struct tun_device_t {
 	 * @return				interface name
 	 */
 	char *(*get_name)(tun_device_t *this);
-
+#ifdef WIN32
+        /*
+         * Get the underlying tun handle.
+         *
+         * @return                              file handle of this tun device
+         */
+        HANDLE (*get_handle)(tun_device_t *this);
+
+#else
 	/**
 	 * Get the underlying tun file descriptor.
 	 *
@@ -106,6 +141,7 @@ struct tun_device_t {
 	 */
 	int (*get_fd)(tun_device_t *this);
 
+#endif
 	/**
 	 * Destroy a tun_device_t
 	 */
diff --git a/src/libstrongswan/networking/win32.h b/src/libstrongswan/networking/win32.h
new file mode 100644
index 0000000..7a59589
--- /dev/null
+++ b/src/libstrongswan/networking/win32.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 Noel Kuntze
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef WIN32_H
+#define WIN32_H
+
+#define TAP_WIN_COMPONENT_ID "tap0901"
+#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+
+/*
+ * ======================
+ * Filesystem prefixes
+ * ======================
+ */
+
+#define USERMODEDEVICEDIR "\\\\.\\Global\\"
+#define TAP_WIN_SUFFIX    ".tap"
+
+/*
+ * TAP IOCTL constants and macros.
+ *
+ */
+#define TAP_WIN_CONTROL_CODE(request,method) \
+  CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
+
+/* Present in 8.1 */
+
+#define TAP_WIN_IOCTL_GET_MAC               TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_GET_VERSION           TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_GET_MTU               TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_GET_INFO              TAP_WIN_CONTROL_CODE (4, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE (5, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_SET_MEDIA_STATUS      TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ      TAP_WIN_CONTROL_CODE (7, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_GET_LOG_LINE          TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT   TAP_WIN_CONTROL_CODE (9, METHOD_BUFFERED)
+
+/* Added in 8.2 */
+
+/* obsoletes TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT */
+#define TAP_WIN_IOCTL_CONFIG_TUN            TAP_WIN_CONTROL_CODE (10, METHOD_BUFFERED)
+#define TAP_WIN_IOCTL_CONFIG_SET_SRC_CHECK  TAP_WIN_CONTROL_CODE (11, METHOD_BUFFERED)
+
+
+#endif /* WIN32_H */
\ No newline at end of file
diff --git a/src/libstrongswan/utils/compat/windows.h b/src/libstrongswan/utils/compat/windows.h
index f7e6207..9fa5ab6 100644
--- a/src/libstrongswan/utils/compat/windows.h
+++ b/src/libstrongswan/utils/compat/windows.h
@@ -43,6 +43,13 @@
 typedef u_int uid_t;
 typedef u_int gid_t;
 
+ /**
++ * From winsock2.h
++ */
+#ifndef IPPROTO_IPIP
+#define IPPROTO_IPIP IPPROTO_IPV4
+#endif
+
 /**
  * Initialize Windows libraries
  */

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Dev mailing list
[email protected]
https://lists.strongswan.org/mailman/listinfo/dev

Reply via email to