]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
kernel-wfp: Manually create a ProviderContext to attach individual filters
authorMartin Willi <martin@revosec.ch>
Thu, 19 Dec 2013 15:55:43 +0000 (16:55 +0100)
committerMartin Willi <martin@revosec.ch>
Wed, 4 Jun 2014 14:32:10 +0000 (16:32 +0200)
This gives us more flexibility than using the intransparent FwpmIPsecTunnelAdd,
and fixes the issues we have seen with trap policies. Forward filters are
still missing, but required for site-to-site tunnels.

src/libcharon/plugins/kernel_wfp/ipsecdump.c
src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.c
src/libcharon/plugins/kernel_wfp/kernel_wfp_compat.h
src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c

index ec3c78ea30e95458a36d30d7f6e67b6607f285f0..55e64fe938e743166b266dfaa9e9aaf46c4eab48 100644 (file)
@@ -504,18 +504,6 @@ static char* layer2name(GUID *guid)
        return NULL;
 }
 
-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 }
 };
index 4296e147c24d3cd071cf639211da3a050a08d17a..3660ac9d629e3aa866c7c66231467404adeb19e3 100644 (file)
@@ -54,6 +54,18 @@ const GUID FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4 = {
 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 }
+};
 
 /**
  * Load a function symbol from a loaded dll
index 92c90c61737542433eb7ca374ac87c4b9a0985b5..9c9addbea8e97cbb41e02cc4aab6f77f79e19ec1 100644 (file)
@@ -76,6 +76,16 @@ enum {
        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),
+};
+
 DWORD WINAPI FwpmIPsecTunnelAdd0(HANDLE, UINT32,
        const FWPM_PROVIDER_CONTEXT0*, const FWPM_PROVIDER_CONTEXT0*, UINT32,
        const FWPM_FILTER_CONDITION0*, PSECURITY_DESCRIPTOR);
index ac038e16bafa9eafaa94a998a2ace0f2be75227b..5c956ea690bcce3a14bfcf64d9d9b87faa78fe09 100644 (file)
@@ -174,10 +174,12 @@ typedef struct {
        ipsec_mode_t mode;
        /** UDP encapsulation */
        bool encap;
-       /** WFP allocated LUID for inbound filter/tunnel policy ID */
+       /** WFP allocated LUID for inbound filter ID */
        u_int64_t policy_in;
-       /** WFP allocated LUID for outbound filter ID, unused for tunnel mode */
+       /** WFP allocated LUID for outbound filter ID */
        u_int64_t policy_out;
+       /** provider context, for tunnel mode only */
+       u_int64_t provider;
        /** WFP allocated LUID for SA context */
        u_int64_t sa_id;
 } entry_t;
@@ -232,29 +234,6 @@ static u_int hash_route(route_t *route)
 static bool manage_routes(private_kernel_wfp_ipsec_t *this, entry_t *entry,
                                                  bool add);
 
-/**
- * Remove a transport or tunnel policy from kernel
- */
-static void cleanup_policy(private_kernel_wfp_ipsec_t *this, bool transport,
-                                                  u_int64_t policy)
-{
-       if (transport)
-       {
-               FwpmFilterDeleteById0(this->handle, policy);
-       }
-       else
-       {
-               FWPM_PROVIDER_CONTEXT0 *ctx;
-
-               if (FwpmProviderContextGetById0(this->handle, policy,
-                                                                               &ctx) == ERROR_SUCCESS)
-               {
-                       FwpmIPsecTunnelDeleteByKey0(this->handle, &ctx->providerContextKey);
-                       FwpmFreeMemory0((void**)&ctx);
-               }
-       }
-}
-
 /**
  * Remove policies associated to an entry from kernel
  */
@@ -262,12 +241,12 @@ static void cleanup_policies(private_kernel_wfp_ipsec_t *this, entry_t *entry)
 {
        if (entry->policy_in)
        {
-               cleanup_policy(this, entry->mode == MODE_TRANSPORT, entry->policy_in);
+               FwpmFilterDeleteById0(this->handle, entry->policy_in);
                entry->policy_in = 0;
        }
        if (entry->policy_out)
        {
-               cleanup_policy(this, entry->mode == MODE_TRANSPORT, entry->policy_out);
+               FwpmFilterDeleteById0(this->handle, entry->policy_out);
                entry->policy_out = 0;
        }
        if (entry->mode == MODE_TUNNEL)
@@ -285,6 +264,10 @@ static void entry_destroy(private_kernel_wfp_ipsec_t *this, entry_t *entry)
        {
                IPsecSaContextDeleteById0(this->handle, entry->sa_id);
        }
+       if (entry->provider)
+       {
+               FwpmProviderContextDeleteById0(this->handle, entry->provider);
+       }
        cleanup_policies(this, entry);
        array_destroy_function(entry->sps, (void*)sp_entry_destroy, NULL);
        entry->local->destroy(entry->local);
@@ -547,10 +530,10 @@ static void free_conditions(FWPM_FILTER_CONDITION0 *conds, int count)
 }
 
 /**
- * Install transport mode SP to the kernel
+ * Install a single policy in to the kernel
  */
-static bool install_transport_sp(private_kernel_wfp_ipsec_t *this,
-                                                                entry_t *entry, bool inbound)
+static bool install_sp(private_kernel_wfp_ipsec_t *this,
+                                          entry_t *entry, GUID *context, bool inbound)
 {
        FWPM_FILTER_CONDITION0 *conds = NULL;
        int count = 0;
@@ -560,17 +543,41 @@ static bool install_transport_sp(private_kernel_wfp_ipsec_t *this,
        DWORD res;
        FWPM_FILTER0 filter = {
                .displayData = {
-                       .name = L"charon IPsec transport",
+                       .name = L"charon IPsec policy",
                },
                .action = {
                        .type = FWP_ACTION_CALLOUT_TERMINATING,
-                       .calloutKey = inbound ? FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4 :
-                                                                       FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4,
                },
                .layerKey = inbound ? FWPM_LAYER_INBOUND_TRANSPORT_V4 :
                                                          FWPM_LAYER_OUTBOUND_TRANSPORT_V4,
        };
 
+       if (context)
+       {
+               if (inbound)
+               {
+                       filter.action.calloutKey = FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4;
+               }
+               else
+               {
+                       filter.action.calloutKey = FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4;
+               }
+               filter.flags |= FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT;
+               filter.providerKey = (GUID*)&this->provider.providerKey,
+               memcpy(&filter.providerContextKey, context, sizeof(GUID));
+       }
+       else
+       {
+               if (inbound)
+               {
+                       filter.action.calloutKey = FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4;
+               }
+               else
+               {
+                       filter.action.calloutKey = FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4;
+               }
+       }
+
        enumerator = array_create_enumerator(entry->sps);
        while (enumerator->enumerate(enumerator, &sp))
        {
@@ -609,7 +616,8 @@ static bool install_transport_sp(private_kernel_wfp_ipsec_t *this,
        free_conditions(conds, count);
        if (res != ERROR_SUCCESS)
        {
-               DBG1(DBG_KNL, "installing inbound FWP filter failed: 0x%08x", res);
+               DBG1(DBG_KNL, "installing %sbound FWP filter failed: 0x%08x",
+                        inbound ? "in" : "out", res);
                return FALSE;
        }
        return TRUE;
@@ -883,8 +891,8 @@ static bool install_sas(private_kernel_wfp_ipsec_t *this, entry_t *entry,
        }
        else
        {
-               traffic.tunnelPolicyId = entry->policy_in;
-               spi.inboundIpsecTraffic.tunnelPolicyId = entry->policy_in;
+               traffic.tunnelPolicyId = entry->provider;
+               spi.inboundIpsecTraffic.tunnelPolicyId = entry->provider;
        }
 
        if (!hosts2traffic(this, entry->local, entry->remote, &traffic))
@@ -963,8 +971,8 @@ static bool install_sas(private_kernel_wfp_ipsec_t *this, entry_t *entry,
  */
 static bool install_transport(private_kernel_wfp_ipsec_t *this, entry_t *entry)
 {
-       if (install_transport_sp(this, entry, TRUE) &&
-               install_transport_sp(this, entry, FALSE) &&
+       if (install_sp(this, entry, NULL, TRUE) &&
+               install_sp(this, entry, NULL, FALSE) &&
                install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TRANSPORT))
        {
                return TRUE;
@@ -996,10 +1004,6 @@ static bool generate_guid(private_kernel_wfp_ipsec_t *this, GUID *guid)
  */
 static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry)
 {
-       FWPM_FILTER_CONDITION0 *conds = NULL;
-       int count = 0;
-       enumerator_t *enumerator;
-       sp_entry_t *sp;
        DWORD res;
 
        IPSEC_AUTH_TRANSFORM0 transform = {
@@ -1031,7 +1035,7 @@ static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry)
                        .idleTimeoutSecondsFailOver = proposal.lifetime.lifetimeSeconds,
                },
        };
-       FWPM_PROVIDER_CONTEXT0 *ctx, qm = {
+       FWPM_PROVIDER_CONTEXT0 qm = {
                .displayData = {
                        .name = L"charon tunnel provider context",
                },
@@ -1065,38 +1069,18 @@ static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry)
                return FALSE;
        }
 
-       enumerator = array_create_enumerator(entry->sps);
-       while (enumerator->enumerate(enumerator, &sp))
-       {
-               if (!ts2condition(sp->src, TRUE, &conds, &count) ||
-                       !ts2condition(sp->dst, FALSE, &conds, &count))
-               {
-                       free_conditions(conds, count);
-                       enumerator->destroy(enumerator);
-                       return FALSE;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       res = FwpmIPsecTunnelAdd0(this->handle, 0, NULL, &qm, count, conds, NULL);
-       free_conditions(conds, count);
+       res = FwpmProviderContextAdd0(this->handle, &qm, NULL, &entry->provider);
        if (res != ERROR_SUCCESS)
        {
-               DBG1(DBG_KNL, "installing FWP tunnel policy failed: 0x%08x", res);
+               DBG1(DBG_KNL, "adding provider context failed: 0x%08x", res);
                return FALSE;
        }
 
-       /* to get the tunnelPolicyId LUID we have to query the context */
-       res = FwpmProviderContextGetByKey0(this->handle, &qm.providerContextKey,
-                                                                          &ctx);
-       if (res != ERROR_SUCCESS)
+       if (!install_sp(this, entry, &qm.providerContextKey, TRUE) ||
+               !install_sp(this, entry, &qm.providerContextKey, FALSE))
        {
-               DBG1(DBG_KNL, "getting FWP tunnel policy context failed: 0x%08x", res);
                return FALSE;
        }
-       entry->policy_in = ctx->providerContextId;
-       FwpmFreeMemory0((void**)&ctx);
-
        return TRUE;
 }