Export (0) Print
Expand All

Using Classify Options

The following code samples demonstrate how to use filter classify options in order to alter the filtering process.

Enable Loose Source Mapping for a Remote UDP Port


#include <windows.h>
#include <fwpmu.h>
#include <stdio.h>

#pragma comment(lib, "fwpuclnt.lib")
#pragma comment(lib, "rpcrt4.lib")

#define EXIT_ON_ERROR(fnName) \
   if (result != ERROR_SUCCESS) \
   { \
      printf(#fnName " = 0x%08X\n", result); \
      goto CLEANUP; \
   }

DWORD EnableLooseSourceMapping(
         __in HANDLE engine,
         __in PCWSTR provCtxtName,
         __in PCWSTR filterName,
         __in_opt const GUID* providerKey,
         __in_opt const GUID* subLayerKey,
         __in UINT16 port
         )
{
   DWORD result = ERROR_SUCCESS;
   FWPM_CLASSIFY_OPTION0 option;
   FWPM_CLASSIFY_OPTIONS0 options;
   FWPM_PROVIDER_CONTEXT0 provCtxt;
   FWPM_FILTER_CONDITION0 conds[2];
   FWPM_FILTER0 filter;
   BOOL txnInProgress = FALSE;

   //////////
   // Loose source mapping is controlled through classify options, so first
   // you add a provider context with the desired option value.
   //////////

   option.type = FWP_CLASSIFY_OPTION_LOOSE_SOURCE_MAPPING;
   option.value.type = FWP_UINT32;
   option.value.uint32 = FWP_OPTION_VALUE_ENABLE_LOOSE_SOURCE;

   options.numOptions = 1;
   options.options = &option;

   memset(&provCtxt, 0, sizeof(provCtxt));
   // You have to assign the key yourself since you'll need it when adding 
   // the filters that reference this provider context.
   result = UuidCreate(&(provCtxt.providerContextKey));
   EXIT_ON_ERROR(UuidCreate);
   // For MUI compatibility, object names should be indirect strings. See
   // SHLoadIndirectString for details.
   provCtxt.displayData.name = (PWSTR)provCtxtName;
   // Link all objects to your provider. When multiple providers are
   // installed on a computer, this makes it easy to determine who added what.
   provCtxt.providerKey = (GUID*)providerKey;
   provCtxt.type = FWPM_CLASSIFY_OPTIONS_CONTEXT;
   provCtxt.classifyOptions = &options;

   // Add all the objects from within a single transaction to make it easy
   // to clean up partial results in error paths.
   result = FwpmTransactionBegin0(engine, 0);
   EXIT_ON_ERROR(FwpmTransactionBegin0);
   txnInProgress = TRUE;

   result = FwpmProviderContextAdd0(engine, &provCtxt, NULL, NULL);
   EXIT_ON_ERROR(FwpmProviderContextAdd0);

   //////////
   // Next, add filters at the ALE_AUTH_CONNECT layers that reference the
   // provider context.
   //////////

   // First condition matches UDP traffic only.
   conds[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL;
   conds[0].matchType = FWP_MATCH_EQUAL;
   conds[0].conditionValue.type = FWP_UINT8;
   conds[0].conditionValue.uint16 = IPPROTO_UDP;

   // Second condition matches the remote port.
   conds[1].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
   conds[1].matchType = FWP_MATCH_EQUAL;
   conds[1].conditionValue.type = FWP_UINT16;
   conds[1].conditionValue.uint16 = port;

   // Fill in the common fields shared by all filters.
   memset(&filter, 0, sizeof(filter));
   filter.displayData.name = (PWSTR)filterName;
   // Filters can have either a raw context (which is a UINT64) or a
   // provider context. If using the latter, you have to set the
   // appropriate flag.
   filter.flags = FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT;
   filter.providerKey = (GUID*)providerKey;
   // Generally, it's best to add filters to your own sublayer, so you don't have
   // to worry about being overridden by filters added by another provider.
   if (subLayerKey != NULL)
   {
      filter.subLayerKey = *subLayerKey;
   }
   filter.numFilterConditions = 2;
   filter.filterCondition = conds;
   // The set options callouts never return permit or block, so they're
   // inspection callouts.
   filter.action.type = FWP_ACTION_CALLOUT_INSPECTION;
   // Link the filter to the provider context we just added. Note that multiple
   // filters can reference a single provider context, so once you've added a
   // provider context to enable LSM, you can use it over and over again.
   filter.providerContextKey = provCtxt.providerContextKey;

   // Add the IPv4 filter.
   filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
   filter.action.calloutKey = FWPM_CALLOUT_SET_OPTIONS_AUTH_CONNECT_LAYER_V4;
   result = FwpmFilterAdd0(engine, &filter, NULL, NULL);
   EXIT_ON_ERROR(FwpmFilterAdd0);

   // Add the IPv6 filter.
   filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
   filter.action.calloutKey = FWPM_CALLOUT_SET_OPTIONS_AUTH_CONNECT_LAYER_V6;
   result = FwpmFilterAdd0(engine, &filter, NULL, NULL);
   EXIT_ON_ERROR(FwpmFilterAdd0);

   // Once all the adds have succeeded, commit the transaction to atomically
   // add all the new objects.
   result = FwpmTransactionCommit0(engine);
   EXIT_ON_ERROR(FwpmTransactionCommit0);
   txnInProgress = FALSE;

CLEANUP:
   if (txnInProgress)
   {
      // Abort any transaction still in progress to clean up partial results.
      FwpmTransactionAbort0(engine);
   }
   return result;
}


Modify the Idle Lifetimes for ALE Flows


#include <windows.h>
#include <stdio.h>
#include <fwpmu.h>
#define INITGUID
#include <guiddef.h>

#pragma comment(lib, "fwpuclnt.lib")

// a4124528-12d6-4da5-a9ee-897a46966dfa
DEFINE_GUID(
   CONFIGURE_TIMEOUT_PROVIDER_CONTEXT,
   0xa4124528,
   0x12d6,
   0x4da5,
   0xa9, 0xee, 0x89, 0x7a, 0x46, 0x96, 0x6d, 0xfa
);

#define EXIT_ON_ERROR(fnName) \
   if (result != ERROR_SUCCESS) \
   { \
      printf(#fnName " = 0x%08X\n", result); \
      goto CLEANUP; \
   }

DWORD ConfigureALEFlowTimeouts(
        __in HANDLE engineHandle)
{
   DWORD result = ERROR_SUCCESS;
   FWPM_PROVIDER_CONTEXT0 configureTimeouts;
   FWPM_CLASSIFY_OPTIONS0 options;
   FWPM_CLASSIFY_OPTION0 option[2];
   FWPM_FILTER0 filter;
   FWPM_FILTER_CONDITION0 filterConditions[1];

   // Start Transaction.
   result = FwpmTransactionBegin0(engineHandle, 0);
   EXIT_ON_ERROR(FwpmTransactionBegin0);
   
   RtlZeroMemory(&option, sizeof(option));
   
   option[0].type = FWP_CLASSIFY_OPTION_MCAST_BCAST_LIFETIME;
   option[0].value.type = FWP_UINT32;
   option[0].value.uint32 = 10; // 10 seconds

   option[1].type = FWP_CLASSIFY_OPTION_UNICAST_LIFETIME;
   option[1].value.type = FWP_UINT32;
   option[1].value.uint32 = 90; // 1.5 minutes
   
   RtlZeroMemory(&options, sizeof(FWPM_CLASSIFY_OPTIONS0));
   options.numOptions = 2;
   options.options = option;
   
   RtlZeroMemory(&configureTimeouts, sizeof(FWPM_PROVIDER_CONTEXT0));
   
   configureTimeouts.providerContextKey = CONFIGURE_TIMEOUT_PROVIDER_CONTEXT;
   configureTimeouts.type = FWPM_CLASSIFY_OPTIONS_CONTEXT;
   configureTimeouts.displayData.name = L"Classify Options";
   configureTimeouts.displayData.description = L"Sets options ALE connect layers";
   configureTimeouts.classifyOptions = &options;

   // Add Provider Context for V4 connections.
   result = FwpmProviderContextAdd0(engineHandle, &configureTimeouts, NULL, NULL);
   EXIT_ON_ERROR(FwpmProviderContextAdd0);
   
   RtlZeroMemory(&filter, sizeof(FWPM_FILTER0));

   filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
   filter.displayData.name = L"Implement Configure Timeouts for V4";
   filter.displayData.description = L"Sets up flow for traffic that we are interested in.";
   filter.action.type = FWP_ACTION_CALLOUT_INSPECTION;
   filter.action.calloutKey = FWPM_CALLOUT_SET_OPTIONS_AUTH_CONNECT_LAYER_V4;
   filter.subLayerKey = FWPM_SUBLAYER_INSPECTION;
   filter.weight.type = FWP_EMPTY; // auto-weight
   filter.flags = FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT;

   filter.providerContextKey = CONFIGURE_TIMEOUT_PROVIDER_CONTEXT;
   filter.filterCondition = filterConditions;
   filter.numFilterConditions = 1;

   RtlZeroMemory(filterConditions, sizeof(filterConditions));

   // Enable filter for UDP traffic.
   filterConditions[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL;
   filterConditions[0].matchType = FWP_MATCH_EQUAL;
   filterConditions[0].conditionValue.type = FWP_UINT8;
   filterConditions[0].conditionValue.uint8 = IPPROTO_UDP;

   // Add Connect V4 Configure Timeouts filter.
   result = FwpmFilterAdd0(engineHandle, &filter, NULL, NULL);
   EXIT_ON_ERROR(FwpmFilterAdd0);

   // Commit transaction.
   result = FwpmTransactionCommit0(engineHandle);
   if (ERROR_SUCCESS == result)
   {
      printf("Successfully Committed Transaction\n");
   }
   goto CLEANUP;

CLEANUP:
   return result;
}


DWORD wmain(int argc,
            wchar_t* argv[])
{
   UNREFERENCED_PARAMETER(argc);
   UNREFERENCED_PARAMETER(argv);
   
   HANDLE engineHandle = 0;

   // Use dynamic sessions for efficiency and safety:
   //  - All objects associated with the dynamic session are deleted with one call.
   //  - Filtering policy objects are deleted even when the application crashes. 
   FWPM_SESSION0 session;
   memset(&session, 0, sizeof(session));
   session.flags = FWPM_SESSION_FLAG_DYNAMIC;

   DWORD result = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &engineHandle);
   if (ERROR_SUCCESS == result)
   {
        result = ConfigureALEFlowTimeouts(engineHandle);
   }

   if (result != ERROR_SUCCESS)
   {

       printf("Error: %x\n", result);
   }

   return result;
}


Related topics

Filtering Conditions Available at Each Filtering Layer

 

 

Community Additions

ADD
Show:
© 2014 Microsoft