summaryrefslogtreecommitdiff
path: root/network/trans
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
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'network/trans')
-rw-r--r--network/trans/ddproxy/ReadMe.md66
-rw-r--r--network/trans/ddproxy/ddproxy.sln28
-rw-r--r--network/trans/ddproxy/sys/DD_drv.c1059
-rw-r--r--network/trans/ddproxy/sys/DD_proxy.c1039
-rw-r--r--network/trans/ddproxy/sys/DD_proxy.h251
-rw-r--r--network/trans/ddproxy/sys/ddproxy.inf63
-rw-r--r--network/trans/ddproxy/sys/ddproxy.vcxproj185
-rw-r--r--network/trans/ddproxy/sys/ddproxy.vcxproj.Filters29
-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
-rw-r--r--network/trans/msnmntr/ReadMe.md79
-rw-r--r--network/trans/msnmntr/exe/monitor.cpp715
-rw-r--r--network/trans/msnmntr/exe/monitor.vcxproj251
-rw-r--r--network/trans/msnmntr/exe/monitor.vcxproj.Filters22
-rw-r--r--network/trans/msnmntr/exe/mtrace.cmd288
-rw-r--r--network/trans/msnmntr/inc/ioctl.h36
-rw-r--r--network/trans/msnmntr/inc/mntrguid.h44
-rw-r--r--network/trans/msnmntr/msnmntr.sln46
-rw-r--r--network/trans/msnmntr/sys/ctl.c149
-rw-r--r--network/trans/msnmntr/sys/ctl.h19
-rw-r--r--network/trans/msnmntr/sys/init.c244
-rw-r--r--network/trans/msnmntr/sys/msnmntr.c883
-rw-r--r--network/trans/msnmntr/sys/msnmntr.h55
-rw-r--r--network/trans/msnmntr/sys/msnmntr.inf54
-rw-r--r--network/trans/msnmntr/sys/msnmntr.vcxproj194
-rw-r--r--network/trans/msnmntr/sys/msnmntr.vcxproj.Filters35
-rw-r--r--network/trans/msnmntr/sys/notify.c294
-rw-r--r--network/trans/msnmntr/sys/notify.h32
-rw-r--r--network/trans/stmedit/ReadMe.md60
-rw-r--r--network/trans/stmedit/stmedit.sln28
-rw-r--r--network/trans/stmedit/sys/inline_edit.c546
-rw-r--r--network/trans/stmedit/sys/inline_edit.h65
-rw-r--r--network/trans/stmedit/sys/oob_edit.c1363
-rw-r--r--network/trans/stmedit/sys/oob_edit.h83
-rw-r--r--network/trans/stmedit/sys/stmedit.inf66
-rw-r--r--network/trans/stmedit/sys/stmedit.vcxproj186
-rw-r--r--network/trans/stmedit/sys/stmedit.vcxproj.Filters32
-rw-r--r--network/trans/stmedit/sys/stream_callout.c772
-rw-r--r--network/trans/stmedit/sys/stream_callout.h79
47 files changed, 13109 insertions, 0 deletions
diff --git a/network/trans/ddproxy/ReadMe.md b/network/trans/ddproxy/ReadMe.md
new file mode 100644
index 00000000..67a6b213
--- /dev/null
+++ b/network/trans/ddproxy/ReadMe.md
@@ -0,0 +1,66 @@
+Windows Filtering Platform Packet Modification Sample
+=====================================================
+
+The sample driver demonstrates the packet modification capabilities of the Windows Filtering Platform (WFP).
+
+## Universal Compliant
+This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core.
+
+Run the sample
+--------------
+
+The computer where you install the driver is called the *target computer* or the *test computer*. Typically this is a separate computer from where you develop and build the driver package. The computer where you develop and build the driver is called the *host computer*.
+
+The process of moving the driver package to the target computer and installing the driver is called *deploying the driver*. You can deploy the Windows Filtering Platform Packet Modification Sample driver automatically or manually.
+
+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 ddproxy.inf. Right click ddproxy.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:\\WfpPacketModificationSamplePackage).
+2. On the target computer, navigate to your driver package folder. Right click ddproxy.inf, and choose **Install**
+
+Create Registry values
+----------------------
+
+1. On the target computer, open Regedit, and navigate to this key:
+
+ **HKLM**\\**System**\\**CurrentControlSet**\\**Services**\\**ddproxy**\\**Parameters**
+
+2. Create a REG\_SZ entry named **DestinationAddressToIntercept** and set it's value to an IPV4 or IPV6 address (example: 10.0.0.1).
+
+3. Create a REG\_SZ entry named **NewDestinationAddress**, and set it's value to an IPV4 or IPV6 address (example: 10.0.0.2).
+
+You can also create and set values for the following registry entries.
+
+- **InspectUdp** (REG\_DWORD type): 0 for ICMP and 1 for UDP (default)
+- **DestinationPortToIntercept** (REG\_DWORD type): UDP port number (applicable if InspectUdp is set to 1)
+- **NewDestinationPort** (REG\_DWORD type): UDP port number (applicable if InspectUdp is set to 1)
+
+Start the ddproxy service
+-------------------------
+
+On the target computer, open a Command Prompt window as Administrator, and enter **net start ddproxy**. (To stop the driver, enter **net stop ddproxy**.)
+
+Remarks
+-------
+
+This sample driver consists of a kernel-mode Windows Filtering Platform (WFP) callout driver (Ddproxy.sys) that intercepts User Datagram Protocol (UDP) and nonerror Internet Control Message Protocol (ICMP) traffic of interest and acts as a redirector. For outbound traffic, Ddproxy.sys redirects the traffic to a new destination address and, for UDP, a new UDP port. For inbound traffic, Ddproxy.sys redirects the traffic back to the original address and UDP port values. This redirection is transparent to the application.
+
+Packet modification is done out-of-band by a system worker thread by using the reference-drop-clone-modify-reinject mechanism. Therefore, the sample can serve as a basis for scenarios in which the filtering/modification decision cannot be made within the `classifyFn()` callout, but instead must be made, for example, by a user-mode application.
+
+Ddproxy.sys acts as a redirector for both Internet Protocol version 4 (IPv4) and Internet Protocol version 6 (IPv6) traffic.
+
+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/ddproxy/ddproxy.sln b/network/trans/ddproxy/ddproxy.sln
new file mode 100644
index 00000000..9115b369
--- /dev/null
+++ b/network/trans/ddproxy/ddproxy.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}") = "ddproxy", "sys\ddproxy.vcxproj", "{F5ED1745-0947-474A-924D-CB5D3D2D6C5E}"
+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
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Debug|Win32.Build.0 = Debug|Win32
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Release|Win32.ActiveCfg = Release|Win32
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Release|Win32.Build.0 = Release|Win32
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Debug|x64.ActiveCfg = Debug|x64
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Debug|x64.Build.0 = Debug|x64
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Release|x64.ActiveCfg = Release|x64
+ {F5ED1745-0947-474A-924D-CB5D3D2D6C5E}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/network/trans/ddproxy/sys/DD_drv.c b/network/trans/ddproxy/sys/DD_drv.c
new file mode 100644
index 00000000..18509e53
--- /dev/null
+++ b/network/trans/ddproxy/sys/DD_drv.c
@@ -0,0 +1,1059 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Datagram-Data Transparent Proxy Callout Driver Sample.
+
+ This sample callout driver intercepts UDP and non-error ICMP traffic
+ of interest and proxies them to a new destination address and/or port
+ (for UDP); response traffic will be proxied back to have the original
+ tuple values. The proxying is transparent to the application.
+
+ Inspection parameters and proxy settings are configurable via the
+ following registry values --
+
+ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ddproxy\Parameters
+
+ o InspectUdp (REG_DWORD) : 0 (ICMP); 1 (UDP, default)
+ o DestinationAddressToIntercept (REG_SZ) : literal IPv4/IPv6 string
+ (e.g. �10.0.0.1�)
+ o DestinationPortToIntercept (REG_DWORD) : applicable if InspectUdp is 1
+ o NewDestinationAddress(REG_SZ) : literal IPv4/IPv6 string
+ o NewDestinationPort(REG_DWORD)
+
+ The sample is IP version agnostic. It performs proxying 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 "DD_proxy.h"
+
+#define INITGUID
+#include <guiddef.h>
+
+//
+// Configurable parameters (addresses and ports are in host order)
+//
+
+BOOLEAN configInspectUdp = TRUE;
+
+UINT16 configInspectDestPort = 5001;
+UINT8* configInspectDestAddrV4 = NULL;
+UINT8* configInspectDestAddrV6 = NULL;
+
+UINT16 configNewDestPort = 5001;
+UINT8* configNewDestAddrV4 = NULL;
+UINT8* configNewDestAddrV6 = NULL;
+
+SOCKADDR_STORAGE destAddr, newDestAddr;
+
+//
+// Callout and sublayer GUIDs
+//
+
+// b16b0a6e-2b2a-41a3-8b39-bd3ffc855ff8
+DEFINE_GUID(
+ DD_PROXY_CALLOUT_V4,
+ 0xb16b0a6e,
+ 0x2b2a,
+ 0x41a3,
+ 0x8b, 0x39, 0xbd, 0x3f, 0xfc, 0x85, 0x5f, 0xf8
+);
+// 2cebde39-1f59-48d1-a5d9-3e2458351476
+DEFINE_GUID(
+ DD_PROXY_CALLOUT_V6,
+ 0x2cebde39,
+ 0x1f59,
+ 0x48d1,
+ 0xa5, 0xd9, 0x3e, 0x24, 0x58, 0x35, 0x14, 0x76
+);
+// ee93719d-ad5d-48c9-ae46-7270367d205d
+DEFINE_GUID(
+ DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V4,
+ 0xee93719d,
+ 0xad5d,
+ 0x48c9,
+ 0xae, 0x46, 0x72, 0x70, 0x36, 0x7d, 0x20, 0x5d
+);
+
+// 1e3d3d13-0588-4167-82a3-14f68c98de86
+DEFINE_GUID(
+ DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V6,
+ 0x1e3d3d13,
+ 0x0588,
+ 0x4167,
+ 0x82, 0xa3, 0x14, 0xf6, 0x8c, 0x98, 0xde, 0x86
+);
+
+// 0104fd7e-c825-414e-94c9-f0d525bbc169
+DEFINE_GUID(
+ DD_PROXY_SUBLAYER,
+ 0x0104fd7e,
+ 0xc825,
+ 0x414e,
+ 0x94, 0xc9, 0xf0, 0xd5, 0x25, 0xbb, 0xc1, 0x69
+);
+
+//
+// Callout driver global variables
+//
+
+DEVICE_OBJECT* gWdmDevice;
+
+HANDLE gEngineHandle;
+UINT32 gFlowEstablishedCalloutIdV4, gCalloutIdV4;
+UINT32 gFlowEstablishedCalloutIdV6, gCalloutIdV6;
+
+HANDLE gInjectionHandle;
+
+LIST_ENTRY gFlowList;
+KSPIN_LOCK gFlowListLock;
+
+LIST_ENTRY gPacketQueue;
+KSPIN_LOCK gPacketQueueLock;
+KEVENT gPacketQueueEvent;
+
+BOOLEAN gDriverUnloading = FALSE;
+void* gThreadObj;
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_UNLOAD EvtDriverUnload;
+
+//
+// Callout driver implementation
+//
+
+NTSTATUS
+DDProxyLoadIPAddress(
+ _In_ const WDFKEY key,
+ _In_ const UNICODE_STRING* valueName,
+ _Out_ SOCKADDR_STORAGE* result
+ )
+{
+ NTSTATUS status;
+ PWSTR terminator;
+ DECLARE_UNICODE_STRING_SIZE(value, INET6_ADDRSTRLEN);
+ IN_ADDR *resultV4 = &((SOCKADDR_IN*)result)->sin_addr;
+ IN6_ADDR *resultV6 = &((SOCKADDR_IN6*)result)->sin6_addr;
+
+ status = WdfRegistryQueryUnicodeString(key, valueName, NULL, &value);
+ result->ss_family = AF_UNSPEC;
+
+ if (NT_SUCCESS(status))
+ {
+ // The Registry API does not guarantee that the string will be
+ // null-terminated.
+ // 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,
+ resultV4
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ resultV4->S_un.S_addr = RtlUlongByteSwap(resultV4->S_un.S_addr);
+ result->ss_family = AF_INET;
+ }
+ else
+ {
+ status = RtlIpv6StringToAddressW(
+ value.Buffer,
+ &terminator,
+ resultV6
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ result->ss_family = AF_INET6;
+ }
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+DDProxyLoadConfig(
+ _In_ const WDFKEY key
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ DECLARE_CONST_UNICODE_STRING(inspectUdpValueName, L"InspectUdp");
+ DECLARE_CONST_UNICODE_STRING(destAddrValueName, L"DestinationAddressToIntercept");
+ DECLARE_CONST_UNICODE_STRING(destPortValueName, L"DestinationPortToIntercept");
+ DECLARE_CONST_UNICODE_STRING(newDestAddrValueName, L"NewDestinationAddress");
+ DECLARE_CONST_UNICODE_STRING(newDestPortValueName, L"NewDestinationPort");
+
+ ULONG ulongValue;
+
+ if (NT_SUCCESS(WdfRegistryQueryULong(
+ key,
+ &inspectUdpValueName,
+ &ulongValue
+ )))
+ {
+ configInspectUdp = (ulongValue != 0);
+ }
+
+
+ if (NT_SUCCESS(DDProxyLoadIPAddress(
+ key,
+ &destAddrValueName,
+ &destAddr
+ )))
+ {
+ if (destAddr.ss_family == AF_INET)
+ {
+ configInspectDestAddrV4 = &((SOCKADDR_IN*)&destAddr)->sin_addr.S_un.S_un_b.s_b1;
+ }
+ else if (destAddr.ss_family == AF_INET6)
+ {
+ configInspectDestAddrV6 = (UINT8*)(&((SOCKADDR_IN6*)&destAddr)->sin6_addr.u.Byte[0]);
+ }
+ }
+
+ if (NT_SUCCESS(WdfRegistryQueryULong(
+ key,
+ &destPortValueName,
+ &ulongValue
+ )))
+ {
+ configInspectDestPort = (USHORT) ulongValue;
+ }
+
+ if (NT_SUCCESS(DDProxyLoadIPAddress(
+ key,
+ &newDestAddrValueName,
+ &newDestAddr
+ )))
+ {
+ if (destAddr.ss_family == AF_INET)
+ {
+ configNewDestAddrV4 = &((SOCKADDR_IN*)&newDestAddr)->sin_addr.S_un.S_un_b.s_b1;
+ }
+ else if (destAddr.ss_family == AF_INET6)
+ {
+ configNewDestAddrV6 = (UINT8*)(&((SOCKADDR_IN6*)&newDestAddr)->sin6_addr.u.Byte[0]);
+ }
+ }
+
+ if (NT_SUCCESS(WdfRegistryQueryULong(
+ key,
+ &newDestPortValueName,
+ &ulongValue
+ )))
+ {
+ configNewDestPort = (USHORT) ulongValue;
+ }
+
+ return status;
+}
+
+NTSTATUS
+DDProxyAddFilter(
+ _In_ const PWSTR filterName,
+ _In_ const PWSTR filterDesc,
+ _In_reads_(16) const UINT8* remoteAddr,
+ _In_ USHORT remotePort,
+ _In_ FWP_DIRECTION direction,
+ _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 = DD_PROXY_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_DATAGRAM_DATA_V4) ||
+ IsEqualGUID(layerKey, &FWPM_LAYER_ALE_FLOW_ESTABLISHED_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++;
+ }
+
+ filterConditions[conditionIndex].fieldKey = FWPM_CONDITION_DIRECTION;
+ filterConditions[conditionIndex].matchType = FWP_MATCH_EQUAL;
+ filterConditions[conditionIndex].conditionValue.type = FWP_UINT32;
+ filterConditions[conditionIndex].conditionValue.uint32 = direction;
+
+ conditionIndex++;
+
+ if (configInspectUdp)
+ {
+ filterConditions[conditionIndex].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
+ filterConditions[conditionIndex].matchType = FWP_MATCH_EQUAL;
+ filterConditions[conditionIndex].conditionValue.type = FWP_UINT16;
+ filterConditions[conditionIndex].conditionValue.uint16 = remotePort;
+
+ conditionIndex++;
+ }
+
+ filter.numFilterConditions = conditionIndex;
+
+ status = FwpmFilterAdd(
+ gEngineHandle,
+ &filter,
+ NULL,
+ NULL);
+
+ return status;
+}
+
+NTSTATUS
+DDProxyRegisterFlowEstablishedCallouts(
+ _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 flow creations for the original and the proxy flows.
+
+ FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4
+ FWPM_LAYER_ALE_FLOW_ESTABLISHED_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 = DDProxyFlowEstablishedClassify;
+ sCallout.notifyFn = DDProxyFlowEstablishedNotify;
+
+ status = FwpsCalloutRegister(
+ deviceObject,
+ &sCallout,
+ calloutId
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ calloutRegistered = TRUE;
+
+ displayData.name = L"Datagram-Data Proxy Flow-Established Callout";
+ displayData.description =
+ L"Intercepts flow creations for the original and the proxy flows";
+
+ mCallout.calloutKey = *calloutKey;
+ mCallout.displayData = displayData;
+ mCallout.applicableLayer = *layerKey;
+
+ status = FwpmCalloutAdd(
+ gEngineHandle,
+ &mCallout,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyAddFilter(
+ L"Datagram-Data Proxy Flow-Established Filter (Original Flow)",
+ L"Intercepts flow creations for the original flow",
+ IsEqualGUID(layerKey, &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4) ?
+ configInspectDestAddrV4 : configInspectDestAddrV6,
+ configInspectDestPort,
+ FWP_DIRECTION_OUTBOUND,
+ DD_PROXY_FLOW_ORIGINAL,
+ layerKey,
+ calloutKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyAddFilter(
+ L"Datagram-Data Proxy Flow-Established Filter (Proxy Flow)",
+ L"Intercepts flow creations for the proxy flow",
+ IsEqualGUID(layerKey, &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4) ?
+ configNewDestAddrV4 : configNewDestAddrV6,
+ configNewDestPort,
+ FWP_DIRECTION_OUTBOUND,
+ DD_PROXY_FLOW_PROXY,
+ layerKey,
+ calloutKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (calloutRegistered)
+ {
+ FwpsCalloutUnregisterById(*calloutId);
+ *calloutId = 0;
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+DDProxyRegisterDatagramDataCallouts(
+ _In_ const GUID* layerKey,
+ _In_ const GUID* calloutKey,
+ _Inout_ void* deviceObject,
+ _Out_ UINT32* calloutId
+ )
+/* ++
+
+ This function registers callouts and filters that intercept TCP traffic at
+ WFP FWPM_LAYER_DATAGRAM_DATA_V4 or FWPM_LAYER_DATAGRAM_DATA_V6 layer.
+
+-- */
+{
+ 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 = DDProxyClassify;
+ sCallout.notifyFn = DDProxyNotify;
+ sCallout.flowDeleteFn = DDProxyFlowDelete;
+ sCallout.flags = FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW;
+
+ status = FwpsCalloutRegister(
+ deviceObject,
+ &sCallout,
+ calloutId
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ calloutRegistered = TRUE;
+
+ displayData.name = L"Datagram-Data Proxy Callout";
+ displayData.description = L"Proxies destination address/port for UDP/ICMP";
+
+ mCallout.calloutKey = *calloutKey;
+ mCallout.displayData = displayData;
+ mCallout.applicableLayer = *layerKey;
+
+ status = FwpmCalloutAdd(
+ gEngineHandle,
+ &mCallout,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyAddFilter(
+ L"Datagram-Data Proxy Filter (Outbound)",
+ L"Proxies destination address/port for UDP/ICMP",
+ IsEqualGUID(layerKey, &FWPM_LAYER_DATAGRAM_DATA_V4) ?
+ configInspectDestAddrV4 : configInspectDestAddrV6,
+ configInspectDestPort,
+ FWP_DIRECTION_OUTBOUND,
+ 0,
+ layerKey,
+ calloutKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyAddFilter(
+ L"Datagram-Data Proxy Filter (Inbound)",
+ L"Proxies destination address/port for UDP/ICMP",
+ IsEqualGUID(layerKey, &FWPM_LAYER_DATAGRAM_DATA_V4) ?
+ configNewDestAddrV4 : configNewDestAddrV6,
+ configNewDestPort,
+ FWP_DIRECTION_INBOUND,
+ 0,
+ layerKey,
+ calloutKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (calloutRegistered)
+ {
+ FwpsCalloutUnregisterById(*calloutId);
+ *calloutId = 0;
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+DDProxyRegisterCallouts(
+ _Inout_ void* deviceObject
+ )
+/* ++
+
+ This function registers dynamic callouts and filters that intercept UDP or
+ non-error ICMP traffic at WFP FWPM_LAYER_DATAGRAM_DATA_V{4|6} and
+ FWPM_LAYER_ALE_FLOW_ESTABLISHED_V{4|6} layers.
+
+ Callouts and filters will be removed during DriverUnload.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ FWPM_SUBLAYER DDProxySubLayer;
+
+ 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(&DDProxySubLayer, sizeof(FWPM_SUBLAYER));
+
+ DDProxySubLayer.subLayerKey = DD_PROXY_SUBLAYER;
+ DDProxySubLayer.displayData.name = L"Datagram-Data Proxy Sub-Layer";
+ DDProxySubLayer.displayData.description =
+ L"Sub-Layer for use by Datagram-Data Proxy callouts";
+ DDProxySubLayer.flags = 0;
+ DDProxySubLayer.weight = FWP_EMPTY; // auto-weight.;
+
+ status = FwpmSubLayerAdd(gEngineHandle, &DDProxySubLayer, NULL);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyRegisterFlowEstablishedCallouts(
+ &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4,
+ &DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V4,
+ deviceObject,
+ &gFlowEstablishedCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyRegisterFlowEstablishedCallouts(
+ &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6,
+ &DD_PROXY_FLOW_ESTABLISHED_CALLOUT_V6,
+ deviceObject,
+ &gFlowEstablishedCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyRegisterDatagramDataCallouts(
+ &FWPM_LAYER_DATAGRAM_DATA_V4,
+ &DD_PROXY_CALLOUT_V4,
+ deviceObject,
+ &gCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyRegisterDatagramDataCallouts(
+ &FWPM_LAYER_DATAGRAM_DATA_V6,
+ &DD_PROXY_CALLOUT_V6,
+ deviceObject,
+ &gCalloutIdV6
+ );
+ 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
+DDProxyUnregisterCallouts(void)
+{
+ FwpmEngineClose(gEngineHandle);
+ gEngineHandle = NULL;
+
+ FwpsCalloutUnregisterById(gCalloutIdV6);
+ FwpsCalloutUnregisterById(gCalloutIdV4);
+
+ FwpsCalloutUnregisterById(gFlowEstablishedCalloutIdV6);
+ FwpsCalloutUnregisterById(gFlowEstablishedCalloutIdV4);
+}
+
+void
+DDProxyRemoveFlows(void)
+{
+ while (!IsListEmpty(&gFlowList))
+ {
+ KLOCK_QUEUE_HANDLE flowListLockHandle;
+ LIST_ENTRY* listEntry = NULL;
+ DD_PROXY_FLOW_CONTEXT* flowContext;
+
+ KeAcquireInStackQueuedSpinLock(
+ &gFlowListLock,
+ &flowListLockHandle
+ );
+
+ if (!IsListEmpty(&gFlowList))
+ {
+ listEntry = RemoveHeadList(&gFlowList);
+ }
+
+ //
+ // Releasing the lock here since removing the flow context
+ // will invoke the callout's flowDeleteFn synchronously
+ // if there are no active classifications in progress.
+ //
+ KeReleaseInStackQueuedSpinLock(&flowListLockHandle);
+
+ if (listEntry != NULL)
+ {
+ flowContext = CONTAINING_RECORD(
+ listEntry,
+ DD_PROXY_FLOW_CONTEXT,
+ listEntry
+ );
+
+ flowContext->deleted = TRUE;
+
+ FwpsFlowRemoveContext(
+ flowContext->flowId,
+ flowContext->layerId,
+ flowContext->calloutId
+ );
+ }
+ }
+}
+
+_Function_class_(EVT_WDF_DRIVER_UNLOAD)
+_IRQL_requires_same_
+_IRQL_requires_max_(PASSIVE_LEVEL)
+void
+EvtDriverUnload(
+ _In_ WDFDRIVER driverObject
+ )
+{
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+ KLOCK_QUEUE_HANDLE flowListLockHandle;
+
+ UNREFERENCED_PARAMETER(driverObject);
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ KeAcquireInStackQueuedSpinLock(
+ &gFlowListLock,
+ &flowListLockHandle
+ );
+
+ gDriverUnloading = TRUE;
+
+ KeReleaseInStackQueuedSpinLock(&flowListLockHandle);
+
+ //
+ // Any associated flow contexts must be removed before
+ // a callout can be successfully unregistered.
+ //
+ DDProxyRemoveFlows();
+
+ if (IsListEmpty(&gPacketQueue))
+ {
+ KeSetEvent(
+ &gPacketQueueEvent,
+ IO_NO_INCREMENT,
+ FALSE
+ );
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+
+ NT_ASSERT(gThreadObj != NULL);
+
+ KeWaitForSingleObject(
+ gThreadObj,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ ObDereferenceObject(gThreadObj);
+
+ DDProxyUnregisterCallouts();
+
+ FwpsInjectionHandleDestroy(gInjectionHandle);
+}
+
+//
+// Create the minimal WDF Driver and Device objects required for a WFP callout
+// driver.
+//
+NTSTATUS
+DDProxyInitDriverObjects(
+ _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 = EvtDriverUnload;
+
+ 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;
+ WDFKEY configKey;
+ HANDLE threadHandle;
+
+ // Request NX Non-Paged Pool when available
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+
+ status = DDProxyInitDriverObjects(
+ driverObject,
+ registryPath,
+ &driver,
+ &device
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = WdfDriverOpenParametersRegistryKey(
+ driver,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &configKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = DDProxyLoadConfig(configKey);
+
+ if (!NT_SUCCESS(status))
+ {
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ goto Exit;
+ }
+
+ //
+ // To proxy UDP traffic, a new destination port or a pair of inspect and
+ // proxy ip address need to be pre-configured. To proxy UDP traffic, a
+ // pair of inspect and proxy ip addresses must be pre-configured.
+ //
+ if (configInspectUdp)
+ {
+ if ((configInspectDestPort == configNewDestPort) &&
+ (((configInspectDestAddrV4 == NULL) ||
+ (configNewDestAddrV4 == NULL)) &&
+ ((configInspectDestAddrV6 == NULL) ||
+ (configNewDestAddrV6 == NULL))))
+ {
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ goto Exit;
+ }
+ }
+ else
+ {
+ if (((configInspectDestAddrV4 == NULL) ||
+ (configNewDestAddrV4 == NULL)) &&
+ ((configInspectDestAddrV6 == NULL) ||
+ (configNewDestAddrV6 == NULL)))
+ {
+ status = STATUS_DEVICE_CONFIGURATION_ERROR;
+ goto Exit;
+ }
+ }
+
+ status = FwpsInjectionHandleCreate(
+ AF_UNSPEC,
+ FWPS_INJECTION_TYPE_TRANSPORT,
+ &gInjectionHandle
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ InitializeListHead(&gFlowList);
+ KeInitializeSpinLock(&gFlowListLock);
+
+ InitializeListHead(&gPacketQueue);
+ KeInitializeSpinLock(&gPacketQueueLock);
+ KeInitializeEvent(
+ &gPacketQueueEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ gWdmDevice = WdfDeviceWdmGetDeviceObject(device);
+
+ status = DDProxyRegisterCallouts(gWdmDevice);
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = PsCreateSystemThread(
+ &threadHandle,
+ THREAD_ALL_ACCESS,
+ NULL,
+ NULL,
+ NULL,
+ DDProxyWorker,
+ 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)
+ {
+ DDProxyUnregisterCallouts();
+ }
+ if (gInjectionHandle != NULL)
+ {
+ FwpsInjectionHandleDestroy(gInjectionHandle);
+ }
+ }
+
+ return status;
+}
diff --git a/network/trans/ddproxy/sys/DD_proxy.c b/network/trans/ddproxy/sys/DD_proxy.c
new file mode 100644
index 00000000..a75e2cf9
--- /dev/null
+++ b/network/trans/ddproxy/sys/DD_proxy.c
@@ -0,0 +1,1039 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ This file implements the classifyFn, notifiFn, and flowDeleteFn callout
+ functions for the flow-established and datagram-data callouts. In addition
+ the system worker thread that performs the actual packet modifications
+ is also implemented here along with the eventing mechanisms shared between
+ the classify function and the worker thread.
+
+ Packet modification is done out-of-band by a system worker thread using
+ the reference-drop-clone-modify-reinject mechanism. Therefore the sample
+ can serve as a base in scenarios where filtering/modification 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 "DD_proxy.h"
+
+__inline
+void
+DDProxyFreePendedPacket(
+ _Inout_ __drv_freesMem(Mem) DD_PROXY_PENDED_PACKET* packet,
+ _Inout_opt_ __drv_freesMem(Mem) WSACMSGHDR* controlData
+ )
+{
+ FwpsDereferenceNetBufferList(packet->netBufferList, FALSE);
+ DDProxyDereferenceFlowContext(packet->belongingFlow);
+ if (controlData != NULL)
+ {
+ ExFreePoolWithTag(controlData, DD_PROXY_CONTROL_DATA_POOL_TAG);
+ }
+ ExFreePoolWithTag(packet, DD_PROXY_PENDED_PACKET_POOL_TAG);
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+DDProxyFlowEstablishedClassify(
+ _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
+DDProxyFlowEstablishedClassify(
+ _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 of the flow-established callout. It
+ allocates flow context for the original and the proxy flow and associates
+ them with the indicated flow-id. This function also stores information
+ common to both flows in the context. The flow context is inserted into the
+ global flow list.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ BOOLEAN locked = FALSE;
+
+ KLOCK_QUEUE_HANDLE flowListLockHandle;
+
+ DD_PROXY_FLOW_CONTEXT* flowContextLocal = NULL;
+
+ UNREFERENCED_PARAMETER(layerData);
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(flowContext);
+
+ flowContextLocal = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(DD_PROXY_FLOW_CONTEXT),
+ DD_PROXY_FLOW_CONTEXT_POOL_TAG
+ );
+
+ if (flowContextLocal == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ RtlZeroMemory(flowContextLocal, sizeof(DD_PROXY_FLOW_CONTEXT));
+
+ flowContextLocal->refCount = 1;
+ flowContextLocal->flowType = (DD_PROXY_FLOW_TYPE)(filter->context);
+ flowContextLocal->addressFamily =
+ (inFixedValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4) ?
+ AF_INET : AF_INET6;
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_FLOW_HANDLE));
+ flowContextLocal->flowId = inMetaValues->flowHandle;
+
+ //
+ // Note that since the consumer of the flow context is the datagram-data
+ // layer classifyFn, layerId and calloutId are set to those of DD and not
+ // flow-established.
+ //
+ flowContextLocal->layerId =
+ (flowContextLocal->addressFamily == AF_INET) ?
+ FWPS_LAYER_DATAGRAM_DATA_V4 : FWPS_LAYER_DATAGRAM_DATA_V6;
+ flowContextLocal->calloutId =
+ (flowContextLocal->addressFamily == AF_INET) ?
+ gCalloutIdV4 : gCalloutIdV6;
+
+ if (flowContextLocal->addressFamily == AF_INET)
+ {
+ // 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.
+ flowContextLocal->ipv4LocalAddr =
+ RtlUlongByteSwap(
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS].value.uint32
+ );
+ flowContextLocal->protocol =
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8;
+ }
+ else
+ {
+ RtlCopyMemory(
+ (UINT8*)&flowContextLocal->localAddr,
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_ADDRESS].value.byteArray16,
+ sizeof(FWP_BYTE_ARRAY16)
+ );
+ flowContextLocal->protocol =
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL].value.uint8;
+ }
+
+ if (flowContextLocal->flowType == DD_PROXY_FLOW_ORIGINAL)
+ {
+ flowContextLocal->toRemoteAddr =
+ (flowContextLocal->addressFamily == AF_INET) ?
+ configNewDestAddrV4 : configNewDestAddrV6;
+ // host-order -> network-order conversion for port.
+ flowContextLocal->toRemotePort = RtlUshortByteSwap(configNewDestPort);
+ }
+ else
+ {
+ NT_ASSERT(flowContextLocal->flowType == DD_PROXY_FLOW_PROXY);
+ flowContextLocal->toRemoteAddr =
+ (flowContextLocal->addressFamily == AF_INET) ?
+ configInspectDestAddrV4 : configInspectDestAddrV6;
+ // host-order -> network-order conversion for port.
+ // See PREfast comments above. Opaque pointer tricks PREfast.
+ flowContextLocal->toRemotePort = RtlUshortByteSwap(configInspectDestPort);
+ }
+ if ((flowContextLocal->toRemoteAddr != NULL) &&
+ (flowContextLocal->addressFamily == AF_INET))
+ {
+ // host-order -> network-order conversion for Ipv4 address.
+ // See PREfast comments above. Opaque pointer tricks PREfast.
+ flowContextLocal->ipv4NetworkOrderStorage =
+ RtlUlongByteSwap(*(ULONG*)(flowContextLocal->toRemoteAddr));
+ flowContextLocal->toRemoteAddr =
+ (UINT8*)&flowContextLocal->ipv4NetworkOrderStorage;
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gFlowListLock,
+ &flowListLockHandle
+ );
+
+ locked = TRUE;
+
+ if (!gDriverUnloading)
+ {
+ //
+ // Associate DD_PROXY_FLOW_CONTEXT with the indicated flow-id to be
+ // accessible by the Datagram-Data classifyFn. (i.e. when a packet
+ // belongs to the same flow being classified at Datagram-Data layer,
+ // DD_PROXY_FLOW_CONTEXT will be passed onto the classifyFn as the
+ // "flowContext" parameter.
+ //
+ status = FwpsFlowAssociateContext(
+ flowContextLocal->flowId,
+ flowContextLocal->layerId,
+ flowContextLocal->calloutId,
+ (UINT64)flowContextLocal
+ );
+ if(!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ InsertHeadList(&gFlowList, &flowContextLocal->listEntry);
+ flowContextLocal = NULL; // ownership transferred
+ }
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+
+Exit:
+
+ if(locked)
+ {
+ KeReleaseInStackQueuedSpinLock(&flowListLockHandle);
+ }
+
+ if (flowContextLocal != NULL)
+ {
+ ExFreePoolWithTag(flowContextLocal, DD_PROXY_FLOW_CONTEXT_POOL_TAG);
+ }
+
+ if(!NT_SUCCESS(status))
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ return;
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+DDProxyClassify(
+ _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
+DDProxyClassify(
+ _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 of the datagram-data callout. It
+ allocates a packet structure to store the classify and meta data and
+ it references the net buffer list for out-of-band modification and
+ re-injection. The packet structure will be queued to the global packet
+ queue. The worker thread will then be signaled, if idle, to process
+ the queue.
+
+-- */
+{
+ DD_PROXY_PENDED_PACKET* packet = NULL;
+ DD_PROXY_FLOW_CONTEXT* flowContextLocal = (DD_PROXY_FLOW_CONTEXT*)(DWORD_PTR)flowContext;
+
+ FWPS_PACKET_INJECTION_STATE packetState;
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+ BOOLEAN signalWorkerThread;
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif
+ UNREFERENCED_PARAMETER(filter);
+
+ _Analysis_assume_(layerData != NULL);
+
+ //
+ // We don't have the necessary right to alter the packet.
+ //
+ if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
+ {
+ goto Exit;
+ }
+
+ //
+ // 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;
+ }
+
+ packet = ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(DD_PROXY_PENDED_PACKET),
+ DD_PROXY_PENDED_PACKET_POOL_TAG
+ );
+
+ if (packet == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ RtlZeroMemory(packet, sizeof(DD_PROXY_PENDED_PACKET));
+
+ NT_ASSERT(flowContextLocal != NULL);
+
+ packet->belongingFlow = flowContextLocal;
+ DDProxyReferenceFlowContext(packet->belongingFlow);
+ if (flowContextLocal->addressFamily == AF_INET)
+ {
+ NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4);
+ packet->direction =
+ inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].\
+ value.uint32;
+ }
+ else
+ {
+ NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6);
+ packet->direction =
+ inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_DIRECTION].\
+ value.uint32;
+ }
+ packet->netBufferList = layerData;
+
+ //
+ // Reference the net buffer list to make it accessible outside of
+ // classifyFn.
+ //
+ FwpsReferenceNetBufferList(packet->netBufferList, TRUE);
+
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
+ FWPS_METADATA_FIELD_COMPARTMENT_ID));
+ packet->compartmentId = inMetaValues->compartmentId;
+
+ if (packet->direction == FWP_DIRECTION_OUTBOUND)
+ {
+ NT_ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE));
+ packet->endpointHandle = inMetaValues->transportEndpointHandle;
+
+ if (flowContextLocal->addressFamily == AF_INET)
+ {
+ // See PREfast comments above. Opaque pointer tricks PREfast.
+ packet->ipv4RemoteAddr =
+ RtlUlongByteSwap( /* host-order -> network-order conversion */
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_ADDRESS].value.uint32
+ );
+ }
+ else
+ {
+ RtlCopyMemory(
+ (UINT8*)&packet->remoteAddr,
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_DATAGRAM_DATA_V6_IP_REMOTE_ADDRESS].value.byteArray16,
+ sizeof(FWP_BYTE_ARRAY16)
+ );
+
+ }
+ packet->remoteScopeId = inMetaValues->remoteScopeId;
+
+ if (FWPS_IS_METADATA_FIELD_PRESENT(
+ inMetaValues,
+ FWPS_METADATA_FIELD_TRANSPORT_CONTROL_DATA))
+ {
+ NT_ASSERT(inMetaValues->controlDataLength > 0);
+
+ packet->controlData = ExAllocatePoolWithTag(
+ NonPagedPool,
+ inMetaValues->controlDataLength,
+ DD_PROXY_CONTROL_DATA_POOL_TAG
+ );
+ if (packet->controlData == NULL)
+ {
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ goto Exit;
+ }
+
+ RtlCopyMemory(
+ packet->controlData,
+ inMetaValues->controlData,
+ inMetaValues->controlDataLength
+ );
+
+ packet->controlDataLength = inMetaValues->controlDataLength;
+ }
+ }
+ else
+ {
+ NT_ASSERT(packet->direction == FWP_DIRECTION_INBOUND);
+
+ if (flowContextLocal->addressFamily == AF_INET)
+ {
+ NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4);
+ packet->interfaceIndex =
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_DATAGRAM_DATA_V4_INTERFACE_INDEX].value.uint32;
+ packet->subInterfaceIndex =
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_DATAGRAM_DATA_V4_SUB_INTERFACE_INDEX].value.uint32;
+ }
+ else
+ {
+ NT_ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6);
+ packet->interfaceIndex =
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_DATAGRAM_DATA_V6_INTERFACE_INDEX].value.uint32;
+ packet->subInterfaceIndex =
+ inFixedValues->incomingValue\
+ [FWPS_FIELD_DATAGRAM_DATA_V6_SUB_INTERFACE_INDEX].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));
+ packet->ipHeaderSize = inMetaValues->ipHeaderSize;
+ packet->transportHeaderSize = inMetaValues->transportHeaderSize;
+
+ packet->nblOffset =
+ NET_BUFFER_DATA_OFFSET(NET_BUFFER_LIST_FIRST_NB(packet->netBufferList));
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (!gDriverUnloading)
+ {
+ signalWorkerThread = IsListEmpty(&gPacketQueue);
+
+ InsertTailList(&gPacketQueue, &packet->listEntry);
+ packet = 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 incoming packets.
+ //
+ signalWorkerThread = FALSE;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ }
+
+ if (signalWorkerThread)
+ {
+ KeSetEvent(
+ &gPacketQueueEvent,
+ 0,
+ FALSE
+ );
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+
+Exit:
+
+ if (packet != NULL)
+ {
+ DDProxyFreePendedPacket(packet, packet->controlData);
+ }
+
+ return;
+}
+
+NTSTATUS
+DDProxyFlowEstablishedNotify(
+ _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
+DDProxyNotify(
+ _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
+DDProxyFlowDelete(
+ _In_ UINT16 layerId,
+ _In_ UINT32 calloutId,
+ _In_ UINT64 flowContext
+ )
+/* ++
+
+ This is the flowDeleteFn function of the datagram-data callout. It
+ removes the flow context from the global flow list and dereference the
+ context.
+
+-- */
+{
+ DD_PROXY_FLOW_CONTEXT* flowContextLocal = (DD_PROXY_FLOW_CONTEXT*)(DWORD_PTR)flowContext;
+
+ KLOCK_QUEUE_HANDLE flowListLockHandle;
+
+ UNREFERENCED_PARAMETER(layerId);
+ UNREFERENCED_PARAMETER(calloutId);
+
+ KeAcquireInStackQueuedSpinLock(
+ &gFlowListLock,
+ &flowListLockHandle
+ );
+
+ if (!flowContextLocal->deleted)
+ {
+ RemoveEntryList(&flowContextLocal->listEntry);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&flowListLockHandle);
+
+ DDProxyDereferenceFlowContext(flowContextLocal);
+}
+
+typedef struct UDP_HEADER_ {
+ UINT16 srcPort;
+ UINT16 destPort;
+ UINT16 length;
+ UINT16 checksum;
+} UDP_HEADER;
+
+void DDProxyInjectComplete(
+ _Inout_ void* context,
+ _Inout_ NET_BUFFER_LIST* netBufferList,
+ _In_ BOOLEAN dispatchLevel
+ )
+{
+ DD_PROXY_PENDED_PACKET* packet = context;
+ UNREFERENCED_PARAMETER(dispatchLevel);
+
+ FwpsFreeCloneNetBufferList(netBufferList, 0);
+
+ DDProxyFreePendedPacket(packet, packet->controlData);
+}
+
+NTSTATUS
+DDProxyCloneModifyReinjectOutbound(
+ _In_ DD_PROXY_PENDED_PACKET* packet
+ )
+/* ++
+
+ This function clones the outbound net buffer list and, if needed,
+ modifies the destination port of all indicated packets (i.e. NET_BUFFER)
+ and/or send-injects the clone to a new destination address.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ NET_BUFFER_LIST* clonedNetBufferList = NULL;
+ UDP_HEADER* udpHeader;
+ FWPS_TRANSPORT_SEND_PARAMS sendArgs = {0};
+
+ status = FwpsAllocateCloneNetBufferList(
+ packet->netBufferList,
+ NULL,
+ NULL,
+ 0,
+ &clonedNetBufferList
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ //
+ // Check to see if port modification is required.
+ //
+ if ((packet->belongingFlow->protocol == IPPROTO_UDP) &&
+ (packet->belongingFlow->toRemotePort != 0))
+ {
+ NET_BUFFER* netBuffer;
+
+ //
+ // The data offset of outbound transport packets is the beginning of
+ // transport header (e.g. UDP header). The IP header has not yet been
+ // constructed at Datagram-Data (or outbound Transport) layer.
+ //
+ // Note the packet offset is inherited by the clone.
+ //
+
+ //
+ // Outbound net buffer list can contain more than one net buffer (e.g.
+ // one UDP packet).
+ //
+
+ for (netBuffer = NET_BUFFER_LIST_FIRST_NB(clonedNetBufferList);
+ netBuffer != NULL;
+ netBuffer = NET_BUFFER_NEXT_NB(netBuffer))
+ {
+ udpHeader = NdisGetDataBuffer(
+ netBuffer,
+ sizeof(UDP_HEADER),
+ NULL,
+ sizeof(UINT16),
+ 0
+ );
+ NT_ASSERT(udpHeader != NULL); // We can assume UDP header in a net buffer
+ // is contiguous and 2-byte aligned.
+ _Analysis_assume_(udpHeader != NULL);
+
+ udpHeader->destPort = packet->belongingFlow->toRemotePort;
+ udpHeader->checksum = 0;
+ }
+ }
+
+ //
+ // Determine whehter we need to proxy the destination address. If not,
+ // we set the remoteAddress to the same address that was initially
+ // classified.
+ //
+ sendArgs.remoteAddress =
+ (packet->belongingFlow->toRemoteAddr ? packet->belongingFlow->toRemoteAddr
+ : (UINT8*)&packet->remoteAddr);
+ sendArgs.remoteScopeId = packet->remoteScopeId;
+ sendArgs.controlData = packet->controlData;
+ sendArgs.controlDataLength = packet->controlDataLength;
+
+ //
+ // Send-inject the modified net buffer list to the new destination address.
+ //
+
+ status = FwpsInjectTransportSendAsync(
+ gInjectionHandle,
+ NULL,
+ packet->endpointHandle,
+ 0,
+ &sendArgs,
+ packet->belongingFlow->addressFamily,
+ packet->compartmentId,
+ clonedNetBufferList,
+ DDProxyInjectComplete,
+ 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
+DDProxyCloneModifyReinjectInbound(
+ _In_ DD_PROXY_PENDED_PACKET* packet
+ )
+/* ++
+
+ This function clones the inbound net buffer list and, if needed,
+ modifies the source port and/or source address and receive-injects
+ the clone back to the tcpip stack.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ NET_BUFFER_LIST* clonedNetBufferList = NULL;
+ NET_BUFFER* netBuffer;
+ UDP_HEADER* udpHeader;
+ 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;
+ }
+
+ //
+ // Check to see if port modification is required.
+ //
+ if ((packet->belongingFlow->protocol == IPPROTO_UDP) &&
+ (packet->belongingFlow->toRemotePort != 0))
+ {
+ netBuffer = NET_BUFFER_LIST_FIRST_NB(clonedNetBufferList);
+
+ //
+ // Advance to the beginning of the transport header (i.e. UDP header).
+ //
+ NdisAdvanceNetBufferDataStart(
+ netBuffer,
+ packet->ipHeaderSize,
+ FALSE,
+ NULL
+ );
+
+ udpHeader = NdisGetDataBuffer(
+ netBuffer,
+ sizeof(UDP_HEADER),
+ NULL,
+ sizeof(UINT16),
+ 0
+ );
+ NT_ASSERT(udpHeader != NULL); // We can assume UDP header in a net buffer
+ // is contiguous and 2-byte aligned.
+ _Analysis_assume_(udpHeader != NULL);
+
+ udpHeader->destPort =
+ packet->belongingFlow->toRemotePort;
+ // This is our new source port -- or
+ // the destination port of the original
+ // outbound traffic.
+ udpHeader->checksum = 0;
+
+ //
+ // Undo the advance. Net buffer list needs to be positioned at the
+ // beginning of IP header for address modification and/or receive-
+ // injection.
+ //
+ ndisStatus = NdisRetreatNetBufferDataStart(
+ netBuffer,
+ packet->ipHeaderSize,
+ 0,
+ NULL
+ );
+ _Analysis_assume_(ndisStatus == NDIS_STATUS_SUCCESS);
+
+ }
+
+ if (packet->belongingFlow->toRemoteAddr != NULL)
+ {
+ status = FwpsConstructIpHeaderForTransportPacket(
+ clonedNetBufferList,
+ packet->ipHeaderSize,
+ packet->belongingFlow->addressFamily,
+ packet->belongingFlow->toRemoteAddr,
+ // This is our new source address --
+ // or the destination address of the
+ // original outbound traffic.
+ (UINT8*)&packet->belongingFlow->localAddr,
+ // This is the destination address of
+ // the clone -- or the source of the
+ // original outbound traffic.
+ packet->belongingFlow->protocol,
+ 0,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ 0,
+ 0
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+ status = FwpsInjectTransportReceiveAsync(
+ gInjectionHandle,
+ NULL,
+ NULL,
+ 0,
+ packet->belongingFlow->addressFamily,
+ packet->compartmentId,
+ packet->interfaceIndex,
+ packet->subInterfaceIndex,
+ clonedNetBufferList,
+ DDProxyInjectComplete,
+ 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
+DDProxyWorker(
+ _In_ void* StartContext
+ )
+/* ++
+
+ This worker thread waits for the packet queue event when the queue is
+ empty; and it will be woken up when there are packets queued needing to
+ be proxied to or from the new destination address/port. Once awaking,
+ It will run in a loop to clone-modify-reinject packets until the packet
+ queue is exhausted (and it will go to sleep waiting for more work).
+
+ The worker thread will end once it detected the driver is unloading.
+
+-- */
+{
+ DD_PROXY_PENDED_PACKET* packet;
+ LIST_ENTRY* listEntry;
+ KLOCK_QUEUE_HANDLE packetQueueLockHandle;
+
+ UNREFERENCED_PARAMETER(StartContext);
+
+ for(;;)
+ {
+ KeWaitForSingleObject(
+ &gPacketQueueEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ if (gDriverUnloading)
+ {
+ break;
+ }
+
+ NT_ASSERT(!IsListEmpty(&gPacketQueue));
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ listEntry = RemoveHeadList(&gPacketQueue);
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+
+ packet = CONTAINING_RECORD(
+ listEntry,
+ DD_PROXY_PENDED_PACKET,
+ listEntry
+ );
+
+ if (!packet->belongingFlow->deleted)
+ {
+ NTSTATUS status;
+
+ if (packet->direction == FWP_DIRECTION_OUTBOUND)
+ {
+ status = DDProxyCloneModifyReinjectOutbound(packet);
+ }
+ else
+ {
+ status = DDProxyCloneModifyReinjectInbound(packet);
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ packet = NULL; // ownership transferred.
+ }
+ }
+
+ if (packet != NULL)
+ {
+ DDProxyFreePendedPacket(packet, packet->controlData);
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ if (IsListEmpty(&gPacketQueue) && !gDriverUnloading)
+ {
+ KeClearEvent(&gPacketQueueEvent);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ }
+
+ NT_ASSERT(gDriverUnloading);
+
+ //
+ // Discard all the pended packets if driver is being unloaded.
+ //
+
+ KeAcquireInStackQueuedSpinLock(
+ &gPacketQueueLock,
+ &packetQueueLockHandle
+ );
+
+ while (!IsListEmpty(&gPacketQueue))
+ {
+ listEntry = RemoveHeadList(&gPacketQueue);
+
+ packet = CONTAINING_RECORD(
+ listEntry,
+ DD_PROXY_PENDED_PACKET,
+ listEntry
+ );
+
+ DDProxyFreePendedPacket(packet, packet->controlData);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
+ PsTerminateSystemThread(STATUS_SUCCESS);
+
+
+}
diff --git a/network/trans/ddproxy/sys/DD_proxy.h b/network/trans/ddproxy/sys/DD_proxy.h
new file mode 100644
index 00000000..197b0ff9
--- /dev/null
+++ b/network/trans/ddproxy/sys/DD_proxy.h
@@ -0,0 +1,251 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ This header files declares common data types and function prototypes used
+ throughout the Datagram-Data transparent proxy sample.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#ifndef _DD_PROXY_H_
+#define _DD_PROXY_H_
+
+typedef enum DD_PROXY_FLOW_TYPE_
+{
+ DD_PROXY_FLOW_ORIGINAL,
+ DD_PROXY_FLOW_PROXY
+} DD_PROXY_FLOW_TYPE;
+
+//
+// DD_PROXY_FLOW_CONTEXT is the object type we used to stored information
+// specific flow. This callout driver maintains two kind of flow contexts --
+// the original flow and the flow being proxied to.
+//
+
+typedef struct DD_PROXY_FLOW_CONTEXT_
+{
+ LIST_ENTRY listEntry;
+
+ BOOLEAN deleted;
+
+ DD_PROXY_FLOW_TYPE flowType;
+ ADDRESS_FAMILY addressFamily;
+
+ #pragma warning(push)
+ #pragma warning(disable: 4201) //NAMELESS_STRUCT_UNION
+ union
+ {
+ FWP_BYTE_ARRAY16 localAddr;
+ UINT32 ipv4LocalAddr;
+ };
+ #pragma warning(pop)
+
+
+ UINT8 protocol;
+
+ UINT64 flowId;
+ UINT16 layerId;
+ UINT32 calloutId;
+
+ UINT32 ipv4NetworkOrderStorage;
+
+ //
+ // For DD_PROXY_FLOW_ORIGINAL type, toRemote* is the new address/port
+ // we are proxing to. For DD_PROXY_FLOW_PROXY type, it is the address/
+ // port that we will need to revert to.
+ //
+ UINT8* toRemoteAddr;
+ UINT16 toRemotePort;
+
+ LONG refCount;
+} DD_PROXY_FLOW_CONTEXT;
+
+//
+// DD_PROXY_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.
+
+typedef struct DD_PROXY_PENDED_PACKET_
+{
+ LIST_ENTRY listEntry;
+
+ DD_PROXY_FLOW_CONTEXT* belongingFlow;
+ FWP_DIRECTION direction;
+
+ //
+ // Common fields for inbound and outbound traffic.
+ //
+ NET_BUFFER_LIST* netBufferList;
+ COMPARTMENT_ID compartmentId;
+
+ //
+ // Data fields for outbound packet re-injection.
+ //
+ UINT64 endpointHandle;
+
+ #pragma warning(push)
+ #pragma warning(disable: 4201) //NAMELESS_STRUCT_UNION
+ union
+ {
+ FWP_BYTE_ARRAY16 remoteAddr;
+ UINT32 ipv4RemoteAddr;
+ };
+ #pragma warning(pop)
+
+ SCOPE_ID remoteScopeId;
+ WSACMSGHDR* controlData;
+ ULONG controlDataLength;
+
+ //
+ // Data fields for inbound packet re-injection.
+ //
+ ULONG nblOffset;
+ UINT32 ipHeaderSize;
+ UINT32 transportHeaderSize;
+ IF_INDEX interfaceIndex;
+ IF_INDEX subInterfaceIndex;
+} DD_PROXY_PENDED_PACKET;
+
+//
+// Pooltags used by this callout driver.
+//
+#define DD_PROXY_FLOW_CONTEXT_POOL_TAG 'olfD'
+#define DD_PROXY_PENDED_PACKET_POOL_TAG 'kppD'
+#define DD_PROXY_CONTROL_DATA_POOL_TAG 'dcdD'
+
+//
+// Shared global data.
+//
+extern UINT16 configInspectDestPort;
+extern UINT8* configInspectDestAddrV4;
+extern UINT8* configInspectDestAddrV6;
+
+extern UINT16 configNewDestPort;
+extern UINT8* configNewDestAddrV4;
+extern UINT8* configNewDestAddrV6;
+
+extern HANDLE gInjectionHandle;
+
+extern LIST_ENTRY gFlowList;
+extern KSPIN_LOCK gFlowListLock;
+
+extern LIST_ENTRY gPacketQueue;
+extern KSPIN_LOCK gPacketQueueLock;
+extern KEVENT gPacketQueueEvent;
+
+extern UINT32 gCalloutIdV4;
+extern UINT32 gCalloutIdV6;
+
+extern BOOLEAN gDriverUnloading;
+
+//
+// Utility functions
+//
+
+__inline void
+DDProxyReferenceFlowContext(
+ _Inout_ DD_PROXY_FLOW_CONTEXT* flowContext
+ )
+{
+ NT_ASSERT(flowContext->refCount > 0);
+ InterlockedIncrement(&flowContext->refCount);
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+__inline
+void
+DDProxyDereferenceFlowContext(
+ _Inout_ DD_PROXY_FLOW_CONTEXT* flowContext
+ )
+{
+ NT_ASSERT(flowContext->refCount > 0);
+ InterlockedDecrement(&flowContext->refCount);
+ if (flowContext->refCount == 0)
+ {
+ ExFreePoolWithTag(flowContext, DD_PROXY_FLOW_CONTEXT_POOL_TAG);
+ }
+}
+
+//
+// Shared function prototypes
+//
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+DDProxyFlowEstablishedClassify(
+ _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
+DDProxyClassify(
+ _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
+DDProxyFlowEstablishedClassify(
+ _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
+DDProxyClassify(
+ _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)
+
+void
+DDProxyFlowDelete(
+ _In_ UINT16 layerId,
+ _In_ UINT32 calloutId,
+ _In_ UINT64 flowContext
+ );
+
+NTSTATUS
+DDProxyFlowEstablishedNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ );
+
+
+NTSTATUS
+DDProxyNotify(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter
+ );
+
+KSTART_ROUTINE DDProxyWorker;
+
+#endif // _DD_PROXY_H_
diff --git a/network/trans/ddproxy/sys/ddproxy.inf b/network/trans/ddproxy/sys/ddproxy.inf
new file mode 100644
index 00000000..dd504967
--- /dev/null
+++ b/network/trans/ddproxy/sys/ddproxy.inf
@@ -0,0 +1,63 @@
+;;;
+;;; Copyright (c) Microsoft Corporation. All rights reserved
+;;;
+;;; Abstract:
+;;; DatagramData Proxy Callout sample driver install configuration.
+;;;
+
+[Version]
+ Signature = "$Windows NT$"
+ Class = WFPCALLOUTS
+ ClassGuid = {57465043-616C-6C6F-7574-5F636C617373}
+ Provider = %Contoso%
+ CatalogFile = DDProxy.cat
+ DriverVer = 11/24/2014,14.24.55.836
+
+[SourceDisksNames]
+ 1 = %DDProxyDisk%,,,""
+
+[SourceDisksFiles]
+ DDProxy.sys = 1,,
+
+[DestinationDirs]
+ DefaultDestDir = 12 ; %WinDir%\System32\Drivers
+ DDProxy.DriverFiles = 12 ; %WinDir%\System32\Drivers
+
+[DefaultInstall]
+ OptionDesc = %DDProxyServiceDesc%
+ CopyFiles = DDProxy.DriverFiles
+
+[DefaultInstall.Services]
+ AddService = %DDProxyServiceName%,,DDProxy.Service
+
+[DefaultUninstall]
+ DelFiles = DDProxy.DriverFiles
+
+[DefaultUninstall.Services]
+ DelService = %DDProxyServiceName%,0x200 ; SPSVCINST_STOPSERVICE
+ DelReg = DDProxy.DelRegistry
+
+[DDProxy.DriverFiles]
+ DDProxy.sys,,,0x00000040 ; COPYFLG_OVERWRITE_OLDER_ONLY
+
+[DDProxy.Service]
+ DisplayName = %DDProxyServiceName%
+ Description = %DDProxyServiceDesc%
+ ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+ StartType = 3 ; SERVICE_DEMAND_START
+ ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ ServiceBinary = %12%\DDProxy.sys ; %WinDir%\System32\Drivers\DDProxy.sys
+ AddReg = DDProxy.AddRegistry
+
+[DDProxy.AddRegistry]
+ HKR,"Parameters","DestinationAddressToIntercept",0x00000000,"10.0.0.1" ; FLG_ADDREG_TYPE_SZ
+ HKR,"Parameters","NewDestinationAddress",0x00000000,"10.0.0.2" ; FLG_ADDREG_TYPE_SZ
+
+[DDProxy.DelRegistry]
+ HKR,"Parameters",,,
+
+[Strings]
+ Contoso = "Contoso Ltd."
+ DDProxyDisk = "DatagramData Proxy Installation Disk"
+ DDProxyServiceDesc = "DatagramData Proxy Callout Driver"
+ DDProxyServiceName = "DDProxy" \ No newline at end of file
diff --git a/network/trans/ddproxy/sys/ddproxy.vcxproj b/network/trans/ddproxy/sys/ddproxy.vcxproj
new file mode 100644
index 00000000..9fd6e6af
--- /dev/null
+++ b/network/trans/ddproxy/sys/ddproxy.vcxproj
@@ -0,0 +1,185 @@
+<?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>{F5ED1745-0947-474A-924D-CB5D3D2D6C5E}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{91B8C3EC-EC68-40D0-BDAE-FECDC2A5A69E}</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>ddproxy</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>ddproxy</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>ddproxy</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>ddproxy</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)\ntoskrnl.lib;$(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)\ntoskrnl.lib;$(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)\ntoskrnl.lib;$(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)\ntoskrnl.lib;$(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="dd_drv.c" />
+ <ClCompile Include="dd_proxy.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/ddproxy/sys/ddproxy.vcxproj.Filters b/network/trans/ddproxy/sys/ddproxy.vcxproj.Filters
new file mode 100644
index 00000000..9728a6bb
--- /dev/null
+++ b/network/trans/ddproxy/sys/ddproxy.vcxproj.Filters
@@ -0,0 +1,29 @@
+<?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>{667070D4-ABD3-4134-83D9-C2E8E3B4D990}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{55D8461C-9BC4-4CBA-8364-1C9E8628AD2E}</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>{89C687B6-C04D-48DD-BFC4-36AB091E7E94}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{3E15A537-E520-445D-AFC4-4CFCEF6234E6}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="dd_drv.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dd_proxy.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
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_
diff --git a/network/trans/msnmntr/ReadMe.md b/network/trans/msnmntr/ReadMe.md
new file mode 100644
index 00000000..9f247ff5
--- /dev/null
+++ b/network/trans/msnmntr/ReadMe.md
@@ -0,0 +1,79 @@
+Windows Filtering Platform MSN Messenger Monitor Sample
+=======================================================
+
+This sample application and driver demonstrate the stream inspection capabilities of the Windows Filtering Platform (WFP).
+
+The sample consists of a user mode application (Monitor.exe) that registers traffic of interest. In this case, all Transmission Control Protocol (TCP) data segments that are sent and received by an application of your choice.
+
+**Note**  Originally this sample was written to monitor the MSN Messenger application. Now it can monitor any application that you specify.
+
+Monitor.exe adds filters and callouts to Windows through the Windows Filtering Platform (WFP) Win32 API. A kernel-mode WFP callout driver (Msnmntr.sys) intercepts TCP traffic and parses out communication patterns. Monitor.exe controls the operations of the callout driver through I/O controls (IOCTLs).
+
+The filters and callouts added by Monitor.exe are persistent across system restarts and removed only by Monitor.exe. Adding filters and callouts requires administrator privileges. Therefore, Monitor.exe must be run from an elevated command prompt.
+
+Msnmntr.sys registers itself at two different WFP layers: FLOW-ESTABLISHED and STREAM. For simplicity, only Internet Protocol version 4 (IPv4) traffic is inspected. Msnmntr.sys registers at the FLOW-ESTABLISHED layer to associate a callout driver-specific data structure with application identity (that is, path) recorded such that the STREAM layer will only be invoked if traffic is sent or received from that particular application.
+
+After the filters and callouts are in place and registered, WFP indicates TCP data segments to the Msnmntr.sys for inspection. As the data flows through Msnmntr.sys, it copies them (described by a chain of NET\_BUFFER\_LIST structures) to a flat buffer, parses out the communication patterns (such as client-to-server/client-to-client), and sends them to the Windows Software Trace Preprocessor (WPP) for tracing.
+
+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 msnmntr.inf. Right click msnmntr.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:\\WfpMsnMessengerMonitorSamplePackage).
+2. On the target computer, navigate to your driver package folder. Right click msnmntr.inf, and choose **Install**
+
+Copy additional files to the target computer
+--------------------------------------------
+
+Copy the user-mode application, monitor.exe to a folder on the target computer (for example, c:\\WfpMsnMessengerMonitorSampleApp).
+
+Copy the PDB file, msnmntr.pdb to a folder on the target computer (for example, c:\\Symbols).
+
+Copy the tool TraceView.exe to a folder on the target computer (for example c:\\Tools). TraceView.exe comes with the WDK. You can find it in your WDK installation folder under Tools (for example, c:\\Program Files (x86)\\Windows Kits\\8.1\\Tools\\x64\\TraceView.exe).
+
+Start the msnmntr service
+-------------------------
+
+On the target computer, open a Command Prompt window as Administrator, and enter **net start msnmntr**. (To stop the driver, enter **net stop msnmntr**.)
+
+Running the user-mode application
+---------------------------------
+
+On the target computer, open a Command Prompt window as Administrator, and navigate to the folder that contains monitor.exe. Enter **monitor.exe addcallouts**. Then enter **monitor.exe monitor** *TargetAppPath*, where *TargetAppPath* is the path to the application that you want to monitor. Here is an example that initiates monitoring of Internet Explorer.
+
+``` {.syntax xml:space="preserve"}
+monitor.exe addcallouts
+monitor.exe monitor "C:\Program Files (x86)\Internet Explorer\iexplore.exe"
+```
+
+Start a logging session in TraceView
+------------------------------------
+
+On the target computer, open TraceView.exe as Administrator. On the **File** menu, choose **Create New Log Session**. Click **Add Provider**. Select **PDB (Debug Information File)**, and enter the path to your PDB file, msnmntr.pdb. Click **OK**, and finish working through the setup procedure. Open Internet Explorer, and watch the communication patterns being displayed in the Traceview.exe tool.
+
+Tracing for the sample driver can be started at any time before the driver is started or while the driver is already running.
+
+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).
+
+Using MSBuild
+-------------
+
+As an alternative to building the WFP MSN Messenger Monitor Sample in Visual Studio, you can build it in a Visual Studio Command Prompt window. In Visual Studio, on the **Tools** menu, choose **Visual Studio Command Prompt**. In the Visual Studio Command Prompt window, navigate to the folder that has the solution file, msnmntr.sln. Use the [MSBuild](http://go.microsoft.com/fwlink/p/?linkID=262804) command to build the solution. Here are some examples:
+
+**msbuild /p:configuration=”Win7 Debug” /p:platform=”x64” msnmntr.sln**
+
+**msbuild /p:configuration=”Win8 Release” /p:platform=”win32” msnmntr.sln**
+
+For more information about using [MSBuild](http://go.microsoft.com/fwlink/p/?linkID=262804) to build a driver package, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644).
+
diff --git a/network/trans/msnmntr/exe/monitor.cpp b/network/trans/msnmntr/exe/monitor.cpp
new file mode 100644
index 00000000..def6625c
--- /dev/null
+++ b/network/trans/msnmntr/exe/monitor.cpp
@@ -0,0 +1,715 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream monitor sample executable
+
+Environment:
+
+ User mode
+
+--*/
+
+#include "windows.h"
+#include "winioctl.h"
+#include "strsafe.h"
+
+#ifndef _CTYPE_DISABLE_MACROS
+#define _CTYPE_DISABLE_MACROS
+#endif
+
+#include "fwpmu.h"
+
+#include "winsock2.h"
+#include "ws2def.h"
+
+#include <conio.h>
+#include <stdio.h>
+
+#include "ioctl.h"
+
+#define INITGUID
+#include <guiddef.h>
+#include "mntrguid.h"
+
+
+#define MONITOR_FLOW_ESTABLISHED_CALLOUT_DESCRIPTION L"Monitor Sample - Flow Established Callout"
+#define MONITOR_FLOW_ESTABLISHED_CALLOUT_NAME L"Flow Established Callout"
+
+#define MONITOR_STREAM_CALLOUT_DESCRIPTION L"Monitor Sample - Stream Callout"
+#define MONITOR_STREAM_CALLOUT_NAME L"Stream Callout"
+
+HANDLE quitEvent;
+
+DWORD
+MonitorAppOpenMonitorDevice(
+ _Out_ HANDLE* monitorDevice)
+/*++
+
+Routine Description:
+
+ Opens the Monitor Sample monitorDevice
+
+Arguments:
+
+ [out] HANDLE* monitorDevice
+
+Return Value:
+
+ NO_ERROR, ERROR_INVALID_PARAMETER or a CreateFile specific result.
+
+--*/
+{
+ if (!monitorDevice)
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+ *monitorDevice = CreateFileW(MONITOR_DOS_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+
+ if (*monitorDevice == INVALID_HANDLE_VALUE)
+ {
+ return GetLastError();
+ }
+
+ return NO_ERROR;
+}
+
+BOOL MonitorAppCloseMonitorDevice(
+ _In_ HANDLE monitorDevice)
+/*++
+
+Routine Description:
+
+ Closes the Monitor Sample monitorDevice
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return CloseHandle(monitorDevice);
+}
+
+DWORD
+MonitorAppAddCallouts()
+/*++
+
+Routine Description:
+
+ Adds the callouts during installation
+
+Arguments:
+
+ [in] PCWSTR AppPath - The path to the application to monitor.
+
+Return Value:
+
+ NO_ERROR or a specific FWP result.
+
+--*/
+{
+ FWPM_CALLOUT callout;
+ DWORD result;
+ FWPM_DISPLAY_DATA displayData;
+ HANDLE engineHandle = NULL;
+ FWPM_SESSION session;
+ RtlZeroMemory(&session, sizeof(FWPM_SESSION));
+
+ session.displayData.name = L"Monitor Sample Non-Dynamic Session";
+ session.displayData.description = L"For Adding callouts";
+
+ printf("Opening Filtering Engine\n");
+ result = FwpmEngineOpen(
+ NULL,
+ RPC_C_AUTHN_WINNT,
+ NULL,
+ &session,
+ &engineHandle
+ );
+
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Starting Transaction for adding callouts\n");
+ result = FwpmTransactionBegin(engineHandle, 0);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Successfully started the Transaction\n");
+
+ RtlZeroMemory(&callout, sizeof(FWPM_CALLOUT));
+ displayData.description = MONITOR_FLOW_ESTABLISHED_CALLOUT_DESCRIPTION;
+ displayData.name = MONITOR_FLOW_ESTABLISHED_CALLOUT_NAME;
+
+ callout.calloutKey = MONITOR_SAMPLE_FLOW_ESTABLISHED_CALLOUT_V4;
+ callout.displayData = displayData;
+ callout.applicableLayer = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
+ callout.flags = FWPM_CALLOUT_FLAG_PERSISTENT; // Make this a persistent callout.
+
+ printf("Adding Persistent Flow Established callout through the Filtering Engine\n");
+
+ result = FwpmCalloutAdd(engineHandle, &callout, NULL, NULL);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Successfully Added Persistent Flow Established callout.\n");
+
+ RtlZeroMemory(&callout, sizeof(FWPM_CALLOUT));
+
+ displayData.description = MONITOR_STREAM_CALLOUT_DESCRIPTION;
+ displayData.name = MONITOR_STREAM_CALLOUT_DESCRIPTION;
+
+ callout.calloutKey = MONITOR_SAMPLE_STREAM_CALLOUT_V4;
+ callout.displayData = displayData;
+ callout.applicableLayer = FWPM_LAYER_STREAM_V4;
+ callout.flags = FWPM_CALLOUT_FLAG_PERSISTENT; // Make this a persistent callout.
+
+ printf("Adding Persistent Stream callout through the Filtering Engine\n");
+
+ result = FwpmCalloutAdd(engineHandle, &callout, NULL, NULL);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Successfully Added Persistent Stream callout.\n");
+
+ printf("Committing Transaction\n");
+ result = FwpmTransactionCommit(engineHandle);
+ if (NO_ERROR == result)
+ {
+ printf("Successfully Committed Transaction.\n");
+ }
+ goto cleanup;
+
+abort:
+ printf("Aborting Transaction\n");
+ result = FwpmTransactionAbort(engineHandle);
+ if (NO_ERROR == result)
+ {
+ printf("Successfully Aborted Transaction.\n");
+ }
+
+cleanup:
+
+ if (engineHandle)
+ {
+ FwpmEngineClose(engineHandle);
+ }
+ return result;
+}
+
+DWORD
+MonitorAppRemoveCallouts()
+/*++
+
+Routine Description:
+
+ Sets the kernel callout ID's through the Monitor Sample device
+
+Arguments:
+
+ [in] HANDLE monitorDevice - Monitor Sample device
+ [in] CALLOUTS* callouts - Callout structure with ID's set
+ [in] DWORD size - Size of the callout structure.
+
+Return Value:
+
+ NO_ERROR or a specific DeviceIoControl result.
+
+--*/
+{
+ DWORD result;
+ HANDLE engineHandle = NULL;
+ FWPM_SESSION session;
+
+ RtlZeroMemory(&session, sizeof(FWPM_SESSION));
+
+ session.displayData.name = L"Monitor Sample Non-Dynamic Session";
+ session.displayData.description = L"For Adding callouts";
+
+ printf("Opening Filtering Engine\n");
+ result = FwpmEngineOpen(
+ NULL,
+ RPC_C_AUTHN_WINNT,
+ NULL,
+ &session,
+ &engineHandle
+ );
+
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Starting Transaction for Removing callouts\n");
+
+ result = FwpmTransactionBegin(engineHandle, 0);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+ printf("Successfully started the Transaction\n");
+
+ printf("Deleting Flow Established callout\n");
+ result = FwpmCalloutDeleteByKey(engineHandle,
+ &MONITOR_SAMPLE_FLOW_ESTABLISHED_CALLOUT_V4);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Successfully Deleted Flow Established callout\n");
+
+ printf("Deleting Stream callout\n");
+
+ result = FwpmCalloutDeleteByKey(engineHandle,
+ &MONITOR_SAMPLE_STREAM_CALLOUT_V4);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+ printf("Successfully Deleted Stream callout\n");
+
+ printf("Committing Transaction\n");
+ result = FwpmTransactionCommit(engineHandle);
+ if (NO_ERROR == result)
+ {
+ printf("Successfully Committed Transaction.\n");
+ }
+ goto cleanup;
+
+abort:
+ printf("Aborting Transaction\n");
+ result = FwpmTransactionAbort(engineHandle);
+ if (NO_ERROR == result)
+ {
+ printf("Successfully Aborted Transaction.\n");
+ }
+
+cleanup:
+
+ if (engineHandle)
+ {
+ FwpmEngineClose(engineHandle);
+ }
+
+ return result;
+}
+
+DWORD
+MonitorAppEnableMonitoring(
+ _In_ HANDLE monitorDevice,
+ _In_ MONITOR_SETTINGS* monitorSettings)
+/*++
+
+Routine Description:
+
+ Enables monitoring on new connections.
+
+Arguments:
+
+ [in] HANDLE monitorDevice - Monitor Sample device
+ [in] MONITOR_SETTINGS* monitorSettings - Settings for the Monitor Sample driver.
+
+Return Value:
+
+ NO_ERROR or a specific DeviceIoControl result.
+
+--*/
+{
+ DWORD bytesReturned;
+
+ if (!DeviceIoControl(monitorDevice,
+ MONITOR_IOCTL_ENABLE_MONITOR,
+ monitorSettings,
+ sizeof(MONITOR_SETTINGS),
+ NULL,
+ 0,
+ &bytesReturned,
+ NULL))
+ {
+ return GetLastError();
+ }
+
+ return NO_ERROR;
+}
+
+DWORD
+MonitorAppDisableMonitoring(
+ _In_ HANDLE monitorDevice)
+/*++
+
+Routine Description:
+
+ Disables monitoring of new flows (existing flows will continue to be
+ monitored until the driver is stopped or the flows end).
+
+Arguments:
+
+ [in] HANDLE monitorDevice - Monitor Sample device handle.
+
+Return Value:
+
+ NO_ERROR or DeviceIoControl specific code.
+
+--*/
+{
+ DWORD bytesReturned;
+
+ if (!DeviceIoControl(monitorDevice,
+ MONITOR_IOCTL_DISABLE_MONITOR,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &bytesReturned,
+ NULL))
+ {
+ return GetLastError();
+ }
+
+ return NO_ERROR;
+}
+
+DWORD
+MonitorAppAddFilters(
+ _In_ HANDLE engineHandle,
+ _In_ FWP_BYTE_BLOB* applicationPath)
+/*++
+
+Routine Description:
+
+ Adds the required sublayer, filters and callouts to the Windows
+ Filtering Platform (WFP).
+
+Arguments:
+
+ [in] HANDLE engineHandle - Handle to the base Filtering engine
+ [in] FWP_BYTE_BLOB* applicationPath - full path to the application including
+ the NULL terminator and size also
+ including the NULL the terminator
+ [in] CALLOUTS* callouts - The callouts that need to be added.
+
+Return Value:
+
+ NO_ERROR or a specific result
+
+--*/
+{
+ DWORD result = NO_ERROR;
+ FWPM_SUBLAYER monitorSubLayer;
+ FWPM_FILTER filter;
+ FWPM_FILTER_CONDITION filterConditions[2]; // We only need two for this call.
+
+ RtlZeroMemory(&monitorSubLayer, sizeof(FWPM_SUBLAYER));
+
+ monitorSubLayer.subLayerKey = MONITOR_SAMPLE_SUBLAYER;
+ monitorSubLayer.displayData.name = L"Monitor Sample Sub layer";
+ monitorSubLayer.displayData.description = L"Monitor Sample Sub layer";
+ monitorSubLayer.flags = 0;
+ // We don't really mind what the order of invocation is.
+ monitorSubLayer.weight = 0;
+
+ printf("Starting Transaction\n");
+
+ result = FwpmTransactionBegin(engineHandle, 0);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+ printf("Successfully Started Transaction\n");
+
+ printf("Adding Sublayer\n");
+
+ result = FwpmSubLayerAdd(engineHandle, &monitorSubLayer, NULL);
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Sucessfully added Sublayer\n");
+
+ RtlZeroMemory(&filter, sizeof(FWPM_FILTER));
+
+ filter.layerKey = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
+ filter.displayData.name = L"Flow established filter.";
+ filter.displayData.description = L"Sets up flow for traffic that we are interested in.";
+ filter.action.type = FWP_ACTION_CALLOUT_INSPECTION; // We're only doing inspection.
+ filter.action.calloutKey = MONITOR_SAMPLE_FLOW_ESTABLISHED_CALLOUT_V4;
+ filter.filterCondition = filterConditions;
+ filter.subLayerKey = monitorSubLayer.subLayerKey;
+ filter.weight.type = FWP_EMPTY; // auto-weight.
+
+ filter.numFilterConditions = 2;
+
+ RtlZeroMemory(filterConditions, sizeof(filterConditions));
+
+ //
+ // Add the application path to the filter conditions.
+ //
+ filterConditions[0].fieldKey = FWPM_CONDITION_ALE_APP_ID;
+ filterConditions[0].matchType = FWP_MATCH_EQUAL;
+ filterConditions[0].conditionValue.type = FWP_BYTE_BLOB_TYPE;
+ filterConditions[0].conditionValue.byteBlob = applicationPath;
+
+ //
+ // For the purposes of this sample, we will monitor TCP traffic only.
+ //
+ filterConditions[1].fieldKey = FWPM_CONDITION_IP_PROTOCOL;
+ filterConditions[1].matchType = FWP_MATCH_EQUAL;
+ filterConditions[1].conditionValue.type = FWP_UINT8;
+ filterConditions[1].conditionValue.uint8 = IPPROTO_TCP;
+
+ printf("Adding Flow Established Filter\n");
+
+ result = FwpmFilterAdd(engineHandle,
+ &filter,
+ NULL,
+ NULL);
+
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Successfully added Flow Established filter\n");
+
+ RtlZeroMemory(&filter, sizeof(FWPM_FILTER));
+
+ filter.layerKey = FWPM_LAYER_STREAM_V4;
+ filter.action.type = FWP_ACTION_CALLOUT_INSPECTION; // We're only doing inspection.
+ filter.action.calloutKey = MONITOR_SAMPLE_STREAM_CALLOUT_V4;
+ filter.subLayerKey = monitorSubLayer.subLayerKey;
+ filter.weight.type = FWP_EMPTY; // auto-weight.
+
+ filter.numFilterConditions = 0;
+
+ RtlZeroMemory(filterConditions, sizeof(filterConditions));
+
+ filter.filterCondition = filterConditions;
+
+ filter.displayData.name = L"Stream Layer Filter";
+ filter.displayData.description = L"Monitors TCP traffic.";
+
+ printf("Adding Stream Filter\n");
+
+ result = FwpmFilterAdd(engineHandle,
+ &filter,
+ NULL,
+ NULL);
+
+ if (NO_ERROR != result)
+ {
+ goto abort;
+ }
+
+ printf("Successfully added Stream filter\n");
+
+ printf("Committing Transaction\n");
+ result = FwpmTransactionCommit(engineHandle);
+ if (NO_ERROR == result)
+ {
+ printf("Successfully Committed Transaction\n");
+ }
+ goto cleanup;
+
+abort:
+ printf("Aborting Transaction\n");
+ result = FwpmTransactionAbort(engineHandle);
+ if (NO_ERROR == result)
+ {
+ printf("Successfully Aborted Transaction\n");
+ }
+
+cleanup:
+
+ return result;
+}
+
+DWORD
+MonitorAppIDFromPath(
+ _In_ PCWSTR fileName,
+ _Out_ FWP_BYTE_BLOB** appId)
+{
+ DWORD result = NO_ERROR;
+
+ result = FwpmGetAppIdFromFileName(fileName, appId);
+
+ return result;
+}
+
+DWORD
+MonitorAppDoMonitoring(PCWSTR AppPath)
+{
+ HANDLE monitorDevice = NULL;
+ HANDLE engineHandle = NULL;
+ DWORD result;
+ MONITOR_SETTINGS monitorSettings;
+ FWPM_SESSION session;
+ FWP_BYTE_BLOB* applicationId = NULL;
+
+ RtlZeroMemory(&monitorSettings, sizeof(MONITOR_SETTINGS));
+ RtlZeroMemory(&session, sizeof(FWPM_SESSION));
+
+ session.displayData.name = L"Monitor Sample Session";
+ session.displayData.description = L"Monitors traffic at the Stream layer.";
+
+ // Let the Base Filtering Engine cleanup after us.
+ session.flags = FWPM_SESSION_FLAG_DYNAMIC;
+
+ printf("Opening Filtering Engine\n");
+ result = FwpmEngineOpen(
+ NULL,
+ RPC_C_AUTHN_WINNT,
+ NULL,
+ &session,
+ &engineHandle
+ );
+
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Successfully opened Filtering Engine\n");
+
+ printf("Looking up Application ID from BFE\n");
+ result = MonitorAppIDFromPath(AppPath, &applicationId);
+
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Successfully retrieved Application ID\n");
+
+ printf("Opening Monitor Sample Device\n");
+
+ result = MonitorAppOpenMonitorDevice(&monitorDevice);
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Successfully opened Monitor Device\n");
+
+ printf("Adding Filters through the Filtering Engine\n");
+
+ result = MonitorAppAddFilters(engineHandle,
+ applicationId);
+
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Successfully added Filters through the Filtering Engine\n");
+
+ printf("Enabling monitoring through the Monitor Sample Device\n");
+
+ monitorSettings.monitorOperation = monitorTraffic;
+
+ result = MonitorAppEnableMonitoring(monitorDevice,
+ &monitorSettings);
+ if (NO_ERROR != result)
+ {
+ goto cleanup;
+ }
+
+ printf("Successfully enabled monitoring.\n");
+
+ printf("Events will be traced through WMI. Please press any key to exit and cleanup filters.\n");
+
+#pragma prefast(push)
+#pragma prefast(disable:6031, "by design the return value of _getch() is ignored here")
+ _getch();
+#pragma prefast(pop)
+
+cleanup:
+
+ if (NO_ERROR != result)
+ {
+ printf("Monitor.\tError 0x%x occurred during execution\n", result);
+ }
+
+ if (monitorDevice)
+ {
+ MonitorAppCloseMonitorDevice(monitorDevice);
+ }
+
+ //
+ // Free the application Id that we retrieved.
+ //
+ if (applicationId)
+ {
+ FwpmFreeMemory((void**)&applicationId);
+ }
+
+ if (engineHandle)
+ {
+ result = FwpmEngineClose(engineHandle);
+ engineHandle = NULL;
+ }
+
+ return result;
+}
+
+void
+MonitorPrintUsage()
+{
+ wprintf(L"Usage: monitor ( addcallouts | delcallouts | monitor <targetApp.exe> )\n");
+}
+
+DWORD
+MonitorAppProcessArguments(_In_ int argc, _In_reads_(argc) PCWSTR argv[])
+{
+ if (argc == 2)
+ {
+ if (_wcsicmp(argv[1], L"addcallouts") == 0)
+ {
+ return MonitorAppAddCallouts();
+ }
+ if (_wcsicmp(argv[1], L"delcallouts") == 0)
+ {
+ return MonitorAppRemoveCallouts();
+ }
+ }
+
+ if (argc == 3)
+ {
+ if (_wcsicmp(argv[1], L"monitor") == 0)
+ {
+ return MonitorAppDoMonitoring(argv[2]);
+ }
+ }
+
+ MonitorPrintUsage();
+ return ERROR_INVALID_PARAMETER;
+}
+
+int __cdecl wmain(_In_ int argc, _In_reads_(argc) PCWSTR argv[])
+{
+ DWORD result;
+
+ result = MonitorAppProcessArguments(argc, argv);
+
+ return (int)result;
+}
diff --git a/network/trans/msnmntr/exe/monitor.vcxproj b/network/trans/msnmntr/exe/monitor.vcxproj
new file mode 100644
index 00000000..06902c7c
--- /dev/null
+++ b/network/trans/msnmntr/exe/monitor.vcxproj
@@ -0,0 +1,251 @@
+<?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>{BF8F75F9-23E9-4925-96A1-76FD729EBA93}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{DED4B73F-AFBE-4142-AD53-004F9F079AA7}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</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>monitor</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>monitor</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>monitor</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>monitor</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ <AdditionalOptions>%(AdditionalOptions) -N</AdditionalOptions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ <AdditionalOptions>%(AdditionalOptions) -N</AdditionalOptions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ <AdditionalOptions>%(AdditionalOptions) -N</AdditionalOptions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32</PreprocessorDefinitions>
+ <AdditionalOptions>%(AdditionalOptions) -N</AdditionalOptions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <UseOfAtl>Static</UseOfAtl>
+ <NTDDI_VERSION>NTDDI_WIN7</NTDDI_VERSION>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <UseOfAtl>Static</UseOfAtl>
+ <NTDDI_VERSION>NTDDI_WIN7</NTDDI_VERSION>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <UseOfAtl>Static</UseOfAtl>
+ <NTDDI_VERSION>NTDDI_WIN7</NTDDI_VERSION>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <UseOfAtl>Static</UseOfAtl>
+ <NTDDI_VERSION>NTDDI_WIN7</NTDDI_VERSION>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;comctl32.lib;kernel32.lib;netapi32.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib;ntdll.lib;kernel32.lib;setupapi.lib;rpcrt4.lib;fwpuclnt.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;comctl32.lib;kernel32.lib;netapi32.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib;ntdll.lib;kernel32.lib;setupapi.lib;rpcrt4.lib;fwpuclnt.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;comctl32.lib;kernel32.lib;netapi32.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib;ntdll.lib;kernel32.lib;setupapi.lib;rpcrt4.lib;fwpuclnt.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;comctl32.lib;kernel32.lib;netapi32.lib;ole32.lib;oleaut32.lib;user32.lib;uuid.lib;ntdll.lib;kernel32.lib;setupapi.lib;rpcrt4.lib;fwpuclnt.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="monitor.cpp" />
+ </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/msnmntr/exe/monitor.vcxproj.Filters b/network/trans/msnmntr/exe/monitor.vcxproj.Filters
new file mode 100644
index 00000000..2838b33f
--- /dev/null
+++ b/network/trans/msnmntr/exe/monitor.vcxproj.Filters
@@ -0,0 +1,22 @@
+<?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>{AB53852E-BB5F-49F9-8184-98DAFA476C33}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{253A5086-E26E-4352-B8E1-BBBEB6A81F31}</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>{714E88E3-7CAD-4F49-8A28-32DD65C6691E}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="monitor.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/trans/msnmntr/exe/mtrace.cmd b/network/trans/msnmntr/exe/mtrace.cmd
new file mode 100644
index 00000000..f7c6147f
--- /dev/null
+++ b/network/trans/msnmntr/exe/mtrace.cmd
@@ -0,0 +1,288 @@
+@echo off
+@setlocal
+
+@rem -------------------------------------------------------------------------
+@rem OBTAIN INPUT
+@rem -------------------------------------------------------------------------
+
+set TR_MODULE=%1
+shift
+set TR_LEVEL=%1
+shift
+set TR_VERB=%1
+
+@rem -------------------------------------------------------------------------
+@rem VALIDATE COMPONENT & TRACING LEVEL
+@rem -------------------------------------------------------------------------
+
+if /i "%TR_MODULE%"=="MONITOR" (
+ set TR_GUID={dd65554d-9925-49d1-83b6-46125feb4207}
+ set TR_MODULE=MsnMntrMonitor
+
+ if "%TR_LEVEL%"=="0" (
+ set TR_BITS=
+ set TR_LEVEL=0
+ ) else if "%TR_LEVEL%"=="1" (
+ set TR_BITS=
+ set TR_LEVEL=1
+ ) else if /i "%TR_LEVEL%"=="2" (
+ set TR_BITS=
+ set TR_LEVEL=2
+ ) else if /i "%TR_LEVEL%"=="9" (
+ set TR_BITS=
+ set TR_LEVEL=9
+ ) else (
+ echo.
+ echo Error: Monitor component does not support this trace detail.
+ goto :show_usage_MsnMntrMonitor
+ )
+) else if /i "%TR_MODULE%"=="NOTIFY" (
+ set TR_GUID={aca2f74a-7a0d-4f47-be4b-66900813b8e5}
+ set TR_MODULE=MsnMntrNotify
+
+ if "%TR_LEVEL%"=="0" (
+ set TR_BITS=
+ set TR_LEVEL=0
+ ) else if "%TR_LEVEL%"=="1" (
+ set TR_BITS=
+ set TR_LEVEL=1
+ ) else if /i "%TR_LEVEL%"=="2" (
+ set TR_BITS=
+ set TR_LEVEL=2
+ ) else if /i "%TR_LEVEL%"=="3" (
+ set TR_BITS=
+ set TR_LEVEL=3
+ ) else if /i "%TR_LEVEL%"=="9" (
+ set TR_BITS=
+ set TR_LEVEL=9
+ ) else (
+ echo.
+ echo Error: Notify component does not support this trace detail.
+ goto :show_usage_MsnMntrNotify
+ )
+
+) else if /i "%TR_MODULE%"=="CONTROL" (
+ set TR_GUID={eab718af-52de-477c-874d-cb49746bb131}
+ set TR_MODULE=MsnMntrCtl
+
+ if "%TR_LEVEL%"=="0" (
+ set TR_BITS=
+ set TR_LEVEL=0
+ ) else if "%TR_LEVEL%"=="1" (
+ set TR_BITS=
+ set TR_LEVEL=1
+ ) else if /i "%TR_LEVEL%"=="2" (
+ set TR_BITS=
+ set TR_LEVEL=2
+ ) else if /i "%TR_LEVEL%"=="9" (
+ set TR_BITS=
+ set TR_LEVEL=9
+ ) else (
+ echo.
+ echo Error: Control component does not support this trace detail.
+ goto :show_usage_MsnMntrCtl
+ )
+
+) else if /i "%TR_MODULE%"=="INIT" (
+ set TR_GUID={e7db16bb-41be-4c05-b73e-5feca06f8207}
+ set TR_MODULE=MsnMntrInit
+
+ if "%TR_LEVEL%"=="0" (
+ set TR_BITS=
+ set TR_LEVEL=0
+ ) else if "%TR_LEVEL%"=="1" (
+ set TR_BITS=
+ set TR_LEVEL=1
+ ) else if /i "%TR_LEVEL%"=="9" (
+ set TR_BITS=
+ set TR_LEVEL=9
+ ) else (
+ echo.
+ echo Error: Init component does not support this trace detail.
+ goto :show_usage_MsnMntrInit
+ )
+
+) else (
+ echo.
+ echo Error: No module was selected.
+ goto :show_usage
+)
+
+set TR_NAME=%TR_MODULE%
+set TR_DIR=%SystemRoot%\Tracing\%TR_NAME%
+set TR_LOG=%TR_DIR%\%TR_NAME%.etl
+set TR_BITS=0xFFFFFFFF
+set TR_OPTS=
+set TR_RT_OPTS=-rt -ft 1
+
+set TRACE_FORMAT_PREFIX=%%9!d!:%%3!04X! %%!FUNC!:
+set TRACE_FORMAT_SEARCH_PATH=%TR_DIR%
+
+@rem -------------------------------------------------------------------------
+@rem VALIDATE VERB
+@rem -------------------------------------------------------------------------
+
+if /i "%TR_VERB%"=="start" (
+ call :start_trace
+) else if /i "%TR_VERB%"=="stop" (
+ call :stop_trace
+) else if /i "%TR_VERB%"=="pdb" (
+ call :extract_format_info %1
+) else if /i "%TR_VERB%"=="rt" (
+ call :format_realtime
+) else if /i "%TR_VERB%"=="fmt" (
+ call :format_offline
+) else (
+ echo.
+ echo Error: A supported verb has not been specified.
+ goto :show_usage
+)
+
+goto :eof
+
+:ShowSummary
+ echo.
+ echo Trace name : %TR_NAME%
+ echo Trace directory : %TR_DIR%
+ echo Trace log : %TR_LOG%
+ echo Trace level : %TR_LEVEL%
+
+@rem -------------------------------------------------------------------------
+@rem START TRACING
+@rem -------------------------------------------------------------------------
+:start_trace
+ if not exist %TR_DIR% mkdir %TR_DIR%
+ logman query %TR_NAME% -ets 1 > NUL
+ if errorlevel 1 (
+ logman start %TR_NAME% %TR_OPTS% -p %TR_GUID% %TR_BITS% %TR_LEVEL% -o %TR_LOG% -ets
+ ) else (
+ echo Collection is already started.
+ )
+ goto :eof
+
+@rem -------------------------------------------------------------------------
+@rem STOP TRACING
+@rem -------------------------------------------------------------------------
+:stop_trace
+ logman query %TR_NAME% -ets 1>NUL
+ if NOT errorlevel 1 (
+ logman stop %TR_NAME% -ets
+ )
+ goto :eof
+
+@rem -------------------------------------------------------------------------
+@rem EXTRACT FORMAT INFO
+@rem -------------------------------------------------------------------------
+:extract_format_info
+ if "%1" == "" (
+ set TR_PDB=.\%TR_MODULE%.pdb
+ )else (
+ set TR_PDB=%1
+ )
+ tracepdb -f %TR_PDB% -p %TR_DIR%
+ goto :eof
+
+@rem -------------------------------------------------------------------------
+@rem FORMAT REALTIME
+@rem -------------------------------------------------------------------------
+:format_realtime
+ call :stop_trace
+ set TR_OPTS=%TR_RT_OPTS%
+ call :start_trace
+ start "%TR_NAME% Tracing" /low tracefmt -displayonly -rt %TR_NAME%
+ goto :eof
+
+@rem -------------------------------------------------------------------------
+@rem FORMAT OFFLINE
+@rem -------------------------------------------------------------------------
+:format_offline
+ tracefmt -o %TR_NAME%.txt %TR_LOG% -display
+ goto :eof
+
+goto :eof
+
+@rem -------------------------------------------------------------------------
+@rem CONTEXT SENSITIVE HELP
+@rem -------------------------------------------------------------------------
+:show_usage
+ call :show_usage_header
+ echo 9 Display all trace events
+ echo Select a component to see individual supported tracing levels.
+ call :show_usage_footer
+
+ goto :eof
+
+:show_usage_MsnMntrMonitor
+ call :show_usage_header
+ echo 0 Established flow
+ echo 1 Change of state information
+ echo 2 Layer notifications
+ echo 9 Display all trace events
+ call :show_usage_footer
+
+ goto :eof
+
+:show_usage_MsnMntrNotify
+ call :show_usage_header
+ echo 0 Client to server
+ echo 1 Peer to peer
+ echo 2 Unknown
+ echo 3 All traffic
+ echo 9 Display all trace events
+ call :show_usage_footer
+
+ goto :eof
+
+:show_usage_MsnMntrCtl
+ call :show_usage_header
+ echo 0 Initialization
+ echo 1 Device control
+ echo 2 State
+ echo 9 Display all trace events
+ call :show_usage_footer
+
+ goto :eof
+
+:show_usage_MsnMntrInit
+ call :show_usage_header
+ echo 0 Initialization
+ echo 1 Shutdown
+ echo 9 Display all trace events
+ call :show_usage_footer
+
+ goto :eof
+
+:show_usage_header
+ echo.
+ echo Usage: monitor_trace COMPONENT LEVEL VERB
+ echo.
+ echo Components:
+ echo MONITOR, NOTIFY, CONTROL and INIT
+ echo.
+ echo Trace detail:
+ goto :eof
+
+:show_usage_footer
+ echo.
+ echo Verbs:
+ echo start Start collection.
+ echo stop Stop collection.
+ echo pdb Extract format information from the pdb in the current
+ echo directory.
+ echo pdb [file] Like the above, but allows the full path to the pdb
+ echo to be specified.
+ echo rt Displays the trace output in real-time. This
+ echo automatically stops any existing collection and begins
+ echo a new one with appropriate parameters for real-time.
+ echo fmt Format the trace logfile to the console.
+ echo.
+ echo Note:
+ echo The most common scenario is to extract the format information from
+ echo the pdb, and then display the output in real-time.
+ echo.
+ echo Example:
+ echo cd /d MySymbolDir
+ echo monitor_trace init 0 pdb
+ echo monitor_trace init 0 rt
+
+ goto :eof \ No newline at end of file
diff --git a/network/trans/msnmntr/inc/ioctl.h b/network/trans/msnmntr/inc/ioctl.h
new file mode 100644
index 00000000..ea08dc42
--- /dev/null
+++ b/network/trans/msnmntr/inc/ioctl.h
@@ -0,0 +1,36 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample callout driver IOCTL header
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#pragma once
+
+#define MONITOR_DEVICE_NAME L"\\Device\\MonitorSample"
+#define MONITOR_SYMBOLIC_NAME L"\\DosDevices\\Global\\MonitorSample"
+#define MONITOR_DOS_NAME L"\\\\.\\MonitorSample"
+
+typedef enum _MONITOR_OPERATION_MODE
+{
+ invalidOperation = 0,
+ monitorTraffic = 1,
+ monitorOperationMax
+} MONITOR_OPERATION_MODE;
+
+typedef struct _MONITOR_SETTINGS
+{
+ MONITOR_OPERATION_MODE monitorOperation;
+ UINT32 flags;
+} MONITOR_SETTINGS;
+
+#define MONITOR_IOCTL_ENABLE_MONITOR CTL_CODE(FILE_DEVICE_NETWORK, 0x1, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define MONITOR_IOCTL_DISABLE_MONITOR CTL_CODE(FILE_DEVICE_NETWORK, 0x2, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
diff --git a/network/trans/msnmntr/inc/mntrguid.h b/network/trans/msnmntr/inc/mntrguid.h
new file mode 100644
index 00000000..8b072853
--- /dev/null
+++ b/network/trans/msnmntr/inc/mntrguid.h
@@ -0,0 +1,44 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample callout driver IOCTL header
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#pragma once
+
+// b3241f1d-7cd2-4e7a-8721-2e97d07702e5
+DEFINE_GUID(
+ MONITOR_SAMPLE_SUBLAYER,
+ 0xb3241f1d,
+ 0x7cd2,
+ 0x4e7a,
+ 0x87, 0x21, 0x2e, 0x97, 0xd0, 0x77, 0x02, 0xe5
+);
+
+// 3aaccbc0-2c29-455f-bb91-0e801c8994a4
+DEFINE_GUID(
+ MONITOR_SAMPLE_FLOW_ESTABLISHED_CALLOUT_V4,
+ 0x3aaccbc0,
+ 0x2c29,
+ 0x455f,
+ 0xbb, 0x91, 0x0e, 0x80, 0x1c, 0x89, 0x94, 0xa4
+);
+
+// cea0131a-6ed3-4ed6-b40c-8a8fe8434b0a
+DEFINE_GUID(
+ MONITOR_SAMPLE_STREAM_CALLOUT_V4,
+ 0xcea0131a,
+ 0x6ed3,
+ 0x4ed6,
+ 0xb4, 0x0c, 0x8a, 0x8f, 0xe8, 0x43, 0x4b, 0x0a
+);
+
+
diff --git a/network/trans/msnmntr/msnmntr.sln b/network/trans/msnmntr/msnmntr.sln
new file mode 100644
index 00000000..ac6d8e3e
--- /dev/null
+++ b/network/trans/msnmntr/msnmntr.sln
@@ -0,0 +1,46 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{18ABBE0C-EBB5-4181-AB5D-AD526B2CB283}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{B9075E40-A5B9-42B8-A185-CB3290C4EC12}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "monitor", "exe\monitor.vcxproj", "{BF8F75F9-23E9-4925-96A1-76FD729EBA93}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msnmntr", "sys\msnmntr.vcxproj", "{A0314F39-C7C2-463C-B2BE-DF387AB755F5}"
+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
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Debug|Win32.Build.0 = Debug|Win32
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Release|Win32.ActiveCfg = Release|Win32
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Release|Win32.Build.0 = Release|Win32
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Debug|x64.ActiveCfg = Debug|x64
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Debug|x64.Build.0 = Debug|x64
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Release|x64.ActiveCfg = Release|x64
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93}.Release|x64.Build.0 = Release|x64
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Debug|Win32.Build.0 = Debug|Win32
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Release|Win32.ActiveCfg = Release|Win32
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Release|Win32.Build.0 = Release|Win32
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Debug|x64.ActiveCfg = Debug|x64
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Debug|x64.Build.0 = Debug|x64
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Release|x64.ActiveCfg = Release|x64
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {BF8F75F9-23E9-4925-96A1-76FD729EBA93} = {18ABBE0C-EBB5-4181-AB5D-AD526B2CB283}
+ {A0314F39-C7C2-463C-B2BE-DF387AB755F5} = {B9075E40-A5B9-42B8-A185-CB3290C4EC12}
+ EndGlobalSection
+EndGlobal
diff --git a/network/trans/msnmntr/sys/ctl.c b/network/trans/msnmntr/sys/ctl.c
new file mode 100644
index 00000000..09a418c3
--- /dev/null
+++ b/network/trans/msnmntr/sys/ctl.c
@@ -0,0 +1,149 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver IO control routines
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ntddk.h>
+#include <wdf.h>
+
+#include <fwpmk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+
+#include "ioctl.h"
+
+#include "msnmntr.h"
+#include "ctl.h"
+
+#include "notify.h"
+
+//
+// Software Tracing Definitions
+//
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(MsnMntrCtl,(eab718af, 52de, 477c, 874d, cb49746bb131), \
+ WPP_DEFINE_BIT(TRACE_INIT) \
+ WPP_DEFINE_BIT(TRACE_DEVICE_CONTROL) \
+ WPP_DEFINE_BIT(TRACE_STATE) )
+
+#include "ctl.tmh"
+
+EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL MonitorEvtDeviceControl;
+
+NTSTATUS
+MonitorCtlDriverInit(
+ _In_ WDFDEVICE* pDevice
+ )
+/*++
+
+Routine Description:
+
+ Initializes the request queue for our driver. This is how
+ DeviceIoControl requests are sent to KMDF drivers.
+
+Arguments:
+
+ [in] WDFDEVICE* pDevice - Our device.
+
+--*/
+{
+ NTSTATUS status;
+ WDF_IO_QUEUE_CONFIG queueConfig;
+
+ DoTraceMessage(TRACE_INIT, "MonitorSample Control Initialization in progress.");
+
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
+ &queueConfig,
+ WdfIoQueueDispatchSequential
+ );
+
+ queueConfig.EvtIoDeviceControl = MonitorEvtDeviceControl;
+
+ status = WdfIoQueueCreate(
+ *pDevice,
+ &queueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ NULL
+ );
+
+ return status;
+}
+
+VOID
+MonitorEvtDeviceControl (
+ _In_ WDFQUEUE Queue,
+ _In_ WDFREQUEST Request,
+ _In_ size_t OutputBufferLength,
+ _In_ size_t InputBufferLength,
+ _In_ ULONG IoControlCode
+ )
+/*++
+
+ Handles device IO control requests. This callback drives all communication
+ between the usermode exe and this driver.
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(Queue);
+ UNREFERENCED_PARAMETER(OutputBufferLength);
+
+ DoTraceMessage(TRACE_DEVICE_CONTROL, "MonitorSample Dispatch Device Control: 0x%x", IoControlCode);
+
+ switch (IoControlCode)
+ {
+ case MONITOR_IOCTL_ENABLE_MONITOR:
+ {
+ WDFMEMORY pMemory;
+ void* pBuffer;
+
+ if (InputBufferLength < sizeof(MONITOR_SETTINGS))
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ status = WdfRequestRetrieveInputMemory(Request, &pMemory);
+
+ if (NT_SUCCESS(status))
+ {
+ pBuffer = WdfMemoryGetBuffer(pMemory, NULL);
+ status = MonitorCoEnableMonitoring((MONITOR_SETTINGS*) pBuffer);
+ }
+ }
+ break;
+ }
+
+ case MONITOR_IOCTL_DISABLE_MONITOR:
+ {
+ status = STATUS_SUCCESS;
+
+ MonitorCoDisableMonitoring();
+
+ break;
+ }
+
+ default:
+ {
+ status = STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ WdfRequestComplete(Request, status);
+}
diff --git a/network/trans/msnmntr/sys/ctl.h b/network/trans/msnmntr/sys/ctl.h
new file mode 100644
index 00000000..6e268be2
--- /dev/null
+++ b/network/trans/msnmntr/sys/ctl.h
@@ -0,0 +1,19 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver IO control header
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+NTSTATUS
+MonitorCtlDriverInit(
+ _In_ WDFDEVICE* pDevice
+ );
+
diff --git a/network/trans/msnmntr/sys/init.c b/network/trans/msnmntr/sys/init.c
new file mode 100644
index 00000000..a85ff103
--- /dev/null
+++ b/network/trans/msnmntr/sys/init.c
@@ -0,0 +1,244 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver initialization routines
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ndis.h>
+#include <ntddk.h>
+#include <wdf.h>
+
+#include <fwpmk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include "ioctl.h"
+
+#include "msnmntr.h"
+#include "ctl.h"
+
+#include "notify.h"
+
+//
+// Software Tracing Definitions
+//
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(MsnMntrInit,(e7db16bb, 41be, 4c05, b73e, 5feca06f8207), \
+ WPP_DEFINE_BIT(TRACE_INIT) \
+ WPP_DEFINE_BIT(TRACE_SHUTDOWN) )
+
+#include "init.tmh"
+
+DEVICE_OBJECT* gWdmDevice;
+
+// ===========================================================================
+//
+// LOCAL PROTOTYPES
+//
+// ===========================================================================
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_UNLOAD MonitorEvtDriverUnload;
+
+// We're using what looks like a EVT_WDF_DRIVER_DEVICE_ADD callback, to keep
+// this looking like a normal KMDF driver. However, since this is a non-pnp
+// driver, it will not be used as a callback; we will call it ourselves at the
+// end of DriverEntry. So, do not declare it as a callback.
+// The NONPNP sample demonstrates this as well.
+NTSTATUS
+MonitorEvtDeviceAdd(
+ _In_ PWDFDEVICE_INIT pInit
+ );
+
+// ===========================================================================
+//
+// PUBLIC FUNCTIONS
+//
+// ===========================================================================
+
+NTSTATUS
+DriverEntry(
+ _In_ DRIVER_OBJECT* driverObject,
+ _In_ UNICODE_STRING* registryPath
+ )
+/*++
+
+Routine Description:
+
+ Main driver entry point. Called at driver load time
+
+Arguments:
+
+ driverObject Our driver
+ registryPath A reg key where we can keep parameters
+
+Return Value:
+
+ status of our initialization. A status != STATUS_SUCCESS aborts the
+ driver load and we don't get called again.
+
+ Each component is responsible for logging any error that causes the
+ driver load to fail.
+
+--*/
+{
+ NTSTATUS status;
+ WDF_DRIVER_CONFIG config;
+ WDFDRIVER driver;
+ PWDFDEVICE_INIT pInit = NULL;
+
+ // Request NX Non-Paged Pool when available
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+
+ //
+ // This macro is required to initialize software tracing on XP and beyond
+ // For XP and beyond use the DriverObject as the first argument.
+ //
+
+ WPP_INIT_TRACING(driverObject,registryPath);
+
+ DoTraceMessage(TRACE_INIT, "Initializing MonitorSample Driver");
+
+ WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
+ config.DriverInitFlags |= WdfDriverInitNonPnpDriver;
+ config.EvtDriverUnload = MonitorEvtDriverUnload;
+
+ status = WdfDriverCreate(
+ driverObject,
+ registryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &config,
+ &driver
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ pInit = WdfControlDeviceInitAllocate(driver, &SDDL_DEVOBJ_SYS_ALL_ADM_ALL);
+
+ if (!pInit)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto cleanup;
+ }
+
+ status = MonitorEvtDeviceAdd(pInit);
+
+cleanup:
+ if (!NT_SUCCESS(status))
+ {
+ DoTraceMessage(TRACE_INIT, "MonitorSample Initialization Failed.");
+
+ WPP_CLEANUP(driverObject);
+ }
+
+ return status;
+}
+
+NTSTATUS
+MonitorEvtDeviceAdd(
+ _In_ PWDFDEVICE_INIT pInit
+ )
+{
+ NTSTATUS status;
+ WDFDEVICE device;
+ DECLARE_CONST_UNICODE_STRING(ntDeviceName, MONITOR_DEVICE_NAME);
+ DECLARE_CONST_UNICODE_STRING(symbolicName, MONITOR_SYMBOLIC_NAME);
+
+ WdfDeviceInitSetDeviceType(pInit, FILE_DEVICE_NETWORK);
+ WdfDeviceInitSetCharacteristics(pInit, FILE_DEVICE_SECURE_OPEN, FALSE);
+ status = WdfDeviceInitAssignName(pInit, &ntDeviceName);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ status = WdfDeviceCreate(&pInit, WDF_NO_OBJECT_ATTRIBUTES, &device);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ status = WdfDeviceCreateSymbolicLink(device, &symbolicName);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ status = MonitorCtlDriverInit(&device);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ gWdmDevice = WdfDeviceWdmGetDeviceObject(device);
+ status = MonitorCoInitialize(gWdmDevice);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ status = MonitorNfInitialize(gWdmDevice);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ WdfControlFinishInitializing(device);
+
+cleanup:
+ // If WdfDeviceCreate was successful, it will set pInit to NULL.
+ if (pInit)
+ {
+ WdfDeviceInitFree(pInit);
+ }
+
+ return status;
+}
+
+void
+MonitorEvtDriverUnload(
+ _In_ WDFDRIVER Driver
+ )
+/*++
+
+Routine Description:
+
+ Called to indicate that we are being unloaded and to cause an orderly
+ shutdown
+
+Arguments:
+
+ driverObject Our driver
+
+Return Value:
+
+ None
+
+--*/
+{
+ DRIVER_OBJECT* driverObject;
+
+ MonitorCoUninitialize();
+ MonitorNfUninitialize();
+
+ DoTraceMessage(TRACE_SHUTDOWN, "MonitorSample Driver Shutting Down");
+
+ driverObject = WdfDriverWdmGetDriverObject(Driver);
+ WPP_CLEANUP(driverObject);
+}
diff --git a/network/trans/msnmntr/sys/msnmntr.c b/network/trans/msnmntr/sys/msnmntr.c
new file mode 100644
index 00000000..1aa33431
--- /dev/null
+++ b/network/trans/msnmntr/sys/msnmntr.c
@@ -0,0 +1,883 @@
+/*++
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver callout routines
+
+Environment:
+
+ Kernel mode
+--*/
+
+#include <ntddk.h>
+#include <ntstrsafe.h>
+
+#include <fwpmk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include "ioctl.h"
+
+#include "msnmntr.h"
+#include "notify.h"
+#include "intsafe.h"
+
+#define INITGUID
+#include <guiddef.h>
+#include "mntrguid.h"
+
+//
+// Software Tracing Definitions
+//
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(MsnMntrMonitor,(dd65554d, 9925, 49d1, 83b6, 46125feb4207), \
+ WPP_DEFINE_BIT(TRACE_FLOW_ESTABLISHED) \
+ WPP_DEFINE_BIT(TRACE_STATE_CHANGE) \
+ WPP_DEFINE_BIT(TRACE_LAYER_NOTIFY) )
+
+#include "msnmntr.tmh"
+
+#define TAG_NAME_CALLOUT 'CnoM'
+
+UINT32 flowEstablishedId = 0;
+UINT32 streamId = 0;
+long monitoringEnabled = 0;
+LIST_ENTRY flowContextList;
+KSPIN_LOCK flowContextListLock;
+
+NTSTATUS MonitorCoFlowEstablishedNotifyV4(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter);
+
+NTSTATUS MonitorCoStreamNotifyV4(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter);
+
+void MonitorCoStreamFlowDeletion(
+ _In_ UINT16 layerId,
+ _In_ UINT32 calloutId,
+ _In_ UINT64 flowContext);
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+NTSTATUS MonitorCoFlowEstablishedCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut);
+
+NTSTATUS MonitorCoStreamCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut);
+
+#else
+
+NTSTATUS MonitorCoFlowEstablishedCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut);
+
+NTSTATUS MonitorCoStreamCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut);
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+NTSTATUS
+MonitorCoRegisterCallout(
+ _Inout_ void* deviceObject,
+ _In_ FWPS_CALLOUT_CLASSIFY_FN ClassifyFunction,
+ _In_ FWPS_CALLOUT_NOTIFY_FN NotifyFunction,
+ _In_opt_ FWPS_CALLOUT_FLOW_DELETE_NOTIFY_FN FlowDeleteFunction,
+ _In_ const GUID* calloutKey,
+ _In_ UINT32 flags,
+ _Out_ UINT32* calloutId
+ )
+{
+ FWPS_CALLOUT sCallout;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ memset(&sCallout, 0, sizeof(FWPS_CALLOUT));
+
+ sCallout.calloutKey = *calloutKey;
+ sCallout.flags = flags;
+ sCallout.classifyFn = ClassifyFunction;
+ sCallout.notifyFn = NotifyFunction;
+ sCallout.flowDeleteFn = FlowDeleteFunction;
+
+ status = FwpsCalloutRegister(deviceObject, &sCallout, calloutId);
+
+ return status;
+}
+
+NTSTATUS
+MonitorCoRegisterCallouts(
+ _Inout_ void* deviceObject
+ )
+{
+ NTSTATUS status;
+
+ //
+ // We won't be called for flow deletion for the flow established layer
+ // since we only establish a flow for the stream layer, so we don't
+ // specify a flow deletion function.
+ //
+ status = MonitorCoRegisterCallout(deviceObject,
+ MonitorCoFlowEstablishedCalloutV4,
+ MonitorCoFlowEstablishedNotifyV4,
+ NULL, // We don't need a flow delete function at this layer.
+ &MONITOR_SAMPLE_FLOW_ESTABLISHED_CALLOUT_V4,
+ 0, // No flags.
+ &flowEstablishedId);
+
+ if (NT_SUCCESS(status))
+ {
+ status = MonitorCoRegisterCallout(deviceObject,
+ MonitorCoStreamCalloutV4,
+ MonitorCoStreamNotifyV4,
+ MonitorCoStreamFlowDeletion,
+ &MONITOR_SAMPLE_STREAM_CALLOUT_V4,
+ FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW,
+ &streamId);
+ }
+
+ return status;
+}
+
+NTSTATUS
+MonitorCoUnregisterCallout(
+ _In_ const GUID* calloutKey
+ )
+{
+ NTSTATUS status;
+
+ status = FwpsCalloutUnregisterByKey(calloutKey);
+
+ return status;
+}
+
+NTSTATUS
+MonitorCoUnregisterCallouts(void)
+{
+ NTSTATUS status;
+
+ status = MonitorCoUnregisterCallout(&MONITOR_SAMPLE_FLOW_ESTABLISHED_CALLOUT_V4);
+
+ if (NT_SUCCESS(status))
+ {
+ status = MonitorCoUnregisterCallout(&MONITOR_SAMPLE_STREAM_CALLOUT_V4);
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+MonitorCoInsertFlowContext(
+ _Inout_ FLOW_DATA* flowContext)
+{
+ KLOCK_QUEUE_HANDLE lockHandle;
+ NTSTATUS status;
+
+ KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);
+
+ // Catch the case where we disabled monitoring after we had intended to
+ // associate the context to the flow so that we don't bugcheck due to
+ // our driver being unloaded and then receiving a call for a particular
+ // flow or leak the memory because we unloaded without freeing it.
+ if (monitoringEnabled)
+ {
+ DoTraceMessage(TRACE_FLOW_ESTABLISHED, "Creating flow for traffic.\r\n");
+
+ InsertTailList(&flowContextList, &flowContext->listEntry);
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ DoTraceMessage(TRACE_FLOW_ESTABLISHED, "Unable to create flow, driver shutting down.\r\n");
+
+ // Our driver is shutting down.
+ status = STATUS_SHUTDOWN_IN_PROGRESS;
+ }
+
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+ return status;
+}
+
+void
+MonitorCoCleanupFlowContext(
+ _In_ __drv_freesMem(Mem) FLOW_DATA* flowContext
+ )
+/*
+Routine Description
+
+ Called to cleanup a flow context on flow deletion. ProcessPath is passed
+ as a second parameter so Prefast can see that it's being freed here.
+
+*/
+{
+ if (flowContext->processPath)
+ {
+ ExFreePoolWithTag(flowContext->processPath, TAG_NAME_CALLOUT);
+ }
+ ExFreePoolWithTag(flowContext, TAG_NAME_CALLOUT);
+}
+
+NTSTATUS
+MonitorCoAllocFlowContext(
+ _In_ SIZE_T processPathSize,
+ _Out_ FLOW_DATA** flowContextOut
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ FLOW_DATA* flowContext = NULL;
+
+ *flowContextOut = NULL;
+
+ flowContext = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(FLOW_DATA),
+ TAG_NAME_CALLOUT);
+
+ if (!flowContext)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+
+ RtlZeroMemory(flowContext,
+ sizeof(FLOW_DATA));
+
+
+ flowContext->processPath = ExAllocatePoolWithTag(NonPagedPool,
+ processPathSize,
+ TAG_NAME_CALLOUT);
+ if (!flowContext->processPath)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+
+ }
+
+ *flowContextOut = flowContext;
+
+ cleanup:
+ if (!NT_SUCCESS(status))
+ {
+ if (flowContext)
+ {
+ if (flowContext->processPath)
+ {
+ ExFreePoolWithTag(flowContext->processPath, TAG_NAME_CALLOUT);
+ }
+ ExFreePoolWithTag(flowContext, TAG_NAME_CALLOUT);
+ }
+ }
+
+ return status;
+}
+
+
+UINT64
+MonitorCoCreateFlowContext(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Out_ UINT64* flowHandle)
+/*
+Routine Description
+
+ Creates a flow context that is associated with the current flow
+
+Arguments
+ [IN] FWPS_CALLOUT_NOTIFY_TYPE notifyType - Type of notification
+
+ [IN] GUID* filterKey - Key of the filter that was
+ added/deleted/modified.
+
+ [IN] struct FWPS_FILTER_* filter - pointer to the Filter itself.
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ FLOW_DATA* flowContext = NULL;
+ NTSTATUS status;
+ FWP_BYTE_BLOB* processPath;
+ UINT32 index;
+
+ *flowHandle = 0;
+
+ if (!FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, FWPS_METADATA_FIELD_PROCESS_PATH))
+ {
+ status = STATUS_NOT_FOUND;
+ goto cleanup;
+ }
+
+ processPath = inMetaValues->processPath;
+
+ status = MonitorCoAllocFlowContext(processPath->size, &flowContext);
+ if (!NT_SUCCESS(status))
+ {
+ goto cleanup;
+ }
+
+ // Flow context is always created at the Flow established layer.
+
+ // flowContext gets deleted in MonitorCoCleanupFlowContext
+
+ flowContext->deleting = FALSE;
+ flowContext->flowHandle = inMetaValues->flowHandle;
+ *flowHandle = flowContext->flowHandle;
+
+ index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS;
+ flowContext->localAddressV4 = inFixedValues->incomingValue[index].value.uint32;
+
+
+ index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_PORT;
+ flowContext->localPort = inFixedValues->incomingValue[index].value.uint16;
+
+ index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_ADDRESS;
+ flowContext->remoteAddressV4 = inFixedValues->incomingValue[index].value.uint32;
+
+ index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_PORT;
+ flowContext->remotePort = inFixedValues->incomingValue[index].value.uint16;
+
+ index = FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL;
+ flowContext->ipProto = inFixedValues->incomingValue[index].value.uint16;
+
+ // flowContext->processPath gets deleted in MonitorCoCleanupFlowContext
+ memcpy(flowContext->processPath, processPath->data, processPath->size);
+
+ status = MonitorCoInsertFlowContext(flowContext);
+
+cleanup:
+
+ if (!NT_SUCCESS(status))
+ {
+ flowContext = NULL;
+ }
+
+ return (UINT64) flowContext;
+}
+
+NTSTATUS MonitorCoInitialize(_Inout_ DEVICE_OBJECT* deviceObject)
+/*
+Routine Description
+
+ Initializes our flow tracking so that we can handle the case where
+ the driver is shutdown with flows that are still active.
+
+Arguments
+
+ None.
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ NTSTATUS status;
+
+ // Initialize the flow context list and lock. We need this to be able
+ // to handle the case where our driver is stopped while we still have
+ // contexts associated with flows.
+ InitializeListHead(&flowContextList);
+ KeInitializeSpinLock(&flowContextListLock);
+
+ status = MonitorCoRegisterCallouts(deviceObject);
+
+ return status;
+}
+
+void MonitorCoUninitialize(void)
+/*
+Routine Description
+
+ Uninitializes the callouts module (this module) by ensuring that all
+ flow contexts are no longer associated with a flow to ensure that
+ our driver is not called after it is unloaded.
+
+Arguments
+
+ None.
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ LIST_ENTRY list;
+ KLOCK_QUEUE_HANDLE lockHandle;
+
+ // Make sure we don't associate any more contexts to flows.
+ MonitorCoDisableMonitoring();
+
+ InitializeListHead(&list);
+
+ KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);
+
+ while (!IsListEmpty(&flowContextList))
+ {
+ FLOW_DATA* flowContext;
+ LIST_ENTRY* entry;
+
+ entry = RemoveHeadList(&flowContextList);
+
+ flowContext = CONTAINING_RECORD(entry, FLOW_DATA, listEntry);
+ flowContext->deleting = TRUE; // We don't want our flow deletion function
+ // to try to remove this from the list.
+
+ InsertHeadList(&list, entry);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+
+ while (!IsListEmpty(&list))
+ {
+ FLOW_DATA* flowContext;
+ LIST_ENTRY* entry;
+ NTSTATUS status;
+
+ entry = RemoveHeadList(&list);
+
+ flowContext = CONTAINING_RECORD(entry, FLOW_DATA, listEntry);
+
+ status = FwpsFlowRemoveContext(flowContext->flowHandle,
+ FWPS_LAYER_STREAM_V4,
+ streamId);
+ NT_ASSERT(NT_SUCCESS(status));
+ _Analysis_assume_(NT_SUCCESS(status));
+ }
+
+ MonitorCoUnregisterCallouts();
+}
+
+NTSTATUS MonitorCoEnableMonitoring(
+ _In_ MONITOR_SETTINGS* monitorSettings)
+/*
+Routine Description
+
+ Enables monitoring of traffic. Before this is called the driver will not
+ associate any context to flows and will therefore not do any inspection.
+ Once this is called we will start to track flows for the applications that
+ we are interested in.
+
+Arguments
+ [IN] MONITOR_SETTINS monitorSettings - Settings that govern our behavior.
+ Nothing is specified at this time.
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ KLOCK_QUEUE_HANDLE lockHandle;
+
+ if (!monitorSettings)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ DoTraceMessage(TRACE_STATE_CHANGE, "Enabling monitoring.\r\n");
+
+ KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);
+
+ monitoringEnabled = 1;
+
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+
+ return STATUS_SUCCESS;
+}
+
+void
+MonitorCoDisableMonitoring(void)
+/*
+Routine Description
+
+ Disables monitoring of new connections so that we can safely shutdown.
+
+Arguments
+
+ None.
+
+Return values
+
+ None.
+
+Notes
+
+
+*/
+{
+ KLOCK_QUEUE_HANDLE lockHandle;
+
+ DoTraceMessage(TRACE_STATE_CHANGE, "Disabling monitoring.\r\n");
+
+ KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);
+
+ monitoringEnabled = 0;
+
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+NTSTATUS MonitorCoFlowEstablishedCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut)
+
+#else
+
+NTSTATUS MonitorCoFlowEstablishedCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut)
+
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+/*
+Routine Description
+
+ Our flow established callout for Ipv4 traffic.
+
+Arguments
+ [IN] const FWPS_INCOMING_VALUES* inFixedValues - The fixed values passed in
+ based on the traffic.
+ [IN] const FWPS_INCOMING_METADATA_VALUES* inMetaValues - Metadata the
+ provides additional
+ information about the
+ connection.
+ [IN] void* packet - Depending on the layer and protocol this can be NULL or a
+ layer specific type.
+ [IN, OPTIONAL] const VOID* classifyContext - context data associated with the callout driver
+ [IN] const FWPS_FILTER* filter - The filter that has specified this callout.
+ [IN] UINT64 flowContext - Flow context associated with a flow
+ [OUT] FWPS_CLASSIFY_OUT* classifyOut - Out parameter that is used to inform
+ the filter engine of our decision
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+
+ NTSTATUS status = STATUS_SUCCESS;
+ UINT64 flowHandle;
+ UINT64 flowContextLocal;
+
+ UNREFERENCED_PARAMETER(packet);
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(flowContext);
+
+ if (monitoringEnabled)
+ {
+ flowContextLocal = MonitorCoCreateFlowContext(inFixedValues, inMetaValues, &flowHandle);
+
+ if (!flowContextLocal)
+ {
+ classifyOut->actionType = FWP_ACTION_CONTINUE;
+ goto cleanup;
+ }
+
+ status = FwpsFlowAssociateContext(flowHandle,
+ FWPS_LAYER_STREAM_V4,
+ streamId,
+ flowContextLocal);
+ if (!NT_SUCCESS(status))
+ {
+ classifyOut->actionType = FWP_ACTION_CONTINUE;
+ goto cleanup;
+ }
+ }
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+cleanup:
+
+ return status;
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+NTSTATUS MonitorCoStreamCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_opt_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut)
+
+#else
+
+NTSTATUS MonitorCoStreamCalloutV4(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_opt_ void* packet,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut)
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+/*
+Routine Description
+
+ Our stream layer callout for traffic to/from the application we're
+ interested in. Since we specified the filter that matches this callout
+ as conditional on flow, we only get called if we've associated a flow with
+ the traffic.
+
+Arguments
+ [IN] const FWPS_INCOMING_VALUES* inFixedValues - The fixed values passed in
+ based on the traffic.
+ [IN] const FWPS_INCOMING_METADATA_VALUES* inMetaValues - Metadata the
+ provides additional
+ information about the
+ connection.
+ [IN] void* packet - Depending on the layer and protocol this can be NULL or a
+ layer specific type.
+ [IN] const FWPS_FILTER* filter - The filter that has specified this callout.
+ [IN, OPTIONAL] const VOID* classifyContext - context data associated with the callout driver
+ [IN] UINT64 flowContext - Flow context associated with a flow
+ [OUT] FWPS_CLASSIFY_OUT* classifyOut - Out parameter that is used to inform
+ the filter engine of our decision
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ FLOW_DATA* flowData;
+ FWPS_STREAM_CALLOUT_IO_PACKET* streamPacket;
+ NTSTATUS status = STATUS_SUCCESS;
+ BOOLEAN inbound;
+
+ UNREFERENCED_PARAMETER(inFixedValues);
+ UNREFERENCED_PARAMETER(inMetaValues);
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(filter);
+ UNREFERENCED_PARAMETER(flowContext);
+
+ _Analysis_assume_(packet != NULL);
+
+ if (!monitoringEnabled)
+ {
+ goto cleanup;
+ }
+
+ streamPacket = (FWPS_STREAM_CALLOUT_IO_PACKET*) packet;
+
+ if (streamPacket->streamData != NULL &&
+ streamPacket->streamData->dataLength != 0)
+ {
+ flowData = *(FLOW_DATA**)(UINT64*) &flowContext;
+
+ inbound = (BOOLEAN) ((streamPacket->streamData->flags & FWPS_STREAM_FLAG_RECEIVE) == FWPS_STREAM_FLAG_RECEIVE);
+
+ status = MonitorNfNotifyMessage(streamPacket->streamData,
+ inbound,
+ flowData->localPort,
+ flowData->remotePort);
+ }
+
+cleanup:
+
+ // Return CONTINUE to the filter engine, we're just monitoring.
+
+ classifyOut->actionType = FWP_ACTION_CONTINUE;
+
+ return status;
+}
+
+NTSTATUS MonitorCoFlowEstablishedNotifyV4(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter)
+/*
+Routine Description
+
+ Notification routine that is called whenever a filter is added, deleted or
+ modified on the layer that our callout is registered against.
+
+Arguments
+ [IN] FWPS_CALLOUT_NOTIFY_TYPE notifyType - Type of notification
+
+ [IN] GUID* filterKey - Key of the filter that was
+ added/deleted/modified.
+
+ [IN] struct FWPS_FILTER_* filter - pointer to the Filter itself.
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ switch (notifyType)
+ {
+ case FWPS_CALLOUT_NOTIFY_ADD_FILTER:
+ DoTraceMessage(TRACE_LAYER_NOTIFY,
+ "Filter Added to Flow Established layer.\r\n");
+
+ break;
+ case FWPS_CALLOUT_NOTIFY_DELETE_FILTER:
+ DoTraceMessage(TRACE_LAYER_NOTIFY,
+ "Filter Deleted from Flow Established layer.\r\n");
+ break;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void MonitorCoStreamFlowDeletion(
+ _In_ UINT16 layerId,
+ _In_ UINT32 calloutId,
+ _In_ UINT64 flowContext)
+{
+ KLOCK_QUEUE_HANDLE lockHandle;
+ FLOW_DATA* flowData;
+ HRESULT result;
+ ULONG_PTR flowPtr;
+
+
+ UNREFERENCED_PARAMETER(layerId);
+ UNREFERENCED_PARAMETER(calloutId);
+
+ result = ULongLongToULongPtr(flowContext, &flowPtr);
+ ASSERT(result == S_OK);
+ _Analysis_assume_(result == S_OK);
+
+
+ flowData = ((FLOW_DATA*)flowPtr);
+
+ //
+ // If we're already being deleted from the list then we mustn't try to
+ // remove ourselves here.
+ //
+ KeAcquireInStackQueuedSpinLock(&flowContextListLock, &lockHandle);
+
+ if (!flowData->deleting)
+ {
+ RemoveEntryList(&flowData->listEntry);
+ }
+
+ KeReleaseInStackQueuedSpinLock(&lockHandle);
+
+ MonitorCoCleanupFlowContext(flowData);
+}
+
+NTSTATUS MonitorCoStreamNotifyV4(
+ _In_ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ _In_ const GUID* filterKey,
+ _Inout_ const FWPS_FILTER* filter)
+/*
+Routine Description
+
+ Notification routine that is called whenever a filter is added, deleted or
+ modified on the layer that our callout is registered against.
+
+Arguments
+ [IN] FWPS_CALLOUT_NOTIFY_TYPE notifyType - Type of notification
+
+ [IN] GUID* filterKey - Key of the filter that was
+ added/deleted/modified.
+
+ [IN] struct FWPS_FILTER_* filter - pointer to the Filter itself.
+
+Return values
+
+ STATUS_SUCCESS or a specific error code.
+
+Notes
+
+
+*/
+{
+ UNREFERENCED_PARAMETER(notifyType);
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ switch (notifyType)
+ {
+ case FWPS_CALLOUT_NOTIFY_ADD_FILTER:
+ DoTraceMessage(TRACE_LAYER_NOTIFY,
+ "Filter Added to Stream layer.\r\n");
+
+ break;
+ case FWPS_CALLOUT_NOTIFY_DELETE_FILTER:
+ DoTraceMessage(TRACE_LAYER_NOTIFY,
+ "Filter Deleted from Stream layer.\r\n");
+ break;
+ }
+ return STATUS_SUCCESS;
+}
diff --git a/network/trans/msnmntr/sys/msnmntr.h b/network/trans/msnmntr/sys/msnmntr.h
new file mode 100644
index 00000000..adb470c0
--- /dev/null
+++ b/network/trans/msnmntr/sys/msnmntr.h
@@ -0,0 +1,55 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver callout header
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#pragma once
+
+typedef struct _FLOW_DATA
+{
+ UINT64 flowHandle;
+ UINT64 flowContext;
+ UINT64 calloutId;
+ ULONG localAddressV4;
+ USHORT localPort;
+ USHORT ipProto;
+ ULONG remoteAddressV4;
+ USHORT remotePort;
+ WCHAR* processPath;
+ LIST_ENTRY listEntry;
+ BOOLEAN deleting;
+} FLOW_DATA;
+
+NTSTATUS
+MonitorCoInitialize(_Inout_ DEVICE_OBJECT* deviceObject);
+
+void
+MonitorCoUninitialize(void);
+
+NTSTATUS
+MonitorCoRegisterCallouts(_Inout_ void* deviceObject);
+
+NTSTATUS
+MonitorCoUnregisterCallouts(void);
+
+NTSTATUS
+MonitorCoSetApplication(
+ _In_reads_(size) wchar_t* fileName,
+ _In_ ULONG size);
+
+NTSTATUS
+MonitorCoEnableMonitoring(
+ _In_ MONITOR_SETTINGS* monitorSettings);
+
+void
+MonitorCoDisableMonitoring(void);
+
diff --git a/network/trans/msnmntr/sys/msnmntr.inf b/network/trans/msnmntr/sys/msnmntr.inf
new file mode 100644
index 00000000..30d012b1
--- /dev/null
+++ b/network/trans/msnmntr/sys/msnmntr.inf
@@ -0,0 +1,54 @@
+;;;
+;;; Copyright (c) Microsoft Corporation. All rights reserved
+;;;
+;;; Abstract:
+;;; Monitor Callout sample driver install configuration.
+;;;
+
+[Version]
+ Signature = "$Windows NT$"
+ Class = WFPCALLOUTS
+ ClassGuid = {57465043-616C-6C6F-7574-5F636C617373}
+ Provider = %Contoso%
+ CatalogFile = MSNMntr.cat
+ DriverVer = 11/24/2014,14.24.55.836
+
+[SourceDisksNames]
+ 1 = %MSNMntrDisk%,,,""
+
+[SourceDisksFiles]
+ MSNMntr.sys = 1,,
+
+[DestinationDirs]
+ DefaultDestDir = 12 ; %WinDir%\System32\Drivers
+ MSNMntr.DriverFiles = 12 ; %WinDir%\System32\Drivers
+
+[DefaultInstall]
+ OptionDesc = %MSNMntrServiceDesc%
+ CopyFiles = MSNMntr.DriverFiles
+
+[DefaultInstall.Services]
+ AddService = %MSNMntrServiceName%,,MSNMntr.Service
+
+[DefaultUninstall]
+ DelFiles = MSNMntr.DriverFiles
+
+[DefaultUninstall.Services]
+ DelService = %MSNMntrServiceName%,0x200 ; SPSVCINST_STOPSERVICE
+
+[MSNMntr.DriverFiles]
+ MSNMntr.sys,,,0x00000040 ; COPYFLG_OVERWRITE_OLDER_ONLY
+
+[MSNMntr.Service]
+ DisplayName = %MSNMntrServiceName%
+ Description = %MSNMntrServiceDesc%
+ ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+ StartType = 3 ; SERVICE_DEMAND_START
+ ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ ServiceBinary = %12%\MSNMntr.sys ; %WinDir%\System32\Drivers\MSNMntr.sys
+
+[Strings]
+ Contoso = "Contoso Ltd."
+ MSNMntrDisk = "Monitor Installation Disk"
+ MSNMntrServiceDesc = "Monitor Callout Driver"
+ MSNMntrServiceName = "MSNMntr" \ No newline at end of file
diff --git a/network/trans/msnmntr/sys/msnmntr.vcxproj b/network/trans/msnmntr/sys/msnmntr.vcxproj
new file mode 100644
index 00000000..19d05a61
--- /dev/null
+++ b/network/trans/msnmntr/sys/msnmntr.vcxproj
@@ -0,0 +1,194 @@
+<?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>{A0314F39-C7C2-463C-B2BE-DF387AB755F5}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{2235E7F5-485C-4A50-AC6E-7D5127C63D50}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</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>Desktop</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>Desktop</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>Desktop</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">
+ <ClCompile Include="init.c; msnmntr.c; ctl.c; notify.c">
+ <WppEnabled>true</WppEnabled>
+ <WppKernelMode>true</WppKernelMode>
+ </ClCompile>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>msnmntr</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>msnmntr</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>msnmntr</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>msnmntr</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</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)\ntoskrnl.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'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</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)\ntoskrnl.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'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</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)\ntoskrnl.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'">
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);BINARY_COMPATIBLE=0;NT;UNICODE;_UNICODE;NDIS60;NDIS_SUPPORT_NDIS6;POOL_NX_OPTIN_AUTO</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\inc</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)\ntoskrnl.lib;$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <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/msnmntr/sys/msnmntr.vcxproj.Filters b/network/trans/msnmntr/sys/msnmntr.vcxproj.Filters
new file mode 100644
index 00000000..7a507ae9
--- /dev/null
+++ b/network/trans/msnmntr/sys/msnmntr.vcxproj.Filters
@@ -0,0 +1,35 @@
+<?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>{061ABC02-158F-4210-A282-D00E6E173776}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{EAF55685-C4D1-47E0-A3A8-B3E417170A02}</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>{7449D543-948C-4CDB-AB03-EE885873121D}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{E3258914-96DA-44CC-9DB9-3F58E7232911}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="ctl.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="init.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="msnmntr.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="notify.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/trans/msnmntr/sys/notify.c b/network/trans/msnmntr/sys/notify.c
new file mode 100644
index 00000000..22253797
--- /dev/null
+++ b/network/trans/msnmntr/sys/notify.c
@@ -0,0 +1,294 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver notification routines
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ntddk.h>
+
+#include <fwpmk.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+
+#include "ioctl.h"
+
+#include "msnmntr.h"
+
+#include "notify.h"
+
+//
+// Software Tracing Definitions
+//
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(MsnMntrNotify,(aca2f74a, 7a0d, 4f47, be4b, 66900813b8e5), \
+ WPP_DEFINE_BIT(TRACE_CLIENT_SERVER) \
+ WPP_DEFINE_BIT(TRACE_PEER_TO_PEER) \
+ WPP_DEFINE_BIT(TRACE_UNKNOWN) \
+ WPP_DEFINE_BIT(TRACE_ALL_TRAFFIC) )
+
+#include "notify.tmh" // This file will be auto generated
+
+
+#define TAG_NAME_NOTIFY 'oNnM'
+
+NTSTATUS
+MonitorNfInitialize(
+ _In_ DEVICE_OBJECT* deviceObject)
+{
+ UNREFERENCED_PARAMETER(deviceObject);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+MonitorNfUninitialize(void)
+{
+ return STATUS_SUCCESS;
+}
+
+__forceinline
+void*
+MonitorNfpFindCharacters(
+ _In_reads_bytes_(streamLength) const char* stream,
+ _In_ size_t streamLength,
+ _In_reads_bytes_(subStreamLength) const char* subStream,
+ _In_ size_t subStreamLength,
+ _Out_ size_t* bytesLeft)
+{
+ size_t currentOffset = 0;
+ void* subStreamPtr = NULL;
+
+ *bytesLeft = streamLength;
+
+ if (subStreamLength > streamLength)
+ {
+ return NULL;
+ }
+
+ while (currentOffset+subStreamLength <= streamLength)
+ {
+ if (0 == memcmp((void*)(stream+currentOffset), subStream, subStreamLength))
+ {
+ subStreamPtr = (void*)(char*)(stream+currentOffset);
+ *bytesLeft = streamLength;
+ *bytesLeft -= currentOffset;
+ *bytesLeft -= subStreamLength;
+ break;
+ }
+ currentOffset += subStreamLength;
+ }
+
+ return subStreamPtr;
+}
+
+NTSTATUS
+MonitorNfParseMessageInbound(
+ _In_reads_bytes_(streamLength) BYTE* stream,
+ _In_ size_t streamLength,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort)
+{
+ UNREFERENCED_PARAMETER(stream);
+
+ DoTraceMessage(TRACE_CLIENT_SERVER,
+ "%Id bytes received. Local Port: %d Remote Port: %d.",
+ streamLength,
+ localPort,
+ remotePort);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+MonitorNfParseMessageInboundHttpHeader(
+ _In_reads_bytes_(streamLength) BYTE* stream,
+ _In_ size_t streamLength,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort)
+{
+ BYTE* msgStart = NULL;
+ size_t bytesLeft;
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ // Walk past the HTTP header.
+ msgStart = (BYTE*) MonitorNfpFindCharacters((char*)stream,
+ streamLength,
+ "\r\n\r\n",
+ (ULONG)strlen("\r\n\r\n"),
+ &bytesLeft);
+ if (msgStart && (bytesLeft > 0))
+ {
+ size_t msgLength;
+
+ msgStart += 4; // step past \r\n\r\n.
+
+ msgLength = streamLength - (ULONG)(ULONG_PTR)(msgStart - stream);
+
+ // Do the final inbound message processing.
+ status = MonitorNfParseMessageInbound(msgStart,
+ msgLength,
+ localPort,
+ remotePort);
+ }
+
+ return status;
+}
+
+NTSTATUS
+MonitorNfParseMessageOutbound(
+ _In_reads_bytes_(streamLength) BYTE* stream,
+ _In_ size_t streamLength,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort)
+{
+ UNREFERENCED_PARAMETER(stream);
+
+ DoTraceMessage(TRACE_CLIENT_SERVER,
+ "%Id bytes sent. Local Port: %d Remote Port: %d.",
+ streamLength,
+ localPort,
+ remotePort);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+MonitorNfParseMessageOutboundHttpHeader(
+ _In_reads_bytes_(streamLength) BYTE* stream,
+ _In_ size_t streamLength,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort)
+{
+ BYTE* msgStart = NULL;
+ size_t bytesLeft;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ // Walk past the HTTP header.
+ msgStart = (BYTE*) MonitorNfpFindCharacters((char*)stream,
+ streamLength,
+ "\r\n\r\n",
+ (ULONG)strlen("\r\n\r\n"),
+ &bytesLeft);
+ if (msgStart && (bytesLeft > 0))
+ {
+ size_t msgLength;
+
+ msgStart += 4; // step past \r\n\r\n.
+
+ msgLength = streamLength - (ULONG)(ULONG_PTR)(msgStart - stream);
+ status = MonitorNfParseMessageOutbound(msgStart,
+ msgLength,
+ localPort,
+ remotePort);
+ }
+
+ return status;
+}
+
+NTSTATUS
+MonitorNfParseStreamAndTraceMessage(
+ _In_reads_bytes_(streamLength) BYTE* stream,
+ _In_ size_t streamLength,
+ _In_ BOOLEAN inbound,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort)
+{
+ NTSTATUS status;
+
+ if (!inbound)
+ {
+ if ((_strnicmp((const char*)stream, "POST", streamLength) == 0)
+ || (_strnicmp((const char*)stream, "GET", streamLength) == 0))
+ {
+ if ((MonitorNfParseMessageOutboundHttpHeader(stream,
+ streamLength,
+ localPort,
+ remotePort)) != STATUS_SUCCESS)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ if ((MonitorNfParseMessageOutbound(stream,
+ streamLength,
+ localPort,
+ remotePort)!= STATUS_SUCCESS))
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ if (_strnicmp((const char*)stream, "HTTP", streamLength) == 0)
+ {
+ if ((MonitorNfParseMessageInboundHttpHeader(stream,
+ streamLength,
+ localPort,
+ remotePort)) != STATUS_SUCCESS)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ else
+ {
+ if ((MonitorNfParseMessageInbound(stream,
+ streamLength,
+ localPort,
+ remotePort)) != STATUS_SUCCESS)
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ {
+ status = STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
+
+NTSTATUS MonitorNfNotifyMessage(
+ _In_ const FWPS_STREAM_DATA* streamBuffer,
+ _In_ BOOLEAN inbound,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort
+)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ BYTE* stream = NULL;
+ SIZE_T streamLength = streamBuffer->dataLength;
+ SIZE_T bytesCopied = 0;
+
+ if(streamLength == 0)
+ return status;
+
+ stream = ExAllocatePoolWithTag(NonPagedPool,
+ streamLength,
+ TAG_NAME_NOTIFY);
+ if (!stream)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ RtlZeroMemory(stream,streamLength);
+
+ FwpsCopyStreamDataToBuffer(
+ streamBuffer,
+ stream,
+ streamLength,
+ &bytesCopied);
+
+ NT_ASSERT(bytesCopied == streamLength);
+
+ status = MonitorNfParseStreamAndTraceMessage(stream, streamLength, inbound, localPort, remotePort);
+
+ ExFreePoolWithTag(stream, TAG_NAME_NOTIFY);
+
+ return status;
+}
diff --git a/network/trans/msnmntr/sys/notify.h b/network/trans/msnmntr/sys/notify.h
new file mode 100644
index 00000000..ba37fab2
--- /dev/null
+++ b/network/trans/msnmntr/sys/notify.h
@@ -0,0 +1,32 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Monitor Sample driver notification header
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#pragma once
+
+#define TAG_NOTIFY 'yftN'
+
+NTSTATUS
+MonitorNfInitialize(
+ _In_ DEVICE_OBJECT* deviceObject);
+
+NTSTATUS
+MonitorNfUninitialize(void);
+
+NTSTATUS MonitorNfNotifyMessage(
+ _In_ const FWPS_STREAM_DATA* streamBuffer,
+ _In_ BOOLEAN inbound,
+ _In_ USHORT localPort,
+ _In_ USHORT remotePort);
+
+
diff --git a/network/trans/stmedit/ReadMe.md b/network/trans/stmedit/ReadMe.md
new file mode 100644
index 00000000..da921272
--- /dev/null
+++ b/network/trans/stmedit/ReadMe.md
@@ -0,0 +1,60 @@
+Windows Filtering Platform Stream Edit Sample
+=============================================
+
+This sample driver demonstrates replacing a string pattern for a Transmission Control Protocol (TCP) connection using the Windows Filtering Platform (WFP).
+
+## Universal Compliant
+This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core.
+
+The sample consists of a kernel-mode Windows Filtering Platform (WFP) callout driver (Stmedit.sys) that can operate in one of the following modes:
+
+- Inline editing where all modification is done within the `ClassifyFn` callout function.
+- Out-of-band editing where all modification is done by a worker thread (the default).
+
+The sample performs inspection for both Internet Protocol version 4 (IPv4) and Internet Protocol version 6 (IPv6) traffic.
+
+Before experimenting with the sample, add an exception for the InspectionPort to your host firewall.
+
+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 stmedit.inf. Right click stmedit.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:\\WfpStreamEditSamplePackage).
+2. On the target computer, navigate to your driver package folder. Right click stmedit.inf, and choose **Install**
+
+Create Registry values
+----------------------
+
+- On the target computer, open Regedit, and navigate to this key:
+
+ **HKLM**\\**System**\\**CurrentControlSet**\\**Services**\\**strmedit**\\**Parameters**
+
+You can create and set values for the following registry entries.
+
+- **EditInline** (REG\_DWORD type): 1 for inline editing, 0 for out-of-band editing (the default)
+- **StringToFind** (REG\_SZ type): default = "rainy"
+- **StringToReplace** (REG\_SZ type): default = "sunny"
+- **InspectionPort** (REG\_DWORD type): TCP port (default = 5001)
+- **InspectOutbound** (REG\_DWORD type): TCP port (default = 0)
+
+Start the stmedit service
+-------------------------
+
+On the target computer, open a Command Prompt window as Administrator, and enter **net start stmedit**. (To stop the driver, enter **net stop stmedit**.)
+
+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/stmedit/stmedit.sln b/network/trans/stmedit/stmedit.sln
new file mode 100644
index 00000000..7f1cb436
--- /dev/null
+++ b/network/trans/stmedit/stmedit.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}") = "stmedit", "sys\stmedit.vcxproj", "{98513F1C-C28D-4F03-99A8-88FD4BD707C7}"
+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
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Debug|Win32.Build.0 = Debug|Win32
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Release|Win32.ActiveCfg = Release|Win32
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Release|Win32.Build.0 = Release|Win32
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Debug|x64.ActiveCfg = Debug|x64
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Debug|x64.Build.0 = Debug|x64
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Release|x64.ActiveCfg = Release|x64
+ {98513F1C-C28D-4F03-99A8-88FD4BD707C7}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/network/trans/stmedit/sys/inline_edit.c b/network/trans/stmedit/sys/inline_edit.c
new file mode 100644
index 00000000..16685a9e
--- /dev/null
+++ b/network/trans/stmedit/sys/inline_edit.c
@@ -0,0 +1,546 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream Edit Callout Driver Sample.
+
+ This sample demonstrates inline stream inspection/editing
+ via the WFP stream API.
+
+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 "inline_edit.h"
+#include "oob_edit.h"
+#include "stream_callout.h"
+
+void
+InlineEditInit(
+ _Out_ STREAM_EDITOR* streamEditor
+ )
+{
+ streamEditor->editInline = TRUE;
+ streamEditor->inlineEditState = INLINE_EDIT_WAITING_FOR_DATA;
+}
+
+void
+NTAPI StreamInjectCompletionFn(
+ _Inout_ void* context,
+ _Inout_ NET_BUFFER_LIST* netBufferList,
+ _In_ BOOLEAN dispatchLevel
+ )
+{
+ MDL* mdl = (MDL*)context;
+
+ UNREFERENCED_PARAMETER(dispatchLevel);
+
+ if (mdl != NULL)
+ {
+ IoFreeMdl(mdl);
+ }
+
+ FwpsFreeNetBufferList(netBufferList);
+}
+
+NTSTATUS
+StreamEditFlushData(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ UINT64 flowId,
+ UINT32 calloutId,
+ UINT16 layerId,
+ UINT32 streamFlags
+ )
+/* ++
+
+ This function re-injects buffered data back to the data stream upon
+ receiving a FIN. The data was buffered because it was not big enough
+ (size wise) to make an editing decision.
+
+-- */
+{
+ NTSTATUS status;
+
+ MDL* mdl = NULL;
+ NET_BUFFER_LIST* netBufferList = NULL;
+
+ NT_ASSERT(streamEditor->dataOffset == 0);
+
+ mdl = IoAllocateMdl(
+ streamEditor->scratchBuffer,
+ (ULONG)(streamEditor->dataLength),
+ FALSE,
+ FALSE,
+ NULL
+ );
+
+ if (mdl == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ MmBuildMdlForNonPagedPool(mdl);
+
+ status = FwpsAllocateNetBufferAndNetBufferList(
+ gNetBufferListPool,
+ 0,
+ 0,
+ mdl,
+ 0,
+ streamEditor->dataLength,
+ &netBufferList
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ streamFlags &= ~(FWPS_STREAM_FLAG_SEND_DISCONNECT | FWPS_STREAM_FLAG_RECEIVE_DISCONNECT);
+
+ status = FwpsStreamInjectAsync(
+ gInjectionHandle,
+ NULL,
+ 0,
+ flowId,
+ calloutId,
+ layerId,
+ streamFlags,
+ netBufferList,
+ streamEditor->dataLength,
+ StreamInjectCompletionFn,
+ mdl
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ mdl = NULL;
+ netBufferList = NULL;
+
+Exit:
+
+ if (mdl != NULL)
+ {
+ IoFreeMdl(mdl);
+ }
+ if (netBufferList != NULL)
+ {
+ FwpsFreeNetBufferList(netBufferList);
+ }
+
+ return status;
+}
+
+void
+StreamInlineEdit(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _In_ const FWPS_FILTER* filter,
+ _In_ const FWPS_STREAM_DATA* streamData,
+ _Inout_ FWPS_STREAM_CALLOUT_IO_PACKET* ioPacket,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+/* ++
+
+ This function implements the state machine that scans the content
+ and computes the number of bytes to permit, bytes to block, and
+ performs stream injection to replace the blocked data.
+
+-- */
+{
+ UINT findLength = (UINT) strlen(configStringToFind);
+ UINT replaceLength = (UINT) strlen(configStringToReplace);
+
+ if ((streamData->flags & FWPS_STREAM_FLAG_SEND_DISCONNECT) ||
+ (streamData->flags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT))
+ {
+ if (streamEditor->dataLength > 0)
+ {
+ StreamEditFlushData(
+ streamEditor,
+ inMetaValues->flowHandle,
+ filter->action.calloutId,
+ inFixedValues->layerId,
+ streamData->flags
+ );
+
+ streamEditor->dataLength = 0;
+ streamEditor->dataOffset = 0;
+ }
+
+ NT_ASSERT(streamEditor->inlineEditState == INLINE_EDIT_WAITING_FOR_DATA);
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ if (streamData->dataLength == 0)
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ if (streamEditor->inlineEditState != INLINE_EDIT_SKIPPING)
+ {
+ if ((streamData->dataLength < findLength) &&
+ !(classifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_NO_MORE_DATA))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NEED_MORE_DATA;
+ ioPacket->countBytesRequired = findLength;
+
+ classifyOut->actionType = FWP_ACTION_NONE;
+ goto Exit;
+ }
+ }
+
+ switch (streamEditor->inlineEditState)
+ {
+ case INLINE_EDIT_WAITING_FOR_DATA:
+ {
+ if (StreamCopyDataForInspection(
+ streamEditor,
+ streamData
+ ) == FALSE)
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ goto Exit;
+ }
+
+ //
+ // Pass-thru to scanning
+ //
+ }
+ case INLINE_EDIT_SCANNING:
+ {
+ UINT i;
+ BYTE* dataStart = (BYTE*)streamEditor->scratchBuffer + streamEditor->dataOffset;
+ BOOLEAN found = FALSE;
+
+ for (i = 0; i < streamEditor->dataLength; ++i)
+ {
+ if (i + findLength <= streamEditor->dataLength)
+ {
+ if (RtlCompareMemory(
+ dataStart + i,
+ configStringToFind,
+ findLength
+ ) == findLength)
+ {
+ found = TRUE;
+
+ streamEditor->inlineEditState = INLINE_EDIT_MODIFYING;
+
+ if (i != 0)
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = i;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ streamEditor->dataOffset += i;
+ streamEditor->dataLength -= i;
+
+ break;
+ }
+ else
+ {
+ goto modify_data;
+ }
+ }
+ }
+ else
+ {
+ if (classifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_NO_MORE_DATA)
+ {
+ break;
+ }
+
+ if (RtlCompareMemory(
+ dataStart + i,
+ configStringToFind,
+ streamEditor->dataLength - i
+ ) == streamEditor->dataLength - i)
+ {
+ found = TRUE; // this is a partial find
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = i;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ RtlMoveMemory(
+ streamEditor->scratchBuffer,
+ dataStart + i,
+ streamEditor->dataLength - i
+ );
+
+ streamEditor->dataOffset = 0;
+ streamEditor->dataLength = streamEditor->dataLength - i;
+
+ streamEditor->inlineEditState = INLINE_EDIT_SKIPPING;
+
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = 0;
+
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ streamEditor->dataOffset = 0;
+ streamEditor->dataLength = 0;
+
+ streamEditor->inlineEditState = INLINE_EDIT_WAITING_FOR_DATA;
+ }
+
+ break;
+ }
+ case INLINE_EDIT_SKIPPING:
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = 0;
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+
+ streamEditor->inlineEditState = INLINE_EDIT_WAITING_FOR_DATA;
+
+ break;
+ }
+ case INLINE_EDIT_MODIFYING:
+
+modify_data:
+
+ {
+ NTSTATUS status;
+ NET_BUFFER_LIST* netBufferList;
+
+ status = FwpsAllocateNetBufferAndNetBufferList(
+ gNetBufferListPool,
+ 0,
+ 0,
+ gStringToReplaceMdl,
+ 0,
+ replaceLength,
+ &netBufferList
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ goto Exit;
+ }
+
+ status = FwpsStreamInjectAsync(
+ gInjectionHandle,
+ NULL,
+ 0,
+ inMetaValues->flowHandle,
+ filter->action.calloutId,
+ inFixedValues->layerId,
+ streamData->flags,
+ netBufferList,
+ replaceLength,
+ StreamInjectCompletionFn,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ FwpsFreeNetBufferList(netBufferList);
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ goto Exit;
+ }
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = findLength;
+
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+
+ streamEditor->dataOffset += findLength;
+ streamEditor->dataLength -= findLength;
+
+ if (streamEditor->dataLength > 0)
+ {
+ streamEditor->inlineEditState = INLINE_EDIT_SCANNING;
+ }
+ else
+ {
+ streamEditor->dataOffset = 0;
+
+ streamEditor->inlineEditState = INLINE_EDIT_WAITING_FOR_DATA;
+ }
+
+ break;
+ }
+ default:
+ NT_ASSERT(FALSE);
+ break;
+ };
+
+Exit:
+
+ return;
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+NTAPI
+StreamInlineEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#else
+
+void
+NTAPI
+StreamInlineEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Out_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+/* ++
+
+ This is the ClassifyFn function registered by the inline stream edit callout.
+
+ An inline stream modification callout performs editing from within the
+ ClassifyFn call by permitting sections of the content and replacing other
+ sections by removing them and injecting new content.
+
+-- */
+{
+ FWPS_STREAM_CALLOUT_IO_PACKET* ioPacket;
+ FWPS_STREAM_DATA* streamData;
+
+ ioPacket = (FWPS_STREAM_CALLOUT_IO_PACKET*)layerData;
+ NT_ASSERT(ioPacket != NULL);
+
+ streamData = ioPacket->streamData;
+ NT_ASSERT(streamData != NULL);
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(flowContext);
+
+ RtlZeroMemory(classifyOut, sizeof(FWPS_CLASSIFY_OUT));
+
+ //
+ // Let go the traffic that the editor does not care about.
+ //
+
+ if ((configInspectionOutbound && (streamData->flags & FWPS_STREAM_FLAG_RECEIVE)) ||
+ (!configInspectionOutbound && (streamData->flags & FWPS_STREAM_FLAG_SEND)))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ //
+ // In this sample we don't edit TCP urgent data
+ //
+
+ if ((streamData->flags & FWPS_STREAM_FLAG_SEND_EXPEDITED) ||
+ (streamData->flags & FWPS_STREAM_FLAG_RECEIVE_EXPEDITED))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ StreamInlineEdit(
+ &gStreamEditor,
+ inFixedValues,
+ inMetaValues,
+ filter,
+ streamData,
+ ioPacket,
+ classifyOut
+ );
+
+Exit:
+
+ return;
+}
diff --git a/network/trans/stmedit/sys/inline_edit.h b/network/trans/stmedit/sys/inline_edit.h
new file mode 100644
index 00000000..a9345324
--- /dev/null
+++ b/network/trans/stmedit/sys/inline_edit.h
@@ -0,0 +1,65 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream Edit Callout Driver Sample.
+
+ This sample demonstrates inline stream inspection/editing
+ via the WFP stream API.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#ifndef _INLINE_EDIT_H
+#define _INLINE_EDIT_H
+
+typedef enum INLINE_EDIT_STATE_
+{
+ INLINE_EDIT_WAITING_FOR_DATA,
+ INLINE_EDIT_SKIPPING,
+ INLINE_EDIT_MODIFYING,
+ INLINE_EDIT_SCANNING
+} INLINE_EDIT_STATE;
+
+typedef struct STREAM_EDITOR_ STREAM_EDITOR;
+
+void
+InlineEditInit(
+ _Out_ STREAM_EDITOR*
+ );
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+NTAPI
+StreamInlineEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#else
+
+void
+NTAPI
+StreamInlineEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+#endif // _INLINE_EDIT_H
diff --git a/network/trans/stmedit/sys/oob_edit.c b/network/trans/stmedit/sys/oob_edit.c
new file mode 100644
index 00000000..ee53bc5e
--- /dev/null
+++ b/network/trans/stmedit/sys/oob_edit.c
@@ -0,0 +1,1363 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream Edit Callout Driver Sample.
+
+ This sample demonstrates Out-of-band (OOB) stream inspection/editing
+ via the WFP stream API.
+
+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 "inline_edit.h"
+#include "oob_edit.h"
+#include "stream_callout.h"
+
+#define STREAM_EDITOR_OUTGOING_DATA_TAG 'doeS'
+#define STREAM_EDITOR_MDL_DATA_TAG 'dmeS'
+
+void* gThreadObj;
+
+KSTART_ROUTINE StreamOobEditWorker;
+
+NTSTATUS
+OobEditInit(
+ _Out_ STREAM_EDITOR* streamEditor
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ HANDLE threadHandle;
+
+ streamEditor->editInline = FALSE;
+
+ KeInitializeSpinLock(&streamEditor->oobEditInfo.editLock);
+
+ KeInitializeEvent(
+ &streamEditor->oobEditInfo.editEvent,
+ NotificationEvent,
+ FALSE
+ );
+
+ streamEditor->oobEditInfo.busyThreshold = 32 * 1024;
+ streamEditor->oobEditInfo.editState = OOB_EDIT_IDLE;
+
+ InitializeListHead(&streamEditor->oobEditInfo.outgoingDataQueue);
+
+
+ status = PsCreateSystemThread(
+ &threadHandle,
+ THREAD_ALL_ACCESS,
+ NULL,
+ NULL,
+ NULL,
+ StreamOobEditWorker,
+ &gStreamEditor
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = ObReferenceObjectByHandle(
+ threadHandle,
+ 0,
+ NULL,
+ KernelMode,
+ &gThreadObj,
+ NULL
+ );
+ NT_ASSERT(NT_SUCCESS(status));
+
+ ZwClose(threadHandle);
+
+Exit:
+
+ return status;
+}
+
+void
+OobEditShutdown(
+ _Out_ STREAM_EDITOR* streamEditor
+ )
+{
+ KLOCK_QUEUE_HANDLE editLockHandle;
+
+ KeAcquireInStackQueuedSpinLock(
+ &streamEditor->oobEditInfo.editLock,
+ &editLockHandle
+ );
+
+ streamEditor->oobEditInfo.shuttingDown = TRUE;
+
+ switch (streamEditor->oobEditInfo.editState)
+ {
+ case OOB_EDIT_IDLE:
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_SHUT_DOWN;
+
+ KeSetEvent(
+ &gStreamEditor.oobEditInfo.editEvent,
+ IO_NO_INCREMENT,
+ FALSE
+ );
+
+ break;
+ }
+ default:
+ break;
+ };
+
+ KeReleaseInStackQueuedSpinLock(&editLockHandle);
+
+ NT_ASSERT(gThreadObj != NULL);
+
+ KeWaitForSingleObject(
+ gThreadObj,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ ObDereferenceObject(gThreadObj);
+}
+
+__inline
+NET_BUFFER_LIST*
+TailOfNetBufferListChain(
+ _In_ NET_BUFFER_LIST* netBufferListChain
+ )
+{
+ NT_ASSERT(netBufferListChain != NULL);
+
+ while (netBufferListChain->Next != NULL)
+ {
+ netBufferListChain = netBufferListChain->Next;
+ }
+
+ return netBufferListChain;
+}
+
+void
+NTAPI
+StreamOobInjectCompletionFn(
+ _Inout_ void* context,
+ _Inout_ NET_BUFFER_LIST* netBufferList,
+ BOOLEAN dispatchLevel
+ )
+/* ++
+
+ Injection completion function for injecting an NBL created using
+ FwpsAllocateNetBufferAndNetBufferList. This function frees up
+ resources allocated during StreamOobReinjectData().
+
+-- */
+{
+ MDL* mdl = (MDL*)context;
+
+ UNREFERENCED_PARAMETER(dispatchLevel);
+
+ FwpsFreeNetBufferList(netBufferList);
+
+ if (mdl != NULL)
+ {
+ IoFreeMdl(mdl);
+
+ //
+ // The MDL mapped over a pool alloc which we need to free here.
+ //
+
+ ExFreePoolWithTag(
+ mdl->MappedSystemVa,
+ STREAM_EDITOR_MDL_DATA_TAG
+ );
+ }
+}
+
+void
+NTAPI StreamOobInjectCloneCompletionFn(
+ _Inout_ void* context,
+ _Inout_ NET_BUFFER_LIST* netBufferList,
+ BOOLEAN dispatchLevel
+ )
+/* ++
+
+ Injection completion function for injecting one of the NBLs cloned
+ via FwpsCloneStreamData.
+
+ FwpsCloneStreamData can return a chain of cloned NBLs; each NBL will
+ complete separately.
+
+-- */
+{
+ UNREFERENCED_PARAMETER(context);
+ UNREFERENCED_PARAMETER(dispatchLevel);
+
+ FwpsFreeCloneNetBufferList(netBufferList, 0);
+}
+
+NTSTATUS
+StreamOobQueueUpIncomingData(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ _Inout_ FWPS_STREAM_DATA* streamData
+ )
+/* ++
+
+ This function clones the indicated stream data into a NBL chain and
+ appends the chain at the end of the existing chain (if exists) inside
+ the streamEditor.
+
+ This function assumes that the oobEditInfo lock inside streamEditor is
+ being held.
+
+-- */
+{
+ NTSTATUS status;
+
+ NET_BUFFER_LIST* clonedNetBufferListChain;
+
+ status = FwpsCloneStreamData(
+ streamData,
+ NULL,
+ NULL,
+ 0,
+ &clonedNetBufferListChain
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ //
+ // TCP Fin (EOF) is indicated by an empty NBL with disconnect flag
+ // set, since it does not contain any data we queue it up separately.
+ //
+
+ if ((streamData->flags & FWPS_STREAM_FLAG_SEND_DISCONNECT) ||
+ (streamData->flags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT))
+ {
+ NT_ASSERT(streamEditor->oobEditInfo.noMoreData);
+ NT_ASSERT(streamEditor->oobEditInfo.nblEof == NULL);
+ NT_ASSERT(streamData->dataLength == 0);
+
+ streamEditor->oobEditInfo.nblEof = clonedNetBufferListChain;
+
+ status = STATUS_SUCCESS;
+ goto Exit;
+ }
+
+ if (streamEditor->oobEditInfo.nblTail != NULL)
+ {
+ NT_ASSERT(streamEditor->oobEditInfo.nblHead != NULL);
+ NT_ASSERT(streamEditor->oobEditInfo.nblTail->Next == NULL);
+
+ streamEditor->oobEditInfo.nblTail->Next = clonedNetBufferListChain;
+ }
+ else
+ {
+ NT_ASSERT(streamEditor->oobEditInfo.nblHead == NULL);
+
+ streamEditor->oobEditInfo.nblHead = clonedNetBufferListChain;
+ }
+
+ streamEditor->oobEditInfo.nblTail =
+ TailOfNetBufferListChain(clonedNetBufferListChain);
+
+ streamEditor->oobEditInfo.totalDataLength += streamData->dataLength;
+
+ streamEditor->oobEditInfo.streamFlags = streamData->flags;
+
+Exit:
+
+ return status;
+}
+
+void
+StreamOobEdit(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ const FWPS_INCOMING_VALUES* inFixedValues,
+ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ const FWPS_FILTER* filter,
+ _Inout_ FWPS_STREAM_DATA* streamData,
+ _Inout_ FWPS_STREAM_CALLOUT_IO_PACKET* ioPacket,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+/* ++
+
+ This function queues up incoming data and notifies the worker thread
+ to process them. The incoming data is blocked and removed from the
+ stream while data is pending.
+
+ If the editor is shutdown (e.g. during driverUnload) as indicated
+ by OOB_EDIT_SHUT_DOWN state, it permits the indicated data inline after
+ flushing all pended data (to be carried out by the caller).
+
+-- */
+
+{
+ NTSTATUS status;
+
+ KLOCK_QUEUE_HANDLE editLockHandle;
+
+ KeAcquireInStackQueuedSpinLock(
+ &streamEditor->oobEditInfo.editLock,
+ &editLockHandle
+ );
+
+ if (streamEditor->oobEditInfo.nblEof != NULL)
+ {
+ //
+ // A new flow arrives before we finish processing an earlier flow. Production
+ // code should create 1:1 between streamEditor and flow to handle this
+ // condition. See the "MSN Monitor sample" for how that can be implemented.
+ //
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+
+ goto Exit;
+ }
+
+ if (classifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_NO_MORE_DATA)
+ {
+ NT_ASSERT(streamEditor->oobEditInfo.nblEof == NULL);
+
+ streamEditor->oobEditInfo.noMoreData = TRUE;
+ }
+
+ //
+ // Record needed flow information etc for data (re-)injection.
+ //
+
+ streamEditor->oobEditInfo.calloutId = filter->action.calloutId;
+ streamEditor->oobEditInfo.flowId = inMetaValues->flowHandle;
+ streamEditor->oobEditInfo.layerId = inFixedValues->layerId;
+
+ switch (streamEditor->oobEditInfo.editState)
+ {
+ case OOB_EDIT_PROCESSING:
+ {
+ if ((streamEditor->oobEditInfo.totalDataLength + streamData->dataLength) >
+ streamEditor->oobEditInfo.busyThreshold)
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DEFER;
+ classifyOut->actionType = FWP_ACTION_NONE;
+
+ streamEditor->oobEditInfo.editState = OOB_EDIT_BUSY;
+ }
+ else
+ {
+ status = StreamOobQueueUpIncomingData(
+ streamEditor,
+ streamData
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_ERROR;
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ }
+ else
+ {
+ //
+ // State remains at OOB_EDIT_PROCESSING state. Since the worker thread
+ // is active there is no need to set the event (to wake it up)
+ //
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = 0;
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+ }
+
+ break;
+ }
+ case OOB_EDIT_IDLE:
+ {
+ status = StreamOobQueueUpIncomingData(
+ streamEditor,
+ streamData
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_ERROR;
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ }
+ else
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_PROCESSING;
+
+ //
+ // The worker thread is idle waiting for more work, now wake it up.
+ //
+ KeSetEvent(
+ &streamEditor->oobEditInfo.editEvent,
+ 0,
+ FALSE
+ );
+
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = 0;
+ classifyOut->actionType = FWP_ACTION_BLOCK;
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ break;
+ }
+ case OOB_EDIT_SHUT_DOWN:
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ ioPacket->countBytesEnforced = 0;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ break;
+ }
+ case OOB_EDIT_ERROR:
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ break;
+ }
+ default:
+ NT_ASSERT(FALSE);
+ };
+
+Exit:
+
+ KeReleaseInStackQueuedSpinLock(&editLockHandle);
+}
+
+NTSTATUS
+StreamOobQueueUpOutgoingData(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ _Inout_ NET_BUFFER_LIST* netBufferList,
+ BOOLEAN isClone,
+ size_t dataLength,
+ DWORD streamFlags,
+ _In_opt_ MDL* mdl
+ )
+/* ++
+
+ This function queues up processed data (either sections of the indicated
+ data or newly created data) such that they can be (re-)injected back to
+ the data stream during the following context.
+
+ 1. Before FWP_ACTION_BLOCK is returned from the ClassifyFn, or
+ 2. After EOF is indicated.
+
+ Under the conditions above, the incoming data (which we pend) and the
+ outgoing data (which we (re-)inject) can be synchronized properly).
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ KLOCK_QUEUE_HANDLE editLockHandle;
+ OUTGOING_STREAM_DATA* outgoingStreamData;
+
+ outgoingStreamData = (OUTGOING_STREAM_DATA*) ExAllocatePoolWithTag(
+ NonPagedPool,
+ sizeof(OUTGOING_STREAM_DATA),
+ STREAM_EDITOR_OUTGOING_DATA_TAG
+ );
+
+ if (outgoingStreamData == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ return status;
+ }
+
+ RtlZeroMemory(outgoingStreamData, sizeof(OUTGOING_STREAM_DATA));
+
+ outgoingStreamData->netBufferList = netBufferList;
+ outgoingStreamData->isClone = isClone;
+ outgoingStreamData->dataLength = dataLength;
+ outgoingStreamData->streamFlags = streamFlags;
+ outgoingStreamData->mdl = mdl;
+
+ KeAcquireInStackQueuedSpinLock(
+ &streamEditor->oobEditInfo.editLock,
+ &editLockHandle
+ );
+
+ InsertTailList(
+ &streamEditor->oobEditInfo.outgoingDataQueue,
+ &outgoingStreamData->listEntry
+ );
+
+ KeReleaseInStackQueuedSpinLock(&editLockHandle);
+
+ return status;
+}
+
+NTSTATUS
+StreamOobFlushOutgoingData(
+ _Inout_ STREAM_EDITOR* streamEditor
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ KLOCK_QUEUE_HANDLE editLockHandle;
+ OUTGOING_STREAM_DATA* outgoingStreamData = NULL;
+
+ for(;;)
+ {
+ KeAcquireInStackQueuedSpinLock(
+ &streamEditor->oobEditInfo.editLock,
+ &editLockHandle
+ );
+
+ if (!IsListEmpty(&streamEditor->oobEditInfo.outgoingDataQueue))
+ {
+ LIST_ENTRY* listEntry =
+ RemoveHeadList(&streamEditor->oobEditInfo.outgoingDataQueue);
+
+ outgoingStreamData = CONTAINING_RECORD(
+ listEntry,
+ OUTGOING_STREAM_DATA,
+ listEntry
+ );
+ }
+
+ KeReleaseInStackQueuedSpinLock(&editLockHandle);
+
+ if (outgoingStreamData == NULL)
+ {
+ break;
+ }
+
+ status = FwpsStreamInjectAsync(
+ gInjectionHandle,
+ NULL,
+ 0,
+ streamEditor->oobEditInfo.flowId,
+ streamEditor->oobEditInfo.calloutId,
+ streamEditor->oobEditInfo.layerId,
+ outgoingStreamData->streamFlags,
+ outgoingStreamData->netBufferList,
+ outgoingStreamData->dataLength,
+ outgoingStreamData->isClone ? StreamOobInjectCloneCompletionFn :
+ StreamOobInjectCompletionFn,
+ outgoingStreamData->mdl
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ ExFreePoolWithTag(
+ outgoingStreamData,
+ STREAM_EDITOR_OUTGOING_DATA_TAG
+ );
+
+ outgoingStreamData = NULL;
+ }
+
+Exit:
+
+ if (outgoingStreamData != NULL)
+ {
+ NT_ASSERT(!NT_SUCCESS(status));
+
+ if (outgoingStreamData->isClone)
+ {
+ FwpsDiscardClonedStreamData(
+ outgoingStreamData->netBufferList,
+ 0,
+ FALSE
+ );
+ }
+ else
+ {
+ FwpsFreeNetBufferList(outgoingStreamData->netBufferList);
+
+ if (outgoingStreamData->mdl != NULL)
+ {
+ IoFreeMdl(outgoingStreamData->mdl);
+
+ ExFreePoolWithTag(
+ outgoingStreamData->mdl->MappedSystemVa,
+ STREAM_EDITOR_MDL_DATA_TAG
+ );
+ }
+ }
+
+ ExFreePoolWithTag(
+ outgoingStreamData,
+ STREAM_EDITOR_OUTGOING_DATA_TAG
+ );
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+StreamOobReinjectData(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ UINT32 streamFlags,
+ const void* data,
+ size_t length
+ )
+/* ++
+
+ This function injects a section of the original indicated data back
+ to the data stream.
+
+ An MDL is allocated to describe the data section.
+
+-- */
+{
+ NTSTATUS status;
+
+ void* dataCopy = NULL;
+ MDL* mdl = NULL;
+ NET_BUFFER_LIST* netBufferList = NULL;
+
+ dataCopy = ExAllocatePoolWithTag(
+ NonPagedPool,
+ length,
+ STREAM_EDITOR_MDL_DATA_TAG
+ );
+
+ if (dataCopy == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ RtlCopyMemory(dataCopy, data, length);
+
+ mdl = IoAllocateMdl(
+ dataCopy,
+ (ULONG)length,
+ FALSE,
+ FALSE,
+ NULL
+ );
+ if (mdl == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ MmBuildMdlForNonPagedPool(mdl);
+
+ status = FwpsAllocateNetBufferAndNetBufferList(
+ gNetBufferListPool,
+ 0,
+ 0,
+ mdl,
+ 0,
+ length,
+ &netBufferList
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ NT_ASSERT(!(streamFlags & FWPS_STREAM_FLAG_SEND_DISCONNECT) &&
+ !(streamFlags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT));
+
+ status = StreamOobQueueUpOutgoingData(
+ streamEditor,
+ netBufferList,
+ FALSE,
+ length,
+ streamFlags,
+ mdl
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ dataCopy = NULL;
+ mdl = NULL;
+ netBufferList = NULL;
+
+Exit:
+
+ if (netBufferList != NULL)
+ {
+ FwpsFreeNetBufferList(netBufferList);
+ }
+ if (mdl != NULL)
+ {
+ IoFreeMdl(mdl);
+ }
+ if (dataCopy != NULL)
+ {
+ ExFreePoolWithTag(
+ dataCopy,
+ STREAM_EDITOR_MDL_DATA_TAG
+ );
+ }
+ return status;
+}
+
+NTSTATUS
+StreamOobInjectReplacement(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ UINT32 streamFlags,
+ _In_opt_ MDL* data,
+ size_t length
+ )
+/* ++
+
+ This function injects a section of replacement data (in place of data
+ removed from the stream) into the data stream.
+
+ The MDL describes the replacement data is allocated during DriverEntry
+ and does not need to be freed during injection completion.
+
+-- */
+{
+ NTSTATUS status;
+
+ NET_BUFFER_LIST* netBufferList = NULL;
+
+ status = FwpsAllocateNetBufferAndNetBufferList(
+ gNetBufferListPool,
+ 0,
+ 0,
+ data,
+ 0,
+ length,
+ &netBufferList
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ NT_ASSERT(!(streamFlags & FWPS_STREAM_FLAG_SEND_DISCONNECT) &&
+ !(streamFlags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT));
+
+ status = StreamOobQueueUpOutgoingData(
+ streamEditor,
+ netBufferList,
+ FALSE,
+ length,
+ streamFlags,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ FwpsFreeNetBufferList(netBufferList);
+ goto Exit;
+ }
+
+ netBufferList = NULL;
+
+Exit:
+
+ if (netBufferList != NULL)
+ {
+ FwpsFreeNetBufferList(netBufferList);
+ }
+
+ return status;
+}
+
+NTSTATUS
+StreamOobCopyDataToFlatBuffer(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ _Inout_ NET_BUFFER_LIST* netBufferListChain,
+ size_t totalDataLength,
+ DWORD streamFlags
+ )
+/* ++
+
+ This function copies the data described by NBL(s) into a flat buffer.
+
+ It reuses the FwpsCopyStreamDataToBuffer API (via StreamCopyDataForInspection)
+ by creating a FWPS_STREAM_DATA struct.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPS_STREAM_DATA streamData = {0};
+
+ if (totalDataLength > 0)
+ {
+ streamData.netBufferListChain = netBufferListChain;
+ streamData.dataLength = totalDataLength;
+ streamData.flags = streamFlags;
+
+ streamData.dataOffset.netBufferList = netBufferListChain;
+ streamData.dataOffset.netBuffer =
+ NET_BUFFER_LIST_FIRST_NB(streamData.dataOffset.netBufferList);
+ streamData.dataOffset.mdl =
+ NET_BUFFER_CURRENT_MDL(streamData.dataOffset.netBuffer);
+ streamData.dataOffset.mdlOffset =
+ NET_BUFFER_CURRENT_MDL_OFFSET(streamData.dataOffset.netBuffer);
+
+ if (StreamCopyDataForInspection(
+ streamEditor,
+ &streamData
+ ) == FALSE)
+ {
+ status = STATUS_NO_MEMORY;
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+StreamOobEditData(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ _Inout_ NET_BUFFER_LIST* netBufferListChain,
+ size_t totalDataLength,
+ DWORD streamFlags
+ )
+/* ++
+
+ This function first copies the stream data into a flat inspection buffer;
+ it then parses the buffer looking for the matching pattern. For
+ non-matching sections it re-injects the data back; for a match it skips
+ over and injects an replacement section.
+
+ If a match can not be determined due to lack of data, it injects the
+ non-matching section back and moves the potential match to the beginning
+ of the inspection buffer.
+
+ When an EOF is reached, it flushes all processed stream sections back
+ and re-injects the FIN back to end the stream.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ UINT i = 0;
+ BOOLEAN streamModified = FALSE;
+ BOOLEAN potentialMatch = FALSE;
+
+ BYTE* dataStart;
+
+ UINT findLength = (UINT) strlen(configStringToFind);
+
+ status = StreamOobCopyDataToFlatBuffer(
+ streamEditor,
+ netBufferListChain,
+ totalDataLength,
+ streamFlags
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ dataStart = (BYTE*)streamEditor->scratchBuffer + streamEditor->dataOffset;
+
+ for (; i < streamEditor->dataLength; ++i)
+ {
+ if (i + findLength <= streamEditor->dataLength)
+ {
+ if (RtlCompareMemory(
+ dataStart + i,
+ configStringToFind,
+ findLength
+ ) == findLength)
+ {
+ if (i != 0)
+ {
+ status = StreamOobReinjectData(
+ streamEditor,
+ streamFlags,
+ dataStart,
+ i
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ streamEditor->dataOffset += i;
+ streamEditor->dataLength -= i;
+
+ i = 0;
+ }
+
+ status = StreamOobInjectReplacement(
+ streamEditor,
+ streamFlags,
+ gStringToReplaceMdl,
+ strlen(configStringToReplace)
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ streamEditor->dataOffset += findLength;
+ streamEditor->dataLength -= findLength;
+
+ streamModified = TRUE;
+
+ if (streamEditor->dataLength > 0)
+ {
+ dataStart = (BYTE*)streamEditor->scratchBuffer + streamEditor->dataOffset;
+
+ --i;
+
+ continue;
+ }
+ else
+ {
+ streamEditor->dataOffset = 0;
+ }
+ }
+ }
+ else
+ {
+ if (streamEditor->oobEditInfo.noMoreData)
+ {
+ break;
+ }
+
+ if (RtlCompareMemory(
+ dataStart + i,
+ configStringToFind,
+ streamEditor->dataLength - i
+ ) == streamEditor->dataLength - i)
+ {
+ potentialMatch = TRUE; // this is a partial find
+
+ status = StreamOobReinjectData(
+ streamEditor,
+ streamFlags,
+ dataStart,
+ i
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ RtlMoveMemory(
+ (BYTE*)streamEditor->scratchBuffer,
+ dataStart + i,
+ streamEditor->dataLength - i
+ );
+
+ streamEditor->dataOffset = 0;
+ streamEditor->dataLength = streamEditor->dataLength - i;
+
+ break;
+ }
+ }
+ }
+
+ if (streamModified && streamEditor->dataLength > 0)
+ {
+ status = StreamOobReinjectData(
+ streamEditor,
+ streamFlags,
+ dataStart,
+ streamEditor->dataLength
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ streamEditor->dataOffset = 0;
+ streamEditor->dataLength = 0;
+ }
+
+ if (!streamModified && !potentialMatch)
+ {
+ if (totalDataLength > 0)
+ {
+ NT_ASSERT(!(streamFlags & FWPS_STREAM_FLAG_SEND_DISCONNECT) &&
+ !(streamFlags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT));
+
+ status = StreamOobQueueUpOutgoingData(
+ streamEditor,
+ netBufferListChain,
+ TRUE,
+ totalDataLength,
+ streamFlags,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ netBufferListChain = NULL;
+ }
+ else if (streamEditor->dataLength > 0)
+ {
+ status = StreamOobReinjectData(
+ streamEditor,
+ streamFlags,
+ dataStart,
+ streamEditor->dataLength
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+ streamEditor->dataOffset = 0;
+ streamEditor->dataLength = 0;
+ }
+
+ if (streamEditor->oobEditInfo.nblEof != NULL)
+ {
+ status = StreamOobFlushOutgoingData(streamEditor);
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = FwpsStreamInjectAsync(
+ gInjectionHandle,
+ NULL,
+ 0,
+ streamEditor->oobEditInfo.flowId,
+ streamEditor->oobEditInfo.calloutId,
+ streamEditor->oobEditInfo.layerId,
+ streamFlags | (configInspectionOutbound ? FWPS_STREAM_FLAG_SEND_DISCONNECT :
+ FWPS_STREAM_FLAG_RECEIVE_DISCONNECT),
+ streamEditor->oobEditInfo.nblEof,
+ 0,
+ StreamOobInjectCompletionFn,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ streamEditor->oobEditInfo.nblEof = NULL;
+ streamEditor->oobEditInfo.noMoreData = FALSE;
+ }
+
+Exit:
+
+ if (netBufferListChain != NULL)
+ {
+ FwpsDiscardClonedStreamData(
+ netBufferListChain,
+ 0,
+ FALSE
+ );
+ }
+
+ if (streamEditor->oobEditInfo.nblEof != NULL)
+ {
+ FwpsDiscardClonedStreamData(
+ streamEditor->oobEditInfo.nblEof,
+ 0,
+ FALSE
+ );
+
+ streamEditor->oobEditInfo.nblEof = NULL;
+ }
+
+ return status;
+}
+
+_IRQL_requires_same_
+_Function_class_(KSTART_ROUTINE)
+void
+StreamOobEditWorker(
+ _In_ void* StartContext
+ )
+/* ++
+
+ This function waits for an event which gets signalled when there is data
+ waiting to be inspected.
+
+ Once awaken, the worker thread edits the stream until all stream data is
+ processed (and then it waits for more work again).
+
+ When requested to shutdown, it will finish the editing task and enters
+ "shutdown" state.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ NET_BUFFER_LIST* netBufferListChain = NULL;
+ size_t totalDataLength;
+ STREAM_EDITOR* streamEditor = (STREAM_EDITOR*)StartContext;
+ DWORD streamFlags;
+
+ for(;;)
+ {
+ KLOCK_QUEUE_HANDLE editLockHandle;
+
+ KeWaitForSingleObject(
+ &streamEditor->oobEditInfo.editEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ if (streamEditor->oobEditInfo.editState == OOB_EDIT_ERROR ||
+ streamEditor->oobEditInfo.editState == OOB_EDIT_SHUT_DOWN)
+ {
+ break;
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &streamEditor->oobEditInfo.editLock,
+ &editLockHandle
+ );
+
+ NT_ASSERT(streamEditor->oobEditInfo.editState == OOB_EDIT_PROCESSING ||
+ streamEditor->oobEditInfo.editState == OOB_EDIT_BUSY);
+
+ netBufferListChain = streamEditor->oobEditInfo.nblHead;
+ totalDataLength = streamEditor->oobEditInfo.totalDataLength;
+ streamFlags = streamEditor->oobEditInfo.streamFlags;
+
+ streamEditor->oobEditInfo.nblHead = NULL;
+ streamEditor->oobEditInfo.nblTail = NULL;
+ streamEditor->oobEditInfo.totalDataLength = 0;
+
+ KeReleaseInStackQueuedSpinLock(&editLockHandle);
+
+ _Analysis_assume_(netBufferListChain != NULL);
+ status = StreamOobEditData(
+ streamEditor,
+ netBufferListChain,
+ totalDataLength,
+ streamFlags
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_ERROR;
+ break;
+ }
+
+ if (streamEditor->oobEditInfo.editState == OOB_EDIT_BUSY)
+ {
+ NTSTATUS streamContinueStatus;
+ streamEditor->oobEditInfo.editState = OOB_EDIT_PROCESSING;
+
+ streamContinueStatus = FwpsStreamContinue(
+ streamEditor->oobEditInfo.flowId,
+ streamEditor->oobEditInfo.calloutId,
+ streamEditor->oobEditInfo.layerId,
+ streamEditor->oobEditInfo.streamFlags
+ );
+
+ if (!NT_SUCCESS(streamContinueStatus))
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_ERROR;
+ break;
+ }
+ }
+
+ KeAcquireInStackQueuedSpinLock(
+ &streamEditor->oobEditInfo.editLock,
+ &editLockHandle
+ );
+
+ if (streamEditor->oobEditInfo.nblHead == NULL)
+ {
+ if (!streamEditor->oobEditInfo.shuttingDown)
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_IDLE;
+ KeClearEvent(&streamEditor->oobEditInfo.editEvent);
+ }
+ else
+ {
+ streamEditor->oobEditInfo.editState = OOB_EDIT_SHUT_DOWN;
+ }
+ }
+
+ KeReleaseInStackQueuedSpinLock(&editLockHandle);
+ }
+
+ PsTerminateSystemThread(status);
+}
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+NTAPI
+StreamOobEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ )
+
+#else
+
+void
+NTAPI
+StreamOobEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ 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 registered by the OOB stream edit callout.
+
+ An OOB stream modification callout blocks all indicated data after cloning
+ them for processing by a kernel mode worker thread (or marshalling the data
+ to user mode for inspection); the resultant/edited data will then be put
+ back to the stream via the stream injection API.
+
+ For such a callout, the processed data must be (re-)injected back to the
+ stream from within the ClassifyFn.
+
+-- */
+{
+ FWPS_STREAM_CALLOUT_IO_PACKET* ioPacket;
+ FWPS_STREAM_DATA* streamData;
+
+ UINT findLength = (UINT) strlen(configStringToFind);
+
+ ioPacket = (FWPS_STREAM_CALLOUT_IO_PACKET*)layerData;
+ NT_ASSERT(ioPacket != NULL);
+
+ streamData = ioPacket->streamData;
+ NT_ASSERT(streamData != NULL);
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(classifyContext);
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+ UNREFERENCED_PARAMETER(flowContext);
+
+ RtlZeroMemory(classifyOut, sizeof(FWPS_CLASSIFY_OUT));
+
+ //
+ // Let go the traffic that the editor does not care about.
+ //
+
+ if ((configInspectionOutbound && (streamData->flags & FWPS_STREAM_FLAG_RECEIVE)) ||
+ (!configInspectionOutbound && (streamData->flags & FWPS_STREAM_FLAG_SEND)))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ //
+ // In this sample we don't edit TCP urgent data
+ //
+
+ if ((streamData->flags & FWPS_STREAM_FLAG_SEND_EXPEDITED) ||
+ (streamData->flags & FWPS_STREAM_FLAG_RECEIVE_EXPEDITED))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NONE;
+ classifyOut->actionType = FWP_ACTION_PERMIT;
+
+ if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT)
+ {
+ classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+
+ goto Exit;
+ }
+
+ if ((streamData->dataLength < findLength) &&
+ !(classifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_NO_MORE_DATA))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_NEED_MORE_DATA;
+ ioPacket->countBytesRequired = findLength;
+
+ classifyOut->actionType = FWP_ACTION_NONE;
+ goto Exit;
+ }
+
+ StreamOobEdit(
+ &gStreamEditor,
+ inFixedValues,
+ inMetaValues,
+ filter,
+ streamData,
+ ioPacket,
+ classifyOut
+ );
+
+ if (classifyOut->actionType == FWP_ACTION_BLOCK ||
+ classifyOut->actionType == FWP_ACTION_PERMIT)
+ {
+ if (!(streamData->flags & FWPS_STREAM_FLAG_SEND_DISCONNECT) &&
+ !(streamData->flags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT))
+ {
+ NTSTATUS status = StreamOobFlushOutgoingData( &gStreamEditor);
+ if (!NT_SUCCESS(status))
+ {
+ ioPacket->streamAction = FWPS_STREAM_ACTION_DROP_CONNECTION;
+ classifyOut->actionType = FWP_ACTION_NONE;
+ }
+ }
+ }
+
+Exit:
+
+ return;
+}
diff --git a/network/trans/stmedit/sys/oob_edit.h b/network/trans/stmedit/sys/oob_edit.h
new file mode 100644
index 00000000..e5a0e506
--- /dev/null
+++ b/network/trans/stmedit/sys/oob_edit.h
@@ -0,0 +1,83 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream Edit Callout Driver Sample.
+
+ This sample demonstrates Out-of-band (OOB) stream inspection/editing
+ via the WFP stream API.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#ifndef _OOB_EDIT_H
+#define _OOB_EDIT_H
+
+typedef enum OOB_EDIT_STATE_
+{
+ OOB_EDIT_IDLE,
+ OOB_EDIT_PROCESSING,
+ OOB_EDIT_BUSY,
+ OOB_EDIT_SHUT_DOWN,
+ OOB_EDIT_ERROR
+} OOB_EDIT_STATE;
+
+typedef struct OUTGOING_STREAM_DATA_
+{
+ LIST_ENTRY listEntry;
+
+ NET_BUFFER_LIST* netBufferList;
+ BOOLEAN isClone;
+ size_t dataLength;
+ DWORD streamFlags;
+ MDL* mdl;
+} OUTGOING_STREAM_DATA;
+
+typedef struct STREAM_EDITOR_ STREAM_EDITOR;
+
+NTSTATUS
+OobEditInit(
+ _Out_ STREAM_EDITOR*
+ );
+
+void
+OobEditShutdown(
+ _Out_ STREAM_EDITOR* streamEditor
+ );
+
+#if(NTDDI_VERSION >= NTDDI_WIN7)
+
+void
+NTAPI
+StreamOobEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const void* classifyContext,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#else
+
+void
+NTAPI
+StreamOobEditClassify(
+ _In_ const FWPS_INCOMING_VALUES* inFixedValues,
+ _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
+ _Inout_ void* layerData,
+ _In_ const FWPS_FILTER* filter,
+ _In_ UINT64 flowContext,
+ _Inout_ FWPS_CLASSIFY_OUT* classifyOut
+ );
+
+#endif /// (NTDDI_VERSION >= NTDDI_WIN7)
+
+
+#endif // _OOB_EDIT_H
diff --git a/network/trans/stmedit/sys/stmedit.inf b/network/trans/stmedit/sys/stmedit.inf
new file mode 100644
index 00000000..1e19c787
--- /dev/null
+++ b/network/trans/stmedit/sys/stmedit.inf
@@ -0,0 +1,66 @@
+;;;
+;;; Copyright (c) Microsoft Corporation. All rights reserved
+;;;
+;;; Abstract:
+;;; Stream Edit Callout sample driver install configuration.
+;;;
+
+[Version]
+ Signature = "$Windows NT$"
+ Class = WFPCALLOUTS
+ ClassGuid = {57465043-616C-6C6F-7574-5F636C617373}
+ Provider = %Contoso%
+ CatalogFile = StmEdit.cat
+ DriverVer = 11/24/2014,14.24.55.836
+
+[SourceDisksNames]
+ 1 = %StmEditDisk%,,,""
+
+[SourceDisksFiles]
+ StmEdit.sys = 1,,
+
+[DestinationDirs]
+ DefaultDestDir = 12 ; %WinDir%\System32\Drivers
+ StmEdit.DriverFiles = 12 ; %WinDir%\System32\Drivers
+
+[DefaultInstall]
+ OptionDesc = %StmEditServiceDesc%
+ CopyFiles = StmEdit.DriverFiles
+
+[DefaultInstall.Services]
+ AddService = %StmEditServiceName%,,StmEdit.Service
+
+[DefaultUninstall]
+ DelFiles = StmEdit.DriverFiles
+
+[DefaultUninstall.Services]
+ DelService = %StmEditServiceName%,0x200 ; SPSVCINST_STOPSERVICE
+ DelReg = StmEdit.DelRegistry
+
+[StmEdit.DriverFiles]
+ StmEdit.sys,,,0x00000040 ; COPYFLG_OVERWRITE_OLDER_ONLY
+
+[StmEdit.Service]
+ DisplayName = %StmEditServiceName%
+ Description = %StmEditServiceDesc%
+ ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+ StartType = 3 ; SERVICE_DEMAND_START
+ ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ ServiceBinary = %12%\StmEdit.sys ; %WinDir%\System32\Drivers\StmEdit.sys
+ AddReg = StmEdit.AddRegistry
+
+[StmEdit.AddRegistry]
+ HKR,"Parameters","EditInline",0x00010001,0 ; FLG_ADDREG_TYPE_DWORD
+ HKR,"Parameters","StringToFind",0x00000000,"rainy" ; FLG_ADDREG_TYPE_SZ
+ HKR,"Parameters","StringToReplace",0x00000000,"sunny" ; FLG_ADDREG_TYPE_SZ
+ HKR,"Parameters","InspectionPort",0x00010001,5001 ; FLG_ADDREG_TYPE_DWORD
+ HKR,"Parameters","InspectOutbound",0x00010001,0 ; FLG_ADDREG_TYPE_DWORD
+
+[StmEdit.DelRegistry]
+ HKR,"Parameters",,,
+
+[Strings]
+ Contoso = "Contoso Ltd."
+ StmEditDisk = "Stream Edit Installation Disk"
+ StmEditServiceDesc = "Stream Edit Callout Driver"
+ StmEditServiceName = "StmEdit" \ No newline at end of file
diff --git a/network/trans/stmedit/sys/stmedit.vcxproj b/network/trans/stmedit/sys/stmedit.vcxproj
new file mode 100644
index 00000000..bc3ef00b
--- /dev/null
+++ b/network/trans/stmedit/sys/stmedit.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>{98513F1C-C28D-4F03-99A8-88FD4BD707C7}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{72C54687-6A7C-47CA-9E90-E2D689DC07FF}</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>stmedit</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>stmedit</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>stmedit</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>stmedit</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)\ntoskrnl.lib;$(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)\ntoskrnl.lib;$(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)\ntoskrnl.lib;$(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)\ntoskrnl.lib;$(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="inline_edit.c" />
+ <ClCompile Include="oob_edit.c" />
+ <ClCompile Include="stream_callout.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/stmedit/sys/stmedit.vcxproj.Filters b/network/trans/stmedit/sys/stmedit.vcxproj.Filters
new file mode 100644
index 00000000..54528237
--- /dev/null
+++ b/network/trans/stmedit/sys/stmedit.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>{C9744BA5-8ED9-44CA-83D6-EFDEDA84812B}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{2B1C683F-EF24-453C-B303-9CAE8061F7C3}</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>{FF447D8A-41FE-4980-B0AE-27782414E0C0}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{A061D6F2-D701-4D44-9CAB-055FBD8E95A9}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="inline_edit.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="oob_edit.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stream_callout.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/network/trans/stmedit/sys/stream_callout.c b/network/trans/stmedit/sys/stream_callout.c
new file mode 100644
index 00000000..7816c46d
--- /dev/null
+++ b/network/trans/stmedit/sys/stream_callout.c
@@ -0,0 +1,772 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream Edit Callout Driver Sample.
+
+ This sample demonstrates finding and replacing a string pattern from a
+ live TCP stream via the WFP stream API.
+
+ The driver can function in one of the two modes --
+
+ o Inline Editing where all modification is carried out within the
+ WFP ClassifyFn callout function.
+
+ o Out-of-band (OOB) Editing where all modification is done by a
+ worker thread. (this is the default)
+
+ The mode setting, along with other inspection parameters are configurable
+ via the following registry values
+
+ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\stmedit\Parameters
+
+ o StringToFind (REG_SZ, default = "rainy")
+ o StringToReplace (REG_SZ, default = "sunny")
+ o InspectionPort (REG_DWORD, default = 5001)
+ o InspectOutbound (REG_DWORD, default = 0)
+ o EditInline (REG_DWORD, default = 0)
+
+ The sample is IP version agnostic. It performs inspection on both IPv4 and
+ IPv6 data streams.
+
+ Before experimenting with the sample, please be sure to add an exception for
+ the InspectionPort configured to the firewall.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include <ntifs.h>
+#include <wdf.h>
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+#include <fwpsk.h>
+
+#pragma warning(pop)
+
+#include <fwpmk.h>
+
+#include "inline_edit.h"
+#include "oob_edit.h"
+#include "stream_callout.h"
+
+#define INITGUID
+#include <guiddef.h>
+
+//
+// Configurable parameters
+//
+
+USHORT configInspectionPort = 5001;
+BOOLEAN configInspectionOutbound = FALSE;
+BOOLEAN configEditInline = FALSE;
+
+CHAR configStringToFind[128] = "rainy";
+CHAR configStringToReplace[128] = "sunny";
+
+//
+// Callout driver keys
+//
+
+// e6011cdc-440b-4a6f-8499-6fdb55fb1f92
+DEFINE_GUID(
+ STREAM_EDITOR_STREAM_CALLOUT_V4,
+ 0xe6011cdc,
+ 0x440b,
+ 0x4a6f,
+ 0x84, 0x99, 0x6f, 0xdb, 0x55, 0xfb, 0x1f, 0x92
+);
+// c0bc07b4-aaf6-4242-a3dc-3ef341ffde5d
+DEFINE_GUID(
+ STREAM_EDITOR_STREAM_CALLOUT_V6,
+ 0xc0bc07b4,
+ 0xaaf6,
+ 0x4242,
+ 0xa3, 0xdc, 0x3e, 0xf3, 0x41, 0xff, 0xde, 0x5d
+);
+
+//
+// Callout driver global variables
+//
+
+MDL* gStringToReplaceMdl;
+
+STREAM_EDITOR gStreamEditor;
+
+HANDLE gEngineHandle;
+UINT32 gCalloutIdV4;
+UINT32 gCalloutIdV6;
+
+DEVICE_OBJECT* gWdmDevice;
+
+HANDLE gInjectionHandle;
+
+NDIS_GENERIC_OBJECT* gNdisGenericObj;
+NDIS_HANDLE gNetBufferListPool;
+
+#define STREAM_EDITOR_NDIS_OBJ_TAG 'oneS'
+#define STREAM_EDITOR_NBL_POOL_TAG 'pneS'
+#define STREAM_EDITOR_FLAT_BUFFER_TAG 'bfeS'
+
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_UNLOAD StreamEditEvtDriverUnload;
+
+NTSTATUS
+StreamEditNotify(
+ FWPS_CALLOUT_NOTIFY_TYPE notifyType,
+ const GUID* filterKey,
+ const FWPS_FILTER* filter
+ )
+{
+ UNREFERENCED_PARAMETER(notifyType);
+ UNREFERENCED_PARAMETER(filterKey);
+ UNREFERENCED_PARAMETER(filter);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+RegisterCalloutForLayer(
+ const GUID* layerKey,
+ const GUID* calloutKey,
+ _Inout_ void* deviceObject,
+ _Out_ UINT32* calloutId
+ )
+/* ++
+
+ This function registers callouts and filters that intercept TCP
+ traffic at WFP FWPM_LAYER_STREAM_V4 or FWPM_LAYER_STREAM_V6 layer.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ FWPS_CALLOUT sCallout = {0};
+
+ FWPM_FILTER filter = {0};
+ FWPM_FILTER_CONDITION filterConditions[1] = {0};
+
+ FWPM_CALLOUT mCallout = {0};
+ FWPM_DISPLAY_DATA displayData = {0};
+
+ BOOLEAN calloutRegistered = FALSE;
+
+ sCallout.calloutKey = *calloutKey;
+ sCallout.classifyFn = (configEditInline ? StreamInlineEditClassify :
+ StreamOobEditClassify);
+ sCallout.notifyFn = StreamEditNotify;
+
+ status = FwpsCalloutRegister(
+ deviceObject,
+ &sCallout,
+ calloutId
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ calloutRegistered = TRUE;
+
+ displayData.name = L"Stream Edit Callout";
+ displayData.description = L"Callout that finds and replaces a token from a TCP stream";
+
+ mCallout.calloutKey = *calloutKey;
+ mCallout.displayData = displayData;
+ mCallout.applicableLayer = *layerKey;
+ status = FwpmCalloutAdd(
+ gEngineHandle,
+ &mCallout,
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ filter.layerKey = *layerKey;
+ filter.displayData.name = L"Stream Edit Filter";
+ filter.displayData.description = L"Filter that finds and replaces a token from a TCP stream";
+
+ filter.action.type = FWP_ACTION_CALLOUT_TERMINATING;
+ filter.action.calloutKey = *calloutKey;
+ filter.filterCondition = filterConditions;
+ filter.numFilterConditions = 1;
+ filter.subLayerKey = FWPM_SUBLAYER_UNIVERSAL;
+ filter.weight.type = FWP_EMPTY; // auto-weight.
+
+ filterConditions[0].fieldKey = (configInspectionOutbound ? FWPM_CONDITION_IP_REMOTE_PORT :
+ FWPM_CONDITION_IP_LOCAL_PORT);
+ filterConditions[0].matchType = FWP_MATCH_EQUAL;
+ filterConditions[0].conditionValue.type = FWP_UINT16;
+ filterConditions[0].conditionValue.uint16 = configInspectionPort;
+
+ status = FwpmFilterAdd(
+ gEngineHandle,
+ &filter,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (calloutRegistered)
+ {
+ FwpsCalloutUnregisterById(*calloutId);
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS
+StreamEditRegisterCallout(
+ const STREAM_EDITOR* streamEditor,
+ _Inout_ void* deviceObject
+ )
+/* ++
+
+ This function registers dynamic callouts and filters that intercept
+ TCP traffic at WFP FWPM_LAYER_STREAM_V4 and FWPM_LAYER_STREAM_V6
+ layer.
+
+ Callouts and filters will be removed during DriverUnload.
+
+-- */
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ BOOLEAN engineOpened = FALSE;
+ BOOLEAN inTransaction = FALSE;
+
+ FWPM_SESSION session = {0};
+
+ UNREFERENCED_PARAMETER(streamEditor);
+
+ 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;
+
+ status = RegisterCalloutForLayer(
+ &FWPM_LAYER_STREAM_V4,
+ &STREAM_EDITOR_STREAM_CALLOUT_V4,
+ deviceObject,
+ &gCalloutIdV4
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = RegisterCalloutForLayer(
+ &FWPM_LAYER_STREAM_V6,
+ &STREAM_EDITOR_STREAM_CALLOUT_V6,
+ deviceObject,
+ &gCalloutIdV6
+ );
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = FwpmTransactionCommit(gEngineHandle);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ inTransaction = FALSE;
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (inTransaction)
+ {
+ NTSTATUS abortStatus;
+ abortStatus = FwpmTransactionAbort(gEngineHandle);
+ _Analysis_assume_(NT_SUCCESS(abortStatus));
+ }
+ if (engineOpened)
+ {
+ FwpmEngineClose(gEngineHandle);
+ gEngineHandle = NULL;
+ }
+ }
+
+ return status;
+}
+
+void
+StreamEditUnregisterCallout(void)
+{
+ FwpmEngineClose(gEngineHandle);
+ gEngineHandle = NULL;
+
+ FwpsCalloutUnregisterById(gCalloutIdV6);
+ FwpsCalloutUnregisterById(gCalloutIdV4);
+}
+
+_Function_class_(EVT_WDF_DRIVER_UNLOAD)
+_IRQL_requires_same_
+_IRQL_requires_max_(PASSIVE_LEVEL)
+void
+StreamEditEvtDriverUnload(
+ _In_ WDFDRIVER driverObject
+ )
+{
+
+ UNREFERENCED_PARAMETER(driverObject);
+
+ if (!configEditInline)
+ {
+ OobEditShutdown(&gStreamEditor);
+ }
+
+ if (gStreamEditor.scratchBuffer != NULL)
+ {
+ ExFreePoolWithTag(
+ gStreamEditor.scratchBuffer,
+ STREAM_EDITOR_FLAT_BUFFER_TAG
+ );
+
+ }
+
+ StreamEditUnregisterCallout();
+
+ FwpsInjectionHandleDestroy(gInjectionHandle);
+
+ NdisFreeNetBufferListPool(gNetBufferListPool);
+ NdisFreeGenericObject(gNdisGenericObj);
+
+ IoFreeMdl(gStringToReplaceMdl);
+}
+
+NTSTATUS
+StreamEditLoadConfig(
+ const WDFKEY key
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ DECLARE_CONST_UNICODE_STRING(stringToFindKey, L"StringToFind");
+ DECLARE_CONST_UNICODE_STRING(stringToReplaceKey, L"StringToReplace");
+ DECLARE_CONST_UNICODE_STRING(inspectionPortKey, L"InspectionPort");
+ DECLARE_CONST_UNICODE_STRING(editInlineKey, L"EditInline");
+ DECLARE_CONST_UNICODE_STRING(inspectOutboundKey, L"InspectOutbound");
+
+ UNICODE_STRING stringValue;
+ WCHAR buffer[128];
+ USHORT requiredSize;
+ ULONG valueSize;
+ ULONG ulongValue;
+
+ stringValue.Buffer = buffer;
+ stringValue.Length = 0;
+ stringValue.MaximumLength = sizeof(buffer) - sizeof(buffer[0]);
+
+ if (NT_SUCCESS(
+ WdfRegistryQueryUnicodeString(
+ key,
+ &stringToFindKey,
+ &requiredSize,
+ &stringValue
+ )))
+ {
+ stringValue.Buffer[stringValue.Length/sizeof(stringValue.Buffer[0])] =
+ UNICODE_NULL;
+
+ status = RtlUnicodeToMultiByteN(
+ configStringToFind,
+ sizeof(configStringToFind) - 1,
+ &valueSize,
+ stringValue.Buffer,
+ (ULONG)requiredSize
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ configStringToFind[valueSize] = '\0';
+ }
+
+ if (NT_SUCCESS(
+ WdfRegistryQueryUnicodeString(
+ key,
+ &stringToReplaceKey,
+ &requiredSize,
+ &stringValue
+ )))
+ {
+ status = RtlUnicodeToMultiByteN(
+ configStringToReplace,
+ sizeof(configStringToReplace) - 1,
+ &valueSize,
+ stringValue.Buffer,
+ (ULONG)requiredSize
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ configStringToReplace[valueSize] = '\0';
+ }
+
+ if (NT_SUCCESS(
+ WdfRegistryQueryULong(
+ key,
+ &inspectionPortKey,
+ &ulongValue
+ )))
+ {
+ configInspectionPort = (USHORT) ulongValue;
+ }
+
+ if (NT_SUCCESS(
+ WdfRegistryQueryULong(
+ key,
+ &editInlineKey,
+ &ulongValue
+ )))
+ {
+ configEditInline = (ulongValue != 0);
+ }
+
+ if (NT_SUCCESS(
+ WdfRegistryQueryULong(
+ key,
+ &inspectOutboundKey,
+ &ulongValue
+ )))
+ {
+ configInspectionOutbound = (ulongValue != 0);
+ }
+
+Exit:
+ return status;
+}
+
+NTSTATUS
+StreamEditInitDriverObjects(
+ _Inout_ DRIVER_OBJECT* driverObject,
+ 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 = StreamEditEvtDriverUnload;
+
+ 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;
+ }
+
+ WdfDeviceInitSetCharacteristics(pInit, FILE_AUTOGENERATED_DEVICE_NAME, TRUE);
+ WdfDeviceInitSetDeviceType(pInit, FILE_DEVICE_NETWORK);
+ WdfDeviceInitSetCharacteristics(pInit, FILE_DEVICE_SECURE_OPEN, 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;
+ WDFDEVICE device;
+ WDFDRIVER driver;
+ WDFKEY configKey;
+ NET_BUFFER_LIST_POOL_PARAMETERS nblPoolParams = {0};
+
+ // Request NX Non-Paged Pool when available
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+
+ status = StreamEditInitDriverObjects(
+ driverObject,
+ registryPath,
+ &driver,
+ &device
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = WdfDriverOpenParametersRegistryKey(
+ driver,
+ KEY_READ,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &configKey
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ status = StreamEditLoadConfig(configKey);
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ gStringToReplaceMdl = IoAllocateMdl(
+ configStringToReplace,
+ (ULONG) strlen(configStringToReplace),
+ FALSE,
+ FALSE,
+ NULL
+ );
+ if (gStringToReplaceMdl == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ MmBuildMdlForNonPagedPool(gStringToReplaceMdl);
+
+ gNdisGenericObj = NdisAllocateGenericObject(
+ driverObject,
+ STREAM_EDITOR_NDIS_OBJ_TAG,
+ 0
+ );
+
+ if (gNdisGenericObj == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ nblPoolParams.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ nblPoolParams.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+ nblPoolParams.Header.Size = sizeof(nblPoolParams);
+
+ nblPoolParams.fAllocateNetBuffer = TRUE;
+ nblPoolParams.DataSize = 0;
+
+ nblPoolParams.PoolTag = STREAM_EDITOR_NBL_POOL_TAG;
+
+ gNetBufferListPool = NdisAllocateNetBufferListPool(
+ gNdisGenericObj,
+ &nblPoolParams
+ );
+
+ if (gNetBufferListPool == NULL)
+ {
+ status = STATUS_NO_MEMORY;
+ goto Exit;
+ }
+
+ status = FwpsInjectionHandleCreate(
+ AF_UNSPEC,
+ FWPS_INJECTION_TYPE_STREAM,
+ &gInjectionHandle
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ gWdmDevice = WdfDeviceWdmGetDeviceObject(device);
+
+ status = StreamEditRegisterCallout(
+ &gStreamEditor,
+ gWdmDevice
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+ if (configEditInline)
+ {
+ InlineEditInit(&gStreamEditor);
+ }
+ else
+ {
+
+ status = OobEditInit(&gStreamEditor);
+
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+ }
+
+Exit:
+
+ if (!NT_SUCCESS(status))
+ {
+ if (gEngineHandle != NULL)
+ {
+ StreamEditUnregisterCallout();
+ }
+ if (gInjectionHandle != NULL)
+ {
+ FwpsInjectionHandleDestroy(gInjectionHandle);
+ }
+ if (gNetBufferListPool != NULL)
+ {
+ NdisFreeNetBufferListPool(gNetBufferListPool);
+ }
+ if (gNdisGenericObj != NULL)
+ {
+ NdisFreeGenericObject(gNdisGenericObj);
+ }
+ if (gStringToReplaceMdl != NULL)
+ {
+ IoFreeMdl(gStringToReplaceMdl);
+ }
+ }
+
+ return status;
+}
+
+BOOLEAN
+StreamCopyDataForInspection(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ const FWPS_STREAM_DATA* streamData
+ )
+/* ++
+
+ This function copies stream data described by the FWPS_STREAM_DATA
+ structure into a flat buffer.
+
+-- */
+
+{
+ SIZE_T bytesCopied;
+
+ size_t existingDataLength = streamEditor->dataLength;
+ NT_ASSERT(streamEditor->dataOffset == 0);
+ if (streamEditor->bufferSize - existingDataLength < streamData->dataLength)
+ {
+ size_t newBufferSize = (streamData->dataLength + existingDataLength) * 2;
+ void* newBuffer = ExAllocatePoolWithTag(
+ NonPagedPool,
+ newBufferSize,
+ STREAM_EDITOR_FLAT_BUFFER_TAG
+ );
+
+ if (newBuffer != NULL)
+ {
+ if (existingDataLength > 0)
+ {
+ NT_ASSERT(streamEditor->scratchBuffer != NULL);
+ RtlCopyMemory(
+ newBuffer,
+ streamEditor->scratchBuffer,
+ existingDataLength
+ );
+ }
+ }
+
+ if (streamEditor->scratchBuffer != NULL)
+ {
+ ExFreePoolWithTag(
+ streamEditor->scratchBuffer,
+ STREAM_EDITOR_FLAT_BUFFER_TAG
+ );
+
+ streamEditor->scratchBuffer = NULL;
+ streamEditor->bufferSize = 0;
+ streamEditor->dataLength = 0;
+ }
+
+ if (newBuffer != NULL)
+ {
+ streamEditor->scratchBuffer = newBuffer;
+ streamEditor->bufferSize = newBufferSize;
+ streamEditor->dataLength = existingDataLength;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ FwpsCopyStreamDataToBuffer(
+ streamData,
+ (BYTE*)streamEditor->scratchBuffer + streamEditor->dataLength,
+ streamData->dataLength,
+ &bytesCopied
+ );
+
+ NT_ASSERT(bytesCopied == streamData->dataLength);
+
+ streamEditor->dataLength += bytesCopied;
+
+ return TRUE;
+}
diff --git a/network/trans/stmedit/sys/stream_callout.h b/network/trans/stmedit/sys/stream_callout.h
new file mode 100644
index 00000000..7fff047f
--- /dev/null
+++ b/network/trans/stmedit/sys/stream_callout.h
@@ -0,0 +1,79 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved
+
+Abstract:
+
+ Stream Edit Callout Driver Sample.
+
+ This sample demonstrates finding and replacing a string pattern from a
+ live TCP stream via the WFP stream API.
+
+--*/
+
+#ifndef _STREAM_CALLOUT_H
+#define _STREAM_CALLOUT_H
+
+extern MDL* gStringToReplaceMdl;
+extern HANDLE gInjectionHandle;
+extern NDIS_HANDLE gNetBufferListPool;
+extern STREAM_EDITOR gStreamEditor;
+
+//
+// Configurable parameters
+//
+
+extern USHORT configInspectionPort;
+extern BOOLEAN configInspectionOutbound;
+extern BOOLEAN configEditInline;
+
+extern CHAR configStringToFind[];
+extern CHAR configStringToReplace[];
+
+#pragma warning(push)
+#pragma warning(disable:4201) // unnamed struct/union
+
+typedef struct STREAM_EDITOR_
+{
+ BOOLEAN editInline;
+
+ union
+ {
+ INLINE_EDIT_STATE inlineEditState;
+ struct
+ {
+ OOB_EDIT_STATE editState;
+ BOOLEAN shuttingDown;
+
+ KSPIN_LOCK editLock;
+ NET_BUFFER_LIST* nblHead;
+ NET_BUFFER_LIST* nblTail;
+ size_t totalDataLength;
+ BOOLEAN noMoreData;
+ NET_BUFFER_LIST* nblEof;
+ size_t busyThreshold;
+ UINT64 flowId;
+ UINT32 calloutId;
+ UINT16 layerId;
+ DWORD streamFlags;
+ KEVENT editEvent;
+ LIST_ENTRY outgoingDataQueue;
+ } oobEditInfo;
+ };
+
+ void* scratchBuffer;
+ size_t bufferSize;
+ size_t dataOffset;
+ size_t dataLength;
+
+}STREAM_EDITOR;
+
+#pragma warning(pop)
+
+BOOLEAN
+StreamCopyDataForInspection(
+ _Inout_ STREAM_EDITOR* streamEditor,
+ const FWPS_STREAM_DATA* streamData
+ );
+
+#endif // _STREAM_CALLOUT_H