aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcharon/plugins
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2013-12-16 17:13:03 +0100
committerMartin Willi <martin@revosec.ch>2014-06-04 16:32:09 +0200
commit489a4f2192a4cc246869fe8e129e7f31196ccc77 (patch)
tree8dc8c5c7e79a59707b8d88e73c982adc37445d3f /src/libcharon/plugins
parent9c974c329d0ad6f4b303236f1b2c29f0c8e1b39f (diff)
downloadstrongswan-489a4f2192a4cc246869fe8e129e7f31196ccc77.tar.bz2
strongswan-489a4f2192a4cc246869fe8e129e7f31196ccc77.tar.xz
kernel-wfp: Add an ipsecdump utility to show installed SAs/SPs on Windows
Diffstat (limited to 'src/libcharon/plugins')
-rw-r--r--src/libcharon/plugins/kernel_wfp/Makefile.am9
-rw-r--r--src/libcharon/plugins/kernel_wfp/ipsecdump.c419
-rw-r--r--src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c4
3 files changed, 432 insertions, 0 deletions
diff --git a/src/libcharon/plugins/kernel_wfp/Makefile.am b/src/libcharon/plugins/kernel_wfp/Makefile.am
index 405e581e4..5ff93da4b 100644
--- a/src/libcharon/plugins/kernel_wfp/Makefile.am
+++ b/src/libcharon/plugins/kernel_wfp/Makefile.am
@@ -19,3 +19,12 @@ libstrongswan_kernel_wfp_la_SOURCES = \
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
diff --git a/src/libcharon/plugins/kernel_wfp/ipsecdump.c b/src/libcharon/plugins/kernel_wfp/ipsecdump.c
new file mode 100644
index 000000000..af3bd044c
--- /dev/null
+++ b/src/libcharon/plugins/kernel_wfp/ipsecdump.c
@@ -0,0 +1,419 @@
+/*
+ * 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;
+}
+
+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 }
+};
+
+/**
+ * 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;
+}
+
+/**
+ * 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;
+ }
+ code = list_contexts(engine) ? 0 : 1;
+ FwpmEngineClose0(engine);
+ return code;
+}
diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c
index 6b32f3192..05659399d 100644
--- a/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c
+++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c
@@ -96,3 +96,7 @@ STUB(fwpuclnt, DWORD, IPsecSaContextGetById1, 24,
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)