Merge branch 'win-kernel'

Adds the kernel-iph and kernel-wfp kernel backends for the Windows platform.
kernel-iph provides a networking backend using the IP Helper native Windows
API, while the kernel-wfp backend implements an interface to the Windows Kernel
IPsec layer using the Windows Filtering Platform API.
This commit is contained in:
Martin Willi
2014-06-04 16:32:23 +02:00
22 changed files with 4822 additions and 4 deletions
+8
View File
@@ -204,6 +204,8 @@ ARG_ENABL_SET([kernel-pfkey], [enable the PF_KEY kernel interface.])
ARG_ENABL_SET([kernel-pfroute], [enable the PF_ROUTE kernel interface.])
ARG_ENABL_SET([kernel-klips], [enable the KLIPS kernel interface.])
ARG_ENABL_SET([kernel-libipsec],[enable the libipsec kernel interface.])
ARG_ENABL_SET([kernel-iph], [enable the Windows IP Helper based networking backend.])
ARG_ENABL_SET([kernel-wfp], [enable the Windows Filtering Platform IPsec backend.])
ARG_DISBL_SET([socket-default], [disable default socket implementation for charon.])
ARG_ENABL_SET([socket-dynamic], [enable dynamic socket implementation for charon])
ARG_ENABL_SET([socket-win], [enable Winsock2 based socket implementation for charon])
@@ -1209,6 +1211,8 @@ ADD_PLUGIN([attr], [h charon])
ADD_PLUGIN([attr-sql], [h charon])
ADD_PLUGIN([load-tester], [c charon])
ADD_PLUGIN([kernel-libipsec], [c charon cmd])
ADD_PLUGIN([kernel-wfp], [c charon])
ADD_PLUGIN([kernel-iph], [c charon])
ADD_PLUGIN([kernel-pfkey], [h charon starter nm cmd])
ADD_PLUGIN([kernel-pfroute], [h charon starter nm cmd])
ADD_PLUGIN([kernel-klips], [h charon starter])
@@ -1368,6 +1372,8 @@ AM_CONDITIONAL(USE_UNIT_TESTS, test x$unit_tester = xtrue)
AM_CONDITIONAL(USE_LOAD_TESTER, test x$load_tester = xtrue)
AM_CONDITIONAL(USE_HA, test x$ha = xtrue)
AM_CONDITIONAL(USE_KERNEL_LIBIPSEC, test x$kernel_libipsec = xtrue)
AM_CONDITIONAL(USE_KERNEL_WFP, test x$kernel_wfp = xtrue)
AM_CONDITIONAL(USE_KERNEL_IPH, test x$kernel_iph = xtrue)
AM_CONDITIONAL(USE_WHITELIST, test x$whitelist = xtrue)
AM_CONDITIONAL(USE_LOOKIP, test x$lookip = xtrue)
AM_CONDITIONAL(USE_ERROR_NOTIFY, test x$error_notify = xtrue)
@@ -1662,6 +1668,8 @@ AC_CONFIG_FILES([
src/libcharon/plugins/uci/Makefile
src/libcharon/plugins/ha/Makefile
src/libcharon/plugins/kernel_libipsec/Makefile
src/libcharon/plugins/kernel_wfp/Makefile
src/libcharon/plugins/kernel_iph/Makefile
src/libcharon/plugins/whitelist/Makefile
src/libcharon/plugins/lookip/Makefile
src/libcharon/plugins/error_notify/Makefile
+2 -1
View File
@@ -34,7 +34,8 @@ all)
--disable-dumm --disable-kernel-pfroute --disable-keychain
--disable-lock-profiler --disable-maemo --disable-padlock
--disable-osx-attr --disable-tkm --disable-uci --disable-aikgen
--disable-svc --disable-dbghelp-backtraces --disable-socket-win"
--disable-svc --disable-dbghelp-backtraces --disable-socket-win
--disable-kernel-wfp --disable-kernel-iph"
if test "$LEAK_DETECTIVE" = "yes"; then
# libgcrypt can't be deinitialized
CONFIG="$CONFIG --disable-gcrypt"
+14
View File
@@ -489,6 +489,20 @@ if MONOLITHIC
endif
endif
if USE_KERNEL_WFP
SUBDIRS += plugins/kernel_wfp
if MONOLITHIC
libcharon_la_LIBADD += plugins/kernel_wfp/libstrongswan-kernel-wfp.la
endif
endif
if USE_KERNEL_IPH
SUBDIRS += plugins/kernel_iph
if MONOLITHIC
libcharon_la_LIBADD += plugins/kernel_iph/libstrongswan-kernel-iph.la
endif
endif
if USE_WHITELIST
SUBDIRS += plugins/whitelist
if MONOLITHIC
@@ -0,0 +1,20 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libhydra \
-I$(top_srcdir)/src/libcharon
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
if MONOLITHIC
noinst_LTLIBRARIES = libstrongswan-kernel-iph.la
else
plugin_LTLIBRARIES = libstrongswan-kernel-iph.la
endif
libstrongswan_kernel_iph_la_SOURCES = \
kernel_iph_plugin.h kernel_iph_plugin.c \
kernel_iph_net.h kernel_iph_net.c
libstrongswan_kernel_iph_la_LDFLAGS = -module -avoid-version
libstrongswan_kernel_iph_la_LIBADD = -liphlpapi
@@ -0,0 +1,772 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/* Windows 7, for some iphlpapi.h functionality */
#define _WIN32_WINNT 0x0601
#include <winsock2.h>
#include <ws2ipdef.h>
#include <windows.h>
#include <ntddndis.h>
#include <naptypes.h>
#include <iphlpapi.h>
#include "kernel_iph_net.h"
#include <hydra.h>
#include <threading/mutex.h>
#include <collections/linked_list.h>
#include <processing/jobs/callback_job.h>
/** delay before firing roam events (ms) */
#define ROAM_DELAY 500
typedef struct private_kernel_iph_net_t private_kernel_iph_net_t;
/**
* Private data of kernel_iph_net implementation.
*/
struct private_kernel_iph_net_t {
/**
* Public interface.
*/
kernel_iph_net_t public;
/**
* NotifyIpInterfaceChange() handle
*/
HANDLE changes;
/**
* EnableRouter() OVERLAPPED
*/
OVERLAPPED router;
/**
* Mutex to access interface list
*/
mutex_t *mutex;
/**
* Known interfaces, as iface_t
*/
linked_list_t *ifaces;
/**
* Earliest time of the next roam event
*/
timeval_t roam_next;
/**
* Roam event due to address change?
*/
bool roam_address;
};
/**
* Interface entry
*/
typedef struct {
/** interface index */
DWORD ifindex;
/** interface name */
char *ifname;
/** interface description */
char *ifdesc;
/** type of interface */
DWORD iftype;
/** interface status */
IF_OPER_STATUS status;
/** list of known addresses, as host_t */
linked_list_t *addrs;
} iface_t;
/**
* Clean up an iface_t
*/
static void iface_destroy(iface_t *this)
{
this->addrs->destroy_offset(this->addrs, offsetof(host_t, destroy));
free(this->ifname);
free(this->ifdesc);
free(this);
}
/**
* Enum names for Windows IF_OPER_STATUS
*/
ENUM(if_oper_names, IfOperStatusUp, IfOperStatusLowerLayerDown,
"Up",
"Down",
"Testing",
"Unknown",
"Dormant",
"NotPresent",
"LowerLayerDown",
);
/**
* Callback function that raises the delayed roam event
*/
static job_requeue_t roam_event(private_kernel_iph_net_t *this)
{
bool address;
this->mutex->lock(this->mutex);
address = this->roam_address;
this->roam_address = FALSE;
this->mutex->unlock(this->mutex);
hydra->kernel_interface->roam(hydra->kernel_interface, address);
return JOB_REQUEUE_NONE;
}
/**
* Fire delayed roam event, caller should hold mutex
*/
static void fire_roam_event(private_kernel_iph_net_t *this, bool address)
{
timeval_t now;
time_monotonic(&now);
this->roam_address |= address;
if (timercmp(&now, &this->roam_next, >))
{
timeval_add_ms(&now, ROAM_DELAY);
this->roam_next = now;
lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*)
callback_job_create((callback_job_cb_t)roam_event,
this, NULL, NULL),
ROAM_DELAY);
}
}
/**
* Update addresses for an iface entry
*/
static void update_addrs(private_kernel_iph_net_t *this, iface_t *entry,
IP_ADAPTER_ADDRESSES *addr, bool log)
{
IP_ADAPTER_UNICAST_ADDRESS *current;
enumerator_t *enumerator;
linked_list_t *list;
host_t *host, *old;
bool changes = FALSE;
list = entry->addrs;
entry->addrs = linked_list_create();
for (current = addr->FirstUnicastAddress; current; current = current->Next)
{
if (current->Address.lpSockaddr->sa_family == AF_INET6)
{
struct sockaddr_in6 *sin;
sin = (struct sockaddr_in6*)current->Address.lpSockaddr;
if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
{
continue;
}
}
host = host_create_from_sockaddr(current->Address.lpSockaddr);
if (host)
{
bool found = FALSE;
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &old))
{
if (host->ip_equals(host, old))
{
list->remove_at(list, enumerator);
old->destroy(old);
found = TRUE;
}
}
enumerator->destroy(enumerator);
entry->addrs->insert_last(entry->addrs, host);
if (!found && log)
{
DBG1(DBG_KNL, "%H appeared on interface %u '%s'",
host, entry->ifindex, entry->ifdesc);
changes = TRUE;
}
}
}
while (list->remove_first(list, (void**)&old) == SUCCESS)
{
if (log)
{
DBG1(DBG_KNL, "%H disappeared from interface %u '%s'",
old, entry->ifindex, entry->ifdesc);
changes = TRUE;
}
old->destroy(old);
}
list->destroy(list);
if (changes)
{
fire_roam_event(this, TRUE);
}
}
/**
* Add an interface entry
*/
static void add_interface(private_kernel_iph_net_t *this,
IP_ADAPTER_ADDRESSES *addr, bool log)
{
enumerator_t *enumerator;
iface_t *entry;
bool exists = FALSE;
this->mutex->lock(this->mutex);
enumerator = this->ifaces->create_enumerator(this->ifaces);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->ifindex == addr->IfIndex)
{
exists = TRUE;
break;
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
if (!exists)
{
char desc[128] = "";
wcstombs(desc, addr->Description, sizeof(desc));
INIT(entry,
.ifindex = addr->IfIndex,
.ifname = strdup(addr->AdapterName),
.ifdesc = strdup(desc),
.iftype = addr->IfType,
.status = addr->OperStatus,
.addrs = linked_list_create(),
);
if (log)
{
DBG1(DBG_KNL, "interface %u '%s' appeared",
entry->ifindex, entry->ifdesc);
}
this->mutex->lock(this->mutex);
update_addrs(this, entry, addr, log);
this->ifaces->insert_last(this->ifaces, entry);
this->mutex->unlock(this->mutex);
}
}
/**
* Remove an interface entry that is gone
*/
static void remove_interface(private_kernel_iph_net_t *this, NET_IFINDEX index)
{
enumerator_t *enumerator;
iface_t *entry;
this->mutex->lock(this->mutex);
enumerator = this->ifaces->create_enumerator(this->ifaces);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->ifindex == index)
{
this->ifaces->remove_at(this->ifaces, enumerator);
DBG1(DBG_KNL, "interface %u '%s' disappeared",
entry->ifindex, entry->ifdesc);
iface_destroy(entry);
fire_roam_event(this, TRUE);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
/**
* Update an interface entry changed
*/
static void update_interface(private_kernel_iph_net_t *this,
IP_ADAPTER_ADDRESSES *addr)
{
enumerator_t *enumerator;
iface_t *entry;
this->mutex->lock(this->mutex);
enumerator = this->ifaces->create_enumerator(this->ifaces);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->ifindex == addr->IfIndex)
{
if (entry->status != addr->OperStatus)
{
DBG1(DBG_KNL, "interface %u '%s' changed state from %N to %N",
entry->ifindex, entry->ifdesc, if_oper_names,
entry->status, if_oper_names, addr->OperStatus);
entry->status = addr->OperStatus;
fire_roam_event(this, TRUE);
}
update_addrs(this, entry, addr, TRUE);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
/**
* MinGW gets MIB_IPINTERFACE_ROW wrong, as it packs InterfaceLuid just after
* Family. Fix that with our own version of the struct header.
*/
typedef struct {
ADDRESS_FAMILY Family;
union {
ULONG64 Value;
struct {
ULONG64 Reserved :24;
ULONG64 NetLuidIndex :24;
ULONG64 IfType :16;
} Info;
} InterfaceLuid;
NET_IFINDEX InterfaceIndex;
/* more would go here if needed */
} MIB_IPINTERFACE_ROW_FIXUP;
/**
* NotifyIpInterfaceChange() callback
*/
static void change_interface(private_kernel_iph_net_t *this,
MIB_IPINTERFACE_ROW_FIXUP *row, MIB_NOTIFICATION_TYPE type)
{
IP_ADAPTER_ADDRESSES addrs[64], *current;
ULONG res, size = sizeof(addrs);
if (row && type == MibDeleteInstance)
{
remove_interface(this, row->InterfaceIndex);
}
else
{
res = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL, addrs, &size);
if (res == NO_ERROR)
{
current = addrs;
while (current)
{
/* row is NULL only on MibInitialNotification */
if (!row || row->InterfaceIndex == current->IfIndex)
{
switch (type)
{
case MibParameterNotification:
update_interface(this, current);
break;
case MibInitialNotification:
add_interface(this, current, FALSE);
break;
case MibAddInstance:
add_interface(this, current, TRUE);
break;
default:
break;
}
}
current = current->Next;
}
}
else
{
DBG1(DBG_KNL, "getting IPH adapter addresses failed: 0x%08lx", res);
}
}
}
/**
* Get an iface entry for a local address, does no locking
*/
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;
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))
{
if (host->ip_equals(host, ip))
{
found = entry;
}
}
addrs->destroy(addrs);
}
ifaces->destroy(ifaces);
return found;
}
METHOD(kernel_net_t, get_interface_name, bool,
private_kernel_iph_net_t *this, host_t* ip, char **name)
{
iface_t *entry;
this->mutex->lock(this->mutex);
entry = address2entry(this, ip);
if (entry && name)
{
*name = strdup(entry->ifname);
}
this->mutex->unlock(this->mutex);
return entry != NULL;
}
/**
* Address enumerator
*/
typedef struct {
/** implements enumerator_t */
enumerator_t public;
/** what kind of address should we enumerate? */
kernel_address_type_t which;
/** enumerator over interfaces */
enumerator_t *ifaces;
/** current enumerator over addresses, or NULL */
enumerator_t *addrs;
/** mutex to unlock on destruction */
mutex_t *mutex;
} addr_enumerator_t;
METHOD(enumerator_t, addr_enumerate, bool,
addr_enumerator_t *this, host_t **host)
{
iface_t *entry;
while (TRUE)
{
while (!this->addrs)
{
if (!this->ifaces->enumerate(this->ifaces, &entry))
{
return FALSE;
}
if (entry->iftype == IF_TYPE_SOFTWARE_LOOPBACK &&
!(this->which & ADDR_TYPE_LOOPBACK))
{
continue;
}
if (entry->status != IfOperStatusUp &&
!(this->which & ADDR_TYPE_DOWN))
{
continue;
}
this->addrs = entry->addrs->create_enumerator(entry->addrs);
}
if (this->addrs->enumerate(this->addrs, host))
{
return TRUE;
}
this->addrs->destroy(this->addrs);
this->addrs = NULL;
}
}
METHOD(enumerator_t, addr_destroy, void,
addr_enumerator_t *this)
{
DESTROY_IF(this->addrs);
this->ifaces->destroy(this->ifaces);
this->mutex->unlock(this->mutex);
free(this);
}
METHOD(kernel_net_t, create_address_enumerator, enumerator_t*,
private_kernel_iph_net_t *this, kernel_address_type_t which)
{
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,
},
.which = which,
.ifaces = this->ifaces->create_enumerator(this->ifaces),
.mutex = this->mutex,
);
return &enumerator->public;
}
METHOD(kernel_net_t, get_source_addr, host_t*,
private_kernel_iph_net_t *this, host_t *dest, host_t *src)
{
MIB_IPFORWARD_ROW2 route;
SOCKADDR_INET best, *sai_dst, *sai_src = NULL;
DWORD res, index = 0;
res = GetBestInterfaceEx(dest->get_sockaddr(dest), &index);
if (res != NO_ERROR)
{
DBG1(DBG_KNL, "getting interface to %H failed: 0x%08x", dest, res);
return NULL;
}
sai_dst = (SOCKADDR_INET*)dest->get_sockaddr(dest);
if (src)
{
sai_src = (SOCKADDR_INET*)src->get_sockaddr(src);
}
res = GetBestRoute2(0, index, sai_src, sai_dst, 0, &route, &best);
if (res != NO_ERROR)
{
DBG2(DBG_KNL, "getting src address to %H failed: 0x%08x", dest, res);
return NULL;
}
return host_create_from_sockaddr((struct sockaddr*)&best);
}
METHOD(kernel_net_t, get_nexthop, host_t*,
private_kernel_iph_net_t *this, host_t *dest, host_t *src)
{
MIB_IPFORWARD_ROW2 route;
SOCKADDR_INET best, *sai_dst, *sai_src = NULL;
DWORD res, index = 0;
host_t *nexthop;
res = GetBestInterfaceEx(dest->get_sockaddr(dest), &index);
if (res != NO_ERROR)
{
DBG1(DBG_KNL, "getting interface to %H failed: 0x%08x", dest, res);
return NULL;
}
sai_dst = (SOCKADDR_INET*)dest->get_sockaddr(dest);
if (src)
{
sai_src = (SOCKADDR_INET*)src->get_sockaddr(src);
}
res = GetBestRoute2(0, index, sai_src, sai_dst, 0, &route, &best);
if (res != NO_ERROR)
{
DBG2(DBG_KNL, "getting nexthop to %H failed: 0x%08x", dest, res);
return NULL;
}
nexthop = host_create_from_sockaddr((struct sockaddr*)&route.NextHop);
if (nexthop)
{
if (!nexthop->is_anyaddr(nexthop))
{
return nexthop;
}
nexthop->destroy(nexthop);
}
return NULL;
}
METHOD(kernel_net_t, add_ip, status_t,
private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix,
char *iface_name)
{
return NOT_SUPPORTED;
}
METHOD(kernel_net_t, del_ip, status_t,
private_kernel_iph_net_t *this, host_t *virtual_ip, int prefix,
bool wait)
{
return NOT_SUPPORTED;
}
/**
* Add or remove a route
*/
static status_t manage_route(private_kernel_iph_net_t *this, bool add,
chunk_t dst, u_int8_t prefixlen, host_t *gtw, char *name)
{
MIB_IPFORWARD_ROW2 row = {
.DestinationPrefix = {
.PrefixLength = prefixlen,
},
.SitePrefixLength = prefixlen,
.ValidLifetime = INFINITE,
.PreferredLifetime = INFINITE,
.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 (streq(name, entry->ifname))
{
row.InterfaceIndex = entry->ifindex;
break;
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
if (!row.InterfaceIndex)
{
return NOT_FOUND;
}
switch (dst.len)
{
case 4:
row.DestinationPrefix.Prefix.si_family = AF_INET;
memcpy(&row.DestinationPrefix.Prefix.Ipv4.sin_addr,
dst.ptr, dst.len);
break;
case 16:
row.DestinationPrefix.Prefix.si_family = AF_INET6;
memcpy(&row.DestinationPrefix.Prefix.Ipv6.sin6_addr,
dst.ptr, dst.len);
break;
default:
return FAILED;
}
if (gtw)
{
memcpy(&row.NextHop, gtw->get_sockaddr(gtw),
*gtw->get_sockaddr_len(gtw));
}
if (add)
{
ret = CreateIpForwardEntry2(&row);
}
else
{
ret = DeleteIpForwardEntry2(&row);
}
if (ret != NO_ERROR)
{
DBG1(DBG_KNL, "%sing route failed: 0x%08lx", add ? "add" : "remov", ret);
return FAILED;
}
if (add)
{
ret = EnableRouter(NULL, &this->router);
if (ret != ERROR_IO_PENDING)
{
DBG1(DBG_KNL, "EnableRouter router failed: 0x%08lx", ret);
}
}
else
{
ret = UnenableRouter(&this->router, NULL);
if (ret != NO_ERROR)
{
DBG1(DBG_KNL, "UnenableRouter router failed: 0x%08lx", ret);
}
}
return SUCCESS;
}
METHOD(kernel_net_t, add_route, status_t,
private_kernel_iph_net_t *this, chunk_t dst, u_int8_t prefixlen,
host_t *gateway, host_t *src, char *name)
{
return manage_route(this, TRUE, dst, prefixlen, gateway, name);
}
METHOD(kernel_net_t, del_route, status_t,
private_kernel_iph_net_t *this, chunk_t dst, u_int8_t prefixlen,
host_t *gateway, host_t *src, char *name)
{
return manage_route(this, FALSE, dst, prefixlen, gateway, name);
}
METHOD(kernel_net_t, destroy, void,
private_kernel_iph_net_t *this)
{
if (this->changes)
{
CancelMibChangeNotify2(this->changes);
}
CloseHandle(this->router.hEvent);
this->mutex->destroy(this->mutex);
this->ifaces->destroy_function(this->ifaces, (void*)iface_destroy);
free(this);
}
/*
* Described in header.
*/
kernel_iph_net_t *kernel_iph_net_create()
{
private_kernel_iph_net_t *this;
ULONG res;
INIT(this,
.public = {
.interface = {
.get_interface = _get_interface_name,
.create_address_enumerator = _create_address_enumerator,
.get_source_addr = _get_source_addr,
.get_nexthop = _get_nexthop,
.add_ip = _add_ip,
.del_ip = _del_ip,
.add_route = _add_route,
.del_route = _del_route,
.destroy = _destroy,
},
},
.router = {
.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL),
},
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
.ifaces = linked_list_create(),
);
res = NotifyIpInterfaceChange(AF_UNSPEC, (void*)change_interface,
this, TRUE, &this->changes);
if (res != NO_ERROR)
{
DBG1(DBG_KNL, "registering for IPH interface changes failed: 0x%08lx",
res);
destroy(this);
return NULL;
}
return &this->public;
}
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup kernel_iph_net_i kernel_iph_net
* @{ @ingroup kernel_iph
*/
#ifndef KERNEL_IPH_NET_H_
#define KERNEL_IPH_NET_H_
#include <kernel/kernel_net.h>
typedef struct kernel_iph_net_t kernel_iph_net_t;
/**
* Implementation of the kernel network interface using Windows IP Helper.
*/
struct kernel_iph_net_t {
/**
* Implements kernel_net_t interface
*/
kernel_net_t interface;
};
/**
* Create IP Helper network backend instance.
*
* @return kernel_iph_net_t instance
*/
kernel_iph_net_t *kernel_iph_net_create();
#endif /** KERNEL_IPH_NET_H_ @}*/
@@ -0,0 +1,76 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "kernel_iph_plugin.h"
#include "kernel_iph_net.h"
#include <hydra.h>
typedef struct private_kernel_iph_plugin_t private_kernel_iph_plugin_t;
/**
* Private data of kernel iph plugin
*/
struct private_kernel_iph_plugin_t {
/**
* Implements plugin interface
*/
kernel_iph_plugin_t public;
};
METHOD(plugin_t, get_name, char*,
private_kernel_iph_plugin_t *this)
{
return "kernel-iph";
}
METHOD(plugin_t, get_features, int,
private_kernel_iph_plugin_t *this, plugin_feature_t *features[])
{
static plugin_feature_t f[] = {
PLUGIN_CALLBACK(kernel_net_register, kernel_iph_net_create),
PLUGIN_PROVIDE(CUSTOM, "kernel-net"),
};
*features = f;
return countof(f);
}
METHOD(plugin_t, destroy, void,
private_kernel_iph_plugin_t *this)
{
free(this);
}
/*
* See header file
*/
plugin_t *kernel_iph_plugin_create()
{
private_kernel_iph_plugin_t *this;
INIT(this,
.public = {
.plugin = {
.get_name = _get_name,
.get_features = _get_features,
.destroy = _destroy,
},
},
);
return &this->public.plugin;
}
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup kernel_iph kernel_iph
* @ingroup cplugins
*
* @defgroup kernel_iph_plugin kernel_iph_plugin
* @{ @ingroup kernel_iph
*/
#ifndef KERNEL_IPH_PLUGIN_H_
#define KERNEL_IPH_PLUGIN_H_
#include <plugins/plugin.h>
typedef struct kernel_iph_plugin_t kernel_iph_plugin_t;
/**
* Windows IP Helper API based networking backend.
*/
struct kernel_iph_plugin_t {
/**
* Implements plugin interface.
*/
plugin_t plugin;
};
#endif /** KERNEL_IPH_PLUGIN_H_ @}*/
@@ -0,0 +1,33 @@
AM_CPPFLAGS = \
-I$(top_srcdir)/src/libstrongswan \
-I$(top_srcdir)/src/libhydra \
-I$(top_srcdir)/src/libcharon
AM_CFLAGS = \
$(PLUGIN_CFLAGS)
if MONOLITHIC
noinst_LTLIBRARIES = libstrongswan-kernel-wfp.la
else
plugin_LTLIBRARIES = libstrongswan-kernel-wfp.la
endif
libstrongswan_kernel_wfp_la_SOURCES = \
kernel_wfp_plugin.h kernel_wfp_plugin.c \
kernel_wfp_compat.c kernel_wfp_compat.h \
kernel_wfp_ipsec.h kernel_wfp_ipsec.c
libstrongswan_kernel_wfp_la_LDFLAGS = -module -avoid-version
libstrongswan_kernel_wfp_la_LIBADD = -lfwpuclnt
noinst_PROGRAMS = ipsecdump
ipsecdump_SOURCES = \
ipsecdump.c
ipsecdump_LDADD = \
libstrongswan-kernel-wfp.la \
$(top_builddir)/src/libstrongswan/libstrongswan.la
EXTRA_DIST = mingw-w64-4.8.1.diff
@@ -0,0 +1,666 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/* Windows 7, for some fwpmu.h functionality */
#define _WIN32_WINNT 0x0601
#include "kernel_wfp_compat.h"
#include <library.h>
ENUM(auth_type_names, IPSEC_AUTH_MD5, IPSEC_AUTH_AES_256,
"MD5",
"SHA1",
"SHA256",
"AES128",
"AES192",
"AES256",
);
ENUM(auth_config_names, 0, 5,
"HMAC96",
"HMAC96",
"HMAC128",
"GMAC",
"GMAC",
"GMAC",
);
ENUM(cipher_type_names, IPSEC_CIPHER_TYPE_DES, IPSEC_CIPHER_TYPE_AES_256,
"DES",
"3DES",
"AES128",
"AES192",
"AES256",
);
ENUM(cipher_config_names, 1, 8,
"CBC",
"CBC",
"CBC",
"CBC",
"CBC",
"GCM",
"GCM",
"GCM",
);
ENUM(match_type_names, FWP_MATCH_EQUAL, FWP_MATCH_NOT_EQUAL,
"equals",
"greater",
"less than",
"greater or equal than",
"less or equal than",
"in range",
"has all flags set",
"has any flags set",
"has none flags set",
"equals case insensitive",
"not equal",
);
ENUM(traffic_type_names, IPSEC_TRAFFIC_TYPE_TRANSPORT, IPSEC_TRAFFIC_TYPE_TUNNEL,
"Transport",
"Tunnel",
);
/**
* Print a GUID to a static buffer
*/
static char *guid2string(GUID *guid)
{
static char buf[64];
snprintf(buf, sizeof(buf),
"%08x,%04x,%04x%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x",
guid->Data1, guid->Data2, guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
return buf;
}
/**
* Convert filter condition key GUID to some known strings
*/
static char* cond2name(GUID *guid, bool *address)
{
struct {
GUID guid;
char *name;
bool address;
} map[] = {
{ FWPM_CONDITION_IP_LOCAL_ADDRESS, "local address", TRUE},
{ FWPM_CONDITION_IP_REMOTE_ADDRESS, "remote address", TRUE},
{ FWPM_CONDITION_IP_SOURCE_ADDRESS, "source address", TRUE},
{ FWPM_CONDITION_IP_DESTINATION_ADDRESS, "destination address", TRUE},
{ FWPM_CONDITION_IP_LOCAL_PORT, "local port", FALSE},
{ FWPM_CONDITION_IP_REMOTE_PORT, "remote port", FALSE},
{ FWPM_CONDITION_IP_PROTOCOL, "protocol", FALSE},
{ FWPM_CONDITION_ICMP_CODE, "icmp code", FALSE},
{ FWPM_CONDITION_ICMP_TYPE, "icmp type", FALSE},
};
int i;
for (i = 0; i < countof(map); i++)
{
if (memeq(&map[i].guid, guid, sizeof(GUID)))
{
*address = map[i].address;
return map[i].name;
}
}
*address = FALSE;
return guid2string(guid);
}
/**
* Print a host from raw data and IP version
*/
static void print_host(FWP_IP_VERSION version, void *data)
{
host_t *host = NULL;
UINT32 ints[4];
switch (version)
{
case FWP_IP_VERSION_V4:
ints[0] = untoh32(data);
host = host_create_from_chunk(AF_INET, chunk_from_thing(ints[0]), 0);
break;
case FWP_IP_VERSION_V6:
ints[3] = untoh32(data);
ints[2] = untoh32(data + 4);
ints[1] = untoh32(data + 8);
ints[0] = untoh32(data + 12);
host = host_create_from_chunk(AF_INET6, chunk_from_thing(ints), 0);
break;
default:
break;
}
if (host)
{
printf("%H", host);
host->destroy(host);
}
}
/**
* Print IPSEC_SA_AUTH_INFORMATION0
*/
static void print_auth(IPSEC_SA_AUTH_INFORMATION0 *a)
{
printf("%N-%N",
auth_type_names, a->authTransform.authTransformId.authType,
auth_config_names, a->authTransform.authTransformId.authConfig);
}
/**
* Print IPSEC_SA_CIPHER_INFORMATION0
*/
static void print_cipher(IPSEC_SA_CIPHER_INFORMATION0 *c)
{
printf("%N-%N",
cipher_type_names, c->cipherTransform.cipherTransformId.cipherType,
cipher_config_names, c->cipherTransform.cipherTransformId.cipherConfig);
}
/**
* Print IPsec SA transform
*/
static void list_sa(HANDLE engine, IPSEC_SA0 *sa)
{
printf(" SPI 0x%08x\n", sa->spi);
switch (sa->saTransformType)
{
case IPSEC_TRANSFORM_AH:
printf(" AH: ");
print_auth(sa->ahInformation);
break;
case IPSEC_TRANSFORM_ESP_AUTH:
printf(" ESP: ");
print_auth(sa->espAuthInformation);
break;
case IPSEC_TRANSFORM_ESP_CIPHER:
printf(" ESP: ");
print_cipher(sa->espCipherInformation);
break;
case IPSEC_TRANSFORM_ESP_AUTH_AND_CIPHER:
printf(" ESP: ");
print_auth(&sa->espAuthAndCipherInformation->saAuthInformation);
printf(", ");
print_cipher(&sa->espAuthAndCipherInformation->saCipherInformation);
break;
default:
printf(" (Transform %d)", sa->saTransformType);
break;
}
printf("\n");
}
/**
* List a filter condition value, optionally as IP address
*/
static void print_value(FWP_CONDITION_VALUE0 *value, bool address)
{
chunk_t chunk;
switch (value->type)
{
case FWP_EMPTY:
printf("empty");
break;
case FWP_UINT8:
printf("%u", value->uint8);
break;
case FWP_UINT16:
printf("%u", value->uint16);
break;
case FWP_UINT32:
if (address)
{
print_host(FWP_IP_VERSION_V4, &value->uint32);
}
else
{
printf("%u", value->uint32);
}
break;
case FWP_UINT64:
printf("%llu", value->uint64);
break;
case FWP_INT8:
printf("%d", value->int8);
break;
case FWP_INT16:
printf("%d", value->int16);
break;
case FWP_INT32:
printf("%d", value->int32);
break;
case FWP_INT64:
printf("%lld", value->int64);
break;
case FWP_FLOAT:
printf("%f", value->float32);
break;
case FWP_DOUBLE:
printf("%lf", value->double64);
break;
case FWP_BYTE_ARRAY16_TYPE:
if (address)
{
print_host(FWP_IP_VERSION_V6, value->byteArray16);
}
else
{
chunk = chunk_create((u_char*)value->byteArray16, 16);
printf("%#B", &chunk);
}
break;
case FWP_BYTE_BLOB_TYPE:
chunk = chunk_create(value->byteBlob->data, value->byteBlob->size);
printf("%#B", &chunk);
break;
case FWP_V4_ADDR_MASK:
print_host(FWP_IP_VERSION_V4, &value->v4AddrMask->addr);
printf("/");
print_host(FWP_IP_VERSION_V4, &value->v4AddrMask->mask);
break;
case FWP_V6_ADDR_MASK:
print_host(FWP_IP_VERSION_V6, &value->v6AddrMask->addr);
printf("/%u", &value->v6AddrMask->prefixLength);
break;
case FWP_RANGE_TYPE:
print_value((FWP_CONDITION_VALUE0*)&value->rangeValue->valueLow,
address);
printf(" - ");
print_value((FWP_CONDITION_VALUE0*)&value->rangeValue->valueHigh,
address);
break;
default:
printf("(unsupported)");
break;
}
}
/**
* List a filter condition
*/
static void list_cond(HANDLE engine, FWPM_FILTER_CONDITION0 *cond)
{
bool address;
printf(" '%s' %N '", cond2name(&cond->fieldKey, &address),
match_type_names, cond->matchType);
print_value(&cond->conditionValue, address);
printf("'\n");
}
/**
* Print IPsec SA details
*/
static void list_details(HANDLE engine, IPSEC_SA_DETAILS1 *details)
{
int i;
printf(" %sbound SA: ",
details->saDirection == FWP_DIRECTION_INBOUND ? "In" : "Out");
print_host(details->traffic.ipVersion, &details->traffic.localV4Address);
printf(" %s ", details->saDirection == FWP_DIRECTION_INBOUND ? "<-" : "->");
print_host(details->traffic.ipVersion, &details->traffic.remoteV4Address);
printf("\n %N, flags: 0x%06x, lifetime: %us\n",
traffic_type_names, details->traffic.trafficType,
details->saBundle.flags, details->saBundle.lifetime.lifetimeSeconds);
if (details->udpEncapsulation)
{
printf(" UDP encap ports %u - %u\n",
details->udpEncapsulation->localUdpEncapPort,
details->udpEncapsulation->remoteUdpEncapPort);
}
for (i = 0; i < details->saBundle.numSAs; i++)
{
list_sa(engine, &details->saBundle.saList[i]);
}
printf(" Filter ID %llu\n", details->transportFilter->filterId);
for (i = 0; i < details->transportFilter->numFilterConditions; i++)
{
list_cond(engine, &details->transportFilter->filterCondition[i]);
}
}
/**
* List installed SA contexts
*/
static bool list_contexts(HANDLE engine)
{
HANDLE handle;
UINT32 returned;
DWORD res;
IPSEC_SA_CONTEXT1 **entries;
res = IPsecSaContextCreateEnumHandle0(engine, NULL, &handle);
if (res != ERROR_SUCCESS)
{
fprintf(stderr, "IPsecSaContextCreateEnumHandle0(): 0x%08x\n", res);
return FALSE;
}
while (TRUE)
{
res = IPsecSaContextEnum1(engine, handle, 1, &entries, &returned);
if (res != ERROR_SUCCESS)
{
fprintf(stderr, "IPsecSaContextEnum1(): 0x%08x\n", res);
IPsecSaContextDestroyEnumHandle0(engine, handle);
return FALSE;
}
if (returned == 0)
{
break;
}
printf("SA context %llu:\n", entries[0]->saContextId);
list_details(engine, entries[0]->inboundSa);
list_details(engine, entries[0]->outboundSa);
FwpmFreeMemory0((void**)&entries);
}
IPsecSaContextDestroyEnumHandle0(engine, handle);
return TRUE;
}
const GUID FWPM_LAYER_IPSEC_KM_DEMUX_V4 = {
0xf02b1526, 0xa459, 0x4a51, { 0xb9, 0xe3, 0x75, 0x9d, 0xe5, 0x2b, 0x9d, 0x2c }
};
const GUID FWPM_LAYER_IPSEC_KM_DEMUX_V6 = {
0x2f755cf6, 0x2fd4, 0x4e88, { 0xb3, 0xe4, 0xa9, 0x1b, 0xca, 0x49, 0x52, 0x35 }
};
const GUID FWPM_LAYER_IPSEC_V4 = {
0xeda65c74, 0x610d, 0x4bc5, { 0x94, 0x8f, 0x3c, 0x4f, 0x89, 0x55, 0x68, 0x67 }
};
const GUID FWPM_LAYER_IPSEC_V6 = {
0x13c48442, 0x8d87, 0x4261, { 0x9a, 0x29, 0x59, 0xd2, 0xab, 0xc3, 0x48, 0xb4 }
};
const GUID FWPM_LAYER_IKEEXT_V4 = {
0xb14b7bdb, 0xdbbd, 0x473e, { 0xbe, 0xd4, 0x8b, 0x47, 0x08, 0xd4, 0xf2, 0x70 }
};
const GUID FWPM_LAYER_IKEEXT_V6 = {
0xb64786b3, 0xf687, 0x4eb9, { 0x89, 0xd2, 0x8e, 0xf3, 0x2a, 0xcd, 0xab, 0xe2 }
};
const GUID FWPM_LAYER_INBOUND_IPPACKET_V4 = {
0xc86fd1bf, 0x21cd, 0x497e, { 0xa0, 0xbb, 0x17, 0x42, 0x5c, 0x88, 0x5c, 0x58 }
};
const GUID FWPM_LAYER_INBOUND_IPPACKET_V4_DISCARD = {
0xb5a230d0, 0xa8c0, 0x44f2, { 0x91, 0x6e, 0x99, 0x1b, 0x53, 0xde, 0xd1, 0xf7 }
};
const GUID FWPM_LAYER_INBOUND_IPPACKET_V6 = {
0xf52032cb, 0x991c, 0x46e7, { 0x97, 0x1d, 0x26, 0x01, 0x45, 0x9a, 0x91, 0xca }
};
const GUID FWPM_LAYER_INBOUND_IPPACKET_V6_DISCARD = {
0xbb24c279, 0x93b4, 0x47a2, { 0x83, 0xad, 0xae, 0x16, 0x98, 0xb5, 0x08, 0x85 }
};
const GUID FWPM_LAYER_OUTBOUND_IPPACKET_V4 = {
0x1e5c9fae, 0x8a84, 0x4135, { 0xa3, 0x31, 0x95, 0x0b, 0x54, 0x22, 0x9e, 0xcd }
};
const GUID FWPM_LAYER_OUTBOUND_IPPACKET_V4_DISCARD = {
0x08e4bcb5, 0xb647, 0x48f3, { 0x95, 0x3c, 0xe5, 0xdd, 0xbd, 0x03, 0x93, 0x7e }
};
const GUID FWPM_LAYER_OUTBOUND_IPPACKET_V6 = {
0xa3b3ab6b, 0x3564, 0x488c, { 0x91, 0x17, 0xf3, 0x4e, 0x82, 0x14, 0x27, 0x63 }
};
const GUID FWPM_LAYER_OUTBOUND_IPPACKET_V6_DISCARD = {
0x9513d7c4, 0xa934, 0x49dc, { 0x91, 0xa7, 0x6c, 0xcb, 0x80, 0xcc, 0x02, 0xe3 }
};
const GUID FWPM_LAYER_IPFORWARD_V4_DISCARD = {
0x9e9ea773, 0x2fae, 0x4210, { 0x8f, 0x17, 0x34, 0x12, 0x9e, 0xf3, 0x69, 0xeb }
};
const GUID FWPM_LAYER_IPFORWARD_V6_DISCARD = {
0x31524a5d, 0x1dfe, 0x472f, { 0xbb, 0x93, 0x51, 0x8e, 0xe9, 0x45, 0xd8, 0xa2 }
};
const GUID FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD = {
0xac4a9833, 0xf69d, 0x4648, { 0xb2, 0x61, 0x6d, 0xc8, 0x48, 0x35, 0xef, 0x39 }
};
const GUID FWPM_LAYER_INBOUND_TRANSPORT_V6_DISCARD = {
0x2a6ff955, 0x3b2b, 0x49d2, { 0x98, 0x48, 0xad, 0x9d, 0x72, 0xdc, 0xaa, 0xb7 }
};
const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V4_DISCARD = {
0xc5f10551, 0xbdb0, 0x43d7, { 0xa3, 0x13, 0x50, 0xe2, 0x11, 0xf4, 0xd6, 0x8a }
};
const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V6_DISCARD = {
0xf433df69, 0xccbd, 0x482e, { 0xb9, 0xb2, 0x57, 0x16, 0x56, 0x58, 0xc3, 0xb3 }
};
/**
* Convert filter layer GUID to name
*/
static char* layer2name(GUID *guid)
{
struct {
GUID guid;
char *name;
} map[] = {
{ FWPM_LAYER_IPSEC_KM_DEMUX_V4, "IPsec KM demux v4" },
{ FWPM_LAYER_IPSEC_KM_DEMUX_V6, "IPsec KM demux v6" },
{ FWPM_LAYER_IPSEC_V4, "IPsec v4" },
{ FWPM_LAYER_IPSEC_V6, "IPsec v6" },
{ FWPM_LAYER_IKEEXT_V4, "IKE ext v4" },
{ FWPM_LAYER_IKEEXT_V6, "IKE ext v6" },
{ FWPM_LAYER_INBOUND_IPPACKET_V4, "inbound v4" },
{ FWPM_LAYER_INBOUND_IPPACKET_V4_DISCARD, "inbound v4 dsc" },
{ FWPM_LAYER_INBOUND_IPPACKET_V6, "inbound v6" },
{ FWPM_LAYER_INBOUND_IPPACKET_V6_DISCARD, "inbound v6 dsc" },
{ FWPM_LAYER_OUTBOUND_IPPACKET_V4, "outbound v4" },
{ FWPM_LAYER_OUTBOUND_IPPACKET_V4_DISCARD, "outbound v4 dsc" },
{ FWPM_LAYER_OUTBOUND_IPPACKET_V6, "outbound v6" },
{ FWPM_LAYER_OUTBOUND_IPPACKET_V6_DISCARD, "outbound v6 dsc" },
{ FWPM_LAYER_IPFORWARD_V4, "forward v4" },
{ FWPM_LAYER_IPFORWARD_V4_DISCARD, "forward v4 dsc" },
{ FWPM_LAYER_IPFORWARD_V6, "forward v6" },
{ FWPM_LAYER_IPFORWARD_V6_DISCARD, "forward v6 discard" },
{ FWPM_LAYER_INBOUND_TRANSPORT_V4, "inbound transport v4" },
{ FWPM_LAYER_INBOUND_TRANSPORT_V4_DISCARD, "inbound transport v4 dsc" },
{ FWPM_LAYER_INBOUND_TRANSPORT_V6, "inbound transport v6" },
{ FWPM_LAYER_INBOUND_TRANSPORT_V6_DISCARD, "inbound v6 transport dsc" },
{ FWPM_LAYER_OUTBOUND_TRANSPORT_V4, "outbound transport v4" },
{ FWPM_LAYER_OUTBOUND_TRANSPORT_V4_DISCARD, "outbound transport v4 dsc" },
{ FWPM_LAYER_OUTBOUND_TRANSPORT_V6, "outbound transport v6" },
{ FWPM_LAYER_OUTBOUND_TRANSPORT_V6_DISCARD, "outbound transport v6 dsc" },
};
int i;
for (i = 0; i < countof(map); i++)
{
if (memeq(&map[i].guid, guid, sizeof(GUID)))
{
return map[i].name;
}
}
return NULL;
}
/**
* Convert filter callout GUID to name
*/
static char* callout2name(GUID *guid)
{
struct {
GUID guid;
char *name;
} map[] = {
{ FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4, "inbound transport v4" },
{ FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6, "inbound transport v6" },
{ FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4, "outbound transport v4" },
{ FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6, "outbound transport v6" },
{ FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4, "inbound tunnel v4" },
{ FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6, "inbound tunnel v6" },
{ FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4, "outbound tunnel v4" },
{ FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6, "outbound tunnel v6" },
{ FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4, "forward in tunnel v4" },
{ FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6, "forward in tunnel v6" },
{ FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4, "forward out tunnel v4" },
{ FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6, "forward out tunnel v6" },
};
int i;
for (i = 0; i < countof(map); i++)
{
if (memeq(&map[i].guid, guid, sizeof(GUID)))
{
return map[i].name;
}
}
return guid2string(guid);
}
/**
* Print display data with description
*/
static void print_display_data(FWPM_DISPLAY_DATA0 *data)
{
char buf[128];
buf[0] = '\0';
if (data->name)
{
wcstombs(buf, data->name, sizeof(buf));
}
printf("%s", buf);
if (data->description)
{
buf[0] = '\0';
wcstombs(buf, data->description, sizeof(buf));
if (strlen(buf))
{
printf(" (%s)", buf);
}
}
}
/**
* List installed firewall filters
*/
static bool list_filters(HANDLE engine)
{
HANDLE handle;
UINT32 returned;
DWORD res;
FWPM_FILTER0 **entries;
char *layer;
int i;
res = FwpmFilterCreateEnumHandle0(engine, NULL, &handle);
if (res != ERROR_SUCCESS)
{
fprintf(stderr, "FwpmFilterCreateEnumHandle0(): 0x%08x\n", res);
return FALSE;
}
while (TRUE)
{
res = FwpmFilterEnum0(engine, handle, 1, &entries, &returned);
if (res != ERROR_SUCCESS)
{
fprintf(stderr, "FwpmFilterEnum0(): 0x%08x\n", res);
FwpmFilterDestroyEnumHandle0(engine, handle);
return FALSE;
}
if (returned == 0)
{
break;
}
layer = layer2name(&entries[0]->layerKey);
if (layer)
{
printf("Filter ID %llu, '", entries[0]->filterId);
print_display_data(&entries[0]->displayData);
printf("'\n");
printf(" %s, ", layer);
if (entries[0]->effectiveWeight.type == FWP_UINT64)
{
printf("weight %016llx, ", *entries[0]->effectiveWeight.uint64);
}
switch (entries[0]->action.type)
{
case FWP_ACTION_BLOCK:
printf("block\n");
break;
case FWP_ACTION_PERMIT:
printf("permit\n");
break;
case FWP_ACTION_CALLOUT_TERMINATING:
printf("callout terminating: %s\n",
callout2name(&entries[0]->action.calloutKey));
break;
case FWP_ACTION_CALLOUT_INSPECTION:
printf("callout inspection: %s\n",
callout2name(&entries[0]->action.calloutKey));
break;
case FWP_ACTION_CALLOUT_UNKNOWN:
printf("callout unknown: %s\n",
callout2name(&entries[0]->action.calloutKey));
break;
default:
printf("(unknown action)\n");
break;
}
for (i = 0; i < entries[0]->numFilterConditions; i++)
{
list_cond(engine, &entries[0]->filterCondition[i]);
}
}
FwpmFreeMemory0((void**)&entries);
}
FwpmFilterDestroyEnumHandle0(engine, handle);
return TRUE;
}
/**
* ipsecdump main()
*/
int main(int argc, char *argv[])
{
FWPM_SESSION0 session = {
.displayData = {
.name = L"ipsecdump",
.description = L"strongSwan SAD/SPD dumper",
},
};
HANDLE engine;
DWORD res;
int code;
library_init(NULL, "ipsecdump");
atexit(library_deinit);
res = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &engine);
if (res != ERROR_SUCCESS)
{
fprintf(stderr, "FwpmEngineOpen(): 0x%08x\n", res);
return 2;
}
if (argc > 1 && streq(argv[1], "filters"))
{
code = list_filters(engine) ? 0 : 1;
}
else
{
code = list_contexts(engine) ? 0 : 1;
}
FwpmEngineClose0(engine);
return code;
}
@@ -0,0 +1,157 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include <library.h>
const GUID FWPM_CONDITION_IP_REMOTE_ADDRESS = {
0xb235ae9a, 0x1d64, 0x49b8, { 0xa4,0x4c,0x5f,0xf3,0xd9,0x09,0x50,0x45 }
};
const GUID FWPM_CONDITION_IP_LOCAL_ADDRESS = {
0xd9ee00de, 0xc1ef, 0x4617, { 0xbf,0xe3,0xff,0xd8,0xf5,0xa0,0x89,0x57 }
};
const GUID FWPM_CONDITION_IP_SOURCE_ADDRESS = {
0xae96897e, 0x2e94, 0x4bc9, { 0xb3,0x13,0xb2,0x7e,0xe8,0x0e,0x57,0x4d }
};
const GUID FWPM_CONDITION_IP_DESTINATION_ADDRESS = {
0x2d79133b, 0xb390, 0x45c6, { 0x86,0x99,0xac,0xac,0xea,0xaf,0xed,0x33 }
};
const GUID FWPM_CONDITION_IP_LOCAL_PORT = {
0x0c1ba1af, 0x5765, 0x453f, { 0xaf,0x22,0xa8,0xf7,0x91,0xac,0x77,0x5b }
};
const GUID FWPM_CONDITION_IP_REMOTE_PORT = {
0xc35a604d, 0xd22b, 0x4e1a, { 0x91,0xb4,0x68,0xf6,0x74,0xee,0x67,0x4b }
};
const GUID FWPM_CONDITION_IP_PROTOCOL = {
0x3971ef2b, 0x623e, 0x4f9a, { 0x8c,0xb1,0x6e,0x79,0xb8,0x06,0xb9,0xa7 }
};
const GUID FWPM_LAYER_INBOUND_TRANSPORT_V4 = {
0x5926dfc8, 0xe3cf, 0x4426, { 0xa2,0x83,0xdc,0x39,0x3f,0x5d,0x0f,0x9d }
};
const GUID FWPM_LAYER_INBOUND_TRANSPORT_V6 = {
0x634a869f, 0xfc23, 0x4b90, { 0xb0,0xc1,0xbf,0x62,0x0a,0x36,0xae,0x6f }
};
const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V4 = {
0x09e61aea, 0xd214, 0x46e2, { 0x9b,0x21,0xb2,0x6b,0x0b,0x2f,0x28,0xc8 }
};
const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V6 = {
0xe1735bde, 0x013f, 0x4655, { 0xb3,0x51,0xa4,0x9e,0x15,0x76,0x2d,0xf0 }
};
const GUID FWPM_LAYER_IPFORWARD_V4 = {
0xa82acc24, 0x4ee1, 0x4ee1, { 0xb4,0x65,0xfd,0x1d,0x25,0xcb,0x10,0xa4}
};
const GUID FWPM_LAYER_IPFORWARD_V6 = {
0x7b964818, 0x19c7, 0x493a, { 0xb7,0x1f,0x83,0x2c,0x36,0x84,0xd2,0x8c }
};
const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4 = {
0x5132900d, 0x5e84, 0x4b5f, { 0x80,0xe4,0x01,0x74,0x1e,0x81,0xff,0x10 }
};
const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6 = {
0x49d3ac92, 0x2a6c, 0x4dcf, { 0x95,0x5f,0x1c,0x3b,0xe0,0x09,0xdd,0x99 }
};
const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4 = {
0x4b46bf0a, 0x4523, 0x4e57, { 0xaa,0x38,0xa8,0x79,0x87,0xc9,0x10,0xd9 }
};
const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6 = {
0x38d87722, 0xad83, 0x4f11, { 0xa9,0x1f,0xdf,0x0f,0xb0,0x77,0x22,0x5b }
};
const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4 = {
0x191a8a46, 0x0bf8, 0x46cf, { 0xb0,0x45,0x4b,0x45,0xdf,0xa6,0xa3,0x24 }
};
const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6 = {
0x80c342e3, 0x1e53, 0x4d6f, { 0x9b,0x44,0x03,0xdf,0x5a,0xee,0xe1,0x54 }
};
const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4 = {
0x70a4196c, 0x835b, 0x4fb0, { 0x98,0xe8,0x07,0x5f,0x4d,0x97,0x7d,0x46 }
};
const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6 = {
0xf1835363, 0xa6a5, 0x4e62, { 0xb1,0x80,0x23,0xdb,0x78,0x9d,0x8d,0xa6 }
};
const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4 = {
0x28829633, 0xc4f0, 0x4e66, { 0x87,0x3f,0x84,0x4d,0xb2,0xa8,0x99,0xc7 }
};
const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6 = {
0xaf50bec2, 0xc686, 0x429a, { 0x88,0x4d,0xb7,0x44,0x43,0xe7,0xb0,0xb4 }
};
const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4 = {
0xfb532136, 0x15cb, 0x440b, { 0x93,0x7c,0x17,0x17,0xca,0x32,0x0c,0x40 }
};
const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6 = {
0xdae640cc, 0xe021, 0x4bee, { 0x9e,0xb6,0xa4,0x8b,0x27,0x5c,0x8c,0x1d }
};
/**
* Load a function symbol from a loaded dll
*/
static inline void *load_function(char *dll, char *name)
{
HANDLE handle;
void *sym = NULL;
handle = GetModuleHandle(dll);
if (!handle)
{
return NULL;
}
sym = GetProcAddress(handle, name);
return sym;
}
/**
* Macro that defines a stub for a function that calls the same DLL function
*
* @param dll DLL to find function in
* @param ret return type of function
* @param name function name
* @param size size of all arguments on stack
* @param ... arguments of function
*/
#define STUB(dll, ret, name, size, ...) \
ret WINAPI name(__VA_ARGS__) \
{ \
static void (*fun)() = NULL; \
if (!fun) \
{ \
fun = load_function(#dll, #name); \
} \
if (fun) \
{ \
__builtin_return(__builtin_apply(fun, __builtin_apply_args(), size)); \
} \
return ERROR_NOT_SUPPORTED; \
}
STUB(fwpuclnt, DWORD, IPsecSaContextCreate1, 40,
HANDLE engineHandle, const void *outboundTraffic,
const void *virtualIfTunnelInfo, UINT64 *inboundFilterId, UINT64 *id)
STUB(fwpuclnt, DWORD, IPsecSaContextSetSpi0, 32,
HANDLE engineHandle, UINT64 id, const void *getSpi, UINT32 inboundSpi)
STUB(fwpuclnt, DWORD, IPsecSaContextGetById1, 24,
HANDLE engineHandle, UINT64 id, void **saContext)
STUB(fwpuclnt, DWORD, IPsecSaContextUpdate0, 24,
HANDLE engineHandle, UINT32 flags, const void *newValues)
STUB(fwpuclnt, DWORD, IPsecSaContextEnum1, 40,
HANDLE engineHandle, HANDLE enumHandle, UINT32 numEntriesRequested,
void ***entries, UINT32 *numEntriesReturned)
STUB(fwpuclnt, DWORD, FwpmNetEventSubscribe0, 40,
HANDLE engineHandle, const void *subscription, void(*callback)(),
void *context, HANDLE *eventsHandle)
STUB(fwpuclnt, DWORD, FwpmNetEventUnsubscribe0, 16,
HANDLE engineHandle, HANDLE eventsHandle)
@@ -0,0 +1,205 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup kernel_wfp_compat kernel_wfp_compat
* @{ @ingroup kernel_wfp
*/
#ifndef KERNEL_WFP_COMPAT_H_
#define KERNEL_WFP_COMPAT_H_
#include <winsock2.h>
#include <windows.h>
#include <ipsectypes.h>
/* MinGW defines CIPHERs incorrectly starting at 0 */
#define IPSEC_CIPHER_TYPE_DES 1
#define IPSEC_CIPHER_TYPE_3DES 2
#define IPSEC_CIPHER_TYPE_AES_128 3
#define IPSEC_CIPHER_TYPE_AES_192 4
#define IPSEC_CIPHER_TYPE_AES_256 5
#define IPSEC_CIPHER_TYPE_MAX 6
#include <fwpmtypes.h>
#include <fwpmu.h>
#undef interface
/* MinGW defines TRANSFORMs incorrectly starting at 0 */
#define IPSEC_TRANSFORM_AH 1
#define IPSEC_TRANSFORM_ESP_AUTH 2
#define IPSEC_TRANSFORM_ESP_CIPHER 3
#define IPSEC_TRANSFORM_ESP_AUTH_AND_CIPHER 4
#define IPSEC_TRANSFORM_ESP_AUTH_FW 5
#define IPSEC_TRANSFORM_TYPE_MAX 6
/* missing in MinGW */
enum {
FWPM_TUNNEL_FLAG_POINT_TO_POINT = (1<<0),
FWPM_TUNNEL_FLAG_ENABLE_VIRTUAL_IF_TUNNELING = (1<<1),
};
/* missing in MinGW */
enum {
IPSEC_SA_DETAILS_UPDATE_TRAFFIC = (1<<0),
IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION = (1<<1),
IPSEC_SA_BUNDLE_UPDATE_FLAGS = (1<<2),
IPSEC_SA_BUNDLE_UPDATE_NAP_CONTEXT = (1<<3),
IPSEC_SA_BUNDLE_UPDATE_KEY_MODULE_STATE = (1<<4),
IPSEC_SA_BUNDLE_UPDATE_PEER_V4_PRIVATE_ADDRESS = (1<<5),
IPSEC_SA_BUNDLE_UPDATE_MM_SA_ID = (1<<6),
};
/* missing in MinGW */
enum {
FWPM_NET_EVENT_FLAG_IP_PROTOCOL_SET = (1<<0),
FWPM_NET_EVENT_FLAG_LOCAL_ADDR_SET = (1<<1),
FWPM_NET_EVENT_FLAG_REMOTE_ADDR_SET = (1<<2),
FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET = (1<<3),
FWPM_NET_EVENT_FLAG_REMOTE_PORT_SET = (1<<4),
FWPM_NET_EVENT_FLAG_APP_ID_SET = (1<<5),
FWPM_NET_EVENT_FLAG_USER_ID_SET = (1<<6),
FWPM_NET_EVENT_FLAG_SCOPE_ID_SET = (1<<7),
FWPM_NET_EVENT_FLAG_IP_VERSION_SET = (1<<8),
FWPM_NET_EVENT_FLAG_REAUTH_REASON_SET = (1<<9),
};
/* missing in MinGW */
enum {
FWPM_FILTER_FLAG_PERSISTENT = (1<<0),
FWPM_FILTER_FLAG_BOOTTIME = (1<<1),
FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT = (1<<2),
FWPM_FILTER_FLAG_CLEAR_ACTION_RIGHT = (1<<3),
FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED = (1<<4),
FWPM_FILTER_FLAG_DISABLED = (1<<5),
};
/* missing in MinGW */
enum {
IPSEC_SA_BUNDLE_FLAG_ND_SECURE = (1<< 0),
IPSEC_SA_BUNDLE_FLAG_ND_BOUNDARY = (1<< 1),
IPSEC_SA_BUNDLE_FLAG_ND_PEER_NAT_BOUNDARY = (1<< 2),
IPSEC_SA_BUNDLE_FLAG_GUARANTEE_ENCRYPTION = (1<< 3),
IPSEC_SA_BUNDLE_FLAG_NLB = (1<< 4),
IPSEC_SA_BUNDLE_FLAG_NO_MACHINE_LUID_VERIFY = (1<< 5),
IPSEC_SA_BUNDLE_FLAG_NO_IMPERSONATION_LUID_VERIFY = (1<< 6),
IPSEC_SA_BUNDLE_FLAG_NO_EXPLICIT_CRED_MATCH = (1<< 7),
IPSEC_SA_BUNDLE_FLAG_ALLOW_NULL_TARGET_NAME_MATCH = (1<< 9),
IPSEC_SA_BUNDLE_FLAG_CLEAR_DF_ON_TUNNEL = (1<<10),
IPSEC_SA_BUNDLE_FLAG_ASSUME_UDP_CONTEXT_OUTBOUND = (1<<11),
IPSEC_SA_BUNDLE_FLAG_ND_PEER_BOUNDARY = (1<<12),
IPSEC_SA_BUNDLE_FLAG_SUPPRESS_DUPLICATE_DELETION = (1<<13),
IPSEC_SA_BUNDLE_FLAG_PEER_SUPPORTS_GUARANTEE_ENCRYPTION = (1<<14),
IPSEC_SA_BUNDLE_FLAG_FORCE_INBOUND_CONNECTIONS = (1<<15),
IPSEC_SA_BUNDLE_FLAG_FORCE_OUTBOUND_CONNECTIONS = (1<<16),
IPSEC_SA_BUNDLE_FLAG_FORWARD_PATH_INITIATOR = (1<<17),
};
/* missing in some MinGW versions */
const GUID FWPM_CONDITION_IP_REMOTE_ADDRESS;
const GUID FWPM_CONDITION_IP_LOCAL_ADDRESS;
const GUID FWPM_CONDITION_IP_SOURCE_ADDRESS;
const GUID FWPM_CONDITION_IP_DESTINATION_ADDRESS;
const GUID FWPM_CONDITION_IP_LOCAL_PORT;
const GUID FWPM_CONDITION_IP_REMOTE_PORT;
const GUID FWPM_CONDITION_IP_PROTOCOL;
#ifndef FWPM_CONDITION_ICMP_TYPE
# define FWPM_CONDITION_ICMP_TYPE FWPM_CONDITION_IP_LOCAL_PORT
#endif
#ifndef FWPM_CONDITION_ICMP_CODE
# define FWPM_CONDITION_ICMP_CODE FWPM_CONDITION_IP_REMOTE_PORT
#endif
const GUID FWPM_LAYER_INBOUND_TRANSPORT_V4;
const GUID FWPM_LAYER_INBOUND_TRANSPORT_V6;
const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V4;
const GUID FWPM_LAYER_OUTBOUND_TRANSPORT_V6;
const GUID FWPM_LAYER_IPFORWARD_V4;
const GUID FWPM_LAYER_IPFORWARD_V6;
const GUID FWPM_SUBLAYER_IPSEC_TUNNEL;
const GUID FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL;
const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4;
const GUID FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6;
const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4;
const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6;
const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4;
const GUID FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6;
const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4;
const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6;
const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4;
const GUID FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6;
const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4;
const GUID FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6;
/* integrity config, missing in some MinGW versions */
#ifndef IPSEC_AUTH_CONFIG_HMAC_MD5_96
enum {
IPSEC_AUTH_CONFIG_HMAC_MD5_96 = 0,
IPSEC_AUTH_CONFIG_HMAC_SHA_1_96,
IPSEC_AUTH_CONFIG_HMAC_SHA_256_128,
IPSEC_AUTH_CONFIG_GCM_AES_128,
IPSEC_AUTH_CONFIG_GCM_AES_192,
IPSEC_AUTH_CONFIG_GCM_AES_256,
IPSEC_AUTH_CONFIG_MAX
};
#define IPSEC_AUTH_TRANSFORM_ID_HMAC_MD5_96 { \
IPSEC_AUTH_MD5, IPSEC_AUTH_CONFIG_HMAC_MD5_96 }
#define IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96 { \
IPSEC_AUTH_SHA_1, IPSEC_AUTH_CONFIG_HMAC_SHA_1_96 }
#define IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_256_128 { \
IPSEC_AUTH_SHA_256, IPSEC_AUTH_CONFIG_HMAC_SHA_256_128 }
#define IPSEC_AUTH_TRANSFORM_ID_GCM_AES_128 { \
IPSEC_AUTH_AES_128, IPSEC_AUTH_CONFIG_GCM_AES_128 }
#define IPSEC_AUTH_TRANSFORM_ID_GCM_AES_192 { \
IPSEC_AUTH_AES_192, IPSEC_AUTH_CONFIG_GCM_AES_192 }
#define IPSEC_AUTH_TRANSFORM_ID_GCM_AES_256 { \
IPSEC_AUTH_AES_256, IPSEC_AUTH_CONFIG_GCM_AES_256 }
#endif
/* encryption config, missing in some MinGW versions */
#ifndef IPSEC_CIPHER_CONFIG_CBC_DES
enum {
IPSEC_CIPHER_CONFIG_CBC_DES = 1,
IPSEC_CIPHER_CONFIG_CBC_3DES,
IPSEC_CIPHER_CONFIG_CBC_AES_128,
IPSEC_CIPHER_CONFIG_CBC_AES_192,
IPSEC_CIPHER_CONFIG_CBC_AES_256,
IPSEC_CIPHER_CONFIG_GCM_AES_128,
IPSEC_CIPHER_CONFIG_GCM_AES_192,
IPSEC_CIPHER_CONFIG_GCM_AES_256,
IPSEC_CIPHER_CONFIG_MAX
};
#define IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_128 { \
IPSEC_CIPHER_TYPE_AES_128, IPSEC_CIPHER_CONFIG_GCM_AES_128 }
#define IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_192 { \
IPSEC_CIPHER_TYPE_AES_192, IPSEC_CIPHER_CONFIG_GCM_AES_192 }
#define IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_256 { \
IPSEC_CIPHER_TYPE_AES_256, IPSEC_CIPHER_CONFIG_GCM_AES_256 }
#define IPSEC_CIPHER_TRANSFORM_ID_CBC_DES { \
IPSEC_CIPHER_TYPE_DES, IPSEC_CIPHER_CONFIG_CBC_DES }
#define IPSEC_CIPHER_TRANSFORM_ID_CBC_3DES { \
IPSEC_CIPHER_TYPE_3DES, IPSEC_CIPHER_CONFIG_CBC_3DES }
#define IPSEC_CIPHER_TRANSFORM_ID_AES_128 { \
IPSEC_CIPHER_TYPE_AES_128, IPSEC_CIPHER_CONFIG_CBC_AES_128 }
#define IPSEC_CIPHER_TRANSFORM_ID_AES_192 { \
IPSEC_CIPHER_TYPE_AES_192, IPSEC_CIPHER_CONFIG_CBC_AES_192 }
#define IPSEC_CIPHER_TRANSFORM_ID_AES_256 { \
IPSEC_CIPHER_TYPE_AES_256, IPSEC_CIPHER_CONFIG_CBC_AES_256 }
#endif
DWORD WINAPI FwpmIPsecTunnelAdd0(HANDLE, UINT32,
const FWPM_PROVIDER_CONTEXT0*, const FWPM_PROVIDER_CONTEXT0*, UINT32,
const FWPM_FILTER_CONDITION0*, PSECURITY_DESCRIPTOR);
#endif /** KERNEL_WFP_COMPAT_H_ @}*/
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup kernel_wfp_ipsec kernel_wfp_ipsec
* @{ @ingroup kernel_wfp
*/
#ifndef KERNEL_WFP_IPSEC_H_
#define KERNEL_WFP_IPSEC_H_
#include <library.h>
#include <kernel/kernel_ipsec.h>
typedef struct kernel_wfp_ipsec_t kernel_wfp_ipsec_t;
/**
* Windows Filter Platform based IPsec kernel backend.
*/
struct kernel_wfp_ipsec_t {
/**
* Implements kernel_ipsec_t interface
*/
kernel_ipsec_t interface;
};
/**
* Create WFP kernel interface instance.
*
* @return kernel_wfp_ipsec_t instance
*/
kernel_wfp_ipsec_t *kernel_wfp_ipsec_create();
#endif /** KERNEL_WFP_IPSEC_H_ @}*/
@@ -0,0 +1,77 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "kernel_wfp_plugin.h"
#include "kernel_wfp_ipsec.h"
#include <daemon.h>
typedef struct private_kernel_wfp_plugin_t private_kernel_wfp_plugin_t;
/**
* Private data of kernel-wfp plugin
*/
struct private_kernel_wfp_plugin_t {
/**
* Implements plugin interface
*/
kernel_wfp_plugin_t public;
};
METHOD(plugin_t, get_name, char*,
private_kernel_wfp_plugin_t *this)
{
return "kernel-wfp";
}
METHOD(plugin_t, get_features, int,
private_kernel_wfp_plugin_t *this, plugin_feature_t *features[])
{
static plugin_feature_t f[] = {
PLUGIN_CALLBACK(kernel_ipsec_register, kernel_wfp_ipsec_create),
PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
PLUGIN_DEPENDS(RNG, RNG_WEAK),
PLUGIN_DEPENDS(RNG, RNG_STRONG),
};
*features = f;
return countof(f);
}
METHOD(plugin_t, destroy, void,
private_kernel_wfp_plugin_t *this)
{
free(this);
}
/*
* see header file
*/
plugin_t *kernel_wfp_plugin_create()
{
private_kernel_wfp_plugin_t *this;
INIT(this,
.public = {
.plugin = {
.get_name = _get_name,
.get_features = _get_features,
.destroy = _destroy,
},
},
);
return &this->public.plugin;
}
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* 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
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup kernel_wfp kernel_wfp
* @ingroup cplugins
*
* @defgroup kernel_wfp_plugin kernel_wfp_plugin
* @{ @ingroup kernel_wfp
*/
#ifndef KERNEL_WFP_PLUGIN_H_
#define KERNEL_WFP_PLUGIN_H_
#include <library.h>
#include <plugins/plugin.h>
typedef struct kernel_wfp_plugin_t kernel_wfp_plugin_t;
/**
* Windows Filter Platform based IPsec backend plugin.
*/
struct kernel_wfp_plugin_t {
/**
* implements plugin interface
*/
plugin_t plugin;
};
#endif /** KERNEL_WFP_PLUGIN_H_ @}*/
@@ -0,0 +1,26 @@
diff -Naur /mingw-orig/x86_64-w64-mingw32/include/fwptypes.h /mingw/x86_64-w64-mingw32/include/fwptypes.h
--- /mingw-orig/x86_64-w64-mingw32/include/fwptypes.h 2013-08-30 07:15:40 +0200
+++ /mingw/x86_64-w64-mingw32/include/fwptypes.h 2014-01-02 16:32:26 +0100
@@ -333,11 +333,6 @@
} __C89_NAMELESSUNIONNAME;
} FWP_CONDITION_VALUE0;
-typedef struct FWPM_DISPLAY_DATA0_ {
- wchar_t *name;
- wchar_t *description;
-} FWPM_DISPLAY_DATA0;
-
#endif /* WINAPI_PARTITION_DESKTOP. */
/* Begin additional prototypes for all interfaces */
diff -Naur /mingw-orig/x86_64-w64-mingw32/include/iketypes.h /mingw/x86_64-w64-mingw32/include/iketypes.h
--- /mingw-orig/x86_64-w64-mingw32/include/iketypes.h 2013-08-30 07:15:40 +0200
+++ /mingw/x86_64-w64-mingw32/include/iketypes.h 2014-01-02 16:31:12 +0100
@@ -212,7 +212,6 @@
FWP_BYTE_BLOB presharedKey;
UINT32 flags;
} IKEEXT_PRESHARED_KEY_AUTHENTICATION1;
-#endif
typedef struct IKEEXT_CERTIFICATE_AUTHENTICATION0_ {
IKEEXT_CERT_CONFIG_TYPE inboundConfigType;
@@ -49,6 +49,7 @@ METHOD(plugin_t, get_features, int,
static plugin_feature_t f[] = {
PLUGIN_CALLBACK(socket_register, socket_win_socket_create),
PLUGIN_PROVIDE(CUSTOM, "socket"),
PLUGIN_DEPENDS(CUSTOM, "kernel-ipsec"),
};
*features = f;
return countof(f);
@@ -19,6 +19,7 @@
#include "socket_win_socket.h"
#include <library.h>
#include <hydra.h>
#include <threading/thread.h>
#include <daemon.h>
@@ -424,6 +425,16 @@ static SOCKET open_socket(private_socket_win_socket_t *this, int i)
closesocket(s);
return INVALID_SOCKET;
}
if (!hydra->kernel_interface->bypass_socket(hydra->kernel_interface,
s, AF_INET))
{
DBG1(DBG_NET, "installing IPv4 IKE bypass policy failed");
}
if (!hydra->kernel_interface->bypass_socket(hydra->kernel_interface,
s, AF_INET6))
{
DBG1(DBG_NET, "installing IPv6 IKE bypass policy failed");
}
return s;
}
+22 -3
View File
@@ -730,6 +730,17 @@ METHOD(child_sa_t, install, status_t,
return status;
}
/**
* Check kernel interface if policy updates are required
*/
static bool require_policy_update()
{
kernel_feature_t f;
f = hydra->kernel_interface->get_features(hydra->kernel_interface);
return !(f & KERNEL_NO_POLICY_UPDATES);
}
/**
* Install 3 policies: out, in and forward
*/
@@ -836,13 +847,21 @@ METHOD(child_sa_t, add_policies, status_t,
priority = this->trap ? POLICY_PRIORITY_ROUTED
: POLICY_PRIORITY_DEFAULT;
enumerator = create_policy_enumerator(this);
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
{
my_sa.policy_count++;
other_sa.policy_count++;
}
enumerator->destroy(enumerator);
/* enumerate pairs of traffic selectors */
enumerator = create_policy_enumerator(this);
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
{
/* install outbound drop policy to avoid packets leaving unencrypted
* when updating policies */
if (priority == POLICY_PRIORITY_DEFAULT)
if (priority == POLICY_PRIORITY_DEFAULT && require_policy_update())
{
status |= install_policies_internal(this, this->my_addr,
this->other_addr, my_ts, other_ts,
@@ -936,7 +955,7 @@ METHOD(child_sa_t, update, status_t,
}
}
if (this->config->install_policy(this->config))
if (this->config->install_policy(this->config) && require_policy_update())
{
ipsec_sa_cfg_t my_sa = {
.mode = this->mode,
@@ -1075,7 +1094,7 @@ METHOD(child_sa_t, destroy, void,
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
{
del_policies_internal(this, my_ts, other_ts, priority);
if (priority == POLICY_PRIORITY_DEFAULT)
if (priority == POLICY_PRIORITY_DEFAULT && require_policy_update())
{
del_policies_internal(this, my_ts, other_ts,
POLICY_PRIORITY_FALLBACK);
+2
View File
@@ -69,6 +69,8 @@ enum kernel_feature_t {
KERNEL_REQUIRE_EXCLUDE_ROUTE = (1<<1),
/** IPsec implementation requires UDP encapsulation of ESP packets */
KERNEL_REQUIRE_UDP_ENCAPSULATION = (1<<2),
/** IPsec backend does not require a policy reinstall on SA updates */
KERNEL_NO_POLICY_UPDATES = (1<<3),
};
/**
+2
View File
@@ -122,6 +122,8 @@ struct ipsec_sa_cfg_t {
ipsec_mode_t mode;
/** unique ID */
u_int32_t reqid;
/** number of policies of the same kind (in/out/fwd) attached to SA */
u_int32_t policy_count;
/** details about ESP/AH */
struct {
/** TRUE if this protocol is used */