From 5d61a4a79a1e96dc5d9af1e5e712c84507307544 Mon Sep 17 00:00:00 2001 From: J M Rossy Date: Wed, 29 Jul 2015 15:40:09 -0700 Subject: Samples update for public Windows 10 release Fix #2 Enabling WPP Recorder in Sensors Samples causes errors Fix #4 Add back fixed KMDOD sample Add new BarcodeScanner sample in pos folder Add new MagneticStripeReader sample in pos folder Add new SynpaticsTouch sample in input folder Add new Power Engine Plugin sample in pofx folder Add new DeviceMft sample in avstream folder Add new AvsCamera sample in root Add new SimBatt sample in root Add other pre-existing samples not yet released for Win10 --- ...ssifyFunctions_BasicPacketInjectionCallouts.cpp | 4231 ++++++++++++++++++++ 1 file changed, 4231 insertions(+) create mode 100644 network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketInjectionCallouts.cpp (limited to 'network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketInjectionCallouts.cpp') diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketInjectionCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketInjectionCallouts.cpp new file mode 100644 index 00000000..2409a64d --- /dev/null +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketInjectionCallouts.cpp @@ -0,0 +1,4231 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2014 Microsoft Corporation. All Rights Reserved. +// +// Module Name: +// ClassifyFunctions_BasicPacketInjectionCallouts.cpp +// +// Abstract: +// This module contains WFP Classify functions for injecting packets back into the data path +// using the clone / block / inject method. +// +// Naming Convention: +// +// +// +// i.e. +// ClassifyBasicPacketInjection +// +// +// Classify - Function is an FWPS_CALLOUT_CLASSIFY_FN +// +// BasicPacketInjection - Function demonstrates the clone / block / inject model. +// +// +// +// i.e. +// TriggerBasicPacketInjectionOutOfBand +// +// +// { +// - +// Trigger - Initiates the desired scenario. +// Perform - Executes the desired scenario. +// } +// +// BasicPacketInjection - Function demonstrates the clone / block / inject model. +// +// DeferredProcedureCall - DPC routine for Out of Band injection which dispatches the +// proper Perform Function. +// WorkItemRoutine - WorkItem Routine for Out of Band Injection which dispatches +// the proper Perform Function. +// AtInboundMACFrame - Function operates on: +// FWPM_LAYER_INBOUND_MAC_FRAME_ETHERNET, and +// FWPM_LAYER_INBOUND_MAC_NATIVE. +// AtOutboundMACFrame - Function operates on: +// FWPM_LAYER_OUTBOUND_MAC_FRAME_ETHERNET, and +// FWPM_LAYER_OUTBOUND_MAC_NATIVE. +// AtEgressVSwitchEthernet - Function operates on: +// FWPM_LAYER_EGRESS_VSWITCH_ETHERNET. +// AtIngressVSwitchEthernet - Function operates on: +// FWPM_LAYER_INGRESS_VSWITCH_ETHERNET. +// AtInboundNetwork - Function operates on: +// FWPM_LAYER_INBOUND_IPPACKET_V{4/6} +// AtOutboundNetwork - Function operates on: +// FWPM_LAYER_OUTBOUND_IPPACKET_V{4/6} +// AtForward - Function operates on: +// FWPM_LAYER_IPFORWARD_V{4/6} +// AtInboundTransport - Function operates on: +// FWPM_LAYER_INBOUND_TRANSPORT_V{4/6}, +// FWPM_LAYER_INBOUND_ICMP_ERROR_V{4/6}, +// FWPM_LAYER_DATAGRAM_DATA_V{4/6}, +// FWPM_LAYER_STREAM_PACKET_V{4/6}, and +// FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V{4/6} +// FWPM_LAYER_ALE_FLOW_ESTABLISHED_V{4/6} +// AtOutboundTransport - Function operates on: +// FWPM_LAYER_OUTBOUND_TRANSPORT_V{4/6}, +// FWPM_LAYER_OUTBOUND_ICMP_ERROR_V{4/6}, +// FWPM_LAYER_DATAGRAM_DATA_V{4/6}, +// FWPM_LAYER_STREAM_PACKET_V{4/6}, and +// FWPM_LAYER_ALE_AUTH_CONNECT_V{4/6} +// FWPM_LAYER_ALE_FLOW_ESTABLISHED_V{4/6} +// +// Private Functions: +// BasicPacketInjectionDeferredProcedureCall(), +// BasicPacketInjectionWorkItemRoutine(), +// PerformBasicPacketInjectionAtEgressVSwitchEthernet(), +// PerformBasicPacketInjectionAtForward(), +// PerformBasicPacketInjectionAtInboundMACFrame(), +// PerformBasicPacketInjectionAtInboundNetwork(), +// PerformBasicPacketInjectionAtInboundTransport(), +// PerformBasicPacketInjectionAtIngressVSwitchEthernet(), +// PerformBasicPacketInjectionAtOutboundMACFrame(), +// PerformBasicPacketInjectionAtOutboundNetwork(), +// PerformBasicPacketInjectionAtOutboundTransport(), +// TriggerBasicPacketInjectionInline(), +// TriggerBasicPacketInjectionOutOfBand(), +// +// Public Functions: +// ClassifyBasicPacketInjection(), +// +// Author: +// Dusty Harper (DHarper) +// +// Revision History: +// +// [ Month ][Day] [Year] - [Revision]-[ Comments ] +// May 01, 2010 - 1.0 - Creation +// December 13, 2013 - 1.1 - Enhance function declaration for IntelliSense, enhance +// traces, fix weakhost injection, fix expected +// offsets, and add support for multiple injectors and +// controlData. +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "Framework_WFPSamplerCalloutDriver.h" /// . +#include "ClassifyFunctions_BasicPacketInjectionCallouts.tmh" /// $(OBJ_PATH)\$(O)\ + +#if DBG + +INJECTION_COUNTERS g_bpiTotalClassifies = {0}; +INJECTION_COUNTERS g_bpiTotalBlockedAndAbsorbed = {0}; +INJECTION_COUNTERS g_bpiTotalPermitted = {0}; +INJECTION_COUNTERS g_bpiTotalSuccessfulInjectionCalls = {0}; +INJECTION_COUNTERS g_bpiTotalFailedInjectionCalls = {0}; +INJECTION_COUNTERS g_bpiOutstandingNBLClones = {0}; + +/** + @function="PrvBasicPacketInjectionCountersIncrement" + + Purpose: Increment the appropriate counters based on the layerId and direction.
+
+ Notes:
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Desktop/MS683615.aspx
+*/ +VOID PrvBasicPacketInjectionCountersIncrement(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadataValues, + _Inout_ INJECTION_COUNTERS* pCounters) +{ + UINT32 direction = FWP_DIRECTION_MAX; + FWP_VALUE* pDirectionValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_DIRECTION); + + direction = KrnlHlprFwpsLayerGetDirection(pClassifyValues->layerId); + + if(pDirectionValue && + pDirectionValue->type == FWP_UINT32) + direction = (FWP_DIRECTION)pDirectionValue->uint32; + else + { + if(pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || + pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4_DISCARD || + pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6 || + pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6_DISCARD) + { + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadataValues, + FWPS_METADATA_FIELD_FORWARD_LAYER_INBOUND_PASS_THRU)) + direction = FWP_DIRECTION_INBOUND; + else if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadataValues, + FWPS_METADATA_FIELD_FORWARD_LAYER_OUTBOUND_PASS_THRU)) + direction = FWP_DIRECTION_OUTBOUND; + } + else + { + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadataValues, + FWPS_METADATA_FIELD_PACKET_DIRECTION)) + direction = pMetadataValues->packetDirection; + } + } + + switch(pClassifyValues->layerId) + { + case FWPS_LAYER_INBOUND_IPPACKET_V4: + { + InterlockedIncrement64((LONG64*)&(pCounters->inboundNetwork_IPv4)); + + break; + } + case FWPS_LAYER_INBOUND_IPPACKET_V6: + { + InterlockedIncrement64((LONG64*)&(pCounters->inboundNetwork_IPv6)); + + break; + } + case FWPS_LAYER_OUTBOUND_IPPACKET_V4: + { + InterlockedIncrement64((LONG64*)&(pCounters->outboundNetwork_IPv4)); + + break; + } + case FWPS_LAYER_OUTBOUND_IPPACKET_V6: + { + InterlockedIncrement64((LONG64*)&(pCounters->outboundNetwork_IPv6)); + + break; + } + case FWPS_LAYER_IPFORWARD_V4: + { + if(direction == FWP_DIRECTION_OUTBOUND) + InterlockedIncrement64((LONG64*)&(pCounters->inboundForward_IPv4)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundForward_IPv4)); + + break; + } + case FWPS_LAYER_IPFORWARD_V6: + { + if(direction == FWP_DIRECTION_INBOUND) + InterlockedIncrement64((LONG64*)&(pCounters->inboundForward_IPv6)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundForward_IPv6)); + + break; + } + case FWPS_LAYER_INBOUND_TRANSPORT_V4: + { + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv4)); + + break; + } + case FWPS_LAYER_INBOUND_TRANSPORT_V6: + { + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv6)); + + break; + } + case FWPS_LAYER_OUTBOUND_TRANSPORT_V4: + { + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv4)); + + break; + } + case FWPS_LAYER_OUTBOUND_TRANSPORT_V6: + { + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv6)); + + + break; + } + case FWPS_LAYER_DATAGRAM_DATA_V4: + { + if(direction == FWP_DIRECTION_INBOUND) + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv4)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv4)); + + break; + } + case FWPS_LAYER_DATAGRAM_DATA_V6: + { + if(direction == FWP_DIRECTION_INBOUND) + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv6)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv6)); + + break; + } + case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4: + { + if(direction == FWP_DIRECTION_INBOUND) + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv4)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv4)); + + break; + } + case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6: + { + if(direction == FWP_DIRECTION_INBOUND) + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv6)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv6)); + + break; + } + case FWPS_LAYER_ALE_AUTH_CONNECT_V4: + { + if(direction == FWP_DIRECTION_INBOUND) + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv4)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv4)); + + break; + } + case FWPS_LAYER_ALE_AUTH_CONNECT_V6: + { + if(direction == FWP_DIRECTION_INBOUND) + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv6)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv6)); + + break; + } + case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4: + { + if(direction == FWP_DIRECTION_INBOUND) + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv4)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv4)); + + break; + } + case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6: + { + if(direction == FWP_DIRECTION_INBOUND) + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv6)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv6)); + + break; + } + +#if(NTDDI_VERSION >= NTDDI_WIN7) + + case FWPS_LAYER_STREAM_PACKET_V4: + { + if(direction == FWP_DIRECTION_INBOUND) + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv4)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv4)); + + break; + } + case FWPS_LAYER_STREAM_PACKET_V6: + { + if(direction == FWP_DIRECTION_INBOUND) + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv6)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv6)); + + break; + } + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + case FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET: + { + UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_ETHERNET_ETHER_TYPE].value.uint16; + + if(etherType == 0x86DD) + InterlockedIncrement64((LONG64*)&(pCounters->inboundMAC_IPv6)); + else if(etherType == 0x800) + InterlockedIncrement64((LONG64*)&(pCounters->inboundMAC_IPv4)); + else + InterlockedIncrement64((LONG64*)&(pCounters->inboundMAC_Unknown)); + + break; + } + case FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET: + { + UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_MAC_FRAME_ETHERNET_ETHER_TYPE].value.uint16; + + if(etherType == 0x86DD) + InterlockedIncrement64((LONG64*)&(pCounters->outboundMAC_IPv6)); + else if(etherType == 0x800) + InterlockedIncrement64((LONG64*)&(pCounters->outboundMAC_IPv4)); + else + InterlockedIncrement64((LONG64*)&(pCounters->outboundMAC_Unknown)); + + break; + } + case FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE: + { + InterlockedIncrement64((LONG64*)&(pCounters->inboundMAC_Unknown)); + + break; + } + case FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE: + { + InterlockedIncrement64((LONG64*)&(pCounters->outboundMAC_Unknown)); + + break; + } + case FWPS_LAYER_INGRESS_VSWITCH_ETHERNET: + { + UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_INGRESS_VSWITCH_ETHERNET_ETHER_TYPE].value.uint16; + + if(etherType == 0x86DD) + InterlockedIncrement64((LONG64*)&(pCounters->ingressVSwitch_IPv6)); + else if(etherType == 0x800) + InterlockedIncrement64((LONG64*)&(pCounters->ingressVSwitch_IPv4)); + else + InterlockedIncrement64((LONG64*)&(pCounters->ingressVSwitch_Unknown)); + + break; + } + case FWPS_LAYER_EGRESS_VSWITCH_ETHERNET: + { + UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_EGRESS_VSWITCH_ETHERNET_ETHER_TYPE].value.uint16; + + if(etherType == 0x86DD) + InterlockedIncrement64((LONG64*)&(pCounters->egressVSwitch_IPv6)); + else if(etherType == 0x800) + InterlockedIncrement64((LONG64*)&(pCounters->egressVSwitch_IPv4)); + else + InterlockedIncrement64((LONG64*)&(pCounters->egressVSwitch_Unknown)); + + break; + } + +#endif // (NTDDI_VERSION >= NTDDI_WIN8) +#endif // (NTDDI_VERSION >= NTDDI_WIN7) + + } + + return; +} + +/** + @private_function="PrvBasicPacketInjectionCountersIncrementTotalActionResults" + + Purpose: Increment the appropriate counters based on the layerId, direction, and action.
+
+ Notes:
+
+ MSDN_Ref:
+*/ +VOID PrvBasicPacketInjectionCountersIncrementTotalActionResults(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadataValues, + _In_ const FWPS_CLASSIFY_OUT* pClassifyOut) +{ + INJECTION_COUNTERS* pCounters = 0; + + if(pClassifyOut->actionType == FWP_ACTION_BLOCK) + { + NT_ASSERT(pClassifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_ABSORB); + + pCounters = &g_bpiTotalBlockedAndAbsorbed; + } + else + pCounters = &g_bpiTotalPermitted; + + PrvBasicPacketInjectionCountersIncrement(pClassifyValues, + pMetadataValues, + pCounters); + + return; +} + +/** + @function="BasicPacketInjectionCountersIncrement" + + Purpose: Increment the appropriate counters based on the injection handle.
+
+ Notes:
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Desktop/MS683615.aspx
+*/ +VOID BasicPacketInjectionCountersIncrement(_In_ HANDLE injectionHandle, + _Inout_ INJECTION_COUNTERS* pCounters) +{ + if(injectionHandle == g_pIPv4InboundNetworkInjectionHandles[0] || + injectionHandle == g_pIPv4InboundNetworkInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->inboundNetwork_IPv4)); + else if(injectionHandle == g_pIPv6InboundNetworkInjectionHandles[0] || + injectionHandle == g_pIPv6InboundNetworkInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->inboundNetwork_IPv6)); + else if(injectionHandle == g_pIPv4OutboundNetworkInjectionHandles[0] || + injectionHandle == g_pIPv4OutboundNetworkInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->outboundNetwork_IPv4)); + else if(injectionHandle == g_pIPv6OutboundNetworkInjectionHandles[0] || + injectionHandle == g_pIPv6OutboundNetworkInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->outboundNetwork_IPv6)); + else if(injectionHandle == g_pIPv4InboundForwardInjectionHandles[0] || + injectionHandle == g_pIPv4InboundForwardInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->inboundForward_IPv4)); + else if(injectionHandle == g_pIPv6InboundForwardInjectionHandles[0] || + injectionHandle == g_pIPv6InboundForwardInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->inboundForward_IPv6)); + else if(injectionHandle == g_pIPv4OutboundForwardInjectionHandles[0] || + injectionHandle == g_pIPv4OutboundForwardInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->outboundForward_IPv4)); + else if(injectionHandle == g_pIPv6OutboundForwardInjectionHandles[0] || + injectionHandle == g_pIPv6OutboundForwardInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->outboundForward_IPv6)); + else if(injectionHandle == g_pIPv4InboundTransportInjectionHandles[0] || + injectionHandle == g_pIPv4InboundTransportInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv4)); + else if(injectionHandle == g_pIPv6InboundTransportInjectionHandles[0] || + injectionHandle == g_pIPv6InboundTransportInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->inboundTransport_IPv6)); + else if(injectionHandle == g_pIPv4OutboundTransportInjectionHandles[0] || + injectionHandle == g_pIPv4OutboundTransportInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv4)); + else if(injectionHandle == g_pIPv6OutboundTransportInjectionHandles[0] || + injectionHandle == g_pIPv6OutboundTransportInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->outboundTransport_IPv6)); + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + else if(injectionHandle == g_pIPv4InboundMACInjectionHandles[0] || + injectionHandle == g_pIPv4InboundMACInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->inboundMAC_IPv4)); + else if(injectionHandle == g_pIPv6InboundMACInjectionHandles[0] || + injectionHandle == g_pIPv6InboundMACInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->inboundMAC_IPv6)); + else if(injectionHandle == g_pInboundMACInjectionHandles[0] || + injectionHandle == g_pInboundMACInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->inboundMAC_Unknown)); + else if(injectionHandle == g_pIPv4OutboundMACInjectionHandles[0] || + injectionHandle == g_pIPv4OutboundMACInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->outboundMAC_IPv4)); + else if(injectionHandle == g_pIPv6OutboundMACInjectionHandles[0] || + injectionHandle == g_pIPv6OutboundMACInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->outboundMAC_IPv6)); + else if(injectionHandle == g_pOutboundMACInjectionHandles[0] || + injectionHandle == g_pOutboundMACInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->outboundMAC_Unknown)); + else if(injectionHandle == g_pIPv4IngressVSwitchEthernetInjectionHandles[0] || + injectionHandle == g_pIPv4IngressVSwitchEthernetInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->ingressVSwitch_IPv4)); + else if(injectionHandle == g_pIPv6IngressVSwitchEthernetInjectionHandles[0] || + injectionHandle == g_pIPv6IngressVSwitchEthernetInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->ingressVSwitch_IPv6)); + else if(injectionHandle == g_pIngressVSwitchEthernetInjectionHandles[0] || + injectionHandle == g_pIngressVSwitchEthernetInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->ingressVSwitch_Unknown)); + else if(injectionHandle == g_pIPv4EgressVSwitchEthernetInjectionHandles[0] || + injectionHandle == g_pIPv4EgressVSwitchEthernetInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->egressVSwitch_IPv4)); + else if(injectionHandle == g_pIPv6EgressVSwitchEthernetInjectionHandles[0] || + injectionHandle == g_pIPv6EgressVSwitchEthernetInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->egressVSwitch_IPv6)); + else if(injectionHandle == g_pEgressVSwitchEthernetInjectionHandles[0] || + injectionHandle == g_pEgressVSwitchEthernetInjectionHandles[1]) + InterlockedIncrement64((LONG64*)&(pCounters->egressVSwitch_Unknown)); + +#endif /// (NTDDI_VERSION >= NTDDI_WIN8) + + return; +} + +#endif /// DBG + +#if(NTDDI_VERSION >= NTDDI_WIN8) + +/** + @private_function="PerformBasicPacketInjectionAtInboundMACFrame" + + Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the stack from the + incoming MAC Layers using FwpsInjectMacReceiveAsync().
+
+ Notes: Applies to the following inbound layers:
+ FWPM_LAYER_INBOUND_MAC_FRAME_ETHERNET
+ FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/HH439588.aspx
+ HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +NTSTATUS PerformBasicPacketInjectionAtInboundMACFrame(_In_ CLASSIFY_DATA** ppClassifyData, + _In_ INJECTION_DATA** ppInjectionData, + _In_ BOOLEAN isInline = FALSE) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformBasicPacketInjectionAtInboundMACFrame()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppInjectionData); + NT_ASSERT(*ppClassifyData); + NT_ASSERT(*ppInjectionData); + + NTSTATUS status = STATUS_SUCCESS; + FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; + FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; + IF_INDEX interfaceIndex = 0; + NDIS_PORT_NUMBER ndisPort = 0; + NET_BUFFER_LIST* pNetBufferList = 0; + BASIC_PACKET_INJECTION_COMPLETION_DATA* pCompletionData = 0; + UINT32 bytesRetreated = 0; + FWP_VALUE* pInterfaceIndex = 0; + FWP_VALUE* pNDISPort = 0; + +#if DBG + + KIRQL irql = KeGetCurrentIrql(); + HANDLE injectionHandle = (*ppInjectionData)->injectionHandle; + +#endif /// DBG + +#pragma warning(push) +#pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + HLPR_NEW(pCompletionData, + BASIC_PACKET_INJECTION_COMPLETION_DATA, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, + status); + +#pragma warning(pop) + + KeInitializeSpinLock(&(pCompletionData->spinLock)); + + pCompletionData->performedInline = isInline; + pCompletionData->pClassifyData = *ppClassifyData; + pCompletionData->pInjectionData = *ppInjectionData; + + /// Responsibility for freeing this memory has been transferred to the pCompletionData + *ppClassifyData = 0; + + *ppInjectionData = 0; + + pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_INTERFACE_INDEX); + if(pInterfaceIndex && + pInterfaceIndex->type == FWP_UINT32) + interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32; + + pNDISPort = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_NDIS_PORT); + if(pNDISPort && + pNDISPort->type == FWP_UINT32) + ndisPort = (NDIS_PORT_NUMBER)pNDISPort->uint32; + + /// If NATIVE, initial offset is at the MAC Header ... + if(pClassifyValues->layerId != FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE && + FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata, + FWPS_L2_METADATA_FIELD_ETHERNET_MAC_HEADER_SIZE)) + bytesRetreated = pMetadata->ethernetMacHeaderSize; + + if(bytesRetreated) + { + /// ... otherwise the offset is at the IP Header, so retreat the size of the MAC Header ... + status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), + bytesRetreated, + 0, + 0); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundMACFrame: NdisRetreatNetBufferDataStart() [status: %#x]\n", + status); + + HLPR_BAIL; + } + } + + /// ... clone the entire NET_BUFFER_LIST ... + status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + g_pNDISPoolData->nblPoolHandle, + g_pNDISPoolData->nbPoolHandle, + 0, + &pNetBufferList); + + if(bytesRetreated) + { + /// ... and advance the offset back to the original position. + NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), + bytesRetreated, + FALSE, + 0); + } + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundMACFrame: FwpsAllocateCloneNetBufferList() [status: %#x]\n", + status); + + HLPR_BAIL; + } + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif /// DBG + + pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList, + TRUE); + + status = FwpsInjectMacReceiveAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + 0, + pClassifyValues->layerId, + interfaceIndex, + ndisPort, + pNetBufferList, + CompleteBasicPacketInjection, + pCompletionData); + + NT_ASSERT(irql == KeGetCurrentIrql()); + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundMACFrame: FwpsInjectMacReceiveAsync() [status: %#x]\n", + status); + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalFailedInjectionCalls); + +#endif /// DBG + + } + +#if DBG + + else + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalSuccessfulInjectionCalls); + +#endif /// DBG + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + + if(status != STATUS_SUCCESS) + { + if(pNetBufferList) + { + FwpsFreeCloneNetBufferList(pNetBufferList, + 0); + + pNetBufferList = 0; + +#if DBG + + BasicPacketInjectionCountersDecrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif + + } + + if(pCompletionData) + BasicPacketInjectionCompletionDataDestroy(&pCompletionData, + TRUE); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformBasicPacketInjectionAtInboundMACFrame() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="PerformBasicPacketInjectionAtOutboundMACFrame" + + Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the stack from the + outgoing MAC Layers using FwpsInjectMacSendAsync().
+
+ Notes: Applies to the following outbound layers:
+ FWPM_LAYER_OUTBOUND_MAC_FRAME_ETHERNET
+ FWPM_LAYER_OUTBOUND_MAC_FRAME_NATIVE
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/HH439593.aspx
+ HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +NTSTATUS PerformBasicPacketInjectionAtOutboundMACFrame(_In_ CLASSIFY_DATA** ppClassifyData, + _In_ INJECTION_DATA** ppInjectionData, + _In_ BOOLEAN isInline = FALSE) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformBasicPacketInjectionAtOutboundMACFrame()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppInjectionData); + NT_ASSERT(*ppClassifyData); + NT_ASSERT(*ppInjectionData); + + NTSTATUS status = STATUS_SUCCESS; + FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; + IF_INDEX interfaceIndex = 0; + NDIS_PORT_NUMBER ndisPort = 0; + NET_BUFFER_LIST* pNetBufferList = 0; + BASIC_PACKET_INJECTION_COMPLETION_DATA* pCompletionData = 0; + FWP_VALUE* pInterfaceIndex = 0; + FWP_VALUE* pNDISPort = 0; + +#if DBG + + KIRQL irql = KeGetCurrentIrql(); + HANDLE injectionHandle = (*ppInjectionData)->injectionHandle; + +#endif /// DBG + +#pragma warning(push) +#pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + HLPR_NEW(pCompletionData, + BASIC_PACKET_INJECTION_COMPLETION_DATA, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, + status); + +#pragma warning(pop) + + KeInitializeSpinLock(&(pCompletionData->spinLock)); + + pCompletionData->performedInline = isInline; + pCompletionData->pClassifyData = *ppClassifyData; + pCompletionData->pInjectionData = *ppInjectionData; + + /// Responsibility for freeing this memory has been transferred to the pCompletionData + *ppClassifyData = 0; + + *ppInjectionData = 0; + + pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_INTERFACE_INDEX); + if(pInterfaceIndex && + pInterfaceIndex->type == FWP_UINT32) + interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32; + + pNDISPort = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_NDIS_PORT); + if(pNDISPort && + pNDISPort->type == FWP_UINT32) + ndisPort = (NDIS_PORT_NUMBER)pNDISPort->uint32; + + /// Initial offset is at the MAC Header, so just clone the entire NET_BUFFER_LIST. + status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + g_pNDISPoolData->nblPoolHandle, + g_pNDISPoolData->nbPoolHandle, + 0, + &pNetBufferList); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtOutboundMACFrame: FwpsAllocateCloneNetBufferList() [status: %#x]\n", + status); + + HLPR_BAIL; + } + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif /// DBG + + pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList, + TRUE); + + status = FwpsInjectMacSendAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + 0, + pClassifyValues->layerId, + interfaceIndex, + ndisPort, + pNetBufferList, + CompleteBasicPacketInjection, + pCompletionData); + + NT_ASSERT(irql == KeGetCurrentIrql()); + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtOutboundMACFrame: FwpsInjectMacSendAsync() [status: %#x]\n", + status); + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalFailedInjectionCalls); + +#endif /// DBG + + } + +#if DBG + + else + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalSuccessfulInjectionCalls); + +#endif /// DBG + + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + + if(status != STATUS_SUCCESS) + { + if(pNetBufferList) + { + FwpsFreeCloneNetBufferList(pNetBufferList, + 0); + + pNetBufferList = 0; + +#if DBG + + BasicPacketInjectionCountersDecrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif + + } + + if(pCompletionData) + BasicPacketInjectionCompletionDataDestroy(&pCompletionData, + TRUE); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformBasicPacketInjectionAtOutboundMACFrame() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="PerformBasicPacketInjectionAtIngressVSwitchEthernet" + + Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the virtual switch's + ingress path from the ingress VSwitch Layers using + FwpsInjectvSwitchEthernetIngressAsync0().
+
+ Notes: Applies to the following ingress layers:
+ FWPM_LAYER_INGRESS_VSWITCH_ETHERNET
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/HH439669.aspx
+ HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +NTSTATUS PerformBasicPacketInjectionAtIngressVSwitchEthernet(_In_ CLASSIFY_DATA** ppClassifyData, + _In_ INJECTION_DATA** ppInjectionData, + _In_ BOOLEAN isInline = FALSE) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformBasicPacketInjectionAtIngressVSwitchEthernet()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppInjectionData); + NT_ASSERT(*ppClassifyData); + NT_ASSERT(*ppInjectionData); + + NTSTATUS status = STATUS_SUCCESS; + FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; + FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; + FWP_VALUE* pVSwitchIDValue = 0; + FWP_BYTE_BLOB* pVSwitchID = 0; + NDIS_SWITCH_PORT_ID sourcePortID = 0; + NDIS_SWITCH_NIC_INDEX sourceNICIndex = 0; + NET_BUFFER_LIST* pNetBufferList = 0; + BASIC_PACKET_INJECTION_COMPLETION_DATA* pCompletionData = 0; + +#if DBG + + KIRQL irql = KeGetCurrentIrql(); + HANDLE injectionHandle = (*ppInjectionData)->injectionHandle; + +#endif /// DBG + +#pragma warning(push) +#pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + HLPR_NEW(pCompletionData, + BASIC_PACKET_INJECTION_COMPLETION_DATA, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, + status); + +#pragma warning(pop) + + KeInitializeSpinLock(&(pCompletionData->spinLock)); + + pCompletionData->performedInline = isInline; + pCompletionData->pClassifyData = *ppClassifyData; + pCompletionData->pInjectionData = *ppInjectionData; + + /// Responsibility for freeing this memory has been transferred to the pCompletionData + *ppClassifyData = 0; + + *ppInjectionData = 0; + + if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata, + FWPS_L2_METADATA_FIELD_VSWITCH_SOURCE_PORT_ID)) + sourcePortID = pMetadata->vSwitchSourcePortId; + + if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata, + FWPS_L2_METADATA_FIELD_VSWITCH_SOURCE_NIC_INDEX)) + sourceNICIndex = (NDIS_SWITCH_NIC_INDEX)pMetadata->vSwitchSourceNicIndex; + + pVSwitchIDValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_VSWITCH_ID); + if(pVSwitchIDValue) + pVSwitchID = pVSwitchIDValue->byteBlob; + + if(pVSwitchID == 0) + { + status = STATUS_INVALID_MEMBER; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtIngressVSwitchEthernet() [status: %#x][pVSwitchID: %#p]\n", + status, + pVSwitchID); + + HLPR_BAIL; + } + + /// Initial offset is at the MAC Header, so just clone the entire NET_BUFFER_LIST. + status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + g_pNDISPoolData->nblPoolHandle, + g_pNDISPoolData->nbPoolHandle, + 0, + &pNetBufferList); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtIngressVSwitchEthernet: FwpsAllocateCloneNetBufferList() [status: %#x]\n", + status); + + HLPR_BAIL; + } + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif /// DBG + + pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList, + TRUE); + + status = FwpsInjectvSwitchEthernetIngressAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + 0, + 0, + pVSwitchID, + sourcePortID, + sourceNICIndex, + pNetBufferList, + CompleteBasicPacketInjection, + pCompletionData); + + NT_ASSERT(irql == KeGetCurrentIrql()); + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtIngressVSwitchEthernet: FwpsInjectvSwitchEthernetIngressAsync() [status: %#x]\n", + status); + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalFailedInjectionCalls); + +#endif /// DBG + + } + +#if DBG + + else + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalSuccessfulInjectionCalls); + +#endif /// DBG + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + + if(status != STATUS_SUCCESS) + { + if(pNetBufferList) + { + FwpsFreeCloneNetBufferList(pNetBufferList, + 0); + + pNetBufferList = 0; + +#if DBG + + BasicPacketInjectionCountersDecrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif + + } + + if(pCompletionData) + BasicPacketInjectionCompletionDataDestroy(&pCompletionData, + TRUE); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformBasicPacketInjectionAtIngressVSwitchEthernet() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="PerformBasicPacketInjectionAtEgressVSwitchEthernet" + + Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the virtual switch's + ingress path from the egress VSwitch Layers using + FwpsInjectvSwitchEthernetIngressAsync0().
+
+ Notes: Applies to the following egress layers:
+ FWPM_LAYER_EGRESS_VSWITCH_ETHERNET
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/HH439662.aspx
+ HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +NTSTATUS PerformBasicPacketInjectionAtEgressVSwitchEthernet(_In_ CLASSIFY_DATA** ppClassifyData, + _In_ INJECTION_DATA** ppInjectionData, + _In_ BOOLEAN isInline = FALSE) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformBasicPacketInjectionAtEgressVSwitchEthernet()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppInjectionData); + NT_ASSERT(*ppClassifyData); + NT_ASSERT(*ppInjectionData); + + NTSTATUS status = STATUS_SUCCESS; + FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; + FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; + FWP_VALUE* pVSwitchIDValue = 0; + FWP_BYTE_BLOB* pVSwitchID = 0; + NDIS_SWITCH_PORT_ID sourcePortID = 0; + NDIS_SWITCH_NIC_INDEX sourceNICIndex = 0; + NET_BUFFER_LIST* pNetBufferList = 0; + BASIC_PACKET_INJECTION_COMPLETION_DATA* pCompletionData = 0; + +#if DBG + + KIRQL irql = KeGetCurrentIrql(); + HANDLE injectionHandle = (*ppInjectionData)->injectionHandle; + +#endif /// DBG + +#pragma warning(push) +#pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + HLPR_NEW(pCompletionData, + BASIC_PACKET_INJECTION_COMPLETION_DATA, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, + status); + +#pragma warning(pop) + + KeInitializeSpinLock(&(pCompletionData->spinLock)); + + pCompletionData->performedInline = isInline; + pCompletionData->pClassifyData = *ppClassifyData; + pCompletionData->pInjectionData = *ppInjectionData; + + /// Responsibility for freeing this memory has been transferred to the pCompletionData + *ppClassifyData = 0; + + *ppInjectionData = 0; + + if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata, + FWPS_L2_METADATA_FIELD_VSWITCH_SOURCE_PORT_ID)) + sourcePortID = pMetadata->vSwitchSourcePortId; + + if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata, + FWPS_L2_METADATA_FIELD_VSWITCH_SOURCE_NIC_INDEX)) + sourceNICIndex = (NDIS_SWITCH_NIC_INDEX)pMetadata->vSwitchSourceNicIndex; + + pVSwitchIDValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_VSWITCH_ID); + if(pVSwitchIDValue) + pVSwitchID = pVSwitchIDValue->byteBlob; + + if(pVSwitchID == 0) + { + status = STATUS_INVALID_MEMBER; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtEgressVSwitchEthernet() [status: %#x][pVSwitchID: %#p]\n", + status, + pVSwitchID); + + HLPR_BAIL; + } + + /// Initial offset is at the MAC Header, so just clone the entire NET_BUFFER_LIST. + status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + g_pNDISPoolData->nblPoolHandle, + g_pNDISPoolData->nbPoolHandle, + 0, + &pNetBufferList); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtEgressVSwitchEthernet: FwpsAllocateCloneNetBufferList() [status: %#x]\n", + status); + + HLPR_BAIL; + } + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif /// DBG + + pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList, + TRUE); + + status = FwpsInjectvSwitchEthernetIngressAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + 0, + 0, + pVSwitchID, + sourcePortID, + sourceNICIndex, + pNetBufferList, + CompleteBasicPacketInjection, + pCompletionData); + + NT_ASSERT(irql == KeGetCurrentIrql()); + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtEgressVSwitchEthernet: FwpsInjectvSwitchEthernetEgressAsync() [status: %#x]\n", + status); + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalFailedInjectionCalls); + +#endif /// DBG + + } + +#if DBG + + else + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalSuccessfulInjectionCalls); + +#endif /// DBG + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + + if(status != STATUS_SUCCESS) + { + if(pNetBufferList) + { + FwpsFreeCloneNetBufferList(pNetBufferList, + 0); + + pNetBufferList = 0; + +#if DBG + + BasicPacketInjectionCountersDecrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif + + } + + if(pCompletionData) + BasicPacketInjectionCompletionDataDestroy(&pCompletionData, + TRUE); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformBasicPacketInjectionAtEgressVSwitchEthernet() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +#endif // (NTDDI_VERSION >= NTDDI_WIN8) + +/** + @private_function="PerformBasicPacketInjectionAtInboundNetwork" + + Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the stack's inbound path + from the incoming Network Layers using FwpsInjectNetworkReceiveAsync().
+
+ Notes: Applies to the following inbound layers:
+ FWPM_LAYER_INBOUND_IPPACKET_V{4/6}
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF551183.aspx
+ HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +NTSTATUS PerformBasicPacketInjectionAtInboundNetwork(_In_ CLASSIFY_DATA** ppClassifyData, + _In_ INJECTION_DATA** ppInjectionData, + _In_ BOOLEAN isInline = FALSE) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformBasicPacketInjectionAtInboundNetwork()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppInjectionData); + NT_ASSERT(*ppClassifyData); + NT_ASSERT(*ppInjectionData); + + NTSTATUS status = STATUS_SUCCESS; + FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; + FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; + COMPARTMENT_ID compartmentID = DEFAULT_COMPARTMENT_ID; + IF_INDEX interfaceIndex = 0; + IF_INDEX subInterfaceIndex = 0; + UINT32 flags = 0; + NET_BUFFER_LIST* pNetBufferList = 0; + BASIC_PACKET_INJECTION_COMPLETION_DATA* pCompletionData = 0; + UINT32 ipHeaderSize = 0; + UINT32 bytesRetreated = 0; + FWP_VALUE* pInterfaceIndex = 0; + FWP_VALUE* pSubInterfaceIndex = 0; + FWP_VALUE* pFlags = 0; + NDIS_TCP_IP_CHECKSUM_PACKET_INFO checksumInfo = {0}; + +#if DBG + + KIRQL irql = KeGetCurrentIrql(); + HANDLE injectionHandle = (*ppInjectionData)->injectionHandle; + +#endif /// DBG + +#pragma warning(push) +#pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + HLPR_NEW(pCompletionData, + BASIC_PACKET_INJECTION_COMPLETION_DATA, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, + status); + +#pragma warning(pop) + + KeInitializeSpinLock(&(pCompletionData->spinLock)); + + pCompletionData->performedInline = isInline; + pCompletionData->pClassifyData = *ppClassifyData; + pCompletionData->pInjectionData = *ppInjectionData; + + /// Responsibility for freeing this memory has been transferred to the pCompletionData + *ppClassifyData = 0; + + *ppInjectionData = 0; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_COMPARTMENT_ID)) + compartmentID = (COMPARTMENT_ID)pMetadata->compartmentId; + + pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_INTERFACE_INDEX); + if(pInterfaceIndex && + pInterfaceIndex->type == FWP_UINT32) + interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32; + + pSubInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_SUB_INTERFACE_INDEX); + if(pSubInterfaceIndex && + pSubInterfaceIndex->type == FWP_UINT32) + subInterfaceIndex = (IF_INDEX)pSubInterfaceIndex->uint32; + + pFlags = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_FLAGS); + if(pFlags && + pFlags->type == FWP_UINT32) + flags = pFlags->uint32; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_IP_HEADER_SIZE)) + bytesRetreated = ipHeaderSize = pMetadata->ipHeaderSize; + + checksumInfo.Value = (ULONG)(ULONG_PTR)NET_BUFFER_LIST_INFO((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + TcpIpChecksumNetBufferListInfo); + + /// Initial offset is at the Transport Header, so retreat the size of the IP Header ... + status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), + bytesRetreated, + 0, + 0); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundNetwork: NdisRetreatNetBufferDataStart() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + /// ... clone the entire NET_BUFFER_LIST ... + status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + g_pNDISPoolData->nblPoolHandle, + g_pNDISPoolData->nbPoolHandle, + 0, + &pNetBufferList); + + /// ... and advance the offset back to the original position. + NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), + bytesRetreated, + FALSE, + 0); + + if(status != STATUS_SUCCESS || + !pNetBufferList) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundNetwork: FwpsAllocateCloneNetBufferList() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + /// Handle if this packet had the IP checksum offloaded or if it's loopback + if(checksumInfo.Receive.NdisPacketIpChecksumSucceeded || + flags & FWP_CONDITION_FLAG_IS_LOOPBACK) + { + /// Prevent TCP/IP Zone crossing and recalculate the checksums + if(flags & FWP_CONDITION_FLAG_IS_LOOPBACK) + { + FWP_VALUE* pLocalAddress = 0; + FWP_VALUE* pRemoteAddress = 0; + FWP_VALUE* pLoopbackAddress = 0; + + pLocalAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_REMOTE_ADDRESS); + if(pLocalAddress && + ((pLocalAddress->type == FWP_UINT32 && + RtlCompareMemory(&(pLocalAddress->uint32), + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE)) || + (pLocalAddress->type == FWP_BYTE_ARRAY16_TYPE && + RtlCompareMemory(pLocalAddress->byteArray16->byteArray16, + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE)))) + pLoopbackAddress = pLocalAddress; + + if(!pLoopbackAddress) + { + pRemoteAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_REMOTE_ADDRESS); + if(pRemoteAddress && + ((pRemoteAddress->type == FWP_UINT32 && + RtlCompareMemory(&(pRemoteAddress->uint32), + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE)) || + (pRemoteAddress->type == FWP_BYTE_ARRAY16_TYPE && + RtlCompareMemory(pRemoteAddress->byteArray16->byteArray16, + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE)))) + pLoopbackAddress = pRemoteAddress; + } + + if(pLoopbackAddress) + { + status = KrnlHlprIPHeaderModifyLoopbackToLocal(pMetadata, + pLoopbackAddress, + ipHeaderSize, + pNetBufferList, + (const WSACMSGHDR*)pCompletionData->pInjectionData->pControlData, + pCompletionData->pInjectionData->controlDataLength); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundNetwork: KrnlHlprIPHeaderModifyLoopbackToLocal() [status: %#x]\n", + status); + + HLPR_BAIL; + } + } + } + else + { + /// Recalculate the checksum + if(pCompletionData->pInjectionData->addressFamily == AF_INET) + KrnlHlprIPHeaderCalculateV4Checksum(pNetBufferList, + ipHeaderSize); + } + } + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif /// DBG + + pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList); + + /// Handle if this packet is destined for the software loopback + if(flags & FWP_CONDITION_FLAG_IS_LOOPBACK) + { + FWP_VALUE* pLocalAddress = 0; + FWP_VALUE* pRemoteAddress = 0; + FWP_VALUE* pLoopbackAddress = 0; + + pLocalAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_REMOTE_ADDRESS); + if(pLocalAddress && + ((pLocalAddress->type == FWP_UINT32 && + RtlCompareMemory(&(pLocalAddress->uint32), + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE)) || + (pLocalAddress->type == FWP_BYTE_ARRAY16_TYPE && + RtlCompareMemory(pLocalAddress->byteArray16->byteArray16, + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE)))) + pLoopbackAddress = pLocalAddress; + + if(!pLoopbackAddress) + { + pRemoteAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_REMOTE_ADDRESS); + if(pRemoteAddress && + ((pRemoteAddress->type == FWP_UINT32 && + RtlCompareMemory(&(pRemoteAddress->uint32), + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE)) || + (pRemoteAddress->type == FWP_BYTE_ARRAY16_TYPE && + RtlCompareMemory(pRemoteAddress->byteArray16->byteArray16, + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE)))) + pLoopbackAddress = pRemoteAddress; + } + + if(pLoopbackAddress) + { + status = KrnlHlprIPHeaderModifyLoopbackToLocal(pMetadata, + pLoopbackAddress, + ipHeaderSize, + pNetBufferList, + (const WSACMSGHDR*)pCompletionData->pInjectionData->pControlData, + pCompletionData->pInjectionData->controlDataLength); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundNetwork: KrnlHlprIPHeaderModifyLoopbackToLocal() [status: %#x]\n", + status); + + HLPR_BAIL; + } + } + } + + status = FwpsInjectNetworkReceiveAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + 0, + compartmentID, + interfaceIndex, + subInterfaceIndex, + pNetBufferList, + CompleteBasicPacketInjection, + pCompletionData); + + NT_ASSERT(irql == KeGetCurrentIrql()); + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundNetwork: FwpsInjectNetworkReceiveAsync() [status: %#x]\n", + status); + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalFailedInjectionCalls); + +#endif /// DBG + + } + +#if DBG + + else + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalSuccessfulInjectionCalls); + +#endif /// DBG + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + + if(status != STATUS_SUCCESS) + { + if(pNetBufferList) + { + FwpsFreeCloneNetBufferList(pNetBufferList, + 0); + + pNetBufferList = 0; + +#if DBG + + BasicPacketInjectionCountersDecrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif + + } + + if(pCompletionData) + BasicPacketInjectionCompletionDataDestroy(&pCompletionData, + TRUE); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformBasicPacketInjectionAtInboundNetwork() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="PerformBasicPacketInjectionAtOutboundNetwork" + + Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the stack's outbound path + from the outgoing Network Layers using FwpsInjectNetworkSendAsync().
+
+ Notes: Applies to the following outbound layers:
+ FWPM_LAYER_OUTBOUND_IPPACKET_V{4/6}
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF551185.aspx
+ HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +NTSTATUS PerformBasicPacketInjectionAtOutboundNetwork(_In_ CLASSIFY_DATA** ppClassifyData, + _In_ INJECTION_DATA** ppInjectionData, + _In_ BOOLEAN isInline = FALSE) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformBasicPacketInjectionAtOutboundNetwork()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppInjectionData); + NT_ASSERT(*ppClassifyData); + NT_ASSERT(*ppInjectionData); + + NTSTATUS status = STATUS_SUCCESS; + FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; + COMPARTMENT_ID compartmentID = DEFAULT_COMPARTMENT_ID; + NET_BUFFER_LIST* pNetBufferList = 0; + BASIC_PACKET_INJECTION_COMPLETION_DATA* pCompletionData = 0; + +#if DBG + + KIRQL irql = KeGetCurrentIrql(); + HANDLE injectionHandle = (*ppInjectionData)->injectionHandle; + +#endif /// DBG + +#pragma warning(push) +#pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + HLPR_NEW(pCompletionData, + BASIC_PACKET_INJECTION_COMPLETION_DATA, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, + status); + +#pragma warning(pop) + + KeInitializeSpinLock(&(pCompletionData->spinLock)); + + pCompletionData->performedInline = isInline; + pCompletionData->pClassifyData = *ppClassifyData; + pCompletionData->pInjectionData = *ppInjectionData; + + /// Responsibility for freeing this memory has been transferred to the pCompletionData + *ppClassifyData = 0; + + *ppInjectionData = 0; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_COMPARTMENT_ID)) + compartmentID = (COMPARTMENT_ID)pMetadata->compartmentId; + + /// Initial offset is at the IP Header, so just clone the entire NET_BUFFER_LIST. + status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + g_pNDISPoolData->nblPoolHandle, + g_pNDISPoolData->nbPoolHandle, + 0, + &pNetBufferList); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtOutboundNetwork: FwpsAllocateCloneNetBufferList() [status: %#x]\n", + status); + + HLPR_BAIL; + } + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif /// DBG + + pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList); + + status = FwpsInjectNetworkSendAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + 0, + compartmentID, + pNetBufferList, + CompleteBasicPacketInjection, + pCompletionData); + + NT_ASSERT(irql == KeGetCurrentIrql()); + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtOutboundNetwork: FwpsInjectNetworkSendAsync() [status: %#x]\n", + status); + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalFailedInjectionCalls); + +#endif /// DBG + + } + +#if DBG + + else + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalSuccessfulInjectionCalls); + +#endif /// DBG + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + + if(status != STATUS_SUCCESS) + { + if(pNetBufferList) + { + FwpsFreeCloneNetBufferList(pNetBufferList, + 0); + + pNetBufferList = 0; + +#if DBG + + BasicPacketInjectionCountersDecrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif + + } + + if(pCompletionData) + BasicPacketInjectionCompletionDataDestroy(&pCompletionData, + TRUE); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformBasicPacketInjectionAtOutboundNetwork() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="PerformBasicPacketInjectionAtForward" + + Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the stack's forward path + using FwpsInjectForwardAsync().
+
+ Notes: Applies to the following forwarding layers:
+ FWPM_LAYER_IPFORWARD_V{4/6}
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF551186.aspx
+ HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +NTSTATUS PerformBasicPacketInjectionAtForward(_In_ CLASSIFY_DATA** ppClassifyData, + _In_ INJECTION_DATA** ppInjectionData, + _In_ BOOLEAN isInline = FALSE) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformBasicPacketInjectionAtForward()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppInjectionData); + NT_ASSERT(*ppClassifyData); + NT_ASSERT(*ppInjectionData); + + NTSTATUS status = STATUS_SUCCESS; + FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; + FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; + COMPARTMENT_ID compartmentID = DEFAULT_COMPARTMENT_ID; + IF_INDEX interfaceIndex = 0; + UINT32 flags = 0; + NET_BUFFER_LIST* pNetBufferList = 0; + BASIC_PACKET_INJECTION_COMPLETION_DATA* pCompletionData = 0; + UINT32 ipHeaderSize = 0; + FWP_VALUE* pInterfaceIndex = 0; + FWP_VALUE* pFlags = 0; + BOOLEAN isWeakHostReceive = FALSE; + BOOLEAN isWeakHostSend = FALSE; + PSTR pInjectionFn = "FwpsInjectForwardAsync"; + NDIS_TCP_IP_CHECKSUM_PACKET_INFO checksumInfo = {0}; + +#if DBG + + KIRQL irql = KeGetCurrentIrql(); + HANDLE injectionHandle = (*ppInjectionData)->injectionHandle; + +#endif /// DBG + +#pragma warning(push) +#pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + HLPR_NEW(pCompletionData, + BASIC_PACKET_INJECTION_COMPLETION_DATA, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, + status); + +#pragma warning(pop) + + KeInitializeSpinLock(&(pCompletionData->spinLock)); + + pCompletionData->performedInline = isInline; + pCompletionData->pClassifyData = *ppClassifyData; + pCompletionData->pInjectionData = *ppInjectionData; + + /// Responsibility for freeing this memory has been transferred to the pCompletionData + *ppClassifyData = 0; + + *ppInjectionData = 0; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_COMPARTMENT_ID)) + compartmentID = (COMPARTMENT_ID)pMetadata->compartmentId; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_IP_HEADER_SIZE)) + ipHeaderSize = pMetadata->ipHeaderSize; + + pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_DESTINATION_INTERFACE_INDEX); + if(pInterfaceIndex && + pInterfaceIndex->type == FWP_UINT32) + interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32; + + pFlags = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_FLAGS); + if(pFlags && + pFlags->type == FWP_UINT32) + flags = pFlags->uint32; + +#if(NTDDI_VERSION >= NTDDI_WIN7) + + /// Determine if this is a weakhost forward + if(flags & FWP_CONDITION_FLAG_IS_INBOUND_PASS_THRU) + isWeakHostReceive = TRUE; + + if(flags & FWP_CONDITION_FLAG_IS_OUTBOUND_PASS_THRU) + isWeakHostSend = TRUE; + +#endif /// (NTDDI_VERSION >= NTDDI_WIN7) + + /// Initial offset is at the IP Header, so just clone the entire NET_BUFFER_LIST. + status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + g_pNDISPoolData->nblPoolHandle, + g_pNDISPoolData->nbPoolHandle, + 0, + &pNetBufferList); + if(status != STATUS_SUCCESS || + !pNetBufferList) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtForward: FwpsAllocateCloneNetBufferList() [status: %#x]\n", + status); + + HLPR_BAIL; + } + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif /// DBG + + checksumInfo.Value = (ULONG)(ULONG_PTR)NET_BUFFER_LIST_INFO((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + TcpIpChecksumNetBufferListInfo); + + /// Handle if this packet had the IP checksum offloaded or if it's loopback + if(checksumInfo.Receive.NdisPacketIpChecksumSucceeded || + flags & FWP_CONDITION_FLAG_IS_LOOPBACK) + { + /// Prevent TCP/IP Zone crossing and recalculate the checksums + if(flags & FWP_CONDITION_FLAG_IS_LOOPBACK) + { + FWP_VALUE* pLocalAddress = 0; + FWP_VALUE* pRemoteAddress = 0; + FWP_VALUE* pLoopbackAddress = 0; + + pLocalAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_REMOTE_ADDRESS); + if(pLocalAddress && + ((pLocalAddress->type == FWP_UINT32 && + RtlCompareMemory(&(pLocalAddress->uint32), + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE)) || + (pLocalAddress->type == FWP_BYTE_ARRAY16_TYPE && + RtlCompareMemory(pLocalAddress->byteArray16->byteArray16, + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE)))) + pLoopbackAddress = pLocalAddress; + + if(!pLoopbackAddress) + { + pRemoteAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_REMOTE_ADDRESS); + if(pRemoteAddress && + ((pRemoteAddress->type == FWP_UINT32 && + RtlCompareMemory(&(pRemoteAddress->uint32), + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE)) || + (pRemoteAddress->type == FWP_BYTE_ARRAY16_TYPE && + RtlCompareMemory(pRemoteAddress->byteArray16->byteArray16, + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE)))) + pLoopbackAddress = pRemoteAddress; + } + + if(pLoopbackAddress) + { + status = KrnlHlprIPHeaderModifyLoopbackToLocal(pMetadata, + pLoopbackAddress, + ipHeaderSize, + pNetBufferList, + (const WSACMSGHDR*)pCompletionData->pInjectionData->pControlData, + pCompletionData->pInjectionData->controlDataLength); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtForward: KrnlHlprIPHeaderModifyLoopbackToLocal() [status: %#x]\n", + status); + + HLPR_BAIL; + } + } + } + else + { + /// Recalculate the checksum + if(pCompletionData->pInjectionData->addressFamily == AF_INET) + KrnlHlprIPHeaderCalculateV4Checksum(pNetBufferList, + ipHeaderSize); + } + } + + pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList); + + /// If the Forwarded NBL is destined locally, inject using FwpsInjectNetworkReceiveAsync rather + /// than the traditional FwpsInjectForwardAsync otherwise STATUS_INVALID_PARAMETER will be + /// returned in the NBL.status and the injection fails. + if(isWeakHostReceive) + { + UINT32 index = WFPSAMPLER_INDEX; + IF_INDEX subInterfaceIndex = 0; + FWP_VALUE* pSubInterfaceIndex = 0; + + if(pCompletionData->pClassifyData->pFilter->subLayerWeight == FWPM_SUBLAYER_UNIVERSAL_WEIGHT) + index = UNIVERSAL_INDEX; + +#if DBG + + if(injectionHandle == g_pIPv4InboundForwardInjectionHandles[0] || + injectionHandle == g_pIPv4InboundForwardInjectionHandles[1]) + InterlockedDecrement64((LONG64*)&(g_bpiOutstandingNBLClones.inboundForward_IPv4)); + else if(injectionHandle == g_pIPv6InboundForwardInjectionHandles[0] || + injectionHandle == g_pIPv6InboundForwardInjectionHandles[1]) + InterlockedDecrement64((LONG64*)&(g_bpiOutstandingNBLClones.inboundForward_IPv6)); + +#endif /// DBG + + if(pCompletionData->pInjectionData->addressFamily == AF_INET) + pCompletionData->pInjectionData->injectionHandle = g_pIPv4InboundNetworkInjectionHandles[index]; + else + pCompletionData->pInjectionData->injectionHandle = g_pIPv6InboundNetworkInjectionHandles[index]; + + pSubInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_DESTINATION_SUB_INTERFACE_INDEX); + if(pSubInterfaceIndex && + pSubInterfaceIndex->type == FWP_UINT32) + subInterfaceIndex = (IF_INDEX)pSubInterfaceIndex->uint32; + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif /// DBG + + status = FwpsInjectNetworkReceiveAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + 0, + compartmentID, + interfaceIndex, + subInterfaceIndex, + pNetBufferList, + CompleteBasicPacketInjection, + pCompletionData); + } + /// If the Forwarded NBL is sourced locally, but another interface, inject using + /// FwpsInjectNetworkSendAsync rather than the traditional FwpsInjectForwardAsync otherwise + /// STATUS_INVALID_PARAMETER will be returned in the NBL.status and the injection fails + else if(isWeakHostSend) + { + UINT32 index = WFPSAMPLER_INDEX; + + if(pCompletionData->pClassifyData->pFilter->subLayerWeight == FWPM_SUBLAYER_UNIVERSAL_WEIGHT) + index = UNIVERSAL_INDEX; + +#if DBG + + if(injectionHandle == g_pIPv4OutboundForwardInjectionHandles[0] || + injectionHandle == g_pIPv4OutboundForwardInjectionHandles[1]) + InterlockedDecrement64((LONG64*)&(g_bpiOutstandingNBLClones.outboundForward_IPv4)); + else if(injectionHandle == g_pIPv6OutboundForwardInjectionHandles[0] || + injectionHandle == g_pIPv6OutboundForwardInjectionHandles[1]) + InterlockedDecrement64((LONG64*)&(g_bpiOutstandingNBLClones.outboundForward_IPv6)); + +#endif /// DBG + + if(pCompletionData->pInjectionData->addressFamily == AF_INET) + pCompletionData->pInjectionData->injectionHandle = g_pIPv4OutboundNetworkInjectionHandles[index]; + else + pCompletionData->pInjectionData->injectionHandle = g_pIPv6OutboundNetworkInjectionHandles[index]; + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif /// DBG + + status = FwpsInjectNetworkSendAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + 0, + compartmentID, + pNetBufferList, + CompleteBasicPacketInjection, + pCompletionData); + } + else + status = FwpsInjectForwardAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + 0, + pCompletionData->pInjectionData->addressFamily, + compartmentID, + interfaceIndex, + pNetBufferList, + CompleteBasicPacketInjection, + pCompletionData); + + NT_ASSERT(irql == KeGetCurrentIrql()); + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtForward: %s() [status: %#x]\n", + pInjectionFn, + status); + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalFailedInjectionCalls); + +#endif /// DBG + + } + +#if DBG + + else + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalSuccessfulInjectionCalls); + +#endif /// DBG + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + + if(status != STATUS_SUCCESS) + { + if(pNetBufferList) + { + FwpsFreeCloneNetBufferList(pNetBufferList, + 0); + + pNetBufferList = 0; + +#if DBG + + BasicPacketInjectionCountersDecrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif + + } + + if(pCompletionData) + BasicPacketInjectionCompletionDataDestroy(&pCompletionData, + TRUE); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformBasicPacketInjectionAtForward() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="PerformBasicPacketInjectionAtInboundTransport" + + Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the stack's inbound path + from the incoming Transport Layers using FwpsInjectTransportRecveiveAsync().
+
+ Notes: Applies to the following inbound layers:
+ FWPM_LAYER_INBOUND_TRANSPORT_V{4/6}
+ FWPM_LAYER_INBOUND_ICMP_ERROR_V{4/6}
+ FWPM_LAYER_DATAGRAM_DATA_V{4/6} (Inbound only)
+ FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V{4/6} (Inbound only)
+ FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V{4/6} (Inbound only)
+ FWPM_LAYER_ALE_AUTH_CONNECT_V{4/6} (Inbound, reauthorization only)
+ FWPM_LAYER_ALE_FLOW_ESTABLISHED_V{4/6} (Inbound, non-TCP only)
+ FWPM_LAYER_STREAM_PACKET_V{4/6} (Inbound only)
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF551186.aspx
+ HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +NTSTATUS PerformBasicPacketInjectionAtInboundTransport(_In_ CLASSIFY_DATA** ppClassifyData, + _In_ INJECTION_DATA** ppInjectionData, + _In_ BOOLEAN isInline = FALSE) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformBasicPacketInjectionAtInboundTransport()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppInjectionData); + NT_ASSERT(*ppClassifyData); + NT_ASSERT(*ppInjectionData); + + NTSTATUS status = STATUS_SUCCESS; + FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; + FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; + COMPARTMENT_ID compartmentID = DEFAULT_COMPARTMENT_ID; + IF_INDEX interfaceIndex = 0; + IF_INDEX subInterfaceIndex = 0; + UINT32 flags = 0; + NET_BUFFER_LIST* pNetBufferList = 0; + BASIC_PACKET_INJECTION_COMPLETION_DATA* pCompletionData = 0; + UINT32 ipHeaderSize = 0; + UINT32 transportHeaderSize = 0; + UINT32 bytesRetreated = 0; + IPPROTO protocol = IPPROTO_MAX; + FWP_VALUE* pProtocol = 0; + FWP_VALUE* pInterfaceIndex = 0; + FWP_VALUE* pSubInterfaceIndex = 0; + FWP_VALUE* pFlags = 0; + FWPS_PACKET_LIST_INFORMATION* pPacketInformation = 0; + BOOLEAN bypassInjection = FALSE; + BYTE* pSourceAddress = 0; + BYTE* pDestinationAddress = 0; + NDIS_TCP_IP_CHECKSUM_PACKET_INFO checksumInfo = {0}; + +#if DBG + + KIRQL irql = KeGetCurrentIrql(); + HANDLE injectionHandle = (*ppInjectionData)->injectionHandle; + +#endif /// DBG + +#pragma warning(push) +#pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + HLPR_NEW(pCompletionData, + BASIC_PACKET_INJECTION_COMPLETION_DATA, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, + status); + +#pragma warning(pop) + + KeInitializeSpinLock(&(pCompletionData->spinLock)); + + pCompletionData->performedInline = isInline; + pCompletionData->pClassifyData = *ppClassifyData; + pCompletionData->pInjectionData = *ppInjectionData; + + /// Responsibility for freeing this memory has been transferred to the pCompletionData + *ppClassifyData = 0; + + *ppInjectionData = 0; + + HLPR_NEW(pPacketInformation, + FWPS_PACKET_LIST_INFORMATION, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pPacketInformation, + status); + pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_INTERFACE_INDEX); + if(pInterfaceIndex && + pInterfaceIndex->type == FWP_UINT32) + interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32; + + pSubInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_SUB_INTERFACE_INDEX); + if(pSubInterfaceIndex && + pSubInterfaceIndex->type == FWP_UINT32) + subInterfaceIndex = (IF_INDEX)pSubInterfaceIndex->uint32; + + pFlags = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_FLAGS); + if(pFlags && + pFlags->type == FWP_UINT32) + flags = pFlags->uint32; + + if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4) + protocol = IPPROTO_ICMP; + else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6) + protocol = IPPROTO_ICMPV6; + +#if(NTDDI_VERSION >= NTDDI_WIN7) + + else if(pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6) + protocol = IPPROTO_TCP; + +#endif /// (NTDDI_VERSION >= NTDDI_WIN7) + + else + { + pProtocol = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_PROTOCOL); + HLPR_BAIL_ON_NULL_POINTER(pProtocol); + + protocol = (IPPROTO)pProtocol->uint8; + } + + if(pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4) + { + ipHeaderSize = IPV4_HEADER_MIN_SIZE; + + if(protocol == IPPROTO_ICMP) + transportHeaderSize = ICMP_HEADER_MIN_SIZE; + else if(protocol == IPPROTO_TCP) + transportHeaderSize = TCP_HEADER_MIN_SIZE; + else if(protocol == IPPROTO_UDP) + transportHeaderSize = UDP_HEADER_MIN_SIZE; + } + else if(pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6) + { + ipHeaderSize = IPV6_HEADER_MIN_SIZE; + + if(protocol == IPPROTO_ICMPV6) + transportHeaderSize = ICMP_HEADER_MIN_SIZE; + else if(protocol == IPPROTO_TCP) + transportHeaderSize = TCP_HEADER_MIN_SIZE; + else if(protocol == IPPROTO_UDP) + transportHeaderSize = UDP_HEADER_MIN_SIZE; + } + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_COMPARTMENT_ID)) + compartmentID = (COMPARTMENT_ID)pMetadata->compartmentId; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_IP_HEADER_SIZE) && + pMetadata->ipHeaderSize) + ipHeaderSize = pMetadata->ipHeaderSize; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE) && + pMetadata->transportHeaderSize) + transportHeaderSize = pMetadata->transportHeaderSize; + + bytesRetreated = ipHeaderSize; + + if(protocol != IPPROTO_ICMP && + protocol != IPPROTO_ICMPV6) + { + if(!isInline && + protocol != IPPROTO_TCP && + !(protocol == IPPROTO_UDP && + flags & FWP_CONDITION_FLAG_IS_RAW_ENDPOINT) && + (pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6)) + { + /// For asynchronous execution, the drop will cause the stack to continue processing on the + /// NBL for auditing purposes. This processing retreats the NBL Offset to the Transport header. + /// We need to take this into account because we only took a reference on the NBL. + } + else + bytesRetreated += transportHeaderSize; + } + else + { + if(pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6) + { + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) + bytesRetreated += pMetadata->transportHeaderSize; + } + } + + /// Query to see if IPsec has applied tunnel mode SA's to this NET_BUFFER_LIST ... + status = FwpsGetPacketListSecurityInformation((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + FWPS_PACKET_LIST_INFORMATION_QUERY_ALL_INBOUND, + pPacketInformation); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundTransport: FwpsGetPacketListSecurityInformation() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + /// ... if it has, then bypass the injection until the NET_BUFFER_LIST has come out of the tunnel + if((pPacketInformation->ipsecInformation.inbound.isTunnelMode && + !(pPacketInformation->ipsecInformation.inbound.isDeTunneled)) || + pPacketInformation->ipsecInformation.inbound.isSecure) + { + bypassInjection = TRUE; + + HLPR_BAIL; + } + + /// Initial offset is at the data, so retreat the size of the IP Header and Transport Header ... + /// For ICMP, offset is at the ICMP Header, so retreat the size of the IP Header ... + status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), + bytesRetreated, + 0, + 0); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundTransport: NdisRetreatNetBufferDataStart() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + /// ... clone the entire NET_BUFFER_LIST ... + status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + g_pNDISPoolData->nblPoolHandle, + g_pNDISPoolData->nbPoolHandle, + 0, + &pNetBufferList); + + /// ... and advance the offset back to the original position. + NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), + bytesRetreated, + FALSE, + 0); + if(status != STATUS_SUCCESS || + !pNetBufferList) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundTransport: FwpsAllocateCloneNetBufferList() [status: %#x]\n", + status); + + HLPR_BAIL; + } + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif /// DBG + + checksumInfo.Value = (ULONG)(ULONG_PTR)NET_BUFFER_LIST_INFO((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + TcpIpChecksumNetBufferListInfo); + + /// Handle if the packet was IPsec secured + if(pCompletionData->pInjectionData->isIPsecSecured) + { + /// For performance reasons, IPsec leaves the original ESP / AH information in the IP Header ... + UINT32 headerIncludeSize = 0; + UINT64 endpointHandle = 0; + UINT32 ipv4Address = 0; + UINT32 addressSize = 0; + FWP_VALUE* pRemoteAddressValue = 0; + FWP_VALUE* pLocalAddressValue = 0; + FWP_VALUE* pProtocolValue = 0; + + pRemoteAddressValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_REMOTE_ADDRESS); + if(pRemoteAddressValue) + { + if(pRemoteAddressValue->type == FWP_BYTE_ARRAY16_TYPE) + addressSize = IPV6_ADDRESS_SIZE; + else + addressSize = IPV4_ADDRESS_SIZE; + + HLPR_NEW_ARRAY(pSourceAddress, + BYTE, + addressSize, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pSourceAddress, + status); + + if(pRemoteAddressValue->type == FWP_BYTE_ARRAY16_TYPE) + RtlCopyMemory(pSourceAddress, + pRemoteAddressValue->byteArray16->byteArray16, + addressSize); + else + { + ipv4Address = htonl(pRemoteAddressValue->uint32); + + RtlCopyMemory(pSourceAddress, + &ipv4Address, + addressSize); + } + } + + pLocalAddressValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_LOCAL_ADDRESS); + if(pLocalAddressValue) + { + if(pLocalAddressValue->type == FWP_BYTE_ARRAY16_TYPE) + addressSize = IPV6_ADDRESS_SIZE; + else + addressSize = IPV4_ADDRESS_SIZE; + + HLPR_NEW_ARRAY(pDestinationAddress, + BYTE, + addressSize, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pDestinationAddress, + status); + + if(pLocalAddressValue->type == FWP_BYTE_ARRAY16_TYPE) + RtlCopyMemory(pDestinationAddress, + pLocalAddressValue->byteArray16->byteArray16, + addressSize); + else + { + ipv4Address = htonl(pLocalAddressValue->uint32); + + RtlCopyMemory(pDestinationAddress, + &ipv4Address, + addressSize); + } + } + + pProtocolValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_PROTOCOL); + if(pProtocolValue && + pProtocolValue->type == FWP_UINT8) + protocol = (IPPROTO)pProtocolValue->uint8; + else + protocol = IPPROTO_MAX; + + NT_ASSERT(protocol != IPPROTO_MAX); + +#if (NTDDI_VERSION >= NTDDI_WIN6SP1) + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_INCLUDE_HEADER)) + headerIncludeSize = pMetadata->headerIncludeHeaderLength; + +#endif // (NTDDI_VERSION >= NTDDI_WIN6SP1) + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE)) + endpointHandle = pMetadata->transportEndpointHandle; + + if(pSourceAddress == 0 || + pDestinationAddress == 0) + { + status = STATUS_INVALID_MEMBER; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketModificationAtInboundTransport() [status: %#x][pSourceAddress: %#p][pDestinationAddress: %#p]\n", + status, + pSourceAddress, + pDestinationAddress); + + HLPR_BAIL; + } + + /// ... so we must re-construct the IPHeader with the appropriate information + status = FwpsConstructIpHeaderForTransportPacket(pNetBufferList, + headerIncludeSize, + pCompletionData->pInjectionData->addressFamily, + pSourceAddress, + pDestinationAddress, + protocol, + endpointHandle, + (const WSACMSGHDR*)pCompletionData->pInjectionData->pControlData, + pCompletionData->pInjectionData->controlDataLength, + 0, + 0, + interfaceIndex, + subInterfaceIndex); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundTransport: FwpsConstructIpHeaderForTransportPacket() [status: %#x]\n", + status); + + HLPR_BAIL; + } + } + /// Handle if this packet had the IP or Transport checksums offloaded or if it's loopback + else if(checksumInfo.Receive.NdisPacketIpChecksumSucceeded || + checksumInfo.Receive.NdisPacketTcpChecksumSucceeded || + checksumInfo.Receive.NdisPacketUdpChecksumSucceeded || + flags & FWP_CONDITION_FLAG_IS_LOOPBACK) + { + /// Prevent TCP/IP Zone crossing and recalculate the checksums + if(flags & FWP_CONDITION_FLAG_IS_LOOPBACK) + { + FWP_VALUE* pLocalAddress = 0; + FWP_VALUE* pRemoteAddress = 0; + FWP_VALUE* pLoopbackAddress = 0; + + pLocalAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_REMOTE_ADDRESS); + if(pLocalAddress && + ((pLocalAddress->type == FWP_UINT32 && + RtlCompareMemory(&(pLocalAddress->uint32), + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE)) || + (pLocalAddress->type == FWP_BYTE_ARRAY16_TYPE && + RtlCompareMemory(pLocalAddress->byteArray16->byteArray16, + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE)))) + pLoopbackAddress = pLocalAddress; + + if(!pLoopbackAddress) + { + pRemoteAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_REMOTE_ADDRESS); + if(pRemoteAddress && + ((pRemoteAddress->type == FWP_UINT32 && + RtlCompareMemory(&(pRemoteAddress->uint32), + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE)) || + (pRemoteAddress->type == FWP_BYTE_ARRAY16_TYPE && + RtlCompareMemory(pRemoteAddress->byteArray16->byteArray16, + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE)))) + pLoopbackAddress = pRemoteAddress; + } + + if(pLoopbackAddress) + { + status = KrnlHlprIPHeaderModifyLoopbackToLocal(pMetadata, + pLoopbackAddress, + ipHeaderSize, + pNetBufferList, + (const WSACMSGHDR*)pCompletionData->pInjectionData->pControlData, + pCompletionData->pInjectionData->controlDataLength); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundTransport: KrnlHlprIPHeaderModifyLoopbackToLocal() [status: %#x]\n", + status); + + HLPR_BAIL; + } + } + } + else + { + /// Recalculate the checksum + if(pCompletionData->pInjectionData->addressFamily == AF_INET) + KrnlHlprIPHeaderCalculateV4Checksum(pNetBufferList, + ipHeaderSize); + } + } + + pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList); + + status = FwpsInjectTransportReceiveAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + 0, + 0, + pCompletionData->pInjectionData->addressFamily, + compartmentID, + interfaceIndex, + subInterfaceIndex, + pNetBufferList, + CompleteBasicPacketInjection, + pCompletionData); + + NT_ASSERT(irql == KeGetCurrentIrql()); + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtInboundTransport: FwpsInjectTransportReceiveAsync() [status: %#x]\n", + status); + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalFailedInjectionCalls); + +#endif /// DBG + + } + +#if DBG + + else + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalSuccessfulInjectionCalls); + +#endif /// DBG + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + + if(status != STATUS_SUCCESS || + bypassInjection) + { + if(pNetBufferList) + { + FwpsFreeCloneNetBufferList(pNetBufferList, + 0); + + pNetBufferList = 0; + +#if DBG + + BasicPacketInjectionCountersDecrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif + + } + + if(pCompletionData) + BasicPacketInjectionCompletionDataDestroy(&pCompletionData, + TRUE); + } + + HLPR_DELETE_ARRAY(pSourceAddress, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + + HLPR_DELETE_ARRAY(pDestinationAddress, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + + HLPR_DELETE(pPacketInformation, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformBasicPacketInjectionAtInboundTransport() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="PerformBasicPacketInjectionAtOutboundTransport" + + Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the stack's outbound path + from the outgoing Transport Layers using FwpsInjectTransportSendAsync().
+
+ Notes: Applies to the following outbound layers:
+ FWPM_LAYER_OUTBOUND_TRANSPORT_V{4/6}
+ FWPM_LAYER_OUTBOUND_ICMP_ERROR_V{4/6}
+ FWPM_LAYER_DATAGRAM_DATA_V{4/6} (Outbound only)
+ FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V{4/6} (Outbound only)
+ FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V{4/6} (Outbound only)
+ FWPM_LAYER_ALE_AUTH_CONNECT_V{4/6} (Outbound reauthorization only)
+ FWPM_LAYER_ALE_FLOW_ESTABLISHED_V{4/6} (Outbound, non-TCP only)
+ FWPM_LAYER_STREAM_PACKET_V{4/6} (Outbound only)
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF551188.aspx
+ HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +NTSTATUS PerformBasicPacketInjectionAtOutboundTransport(_In_ CLASSIFY_DATA** ppClassifyData, + _In_ INJECTION_DATA** ppInjectionData, + _In_ BOOLEAN isInline = FALSE) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformBasicPacketInjectionAtOutboundTransport()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppInjectionData); + NT_ASSERT(*ppClassifyData); + NT_ASSERT(*ppInjectionData); + + NTSTATUS status = STATUS_SUCCESS; + FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; + FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; + UINT64 endpointHandle = 0; + FWPS_TRANSPORT_SEND_PARAMS* pSendParams = 0; + COMPARTMENT_ID compartmentID = DEFAULT_COMPARTMENT_ID; + NET_BUFFER_LIST* pNetBufferList = 0; + BASIC_PACKET_INJECTION_COMPLETION_DATA* pCompletionData = 0; + BYTE* pRemoteAddress = 0; + FWP_VALUE* pAddressValue = 0; + +#if DBG + + KIRQL irql = KeGetCurrentIrql(); + HANDLE injectionHandle = (*ppInjectionData)->injectionHandle; + +#endif /// DBG + +#pragma warning(push) +#pragma warning(disable: 6014) /// pCompletionData & pSendParams will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + HLPR_NEW(pCompletionData, + BASIC_PACKET_INJECTION_COMPLETION_DATA, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, + status); + + HLPR_NEW(pSendParams, + FWPS_TRANSPORT_SEND_PARAMS, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pSendParams, + status); + +#pragma warning(pop) + + KeInitializeSpinLock(&(pCompletionData->spinLock)); + + pCompletionData->performedInline = isInline; + pCompletionData->pClassifyData = *ppClassifyData; + pCompletionData->pInjectionData = *ppInjectionData; + pCompletionData->pSendParams = pSendParams; + + /// Responsibility for freeing this memory has been transferred to the pCompletionData + *ppClassifyData = 0; + + *ppInjectionData = 0; + + pSendParams = 0; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE)) + endpointHandle = pMetadata->transportEndpointHandle; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_COMPARTMENT_ID)) + compartmentID = (COMPARTMENT_ID)pMetadata->compartmentId; + + pAddressValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_REMOTE_ADDRESS); + if(pAddressValue) + { + if(pCompletionData->pInjectionData->addressFamily == AF_INET) + { + UINT32 tempAddress = htonl(pAddressValue->uint32); + + HLPR_NEW_ARRAY(pRemoteAddress, + BYTE, + IPV4_ADDRESS_SIZE, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pRemoteAddress, + status); + + RtlCopyMemory(pRemoteAddress, + &tempAddress, + IPV4_ADDRESS_SIZE); + } + else + { +#pragma warning(push) +#pragma warning(disable: 6014) /// pRemoteAddress will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + HLPR_NEW_ARRAY(pRemoteAddress, + BYTE, + IPV6_ADDRESS_SIZE, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pRemoteAddress, + status); + +#pragma warning(pop) + + RtlCopyMemory(pRemoteAddress, + pAddressValue->byteArray16->byteArray16, + IPV6_ADDRESS_SIZE); + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_REMOTE_SCOPE_ID)) + pCompletionData->pSendParams->remoteScopeId = pMetadata->remoteScopeId; + } + + pCompletionData->pSendParams->remoteAddress = pRemoteAddress; + } + + pCompletionData->pSendParams->controlData = (WSACMSGHDR*)pCompletionData->pInjectionData->pControlData; + pCompletionData->pSendParams->controlDataLength = pCompletionData->pInjectionData->controlDataLength; + + /// Initial offset is at Transport Header, so just clone entire NET_BUFFER_LIST. + status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, + g_pNDISPoolData->nblPoolHandle, + g_pNDISPoolData->nbPoolHandle, + 0, + &pNetBufferList); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtOutboundTransport: FwpsAllocateCloneNetBufferList() [status: %#x]\n", + status); + + HLPR_BAIL; + } + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif /// DBG + + pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList); + + status = FwpsInjectTransportSendAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + endpointHandle, + 0, + pCompletionData->pSendParams, + pCompletionData->pInjectionData->addressFamily, + compartmentID, + pNetBufferList, + CompleteBasicPacketInjection, + pCompletionData); + + NT_ASSERT(irql == KeGetCurrentIrql()); + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformBasicPacketInjectionAtOutboundTransport: FwpsInjectTransportSendAsync() [status: %#x]\n", + status); + +#if DBG + + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalFailedInjectionCalls); + +#endif /// DBG + + } + +#if DBG + + else + BasicPacketInjectionCountersIncrement(injectionHandle, + &g_bpiTotalSuccessfulInjectionCalls); + +#endif /// DBG + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + + if(status != STATUS_SUCCESS) + { + if(pNetBufferList) + { + FwpsFreeCloneNetBufferList(pNetBufferList, + 0); + + pNetBufferList = 0; + +#if DBG + + BasicPacketInjectionCountersDecrement(injectionHandle, + &g_bpiOutstandingNBLClones); + +#endif + + } + + if(pCompletionData) + BasicPacketInjectionCompletionDataDestroy(&pCompletionData, + TRUE); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformBasicPacketInjectionAtOutboundTransport() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="BasicPacketInjectionDeferredProcedureCall" + + Purpose: Invokes the appropriate private injection routine to perform the injection at + DISPATCH_LEVEL.
+
+ Notes:
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF542972.aspx
+*/ +_IRQL_requires_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Function_class_(KDEFERRED_ROUTINE) +VOID BasicPacketInjectionDeferredProcedureCall(_In_ KDPC* pDPC, + _In_opt_ PVOID pContext, + _In_opt_ PVOID pArg1, + _In_opt_ PVOID pArg2) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> BasicPacketInjectionDeferredProcedureCall()\n"); + +#endif /// DBG + + UNREFERENCED_PARAMETER(pDPC); + UNREFERENCED_PARAMETER(pContext); + UNREFERENCED_PARAMETER(pArg2); + + NT_ASSERT(pDPC); + NT_ASSERT(pArg1); + NT_ASSERT(((DPC_DATA*)pArg1)->pClassifyData); + NT_ASSERT(((DPC_DATA*)pArg1)->pInjectionData); + + DPC_DATA* pDPCData = (DPC_DATA*)pArg1; + + if(pDPCData) + { + NTSTATUS status = STATUS_SUCCESS; + FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)pDPCData->pClassifyData->pClassifyValues; + + if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) + status = PerformBasicPacketInjectionAtInboundNetwork(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6) + status = PerformBasicPacketInjectionAtOutboundNetwork(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || + pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6) + status = PerformBasicPacketInjectionAtForward(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V6 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || + (pDPCData->pInjectionData->direction == FWP_DIRECTION_INBOUND && + (pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || /// Policy Change Reauthorization + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || /// Policy Change Reauthorization + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6))) + status = PerformBasicPacketInjectionAtInboundTransport(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6 || + (pDPCData->pInjectionData->direction == FWP_DIRECTION_OUTBOUND && + (pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || /// Policy Change Reauthorization + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || /// Policy Change Reauthorization + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6))) + status = PerformBasicPacketInjectionAtOutboundTransport(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + FALSE); + +#if(NTDDI_VERSION >= NTDDI_WIN7) + + else if(pDPCData->pInjectionData->direction == FWP_DIRECTION_INBOUND && + (pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)) + status = PerformBasicPacketInjectionAtInboundTransport(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + FALSE); + else if(pDPCData->pInjectionData->direction == FWP_DIRECTION_OUTBOUND && + (pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)) + status = PerformBasicPacketInjectionAtOutboundTransport(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + FALSE); + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE) + status = PerformBasicPacketInjectionAtInboundMACFrame(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE) + status = PerformBasicPacketInjectionAtOutboundMACFrame(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_INGRESS_VSWITCH_ETHERNET) + status = PerformBasicPacketInjectionAtIngressVSwitchEthernet(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_EGRESS_VSWITCH_ETHERNET) + status = PerformBasicPacketInjectionAtEgressVSwitchEthernet(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + FALSE); + +#endif // (NTDDI_VERSION >= NTDDI_WIN8) +#endif // (NTDDI_VERSION >= NTDDI_WIN7) + + else + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! BasicPacketInjectionDeferredProcedureCall() [status: %#x]\n", + (UINT32)STATUS_NOT_SUPPORTED); + + if(status != STATUS_SUCCESS) + { + if(pDPCData->pClassifyData) + KrnlHlprClassifyDataDestroyLocalCopy(&(pDPCData->pClassifyData)); + + if(pDPCData->pInjectionData) + KrnlHlprInjectionDataDestroy(&(pDPCData->pInjectionData)); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! BasicPacketInjectionDeferredProcedureCall: PerformBasicPacketInjection() [status: %#x]\n", + status); + } + + KrnlHlprDPCDataDestroy(&pDPCData); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- BasicPacketInjectionDeferredProcedureCall()\n"); + +#endif /// DBG + + return; +} + +/** + @private_function="BasicPacketInjectionWorkItemRoutine" + + Purpose: Invokes the appropriate private injection routine to perform the injection at + PASSIVE_LEVEL.
+
+ Notes:
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF566380.aspx
+*/ +_IRQL_requires_(PASSIVE_LEVEL) +_IRQL_requires_same_ +_Function_class_(IO_WORKITEM_ROUTINE) +VOID BasicPacketInjectionWorkItemRoutine(_In_ PDEVICE_OBJECT pDeviceObject, + _Inout_opt_ PVOID pContext) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> BasicPacketInjectionWorkItemRoutine()\n"); + +#endif /// DBG + + UNREFERENCED_PARAMETER(pDeviceObject); + + NT_ASSERT(pContext); + NT_ASSERT(((WORKITEM_DATA*)pContext)->pClassifyData); + NT_ASSERT(((WORKITEM_DATA*)pContext)->pInjectionData); + + WORKITEM_DATA* pWorkItemData = (WORKITEM_DATA*)pContext; + + if(pWorkItemData) + { + NTSTATUS status = STATUS_SUCCESS; + FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)pWorkItemData->pClassifyData->pClassifyValues; + + if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) + status = PerformBasicPacketInjectionAtInboundNetwork(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6) + status = PerformBasicPacketInjectionAtOutboundNetwork(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || + pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6) + status = PerformBasicPacketInjectionAtForward(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V6 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || + (pWorkItemData->pInjectionData->direction == FWP_DIRECTION_INBOUND && + (pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || /// Policy Change Reauthorization + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || /// Policy Change Reauthorization + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6))) + status = PerformBasicPacketInjectionAtInboundTransport(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6 || + (pWorkItemData->pInjectionData->direction == FWP_DIRECTION_OUTBOUND && + (pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || /// Policy Change Reauthorization + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || /// Policy Change Reauthorization + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6))) + status = PerformBasicPacketInjectionAtOutboundTransport(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + FALSE); + +#if(NTDDI_VERSION >= NTDDI_WIN7) + + else if(pWorkItemData->pInjectionData->direction == FWP_DIRECTION_INBOUND && + (pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)) + status = PerformBasicPacketInjectionAtInboundTransport(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + FALSE); + else if(pWorkItemData->pInjectionData->direction == FWP_DIRECTION_OUTBOUND && + (pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)) + status = PerformBasicPacketInjectionAtOutboundTransport(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + FALSE); + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE) + status = PerformBasicPacketInjectionAtInboundMACFrame(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE) + status = PerformBasicPacketInjectionAtOutboundMACFrame(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_INGRESS_VSWITCH_ETHERNET) + status = PerformBasicPacketInjectionAtIngressVSwitchEthernet(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + FALSE); + else if(pClassifyValues->layerId == FWPS_LAYER_EGRESS_VSWITCH_ETHERNET) + status = PerformBasicPacketInjectionAtEgressVSwitchEthernet(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + FALSE); + +#endif // (NTDDI_VERSION >= NTDDI_WIN8) +#endif // (NTDDI_VERSION >= NTDDI_WIN7) + + else + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! BasicPacketInjectionWorkItemRoutine() [status: %#x]\n", + (UINT32)STATUS_NOT_SUPPORTED); + + if(status != STATUS_SUCCESS) + { + if(pWorkItemData->pClassifyData) + KrnlHlprClassifyDataDestroyLocalCopy(&(pWorkItemData->pClassifyData)); + + if(pWorkItemData->pInjectionData) + KrnlHlprInjectionDataDestroy(&(pWorkItemData->pInjectionData)); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! BasicPacketInjectionWorkItemRoutine: PerformBasicPacketInjection() [status: %#x]\n", + status); + } + + KrnlHlprWorkItemDataDestroy(&pWorkItemData); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- BasicPacketInjectionWorkItemRoutine()\n"); + +#endif /// DBG + + return; +} + +/** + @private_function="TriggerBasicPacketInjectionInline" + + Purpose: Makes a reference to all the classification data structures and invokes the + appropriate private injection routine to perform the injection.
+
+ Notes:
+
+ MSDN_Ref:
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +NTSTATUS TriggerBasicPacketInjectionInline(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _Inout_opt_ VOID* pNetBufferList, + _In_opt_ const VOID* pClassifyContext, + _In_ const FWPS_FILTER* pFilter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* pClassifyOut, + _In_ INJECTION_DATA** ppInjectionData) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> TriggerBasicPacketInjectionInline()\n"); + +#endif /// DBG + + NT_ASSERT(pClassifyValues); + NT_ASSERT(pMetadata); + NT_ASSERT(pNetBufferList); + NT_ASSERT(pFilter); + NT_ASSERT(pClassifyOut); + NT_ASSERT(ppInjectionData); + NT_ASSERT(*ppInjectionData); + + + NTSTATUS status = STATUS_SUCCESS; + CLASSIFY_DATA* pClassifyData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pClassifyData will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + HLPR_NEW(pClassifyData, + CLASSIFY_DATA, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pClassifyData, + status); + +#pragma warning(pop) + + pClassifyData->pClassifyValues = pClassifyValues; + pClassifyData->pMetadataValues = pMetadata; + pClassifyData->pPacket = pNetBufferList; + pClassifyData->pClassifyContext = pClassifyContext; + pClassifyData->pFilter = pFilter; + pClassifyData->flowContext = flowContext; + pClassifyData->pClassifyOut = pClassifyOut; + + if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) + status = PerformBasicPacketInjectionAtInboundNetwork(&pClassifyData, + ppInjectionData, + TRUE); + else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6) + status = PerformBasicPacketInjectionAtOutboundNetwork(&pClassifyData, + ppInjectionData, + TRUE); + else if(pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || + pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6) + status = PerformBasicPacketInjectionAtForward(&pClassifyData, + ppInjectionData, + TRUE); + else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V6 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || + ((*ppInjectionData)->direction == FWP_DIRECTION_INBOUND && + (pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || /// Policy Change Reauthorization + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || /// Policy Change Reauthorization + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6))) + status = PerformBasicPacketInjectionAtInboundTransport(&pClassifyData, + ppInjectionData, + TRUE); + else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6 || + ((*ppInjectionData)->direction == FWP_DIRECTION_OUTBOUND && + (pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || /// Policy Change Reauthorization + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || /// Policy Change Reauthorization + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6))) + status = PerformBasicPacketInjectionAtOutboundTransport(&pClassifyData, + ppInjectionData, + TRUE); + +#if(NTDDI_VERSION >= NTDDI_WIN7) + + else if((*ppInjectionData)->direction == FWP_DIRECTION_INBOUND && + (pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)) + status = PerformBasicPacketInjectionAtInboundTransport(&pClassifyData, + ppInjectionData, + TRUE); + else if((*ppInjectionData)->direction == FWP_DIRECTION_OUTBOUND && + (pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)) + status = PerformBasicPacketInjectionAtOutboundTransport(&pClassifyData, + ppInjectionData, + TRUE); + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE) + status = PerformBasicPacketInjectionAtInboundMACFrame(&pClassifyData, + ppInjectionData, + TRUE); + else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE) + status = PerformBasicPacketInjectionAtOutboundMACFrame(&pClassifyData, + ppInjectionData, + TRUE); + else if(pClassifyValues->layerId == FWPS_LAYER_INGRESS_VSWITCH_ETHERNET) + status = PerformBasicPacketInjectionAtIngressVSwitchEthernet(&pClassifyData, + ppInjectionData, + TRUE); + else if(pClassifyValues->layerId == FWPS_LAYER_EGRESS_VSWITCH_ETHERNET) + status = PerformBasicPacketInjectionAtEgressVSwitchEthernet(&pClassifyData, + ppInjectionData, + TRUE); + +#endif // (NTDDI_VERSION >= NTDDI_WIN8) +#endif // (NTDDI_VERSION >= NTDDI_WIN7) + + else + { + status = STATUS_NOT_SUPPORTED; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! TriggerBasicPacketInjectionInline() [status: %#x]\n", + status); + } + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- TriggerBasicPacketInjectionInline() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="TriggerBasicPacketInjectionOutOfBand" + + Purpose: Creates a local copy of the classification data structures and queues a WorkItem + to perform the injection at PASSIVE_LEVEL.
+
+ Notes:
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF550679.aspx
+ HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF566380.aspx
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +NTSTATUS TriggerBasicPacketInjectionOutOfBand(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _Inout_opt_ VOID* pNetBufferList, + _In_opt_ const VOID* pClassifyContext, + _In_ const FWPS_FILTER* pFilter, + _In_ UINT64 flowContext, + _In_ FWPS_CLASSIFY_OUT* pClassifyOut, + _In_ INJECTION_DATA* pInjectionData, + _In_ PC_BASIC_PACKET_INJECTION_DATA* pPCData) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> TriggerBasicPacketInjectionOutOfBand()\n"); + +#endif /// DBG + + UNREFERENCED_PARAMETER(pClassifyOut); + + NT_ASSERT(pClassifyValues); + NT_ASSERT(pMetadata); + NT_ASSERT(pNetBufferList); + NT_ASSERT(pFilter); + NT_ASSERT(pClassifyOut); + NT_ASSERT(pInjectionData); + NT_ASSERT(pPCData); + + NTSTATUS status = STATUS_SUCCESS; + CLASSIFY_DATA* pClassifyData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pClassifyData will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + status = KrnlHlprClassifyDataCreateLocalCopy(&pClassifyData, + pClassifyValues, + pMetadata, + pNetBufferList, + pClassifyContext, + pFilter, + flowContext, + pClassifyOut); + HLPR_BAIL_ON_FAILURE(status); + +#pragma warning(pop) + + if(pPCData->useWorkItems) + status = KrnlHlprWorkItemQueue(g_pWDMDevice, + BasicPacketInjectionWorkItemRoutine, + pClassifyData, + pInjectionData, + 0); + else if(pPCData->useThreadedDPC) + status = KrnlHlprThreadedDPCQueue(BasicPacketInjectionDeferredProcedureCall, + pClassifyData, + pInjectionData, + 0); + else + status = KrnlHlprDPCQueue(BasicPacketInjectionDeferredProcedureCall, + pClassifyData, + pInjectionData, + 0); + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + + if(status != STATUS_SUCCESS) + { + if(pClassifyData) + KrnlHlprClassifyDataDestroyLocalCopy(&pClassifyData); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- TriggerBasicPacketInjectionOutOfBand() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +#if(NTDDI_VERSION >= NTDDI_WIN7) + +/** + @classify_function="ClassifyBasicPacketInjection" + + Purpose: Blocks the current NET_BUFFER_LIST and injects a clone back to the stack without + modification.
+
+ Notes: Applies to the following layers:
+ FWPS_LAYER_INBOUND_IPPACKET_V{4/6}
+ FWPS_LAYER_OUTBOUND_IPPACKET_V{4/6}
+ FWPS_LAYER_IPFORWARD_V{4/6}
+ FWPS_LAYER_INBOUND_TRANSPORT_V{4/6}
+ FWPS_LAYER_OUTBOUND_TRANSPORT_V{4/6}
+ FWPS_LAYER_DATAGRAM_DATA_V{4/6}
+ FWPS_LAYER_INBOUND_ICMP_ERROR_V{4/6}
+ FWPS_LAYER_OUTBOUND_ICMP_ERROR_V{4/6}
+ FWPS_LAYER_ALE_AUTH_CONNECT_V{4/6}
+ FWPS_LAYER_ALE_FLOW_ESTABLISHED_V{4/6}
+ FWPS_LAYER_STREAM_PACKET_V{4/6}
+ FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET
+ FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET
+ FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE
+ FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE
+ FWPS_LAYER_INGRESS_VSWITCH_ETHERNET
+ FWPS_LAYER_EGRESS_VSWITCH_ETHERNET
+
+ TCP @ FWPM_LAYER_ALE_AUTH_CONNECT_V{4/6} has no NBL
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF544893.aspx
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +VOID NTAPI ClassifyBasicPacketInjection(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _Inout_opt_ VOID* pNetBufferList, + _In_opt_ const VOID* pClassifyContext, + _In_ const FWPS_FILTER* pFilter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* pClassifyOut) +{ + NT_ASSERT(pClassifyValues); + NT_ASSERT(pMetadata); + NT_ASSERT(pFilter); + NT_ASSERT(pClassifyOut); + NT_ASSERT(pFilter->providerContext); + NT_ASSERT(pFilter->providerContext->type == FWPM_GENERAL_CONTEXT); + NT_ASSERT(pFilter->providerContext->dataBuffer); + NT_ASSERT(pFilter->providerContext->dataBuffer->size == sizeof(PC_BASIC_PACKET_INJECTION_DATA)); + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + NT_ASSERT(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6 || + pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || + pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6 || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE || + pClassifyValues->layerId == FWPS_LAYER_INGRESS_VSWITCH_ETHERNET || + pClassifyValues->layerId == FWPS_LAYER_EGRESS_VSWITCH_ETHERNET); + +#else + + NT_ASSERT(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6 || + pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || + pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6 || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6); + +#endif /// (NTDDI_VERSION >= NTDDI_WIN8) + + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> ClassifyBasicPacketInjection() [Layer: %s][FilterID: %#I64x][Rights: %#x]", + KrnlHlprFwpsLayerIDToString(pClassifyValues->layerId), + pFilter->filterId, + pClassifyOut->rights); + +#if DBG + + PrvBasicPacketInjectionCountersIncrement(pClassifyValues, + pMetadata, + &g_bpiTotalClassifies); + +#endif /// DBG + + if(pClassifyOut->rights & FWPS_RIGHT_ACTION_WRITE) + { + /// Packets are not available for TCP @ ALE_AUTH_CONNECT, so skip over as there is nothing to inject + if(pNetBufferList) + { + NTSTATUS status = STATUS_SUCCESS; + FWP_VALUE* pFlags = 0; + INJECTION_DATA* pInjectionData = 0; + + pClassifyOut->actionType = FWP_ACTION_CONTINUE; + + pFlags = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_FLAGS); + if(pFlags && + pFlags->type == FWP_UINT32) + { + /// For IPsec interop, if ALE classification is required, bypass the injection + if(pFlags->uint32 & FWP_CONDITION_FLAG_IS_IPSEC_SECURED && + FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED)) + HLPR_BAIL; + + /// Inject the individual fragments, but not the fragment grouping of those fragments + if(pFlags->uint32 & FWP_CONDITION_FLAG_IS_FRAGMENT_GROUP) + HLPR_BAIL; + } + +#pragma warning(push) +#pragma warning(disable: 6014) /// pInjectionData will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + status = KrnlHlprInjectionDataCreate(&pInjectionData, + pClassifyValues, + pMetadata, + (NET_BUFFER_LIST*)pNetBufferList, + pFilter); + HLPR_BAIL_ON_FAILURE(status); + +#pragma warning(pop) + + if(pInjectionData->injectionState != FWPS_PACKET_INJECTED_BY_SELF && + pInjectionData->injectionState != FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF) + { + BOOLEAN performOutOfBand = TRUE; + FWP_VALUE* pProtocolValue = 0; + PC_BASIC_PACKET_INJECTION_DATA* pData = (PC_BASIC_PACKET_INJECTION_DATA*)pFilter->providerContext->dataBuffer->data; + + pClassifyOut->actionType = FWP_ACTION_BLOCK; + pClassifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; + pClassifyOut->rights ^= FWPS_RIGHT_ACTION_WRITE; + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + /// This indicates that we have already acted on the 1st NBL of the distributed set. + /// We can ignore injecting the rest of the individual distributed NBLs because the + /// injected NBL will get redistributed. Flag is only set for FWPM_LAYER_EGRESS_VSWITCH. + if(pMetadata->l2Flags & FWPS_L2_INCOMING_FLAG_RECLASSIFY_MULTI_DESTINATION) + HLPR_BAIL; + +#endif /// (NTDDI_VERSION >= NTDDI_WIN8) + + if(pFlags && + pFlags->type == FWP_UINT32 && + pFlags->uint32 & FWP_CONDITION_FLAG_IS_IPSEC_SECURED) + pInjectionData->isIPsecSecured = TRUE; + + /// Override the default of performing Out of Band with the user's specified setting ... + if(pData->performInline) + performOutOfBand = FALSE; + + /// ... however, due to TCP's locking semantics, TCP can only be injected Out of Band at any transport layer or equivalent, ... + pProtocolValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_PROTOCOL); + if((pProtocolValue && + pProtocolValue->uint8 == IPPROTO_TCP && + pClassifyValues->layerId > FWPS_LAYER_IPFORWARD_V6_DISCARD) || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6) + performOutOfBand = TRUE; + + /// ... and inbound injection of loopback traffic requires us to use Out of Band modification as well due to address lookups. + if(!performOutOfBand && + pFlags && + pFlags->type == FWP_UINT32 && + pFlags->uint32 & FWP_CONDITION_FLAG_IS_LOOPBACK && + pInjectionData->direction == FWP_DIRECTION_INBOUND) + { + FWP_VALUE* pLocalAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_LOCAL_ADDRESS); + FWP_VALUE* pRemoteAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_REMOTE_ADDRESS); + + if((pLocalAddress && + ((pLocalAddress->type == FWP_UINT32 && + RtlCompareMemory(&(pLocalAddress->uint32), + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE)) || + (pLocalAddress->type == FWP_BYTE_ARRAY16_TYPE && + pLocalAddress->byteArray16 && + RtlCompareMemory(&(pLocalAddress->byteArray16->byteArray16), + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE)))) || + (pRemoteAddress && + ((pRemoteAddress->type == FWP_UINT32 && + RtlCompareMemory(&(pRemoteAddress->uint32), + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE)) || + (pRemoteAddress->type == FWP_BYTE_ARRAY16_TYPE && + pRemoteAddress->byteArray16 && + RtlCompareMemory(&(pRemoteAddress->byteArray16->byteArray16), + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE))))) + performOutOfBand = TRUE; + } + + if(performOutOfBand) + status = TriggerBasicPacketInjectionOutOfBand(pClassifyValues, + pMetadata, + pNetBufferList, + pClassifyContext, + pFilter, + flowContext, + pClassifyOut, + pInjectionData, + pData); + else + status = TriggerBasicPacketInjectionInline(pClassifyValues, + pMetadata, + pNetBufferList, + pClassifyContext, + pFilter, + flowContext, + pClassifyOut, + &pInjectionData); + } + else + { + pClassifyOut->actionType = FWP_ACTION_PERMIT; + + KrnlHlprInjectionDataDestroy(&pInjectionData); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " -- Injection previously performed.\n"); + } + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + + if(status != STATUS_SUCCESS) + { + KrnlHlprInjectionDataDestroy(&pInjectionData); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! ClassifyBasicPacketInjection() [status: %#x]\n", + status); + } + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + else if(pMetadata->l2Flags & FWPS_L2_INCOMING_FLAG_RECLASSIFY_MULTI_DESTINATION) + KrnlHlprInjectionDataDestroy(&pInjectionData); + +#endif /// (NTDDI_VERSION >= NTDDI_WIN8) + + } + else + pClassifyOut->actionType = FWP_ACTION_PERMIT; + } + +#if DBG + + PrvBasicPacketInjectionCountersIncrementTotalActionResults(pClassifyValues, + pMetadata, + pClassifyOut); + +#endif /// DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- ClassifyBasicPacketInjection() [Layer: %s][FilterID: %#I64x][Action: %#x][Rights: %#x][Absorb: %s]\n", + KrnlHlprFwpsLayerIDToString(pClassifyValues->layerId), + pFilter->filterId, + pClassifyOut->actionType, + pClassifyOut->rights, + (pClassifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_ABSORB) ? "TRUE" : "FALSE"); + + return; +} + +#else + +/** + @classify_function="ClassifyBasicPacketInjection" + + Purpose: Blocks the current NET_BUFFER_LIST and injects a clone back to the stack without + modification.
+
+ Notes: Applies to the following layers:
+ FWPS_LAYER_INBOUND_IPPACKET_V{4/6}
+ FWPS_LAYER_OUTBOUND_IPPACKET_V{4/6}
+ FWPS_LAYER_IPFORWARD_V{4/6}
+ FWPS_LAYER_INBOUND_TRANSPORT_V{4/6}
+ FWPS_LAYER_OUTBOUND_TRANSPORT_V{4/6}
+ FWPS_LAYER_DATAGRAM_DATA_V{4/6}
+ FWPS_LAYER_INBOUND_ICMP_ERROR_V{4/6}
+ FWPS_LAYER_OUTBOUND_ICMP_ERROR_V{4/6}
+ FWPS_LAYER_ALE_AUTH_CONNECT_V{4/6}
+ FWPS_LAYER_ALE_FLOW_ESTABLISHED_V{4/6}
+
+ TCP @ FWPM_LAYER_ALE_AUTH_CONNECT_V{4/6} has no NBL
+
+ MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF544890.aspx
+*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +VOID NTAPI ClassifyBasicPacketInjection(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _Inout_opt_ VOID* pNetBufferList, + _In_ const FWPS_FILTER* pFilter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* pClassifyOut) +{ + NT_ASSERT(pClassifyValues); + NT_ASSERT(pMetadata); + NT_ASSERT(pFilter); + NT_ASSERT(pClassifyOut); + NT_ASSERT(pFilter->providerContext); + NT_ASSERT(pFilter->providerContext->type == FWPM_GENERAL_CONTEXT); + NT_ASSERT(pFilter->providerContext->dataBuffer); + NT_ASSERT(pFilter->providerContext->dataBuffer->size == sizeof(PC_BASIC_PACKET_INJECTION_DATA)); + NT_ASSERT(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6 || + pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || + pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || + pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> ClassifyBasicPacketInjection() [Layer: %s][FilterID: %#I64x][Rights: %#x]", + KrnlHlprFwpsLayerIDToString(pClassifyValues->layerId), + pFilter->filterId, + pClassifyOut->rights); + +#if DBG + + PrvBasicPacketInjectionCountersIncrement(pClassifyValues, + pMetadata, + &g_bpiTotalClassifies); + +#endif /// DBG + + if(pClassifyOut->rights & FWPS_RIGHT_ACTION_WRITE) + { + /// Packets are not available for TCP @ ALE_AUTH_CONNECT, so skip over as there is nothing to inject + if(pNetBufferList) + { + NTSTATUS status = STATUS_SUCCESS; + FWP_VALUE* pFlags = 0; + INJECTION_DATA* pInjectionData = 0; + + pClassifyOut->actionType = FWP_ACTION_CONTINUE; + + pFlags = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_FLAGS); + if(pFlags && + pFlags->type == FWP_UINT32) + { + /// For IPsec interop, if ALE classification is required, bypass the injection + if(pFlags->uint32 & FWP_CONDITION_FLAG_IS_IPSEC_SECURED && + +#if(NTDDI_VERSION >= NTDDI_WIN6SP1) + + FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED)) + +#else + + pFlags->uint32 & FWP_CONDITION_FLAG_REQUIRES_ALE_CLASSIFY) + +#endif // (NTDDI_VERSION >= NTDDI_WIN6SP1) + + HLPR_BAIL; + + /// Inject the individual fragments, but not the fragment grouping of those fragments + if(pFlags->uint32 & FWP_CONDITION_FLAG_IS_FRAGMENT_GROUP) + HLPR_BAIL; + } + +#pragma warning(push) +#pragma warning(disable: 6014) /// pInjectionData will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + status = KrnlHlprInjectionDataCreate(&pInjectionData, + pClassifyValues, + pMetadata, + (NET_BUFFER_LIST*)pNetBufferList, + pFilter); + HLPR_BAIL_ON_FAILURE(status); + +#pragma warning(pop) + + if(pInjectionData->injectionState != FWPS_PACKET_INJECTED_BY_SELF && + pInjectionData->injectionState != FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF) + { + BOOLEAN performOutOfBand = TRUE; + FWP_VALUE* pProtocolValue = 0; + PC_BASIC_PACKET_INJECTION_DATA* pData = (PC_BASIC_PACKET_INJECTION_DATA*)pFilter->providerContext->dataBuffer->data; + + pClassifyOut->actionType = FWP_ACTION_BLOCK; + pClassifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; + pClassifyOut->rights ^= FWPS_RIGHT_ACTION_WRITE; + + if(pFlags && + pFlags->type == FWP_UINT32 && + pFlags->uint32 & FWP_CONDITION_FLAG_IS_IPSEC_SECURED) + pInjectionData->isIPsecSecured = TRUE; + + /// Override the default of performing Out of Band with the user's specified setting ... + if(pData->performInline) + performOutOfBand = FALSE; + + /// ... however, due to TCP's locking semantics, TCP can only be injected Out of Band at any transport layer or equivalent, ... + pProtocolValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_PROTOCOL); + if(pProtocolValue && + pProtocolValue->uint8 == IPPROTO_TCP && + pClassifyValues->layerId > FWPS_LAYER_IPFORWARD_V6_DISCARD) + performOutOfBand = TRUE; + + /// ... and inbound injection of loopback traffic requires us to use Out of Band modification as well due to address lookups. + if(!performOutOfBand && + pFlags && + pFlags->type == FWP_UINT32 && + pFlags->uint32 & FWP_CONDITION_FLAG_IS_LOOPBACK && + pInjectionData->direction == FWP_DIRECTION_INBOUND) + { + FWP_VALUE* pLocalAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_LOCAL_ADDRESS); + FWP_VALUE* pRemoteAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_REMOTE_ADDRESS); + + if((pLocalAddress && + (pLocalAddress->type == FWP_UINT32 && + RtlCompareMemory(&(pLocalAddress->uint32), + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE)) || + (pLocalAddress->type == FWP_BYTE_ARRAY16_TYPE && + RtlCompareMemory(&(pLocalAddress->byteArray16->byteArray16), + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE))) || + (pRemoteAddress && + (pRemoteAddress->type == FWP_UINT32 && + RtlCompareMemory(&(pRemoteAddress->uint32), + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE)) || + (pRemoteAddress->type == FWP_BYTE_ARRAY16_TYPE && + RtlCompareMemory(&(pRemoteAddress->byteArray16->byteArray16), + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE)))) + performOutOfBand = TRUE; + } + + if(performOutOfBand) + status = TriggerBasicPacketInjectionOutOfBand(pClassifyValues, + pMetadata, + pNetBufferList, + 0, + pFilter, + flowContext, + pClassifyOut, + pInjectionData, + pData); + else + status = TriggerBasicPacketInjectionInline(pClassifyValues, + pMetadata, + pNetBufferList, + 0, + pFilter, + flowContext, + pClassifyOut, + &pInjectionData); + } + else + { + pClassifyOut->actionType = FWP_ACTION_PERMIT; + + KrnlHlprInjectionDataDestroy(&pInjectionData); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " -- Injection previously performed.\n"); + } + + HLPR_BAIL_LABEL: + + NT_ASSERT(status == STATUS_SUCCESS); + + if(status != STATUS_SUCCESS) + { + KrnlHlprInjectionDataDestroy(&pInjectionData); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! ClassifyBasicPacketInjection() [status: %#x]\n", + status); + } + } + else + pClassifyOut->actionType = FWP_ACTION_PERMIT; + } + +#if DBG + + PrvBasicPacketInjectionCountersIncrementTotalActionResults(pClassifyValues, + pMetadata, + pClassifyOut); + +#endif /// DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- ClassifyBasicPacketInjection() [Layer: %s][FilterID: %#I64x][Action: %#x][Rights: %#x][Absorb: %s]\n", + KrnlHlprFwpsLayerIDToString(pClassifyValues->layerId), + pFilter->filterId, + pClassifyOut->actionType, + pClassifyOut->rights, + (pClassifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_ABSORB) ? "TRUE" : "FALSE"); + + return; +} + +#endif // (NTDDI_VERSION >= NTDDI_WIN7) -- cgit v1.3.1