summaryrefslogtreecommitdiff
path: root/network/trans/inspect
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /network/trans/inspect
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'network/trans/inspect')
-rw-r--r--network/trans/inspect/ReadMe.md55
-rw-r--r--network/trans/inspect/inspect.sln28
-rw-r--r--network/trans/inspect/sys/TL_drv.c927
-rw-r--r--network/trans/inspect/sys/inspect.c1418
-rw-r--r--network/trans/inspect/sys/inspect.h214
-rw-r--r--network/trans/inspect/sys/inspect.inf63
-rw-r--r--network/trans/inspect/sys/inspect.vcxproj186
-rw-r--r--network/trans/inspect/sys/inspect.vcxproj.Filters32
-rw-r--r--network/trans/inspect/sys/utils.c448
-rw-r--r--network/trans/inspect/sys/utils.h298
10 files changed, 3669 insertions, 0 deletions
diff --git a/network/trans/inspect/ReadMe.md b/network/trans/inspect/ReadMe.md
new file mode 100644
index 00000000..a288e694
--- /dev/null
+++ b/network/trans/inspect/ReadMe.md
@@ -0,0 +1,55 @@
+Windows Filtering Platform Traffic Inspection Sample
+====================================================
+
+This sample driver demonstrates the traffic inspection capabilities of the Windows Filtering Platform (WFP).
+
+The sample driver consists of a kernel-mode Windows Filtering Platform (WFP) callout driver (Inspect.sys) that intercepts all transport layer traffic (for example, Transmission Control Protocol (TCP), User Datagram Protocol (UDP), and nonerror Internet Control Message Protocol (ICMP)) sent to or received from a configurable remote peer and queues then to a worker thread for out-of-band processing.
+
+Inspect.sys inspects inbound and outbound connections and all packets that belong to those connections. Additionally, Inspect.sys demonstrates the special considerations that are required to be compatible with Internet Protocol security (IPsec) in Windows Vista and Windows Server 2008.
+
+Inspect.sys implements the `ClassifyFn` callout functions for the ALE Connect, Recv-Accept, and Transport callouts. In addition, the system worker thread that performs the actual packet inspection is also implemented along with the event mechanisms that are shared between the Classify function and the worker thread.
+
+Connect/Packet inspection is done out-of-band by a system worker thread by using the reference-drop-clone-reinject mechanism as well as the ALE pend/complete mechanism. Therefore, the sample can serve as a basis for scenarios in which a filtering decision cannot be made within the `classifyFn()` callout and instead must be made, for example, by a user-mode application.
+
+## Universal Compliant
+This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core.
+
+Automatic deployment
+--------------------
+
+Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). After you have provisioned the target computer, continue with these steps:
+
+1. On the host computer, in Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**.
+2. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Do not install**. Click **OK**.
+3. On the **Build** menu, choose **Build Solution**.
+4. On the target computer, navigate to DriverTest\\Drivers, and locate the file inspect.inf. Right click inspect.inf, and choose **Install**.
+
+Manual deployment
+-----------------
+
+Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571). After you have prepared the target computer for manual deployment, continue with these steps:
+
+1. Copy all of the files in your driver package to a folder on the target computer (for example, c:\\WfpTrafficInspectionSamplePackage).
+2. On the target computer, navigate to your driver package folder. Right click inspect.inf, and choose **Install**
+
+Create Registry values
+----------------------
+
+1. On the target computer, open Regedit, and navigate to this key:
+
+ **HKLM**\\**System**\\**CurrentControlSet**\\**Services**\\**inspect**\\**Parameters**
+
+2. Create a REG\_DWORD entry named **BlockTraffic** and set it's value to 0 for permit or 1 to block.
+
+3. Create a REG\_SZ entry named **RemoteAddressToInspect**, and set it's value to an IPV4 or IPV6 address (example: 10.0.0.2).
+
+Start the inspect service
+-------------------------
+
+On the target computer, open a Command Prompt window as Administrator, and enter **net start inspect**. (To stop the driver, enter **net stop inspect**.)
+
+Remarks
+-------
+
+For more information on creating a Windows Filtering Platform Callout Driver, see [Windows Filtering Platform Callout Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff571068).
+
diff --git a/network/trans/inspect/inspect.sln b/network/trans/inspect/inspect.sln
new file mode 100644
index 00000000..79901c54
--- /dev/null
+++ b/network/trans/inspect/inspect.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inspect", "sys\inspect.vcxproj", "{43AC1739-03F1-4465-8A16-F5FCD06BC2E9}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Debug|Win32.Build.0 = Debug|Win32
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Release|Win32.ActiveCfg = Release|Win32
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Release|Win32.Build.0 = Release|Win32
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Debug|x64.ActiveCfg = Debug|x64
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Debug|x64.Build.0 = Debug|x64
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Release|x64.ActiveCfg = Release|x64
+ {43AC1739-03F1-4465-8A16-F5FCD06BC2E9}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/network/trans/inspect/sys/TL_drv.c b/network/trans/inspect/sys/TL_drv.c
new file mode 100644
index 00000000..5186b69c
--- /dev/null
+++ b/network/trans/inspect/sys/TL_drv.c
@@ -0,0 +1,927 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Transport Inspect Proxy Callout Driver Sample.
+
+ This sample callout driver intercepts all transport layer traffic (e.g.
+ TCP, UDP, and non-error ICMP) sent to or receive from a (configurable)
+ remote peer and queue them to a worker thread for out-of-band processing.
+ The sample performs inspection of inbound and outbound connections as
+ well as all packets belong to those connections. In addition the sample
+ demonstrates special considerations required to be compatible with Windows
+ Vista and Windows Server 2008�s IpSec implementation.
+
+ Inspection parameters are configurable via the following registry
+ values --
+
+ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Inspect\Parameters
+
+ o BlockTraffic (REG_DWORD) : 0 (permit, default); 1 (block)
+ o RemoteAddressToInspect (REG_SZ) : literal IPv4/IPv6 string
+ (e.g. �10.0.0.1�)
+ The sample is IP version agnostic. It performs inspection for
+ both IPv4 and IPv6 traffic.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ntddk.h>
+#include <wdf.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include <fwpmk.h>
+
+#include <ws2ipdef.h>
+#include <in6addr.h>
+#include <ip2string.h>
+
+#include "inspect.h"
+
+#define INITGUID
+#include <guiddef.h>
+
+
+//
+// Configurable parameters (addresses and ports are in host order)
+//
+
+BOOLEAN configPermitTraffic = TRUE;
+
+UINT8* configInspectRemoteAddrV4 = NULL;
+UINT8* configInspectRemoteAddrV6 = NULL;
+
+IN_ADDR remoteAddrStorageV4;
+IN6_ADDR remoteAddrStorageV6;
+
+//
+// Callout and sublayer GUIDs
+//
+
+// bb6e405b-19f4-4ff3-b501-1a3dc01aae01
+DEFINE_GUID(
+ TL_INSPECT_OUTBOUND_TRANSPORT_CALLOUT_V4,
+ 0xbb6e405b,
+ 0x19f4,
+ 0x4ff3,
+ 0xb5, 0x01, 0x1a, 0x3d, 0xc0, 0x1a, 0xae, 0x01
+);
+// cabf7559-7c60-46c8-9d3b-2155ad5cf83f
+DEFINE_GUID(
+ TL_INSPECT_OUTBOUND_TRANSPORT_CALLOUT_V6,
+ 0xcabf7559,
+ 0x7c60,
+ 0x46c8,
+ 0x9d, 0x3b, 0x21, 0x55, 0xad, 0x5c, 0xf8, 0x3f
+);
+// 07248379-248b-4e49-bf07-24d99d52f8d0
+DEFINE_GUID(
+ TL_INSPECT_INBOUND_TRANSPORT_CALLOUT_V4,
+ 0x07248379,
+ 0x248b,
+ 0x4e49,
+ 0xbf, 0x07, 0x24, 0xd9, 0x9d, 0x52, 0xf8, 0xd0
+);
+// 6d126434-ed67-4285-925c-cb29282e0e06
+DEFINE_GUID(
+ TL_INSPECT_INBOUND_TRANSPORT_CALLOUT_V6,
+ 0x6d126434,
+ 0xed67,
+ 0x4285,
+ 0x92, 0x5c, 0xcb, 0x29, 0x28, 0x2e, 0x0e, 0x06
+);
+// 76b743d4-1249-4614-a632-6f9c4d08d25a
+DEFINE_GUID(
+ TL_INSPECT_ALE_CONNECT_CALLOUT_V4,
+ 0x76b743d4,
+ 0x1249,
+ 0x4614,
+ 0xa6, 0x32, 0x6f, 0x9c, 0x4d, 0x08, 0xd2, 0x5a
+);
+
+// ac80683a-5b84-43c3-8ae9-eddb5c0d23c2
+DEFINE_GUID(
+ TL_INSPECT_ALE_CONNECT_CALLOUT_V6,
+ 0xac80683a,
+ 0x5b84,
+ 0x43c3,
+ 0x8a, 0xe9, 0xed, 0xdb, 0x5c, 0x0d, 0x23, 0xc2
+);
+
+// 7ec7f7f5-0c55-4121-adc5-5d07d2ac0cef
+DEFINE_GUID(
+ TL_INSPECT_ALE_RECV_ACCEPT_CALLOUT_V4,
+ 0x7ec7f7f5,
+ 0x0c55,
+ 0x4121,
+ 0xad, 0xc5, 0x5d, 0x07, 0xd2, 0xac, 0x0c, 0xef
+);
+
+// b74ac2ed-4e71-4564-9975-787d5168a151
+DEFINE_GUID(
+ TL_INSPECT_ALE_RECV_ACCEPT_CALLOUT_V6,
+ 0xb74ac2ed,
+ 0x4e71,
+ 0x4564,
+ 0x99, 0x75, 0x78, 0x7d, 0x51, 0x68, 0xa1, 0x51
+);
+
+// 2e207682-d95f-4525-b966-969f26587f03
+DEFINE_GUID(
+ TL_INSPECT_SUBLAYER,
+ 0x2e207682,
+ 0xd95f,
+ 0x4525,
+ 0xb9, 0x66, 0x96, 0x9f, 0x26, 0x58, 0x7f, 0x03
+);
+
+//
+// Callout driver global variables
+//
+
+DEVICE_OBJECT* gWdmDevice;
+WDFKEY gParametersKey;
+
+HANDLE gEngineHandle;
+UINT32 gAleConnectCalloutIdV4, gOutboundTlCalloutIdV4;
+UINT32 gAleRecvAcceptCalloutIdV4, gInboundTlCalloutIdV4;
+UINT32 gAleConnectCalloutIdV6, gOutboundTlCalloutIdV6;
+UINT32 gAleRecvAcceptCalloutIdV6, gInboundTlCalloutIdV6;
+
+HANDLE gInjectionHandle;
+
+LIST_ENTRY gConnList;
+KSPIN_LOCK gConnListLock;
+LIST_ENTRY gPacketQueue;
+KSPIN_LOCK gPacketQueueLock;
+
+KEVENT gWorkerEvent;
+
+BOOLEAN gDriverUnloading = FALSE;
+void* gThreadObj;
+
+//
+// Callout driver implementation
+//
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_UNLOAD TLInspectEvtDriverUnload;
+
+NTSTATUS
+TLInspectLoadConfig(
+ _In_ const WDFKEY key
+ )
+{
+ NTSTATUS status;
+ DECLARE_CONST_UNICODE_STRING(valueName, L"RemoteAddressToInspect");
+ DECLARE_UNICODE_STRING_SIZE(value, INET6_ADDRSTRLEN);
+
+ status = WdfRegistryQueryUnicodeString(key, &valueName, NULL, &value);
+
+ if (NT_SUCCESS(status))
+ {
+ PWSTR terminator;
+ // Defensively null-terminate the string
+ value.Length = min(value.Length, value.MaximumLength - sizeof(WCHAR));
+ value.Buffer[value.Length/sizeof(WCHAR)] = UNICODE_NULL;
+
+ status = RtlIpv4StringToAddressW(
+ value.Buffer,
+ TRUE,
+ &terminator,
+ &remoteAddrStorageV4
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ remoteAddrStorageV4.S_un.S_addr =
+ RtlUlongByteSwap(remoteAddrStorageV4.S_un.S_addr);
+ configInspectRemoteAddrV4 = &remoteAddrStorageV4.S_un.S_un_b.s_b1;
+ }
+ else
+ {
+ status = RtlIpv6StringToAddressW(
+ value.Buffer,
+ &terminator,
+ &remoteAddrStorageV6
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ configInspectRemoteAddrV6 = (UINT8*)(&remoteAddrStorageV6.u.Byte[0]);
+ }
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+TLInspectAddFilter(
+ _In_ const wchar_t* filterName,
+ _In_ const wchar_t* filterDesc,
+ _In_reads_opt_(16) const UINT8* remoteAddr,
+ _In_ UINT64 context,
+ _In_ const GUID* layerKey,
+ _In_ const GUID* calloutKey
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPM_FILTER filter = {0};
+ FWPM_FILTER_CONDITION filterConditions[3] = {0};
+ UINT conditionIndex;
+
+ filter.layerKey = *layerKey;
+ filter.displayData.name = (wchar_t*)filterName;
+ filter.displayData.description = (wchar_t*)filterDesc;
+
+ filter.action.type = FWP_ACTION_CALLOUT_TERMINATING;
+ filter.action.calloutKey = *calloutKey;
+ filter.filterCondition = filterConditions;
+ filter.subLayerKey = TL_INSPECT_SUBLAYER;
+ filter.weight.type = FWP_EMPTY; // auto-weight.
+ filter.rawContext = context;
+
+ conditionIndex = 0;
+
+ if (remoteAddr != NULL)
+ {
+ filterConditions[conditionIndex].fieldKey =
+ FWPM_CONDITION_IP_REMOTE_ADDRESS;
+ filterConditions[conditionIndex].matchType = FWP_MATCH_EQUAL;
+
+ if (IsEqualGUID(layerKey, &FWPM_LAYER_ALE_AUTH_CONNECT_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_INBOUND_TRANSPORT_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4))
+ {
+ filterConditions[conditionIndex].conditionValue.type = FWP_UINT32;
+ filterConditions[conditionIndex].conditionValue.uint32 =
+ *(UINT32*)remoteAddr;
+ }
+ else
+ {
+ filterConditions[conditionIndex].conditionValue.type =
+ FWP_BYTE_ARRAY16_TYPE;
+ filterConditions[conditionIndex].conditionValue.byteArray16 =
+ (FWP_BYTE_ARRAY16*)remoteAddr;
+ }
+
+ conditionIndex++;
+ }
+
+ filter.numFilterConditions = conditionIndex;
+
+ status = FwpmFilterAdd(
+ gEngineHandle,
+ &filter,
+ NULL,
+ NULL);
+
+ return status;
+}
+
+NTSTATUS
+TLInspectRegisterALEClassifyCallouts(
+ _In_ const GUID* layerKey,
+ _In_ const GUID* calloutKey,
+ _Inout_ void* deviceObject,
+ _Out_ UINT32* calloutId
+ )
+/* ++
+
+ This function registers callouts and filters at the following layers
+ to intercept inbound or outbound connect attempts.
+
+ FWPM_LAYER_ALE_AUTH_CONNECT_V4
+ FWPM_LAYER_ALE_AUTH_CONNECT_V6
+ FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4
+ FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPS_CALLOUT sCallout = {0};
+ FWPM_CALLOUT mCallout = {0};
+
+ FWPM_DISPLAY_DATA displayData = {0};
+
+ BOOLEAN calloutRegistered = FALSE;
+
+ sCallout.calloutKey = *calloutKey;
+
+ if (IsEqualGUID(layerKey, &FWPM_LAYER_ALE_AUTH_CONNECT_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_ALE_AUTH_CONNECT_V6))
+ {
+ sCallout.classifyFn = TLInspectALEConnectClassify;
+ sCallout.notifyFn = TLInspectALEConnectNotify;
+ }
+ else
+ {
+ sCallout.classifyFn = TLInspectALERecvAcceptClassify;
+ sCallout.notifyFn = TLInspectALERecvAcceptNotify;
+ }
+
+ status = FwpsCalloutRegister(
+ deviceObject,
+ &sCallout,
+ calloutId
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ calloutRegistered = TRUE;
+
+ displayData.name = L"Transport Inspect ALE Classify Callout";
+ displayData.description =
+ L"Intercepts inbound or outbound connect attempts";
+
+ mCallout.calloutKey = *calloutKey;
+ mCallout.displayData = displayData;
+ mCallout.applicableLayer = *layerKey;
+
+ status = FwpmCalloutAdd(
+ gEngineHandle,
+ &mCallout,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectAddFilter(
+ L"Transport Inspect ALE Classify",
+ L"Intercepts inbound or outbound connect attempts",
+ (IsEqualGUID(layerKey, &FWPM_LAYER_ALE_AUTH_CONNECT_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4)) ?
+ configInspectRemoteAddrV4 : configInspectRemoteAddrV6,
+ 0,
+ layerKey,
+ calloutKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (calloutRegistered)
+ {
+ FwpsCalloutUnregisterById(*calloutId);
+ *calloutId = 0;
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+TLInspectRegisterTransportCallouts(
+ _In_ const GUID* layerKey,
+ _In_ const GUID* calloutKey,
+ _Inout_ void* deviceObject,
+ _Out_ UINT32* calloutId
+ )
+/* ++
+
+ This function registers callouts and filters that intercept transport
+ traffic at the following layers --
+
+ FWPM_LAYER_OUTBOUND_TRANSPORT_V4
+ FWPM_LAYER_OUTBOUND_TRANSPORT_V6
+ FWPM_LAYER_INBOUND_TRANSPORT_V4
+ FWPM_LAYER_INBOUND_TRANSPORT_V6
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPS_CALLOUT sCallout = {0};
+ FWPM_CALLOUT mCallout = {0};
+
+ FWPM_DISPLAY_DATA displayData = {0};
+
+ BOOLEAN calloutRegistered = FALSE;
+
+ sCallout.calloutKey = *calloutKey;
+ sCallout.classifyFn = TLInspectTransportClassify;
+ sCallout.notifyFn = TLInspectTransportNotify;
+
+ status = FwpsCalloutRegister(
+ deviceObject,
+ &sCallout,
+ calloutId
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ calloutRegistered = TRUE;
+
+ displayData.name = L"Transport Inspect Callout";
+ displayData.description = L"Inspect inbound/outbound transport traffic";
+
+ mCallout.calloutKey = *calloutKey;
+ mCallout.displayData = displayData;
+ mCallout.applicableLayer = *layerKey;
+
+ status = FwpmCalloutAdd(
+ gEngineHandle,
+ &mCallout,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectAddFilter(
+ L"Transport Inspect Filter (Outbound)",
+ L"Inspect inbound/outbound transport traffic",
+ (IsEqualGUID(layerKey, &FWPM_LAYER_OUTBOUND_TRANSPORT_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_INBOUND_TRANSPORT_V4))?
+ configInspectRemoteAddrV4 : configInspectRemoteAddrV6,
+ 0,
+ layerKey,
+ calloutKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (calloutRegistered)
+ {
+ FwpsCalloutUnregisterById(*calloutId);
+ *calloutId = 0;
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+TLInspectRegisterCallouts(
+ _Inout_ void* deviceObject
+ )
+/* ++
+
+ This function registers dynamic callouts and filters that intercept
+ transport traffic at ALE AUTH_CONNECT/AUTH_RECV_ACCEPT and
+ INBOUND/OUTBOUND transport layers.
+
+ Callouts and filters will be removed during DriverUnload.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ FWPM_SUBLAYER TLInspectSubLayer;
+
+ BOOLEAN engineOpened = FALSE;
+ BOOLEAN inTransaction = FALSE;
+
+ FWPM_SESSION session = {0};
+
+ session.flags = FWPM_SESSION_FLAG_DYNAMIC;
+
+ status = FwpmEngineOpen(
+ NULL,
+ RPC_C_AUTHN_WINNT,
+ NULL,
+ &session,
+ &gEngineHandle
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ engineOpened = TRUE;
+
+ status = FwpmTransactionBegin(gEngineHandle, 0);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ inTransaction = TRUE;
+
+ RtlZeroMemory(&TLInspectSubLayer, sizeof(FWPM_SUBLAYER));
+
+ TLInspectSubLayer.subLayerKey = TL_INSPECT_SUBLAYER;
+ TLInspectSubLayer.displayData.name = L"Transport Inspect Sub-Layer";
+ TLInspectSubLayer.displayData.description =
+ L"Sub-Layer for use by Transport Inspect callouts";
+ TLInspectSubLayer.flags = 0;
+ TLInspectSubLayer.weight = 0; // must be less than the weight of
+ // FWPM_SUBLAYER_UNIVERSAL to be
+ // compatible with Vista's IpSec
+ // implementation.
+
+ status = FwpmSubLayerAdd(gEngineHandle, &TLInspectSubLayer, NULL);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ if (configInspectRemoteAddrV4 != NULL)
+ {
+ status = TLInspectRegisterALEClassifyCallouts(
+ &FWPM_LAYER_ALE_AUTH_CONNECT_V4,
+ &TL_INSPECT_ALE_CONNECT_CALLOUT_V4,
+ deviceObject,
+ &gAleConnectCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectRegisterALEClassifyCallouts(
+ &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4,
+ &TL_INSPECT_ALE_RECV_ACCEPT_CALLOUT_V4,
+ deviceObject,
+ &gAleRecvAcceptCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectRegisterTransportCallouts(
+ &FWPM_LAYER_OUTBOUND_TRANSPORT_V4,
+ &TL_INSPECT_OUTBOUND_TRANSPORT_CALLOUT_V4,
+ deviceObject,
+ &gOutboundTlCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectRegisterTransportCallouts(
+ &FWPM_LAYER_INBOUND_TRANSPORT_V4,
+ &TL_INSPECT_INBOUND_TRANSPORT_CALLOUT_V4,
+ deviceObject,
+ &gInboundTlCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+ if (configInspectRemoteAddrV6 != NULL)
+ {
+ status = TLInspectRegisterALEClassifyCallouts(
+ &FWPM_LAYER_ALE_AUTH_CONNECT_V6,
+ &TL_INSPECT_ALE_CONNECT_CALLOUT_V6,
+ deviceObject,
+ &gAleConnectCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectRegisterALEClassifyCallouts(
+ &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6,
+ &TL_INSPECT_ALE_RECV_ACCEPT_CALLOUT_V6,
+ deviceObject,
+ &gAleRecvAcceptCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectRegisterTransportCallouts(
+ &FWPM_LAYER_OUTBOUND_TRANSPORT_V6,
+ &TL_INSPECT_OUTBOUND_TRANSPORT_CALLOUT_V6,
+ deviceObject,
+ &gOutboundTlCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectRegisterTransportCallouts(
+ &FWPM_LAYER_INBOUND_TRANSPORT_V6,
+ &TL_INSPECT_INBOUND_TRANSPORT_CALLOUT_V6,
+ deviceObject,
+ &gInboundTlCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+ status = FwpmTransactionCommit(gEngineHandle);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ inTransaction = FALSE;
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (inTransaction)
+ {
+ FwpmTransactionAbort(gEngineHandle);
+ _Analysis_assume_lock_not_held_(gEngineHandle); // Potential leak if "FwpmTransactionAbort" fails
+ }
+ if (engineOpened)
+ {
+ FwpmEngineClose(gEngineHandle);
+ gEngineHandle = NULL;
+ }
+ }
+
+ return status;
+}
+
+void
+TLInspectUnregisterCallouts(void)
+{
+ FwpmEngineClose(gEngineHandle);
+ gEngineHandle = NULL;
+
+ FwpsCalloutUnregisterById(gOutboundTlCalloutIdV6);
+ FwpsCalloutUnregisterById(gOutboundTlCalloutIdV4);
+ FwpsCalloutUnregisterById(gInboundTlCalloutIdV6);
+ FwpsCalloutUnregisterById(gInboundTlCalloutIdV4);
+
+ FwpsCalloutUnregisterById(gAleConnectCalloutIdV6);
+ FwpsCalloutUnregisterById(gAleConnectCalloutIdV4);
+ FwpsCalloutUnregisterById(gAleRecvAcceptCalloutIdV6);
+ FwpsCalloutUnregisterById(gAleRecvAcceptCalloutIdV4);
+}
+
+_Function_class_(EVT_WDF_DRIVER_UNLOAD)
+_IRQL_requires_same_
+_IRQL_requires_max_(PASSIVE_LEVEL)
+void
+TLInspectEvtDriverUnload(
+ _In_ WDFDRIVER driverObject
+ )
+{
+
+ KLOCK_QUEUE_HANDLE connListLockHandle;
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+
+ UNREFERENCED_PARAMETER(driverObject);
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ gDriverUnloading = TRUE;
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (IsListEmpty(&gConnList) && IsListEmpty(&gPacketQueue))
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ IO_NO_INCREMENT,
+ FALSE
+ );
+ }
+
+ NT_ASSERT(gThreadObj != NULL);
+
+ KeWaitForSingleObject(
+ gThreadObj,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ ObDereferenceObject(gThreadObj);
+
+ TLInspectUnregisterCallouts();
+
+ FwpsInjectionHandleDestroy(gInjectionHandle);
+}
+
+NTSTATUS
+TLInspectInitDriverObjects(
+ _Inout_ DRIVER_OBJECT* driverObject,
+ _In_ const UNICODE_STRING* registryPath,
+ _Out_ WDFDRIVER* pDriver,
+ _Out_ WDFDEVICE* pDevice
+ )
+{
+ NTSTATUS status;
+ WDF_DRIVER_CONFIG config;
+ PWDFDEVICE_INIT pInit = NULL;
+
+ WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
+
+ config.DriverInitFlags |= WdfDriverInitNonPnpDriver;
+ config.EvtDriverUnload = TLInspectEvtDriverUnload;
+
+ status = WdfDriverCreate(
+ driverObject,
+ registryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config,
+ pDriver
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ pInit = WdfControlDeviceInitAllocate(*pDriver, &SDDL_DEVOBJ_KERNEL_ONLY);
+
+ if (!pInit)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ WdfDeviceInitSetDeviceType(pInit, FILE_DEVICE_NETWORK);
+ WdfDeviceInitSetCharacteristics(pInit, FILE_DEVICE_SECURE_OPEN, FALSE);
+ WdfDeviceInitSetCharacteristics(pInit, FILE_AUTOGENERATED_DEVICE_NAME, TRUE);
+
+ status = WdfDeviceCreate(&pInit, WDF_NO_OBJECT_ATTRIBUTES, pDevice);
+ if (!NT_SUCCESS(status))
+ {
+ WdfDeviceInitFree(pInit);
+ goto Exit;
+ }
+
+ WdfControlFinishInitializing(*pDevice);
+
+Exit:
+ return status;
+}
+
+NTSTATUS
+DriverEntry(
+ DRIVER_OBJECT* driverObject,
+ UNICODE_STRING* registryPath
+ )
+{
+ NTSTATUS status;
+ WDFDRIVER driver;
+ WDFDEVICE device;
+ HANDLE threadHandle;
+
+ // Request NX Non-Paged Pool when available
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+
+ status = TLInspectInitDriverObjects(
+ driverObject,
+ registryPath,
+ &driver,
+ &device
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = WdfDriverOpenParametersRegistryKey(
+ driver,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &gParametersKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = TLInspectLoadConfig(gParametersKey);
+
+ if (!NT_SUCCESS(status))
+ {
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ goto Exit;
+ }
+
+ if ((configInspectRemoteAddrV4 == NULL) &&
+ (configInspectRemoteAddrV6 == NULL))
+ {
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ goto Exit;
+ }
+
+ status = FwpsInjectionHandleCreate(
+ AF_UNSPEC,
+ FWPS_INJECTION_TYPE_TRANSPORT,
+ &gInjectionHandle
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ InitializeListHead(&gConnList);
+ KeInitializeSpinLock(&gConnListLock);
+
+ InitializeListHead(&gPacketQueue);
+ KeInitializeSpinLock(&gPacketQueueLock);
+
+ KeInitializeEvent(
+ &gWorkerEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ gWdmDevice = WdfDeviceWdmGetDeviceObject(device);
+
+ status = TLInspectRegisterCallouts(gWdmDevice);
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = PsCreateSystemThread(
+ &threadHandle,
+ THREAD_ALL_ACCESS,
+ NULL,
+ NULL,
+ NULL,
+ TLInspectWorker,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = ObReferenceObjectByHandle(
+ threadHandle,
+ 0,
+ NULL,
+ KernelMode,
+ &gThreadObj,
+ NULL
+ );
+ NT_ASSERT(NT_SUCCESS(status));
+
+ ZwClose(threadHandle);
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (gEngineHandle != NULL)
+ {
+ TLInspectUnregisterCallouts();
+ }
+ if (gInjectionHandle != NULL)
+ {
+ FwpsInjectionHandleDestroy(gInjectionHandle);
+ }
+ }
+
+ return status;
+};
+
diff --git a/network/trans/inspect/sys/inspect.c b/network/trans/inspect/sys/inspect.c
new file mode 100644
index 00000000..26b01e9b
--- /dev/null
+++ b/network/trans/inspect/sys/inspect.c
@@ -0,0 +1,1418 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ This file implements the classifyFn callout functions for the ALE connect,
+ recv-accept, and transport callouts. In addition the system worker thread
+ that performs the actual packet inspection is also implemented here along
+ with the eventing mechanisms shared between the classify function and the
+ worker thread.
+
+ connect/Packet inspection is done out-of-band by a system worker thread
+ using the reference-drop-clone-reinject as well as ALE pend/complete
+ mechanism. Therefore the sample can serve as a base in scenarios where
+ filtering decision cannot be made within the classifyFn() callout and
+ instead must be made, for example, by an user-mode application.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+
+#include <ntddk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include <fwpmk.h>
+
+#include "inspect.h"
+#include "utils.h"
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+TLInspectALEConnectClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#else
+
+void
+TLInspectALEConnectClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+/* ++
+
+ This is the classifyFn function for the ALE connect (v4 and v6) callout.
+ For an initial classify (where the FWP_CONDITION_FLAG_IS_REAUTHORIZE flag
+ is not set), it is queued to the connection list for inspection by the
+ worker thread. For re-auth, we first check if it is triggered by an ealier
+ FwpsCompleteOperation call by looking for an pended connect that has been
+ inspected. If found, we remove it from the connect list and return the
+ inspection result; otherwise we can conclude that the re-auth is triggered
+ by policy change so we queue it to the packet queue to be process by the
+ worker thread like any other regular packets.
+
+-- */
+{
+ NTSTATUS status;
+
+ KLOCK_QUEUE_HANDLE connListLockHandle;
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+
+ TL_INSPECT_PENDED_PACKET* pendedConnect = NULL;
+ TL_INSPECT_PENDED_PACKET* connEntry;
+ TL_INSPECT_PENDED_PACKET* pendedPacket = NULL;
+
+ ADDRESS_FAMILY addressFamily;
+ FWPS_PACKET_INJECTION_STATE packetState;
+ BOOLEAN signalWorkerThread;
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(filter);
+ UNREFERENCED_PARAMETER(flowContext);
+
+ //
+ // We don't have the necessary right to alter the classify, exit.
+ //
+ if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
+ {
+ goto Exit;
+ }
+
+ if (layerData != NULL)
+ {
+ //
+ // We don't re-inspect packets that we've inspected earlier.
+ //
+ packetState = FwpsQueryPacketInjectionState(
+ gInjectionHandle,
+ layerData,
+ NULL
+ );
+
+ if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
+ (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
+ {
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+ }
+
+ addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId);
+
+ if (!IsAleReauthorize(inFixedValues))
+ {
+ //
+ // If the classify is the initial authorization for a connection, we
+ // queue it to the pended connection list and notify the worker thread
+ // for out-of-band processing.
+ //
+ pendedConnect = AllocateAndInitializePendedPacket(
+ inFixedValues,
+ inMetaValues,
+ addressFamily,
+ layerData,
+ TL_INSPECT_CONNECT_PACKET,
+ FWP_DIRECTION_OUTBOUND
+ );
+
+ if (pendedConnect == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_COMPLETION_HANDLE));
+
+ //
+ // Pend the ALE_AUTH_CONNECT classify.
+ //
+ status = FwpsPendOperation(
+ inMetaValues->completionHandle,
+ &pendedConnect->completionContext
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ signalWorkerThread = IsListEmpty(&gConnList) &&
+ IsListEmpty(&gPacketQueue);
+
+ InsertTailList(&gConnList, &pendedConnect->listEntry);
+ pendedConnect = NULL; // ownership transferred
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ 0,
+ FALSE
+ );
+ }
+ }
+ else // re-auth @ ALE_AUTH_CONNECT
+ {
+ FWP_DIRECTION packetDirection;
+ //
+ // The classify is the re-authorization for an existing connection, it
+ // could have been triggered for one of the three cases --
+ //
+ // 1) The re-auth is triggered by a FwpsCompleteOperation call to
+ // complete a ALE_AUTH_CONNECT classify pended earlier.
+ // 2) The re-auth is triggered by an outbound packet sent immediately
+ // after a policy change at ALE_AUTH_CONNECT layer.
+ // 3) The re-auth is triggered by an inbound packet received
+ // immediately after a policy change at ALE_AUTH_CONNECT layer.
+ //
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_PACKET_DIRECTION));
+ packetDirection = inMetaValues->packetDirection;
+
+ if (packetDirection == FWP_DIRECTION_OUTBOUND)
+ {
+ LIST_ENTRY* listEntry;
+ BOOLEAN authComplete = FALSE;
+
+ //
+ // We first check whether this is a FwpsCompleteOperation-triggered
+ // reauth by looking for a pended connect that has the inspection
+ // decision recorded. If found, we return that decision and remove
+ // the pended connect from the list.
+ //
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+
+ for (listEntry = gConnList.Flink;
+ listEntry != &gConnList;
+ listEntry = listEntry->Flink)
+ {
+ connEntry = CONTAINING_RECORD(
+ listEntry,
+ TL_INSPECT_PENDED_PACKET,
+ listEntry
+ );
+
+ if (IsMatchingConnectPacket(
+ inFixedValues,
+ addressFamily,
+ packetDirection,
+ connEntry
+ ) && (connEntry->authConnectDecision != 0))
+ {
+ // We found a match.
+ pendedConnect = connEntry;
+
+ NT_ASSERT((pendedConnect->authConnectDecision == FWP_ACTION_PERMIT) ||
+ (pendedConnect->authConnectDecision == FWP_ACTION_BLOCK));
+
+ classifyOut->actionType = pendedConnect->authConnectDecision;
+ if (classifyOut->actionType == FWP_ACTION_BLOCK ||
+ filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ RemoveEntryList(&pendedConnect->listEntry);
+
+ if (!gDriverUnloading &&
+ (pendedConnect->netBufferList != NULL) &&
+ (pendedConnect->authConnectDecision == FWP_ACTION_PERMIT))
+ {
+ //
+ // Now the outbound connection has been authorized. If the
+ // pended connect has a net buffer list in it, we need it
+ // morph it into a data packet and queue it to the packet
+ // queue for send injecition.
+ //
+ pendedConnect->type = TL_INSPECT_DATA_PACKET;
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ signalWorkerThread = IsListEmpty(&gPacketQueue) &&
+ IsListEmpty(&gConnList);
+
+ InsertTailList(&gPacketQueue, &pendedConnect->listEntry);
+ pendedConnect = NULL; // ownership transferred
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ 0,
+ FALSE
+ );
+ }
+ }
+
+ authComplete = TRUE;
+ break;
+ }
+ }
+
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (authComplete)
+ {
+ goto Exit;
+ }
+ }
+
+ //
+ // If we reach here it means this is a policy change triggered re-auth
+ // for an pre-existing connection. For such a packet (inbound or
+ // outbound) we queue it to the packet queue and inspect it just like
+ // other regular data packets from TRANSPORT layers.
+ //
+
+ NT_ASSERT(layerData != NULL);
+
+ pendedPacket = AllocateAndInitializePendedPacket(
+ inFixedValues,
+ inMetaValues,
+ addressFamily,
+ layerData,
+ TL_INSPECT_REAUTH_PACKET,
+ packetDirection
+ );
+
+ if (pendedPacket == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ if (packetDirection == FWP_DIRECTION_INBOUND)
+ {
+ pendedPacket->ipSecProtected = IsSecureConnection(inFixedValues);
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (!gDriverUnloading)
+ {
+ signalWorkerThread = IsListEmpty(&gPacketQueue) &&
+ IsListEmpty(&gConnList);
+
+ InsertTailList(&gPacketQueue, &pendedPacket->listEntry);
+ pendedPacket = NULL; // ownership transferred
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
+ }
+ else
+ {
+ //
+ // Driver is being unloaded, permit any connect classify.
+ //
+ signalWorkerThread = FALSE;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ 0,
+ FALSE
+ );
+ }
+
+ }
+
+Exit:
+
+ if (pendedPacket != NULL)
+ {
+ FreePendedPacket(pendedPacket);
+ }
+ if (pendedConnect != NULL)
+ {
+ FreePendedPacket(pendedConnect);
+ }
+
+ return;
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+TLInspectALERecvAcceptClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#else
+
+void
+TLInspectALERecvAcceptClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+/* ++
+
+ This is the classifyFn function for the ALE Recv-Accept (v4 and v6) callout.
+ For an initial classify (where the FWP_CONDITION_FLAG_IS_REAUTHORIZE flag
+ is not set), it is queued to the connection list for inspection by the
+ worker thread. For re-auth, it is queued to the packet queue to be process
+ by the worker thread like any other regular packets.
+
+-- */
+{
+ NTSTATUS status;
+
+ KLOCK_QUEUE_HANDLE connListLockHandle;
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+
+ TL_INSPECT_PENDED_PACKET* pendedRecvAccept = NULL;
+ TL_INSPECT_PENDED_PACKET* pendedPacket = NULL;
+
+ ADDRESS_FAMILY addressFamily;
+ FWPS_PACKET_INJECTION_STATE packetState;
+ BOOLEAN signalWorkerThread;
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(filter);
+ UNREFERENCED_PARAMETER(flowContext);
+
+ //
+ // We don't have the necessary right to alter the classify, exit.
+ //
+ if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
+ {
+ goto Exit;
+ }
+
+ NT_ASSERT(layerData != NULL);
+ _Analysis_assume_(layerData != NULL);
+
+ //
+ // We don't re-inspect packets that we've inspected earlier.
+ //
+ packetState = FwpsQueryPacketInjectionState(
+ gInjectionHandle,
+ layerData,
+ NULL
+ );
+
+ if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
+ (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
+ {
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId);
+
+ if (!IsAleReauthorize(inFixedValues))
+ {
+ //
+ // If the classify is the initial authorization for a connection, we
+ // queue it to the pended connection list and notify the worker thread
+ // for out-of-band processing.
+ //
+ pendedRecvAccept = AllocateAndInitializePendedPacket(
+ inFixedValues,
+ inMetaValues,
+ addressFamily,
+ layerData,
+ TL_INSPECT_CONNECT_PACKET,
+ FWP_DIRECTION_INBOUND
+ );
+
+ if (pendedRecvAccept == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_COMPLETION_HANDLE));
+
+ //
+ // Pend the ALE_AUTH_RECV_ACCEPT classify.
+ //
+ status = FwpsPendOperation(
+ inMetaValues->completionHandle,
+ &pendedRecvAccept->completionContext
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ signalWorkerThread = IsListEmpty(&gConnList) &&
+ IsListEmpty(&gPacketQueue);
+
+ InsertTailList(&gConnList, &pendedRecvAccept->listEntry);
+ pendedRecvAccept = NULL; // ownership transferred
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ 0,
+ FALSE
+ );
+ }
+
+ }
+ else // re-auth @ ALE_AUTH_RECV_ACCEPT
+ {
+ FWP_DIRECTION packetDirection;
+ //
+ // The classify is the re-authorization for a existing connection, it
+ // could have been triggered for one of the two cases --
+ //
+ // 1) The re-auth is triggered by an outbound packet sent immediately
+ // after a policy change at ALE_AUTH_RECV_ACCEPT layer.
+ // 2) The re-auth is triggered by an inbound packet received
+ // immediately after a policy change at ALE_AUTH_RECV_ACCEPT layer.
+ //
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_PACKET_DIRECTION));
+ packetDirection = inMetaValues->packetDirection;
+
+ pendedPacket = AllocateAndInitializePendedPacket(
+ inFixedValues,
+ inMetaValues,
+ addressFamily,
+ layerData,
+ TL_INSPECT_REAUTH_PACKET,
+ packetDirection
+ );
+
+ if (pendedPacket == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ if (packetDirection == FWP_DIRECTION_INBOUND)
+ {
+ pendedPacket->ipSecProtected = IsSecureConnection(inFixedValues);
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (!gDriverUnloading)
+ {
+ signalWorkerThread = IsListEmpty(&gPacketQueue) &&
+ IsListEmpty(&gConnList);
+
+ InsertTailList(&gPacketQueue, &pendedPacket->listEntry);
+ pendedPacket = NULL; // ownership transferred
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
+ }
+ else
+ {
+ //
+ // Driver is being unloaded, permit any connect classify.
+ //
+ signalWorkerThread = FALSE;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ 0,
+ FALSE
+ );
+ }
+ }
+
+Exit:
+
+ if (pendedPacket != NULL)
+ {
+ FreePendedPacket(pendedPacket);
+ }
+ if (pendedRecvAccept != NULL)
+ {
+ FreePendedPacket(pendedRecvAccept);
+ }
+
+ return;
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+TLInspectTransportClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#else
+
+void
+TLInspectTransportClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#endif
+/* ++
+
+ This is the classifyFn function for the Transport (v4 and v6) callout.
+ packets (inbound or outbound) are ueued to the packet queue to be processed
+ by the worker thread.
+
+-- */
+{
+
+ KLOCK_QUEUE_HANDLE connListLockHandle;
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+
+ TL_INSPECT_PENDED_PACKET* pendedPacket = NULL;
+ FWP_DIRECTION packetDirection;
+
+ ADDRESS_FAMILY addressFamily;
+ FWPS_PACKET_INJECTION_STATE packetState;
+ BOOLEAN signalWorkerThread;
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(filter);
+ UNREFERENCED_PARAMETER(flowContext);
+
+ //
+ // We don't have the necessary right to alter the classify, exit.
+ //
+ if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
+ {
+ goto Exit;
+ }
+
+ NT_ASSERT(layerData != NULL);
+ _Analysis_assume_(layerData != NULL);
+
+ //
+ // We don't re-inspect packets that we've inspected earlier.
+ //
+ packetState = FwpsQueryPacketInjectionState(
+ gInjectionHandle,
+ layerData,
+ NULL
+ );
+
+ if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
+ (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
+ {
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId);
+
+ packetDirection =
+ GetPacketDirectionForLayer(inFixedValues->layerId);
+
+ if (packetDirection == FWP_DIRECTION_INBOUND)
+ {
+ if (IsAleClassifyRequired(inFixedValues, inMetaValues))
+ {
+ //
+ // Inbound transport packets that are destined to ALE Recv-Accept
+ // layers, for initial authorization or reauth, should be inspected
+ // at the ALE layer. We permit it from Tranport here.
+ //
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ goto Exit;
+ }
+ else
+ {
+ //
+ // To be compatible with Vista's IpSec implementation, we must not
+ // intercept not-yet-detunneled IpSec traffic.
+ //
+ FWPS_PACKET_LIST_INFORMATION packetInfo = {0};
+ FwpsGetPacketListSecurityInformation(
+ layerData,
+ FWPS_PACKET_LIST_INFORMATION_QUERY_IPSEC |
+ FWPS_PACKET_LIST_INFORMATION_QUERY_INBOUND,
+ &packetInfo
+ );
+
+ if (packetInfo.ipsecInformation.inbound.isTunnelMode &&
+ !packetInfo.ipsecInformation.inbound.isDeTunneled)
+ {
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ goto Exit;
+ }
+ }
+ }
+
+ pendedPacket = AllocateAndInitializePendedPacket(
+ inFixedValues,
+ inMetaValues,
+ addressFamily,
+ layerData,
+ TL_INSPECT_DATA_PACKET,
+ packetDirection
+ );
+
+ if (pendedPacket == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (!gDriverUnloading)
+ {
+ signalWorkerThread = IsListEmpty(&gPacketQueue) &&
+ IsListEmpty(&gConnList);
+
+ InsertTailList(&gPacketQueue, &pendedPacket->listEntry);
+ pendedPacket = NULL; // ownership transferred
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
+ }
+ else
+ {
+ //
+ // Driver is being unloaded, permit any connect classify.
+ //
+ signalWorkerThread = FALSE;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gWorkerEvent,
+ 0,
+ FALSE
+ );
+ }
+
+Exit:
+
+ if (pendedPacket != NULL)
+ {
+ FreePendedPacket(pendedPacket);
+ }
+
+ return;
+}
+
+NTSTATUS
+TLInspectALEConnectNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ )
+{
+ UNREFERENCED_PARAMETER(notifyType);
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+TLInspectALERecvAcceptNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ )
+{
+ UNREFERENCED_PARAMETER(notifyType);
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+TLInspectTransportNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ )
+{
+ UNREFERENCED_PARAMETER(notifyType);
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ return STATUS_SUCCESS;
+}
+
+void TLInspectInjectComplete(
+ _Inout_ void* context,
+ _Inout_ NET_BUFFER_LIST* netBufferList,
+ _In_ BOOLEAN dispatchLevel
+ )
+{
+ TL_INSPECT_PENDED_PACKET* packet = context;
+
+ UNREFERENCED_PARAMETER(dispatchLevel);
+
+ FwpsFreeCloneNetBufferList(netBufferList, 0);
+
+ FreePendedPacket(packet);
+}
+
+NTSTATUS
+TLInspectCloneReinjectOutbound(
+ _Inout_ TL_INSPECT_PENDED_PACKET* packet
+ )
+/* ++
+
+ This function clones the outbound net buffer list and reinject it back.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ NET_BUFFER_LIST* clonedNetBufferList = NULL;
+ FWPS_TRANSPORT_SEND_PARAMS sendArgs = {0};
+
+ status = FwpsAllocateCloneNetBufferList(
+ packet->netBufferList,
+ NULL,
+ NULL,
+ 0,
+ &clonedNetBufferList
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ sendArgs.remoteAddress = (UINT8*)(&packet->remoteAddr);
+ sendArgs.remoteScopeId = packet->remoteScopeId;
+ sendArgs.controlData = packet->controlData;
+ sendArgs.controlDataLength = packet->controlDataLength;
+
+ //
+ // Send-inject the cloned net buffer list.
+ //
+
+ status = FwpsInjectTransportSendAsync(
+ gInjectionHandle,
+ NULL,
+ packet->endpointHandle,
+ 0,
+ &sendArgs,
+ packet->addressFamily,
+ packet->compartmentId,
+ clonedNetBufferList,
+ TLInspectInjectComplete,
+ packet
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ clonedNetBufferList = NULL; // ownership transferred to the
+ // completion function.
+
+Exit:
+
+ if (clonedNetBufferList != NULL)
+ {
+ FwpsFreeCloneNetBufferList(clonedNetBufferList, 0);
+ }
+
+ return status;
+}
+
+NTSTATUS
+TLInspectCloneReinjectInbound(
+ _Inout_ TL_INSPECT_PENDED_PACKET* packet
+ )
+/* ++
+
+ This function clones the inbound net buffer list and, if needed,
+ rebuild the IP header to remove the IpSec headers and receive-injects
+ the clone back to the tcpip stack.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ NET_BUFFER_LIST* clonedNetBufferList = NULL;
+ NET_BUFFER* netBuffer;
+ ULONG nblOffset;
+ NDIS_STATUS ndisStatus;
+
+ //
+ // For inbound net buffer list, we can assume it contains only one
+ // net buffer.
+ //
+ netBuffer = NET_BUFFER_LIST_FIRST_NB(packet->netBufferList);
+
+ nblOffset = NET_BUFFER_DATA_OFFSET(netBuffer);
+
+ //
+ // The TCP/IP stack could have retreated the net buffer list by the
+ // transportHeaderSize amount; detect the condition here to avoid
+ // retreating twice.
+ //
+ if (nblOffset != packet->nblOffset)
+ {
+ NT_ASSERT(packet->nblOffset - nblOffset == packet->transportHeaderSize);
+ packet->transportHeaderSize = 0;
+ }
+
+ //
+ // Adjust the net buffer list offset to the start of the IP header.
+ //
+ ndisStatus = NdisRetreatNetBufferDataStart(
+ netBuffer,
+ packet->ipHeaderSize + packet->transportHeaderSize,
+ 0,
+ NULL
+ );
+ _Analysis_assume_(ndisStatus == NDIS_STATUS_SUCCESS);
+
+ //
+ // Note that the clone will inherit the original net buffer list's offset.
+ //
+
+ status = FwpsAllocateCloneNetBufferList(
+ packet->netBufferList,
+ NULL,
+ NULL,
+ 0,
+ &clonedNetBufferList
+ );
+
+ //
+ // Undo the adjustment on the original net buffer list.
+ //
+
+ NdisAdvanceNetBufferDataStart(
+ netBuffer,
+ packet->ipHeaderSize + packet->transportHeaderSize,
+ FALSE,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ if (packet->ipSecProtected)
+ {
+ //
+ // When an IpSec protected packet is indicated to AUTH_RECV_ACCEPT or
+ // INBOUND_TRANSPORT layers, for performance reasons the tcpip stack
+ // does not remove the AH/ESP header from the packet. And such
+ // packets cannot be recv-injected back to the stack w/o removing the
+ // AH/ESP header. Therefore before re-injection we need to "re-build"
+ // the cloned packet.
+ //
+ status = FwpsConstructIpHeaderForTransportPacket(
+ clonedNetBufferList,
+ packet->ipHeaderSize,
+ packet->addressFamily,
+ (UINT8*)&packet->remoteAddr,
+ (UINT8*)&packet->localAddr,
+ packet->protocol,
+ 0,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ 0,
+ 0
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+ if (packet->completionContext != NULL)
+ {
+ NT_ASSERT(packet->type == TL_INSPECT_CONNECT_PACKET);
+
+ FwpsCompleteOperation(
+ packet->completionContext,
+ clonedNetBufferList
+ );
+
+ packet->completionContext = NULL;
+ }
+
+ status = FwpsInjectTransportReceiveAsync(
+ gInjectionHandle,
+ NULL,
+ NULL,
+ 0,
+ packet->addressFamily,
+ packet->compartmentId,
+ packet->interfaceIndex,
+ packet->subInterfaceIndex,
+ clonedNetBufferList,
+ TLInspectInjectComplete,
+ packet
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ clonedNetBufferList = NULL; // ownership transferred to the
+ // completion function.
+
+Exit:
+
+ if (clonedNetBufferList != NULL)
+ {
+ FwpsFreeCloneNetBufferList(clonedNetBufferList, 0);
+ }
+
+ return status;
+}
+
+void
+TlInspectCompletePendedConnection(
+ _Inout_ TL_INSPECT_PENDED_PACKET** pendedConnect,
+ _In_ BOOLEAN permitTraffic
+ )
+/* ++
+
+ This function completes the pended connection (inbound or outbound)
+ with the inspection result.
+
+-- */
+{
+
+ TL_INSPECT_PENDED_PACKET* pendedConnectLocal = *pendedConnect;
+
+ if (pendedConnectLocal->direction == FWP_DIRECTION_OUTBOUND)
+ {
+ HANDLE completionContext = pendedConnectLocal->completionContext;
+
+ pendedConnectLocal->authConnectDecision =
+ permitTraffic ? FWP_ACTION_PERMIT : FWP_ACTION_BLOCK;
+
+ //
+ // For pended ALE_AUTH_CONNECT, FwpsCompleteOperation will trigger
+ // a re-auth during which the inspection decision is to be returned.
+ // Here we don't remove the pended entry from the list such that the
+ // re-auth can find it along with the recorded inspection result.
+ //
+ pendedConnectLocal->completionContext = NULL;
+
+ FwpsCompleteOperation(
+ completionContext,
+ NULL
+ );
+
+ *pendedConnect = NULL; // ownership transferred to the re-auth path.
+ }
+ else
+ {
+ if (!configPermitTraffic)
+ {
+ FreePendedPacket(pendedConnectLocal);
+ *pendedConnect = NULL;
+ }
+
+ //
+ // Permitted ALE_RECV_ACCEPT will pass thru and be processed by
+ // TLInspectCloneReinjectInbound. FwpsCompleteOperation will be called
+ // then when the net buffer list is cloned; after which the clone will
+ // be recv-injected.
+ //
+ }
+}
+
+void
+TLInspectWorker(
+ _In_ void* StartContext
+ )
+/* ++
+
+ This worker thread waits for the connect and packet queue event when the
+ queues are empty; and it will be woken up when there are connects/packets
+ queued needing to be inspected. Once awaking, It will run in a loop to
+ complete the pended ALE classifies and/or clone-reinject packets back
+ until both queues are exhausted (and it will go to sleep waiting for more
+ work).
+
+ The worker thread will end once it detected the driver is unloading.
+
+-- */
+{
+ NTSTATUS status;
+
+ TL_INSPECT_PENDED_PACKET* packet = NULL;
+ LIST_ENTRY* listEntry;
+
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+ KLOCK_QUEUE_HANDLE connListLockHandle;
+
+ UNREFERENCED_PARAMETER(StartContext);
+
+ for(;;)
+ {
+ KeWaitForSingleObject(
+ &gWorkerEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ if (gDriverUnloading)
+ {
+ break;
+ }
+
+ configPermitTraffic = IsTrafficPermitted();
+
+ listEntry = NULL;
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+
+ if (!IsListEmpty(&gConnList))
+ {
+ _Analysis_assume_(gConnList.Flink != NULL);
+ listEntry = gConnList.Flink;
+
+ packet = CONTAINING_RECORD(
+ listEntry,
+ TL_INSPECT_PENDED_PACKET,
+ listEntry
+ );
+ if (packet->direction == FWP_DIRECTION_INBOUND)
+ {
+ RemoveEntryList(&packet->listEntry);
+ }
+
+ //
+ // Leave the pended ALE_AUTH_CONNECT in the connection list, it will
+ // be processed and removed from the list during re-auth.
+ //
+ }
+
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (listEntry == NULL)
+ {
+ NT_ASSERT(!IsListEmpty(&gPacketQueue));
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ listEntry = RemoveHeadList(&gPacketQueue);
+
+ packet = CONTAINING_RECORD(
+ listEntry,
+ TL_INSPECT_PENDED_PACKET,
+ listEntry
+ );
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ }
+
+ if (packet->type == TL_INSPECT_CONNECT_PACKET)
+ {
+ TlInspectCompletePendedConnection(
+ &packet,
+ configPermitTraffic);
+ }
+
+ if ((packet != NULL) && configPermitTraffic)
+ {
+ if (packet->direction == FWP_DIRECTION_OUTBOUND)
+ {
+ status = TLInspectCloneReinjectOutbound(packet);
+ }
+ else
+ {
+ status = TLInspectCloneReinjectInbound(packet);
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ packet = NULL; // ownership transferred.
+ }
+
+ }
+
+ if (packet != NULL)
+ {
+ FreePendedPacket(packet);
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (IsListEmpty(&gConnList) && IsListEmpty(&gPacketQueue) &&
+ !gDriverUnloading)
+ {
+ KeClearEvent(&gWorkerEvent);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+ }
+
+ NT_ASSERT(gDriverUnloading);
+
+ while (!IsListEmpty(&gConnList))
+ {
+ packet = NULL;
+
+ KeAcquireInStackQueuedSpinLock(
+ &gConnListLock,
+ &connListLockHandle
+ );
+
+ if (!IsListEmpty(&gConnList))
+ {
+ listEntry = gConnList.Flink;
+ packet = CONTAINING_RECORD(
+ listEntry,
+ TL_INSPECT_PENDED_PACKET,
+ listEntry
+ );
+ }
+
+ KeReleaseInStackQueuedSpinLock(&connListLockHandle);
+
+ if (packet != NULL)
+ {
+ TlInspectCompletePendedConnection(&packet, FALSE);
+ NT_ASSERT(packet == NULL);
+ }
+ }
+
+ //
+ // Discard all the pended packets if driver is being unloaded.
+ //
+
+ while (!IsListEmpty(&gPacketQueue))
+ {
+ packet = NULL;
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (!IsListEmpty(&gPacketQueue))
+ {
+ listEntry = RemoveHeadList(&gPacketQueue);
+
+ packet = CONTAINING_RECORD(
+ listEntry,
+ TL_INSPECT_PENDED_PACKET,
+ listEntry
+ );
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+
+ if (packet != NULL)
+ {
+ FreePendedPacket(packet);
+ }
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+
+}
diff --git a/network/trans/inspect/sys/inspect.h b/network/trans/inspect/sys/inspect.h
new file mode 100644
index 00000000..baff6485
--- /dev/null
+++ b/network/trans/inspect/sys/inspect.h
@@ -0,0 +1,214 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ This header files declares common data types and function prototypes used
+ throughout the Transport Inspect sample.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#ifndef _TL_INSPECT_H_
+#define _TL_INSPECT_H_
+
+typedef enum TL_INSPECT_PACKET_TYPE_
+{
+ TL_INSPECT_CONNECT_PACKET,
+ TL_INSPECT_DATA_PACKET,
+ TL_INSPECT_REAUTH_PACKET
+} TL_INSPECT_PACKET_TYPE;
+
+//
+// TL_INSPECT_PENDED_PACKET is the object type we used to store all information
+// needed for out-of-band packet modification and re-injection. This type
+// also points back to the flow context the packet belongs to.
+
+#pragma warning(push)
+#pragma warning(disable: 4201) //NAMELESS_STRUCT_UNION
+
+typedef struct TL_INSPECT_PENDED_PACKET_
+{
+ LIST_ENTRY listEntry;
+
+ ADDRESS_FAMILY addressFamily;
+ TL_INSPECT_PACKET_TYPE type;
+ FWP_DIRECTION direction;
+
+ UINT32 authConnectDecision;
+ HANDLE completionContext;
+
+ //
+ // Common fields for inbound and outbound traffic.
+ //
+ UINT8 protocol;
+ NET_BUFFER_LIST* netBufferList;
+ COMPARTMENT_ID compartmentId;
+ union
+ {
+ FWP_BYTE_ARRAY16 localAddr;
+ UINT32 ipv4LocalAddr;
+ };
+ union
+ {
+ UINT16 localPort;
+ UINT16 icmpType;
+ };
+ union
+ {
+ UINT16 remotePort;
+ UINT16 icmpCode;
+ };
+
+ //
+ // Data fields for outbound packet re-injection.
+ //
+ UINT64 endpointHandle;
+ union
+ {
+ FWP_BYTE_ARRAY16 remoteAddr;
+ UINT32 ipv4RemoteAddr;
+ };
+
+ SCOPE_ID remoteScopeId;
+ WSACMSGHDR* controlData;
+ ULONG controlDataLength;
+
+ //
+ // Data fields for inbound packet re-injection.
+ //
+ BOOLEAN ipSecProtected;
+ ULONG nblOffset;
+ UINT32 ipHeaderSize;
+ UINT32 transportHeaderSize;
+ IF_INDEX interfaceIndex;
+ IF_INDEX subInterfaceIndex;
+} TL_INSPECT_PENDED_PACKET;
+
+#pragma warning(pop)
+
+//
+// Pooltags used by this callout driver.
+//
+#define TL_INSPECT_CONNECTION_POOL_TAG 'olfD'
+#define TL_INSPECT_PENDED_PACKET_POOL_TAG 'kppD'
+#define TL_INSPECT_CONTROL_DATA_POOL_TAG 'dcdD'
+
+//
+// Shared global data.
+//
+extern BOOLEAN configPermitTraffic;
+
+extern HANDLE gInjectionHandle;
+
+extern LIST_ENTRY gConnList;
+extern KSPIN_LOCK gConnListLock;
+
+extern LIST_ENTRY gPacketQueue;
+extern KSPIN_LOCK gPacketQueueLock;
+
+extern KEVENT gWorkerEvent;
+
+extern BOOLEAN gDriverUnloading;
+
+//
+// Shared function prototypes
+//
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+TLInspectALEConnectClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+void
+TLInspectALERecvAcceptClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+void
+TLInspectTransportClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#else /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+TLInspectALEConnectClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+void
+TLInspectALERecvAcceptClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+void
+TLInspectTransportClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+NTSTATUS
+TLInspectALEConnectNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ );
+
+NTSTATUS
+TLInspectALERecvAcceptNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ );
+
+NTSTATUS
+TLInspectTransportNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ );
+
+KSTART_ROUTINE TLInspectWorker;
+
+#endif // _TL_INSPECT_H_
diff --git a/network/trans/inspect/sys/inspect.inf b/network/trans/inspect/sys/inspect.inf
new file mode 100644
index 00000000..125f9601
--- /dev/null
+++ b/network/trans/inspect/sys/inspect.inf
@@ -0,0 +1,63 @@
+;;;
+;;; Copyright (c) Microsoft Corporation. All rights reserved
+;;;
+;;; Abstract:
+;;; Traffic Inspect Callout sample driver install configuration.
+;;;
+
+[Version]
+ Signature = "$Windows NT$"
+ Class = WFPCALLOUTS
+ ClassGuid = {57465043-616C-6C6F-7574-5F636C617373}
+ Provider = %Contoso%
+ CatalogFile = Inspect.cat
+ DriverVer = 11/24/2014,14.24.55.836
+
+[SourceDisksNames]
+ 1 = %InspectDisk%,,,""
+
+[SourceDisksFiles]
+ Inspect.sys = 1,,
+
+[DestinationDirs]
+ DefaultDestDir = 12 ; %WinDir%\System32\Drivers
+ Inspect.DriverFiles = 12 ; %WinDir%\System32\Drivers
+
+[DefaultInstall]
+ OptionDesc = %InspectServiceDesc%
+ CopyFiles = Inspect.DriverFiles
+
+[DefaultInstall.Services]
+ AddService = %InspectServiceName%,,Inspect.Service
+
+[DefaultUninstall]
+ DelFiles = Inspect.DriverFiles
+
+[DefaultUninstall.Services]
+ DelService = %InspectServiceName%,0x200 ; SPSVCINST_STOPSERVICE
+ DelReg = Inspect.DelRegistry
+
+[Inspect.DriverFiles]
+ Inspect.sys,,,0x00000040 ; COPYFLG_OVERWRITE_OLDER_ONLY
+
+[Inspect.Service]
+ DisplayName = %InspectServiceName%
+ Description = %InspectServiceDesc%
+ ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+ StartType = 3 ; SERVICE_DEMAND_START
+ ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ ServiceBinary = %12%\Inspect.sys ; %WinDir%\System32\Drivers\Inspect.sys
+ AddReg = Inspect.AddRegistry
+
+[Inspect.AddRegistry]
+ HKR,"Parameters","BlockTraffic",0x00010001,"0" ; FLG_ADDREG_TYPE_DWORD
+ HKR,"Parameters","RemoteAddressToInspect",0x00000000,"10.0.0.1" ; FLG_ADDREG_TYPE_SZ
+
+[Inspect.DelRegistry]
+ HKR,"Parameters",,,
+
+[Strings]
+ Contoso = "Contoso Ltd."
+ InspectDisk = "Traffic Inspect Installation Disk"
+ InspectServiceDesc = "Traffic Inspect Callout Driver"
+ InspectServiceName = "Inspect" \ No newline at end of file
diff --git a/network/trans/inspect/sys/inspect.vcxproj b/network/trans/inspect/sys/inspect.vcxproj
new file mode 100644
index 00000000..d403b025
--- /dev/null
+++ b/network/trans/inspect/sys/inspect.vcxproj
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{43AC1739-03F1-4465-8A16-F5FCD06BC2E9}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{CA2EEED8-4078-42F4-947A-29D46ACCC30F}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>KMDF</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>inspect</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>inspect</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>inspect</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>inspect</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ndis.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="inspect.c" />
+ <ClCompile Include="tl_drv.c" />
+ <ClCompile Include="utils.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/network/trans/inspect/sys/inspect.vcxproj.Filters b/network/trans/inspect/sys/inspect.vcxproj.Filters
new file mode 100644
index 00000000..7fbd1b25
--- /dev/null
+++ b/network/trans/inspect/sys/inspect.vcxproj.Filters
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{89A4FDF7-7B2B-42A3-A13C-4855905159BF}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{893A15B9-96A4-4181-9353-D9C59D6D343C}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{174E13A1-2D15-477C-9E80-060424681A41}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{3D55D549-7A89-4DEB-9C7B-149E8332DD7C}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="inspect.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="tl_drv.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utils.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/trans/inspect/sys/utils.c b/network/trans/inspect/sys/utils.c
new file mode 100644
index 00000000..b6cbf0ce
--- /dev/null
+++ b/network/trans/inspect/sys/utils.c
@@ -0,0 +1,448 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ This file implements the utility/helper functions for use by the classify
+ functions and worker thread of the Transport Inspect sample.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+
+#include <ntddk.h>
+#include <wdf.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include <fwpmk.h>
+
+#include "inspect.h"
+#include "utils.h"
+
+
+BOOLEAN IsAleReauthorize(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues
+ )
+{
+ UINT flagsIndex;
+
+ GetFlagsIndexesForLayer(
+ inFixedValues->layerId,
+ &flagsIndex
+ );
+
+ if((flagsIndex != UINT_MAX) && ((inFixedValues->incomingValue\
+ [flagsIndex].value.uint32 & FWP_CONDITION_FLAG_IS_REAUTHORIZE) != 0))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOLEAN IsSecureConnection(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues
+ )
+{
+ UINT flagsIndex;
+
+ GetFlagsIndexesForLayer(
+ inFixedValues->layerId,
+ &flagsIndex
+ );
+
+ if ((flagsIndex != UINT_MAX) && ((inFixedValues->incomingValue\
+ [flagsIndex].value.uint32 & FWP_CONDITION_FLAG_IS_IPSEC_SECURED) != 0))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+IsAleClassifyRequired(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues
+ )
+{
+ //
+ // Note that use of FWP_CONDITION_FLAG_REQUIRES_ALE_CLASSIFY has been
+ // deprecated in Vista SP1 and Windows Server 2008.
+ //
+ UNREFERENCED_PARAMETER(inFixedValues);
+ return FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED
+ );
+}
+
+BOOLEAN
+IsMatchingConnectPacket(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ ADDRESS_FAMILY addressFamily,
+ _In_ FWP_DIRECTION direction,
+ _Inout_ TL_INSPECT_PENDED_PACKET* pendedPacket
+ )
+{
+ UINT localAddrIndex;
+ UINT remoteAddrIndex;
+ UINT localPortIndex;
+ UINT remotePortIndex;
+ UINT protocolIndex;
+
+ NT_ASSERT(pendedPacket->type == TL_INSPECT_CONNECT_PACKET);
+
+ GetNetwork5TupleIndexesForLayer(
+ inFixedValues->layerId,
+ &localAddrIndex,
+ &remoteAddrIndex,
+ &localPortIndex,
+ &remotePortIndex,
+ &protocolIndex
+ );
+
+ if(localAddrIndex == UINT_MAX)
+ {
+ return FALSE;
+ }
+
+ if (addressFamily != pendedPacket->addressFamily)
+ {
+ return FALSE;
+ }
+
+ if (direction != pendedPacket->direction)
+ {
+ return FALSE;
+ }
+
+ if (inFixedValues->incomingValue[protocolIndex].value.uint8 !=
+ pendedPacket->protocol)
+ {
+ return FALSE;
+ }
+
+ if (RtlUshortByteSwap(
+ inFixedValues->incomingValue[localPortIndex].value.uint16
+ ) != pendedPacket->localPort)
+ {
+ return FALSE;
+ }
+
+ if (RtlUshortByteSwap(
+ inFixedValues->incomingValue[remotePortIndex].value.uint16
+ ) != pendedPacket->remotePort)
+ {
+ return FALSE;
+ }
+
+ if (addressFamily == AF_INET)
+ {
+ UINT32 ipv4LocalAddr =
+ RtlUlongByteSwap(
+ inFixedValues->incomingValue[localAddrIndex].value.uint32
+ );
+ UINT32 ipv4RemoteAddr =
+ // Prefast thinks we are ignoring this return value.
+ // If driver is unloading, we give up and ignore it on purpose.
+ // Otherwise, we put the pointer onto the list, but we make it opaque
+ // by casting it as a UINT64, and this tricks Prefast.
+ RtlUlongByteSwap( /* host-order -> network-order conversion */
+ inFixedValues->incomingValue[remoteAddrIndex].value.uint32
+ );
+ if (ipv4LocalAddr != pendedPacket->ipv4LocalAddr)
+ {
+ return FALSE;
+ }
+
+ if (ipv4RemoteAddr != pendedPacket->ipv4RemoteAddr)
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ if (RtlCompareMemory(
+ inFixedValues->incomingValue[localAddrIndex].value.byteArray16,
+ &pendedPacket->localAddr,
+ sizeof(FWP_BYTE_ARRAY16)) != sizeof(FWP_BYTE_ARRAY16))
+ {
+ return FALSE;
+ }
+
+ if (RtlCompareMemory(
+ inFixedValues->incomingValue[remoteAddrIndex].value.byteArray16,
+ &pendedPacket->remoteAddr,
+ sizeof(FWP_BYTE_ARRAY16)) != sizeof(FWP_BYTE_ARRAY16))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+void
+FillNetwork5Tuple(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ ADDRESS_FAMILY addressFamily,
+ _Inout_ TL_INSPECT_PENDED_PACKET* packet
+ )
+{
+ UINT localAddrIndex;
+ UINT remoteAddrIndex;
+ UINT localPortIndex;
+ UINT remotePortIndex;
+ UINT protocolIndex;
+
+ GetNetwork5TupleIndexesForLayer(
+ inFixedValues->layerId,
+ &localAddrIndex,
+ &remoteAddrIndex,
+ &localPortIndex,
+ &remotePortIndex,
+ &protocolIndex
+ );
+
+ if (addressFamily == AF_INET)
+ {
+ packet->ipv4LocalAddr =
+ RtlUlongByteSwap( /* host-order -> network-order conversion */
+ inFixedValues->incomingValue[localAddrIndex].value.uint32
+ );
+ packet->ipv4RemoteAddr =
+ RtlUlongByteSwap( /* host-order -> network-order conversion */
+ inFixedValues->incomingValue[remoteAddrIndex].value.uint32
+ );
+ }
+ else
+ {
+ RtlCopyMemory(
+ (UINT8*)&packet->localAddr,
+ inFixedValues->incomingValue[localAddrIndex].value.byteArray16,
+ sizeof(FWP_BYTE_ARRAY16)
+ );
+ RtlCopyMemory(
+ (UINT8*)&packet->remoteAddr,
+ inFixedValues->incomingValue[remoteAddrIndex].value.byteArray16,
+ sizeof(FWP_BYTE_ARRAY16)
+ );
+ }
+
+ packet->localPort =
+ RtlUshortByteSwap(
+ inFixedValues->incomingValue[localPortIndex].value.uint16
+ );
+ packet->remotePort =
+ RtlUshortByteSwap(
+ inFixedValues->incomingValue[remotePortIndex].value.uint16
+ );
+
+ packet->protocol = inFixedValues->incomingValue[protocolIndex].value.uint8;
+
+ return;
+}
+
+void
+FreePendedPacket(
+ _Inout_ __drv_freesMem(Mem) TL_INSPECT_PENDED_PACKET* packet
+ )
+{
+ if (packet->netBufferList != NULL)
+ {
+ FwpsDereferenceNetBufferList(packet->netBufferList, FALSE);
+ }
+ if (packet->controlData != NULL)
+ {
+ ExFreePoolWithTag(packet->controlData, TL_INSPECT_CONTROL_DATA_POOL_TAG);
+ }
+ if (packet->completionContext != NULL)
+ {
+ NT_ASSERT(packet->type == TL_INSPECT_CONNECT_PACKET);
+ NT_ASSERT(packet->direction == FWP_DIRECTION_INBOUND); // complete for ALE connect
+ // is done prior to freeing
+ // of the packet.
+ FwpsCompleteOperation(packet->completionContext, NULL);
+ }
+ ExFreePoolWithTag(packet, TL_INSPECT_PENDED_PACKET_POOL_TAG);
+}
+
+__drv_allocatesMem(Mem)
+TL_INSPECT_PENDED_PACKET*
+AllocateAndInitializePendedPacket(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _In_ ADDRESS_FAMILY addressFamily,
+ _Inout_opt_ void* layerData,
+ _In_ TL_INSPECT_PACKET_TYPE packetType,
+ _In_ FWP_DIRECTION packetDirection
+ )
+{
+ TL_INSPECT_PENDED_PACKET* pendedPacket;
+
+ pendedPacket = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(TL_INSPECT_PENDED_PACKET),
+ TL_INSPECT_PENDED_PACKET_POOL_TAG
+ );
+
+ if (pendedPacket == NULL)
+ {
+ return NULL;
+ }
+
+ RtlZeroMemory(pendedPacket, sizeof(TL_INSPECT_PENDED_PACKET));
+
+ pendedPacket->type = packetType;
+ pendedPacket->direction = packetDirection;
+
+ pendedPacket->addressFamily = addressFamily;
+
+ FillNetwork5Tuple(
+ inFixedValues,
+ addressFamily,
+ pendedPacket
+ );
+
+ if (layerData != NULL)
+ {
+ pendedPacket->netBufferList = layerData;
+
+ //
+ // Reference the net buffer list to make it accessible outside of
+ // classifyFn.
+ //
+ FwpsReferenceNetBufferList(pendedPacket->netBufferList, TRUE);
+ }
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_COMPARTMENT_ID));
+ pendedPacket->compartmentId = inMetaValues->compartmentId;
+
+ if ((pendedPacket->direction == FWP_DIRECTION_OUTBOUND) &&
+ (layerData != NULL))
+ {
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE));
+ pendedPacket->endpointHandle = inMetaValues->transportEndpointHandle;
+
+ pendedPacket->remoteScopeId = inMetaValues->remoteScopeId;
+
+ if (FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA))
+ {
+ NT_ASSERT(inMetaValues->controlDataLength > 0);
+
+ pendedPacket->controlData = ExAllocatePoolWithTag(
+ NonPagedPool,
+ inMetaValues->controlDataLength,
+ TL_INSPECT_CONTROL_DATA_POOL_TAG
+ );
+ if (pendedPacket->controlData == NULL)
+ {
+ goto Exit;
+ }
+
+ RtlCopyMemory(
+ pendedPacket->controlData,
+ inMetaValues->controlData,
+ inMetaValues->controlDataLength
+ );
+
+ pendedPacket->controlDataLength = inMetaValues->controlDataLength;
+ }
+ }
+ else if (pendedPacket->direction == FWP_DIRECTION_INBOUND)
+ {
+ UINT interfaceIndexIndex = 0;
+ UINT subInterfaceIndexIndex = 0;
+
+ GetDeliveryInterfaceIndexesForLayer(
+ inFixedValues->layerId,
+ &interfaceIndexIndex,
+ &subInterfaceIndexIndex
+ );
+
+ pendedPacket->interfaceIndex =
+ inFixedValues->incomingValue[interfaceIndexIndex].value.uint32;
+ pendedPacket->subInterfaceIndex =
+ inFixedValues->incomingValue[subInterfaceIndexIndex].value.uint32;
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_IP_HEADER_SIZE));
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE));
+ pendedPacket->ipHeaderSize = inMetaValues->ipHeaderSize;
+ pendedPacket->transportHeaderSize = inMetaValues->transportHeaderSize;
+
+ if (pendedPacket->netBufferList != NULL)
+ {
+ FWPS_PACKET_LIST_INFORMATION packetInfo = {0};
+ FwpsGetPacketListSecurityInformation(
+ pendedPacket->netBufferList,
+ FWPS_PACKET_LIST_INFORMATION_QUERY_IPSEC |
+ FWPS_PACKET_LIST_INFORMATION_QUERY_INBOUND,
+ &packetInfo
+ );
+
+ pendedPacket->ipSecProtected =
+ (BOOLEAN)packetInfo.ipsecInformation.inbound.isSecure;
+
+ pendedPacket->nblOffset =
+ NET_BUFFER_DATA_OFFSET(\
+ NET_BUFFER_LIST_FIRST_NB(pendedPacket->netBufferList));
+ }
+ }
+
+ return pendedPacket;
+
+Exit:
+
+ if (pendedPacket != NULL)
+ {
+ FreePendedPacket(pendedPacket);
+ }
+
+ return NULL;
+}
+
+extern WDFKEY gParametersKey;
+
+BOOLEAN
+IsTrafficPermitted(void)
+{
+ NTSTATUS status;
+
+ DECLARE_CONST_UNICODE_STRING(valueName, L"PermitTraffic");
+ ULONG result;
+
+ status = WdfRegistryQueryULong(
+ gParametersKey,
+ &valueName,
+ &result
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ result = 1;
+ }
+
+ return (result != 0);
+}
+
+
diff --git a/network/trans/inspect/sys/utils.h b/network/trans/inspect/sys/utils.h
new file mode 100644
index 00000000..3570cd8a
--- /dev/null
+++ b/network/trans/inspect/sys/utils.h
@@ -0,0 +1,298 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ This file declares the utility/helper functions for use by the classify
+ functions and worker thread of the Transport Inspect sample.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <limits.h>
+
+#ifndef _TL_INSPECT_UTILS_H_
+#define _TL_INSPECT_UTILS_H_
+
+__inline
+ADDRESS_FAMILY GetAddressFamilyForLayer(
+ _In_ UINT16 layerId
+ )
+{
+ ADDRESS_FAMILY addressFamily;
+
+ switch (layerId)
+ {
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V4:
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4:
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V4:
+ case FWPS_LAYER_INBOUND_TRANSPORT_V4:
+ addressFamily = AF_INET;
+ break;
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V6:
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6:
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V6:
+ case FWPS_LAYER_INBOUND_TRANSPORT_V6:
+ addressFamily = AF_INET6;
+ break;
+ default:
+ addressFamily = AF_UNSPEC;
+ NT_ASSERT(0);
+ }
+
+ return addressFamily;
+}
+
+__inline
+FWP_DIRECTION GetPacketDirectionForLayer(
+ _In_ UINT16 layerId
+ )
+{
+ FWP_DIRECTION direction;
+
+ switch (layerId)
+ {
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V4:
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V6:
+ direction = FWP_DIRECTION_OUTBOUND;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V4:
+ case FWPS_LAYER_INBOUND_TRANSPORT_V6:
+ direction = FWP_DIRECTION_INBOUND;
+ break;
+ default:
+ direction = FWP_DIRECTION_MAX;
+ NT_ASSERT(0);
+ }
+
+ return direction;
+}
+
+__inline
+void
+GetFlagsIndexesForLayer(
+ _In_ UINT16 layerId,
+ _Out_ UINT* flagsIndex
+ )
+{
+ switch (layerId)
+ {
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V4:
+ *flagsIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS;
+ break;
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V6:
+ *flagsIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V6_FLAGS;
+ break;
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4:
+ *flagsIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS;
+ break;
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6:
+ *flagsIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_FLAGS;
+ break;
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V4:
+ *flagsIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V4_FLAGS;
+ break;
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V6:
+ *flagsIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V6_FLAGS;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V4:
+ *flagsIndex = FWPS_FIELD_INBOUND_TRANSPORT_V4_FLAGS;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V6:
+ *flagsIndex = FWPS_FIELD_INBOUND_TRANSPORT_V6_FLAGS;
+ break;
+ default:
+ *flagsIndex = UINT_MAX;
+ NT_ASSERT(0);
+ break;
+ }
+}
+
+__inline
+void
+GetDeliveryInterfaceIndexesForLayer(
+ _In_ UINT16 layerId,
+ _Out_ UINT* interfaceIndexIndex,
+ _Out_ UINT* subInterfaceIndexIndex
+ )
+{
+ *interfaceIndexIndex = 0;
+
+ *subInterfaceIndexIndex = 0;
+
+ switch (layerId)
+ {
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V4:
+ *interfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_INTERFACE_INDEX;
+ *subInterfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_SUB_INTERFACE_INDEX;
+ break;
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V6:
+ *interfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_CONNECT_V6_INTERFACE_INDEX;
+ *subInterfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_CONNECT_V6_SUB_INTERFACE_INDEX;
+ break;
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4:
+ *interfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_INTERFACE_INDEX;
+ *subInterfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_SUB_INTERFACE_INDEX;
+ break;
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6:
+ *interfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_INTERFACE_INDEX;
+ *subInterfaceIndexIndex =
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_SUB_INTERFACE_INDEX;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V4:
+ *interfaceIndexIndex =
+ FWPS_FIELD_INBOUND_TRANSPORT_V4_INTERFACE_INDEX;
+ *subInterfaceIndexIndex =
+ FWPS_FIELD_INBOUND_TRANSPORT_V4_SUB_INTERFACE_INDEX;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V6:
+ *interfaceIndexIndex =
+ FWPS_FIELD_INBOUND_TRANSPORT_V6_INTERFACE_INDEX;
+ *subInterfaceIndexIndex =
+ FWPS_FIELD_INBOUND_TRANSPORT_V6_SUB_INTERFACE_INDEX;
+ break;
+ default:
+ NT_ASSERT(0);
+ break;
+ }
+}
+
+__inline
+void
+GetNetwork5TupleIndexesForLayer(
+ _In_ UINT16 layerId,
+ _Out_ UINT* localAddressIndex,
+ _Out_ UINT* remoteAddressIndex,
+ _Out_ UINT* localPortIndex,
+ _Out_ UINT* remotePortIndex,
+ _Out_ UINT* protocolIndex
+ )
+{
+ switch (layerId)
+ {
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V4:
+ *localAddressIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_ALE_AUTH_CONNECT_V6:
+ *localAddressIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4:
+ *localAddressIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6:
+ *localAddressIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V4:
+ *localAddressIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_OUTBOUND_TRANSPORT_V6:
+ *localAddressIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V6_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V6_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V6_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V6_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_OUTBOUND_TRANSPORT_V6_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V4:
+ *localAddressIndex = FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_PROTOCOL;
+ break;
+ case FWPS_LAYER_INBOUND_TRANSPORT_V6:
+ *localAddressIndex = FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_LOCAL_ADDRESS;
+ *remoteAddressIndex = FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_REMOTE_ADDRESS;
+ *localPortIndex = FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_LOCAL_PORT;
+ *remotePortIndex = FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_REMOTE_PORT;
+ *protocolIndex = FWPS_FIELD_INBOUND_TRANSPORT_V6_IP_PROTOCOL;
+ break;
+ default:
+ *localAddressIndex = UINT_MAX;
+ *remoteAddressIndex = UINT_MAX;
+ *localPortIndex = UINT_MAX;
+ *remotePortIndex = UINT_MAX;
+ *protocolIndex = UINT_MAX;
+ NT_ASSERT(0);
+ }
+}
+
+BOOLEAN IsAleReauthorize(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues
+ );
+
+BOOLEAN IsSecureConnection(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues
+ );
+
+BOOLEAN
+IsAleClassifyRequired(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues
+ );
+
+void
+FillNetwork5Tuple(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ ADDRESS_FAMILY addressFamily,
+ _Inout_ TL_INSPECT_PENDED_PACKET* packet
+ );
+
+BOOLEAN
+IsMatchingConnectPacket(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ ADDRESS_FAMILY addressFamily,
+ _In_ FWP_DIRECTION direction,
+ _Inout_ TL_INSPECT_PENDED_PACKET* pendedPacket
+ );
+
+__drv_allocatesMem(Mem)
+TL_INSPECT_PENDED_PACKET*
+AllocateAndInitializePendedPacket(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _In_ ADDRESS_FAMILY addressFamily,
+ _Inout_opt_ void* layerData,
+ _In_ TL_INSPECT_PACKET_TYPE packetType,
+ _In_ FWP_DIRECTION packetDirection
+ );
+
+void
+FreePendedPacket(
+ _Inout_ __drv_freesMem(Mem) TL_INSPECT_PENDED_PACKET* packet
+ );
+
+BOOLEAN
+IsTrafficPermitted(void);
+
+#endif // _TL_INSPECT_UTILS_H_