diff options
Diffstat (limited to 'network/trans/WFPSampler/sys/ClassifyFunctions_ProxyCallouts.cpp')
| -rw-r--r-- | network/trans/WFPSampler/sys/ClassifyFunctions_ProxyCallouts.cpp | 2424 |
1 files changed, 2424 insertions, 0 deletions
diff --git a/network/trans/WFPSampler/sys/ClassifyFunctions_ProxyCallouts.cpp b/network/trans/WFPSampler/sys/ClassifyFunctions_ProxyCallouts.cpp new file mode 100644 index 00000000..d6b2b4d4 --- /dev/null +++ b/network/trans/WFPSampler/sys/ClassifyFunctions_ProxyCallouts.cpp @@ -0,0 +1,2424 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2014 Microsoft Corporation. All Rights Reserved. +// +// Module Name: +// ClassifyFunctions_ProxyCallouts.cpp +// +// Abstract: +// This module contains WFP Classify functions for proxying connections and sockets. +// +// Naming Convention: +// +// <Module><Scenario> +// +// i.e. +// +// ClassifyProxyByALERedirect +// +// <Module> +// Classify - Function is an FWPS_CALLOUT_CLASSIFY_FN +// Perform - Function executes the desired scenario. +// Prv - Function is a private helper to this module. +// Trigger - +// <Scenario> +// ProxyByALERedirect - Function demonstates use of +// FWPM_LAYER_ALE_CONNECT_REDIRECT_V{4/6} and +// FWPM_LAYER_ALE_BIND_REDIRECT_V{4/6} for proxying. +// (For use in Win7+) +// +// Private Functions: +// PerformProxyInjectionAtInboundNetwork(), +// PerformProxyInjectionAtOutboundTransport(), +// PerformProxySocketRedirection(), +// PerformProxyConnectRedirection(), +// ProxyByALERedirectWorkItemRoutine(), +// ProxyUsingInjectionMethodWorkItemRoutine(), +// TriggerProxyByALERedirectInline(), +// TriggerProxyByALERedirectOutOfBand(), +// TriggerProxyInjectionInline(), +// TriggerProxyInjectionOutOfBand(), +// +// Public Functions: +// ClassifyProxyByALERedirect(), +// ClassifyProxyByInjection(), +// +// 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, fix +// proxying by injection to use INBOUND_IPPACKET, fix +// proxying by ALE to a local service, and add support +// for multiple redirectors. +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "Framework_WFPSamplerCalloutDriver.h" /// . +#include "ClassifyFunctions_ProxyCallouts.tmh" /// $(OBJ_PATH)\$(O)\ + +/** + @private_function="PerformProxyInjectionAtInboundNetwork" + + Purpose: <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS PerformProxyInjectionAtInboundNetwork(_In_ CLASSIFY_DATA** ppClassifyData, + _In_ INJECTION_DATA** ppInjectionData, + _In_ PC_PROXY_DATA* pProxyData, + _In_ BOOLEAN isInline = FALSE) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformProxyInjectionAtInboundNetwork()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppInjectionData); + NT_ASSERT(pProxyData); + 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; + PROXY_COMPLETION_DATA* pCompletionData = 0; + UINT32 ipHeaderSize = 0; + UINT32 bytesRetreated = 0; + UINT64 endpointHandle = 0; + IPPROTO protocol = IPPROTO_MAX; + FWP_VALUE* pInterfaceIndex = 0; + FWP_VALUE* pSubInterfaceIndex = 0; + FWP_VALUE* pFlags = 0; + BYTE* pSourceAddress = 0; + BYTE* pDestinationAddress = 0; + NDIS_TCP_IP_CHECKSUM_PACKET_INFO checksumInfo = {0}; + +#if DBG + + KIRQL irql = KeGetCurrentIrql(); + +#endif /// DBG + +#pragma warning(push) +#pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy + + HLPR_NEW(pCompletionData, + PROXY_COMPLETION_DATA, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, + status); + +#pragma warning(pop) + + 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_TRANSPORT_ENDPOINT_HANDLE)) + endpointHandle = pMetadata->transportEndpointHandle; + + 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, + " !!!! PerformProxyInjectionAtInboundNetwork : 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, + " !!!! PerformProxyInjectionAtInboundNetwork : 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, + " !!!! PerformProxyInjectionAtInboundNetwork: KrnlHlprIPHeaderModifyLoopbackToLocal() [status: %#x]\n", + status); + + HLPR_BAIL; + } + } + } + else + { + /// Recalculate the checksum + if(pCompletionData->pInjectionData->addressFamily == AF_INET) + KrnlHlprIPHeaderCalculateV4Checksum(pNetBufferList, + ipHeaderSize); + } + } + + protocol = KrnlHlprIPHeaderGetProtocolField(pNetBufferList, + pCompletionData->pInjectionData->addressFamily); + + if(pProxyData->flags & PCPDF_PROXY_LOCAL_PORT || + pProxyData->flags & PCPDF_PROXY_REMOTE_PORT) + { + NTSTATUS tmpStatus = STATUS_SUCCESS; + + protocol = KrnlHlprIPHeaderGetProtocolField(pNetBufferList, + pCompletionData->pInjectionData->addressFamily); + + /// The clone is at the IP Header, so advance by the size of the IP Header. + NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), + ipHeaderSize, + FALSE, + 0); + + if(pProxyData->flags & PCPDF_PROXY_LOCAL_PORT) + { + FWP_VALUE localPort; + + RtlZeroMemory(&localPort, + sizeof(FWP_VALUE)); + + localPort.type = FWP_UINT16; + localPort.uint16 = pProxyData->originalLocalPort; + + switch(protocol) + { + case TCP: + { + UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) + tcpHeaderSize = pMetadata->transportHeaderSize; + + status = KrnlHlprTCPHeaderModifyDestinationPort(&localPort, + pNetBufferList, + tcpHeaderSize); + HLPR_BAIL_ON_FAILURE_2(status); + + break; + } + case UDP: + { + UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) + udpHeaderSize = pMetadata->transportHeaderSize; + + status = KrnlHlprUDPHeaderModifyDestinationPort(&localPort, + pNetBufferList, + udpHeaderSize); + HLPR_BAIL_ON_FAILURE_2(status); + + break; + } + } + } + + if(pProxyData->flags & PCPDF_PROXY_REMOTE_PORT) + { + FWP_VALUE remotePort; + + RtlZeroMemory(&remotePort, + sizeof(FWP_VALUE)); + + remotePort.type = FWP_UINT16; + remotePort.uint16 = pProxyData->originalRemotePort; + + switch(protocol) + { + case TCP: + { + UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) + tcpHeaderSize = pMetadata->transportHeaderSize; + + status = KrnlHlprTCPHeaderModifySourcePort(&remotePort, + pNetBufferList, + tcpHeaderSize); + HLPR_BAIL_ON_FAILURE_2(status); + + break; + } + case UDP: + { + UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) + udpHeaderSize = pMetadata->transportHeaderSize; + + status = KrnlHlprUDPHeaderModifySourcePort(&remotePort, + pNetBufferList, + udpHeaderSize); + HLPR_BAIL_ON_FAILURE_2(status); + + break; + } + } + + } + + HLPR_BAIL_LABEL_2: + + /// return the data offset to the beginning of the IP Header + tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), + ipHeaderSize, + 0, + 0); + if(tmpStatus != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformProxyInjectionAtInboundNetwork : NdisRetreatNetBufferDataStart() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + HLPR_BAIL_ON_FAILURE(status); + } + + if(pProxyData->flags & PCPDF_PROXY_LOCAL_ADDRESS) + { + FWP_VALUE localAddress; + + RtlZeroMemory(&localAddress, + sizeof(FWP_VALUE)); + + if(pCompletionData->pInjectionData->addressFamily == AF_INET) + { + localAddress.type = FWP_UINT32; + + RtlCopyMemory(&(localAddress.uint32), + pProxyData->originalLocalAddress.pIPv4, + IPV4_ADDRESS_SIZE); + } + else + { + HLPR_NEW(localAddress.byteArray16, + FWP_BYTE_ARRAY16, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(localAddress.byteArray16, + status); + + localAddress.type = FWP_BYTE_ARRAY16_TYPE; + + RtlCopyMemory(localAddress.byteArray16->byteArray16, + pProxyData->originalLocalAddress.pIPv6, + IPV6_ADDRESS_SIZE); + } + + status = KrnlHlprIPHeaderModifyDestinationAddress(&localAddress, + pNetBufferList, + TRUE); + + KrnlHlprFwpValuePurgeLocalCopy(&localAddress); + + HLPR_BAIL_ON_FAILURE(status); + } + + if(pProxyData->flags & PCPDF_PROXY_REMOTE_ADDRESS) + { + FWP_VALUE remoteAddress; + + RtlZeroMemory(&remoteAddress, + sizeof(FWP_VALUE)); + + if(pCompletionData->pInjectionData->addressFamily == AF_INET) + { + remoteAddress.type = FWP_UINT32; + + RtlCopyMemory(&(remoteAddress.uint32), + pProxyData->originalRemoteAddress.pIPv4, + IPV4_ADDRESS_SIZE); + } + else + { + HLPR_NEW(remoteAddress.byteArray16, + FWP_BYTE_ARRAY16, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(remoteAddress.byteArray16, + status); + + remoteAddress.type = FWP_BYTE_ARRAY16_TYPE; + + RtlCopyMemory(remoteAddress.byteArray16->byteArray16, + pProxyData->originalRemoteAddress.pIPv6, + IPV6_ADDRESS_SIZE); + } + + status = KrnlHlprIPHeaderModifySourceAddress(&remoteAddress, + pNetBufferList, + TRUE); + + KrnlHlprFwpValuePurgeLocalCopy(&remoteAddress); + + HLPR_BAIL_ON_FAILURE(status); + } + + pSourceAddress = KrnlHlprIPHeaderGetSourceAddressField(pNetBufferList, + pCompletionData->pInjectionData->addressFamily); + + pDestinationAddress = KrnlHlprIPHeaderGetDestinationAddressField(pNetBufferList, + pCompletionData->pInjectionData->addressFamily); + + status = FwpsConstructIpHeaderForTransportPacket(pNetBufferList, + ipHeaderSize, + pCompletionData->pInjectionData->addressFamily, + (UCHAR*)pSourceAddress, + (UCHAR*)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, + " !!!! PerformProxyInjectionAtInboundNetwork : NdisRetreatNetBufferDataStart() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + status = FwpsInjectNetworkReceiveAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + 0, + compartmentID, + interfaceIndex, + subInterfaceIndex, + pNetBufferList, + CompleteBasicPacketModification, + pCompletionData); + + NT_ASSERT(irql == KeGetCurrentIrql()); + + if(status != STATUS_SUCCESS) + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformProxyInjectionAtInboundNetwork : FwpsInjectNetworkReceiveAsync() [status: %#x]\n", + status); + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS) + { + if(pNetBufferList) + { + FwpsFreeCloneNetBufferList(pNetBufferList, + 0); + + pNetBufferList = 0; + } + + if(pCompletionData) + ProxyCompletionDataDestroy(&pCompletionData); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformProxyInjectionAtInboundNetwork() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="PerformProxyInjectionAtOutboundTransport" + + Purpose: <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS PerformProxyInjectionAtOutboundTransport(_In_ CLASSIFY_DATA** ppClassifyData, + _In_ INJECTION_DATA** ppInjectionData, + _In_ PC_PROXY_DATA* pProxyData, + _In_ BOOLEAN isInline = FALSE) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformProxyInjectionAtOutboundTransport()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppInjectionData); + NT_ASSERT(pProxyData); + 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; + PROXY_COMPLETION_DATA* pCompletionData = 0; + IPPROTO protocol = IPPROTO_MAX; + BYTE* pRemoteAddress = 0; + FWP_VALUE* pAddressValue = 0; + FWP_VALUE* pProtocolValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_PROTOCOL); + + HLPR_BAIL_ON_NULL_POINTER_WITH_STATUS(pProtocolValue, + status); + +#pragma warning(push) +#pragma warning(disable: 6014) /// pCompletionData & pSendParams will be freed in completionFn using BasicPacketInjectionCompletionDataDestroy + + HLPR_NEW(pCompletionData, + PROXY_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) + + pCompletionData->performedInline = isInline; + pCompletionData->pClassifyData = *ppClassifyData; + pCompletionData->pInjectionData = *ppInjectionData; + pCompletionData->pProxyData = pProxyData; + 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; + + protocol = (IPPROTO)pProtocolValue->uint8; + + 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 BasicPacketModificationCompletionDataDestroy + + 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 (no IP Header yet), 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, + " !!!! PerformProxyInjectionAtOutboundTransport : FwpsAllocateCloneNetBufferList() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + if(pProxyData->flags & PCPDF_PROXY_LOCAL_PORT) + { + FWP_VALUE localPort; + + RtlZeroMemory(&localPort, + sizeof(FWP_VALUE)); + + localPort.type = FWP_UINT16; + localPort.uint16 = pProxyData->proxyLocalPort; + + switch(protocol) + { + case IPPROTO_TCP: + { + UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) + tcpHeaderSize = pMetadata->transportHeaderSize; + + status = KrnlHlprTCPHeaderModifySourcePort(&localPort, + pNetBufferList, + tcpHeaderSize); + + break; + } + case IPPROTO_UDP: + { + UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) + udpHeaderSize = pMetadata->transportHeaderSize; + + status = KrnlHlprUDPHeaderModifySourcePort(&localPort, + pNetBufferList, + udpHeaderSize); + + break; + } + } + + HLPR_BAIL_ON_FAILURE(status); + } + + if(pProxyData->flags & PCPDF_PROXY_REMOTE_PORT) + { + FWP_VALUE remotePort; + + RtlZeroMemory(&remotePort, + sizeof(FWP_VALUE)); + + remotePort.type = FWP_UINT16; + remotePort.uint16 = pProxyData->proxyRemotePort; + + switch(protocol) + { + case IPPROTO_TCP: + { + UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) + tcpHeaderSize = pMetadata->transportHeaderSize; + + status = KrnlHlprTCPHeaderModifyDestinationPort(&remotePort, + pNetBufferList, + tcpHeaderSize); + + break; + } + case IPPROTO_UDP: + { + UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) + udpHeaderSize = pMetadata->transportHeaderSize; + + status = KrnlHlprUDPHeaderModifyDestinationPort(&remotePort, + pNetBufferList, + udpHeaderSize); + + break; + } + } + + HLPR_BAIL_ON_FAILURE(status); + } + + /// As there is no IP Header yet, we can only modify the destination IP address via the FWPS_TRANSPORT_SEND_PARAMS + if(pProxyData->flags & PCPDF_PROXY_REMOTE_ADDRESS) + { + if(pCompletionData->pInjectionData->addressFamily == AF_INET) + RtlCopyMemory(pCompletionData->pSendParams->remoteAddress, + pProxyData->proxyRemoteAddress.pIPv4, + IPV4_ADDRESS_SIZE); + else + { + RtlCopyMemory(pCompletionData->pSendParams->remoteAddress, + pProxyData->proxyRemoteAddress.pIPv6, + IPV6_ADDRESS_SIZE); + + pCompletionData->pSendParams->remoteScopeId.Value = pProxyData->remoteScopeId; + } + } + + status = FwpsInjectTransportSendAsync(pCompletionData->pInjectionData->injectionHandle, + pCompletionData->pInjectionData->injectionContext, + endpointHandle, + 0, + pCompletionData->pSendParams, + pCompletionData->pInjectionData->addressFamily, + compartmentID, + pNetBufferList, + CompleteProxyInjection, + pCompletionData); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! PerformProxyInjectionAtOutboundTransport : FwpsInjectTransportSendAsync() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS) + { + if(pNetBufferList) + { + FwpsFreeCloneNetBufferList(pNetBufferList, + 0); + + pNetBufferList = 0; + } + + if(pCompletionData) + ProxyCompletionDataDestroy(&pCompletionData); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformProxyInjectionAtOutboundTransport() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="ProxyUsingInjectionMethodDeferredProcedureCall" + + Purpose: Invokes the appropriate private injection routine to perform the injection at + DISPATCH_LEVEL. <br> + <br> + Notes: <br> + <br> + MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF542972.aspx <br> +*/ +_IRQL_requires_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Function_class_(KDEFERRED_ROUTINE) +VOID ProxyUsingInjectionMethodDeferredProcedureCall(_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 = 0; + + pClassifyValues = (FWPS_INCOMING_VALUES*)pDPCData->pClassifyData->pClassifyValues; + + if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6) + status = PerformProxyInjectionAtOutboundTransport(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + (PC_PROXY_DATA*)pDPCData->pContext); + else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) + status = PerformProxyInjectionAtInboundNetwork(&(pDPCData->pClassifyData), + &(pDPCData->pInjectionData), + (PC_PROXY_DATA*)pDPCData->pContext); + else + status = STATUS_FWP_INCOMPATIBLE_LAYER; + + + if(status != STATUS_SUCCESS) + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! ProxyUsingInjectionMethodDeferredProcedureCall() [status: %#x]\n", + status); + + KrnlHlprDPCDataDestroy(&pDPCData); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- ProxyUsingInjectionMethodDeferredProcedureCall()\n"); + +#endif /// DBG + + return; +} + +/** + @private_function="ProxyUsingInjectionMethodWorkItemRoutine" + + Purpose: <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_(PASSIVE_LEVEL) +_IRQL_requires_same_ +_Function_class_(IO_WORKITEM_ROUTINE) +VOID ProxyUsingInjectionMethodWorkItemRoutine(_In_ PDEVICE_OBJECT pDeviceObject, + _In_opt_ PVOID pContext) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> ProxyUsingInjectionMethodWorkItemRoutine()\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 = 0; + + pClassifyValues = (FWPS_INCOMING_VALUES*)pWorkItemData->pClassifyData->pClassifyValues; + + if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6) + status = PerformProxyInjectionAtOutboundTransport(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + (PC_PROXY_DATA*)pWorkItemData->pInjectionData->pContext); + else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) + status = PerformProxyInjectionAtInboundNetwork(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pInjectionData), + (PC_PROXY_DATA*)pWorkItemData->pContext); + else + status = STATUS_FWP_INCOMPATIBLE_LAYER; + + + if(status != STATUS_SUCCESS) + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! ProxyUsingInjectionMethodWorkItemRoutine : PerformProxyInjectionAt*() [status: %#x]\n", + status); + + KrnlHlprWorkItemDataDestroy(&pWorkItemData); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- ProxyUsingInjectionMethodWorkItemRoutine()\n"); + +#endif /// DBG + + return; +} + +/** + @private_function="TriggerProxyInjectionInline" + + Purpose: <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS TriggerProxyInjectionInline(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _Inout_ VOID* pNetBufferList, + _In_opt_ const VOID* pClassifyContext, + _In_ const FWPS_FILTER* pFilter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* pClassifyOut, + _In_ INJECTION_DATA** ppInjectionData, + _In_ PC_PROXY_DATA* pProxyData) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> TriggerProxyInjectionInline()\n"); + +#endif /// DBG + + NT_ASSERT(pClassifyValues); + NT_ASSERT(pMetadata); + NT_ASSERT(pNetBufferList); + NT_ASSERT(pFilter); + NT_ASSERT(pClassifyOut); + NT_ASSERT(ppInjectionData); + NT_ASSERT(*ppInjectionData); + NT_ASSERT(pProxyData); + NT_ASSERT(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6); + + NTSTATUS status = STATUS_SUCCESS; + CLASSIFY_DATA* pClassifyData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pClassifyData will be freed in completionFn using ProxyCompletionDataDestroy + + 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_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6) + status = PerformProxyInjectionAtOutboundTransport(&pClassifyData, + ppInjectionData, + pProxyData, + TRUE); + else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) + status = PerformProxyInjectionAtInboundNetwork(&pClassifyData, + ppInjectionData, + pProxyData, + TRUE); + else + status = STATUS_FWP_INCOMPATIBLE_LAYER; + + HLPR_BAIL_LABEL: + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- TriggerProxyInjectionInline() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="TriggerProxyInjectionOutOfBand" + + Purpose: <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS TriggerProxyInjectionOutOfBand(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _Inout_ 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_PROXY_DATA* pPCData) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> TriggerProxyInjectionOutOfBand()\n"); + +#endif /// DBG + + NT_ASSERT(pClassifyValues); + NT_ASSERT(pMetadata); + NT_ASSERT(pNetBufferList); + NT_ASSERT(pFilter); + NT_ASSERT(pClassifyOut); + NT_ASSERT(pInjectionData); + NT_ASSERT(pPCData); + NT_ASSERT(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6); + + NTSTATUS status = STATUS_SUCCESS; + CLASSIFY_DATA* pClassifyData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pClassifyData will be freed in completionFn using ProxyInjectionCompletionDataDestroy + + 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, + ProxyUsingInjectionMethodWorkItemRoutine, + pClassifyData, + pInjectionData, + (VOID*)pPCData); + else if(pPCData->useThreadedDPC) + status = KrnlHlprThreadedDPCQueue(ProxyUsingInjectionMethodDeferredProcedureCall, + pClassifyData, + pInjectionData, + (VOID*)pPCData); + else + status = KrnlHlprDPCQueue(ProxyUsingInjectionMethodDeferredProcedureCall, + pClassifyData, + pInjectionData, + (VOID*)pPCData); + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS) + { + if(pClassifyData) + KrnlHlprClassifyDataDestroyLocalCopy(&pClassifyData); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- TriggerProxyInjectionOutOfBand() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +#if(NTDDI_VERSION >= NTDDI_WIN7) + +#pragma warning(push) +#pragma warning(disable: 6101) /// *ppClassifyData and *ppRedirectData are freed and set to 0 on successful completion + +/** + @private_function="PerformProxySocketRedirection" + + Purpose: <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_At_(*ppRedirectData, _Pre_ _Notnull_) +///_At_(*ppRedirectData, _Post_ _Null_) +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS PerformProxySocketRedirection(_In_ CLASSIFY_DATA** ppClassifyData, + _Inout_ REDIRECT_DATA** ppRedirectData) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformProxySocketRedirection()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppRedirectData); + NT_ASSERT((*ppRedirectData)->pWritableLayerData); + NT_ASSERT((*ppRedirectData)->pProxyData); + + NTSTATUS status = STATUS_SUCCESS; + FWPS_BIND_REQUEST* pBindRequest = (FWPS_BIND_REQUEST*)(*ppRedirectData)->pWritableLayerData; + FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; + FWP_VALUE* pProtocolValue = 0; + UINT8 ipProtocol = 0; + + pProtocolValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_PROTOCOL); + if(pProtocolValue) + ipProtocol = pProtocolValue->uint8; + + if((*ppRedirectData)->pProxyData->flags & PCPDF_PROXY_LOCAL_ADDRESS) + INETADDR_SET_ADDRESS((PSOCKADDR)&(pBindRequest->localAddressAndPort), + (*ppRedirectData)->pProxyData->proxyLocalAddress.pBytes); + + if((*ppRedirectData)->pProxyData->flags & PCPDF_PROXY_LOCAL_PORT) + INETADDR_SET_PORT((PSOCKADDR)&(pBindRequest->localAddressAndPort), + (*ppRedirectData)->pProxyData->proxyLocalPort); + + if(ipProtocol == IPPROTO_TCP) + pBindRequest->portReservationToken = (*ppRedirectData)->pProxyData->tcpPortReservationToken; + else if(ipProtocol == IPPROTO_UDP) + pBindRequest->portReservationToken = (*ppRedirectData)->pProxyData->udpPortReservationToken; + + (*ppRedirectData)->pClassifyOut->actionType = FWP_ACTION_PERMIT; + (*ppRedirectData)->pClassifyOut->rights ^= FWPS_RIGHT_ACTION_WRITE; + +#pragma warning(push) +#pragma warning(disable: 6001) /// *ppRedirectData has already been initialized in previous call to KrnlHlprRedirectDataCreate + + /// This will apply the modified data and cleanup the classify handle + KrnlHlprRedirectDataDestroy(ppRedirectData); + +#pragma warning(pop) + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformProxySocketRedirection() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="PerformProxyConnectRedirection" + + Purpose: <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_At_(*ppRedirectData, _Pre_ _Notnull_) +///_At_(*ppRedirectData, _Post_ _Null_) +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS PerformProxyConnectRedirection(_In_ CLASSIFY_DATA** ppClassifyData, + _Inout_ REDIRECT_DATA** ppRedirectData) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PerformProxyConnectRedirection()\n"); + +#endif /// DBG + + NT_ASSERT(ppClassifyData); + NT_ASSERT(ppRedirectData); + NT_ASSERT(*ppClassifyData); + NT_ASSERT(*ppRedirectData); + + NTSTATUS status = STATUS_SUCCESS; + FWPS_CONNECT_REQUEST* pConnectRequest = (FWPS_CONNECT_REQUEST*)(*ppRedirectData)->pWritableLayerData; + UINT32 actionType = FWP_ACTION_PERMIT; + FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; + FWP_VALUE* pProtocolValue = 0; + UINT8 ipProtocol = 0; + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + SOCKADDR_STORAGE* pSockAddrStorage = 0; + + /// Set redirectHandle only if proxying locally + if((*ppRedirectData)->redirectHandle && + !((*ppRedirectData)->pProxyData->proxyToRemoteService)) + pConnectRequest->localRedirectHandle = (*ppRedirectData)->redirectHandle; + + HLPR_NEW_ARRAY(pSockAddrStorage, + SOCKADDR_STORAGE, + 2, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pSockAddrStorage, + status); + + /// Pass original remote destination values to query them in user mode + RtlCopyMemory(&(pSockAddrStorage[0]), + &(pConnectRequest->remoteAddressAndPort), + sizeof(SOCKADDR_STORAGE)); + + RtlCopyMemory(&(pSockAddrStorage[1]), + &(pConnectRequest->localAddressAndPort), + sizeof(SOCKADDR_STORAGE)); + + /// WFP will take ownership of this memory and free it when the flow / redirection terminates + pConnectRequest->localRedirectContext = pSockAddrStorage; + pConnectRequest->localRedirectContextSize = sizeof(SOCKADDR_STORAGE) * 2; + +#endif /// (NTDDI_VERSION >= NTDDI_WIN8) + + pProtocolValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, + &FWPM_CONDITION_IP_PROTOCOL); + if(pProtocolValue) + ipProtocol = pProtocolValue->uint8; + + /// For non-TCP, this setting will not be enforced being that local redirection of this tuple is only + /// available during bind time. and ideally redirection should be performed using ALE_BIND_REDIRECT instead. + if((*ppRedirectData)->pProxyData->flags & PCPDF_PROXY_LOCAL_ADDRESS) + INETADDR_SET_ADDRESS((PSOCKADDR)&(pConnectRequest->localAddressAndPort), + (*ppRedirectData)->pProxyData->proxyLocalAddress.pBytes); + + /// For non-TCP, this setting will not be enforced being that local redirection of this tuple is only + /// available during bind time. and ideally redirection should be performed using ALE_BIND_REDIRECT instead. + if((*ppRedirectData)->pProxyData->flags & PCPDF_PROXY_LOCAL_PORT) + INETADDR_SET_PORT((PSOCKADDR)&(pConnectRequest->localAddressAndPort), + (*ppRedirectData)->pProxyData->proxyLocalPort); + + if((*ppRedirectData)->pProxyData->flags & PCPDF_PROXY_REMOTE_ADDRESS) + { + if((*ppRedirectData)->pProxyData->proxyToRemoteService) + INETADDR_SET_ADDRESS((PSOCKADDR)&(pConnectRequest->remoteAddressAndPort), + (*ppRedirectData)->pProxyData->proxyRemoteAddress.pBytes); + else + { + /// Ensure we don't need to worry about crossing any of the TCP/IP stack's zones + if(INETADDR_ISANY((PSOCKADDR)&(pConnectRequest->localAddressAndPort))) + INETADDR_SETLOOPBACK((PSOCKADDR)&(pConnectRequest->remoteAddressAndPort)); + else + INETADDR_SET_ADDRESS((PSOCKADDR)&(pConnectRequest->remoteAddressAndPort), + INETADDR_ADDRESS((PSOCKADDR)&(pConnectRequest->localAddressAndPort))); + } + } + + if((*ppRedirectData)->pProxyData->flags & PCPDF_PROXY_REMOTE_PORT) + INETADDR_SET_PORT((PSOCKADDR)&(pConnectRequest->remoteAddressAndPort), + (*ppRedirectData)->pProxyData->proxyRemotePort); + + if(ipProtocol == IPPROTO_TCP) + pConnectRequest->portReservationToken = (*ppRedirectData)->pProxyData->tcpPortReservationToken; + else if(ipProtocol == IPPROTO_UDP) + pConnectRequest->portReservationToken = (*ppRedirectData)->pProxyData->udpPortReservationToken; + + if((*ppRedirectData)->pProxyData->targetProcessID) + pConnectRequest->localRedirectTargetPID = (*ppRedirectData)->pProxyData->targetProcessID; + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS) + { + actionType = FWP_ACTION_BLOCK; + + HLPR_DELETE_ARRAY(pSockAddrStorage, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + } + +#endif /// (NTDDI_VERSION >= NTDDI_WIN8) + +#pragma warning(push) +#pragma warning(disable: 6001) /// *ppRedirectData has already been initialized in previous call to KrnlHlprRedirectDataCreate + + (*ppRedirectData)->pClassifyOut->actionType = actionType; + (*ppRedirectData)->pClassifyOut->rights ^= FWPS_RIGHT_ACTION_WRITE; + + + /// This will apply the modified data and cleanup the classify handle + KrnlHlprRedirectDataDestroy(ppRedirectData); + +#pragma warning(pop) + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PerformProxyConnectRedirection() [status:%#x]\n", + status); + +#endif /// DBG + + return status; +} + +#pragma warning(pop) + +/** + @private_function="ProxyByALERedirectDeferredProcedureCall" + + Purpose: Invokes the appropriate private redirection routine to at DISPATCH_LEVEL. <br> + <br> + Notes: <br> + <br> + MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF542972.aspx <br> +*/ +_IRQL_requires_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Function_class_(KDEFERRED_ROUTINE) +VOID ProxyByALERedirectDeferredProcedureCall(_In_ KDPC* pDPC, + _In_opt_ PVOID pContext, + _In_opt_ PVOID pArg1, + _In_opt_ PVOID pArg2) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> ProxyByALERedirectDeferredProcedureCall()\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_ALE_CONNECT_REDIRECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_CONNECT_REDIRECT_V6) + status = PerformProxyConnectRedirection(&(pDPCData->pClassifyData), + &(pDPCData->pRedirectData)); + else if(pClassifyValues->layerId == FWPS_LAYER_ALE_BIND_REDIRECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_BIND_REDIRECT_V6) + status = PerformProxySocketRedirection(&(pDPCData->pClassifyData), + &(pDPCData->pRedirectData)); + + if(status != STATUS_SUCCESS) + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! ProxyByALERedirectDeferredProcedureCall() [status: %#x]\n", + status); + + KrnlHlprDPCDataDestroy(&pDPCData); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- ProxyByALERedirectDeferredProcedureCall()\n"); + +#endif /// DBG + + return; +} + +/** + @private_function="ProxyByALERedirectWorkItemRoutine" + + Purpose: <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_(PASSIVE_LEVEL) +_IRQL_requires_same_ +_Function_class_(IO_WORKITEM_ROUTINE) +VOID ProxyByALERedirectWorkItemRoutine(_In_ PDEVICE_OBJECT pDeviceObject, + _In_opt_ PVOID pContext) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> ProxyByALERedirectWorkItemRoutine()\n"); + +#endif /// DBG + + UNREFERENCED_PARAMETER(pDeviceObject); + + NT_ASSERT(pContext); + NT_ASSERT((WORKITEM_DATA*)pContext); + NT_ASSERT(((WORKITEM_DATA*)pContext)->pClassifyData); + NT_ASSERT(((WORKITEM_DATA*)pContext)->pRedirectData); + + 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_ALE_CONNECT_REDIRECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_CONNECT_REDIRECT_V6) + status = PerformProxyConnectRedirection(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pRedirectData)); + else if(pClassifyValues->layerId == FWPS_LAYER_ALE_BIND_REDIRECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_BIND_REDIRECT_V6) + status = PerformProxySocketRedirection(&(pWorkItemData->pClassifyData), + &(pWorkItemData->pRedirectData)); + + if(status != STATUS_SUCCESS) + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! ProxyByALERedirectWorkItemRoutine() [status: %#x]\n", + status); + + KrnlHlprWorkItemDataDestroy(&pWorkItemData); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- ProxyUsingInjectionMethodWorkItemRoutine()\n"); + +#endif /// DBG + + return; +} + +/** + @private_function="TriggerProxyByALERedirectInline" + + Purpose: <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS TriggerProxyByALERedirectInline(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _Inout_ VOID* pLayerData, + _In_opt_ const VOID* pClassifyContext, + _In_ const FWPS_FILTER* pFilter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* pClassifyOut, + _Inout_ REDIRECT_DATA** ppRedirectData) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> TriggerProxyByALERedirectInline()\n"); + +#endif /// DBG + + NT_ASSERT(pClassifyValues); + NT_ASSERT(pMetadata); + NT_ASSERT(pLayerData); + NT_ASSERT(pFilter); + NT_ASSERT(pClassifyOut); + NT_ASSERT(ppRedirectData); + NT_ASSERT(*ppRedirectData); + + NTSTATUS status = STATUS_SUCCESS; + CLASSIFY_DATA* pClassifyData = 0; + + HLPR_NEW(pClassifyData, + CLASSIFY_DATA, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pClassifyData, + status); + + pClassifyData->pClassifyValues = pClassifyValues; + pClassifyData->pMetadataValues = pMetadata; + pClassifyData->pPacket = pLayerData; + pClassifyData->pClassifyContext = pClassifyContext; + pClassifyData->pFilter = pFilter; + pClassifyData->flowContext = flowContext; + pClassifyData->pClassifyOut = pClassifyOut; + + (*ppRedirectData)->pClassifyOut = pClassifyOut; + + if(pClassifyValues->layerId == FWPS_LAYER_ALE_CONNECT_REDIRECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_CONNECT_REDIRECT_V6) + status = PerformProxyConnectRedirection(&pClassifyData, + ppRedirectData); + else if(pClassifyValues->layerId == FWPS_LAYER_ALE_BIND_REDIRECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_BIND_REDIRECT_V6) + status = PerformProxySocketRedirection(&pClassifyData, + ppRedirectData); + + HLPR_BAIL_LABEL: + + HLPR_DELETE(pClassifyData, + WFPSAMPLER_CALLOUT_DRIVER_TAG); + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- TriggerProxyByALERedirectInline() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @private_function="TriggerProxyByALERedirectOutOfBand" + + Purpose: <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Check_return_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS TriggerProxyByALERedirectOutOfBand(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _Inout_ VOID* pLayerData, + _In_opt_ const VOID* pClassifyContext, + _In_ const FWPS_FILTER* pFilter, + _In_ UINT64 flowContext, + _In_ FWPS_CLASSIFY_OUT* pClassifyOut, + _Inout_ REDIRECT_DATA* pRedirectData) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> TriggerProxyByALERedirectOutOfBand()\n"); + +#endif /// DBG + + NT_ASSERT(pClassifyValues); + NT_ASSERT(pMetadata); + NT_ASSERT(pLayerData); + NT_ASSERT(pFilter); + NT_ASSERT(pClassifyOut); + NT_ASSERT(pRedirectData); + + NTSTATUS status = STATUS_SUCCESS; + CLASSIFY_DATA* pClassifyData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pClassifyData will be freed in completionFn using ProxyInjectionCompletionDataDestroy + + status = KrnlHlprClassifyDataCreateLocalCopy(&pClassifyData, + pClassifyValues, + pMetadata, + pLayerData, + pClassifyContext, + pFilter, + flowContext, + pClassifyOut); + HLPR_BAIL_ON_FAILURE(status); + +#pragma warning(pop) + + status = FwpsPendClassify(pRedirectData->classifyHandle, + pFilter->filterId, + 0, + pClassifyOut); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! TriggerProxyByALERedirectOutOfBand : FwpsPendClassify() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + pClassifyOut->actionType = FWP_ACTION_BLOCK; + pClassifyOut->rights ^= FWPS_RIGHT_ACTION_WRITE; + + pRedirectData->isPended = TRUE; + pRedirectData->pClassifyOut = pClassifyData->pClassifyOut; + + if(pRedirectData->pProxyData->useWorkItems) + status = KrnlHlprWorkItemQueue(g_pWDMDevice, + ProxyByALERedirectWorkItemRoutine, + pClassifyData, + pRedirectData, + 0); + else if(pRedirectData->pProxyData->useThreadedDPC) + status = KrnlHlprThreadedDPCQueue(ProxyByALERedirectDeferredProcedureCall, + pClassifyData, + pRedirectData, + 0); + else + status = KrnlHlprDPCQueue(ProxyByALERedirectDeferredProcedureCall, + pClassifyData, + pRedirectData, + 0); + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS) + { + if(pClassifyData) + KrnlHlprClassifyDataDestroyLocalCopy(&pClassifyData); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- TriggerProxyByALERedirectOutOfBand() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @classify_function="ClassifyProxyByALERedirect" + + Purpose: <br> + <br> + Notes: Applies to the following layers: <br> + FWPM_LAYER_ALE_REDIRECT_BIND_V4 <br> + FWPM_LAYER_ALE_REDIRECT_BIND_V6 <br> + FWPM_LAYER_ALE_REDIRECT_CONNECT_V4 <br> + FWPM_LAYER_ALE_REDIRECT_CONNECT_V6 <br> + <br> + Microsoft recommends using FWPM_LAYER_STREAM_V{4/6} rather than proxying network + data to a local service. Doing so will make for a better ecosystem, however if you + feel you must proxy, then it is advised to use + FWPM_LAYER_ALE_REDIRECT_CONNECT_V{4/6}, and have the proxy service call the + REDIRECT_RECORD IOCTLs so multiple proxies can coexst without losing data on the + origin of the data. <br> + <br> + MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF551229.aspx <br> + HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF544893.aspx <br> + HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF571005.aspx <br> + HTTP://MSDN.Microsoft.com/En-US/Library/HH439677.aspx <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +VOID NTAPI ClassifyProxyByALERedirect(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _Inout_opt_ VOID* pLayerData, + _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(pLayerData); + NT_ASSERT(pClassifyContext); + NT_ASSERT(pFilter); + NT_ASSERT(pClassifyOut); + NT_ASSERT(pClassifyValues->layerId == FWPS_LAYER_ALE_CONNECT_REDIRECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_CONNECT_REDIRECT_V6 || + pClassifyValues->layerId == FWPS_LAYER_ALE_BIND_REDIRECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_BIND_REDIRECT_V6); + 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_PROXY_DATA)); + NT_ASSERT(pFilter->providerContext->dataBuffer->data); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> ClassifyProxyByALERedirect() [Layer: %s][FilterID: %#I64x][Rights: %#x]", + KrnlHlprFwpsLayerIDToString(pClassifyValues->layerId), + pFilter->filterId, + pClassifyOut->rights); + + if(pClassifyOut->rights & FWPS_RIGHT_ACTION_WRITE) + { + NTSTATUS status = STATUS_SUCCESS; + UINT32 conditionIndex = FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_FLAGS; + BOOLEAN redirectSocket = FALSE; + REDIRECT_DATA* pRedirectData = 0; + UINT32 index = WFPSAMPLER_INDEX; + + if(pFilter->subLayerWeight == FWPM_SUBLAYER_UNIVERSAL_WEIGHT) + index = UNIVERSAL_INDEX; + + if(pClassifyValues->layerId == FWPS_LAYER_ALE_BIND_REDIRECT_V4 || + pClassifyValues->layerId == FWPS_LAYER_ALE_BIND_REDIRECT_V6) + { + conditionIndex = FWPS_FIELD_ALE_BIND_REDIRECT_V4_FLAGS; + + redirectSocket = TRUE; + } + + /// Prevent infinite redirection + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + if(!redirectSocket) + { + FWPS_CONNECTION_REDIRECT_STATE redirectionState = FWPS_CONNECTION_NOT_REDIRECTED; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_REDIRECT_RECORD_HANDLE)) + { + VOID* pRedirectContext = 0; + + redirectionState = FwpsQueryConnectionRedirectState(pMetadata->redirectRecords, + *(g_WFPSamplerDeviceData.ppRedirectionHandles[index]), + &pRedirectContext); + } + + switch(redirectionState) + { + /// Go ahead and continue with our redirection + case FWPS_CONNECTION_NOT_REDIRECTED: + case FWPS_CONNECTION_REDIRECTED_BY_OTHER: + { + break; + } + /// We've already seen this, so let it through + case FWPS_CONNECTION_REDIRECTED_BY_SELF: + { + pClassifyOut->actionType = FWP_ACTION_PERMIT; + + HLPR_BAIL; + } + /// Must not perform redirection. In this case we are letting the last redirection action win. + case FWPS_CONNECTION_PREVIOUSLY_REDIRECTED_BY_SELF: + { + HLPR_BAIL; + } + } + } + +#endif /// (NTDDI_VERSION >= NTDDI_WIN8) + +#pragma warning(push) +#pragma warning(disable: 6014) /// pRedirectData will be freed in completionFn using ProxyInjectionCompletionDataDestroy + + status = KrnlHlprRedirectDataCreate(&pRedirectData, + pClassifyContext, + pFilter, + pClassifyOut, + *(g_WFPSamplerDeviceData.ppRedirectionHandles[index])); + HLPR_BAIL_ON_FAILURE(status); + +#pragma warning(pop) + + /// FWP_CONDITION_FLAG_IS_REAUTHORIZE will be set if: + /// 1) a callout with a higher priority completed its pended classification and the current + /// callout is seeing the connection for the first time + /// 2) FWPS_CLASSIFY_FLAG_REAUTHORIZE_IF_MODIFIED_BY_OTHERS was set when calling FwpsApplyModifiedLayerData + /// and another callout has further redirected the initial connection. + if(pClassifyValues->incomingValue[conditionIndex].value.uint32 & FWP_CONDITION_FLAG_IS_REAUTHORIZE) + { + if(redirectSocket) + { + FWPS_BIND_REQUEST* pBindRequest = ((FWPS_BIND_REQUEST*)(pRedirectData->pWritableLayerData))->previousVersion; + + /// ReAuth for our proxying, so let it go, + /// and set the rights to write back as it was removed by acquiring the layer data + if(pBindRequest->modifierFilterId == pFilter->filterId) + { + pClassifyOut->actionType = FWP_ACTION_PERMIT; + pClassifyOut->rights |= FWPS_RIGHT_ACTION_WRITE; + + KrnlHlprRedirectDataDestroy(&pRedirectData); + + HLPR_BAIL; + } + } + else + { + FWPS_CONNECT_REQUEST* pConnectRequest = ((FWPS_CONNECT_REQUEST*)(pRedirectData->pWritableLayerData))->previousVersion; + + /// ReAuth for our proxying, so let it go, + /// and set the rights to write back as it was removed by acquiring the layer data + if(pConnectRequest->modifierFilterId == pFilter->filterId) + { + pClassifyOut->actionType = FWP_ACTION_PERMIT; + pClassifyOut->rights |= FWPS_RIGHT_ACTION_WRITE; + + KrnlHlprRedirectDataDestroy(&pRedirectData); + + HLPR_BAIL; + } + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + else + { + /// No more redirection if someone else has done it locally. We could catch the new + /// connection from their proxy if we really must act on it. + /// Set the rights to write back as it was removed when acquiring the layer data + if(pConnectRequest->localRedirectHandle) + { + pClassifyOut->actionType = FWP_ACTION_PERMIT; + pClassifyOut->rights |= FWPS_RIGHT_ACTION_WRITE; + + KrnlHlprRedirectDataDestroy(&pRedirectData); + + HLPR_BAIL; + } + } + +#endif /// (NTDDI_VERSION >= NTDDI_WIN8) + + } + } + + if(redirectSocket) + { + UINT32 timesRedirected = 0; + + for(FWPS_BIND_REQUEST* pBindRequest = ((FWPS_BIND_REQUEST*)(pRedirectData->pWritableLayerData))->previousVersion; + pBindRequest; + pBindRequest = pBindRequest->previousVersion) + { + if(pBindRequest->modifierFilterId == pFilter->filterId) + timesRedirected++; + + /// Don't redirect the same socket more than 3 times + if(timesRedirected > 3) + { + status = STATUS_TOO_MANY_COMMANDS; + + HLPR_BAIL; + } + } + } + else + { + UINT32 timesRedirected = 0; + + for(FWPS_CONNECT_REQUEST* pConnectRequest = ((FWPS_CONNECT_REQUEST*)(pRedirectData->pWritableLayerData))->previousVersion; + pConnectRequest; + pConnectRequest = pConnectRequest->previousVersion) + { + if(pConnectRequest->modifierFilterId == pFilter->filterId) + timesRedirected++; + + /// Don't redirect the same connection more than 3 times + if(timesRedirected > 3) + { + status = STATUS_TOO_MANY_COMMANDS; + + HLPR_BAIL; + } + } + } + + if(pRedirectData->pProxyData->performInline) + status = TriggerProxyByALERedirectInline(pClassifyValues, + pMetadata, + pLayerData, + pClassifyContext, + pFilter, + flowContext, + pClassifyOut, + &pRedirectData); + else + status = TriggerProxyByALERedirectOutOfBand(pClassifyValues, + pMetadata, + pLayerData, + pClassifyContext, + pFilter, + flowContext, + pClassifyOut, + pRedirectData); + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! ClassifyProxyByALERedirect() [status: %#x]\n", + status); + + if(pRedirectData) + KrnlHlprRedirectDataDestroy(&pRedirectData); + + pClassifyOut->actionType = FWP_ACTION_BLOCK; + pClassifyOut->rights |= FWPS_RIGHT_ACTION_WRITE; + } + } + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- ClassifyProxyByALERedirect() [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; +} + +/** + @classify_function="ClassifyProxyByInjection" + + Purpose: <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +VOID NTAPI ClassifyProxyByInjection(_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(pNetBufferList); + NT_ASSERT(pFilter); + NT_ASSERT(pClassifyOut); + NT_ASSERT(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6); + NT_ASSERT(pFilter->providerContext); + NT_ASSERT(pFilter->providerContext->type == FWPM_GENERAL_CONTEXT); + NT_ASSERT(pFilter->providerContext->dataBuffer); + NT_ASSERT(pFilter->providerContext->dataBuffer->data); + NT_ASSERT(pFilter->providerContext->dataBuffer->size == sizeof(PC_PROXY_DATA)); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> ClassifyProxyByInjection() [Layer: %s][FilterID: %#I64x][Rights: %#x]", + KrnlHlprFwpsLayerIDToString(pClassifyValues->layerId), + pFilter->filterId, + pClassifyOut->rights); + + if(pClassifyOut->rights & FWPS_RIGHT_ACTION_WRITE) + { + NTSTATUS status = STATUS_SUCCESS; + INJECTION_DATA* pInjectionData = 0; + + pClassifyOut->actionType = FWP_ACTION_CONTINUE; + + if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) + { + /// Validate this is the correct traffic + PC_PROXY_DATA* pProxyData = (PPC_PROXY_DATA)pFilter->providerContext->dataBuffer->data; + UINT32 ipHeaderSize = 0; + UINT8 version = IPV4; + IPPROTO protocol = IPPROTO_MAX; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_IP_HEADER_SIZE)) + ipHeaderSize = pMetadata->ipHeaderSize; + + /// 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*)pNetBufferList), + ipHeaderSize, + 0, + 0); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! ClassifyProxyByInjection: NdisRetreatNetBufferDataStart() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + version = KrnlHlprIPHeaderGetVersionField((NET_BUFFER_LIST*)pNetBufferList); + + protocol = KrnlHlprIPHeaderGetProtocolField((NET_BUFFER_LIST*)pNetBufferList, + version == IPV4 ? AF_INET : AF_INET6); + + /// ... and advance the offset back to the original position. + NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pNetBufferList), + ipHeaderSize, + FALSE, + 0); + + if(protocol == pProxyData->ipProtocol) + { + UINT16 destinationPort = KrnlHlprTransportHeaderGetDestinationPortField((NET_BUFFER_LIST*)pNetBufferList, + protocol); + UINT16 sourcePort = KrnlHlprTransportHeaderGetSourcePortField((NET_BUFFER_LIST*)pNetBufferList, + protocol); + + if(pProxyData->proxyLocalPort && + pProxyData->proxyLocalPort != destinationPort) + HLPR_BAIL; + + if(pProxyData->proxyRemotePort && + pProxyData->proxyRemotePort != sourcePort) + HLPR_BAIL; + } + else + HLPR_BAIL; + } + +#pragma warning(push) +#pragma warning(disable: 6014) /// pInjectionData will be freed in completionFn using ProxyInjectionCompletionDataDestroy + + 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) + { + PC_PROXY_DATA* pProxyData = (PPC_PROXY_DATA)pFilter->providerContext->dataBuffer->data; + + pClassifyOut->actionType = FWP_ACTION_BLOCK; + pClassifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; + + if(pProxyData->performInline) + status = TriggerProxyInjectionInline(pClassifyValues, + pMetadata, + pNetBufferList, + pClassifyContext, + pFilter, + flowContext, + pClassifyOut, + &pInjectionData, + pProxyData); + else + status = TriggerProxyInjectionOutOfBand(pClassifyValues, + pMetadata, + pNetBufferList, + pClassifyContext, + pFilter, + flowContext, + pClassifyOut, + pInjectionData, + pProxyData); + } + else + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " -- ClassifyProxyByInjection() Injection previously performed.\n"); + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! ClassifyProxyByInjection() [status: %#x]\n", + status); + + if(pInjectionData) + KrnlHlprInjectionDataDestroy(&pInjectionData); + } + } + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- ClassifyProxyByInjection() [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="ClassifyProxyByALE" + + Purpose: Stub function for downlevel OS's trying to use uplevel functionality. <br> + <br> + Notes: <br> + <br> + MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF551229.aspx <br> + HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF544890.aspx <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +VOID NTAPI ClassifyProxyByALERedirect(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _Inout_opt_ VOID* pLayerData, + _In_ const FWPS_FILTER* pFilter, + _In_ UINT64 flowContext, + _Inout_ FWPS_CLASSIFY_OUT* pClassifyOut) +{ + NT_ASSERT(pClassifyValues); + NT_ASSERT(pMetadata); + NT_ASSERT(pLayerData); + NT_ASSERT(pFilter); + NT_ASSERT(pClassifyOut); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> ClassifyProxyByALERedirect() [Layer: %s][FilterID: %#I64x][Rights: %#x]", + KrnlHlprFwpsLayerIDToString(pClassifyValues->layerId), + pFilter->filterId, + pClassifyOut->rights); + + UNREFERENCED_PARAMETER(pMetadata); + UNREFERENCED_PARAMETER(pLayerData); + UNREFERENCED_PARAMETER(pFilter); + UNREFERENCED_PARAMETER(flowContext); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! ClassifyProxyByALERedirect() : Method not supported prior to Windows 7 [status: %#x]\n", + (UINT32)STATUS_UNSUCCESSFUL); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- ClassifyProxyByALERedirect() [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; +}; + +/** + @classify_function="ClassifyProxyByInjection" + + Purpose: <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +VOID NTAPI ClassifyProxyByInjection(_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(pNetBufferList); + NT_ASSERT(pFilter); + NT_ASSERT(pClassifyOut); + NT_ASSERT(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || + pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || + pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6); + NT_ASSERT(pFilter->providerContext); + NT_ASSERT(pFilter->providerContext->type == FWPM_GENERAL_CONTEXT); + NT_ASSERT(pFilter->providerContext->dataBuffer); + NT_ASSERT(pFilter->providerContext->dataBuffer->data); + NT_ASSERT(pFilter->providerContext->dataBuffer->size == sizeof(PC_PROXY_DATA)); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> ClassifyProxyByInjection() [Layer: %s][FilterID: %#I64x][Rights: %#x]", + KrnlHlprFwpsLayerIDToString(pClassifyValues->layerId), + pFilter->filterId, + pClassifyOut->rights); + + if(pNetBufferList) + { + NTSTATUS status = STATUS_SUCCESS; + INJECTION_DATA* pInjectionData = 0; + + pClassifyOut->actionType = FWP_ACTION_CONTINUE; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pInjectionData will be freed in completionFn using ProxyInjectionCompletionDataDestroy + + 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) + { + PC_PROXY_DATA* pProxyData = (PPC_PROXY_DATA)pFilter->providerContext->dataBuffer->data; + + pClassifyOut->actionType = FWP_ACTION_BLOCK; + pClassifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; + + if(pProxyData->performInline) + status = TriggerProxyInjectionInline(pClassifyValues, + pMetadata, + pNetBufferList, + 0, + pFilter, + flowContext, + pClassifyOut, + &pInjectionData, + pProxyData); + else + status = TriggerProxyInjectionOutOfBand(pClassifyValues, + pMetadata, + pNetBufferList, + 0, + pFilter, + flowContext, + pClassifyOut, + pInjectionData, + pProxyData); + } + else + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " -- ClassifyProxyByInjection() Injection previously performed.\n"); + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! ClassifyProxyByInjection() [status: %#x]\n", + status); + + if(pInjectionData) + KrnlHlprInjectionDataDestroy(&pInjectionData); + } + } + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- ClassifyProxyByInjection() [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) |
