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:
@@ -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
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user