diff options
| author | J M Rossy <[email protected]> | 2015-07-29 15:40:09 -0700 |
|---|---|---|
| committer | J M Rossy <[email protected]> | 2015-07-29 16:34:40 -0700 |
| commit | 5d61a4a79a1e96dc5d9af1e5e712c84507307544 (patch) | |
| tree | 49ed270893578cd18758b74ffcca16dc7ab948d6 /network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp | |
| parent | 5d41613e26e147d2300c786bb2b34cb4b4067a25 (diff) | |
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
Diffstat (limited to 'network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp')
| -rw-r--r-- | network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp | 3899 |
1 files changed, 3899 insertions, 0 deletions
diff --git a/network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp b/network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp new file mode 100644 index 00000000..3a2a7785 --- /dev/null +++ b/network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp @@ -0,0 +1,3899 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2014 Microsoft Corporation. All Rights Reserved. +// +// Module Name: +// HelperFunctions_Headers.cpp +// +// Abstract: +// This module contains kernel helper functions that assist with IP and Transport header +// operations. +// +// Naming Convention: +// +// <Module><Object><Action><Modifier> +// +// i.e. +// +// KrnlHlprIPHeaderCalculateV4Checksum +// +// <Module> +// KrnlHlpr - Function is located in syslib\ and applies to kernel mode. +// <Object> +// { +// IPHeader - Function pertains to the network's IP_HEADER. +// ICMPv4Header - Function pertains to the transport's ICMPV4_HEADER. +// ICMPv6Header - Function pertains to the transport's ICMPV6_HEADER. +// TCPHeader - Function pertains to the transport's TCP_HEADER. +// UDPHeader - Function pertains to the transport's UDP_HEADER. +// } +// <Action> +// { +// Calculate - Function performs a computation on the header. +// Modify - Function changes the field to the provided value. +// } +// <Modifier> +// { +// Code - Function acts on the ICMP Code Field. +// Destination Address - Function acts on the IP Destination Address Field. +// Destination Port - Function acts on the TCP / UDP Destination Port Field. +// Source Address - Function acts on the IP Source Address Field. +// Source Port - Function acts on the TCP / UDP Source Port Field. +// Type - Function acts on the ICMP Type Field. +// V4Checksum - Function pertains to IPv4 packets and its Checksum Field. +// } +// +// Private Functions: +// +// Public Functions: +// KrnlHlprICMPv4HeaderModifyCode(), +// KrnlHlprICMPv4HeaderModifyType(), +// KrnlHlprICMPv6HeaderModifyCode(), +// KrnlHlprICMPv6HeaderModifyType(), +// KrnlHlprIPHeaderCalculateV4Checksum(), +// KrnlHlprIPHeaderDestroy(), +// KrnlHlprIPHeaderGet(), +// KrnlHlprIPHeaderGetProtocolField(), +// KrnlHlprIPHeaderModifyDestinationAddress(), +// KrnlHlprIPHeaderModifyLoopbackToLocal(), +// KrnlHlprIPHeaderModifySourceAddress(), +// KrnlHlprMACHeaderDestroy(), +// KrnlHlprMACHeaderGet(), +// KrnlHlprMACHeaderModifyDestinationAddress(), +// KrnlHlprMACHeaderModifySourceAddress(), +// KrnlHlprTCPHeaderModifyDestinationPort(), +// KrnlHlprTCPHeaderModifySourcePort(), +// KrnlHlprUDPHeaderModifyDestinationPort(), +// KrnlHlprUDPHeaderModifySourcePort(), +// +// Author: +// Dusty Harper (DHarper) +// +// Revision History: +// +// [ Month ][Day] [Year] - [Revision]-[ Comments ] +// May 01, 2010 - 1.0 - Creation +// December 13, 2013 - 1.1 - Enhance annotations, add +// KrnlHlprIPHeaderGetDestinationAddressField, +// KrnlHlprIPHeaderGetSourceAddressField, +// KrnlHlprIPHeaderGetVersionField, +// KrnlHlprTransportHeaderGetSourcePortField, +// KrnlHlprTransportHeaderGetDestinationPortField, add +// support for controlData, and fix various bugs. +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "HelperFunctions_Include.h" /// . +#include "HelperFunctions_Headers.tmh" /// $(OBJ_PATH)\$(O)\ + +/** + @private_kernel_helper_function="PrvKrnlHlprCopyBufferToMDL" + + Purpose: Copy a flat buffer into an MDL chain. <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +NTSTATUS PrvKrnlHlprCopyBufferToMDL(_In_reads_(bytesToCopy) const BYTE* pBuffer, + _In_ PMDL pMDL, + _In_ SIZE_T mdlOffset, + _In_ SIZE_T bytesToCopy, + _Out_ SIZE_T* pBytesCopied) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> PrvKrnlHlprCopyBufferToMDL()\n"); + +#endif /// DBG + + NTSTATUS status = STATUS_SUCCESS; + SIZE_T mdlByteCount = 0; + SIZE_T remainingBytesToCopy = bytesToCopy; + SIZE_T copySize = 0; + + *pBytesCopied = 0; + + if(MmGetMdlByteCount(pMDL) >= mdlOffset + bytesToCopy) + { + BYTE* pSystemAddress = 0; + + pSystemAddress = (BYTE*)MmGetSystemAddressForMdlSafe(pMDL, + LowPagePriority); + if(pSystemAddress) + { + RtlCopyMemory(pSystemAddress + mdlOffset, + pBuffer, + bytesToCopy); + + remainingBytesToCopy = 0; + + HLPR_BAIL; + } + } + + /// Skip over the offset in the MDL chain + for(mdlByteCount = MmGetMdlByteCount(pMDL); + pMDL && + mdlOffset >= mdlByteCount; + mdlByteCount = MmGetMdlByteCount(pMDL)) + { + mdlOffset -= mdlByteCount; + + pMDL = pMDL->Next; + } + + /// Copy data while there are MDLs to walk and data to copy + for(; + pMDL && + remainingBytesToCopy > 0; + pMDL = pMDL->Next) + { + BYTE* pSystemAddress = 0; + + mdlByteCount = MmGetMdlByteCount(pMDL); + if(mdlByteCount) + { + ASSERT(mdlOffset < mdlByteCount); + + mdlByteCount -= mdlOffset; + + copySize = min(remainingBytesToCopy, + mdlByteCount); + + pSystemAddress = (BYTE*)MmGetSystemAddressForMdlSafe(pMDL, + LowPagePriority); + if(pSystemAddress) + { + RtlCopyMemory(pSystemAddress + mdlOffset, + pBuffer, + copySize); + + pBuffer += copySize; + + remainingBytesToCopy -= copySize; + + mdlOffset = 0; + } + else + { + status = STATUS_INSUFFICIENT_RESOURCES; + + HLPR_BAIL; + } + } + } + + HLPR_BAIL_LABEL: + + *pBytesCopied = bytesToCopy - remainingBytesToCopy; + + ASSERT(*pBytesCopied <= bytesToCopy); + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- PrvKrnlHlprCopyBufferToMDL() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +#ifndef MAC_HEADER____ +#define MAC_HEADER____ + +/** + @kernel_helper_function="KrnlHlprMACHeaderDestroy" + + Purpose: Frees the allocated memory indicated in KrnlMACHeaderGet(). <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_At_(*ppMACHeader, _Pre_ _Notnull_) +_At_(*ppMACHeader, _Post_ _Null_) +_Success_(*ppMACHeader == 0) +inline VOID KrnlHlprMACHeaderDestroy(_Inout_ VOID** ppMACHeader) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprMACHeaderDestroy()\n"); + +#endif /// DBG + + NT_ASSERT(ppMACHeader); + + HLPR_DELETE_ARRAY(*ppMACHeader, + WFPSAMPLER_SYSLIB_TAG); + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprMACHeaderDestroy()\n"); + +#endif /// DBG + + return; +} + +/** + @kernel_helper_function="KrnlHlprMACHeaderGet" + + Purpose: Retrieve a pointer to the MAC Header from the NET_BUFFER_LIST. <br> + <br> + Notes: Assumes the NBL is at the start of the MAC Header. <br> + <br> + Function is overloaded. <br> + <br> + If needToFreeMemory is TRUE, caller should call KrnlHlprMACHeaderDestroy() when + finished with the header. <br> + <br> + MSDN_Ref: <br> +*/ +_When_(return != STATUS_SUCCESS, _At_(*ppMACHeader, _Post_ _Null_)) +_When_(return == STATUS_SUCCESS, _At_(*ppMACHeader, _Post_ _Notnull_)) +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS KrnlHlprMACHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList, + _Outptr_ VOID** ppMACHeader, + _Inout_ BOOLEAN* pNeedToFreeMemory, + _In_ UINT32 macHeaderSize) /* 0 */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprMACHeaderGet()\n"); + +#endif /// DBG + + NT_ASSERT(pNetBufferList); + NT_ASSERT(ppMACHeader); + NT_ASSERT(pNeedToFreeMemory); + + NTSTATUS status = STATUS_SUCCESS; + BYTE* pBuffer = 0; + NET_BUFFER* pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + UINT32 bytesNeeded = macHeaderSize ? macHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + PVOID pContiguousData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprMACHeaderDestroy if *pNeedToFreeMemory is TRUE + + HLPR_NEW_ARRAY(pBuffer, + BYTE, + bytesNeeded, + WFPSAMPLER_SYSLIB_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer, + status); + +#pragma warning(pop) + + *pNeedToFreeMemory = TRUE; + + pContiguousData = NdisGetDataBuffer(pNetBuffer, + bytesNeeded, + pBuffer, + 1, + 0); + if(!pContiguousData) + { + status = STATUS_UNSUCCESSFUL; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprMACHeaderGet : NdisGetDataBuffer() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + if(pBuffer != pContiguousData) + { + HLPR_DELETE_ARRAY(pBuffer, + WFPSAMPLER_SYSLIB_TAG); + + *pNeedToFreeMemory = FALSE; + } + + *ppMACHeader = pContiguousData; + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS && + *pNeedToFreeMemory && + pBuffer) + { + KrnlHlprMACHeaderDestroy((VOID**)&pBuffer); + + *pNeedToFreeMemory = FALSE; + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprMACHeaderGet() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprMACHeaderModifySourceAddress" + + Purpose: Set the Source Address field in the MAC Header to the provided value. <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the MAC + Header. <br> + <br> + Assumes the Header is and Ethernet Header. <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 KrnlHlprMACHeaderModifySourceAddress(_In_ const FWP_VALUE* pValue, + _Inout_ NET_BUFFER_LIST* pNetBufferList) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprMACHeaderModifySourceAddress()\n"); + +#endif /// DBG + + NT_ASSERT(pValue); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + VOID* pMACHeader = 0; + BOOLEAN needToFree = FALSE; + ETHERNET_II_HEADER* pEthernetHeader = 0; + + status = KrnlHlprMACHeaderGet(pNetBufferList, + &pMACHeader, + &needToFree); + HLPR_BAIL_ON_FAILURE(status); + + pEthernetHeader = (ETHERNET_II_HEADER*)pMACHeader; + + RtlCopyMemory(pEthernetHeader->pSourceAddress, + pValue->byteArray6->byteArray6, + ETHERNET_ADDRESS_SIZE); + + HLPR_BAIL_LABEL: + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = sizeof(ETHERNET_II_HEADER); + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pEthernetHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprMACHeaderDestroy(&pMACHeader); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprMACHeaderModifySourceAddress() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprMACHeaderModifyDestinationAddress" + + Purpose: Set the Destination Address field in the MAC Header to the provided value. <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the MAC + Header. <br> + <br> + Assumes the Header is and Ethernet Header. <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 KrnlHlprMACHeaderModifyDestinationAddress(_In_ const FWP_VALUE* pValue, + _Inout_ NET_BUFFER_LIST* pNetBufferList) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprMACHeaderModifyDestinationAddress()\n"); + +#endif /// DBG + + NT_ASSERT(pValue); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + VOID* pMACHeader = 0; + BOOLEAN needToFree = FALSE; + ETHERNET_II_HEADER* pEthernetHeader = 0; + + status = KrnlHlprMACHeaderGet(pNetBufferList, + &pMACHeader, + &needToFree); + HLPR_BAIL_ON_FAILURE(status); + + pEthernetHeader = (ETHERNET_II_HEADER*)pMACHeader; + + RtlCopyMemory(pEthernetHeader->pDestinationAddress, + pValue->byteArray6->byteArray6, + ETHERNET_ADDRESS_SIZE); + + HLPR_BAIL_LABEL: + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = sizeof(ETHERNET_II_HEADER); + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pEthernetHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprMACHeaderDestroy(&pMACHeader); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprMACHeaderModifyDestinationAddress() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +#endif /// MAC_HEADER____ + +#ifndef IP_HEADER____ +#define IP_HEADER____ + +/** + @kernel_helper_function="KrnlHlprIPHeaderDestroy" + + Purpose: Frees the allocated memory indicated in KrnlIPHeaderGet(). <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_At_(*ppIPHeader, _Pre_ _Notnull_) +_At_(*ppIPHeader, _Post_ _Null_) +_Success_(*ppIPHeader == 0) +inline VOID KrnlHlprIPHeaderDestroy(_Inout_ VOID** ppIPHeader) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprIPHeaderDestroy()\n"); + +#endif /// DBG + + NT_ASSERT(ppIPHeader); + + HLPR_DELETE_ARRAY(*ppIPHeader, + WFPSAMPLER_SYSLIB_TAG); + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprIPHeaderDestroy()\n"); + +#endif /// DBG + + return; +} + +/** + @kernel_helper_function="KrnlHlprIPHeaderGet" + + Purpose: Retrieve a pointer to the IP Header from the NET_BUFFER_LIST. <br> + <br> + Notes: Function is overloaded . <br> + <br> + If needToFreeMemory is TRUE, caller should call KrnlHlprIPHeaderDestroy() when + finished with the header. <br> + <br> + MSDN_Ref: <br> +*/ +_When_(return != STATUS_SUCCESS, _At_(*ppIPHeader, _Post_ _Null_)) +_When_(return == STATUS_SUCCESS, _At_(*ppIPHeader, _Post_ _Notnull_)) +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS KrnlHlprIPHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList, + _In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _Outptr_result_buffer_(*pIPHeaderSize) VOID** ppIPHeader, + _Inout_ BOOLEAN* pNeedToFreeMemory, + _Inout_opt_ FWP_DIRECTION* pDirection, /* 0 */ + _Inout_opt_ UINT32* pIPHeaderSize) /* 0 */ +{ + NT_ASSERT(pNetBufferList); + NT_ASSERT(pClassifyValues); + NT_ASSERT(pMetadata); + NT_ASSERT(ppIPHeader); + NT_ASSERT(pNeedToFreeMemory); + + NTSTATUS status = STATUS_SUCCESS; + UINT32 bytesRetreated = 0; + UINT32 bytesAdvanced = 0; + UINT32 ipHeaderSize = 0; + UINT32 transportHeaderSize = 0; + FWP_DIRECTION direction = FWP_DIRECTION_MAX; + BOOLEAN ipHeaderAvailable = TRUE; + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + UINT32 ethernetHeaderSize = 0; + + if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata, + FWPS_L2_METADATA_FIELD_ETHERNET_MAC_HEADER_SIZE)) + ethernetHeaderSize = pMetadata->ethernetMacHeaderSize; + +#endif /// (NTDDI_VERSION >= NTDDI_WIN8) + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_IP_HEADER_SIZE)) + ipHeaderSize = pMetadata->ipHeaderSize; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) + transportHeaderSize = pMetadata->transportHeaderSize; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_PACKET_DIRECTION)) + direction = pMetadata->packetDirection; + + switch(pClassifyValues->layerId) + { + case FWPS_LAYER_INBOUND_IPPACKET_V4: + case FWPS_LAYER_INBOUND_IPPACKET_V6: + { + direction = FWP_DIRECTION_INBOUND; + + bytesRetreated = ipHeaderSize; + + break; + } + case FWPS_LAYER_INBOUND_IPPACKET_V4_DISCARD: + case FWPS_LAYER_INBOUND_IPPACKET_V6_DISCARD: + { + direction = FWP_DIRECTION_INBOUND; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_DISCARD_REASON)) + { + if(pMetadata->discardMetadata.discardModule == FWPS_DISCARD_MODULE_GENERAL && + pMetadata->discardMetadata.discardReason == FWPS_DISCARD_FIREWALL_POLICY) + bytesRetreated = ipHeaderSize; + } + + break; + } + case FWPS_LAYER_OUTBOUND_IPPACKET_V4: + case FWPS_LAYER_OUTBOUND_IPPACKET_V4_DISCARD: + case FWPS_LAYER_OUTBOUND_IPPACKET_V6: + case FWPS_LAYER_OUTBOUND_IPPACKET_V6_DISCARD: + { + direction = FWP_DIRECTION_OUTBOUND; + + /// At the IP Header + + break; + } + case FWPS_LAYER_IPFORWARD_V4: + case FWPS_LAYER_IPFORWARD_V4_DISCARD: + case FWPS_LAYER_IPFORWARD_V6: + case FWPS_LAYER_IPFORWARD_V6_DISCARD: + { + /// At the IP Header + + break; + } + case FWPS_LAYER_INBOUND_TRANSPORT_V4: + case FWPS_LAYER_INBOUND_TRANSPORT_V4_DISCARD: + case FWPS_LAYER_INBOUND_TRANSPORT_V6: + case FWPS_LAYER_INBOUND_TRANSPORT_V6_DISCARD: + { + direction = FWP_DIRECTION_INBOUND; + + if(pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMP || + pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMPV6) + bytesRetreated = ipHeaderSize; + else + bytesRetreated = ipHeaderSize + transportHeaderSize; + + break; + } + case FWPS_LAYER_OUTBOUND_TRANSPORT_V4: + case FWPS_LAYER_OUTBOUND_TRANSPORT_V4_DISCARD: + case FWPS_LAYER_OUTBOUND_TRANSPORT_V6: + case FWPS_LAYER_OUTBOUND_TRANSPORT_V6_DISCARD: + { + direction = FWP_DIRECTION_OUTBOUND; + + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_STREAM_V4: + case FWPS_LAYER_STREAM_V4_DISCARD: + case FWPS_LAYER_STREAM_V6: + case FWPS_LAYER_STREAM_V6_DISCARD: + { + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_DATAGRAM_DATA_V4: + case FWPS_LAYER_DATAGRAM_DATA_V4_DISCARD: + case FWPS_LAYER_DATAGRAM_DATA_V6: + case FWPS_LAYER_DATAGRAM_DATA_V6_DISCARD: + { + direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].value.uint32; + + if(direction == FWP_DIRECTION_OUTBOUND) + bytesRetreated = ipHeaderSize; + else + { + if(pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMP || + pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMPV6) + bytesRetreated = ipHeaderSize; + else + bytesRetreated = ipHeaderSize + transportHeaderSize; + } + + break; + } + case FWPS_LAYER_INBOUND_ICMP_ERROR_V4: + case FWPS_LAYER_INBOUND_ICMP_ERROR_V4_DISCARD: + case FWPS_LAYER_INBOUND_ICMP_ERROR_V6: + case FWPS_LAYER_INBOUND_ICMP_ERROR_V6_DISCARD: + { + direction = FWP_DIRECTION_INBOUND; + + bytesRetreated = ipHeaderSize + transportHeaderSize; + + break; + } + case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4: + case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4_DISCARD: + case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6: + case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6_DISCARD: + { + direction = FWP_DIRECTION_OUTBOUND; + + bytesRetreated = ipHeaderSize; + + break; + } + case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V4: + case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V4_DISCARD: + case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V6: + case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V6_DISCARD: + { + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_AUTH_LISTEN_V4: + case FWPS_LAYER_ALE_AUTH_LISTEN_V4_DISCARD: + case FWPS_LAYER_ALE_AUTH_LISTEN_V6: + case FWPS_LAYER_ALE_AUTH_LISTEN_V6_DISCARD: + { + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4: + case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4_DISCARD: + case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6: + case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6_DISCARD: + { + if(direction == FWP_DIRECTION_OUTBOUND) + { + ipHeaderAvailable = FALSE; + } + else + { + if(pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMP || + pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMPV6) + bytesRetreated = ipHeaderSize; + else + bytesRetreated = ipHeaderSize + transportHeaderSize; + } + + break; + } + case FWPS_LAYER_ALE_AUTH_CONNECT_V4: + case FWPS_LAYER_ALE_AUTH_CONNECT_V4_DISCARD: + case FWPS_LAYER_ALE_AUTH_CONNECT_V6: + case FWPS_LAYER_ALE_AUTH_CONNECT_V6_DISCARD: + { + if(pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_TCP) + ipHeaderAvailable = FALSE; + else if(direction == FWP_DIRECTION_INBOUND) + ipHeaderAvailable = FALSE; + else + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4: + case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4_DISCARD: + case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6: + case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6_DISCARD: + { + direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.uint32; + + if(direction == FWP_DIRECTION_OUTBOUND) + bytesRetreated = ipHeaderSize; + else + { + if(pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMP || + pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL].value.uint8 == IPPROTO_ICMPV6) + bytesRetreated = ipHeaderSize; + else + bytesRetreated = ipHeaderSize + transportHeaderSize; + } + + break; + } + +#if(NTDDI_VERSION >= NTDDI_WIN7) + + case FWPS_LAYER_NAME_RESOLUTION_CACHE_V4: + case FWPS_LAYER_NAME_RESOLUTION_CACHE_V6: + { + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_RESOURCE_RELEASE_V4: + case FWPS_LAYER_ALE_RESOURCE_RELEASE_V6: + { + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V4: + case FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V6: + { + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_CONNECT_REDIRECT_V4: + case FWPS_LAYER_ALE_CONNECT_REDIRECT_V6: + { + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_BIND_REDIRECT_V4: + case FWPS_LAYER_ALE_BIND_REDIRECT_V6: + { + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_STREAM_PACKET_V4: + case FWPS_LAYER_STREAM_PACKET_V6: + { + direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V4_DIRECTION].value.uint32; + + if(direction == FWP_DIRECTION_OUTBOUND) + bytesRetreated = ipHeaderSize; + else + bytesRetreated = ipHeaderSize + transportHeaderSize; + + 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 && + etherType != 0x0800) + ipHeaderAvailable = FALSE; + + 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 || + etherType == 0x0800) + bytesAdvanced = ethernetHeaderSize; + else + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE: + case FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE: + { + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_INGRESS_VSWITCH_ETHERNET: + { + UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_INGRESS_VSWITCH_ETHERNET_ETHER_TYPE].value.uint16; + + if(etherType == 0x86DD || + etherType == 0x0800) + bytesAdvanced = ethernetHeaderSize; + else + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_EGRESS_VSWITCH_ETHERNET: + { + UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_EGRESS_VSWITCH_ETHERNET_ETHER_TYPE].value.uint16; + + if(etherType == 0x86DD || + etherType == 0x0800) + bytesAdvanced = ethernetHeaderSize; + else + ipHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_INGRESS_VSWITCH_TRANSPORT_V4: + case FWPS_LAYER_INGRESS_VSWITCH_TRANSPORT_V6: + { + /// At the IP Header + + break; + } + case FWPS_LAYER_EGRESS_VSWITCH_TRANSPORT_V4: + case FWPS_LAYER_EGRESS_VSWITCH_TRANSPORT_V6: + { + /// At the IP Header + + break; + } + +#endif /// (NTDDI_VERSION >= NTDDI_WIN8) +#endif /// (NTDDI_VERSION >= NTDDI_WIN7) + + } + + + if(ipHeaderAvailable) + { + BYTE* pBuffer = 0; + NET_BUFFER* pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + UINT32 bytesNeeded = ipHeaderSize ? ipHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + PVOID pContiguousData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprIPHeaderDestroy if *pNeedToFreeMemory is TRUE + + HLPR_NEW_ARRAY(pBuffer, + BYTE, + bytesNeeded, + WFPSAMPLER_SYSLIB_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer, + status); + +#pragma warning(pop) + + *pNeedToFreeMemory = TRUE; + + if(bytesAdvanced) + NdisAdvanceNetBufferDataStart(pNetBuffer, + bytesAdvanced, + 0, + 0); + else if(bytesRetreated) + { + status = NdisRetreatNetBufferDataStart(pNetBuffer, + bytesRetreated, + 0, + 0); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprIPHeaderGet : NdisRetreatNetBufferDataStart() [status: %#x]\n", + status); + + HLPR_BAIL; + } + } + + pContiguousData = NdisGetDataBuffer(pNetBuffer, + bytesNeeded, + pBuffer, + 1, + 0); + + /// Return to the original offset + if(bytesRetreated) + NdisAdvanceNetBufferDataStart(pNetBuffer, + bytesRetreated, + 0, + 0); + else if(bytesAdvanced) + { + status = NdisRetreatNetBufferDataStart(pNetBuffer, + bytesAdvanced, + 0, + 0); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprIPHeaderGet : NdisRetreatNetBufferDataStart() [status: %#x]\n", + status); + + HLPR_BAIL; + } + } + + if(!pContiguousData) + { + status = STATUS_UNSUCCESSFUL; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprIPHeaderGet : NdisGetDataBuffer() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + if(pBuffer != pContiguousData) + { + HLPR_DELETE_ARRAY(pBuffer, + WFPSAMPLER_SYSLIB_TAG); + + *pNeedToFreeMemory = FALSE; + } + + *ppIPHeader = pContiguousData; + + if(pDirection) + *pDirection = direction; + + if(pIPHeaderSize) + *pIPHeaderSize = ipHeaderSize; + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS && + *pNeedToFreeMemory && + pBuffer) + { + KrnlHlprIPHeaderDestroy((VOID**)&pBuffer); + + *pNeedToFreeMemory = FALSE; + } + } + else + status = STATUS_NO_MATCH; + + return status; +} + + +/** + @kernel_helper_function="KrnlHlprIPHeaderGet" + + Purpose: Retrieve a pointer to the IP Header from the NET_BUFFER_LIST. <br> + <br> + Notes: Assumes the NBL is at the start of the IP Header. <br> + <br> + Function is overloaded. <br> + <br> + If needToFreeMemory is TRUE, caller should call KrnlHlprIPHeaderDestroy() when + finished with the header. <br> + <br> + MSDN_Ref: <br> +*/ +_When_(return != STATUS_SUCCESS, _At_(*ppIPHeader, _Post_ _Null_)) +_When_(return == STATUS_SUCCESS, _At_(*ppIPHeader, _Post_ _Notnull_)) +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS KrnlHlprIPHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList, + _Outptr_result_buffer_(ipHeaderSize) VOID** ppIPHeader, + _Inout_ BOOLEAN* pNeedToFreeMemory, + _In_ UINT32 ipHeaderSize) /* 0 */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprIPHeaderGet()\n"); + +#endif /// DBG + + NT_ASSERT(pNetBufferList); + NT_ASSERT(ppIPHeader); + NT_ASSERT(pNeedToFreeMemory); + + NTSTATUS status = STATUS_SUCCESS; + BYTE* pBuffer = 0; + NET_BUFFER* pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + UINT32 bytesNeeded = ipHeaderSize ? ipHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + PVOID pContiguousData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprIPHeaderDestroy if *pNeedToFreeMemory is TRUE + + HLPR_NEW_ARRAY(pBuffer, + BYTE, + bytesNeeded, + WFPSAMPLER_SYSLIB_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer, + status); + +#pragma warning(pop) + + *pNeedToFreeMemory = TRUE; + + pContiguousData = NdisGetDataBuffer(pNetBuffer, + bytesNeeded, + pBuffer, + 1, + 0); + if(!pContiguousData) + { + status = STATUS_UNSUCCESSFUL; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprIPHeaderGet : NdisGetDataBuffer() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + if(pBuffer != pContiguousData) + { + HLPR_DELETE_ARRAY(pBuffer, + WFPSAMPLER_SYSLIB_TAG); + + *pNeedToFreeMemory = FALSE; + } + + *ppIPHeader = pContiguousData; + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS && + *pNeedToFreeMemory && + pBuffer) + { + KrnlHlprIPHeaderDestroy((VOID**)&pBuffer); + + *pNeedToFreeMemory = FALSE; + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprIPHeaderGet() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprIPHeaderGetDestinationAddressField" + + Purpose: Retrieve the source address from the IP header. <br> + <br> + Notes: Assumes the NBL is at the start of the IP Header. <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return != 0) +BYTE* KrnlHlprIPHeaderGetDestinationAddressField(_In_ NET_BUFFER_LIST* pNetBufferList, + _In_ ADDRESS_FAMILY addressFamily) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprIPHeaderGetDestinationAddressField()\n"); + +#endif /// DBG + + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + VOID* pIPHeader = 0; + BOOLEAN needToFree = FALSE; + BYTE* pDestinationAddress = 0; + + status = KrnlHlprIPHeaderGet(pNetBufferList, + &pIPHeader, + &needToFree); + HLPR_BAIL_ON_FAILURE(status); + + if(addressFamily == AF_INET6) + { + IP_HEADER_V6* pIPv6Header = (IP_HEADER_V6*)pIPHeader; + + pDestinationAddress = pIPv6Header->pDestinationAddress; + } + else + { + IP_HEADER_V4* pIPv4Header = (IP_HEADER_V4*)pIPHeader; + + pDestinationAddress = pIPv4Header->pDestinationAddress; + + } + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = (addressFamily == AF_INET) ? IPV4_HEADER_MIN_SIZE : IPV6_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pIPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprIPHeaderDestroy(&pIPHeader); + } + + HLPR_BAIL_LABEL: + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprIPHeaderGetDestinationAddressField()\n"); + +#endif /// DBG + + return pDestinationAddress; +} + +/** + @kernel_helper_function="KrnlHlprIPHeaderGetSourceAddressField" + + Purpose: Retrieve the source address from the IP header. <br> + <br> + Notes: Assumes the NBL is at the start of the IP Header. <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return != 0) +BYTE* KrnlHlprIPHeaderGetSourceAddressField(_In_ NET_BUFFER_LIST* pNetBufferList, + _In_ ADDRESS_FAMILY addressFamily) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprIPHeaderGetSourceAddressField()\n"); + +#endif /// DBG + + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + VOID* pIPHeader = 0; + BOOLEAN needToFree = FALSE; + BYTE* pSourceAddress = 0; + + status = KrnlHlprIPHeaderGet(pNetBufferList, + &pIPHeader, + &needToFree); + HLPR_BAIL_ON_FAILURE(status); + + if(addressFamily == AF_INET6) + { + IP_HEADER_V6* pIPv6Header = (IP_HEADER_V6*)pIPHeader; + + pSourceAddress = pIPv6Header->pSourceAddress; + } + else + { + IP_HEADER_V4* pIPv4Header = (IP_HEADER_V4*)pIPHeader; + + pSourceAddress = pIPv4Header->pSourceAddress; + + } + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = (addressFamily == AF_INET) ? IPV4_HEADER_MIN_SIZE : IPV6_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pIPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprIPHeaderDestroy(&pIPHeader); + } + + HLPR_BAIL_LABEL: + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprIPHeaderGetSourceAddressField()\n"); + +#endif /// DBG + + return pSourceAddress; +} + +/** + @kernel_helper_function="KrnlHlprIPHeaderGetProtocolField" + + Purpose: Retrieve the protocol from the IP header. <br> + <br> + Notes: Assumes the NBL is at the start of the IP Header. <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +IPPROTO KrnlHlprIPHeaderGetProtocolField(_In_ NET_BUFFER_LIST* pNetBufferList, + _In_ ADDRESS_FAMILY addressFamily) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprIPHeaderGetProtocolField()\n"); + +#endif /// DBG + + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + VOID* pIPHeader = 0; + BOOLEAN needToFree = FALSE; + IPPROTO protocol = IPPROTO_MAX; + + status = KrnlHlprIPHeaderGet(pNetBufferList, + &pIPHeader, + &needToFree); + HLPR_BAIL_ON_FAILURE(status); + + if(addressFamily == AF_INET6) + { + IP_HEADER_V6* pIPv6Header = (IP_HEADER_V6*)pIPHeader; + + protocol = (IPPROTO)pIPv6Header->nextHeader; + } + else + { + IP_HEADER_V4* pIPv4Header = (IP_HEADER_V4*)pIPHeader; + + protocol = (IPPROTO)pIPv4Header->protocol; + } + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = (addressFamily == AF_INET) ? IPV4_HEADER_MIN_SIZE : IPV6_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pIPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprIPHeaderDestroy(&pIPHeader); + } + + HLPR_BAIL_LABEL: + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprIPHeaderGetProtocolField()\n"); + +#endif /// DBG + + return protocol; +} + +/** + @kernel_helper_function="KrnlHlprIPHeaderGetVersionField" + + Purpose: Retrieve the version from the IP header. <br> + <br> + Notes: Assumes the NBL is at the start of the IP Header. <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +UINT8 KrnlHlprIPHeaderGetVersionField(_In_ NET_BUFFER_LIST* pNetBufferList) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprIPHeaderGetVersionField()\n"); + +#endif /// DBG + + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + BYTE* pIPHeader = 0; + BOOLEAN needToFree = FALSE; + UINT8 version = 0; + + status = KrnlHlprIPHeaderGet(pNetBufferList, + (VOID**)&pIPHeader, + &needToFree); + HLPR_BAIL_ON_FAILURE(status); + + version = pIPHeader[0] >> 4; + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = (version == IPV4) ? IPV4_HEADER_MIN_SIZE : IPV6_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL(pIPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprIPHeaderDestroy((VOID**)&pIPHeader); + } + + HLPR_BAIL_LABEL: + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprIPHeaderGetVersionField()\n"); + +#endif /// DBG + + return version; +} + +/** + @kernel_helper_function="KrnlHlprIPHeaderCalculateV4Checksum" + + Purpose: Calculate the Checksum for the IPv4 Header. <br> + <br> + Notes: Assumes the NBL is at the start of the IPv4 Header. <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +VOID KrnlHlprIPHeaderCalculateV4Checksum(_Inout_ NET_BUFFER_LIST* pNetBufferList, + _In_ UINT32 ipHeaderSize) /* IPV4_HEADER_MIN_SIZE */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprIPHeaderCalculateV4Checksum()\n"); + +#endif /// DBG + + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + IP_HEADER_V4* pIPv4Header = 0; + BOOLEAN needToFree = FALSE; + + status = KrnlHlprIPHeaderGet(pNetBufferList, + (VOID**)&pIPv4Header, + &needToFree, + ipHeaderSize); + if(status == STATUS_SUCCESS && + ipHeaderSize >= IPV4_HEADER_MIN_SIZE) + { + UINT32 sum = 0; + UINT32 words = ipHeaderSize / 2; + UINT16 UNALIGNED* pStart = (UINT16*)pIPv4Header; + + pIPv4Header->checksum = 0; + + for(UINT8 i = 0; + i < words; + i++) + { + sum += pStart[i]; + } + + sum = (sum & 0x0000ffff) + (sum >> 16); + sum += (sum >> 16); + + pIPv4Header->checksum = (UINT16)~sum; + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = ipHeaderSize ? ipHeaderSize : IPV4_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pIPv4Header, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprIPHeaderDestroy((VOID**)&pIPv4Header); + } + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprIPHeaderCalculateV4Checksum()\n"); + +#endif /// DBG + + return; +} + +/** + @kernel_helper_function="KrnlHlprIPHeaderModifySourceAddress" + + Purpose: Set the Source Address field in the IP Header to the provided value. <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the IP Header.<br> + <br> + Values should be in Network Byte Order. <br> + <br> + Function is IP version agnostic. <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 KrnlHlprIPHeaderModifySourceAddress(_In_ const FWP_VALUE* pValue, + _Inout_ NET_BUFFER_LIST* pNetBufferList, + _In_ BOOLEAN recalculateChecksum, /* TRUE */ + _In_ BOOLEAN convertByteOrder) /* FALSE */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprIPHeaderModifySourceAddress()\n"); + +#endif /// DBG + + NT_ASSERT(pValue); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + VOID* pIPHeader = 0; + BOOLEAN needToFree = FALSE; + + status = KrnlHlprIPHeaderGet(pNetBufferList, + &pIPHeader, + &needToFree); + HLPR_BAIL_ON_FAILURE(status); + + switch(pValue->type) + { + case FWP_UINT32: + { + IP_HEADER_V4* pIPv4Header = (IP_HEADER_V4*)pIPHeader; + UINT32 sourceAddress = convertByteOrder ? htonl(pValue->uint32) : pValue->uint32; + + RtlCopyMemory(pIPv4Header->pSourceAddress, + &sourceAddress, + IPV4_ADDRESS_SIZE); + + break; + } + case FWP_BYTE_ARRAY16_TYPE: + { + IP_HEADER_V6* pIPv6Header = (IP_HEADER_V6*)pIPHeader; + + RtlCopyMemory(pIPv6Header->pSourceAddress, + &(pValue->byteArray16->byteArray16), + IPV6_ADDRESS_SIZE); + + break; + } + } + + HLPR_BAIL_LABEL: + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = (pValue->type == FWP_UINT32) ? IPV4_HEADER_MIN_SIZE : IPV6_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pIPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprIPHeaderDestroy(&pIPHeader); + } + + if(recalculateChecksum && + pValue->type == FWP_UINT32) + KrnlHlprIPHeaderCalculateV4Checksum(pNetBufferList); + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprIPHeaderModifySourceAddress() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprIPHeaderModifyDestinationAddress" + + Purpose: Set the Destination Address field in the IP Header to the provided value. <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the IP Header.<br> + <br> + Values should be in Network Byte Order. <br> + <br> + Function is IP version agnostic. <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 KrnlHlprIPHeaderModifyDestinationAddress(_In_ const FWP_VALUE* pValue, + _Inout_ NET_BUFFER_LIST* pNetBufferList, + _In_ const BOOLEAN recalculateChecksum, /* TRUE */ + _In_ BOOLEAN convertByteOrder) /* FALSE */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprIPHeaderModifyDestinationAddress()\n"); + +#endif /// DBG + + NT_ASSERT(pValue); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + VOID* pIPHeader = 0; + BOOLEAN needToFree = FALSE; + + status = KrnlHlprIPHeaderGet(pNetBufferList, + &pIPHeader, + &needToFree); + HLPR_BAIL_ON_FAILURE(status); + + switch(pValue->type) + { + case FWP_UINT32: + { + IP_HEADER_V4* pIPv4Header = (IP_HEADER_V4*)pIPHeader; + UINT32 destinationAddress = convertByteOrder ? htonl(pValue->uint32) : pValue->uint32; + + RtlCopyMemory(pIPv4Header->pDestinationAddress, + &destinationAddress, + IPV4_ADDRESS_SIZE); + + break; + } + case FWP_BYTE_ARRAY16_TYPE: + { + IP_HEADER_V6* pIPv6Header = (IP_HEADER_V6*)pIPHeader; + + RtlCopyMemory(pIPv6Header->pDestinationAddress, + &(pValue->byteArray16->byteArray16), + IPV6_ADDRESS_SIZE); + + break; + } + } + + HLPR_BAIL_LABEL: + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = (pValue->type == FWP_UINT32) ? IPV4_HEADER_MIN_SIZE : IPV6_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pIPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprIPHeaderDestroy(&pIPHeader); + } + + if(recalculateChecksum && + pValue->type == FWP_UINT32) + KrnlHlprIPHeaderCalculateV4Checksum(pNetBufferList); + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprIPHeaderModifyDestinationAddress() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprIPHeaderModifyLoopbackToLocal" + + Purpose: Modifies the source address and destination address from software loopback to an + actual local IP address (i.e. 127.0.0.1 to 157.59.10.233). <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the IP Header.<br> + <br> + The source address is modified to pass TCP/IP's source IP address validation, and + the destination address is modified to pass TCP/IP's zone crossing restrictions. <br> + <br> + For some protocols, the need to capture and modify a response packet's addresses + back to the loopback addresses will exist (i.e. ICMP Echo Requests) <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 KrnlHlprIPHeaderModifyLoopbackToLocal(_In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _In_ const FWP_VALUE* pLoopbackAddress, + _In_ const UINT32 ipHeaderSize, + _Inout_ NET_BUFFER_LIST* pNetBufferList, + _In_reads_opt_(controlDataSize) const WSACMSGHDR* pControlData, /* 0 */ + _In_ UINT32 controlDataSize) /* 0 */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprIPHeaderModifyLoopbackToLocal()\n"); + +#endif /// DBG + + NT_ASSERT(pMetadata); + NT_ASSERT(pLoopbackAddress); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + ADDRESS_FAMILY addressFamily = pLoopbackAddress->type == FWP_BYTE_ARRAY16_TYPE ? AF_INET6 : AF_INET; + VOID* pIPHeader = 0; + BOOLEAN needToFreeMemory = FALSE; + UINT8* pLocalAddress = 0; + IPPROTO nextProtocol = IPPROTO_MAX; + + status = KrnlHlprIPHeaderGet(pNetBufferList, + &pIPHeader, + &needToFreeMemory, + ipHeaderSize); + HLPR_BAIL_ON_FAILURE(status); + + if(addressFamily == AF_INET) + { + IP_HEADER_V4* pIPv4Header = (IP_HEADER_V4*)pIPHeader; + + nextProtocol = (IPPROTO)pIPv4Header->protocol; + + /// Only modify if the addresses are different + if(RtlCompareMemory(pIPv4Header->pSourceAddress, + pIPv4Header->pDestinationAddress, + IPV4_ADDRESS_SIZE) != IPV4_ADDRESS_SIZE) + { + HLPR_NEW_ARRAY(pLocalAddress, + UINT8, + IPV4_ADDRESS_SIZE, + WFPSAMPLER_SYSLIB_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pLocalAddress, + status); + + if(RtlCompareMemory(pIPv4Header->pSourceAddress, + IPV4_LOOPBACK_ADDRESS, + IPV4_ADDRESS_SIZE) == IPV4_ADDRESS_SIZE) + RtlCopyMemory(pLocalAddress, + pIPv4Header->pDestinationAddress, + IPV4_ADDRESS_SIZE); + else + RtlCopyMemory(pLocalAddress, + pIPv4Header->pSourceAddress, + IPV4_ADDRESS_SIZE); + } + } + else + { + IP_HEADER_V6* pIPv6Header = (IP_HEADER_V6*)pIPHeader; + + nextProtocol = (IPPROTO)pIPv6Header->nextHeader; + + /// Only modify if the addresses are different + if(RtlCompareMemory(pIPv6Header->pSourceAddress, + pIPv6Header->pDestinationAddress, + IPV6_ADDRESS_SIZE) != IPV6_ADDRESS_SIZE) + { + HLPR_NEW_ARRAY(pLocalAddress, + UINT8, + IPV6_ADDRESS_SIZE, + WFPSAMPLER_SYSLIB_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pLocalAddress, + status); + + if(RtlCompareMemory(pIPv6Header->pSourceAddress, + IPV6_LOOPBACK_ADDRESS, + IPV6_ADDRESS_SIZE) == IPV6_ADDRESS_SIZE) + RtlCopyMemory(pLocalAddress, + pIPv6Header->pDestinationAddress, + IPV6_ADDRESS_SIZE); + else + RtlCopyMemory(pLocalAddress, + pIPv6Header->pSourceAddress, + IPV6_ADDRESS_SIZE); + } + } + + if(pLocalAddress) + { + UINT64 endpointHandle = 0; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE)) + endpointHandle = pMetadata->transportEndpointHandle; + + /// Rebuild the IP Header (recalculating the IP and transport checksums) + status = FwpsConstructIpHeaderForTransportPacket(pNetBufferList, + ipHeaderSize, + addressFamily, + pLocalAddress, + pLocalAddress, + nextProtocol, + endpointHandle, + pControlData, + controlDataSize, + 0, + 0, + 0, + 0); + if(status != STATUS_SUCCESS) + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprIPHeaderModifyLoopbackToLocal : FwpsConstructIpHeaderForTransportPacket() [status: %#x]\n", + status); + } + + HLPR_BAIL_LABEL: + + HLPR_DELETE_ARRAY(pLocalAddress, + WFPSAMPLER_SYSLIB_TAG); + + if(needToFreeMemory) + KrnlHlprIPHeaderDestroy(&pIPHeader); + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprIPHeaderModifyLoopbackToLocal() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +#endif /// IP_HEADER____ + +#ifndef TRANSPORT_HEADERS____ +#define TRANSPORT_HEADERS____ + +/** + @kernel_helper_function="KrnlHlprTransportHeaderDestroy" + + Purpose: Frees the allocated memory indicated in KrnlTransportHeaderGet(). <br> + <br> + Notes: For use with generic and specific transport header functions. <br> + <br> + MSDN_Ref: <br> +*/ +_At_(*ppTransportHeader, _Pre_ _Notnull_) +_At_(*ppTransportHeader, _Post_ _Null_) +_Success_(*ppTransportHeader == 0) +inline VOID KrnlHlprTransportHeaderDestroy(_Inout_ VOID** ppTransportHeader) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprTransportHeaderDestroy()\n"); + +#endif /// DBG + + NT_ASSERT(ppTransportHeader); + + HLPR_DELETE_ARRAY(*ppTransportHeader, + WFPSAMPLER_SYSLIB_TAG); + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprTransportHeaderDestroy()\n"); + +#endif /// DBG + + return; +} + +/** + @kernel_helper_function="KrnlHlprTransportHeaderGet" + + Purpose: Retrieve a pointer to the Transport Header from the NET_BUFFER_LIST. <br> + <br> + Notes: Function is overloaded. . <br> + <br> + If needToFreeMemory is TRUE, caller should call KrnlHlprTransportHeaderDestroy() + when finished with the header. <br> + <br> + MSDN_Ref: <br> +*/ +_When_(return != STATUS_SUCCESS, _At_(*ppTransportHeader, _Post_ _Null_)) +_When_(return == STATUS_SUCCESS, _At_(*ppTransportHeader, _Post_ _Notnull_)) +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS KrnlHlprTransportHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList, + _In_ const FWPS_INCOMING_VALUES* pClassifyValues, + _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, + _Outptr_result_buffer_(*pTransportHeaderSize) VOID** ppTransportHeader, + _Inout_ BOOLEAN* pNeedToFreeMemory, + _Inout_opt_ IPPROTO* pProtocol, /* 0 */ + _Inout_opt_ FWP_DIRECTION* pDirection, /* 0 */ + _Inout_opt_ UINT32* pTransportHeaderSize) /* 0 */ +{ + NT_ASSERT(pNetBufferList); + NT_ASSERT(pClassifyValues); + NT_ASSERT(pMetadata); + NT_ASSERT(ppTransportHeader); + NT_ASSERT(pNeedToFreeMemory); + + NTSTATUS status = STATUS_SUCCESS; + UINT32 bytesRetreated = 0; + UINT32 bytesAdvanced = 0; + UINT32 ipHeaderSize = 0; + UINT32 transportHeaderSize = 0; + FWP_DIRECTION direction = FWP_DIRECTION_MAX; + IPPROTO protocol = IPPROTO_MAX; + BOOLEAN transportHeaderAvailable = TRUE; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_IP_HEADER_SIZE)) + ipHeaderSize = pMetadata->ipHeaderSize; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) + transportHeaderSize = pMetadata->transportHeaderSize; + + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_PACKET_DIRECTION)) + direction = pMetadata->packetDirection; + + switch(pClassifyValues->layerId) + { + case FWPS_LAYER_INBOUND_IPPACKET_V4: + case FWPS_LAYER_INBOUND_IPPACKET_V6: + { + /// At the Transport Header + + break; + } + case FWPS_LAYER_INBOUND_IPPACKET_V4_DISCARD: + case FWPS_LAYER_INBOUND_IPPACKET_V6_DISCARD: + { + if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, + FWPS_METADATA_FIELD_DISCARD_REASON)) + { + if(pMetadata->discardMetadata.discardModule == FWPS_DISCARD_MODULE_GENERAL && + pMetadata->discardMetadata.discardReason == FWPS_DISCARD_FIREWALL_POLICY) + { + /// At the Transport Header + } + } + + break; + } + case FWPS_LAYER_OUTBOUND_IPPACKET_V4: + case FWPS_LAYER_OUTBOUND_IPPACKET_V4_DISCARD: + case FWPS_LAYER_OUTBOUND_IPPACKET_V6: + case FWPS_LAYER_OUTBOUND_IPPACKET_V6_DISCARD: + { + bytesAdvanced = ipHeaderSize; + + break; + } + case FWPS_LAYER_IPFORWARD_V4: + case FWPS_LAYER_IPFORWARD_V4_DISCARD: + case FWPS_LAYER_IPFORWARD_V6: + case FWPS_LAYER_IPFORWARD_V6_DISCARD: + { + bytesAdvanced = ipHeaderSize; + + break; + } + case FWPS_LAYER_INBOUND_TRANSPORT_V4: + case FWPS_LAYER_INBOUND_TRANSPORT_V4_DISCARD: + case FWPS_LAYER_INBOUND_TRANSPORT_V6: + case FWPS_LAYER_INBOUND_TRANSPORT_V6_DISCARD: + { + protocol = (IPPROTO)(pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8); + + if(protocol == IPPROTO_ICMP || + protocol == IPPROTO_ICMPV6) + { + /// At the Transport Header + } + else + bytesRetreated = transportHeaderSize; + + break; + } + case FWPS_LAYER_OUTBOUND_TRANSPORT_V4: + case FWPS_LAYER_OUTBOUND_TRANSPORT_V4_DISCARD: + case FWPS_LAYER_OUTBOUND_TRANSPORT_V6: + case FWPS_LAYER_OUTBOUND_TRANSPORT_V6_DISCARD: + { + protocol = (IPPROTO)(pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8); + + /// At the Transport Header + + break; + } + case FWPS_LAYER_STREAM_V4: + case FWPS_LAYER_STREAM_V4_DISCARD: + case FWPS_LAYER_STREAM_V6: + case FWPS_LAYER_STREAM_V6_DISCARD: + { + transportHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_DATAGRAM_DATA_V4: + case FWPS_LAYER_DATAGRAM_DATA_V4_DISCARD: + case FWPS_LAYER_DATAGRAM_DATA_V6: + case FWPS_LAYER_DATAGRAM_DATA_V6_DISCARD: + { + protocol = (IPPROTO)(pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_PROTOCOL].value.uint8); + + direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].value.uint32; + + if(direction == FWP_DIRECTION_OUTBOUND) + { + /// At the Transport Header + } + else + { + if(protocol == IPPROTO_ICMP || + protocol == IPPROTO_ICMPV6) + { + /// At the Transport Header + } + else + bytesRetreated = transportHeaderSize; + } + + break; + } + case FWPS_LAYER_INBOUND_ICMP_ERROR_V4: + case FWPS_LAYER_INBOUND_ICMP_ERROR_V4_DISCARD: + case FWPS_LAYER_INBOUND_ICMP_ERROR_V6: + case FWPS_LAYER_INBOUND_ICMP_ERROR_V6_DISCARD: + { + direction = FWP_DIRECTION_INBOUND; + + bytesRetreated = transportHeaderSize; + + break; + } + case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4: + case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4_DISCARD: + case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6: + case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6_DISCARD: + { + direction = FWP_DIRECTION_OUTBOUND; + + /// At the Transport Header + + break; + } + case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V4: + case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V4_DISCARD: + case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V6: + case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V6_DISCARD: + { + transportHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_AUTH_LISTEN_V4: + case FWPS_LAYER_ALE_AUTH_LISTEN_V4_DISCARD: + case FWPS_LAYER_ALE_AUTH_LISTEN_V6: + case FWPS_LAYER_ALE_AUTH_LISTEN_V6_DISCARD: + { + transportHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4: + case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4_DISCARD: + case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6: + case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6_DISCARD: + { + protocol = (IPPROTO)(pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8); + + if(direction == FWP_DIRECTION_OUTBOUND) + { + /// At the Transport Header + } + else + { + if(protocol == IPPROTO_ICMP || + protocol == IPPROTO_ICMPV6) + { + /// At the Transport Header + } + else + bytesRetreated = transportHeaderSize; + } + + break; + } + case FWPS_LAYER_ALE_AUTH_CONNECT_V4: + case FWPS_LAYER_ALE_AUTH_CONNECT_V4_DISCARD: + case FWPS_LAYER_ALE_AUTH_CONNECT_V6: + case FWPS_LAYER_ALE_AUTH_CONNECT_V6_DISCARD: + { + protocol = (IPPROTO)(pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8); + + if(protocol == IPPROTO_TCP) + transportHeaderAvailable = FALSE; + if(direction == FWP_DIRECTION_INBOUND) + { + /// At the Transport Header + } + else + { + /// At the Transport Header + } + + break; + } + case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4: + case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4_DISCARD: + case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6: + case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6_DISCARD: + { + direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.uint32; + + protocol = (IPPROTO)(pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8); + + if(direction == FWP_DIRECTION_OUTBOUND) + { + /// At the Transport Header + } + else + { + if(protocol == IPPROTO_ICMP || + protocol == IPPROTO_ICMPV6) + { + /// At the Transport Header + } + else + bytesRetreated = transportHeaderSize; + } + + break; + } + +#if(NTDDI_VERSION >= NTDDI_WIN7) + + case FWPS_LAYER_NAME_RESOLUTION_CACHE_V4: + case FWPS_LAYER_NAME_RESOLUTION_CACHE_V6: + { + transportHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_RESOURCE_RELEASE_V4: + case FWPS_LAYER_ALE_RESOURCE_RELEASE_V6: + { + transportHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V4: + case FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V6: + { + transportHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_CONNECT_REDIRECT_V4: + case FWPS_LAYER_ALE_CONNECT_REDIRECT_V6: + { + transportHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_ALE_BIND_REDIRECT_V4: + case FWPS_LAYER_ALE_BIND_REDIRECT_V6: + { + transportHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_STREAM_PACKET_V4: + case FWPS_LAYER_STREAM_PACKET_V6: + { + direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V4_DIRECTION].value.uint32; + + protocol = IPPROTO_TCP; + + if(direction == FWP_DIRECTION_OUTBOUND) + { + /// At the Transport Header + } + else + bytesRetreated = transportHeaderSize; + + break; + } + +#if(NTDDI_VERSION >= NTDDI_WIN8) + + case FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET: + case FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET: + case FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE: + case FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE: + case FWPS_LAYER_INGRESS_VSWITCH_ETHERNET: + case FWPS_LAYER_EGRESS_VSWITCH_ETHERNET: + { + transportHeaderAvailable = FALSE; + + break; + } + case FWPS_LAYER_INGRESS_VSWITCH_TRANSPORT_V4: + case FWPS_LAYER_INGRESS_VSWITCH_TRANSPORT_V6: + { + bytesAdvanced = ipHeaderSize; + + break; + } + case FWPS_LAYER_EGRESS_VSWITCH_TRANSPORT_V4: + case FWPS_LAYER_EGRESS_VSWITCH_TRANSPORT_V6: + { + bytesAdvanced = ipHeaderSize; + + break; + } + +#endif /// (NTDDI_VERSION >= NTDDI_WIN8) +#endif /// (NTDDI_VERSION >= NTDDI_WIN7) + + } + + if(transportHeaderAvailable) + { + BYTE* pBuffer = 0; + NET_BUFFER* pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + UINT32 bytesNeeded = transportHeaderSize ? transportHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + PVOID pContiguousData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprTransportHeaderDestroy if *pNeedToFreeMemory is TRUE + + HLPR_NEW_ARRAY(pBuffer, + BYTE, + bytesNeeded, + WFPSAMPLER_SYSLIB_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer, + status); + +#pragma warning(pop) + + *pNeedToFreeMemory = TRUE; + + if(bytesAdvanced) + NdisAdvanceNetBufferDataStart(pNetBuffer, + bytesAdvanced, + 0, + 0); + else if(bytesRetreated) + { + status = NdisRetreatNetBufferDataStart(pNetBuffer, + bytesRetreated, + 0, + 0); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlpTransportHeaderGet : NdisRetreatNetBufferDataStart() [status: %#x]\n", + status); + + HLPR_BAIL; + } + } + + pContiguousData = NdisGetDataBuffer(pNetBuffer, + bytesNeeded, + pBuffer, + 1, + 0); + + /// Return to the original offset + if(bytesRetreated) + NdisAdvanceNetBufferDataStart(pNetBuffer, + bytesRetreated, + 0, + 0); + else if(bytesAdvanced) + { + status = NdisRetreatNetBufferDataStart(pNetBuffer, + bytesAdvanced, + 0, + 0); + if(status != STATUS_SUCCESS) + { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprTransportHeaderGet : NdisRetreatNetBufferDataStart() [status: %#x]\n", + status); + + HLPR_BAIL; + } + } + + if(!pContiguousData) + { + status = STATUS_UNSUCCESSFUL; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprTransportHeaderGet : NdisGetDataBuffer() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + if(pBuffer != pContiguousData) + { + HLPR_DELETE_ARRAY(pBuffer, + WFPSAMPLER_SYSLIB_TAG); + + *pNeedToFreeMemory = FALSE; + } + + *ppTransportHeader = pContiguousData; + + if(pProtocol) + *pProtocol = protocol; + + if(pDirection) + *pDirection = direction; + + if(pTransportHeaderSize) + *pTransportHeaderSize = transportHeaderSize; + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS && + *pNeedToFreeMemory && + pBuffer) + { + KrnlHlprTransportHeaderDestroy((VOID**)&pBuffer); + + *pNeedToFreeMemory = FALSE; + } + } + else + status = STATUS_NO_MATCH; + + return status; +} + + +/** + @kernel_helper_function="KrnlHlprTransportHeaderGet" + + Purpose: Retrieve a pointer to the Transport Header from the NET_BUFFER_LIST. <br> + <br> + Notes: Assumes the NBL is at the start of the Transport Header. <br> + <br> + Function is overloaded. <br> + <br> + If needToFreeMemory is TRUE, caller should call KrnlHlprTransportHeaderDestroy() + when finished with the header. <br> + <br> + MSDN_Ref: <br> +*/ +_When_(return != STATUS_SUCCESS, _At_(*ppTransportHeader, _Post_ _Null_)) +_When_(return == STATUS_SUCCESS, _At_(*ppTransportHeader, _Post_ _Notnull_)) +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS KrnlHlprTransportHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList, + _Outptr_result_buffer_(transportHeaderSize) VOID** ppTransportHeader, + _Inout_ BOOLEAN* pNeedToFreeMemory, + _In_ UINT32 transportHeaderSize) /* 0 */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprTransportHeaderGet()\n"); + +#endif /// DBG + + NT_ASSERT(pNetBufferList); + NT_ASSERT(ppTransportHeader); + NT_ASSERT(pNeedToFreeMemory); + + NTSTATUS status = STATUS_SUCCESS; + BYTE* pBuffer = 0; + NET_BUFFER* pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + const UINT32 BUFFER_SIZE = transportHeaderSize ? transportHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + UINT32 bytesNeeded = transportHeaderSize ? transportHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + PVOID pContiguousData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprTransportHeaderDestroy if *pNeedToFreeMemory is TRUE + + HLPR_NEW_ARRAY(pBuffer, + BYTE, + BUFFER_SIZE, + WFPSAMPLER_SYSLIB_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer, + status); + +#pragma warning(pop) + + *pNeedToFreeMemory = TRUE; + + pContiguousData = NdisGetDataBuffer(pNetBuffer, + bytesNeeded, + pBuffer, + 1, + 0); + if(!pContiguousData) + { + status = STATUS_UNSUCCESSFUL; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprTransportHeaderGet : NdisGetDataBuffer() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + if(pBuffer != pContiguousData) + { + HLPR_DELETE_ARRAY(pBuffer, + WFPSAMPLER_SYSLIB_TAG); + + *pNeedToFreeMemory = FALSE; + } + + *ppTransportHeader = pContiguousData; + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS && + *pNeedToFreeMemory && + pBuffer) + { + KrnlHlprTransportHeaderDestroy((VOID**)&pBuffer); + + *pNeedToFreeMemory = FALSE; + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprTransportHeaderGet() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprTransportHeaderGetSourcePortField" + + Purpose: Retrieve the source port from the Transport header. <br> + <br> + Notes: Assumes the NBL is at the start of the Transport Header. <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +UINT16 KrnlHlprTransportHeaderGetSourcePortField(_In_ NET_BUFFER_LIST* pNetBufferList, + _In_ IPPROTO protocol) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprTransportHeaderGetSourcePortField()\n"); + +#endif /// DBG + + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + BYTE* pTransportHeader = 0; + BOOLEAN needToFree = FALSE; + UINT16 port = 0; + + status = KrnlHlprTransportHeaderGet(pNetBufferList, + (VOID**)&pTransportHeader, + &needToFree); + HLPR_BAIL_ON_FAILURE(status); + + switch(protocol) + { + case TCP: + { + TCP_HEADER* pTCPHeader = (TCP_HEADER*)pTransportHeader; + + port = pTCPHeader->sourcePort; + + break; + } + case UDP: + { + UDP_HEADER* pUDPHeader = (UDP_HEADER*)pTransportHeader; + + port = pUDPHeader->sourcePort; + + break; + } + } + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = 0; + SIZE_T bytesCopied = 0; + + switch(protocol) + { + case TCP: + { + headerSize = TCP_HEADER_MIN_SIZE; + + break; + } + case UDP: + { + headerSize = UDP_HEADER_MIN_SIZE; + + break; + } + } + + status = PrvKrnlHlprCopyBufferToMDL(pTransportHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprTransportHeaderDestroy((VOID**)&pTransportHeader); + } + + HLPR_BAIL_LABEL: + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprTransportHeaderGetSourcePortField()\n"); + +#endif /// DBG + + return port; +} + +/** + @kernel_helper_function="KrnlHlprTransportHeaderGetDestinationPortField" + + Purpose: Retrieve the destination port from the Transport header. <br> + <br> + Notes: Assumes the NBL is at the start of the Transport Header. <br> + <br> + MSDN_Ref: <br> +*/ +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +UINT16 KrnlHlprTransportHeaderGetDestinationPortField(_In_ NET_BUFFER_LIST* pNetBufferList, + _In_ IPPROTO protocol) +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprTransportHeaderGetDestinationPortField()\n"); + +#endif /// DBG + + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + BYTE* pTransportHeader = 0; + BOOLEAN needToFree = FALSE; + UINT16 port = 0; + + status = KrnlHlprTransportHeaderGet(pNetBufferList, + (VOID**)&pTransportHeader, + &needToFree); + HLPR_BAIL_ON_FAILURE(status); + + switch(protocol) + { + case TCP: + { + TCP_HEADER* pTCPHeader = (TCP_HEADER*)pTransportHeader; + + port = pTCPHeader->destinationPort; + + break; + } + case UDP: + { + UDP_HEADER* pUDPHeader = (UDP_HEADER*)pTransportHeader; + + port = pUDPHeader->destinationPort; + + break; + } + } + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = 0; + SIZE_T bytesCopied = 0; + + switch(protocol) + { + case TCP: + { + headerSize = TCP_HEADER_MIN_SIZE; + + break; + } + case UDP: + { + headerSize = UDP_HEADER_MIN_SIZE; + + break; + } + } + + status = PrvKrnlHlprCopyBufferToMDL(pTransportHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprTransportHeaderDestroy((VOID**)&pTransportHeader); + } + + HLPR_BAIL_LABEL: + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprTransportHeaderGetDestinationPortField()\n"); + +#endif /// DBG + + return port; +} + +#endif /// TRANSPORT_HEADERS____ + +#ifndef ICMPV4_HEADER____ +#define ICMPV4_HEADER____ + +/** + @kernel_helper_function="KrnlHlprICMPv4HeaderGet" + + Purpose: Retrieve a pointer to the ICMPv4 Header from the NET_BUFFER_LIST. <br> + <br> + Notes: Assumes the NBL is at the start of the ICMPv4 Header. <br> + <br> + MSDN_Ref: <br> +*/ +_When_(return != STATUS_SUCCESS, _At_(*ppICMPv4Header, _Post_ _Null_)) +_When_(return == STATUS_SUCCESS, _At_(*ppICMPv4Header, _Post_ _Notnull_)) +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS KrnlHlprICMPv4HeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList, + _Outptr_result_buffer_(icmpHeaderSize) VOID** ppICMPv4Header, + _Inout_ BOOLEAN* pNeedToFreeMemory, + _In_ UINT32 icmpHeaderSize) /* 0 */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprICMPv4HeaderGet()\n"); + +#endif /// DBG + + NTSTATUS status = STATUS_SUCCESS; + BYTE* pBuffer = 0; + NET_BUFFER* pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + const UINT32 BUFFER_SIZE = icmpHeaderSize ? icmpHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + UINT32 bytesNeeded = icmpHeaderSize ? icmpHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + PVOID pContiguousData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprTransportHeaderDestroy if *pNeedToFreeMemory is TRUE + + HLPR_NEW_ARRAY(pBuffer, + BYTE, + BUFFER_SIZE, + WFPSAMPLER_SYSLIB_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer, + status); + +#pragma warning(pop) + + *pNeedToFreeMemory = TRUE; + + pContiguousData = NdisGetDataBuffer(pNetBuffer, + bytesNeeded, + pBuffer, + 1, + 0); + if(!pContiguousData) + { + status = STATUS_UNSUCCESSFUL; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprICMPv4HeaderGet : NdisGetDataBuffer() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + if(pBuffer != pContiguousData) + { + HLPR_DELETE_ARRAY(pBuffer, + WFPSAMPLER_SYSLIB_TAG); + + *pNeedToFreeMemory = FALSE; + } + + *ppICMPv4Header = pContiguousData; + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS && + *pNeedToFreeMemory && + pBuffer) + { + KrnlHlprTransportHeaderDestroy((VOID**)&pBuffer); + + *pNeedToFreeMemory = FALSE; + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprICMPv4HeaderGet() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprICMPv4HeaderModifyType" + + Purpose: Set the ICMP Type field in the ICMPv4 Header to the provided value. <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the ICMPv4 + Header. <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 KrnlHlprICMPv4HeaderModifyType(_In_ const FWP_VALUE* pValue, + _Inout_ NET_BUFFER_LIST* pNetBufferList, + _In_ UINT32 icmpHeaderSize) /* 0 */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprICMPv4HeaderModifyType()\n"); + +#endif /// DBG + + NT_ASSERT(pValue); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + ICMP_HEADER_V4* pICMPHeader = 0; + BOOLEAN needToFree = FALSE; + + status = KrnlHlprICMPv4HeaderGet(pNetBufferList, + (VOID**)&pICMPHeader, + &needToFree, + icmpHeaderSize); + HLPR_BAIL_ON_FAILURE(status); + + pICMPHeader->type = pValue->uint8; + + HLPR_BAIL_LABEL: + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = icmpHeaderSize ? icmpHeaderSize : ICMP_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pICMPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprTransportHeaderDestroy((VOID**)&pICMPHeader); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprICMPv4HeaderModifyType() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprICMPv4HeaderModifyCode" + + Purpose: Set the ICMP Code field in the ICMPv4 Header to the provided value. <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the ICMPv4 + Header. <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 KrnlHlprICMPv4HeaderModifyCode(_In_ const FWP_VALUE* pValue, + _Inout_ NET_BUFFER_LIST* pNetBufferList, + _In_ UINT32 icmpHeaderSize) /* 0 */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprICMPv4HeaderModifyCode()\n"); + +#endif /// DBG + + NT_ASSERT(pValue); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + ICMP_HEADER_V4* pICMPHeader = 0; + BOOLEAN needToFree = FALSE; + + status = KrnlHlprICMPv4HeaderGet(pNetBufferList, + (VOID**)&pICMPHeader, + &needToFree, + icmpHeaderSize); + HLPR_BAIL_ON_FAILURE(status); + + pICMPHeader->code = pValue->uint8; + + HLPR_BAIL_LABEL: + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = icmpHeaderSize ? icmpHeaderSize : ICMP_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pICMPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprTransportHeaderDestroy((VOID**)&pICMPHeader); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprICMPv4HeaderModifyCode() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +#endif /// ICMPV4_HEADER____ + +#ifndef ICMPV6_HEADER____ +#define ICMPV6_HEADER____ + +/** + @kernel_helper_function="KrnlHlprICMPv6HeaderGet" + + Purpose: Retrieve a pointer to the ICMPv6 Header from the NET_BUFFER_LIST. <br> + <br> + Notes: Assumes the NBL is at the start of the ICMPv6 Header. <br> + <br> + MSDN_Ref: <br> +*/ +_When_(return != STATUS_SUCCESS, _At_(*ppICMPv6Header, _Post_ _Null_)) +_When_(return == STATUS_SUCCESS, _At_(*ppICMPv6Header, _Post_ _Notnull_)) +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS KrnlHlprICMPv6HeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList, + _Outptr_result_buffer_(icmpHeaderSize) VOID** ppICMPv6Header, + _Inout_ BOOLEAN* pNeedToFreeMemory, + _In_ UINT32 icmpHeaderSize) /* 0 */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprICMPv6HeaderGet()\n"); + +#endif /// DBG + + NTSTATUS status = STATUS_SUCCESS; + BYTE* pBuffer = 0; + NET_BUFFER* pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + const UINT32 BUFFER_SIZE = icmpHeaderSize ? icmpHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + UINT32 bytesNeeded = icmpHeaderSize ? icmpHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + PVOID pContiguousData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprTransportHeaderDestroy if *pNeedToFreeMemory is TRUE + + HLPR_NEW_ARRAY(pBuffer, + BYTE, + BUFFER_SIZE, + WFPSAMPLER_SYSLIB_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer, + status); + +#pragma warning(pop) + + *pNeedToFreeMemory = TRUE; + + pContiguousData = NdisGetDataBuffer(pNetBuffer, + bytesNeeded, + pBuffer, + 1, + 0); + if(!pContiguousData) + { + status = STATUS_UNSUCCESSFUL; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprICMPv6HeaderGet : NdisGetDataBuffer() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + if(pBuffer != pContiguousData) + { + HLPR_DELETE_ARRAY(pBuffer, + WFPSAMPLER_SYSLIB_TAG); + + *pNeedToFreeMemory = FALSE; + } + + *ppICMPv6Header = pContiguousData; + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS && + *pNeedToFreeMemory && + pBuffer) + { + KrnlHlprTransportHeaderDestroy((VOID**)&pBuffer); + + *pNeedToFreeMemory = FALSE; + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprICMPv4HeaderGet() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprICMPv6HeaderModifyType" + + Purpose: Set the ICMP Type field in the ICMPv6 Header to the provided value. <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the ICMPv6 + Header. <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 KrnlHlprICMPv6HeaderModifyType(_In_ const FWP_VALUE* pValue, + _Inout_ NET_BUFFER_LIST* pNetBufferList, + _In_ UINT32 icmpHeaderSize) /* 0 */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprICMPv6HeaderModifyType()\n"); + +#endif /// DBG + + NT_ASSERT(pValue); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + ICMP_HEADER_V6* pICMPHeader = 0; + BOOLEAN needToFree = FALSE; + + status = KrnlHlprICMPv4HeaderGet(pNetBufferList, + (VOID**)&pICMPHeader, + &needToFree, + icmpHeaderSize); + HLPR_BAIL_ON_FAILURE(status); + + pICMPHeader->type = pValue->uint8; + + HLPR_BAIL_LABEL: + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = icmpHeaderSize ? icmpHeaderSize : ICMP_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pICMPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprTransportHeaderDestroy((VOID**)&pICMPHeader); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprICMPv6HeaderModifyType() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprICMPv6HeaderModifyCode" + + Purpose: Set the ICMP Code field in the ICMPv6 Header to the provided value. <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the ICMPv6 + Header. <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 KrnlHlprICMPv6HeaderModifyCode(_In_ const FWP_VALUE* pValue, + _Inout_ NET_BUFFER_LIST* pNetBufferList, + _In_ UINT32 icmpHeaderSize) /* 0 */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprICMPv6HeaderModifyCode()\n"); + +#endif /// DBG + + NT_ASSERT(pValue); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + ICMP_HEADER_V6* pICMPHeader = 0; + BOOLEAN needToFree = FALSE; + + status = KrnlHlprICMPv4HeaderGet(pNetBufferList, + (VOID**)&pICMPHeader, + &needToFree, + icmpHeaderSize); + HLPR_BAIL_ON_FAILURE(status); + + pICMPHeader->code = pValue->uint8; + + HLPR_BAIL_LABEL: + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = icmpHeaderSize ? icmpHeaderSize : ICMP_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pICMPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprTransportHeaderDestroy((VOID**)&pICMPHeader); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprICMPv6HeaderModifyCode() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +#endif /// ICMPV6_HEADER____ + +#ifndef TCP_HEADER____ +#define TCP_HEADER____ + +/** + @kernel_helper_function="KrnlHlprTCPHeaderGet" + + Purpose: Retrieve a pointer to the TCP Header from the NET_BUFFER_LIST. <br> + <br> + Notes: Assumes the NBL is at the start of the TCP Header. <br> + <br> + MSDN_Ref: <br> +*/ +_When_(return != STATUS_SUCCESS, _At_(*ppTCPHeader, _Post_ _Null_)) +_When_(return == STATUS_SUCCESS, _At_(*ppTCPHeader, _Post_ _Notnull_)) +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS KrnlHlprTCPHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList, + _Outptr_result_buffer_(tcpHeaderSize) VOID** ppTCPHeader, + _Inout_ BOOLEAN* pNeedToFreeMemory, + _In_ UINT32 tcpHeaderSize) /* 0 */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprTCPHeaderGet()\n"); + +#endif /// DBG + + NTSTATUS status = STATUS_SUCCESS; + BYTE* pBuffer = 0; + NET_BUFFER* pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + const UINT32 BUFFER_SIZE = tcpHeaderSize ? tcpHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + UINT32 bytesNeeded = tcpHeaderSize ? tcpHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + PVOID pContiguousData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprTransportHeaderDestroy if *pNeedToFreeMemory is TRUE + + HLPR_NEW_ARRAY(pBuffer, + BYTE, + BUFFER_SIZE, + WFPSAMPLER_SYSLIB_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer, + status); + +#pragma warning(pop) + + *pNeedToFreeMemory = TRUE; + + pContiguousData = NdisGetDataBuffer(pNetBuffer, + bytesNeeded, + pBuffer, + 1, + 0); + if(!pContiguousData) + { + status = STATUS_UNSUCCESSFUL; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprTCPHeaderGet : NdisGetDataBuffer() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + if(pBuffer != pContiguousData) + { + HLPR_DELETE_ARRAY(pBuffer, + WFPSAMPLER_SYSLIB_TAG); + + *pNeedToFreeMemory = FALSE; + } + + *ppTCPHeader = pContiguousData; + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS && + *pNeedToFreeMemory && + pBuffer) + { + KrnlHlprTransportHeaderDestroy((VOID**)&pBuffer); + + *pNeedToFreeMemory = FALSE; + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprTCPHeaderGet() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprTCPHeaderModifySourcePort" + + Purpose: Set the Source Address field in the TCP Header to the provided value. <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the TCP + Header. <br> + <br> + Values should be in Network Byte Order. <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 KrnlHlprTCPHeaderModifySourcePort(_In_ const FWP_VALUE* pValue, + _Inout_ NET_BUFFER_LIST* pNetBufferList, + _In_ UINT32 tcpHeaderSize, /* 0 */ + _In_ BOOLEAN convertByteOrder) /* FALSE */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprTCPHeaderModifySourcePort()\n"); + +#endif /// DBG + + NT_ASSERT(pValue); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + TCP_HEADER* pTCPHeader = 0; + BOOLEAN needToFree = FALSE; + UINT16 port = convertByteOrder ? htons(pValue->uint16) : pValue->uint16; + + status = KrnlHlprTCPHeaderGet(pNetBufferList, + (VOID**)&pTCPHeader, + &needToFree, + tcpHeaderSize); + HLPR_BAIL_ON_FAILURE(status); + + pTCPHeader->sourcePort = port; + + HLPR_BAIL_LABEL: + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = tcpHeaderSize ? tcpHeaderSize : TCP_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pTCPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprTransportHeaderDestroy((VOID**)&pTCPHeader); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprTCPHeaderModifySourcePort() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprTCPHeaderModifyDestinationPort" + + Purpose: Set the Destination Address field in the TCP Header to the provided value. <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the TCP + Header. <br> + <br> + Values should be in Network Byte Order. <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 KrnlHlprTCPHeaderModifyDestinationPort(_In_ const FWP_VALUE* pValue, + _Inout_ NET_BUFFER_LIST* pNetBufferList, + _In_ UINT32 tcpHeaderSize, /* 0 */ + _In_ BOOLEAN convertByteOrder) /* FALSE */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprTCPHeaderModifyDestinationPort()\n"); + +#endif /// DBG + + NT_ASSERT(pValue); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + TCP_HEADER* pTCPHeader = 0; + BOOLEAN needToFree = FALSE; + UINT16 port = convertByteOrder ? htons(pValue->uint16) : pValue->uint16; + + status = KrnlHlprTCPHeaderGet(pNetBufferList, + (VOID**)&pTCPHeader, + &needToFree, + tcpHeaderSize); + HLPR_BAIL_ON_FAILURE(status); + + pTCPHeader->destinationPort = port; + + HLPR_BAIL_LABEL: + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = tcpHeaderSize ? tcpHeaderSize : TCP_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pTCPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprTransportHeaderDestroy((VOID**)&pTCPHeader); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprTCPHeaderModifyDestinationPort() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +#endif /// TCP_HEADER____ + +#ifndef UDP_HEADER____ +#define UDP_HEADER____ + +/** + @kernel_helper_function="KrnlHlprUDPHeaderGet" + + Purpose: Retrieve a pointer to the UDP Header from the NET_BUFFER_LIST. <br> + <br> + Notes: Assumes the NBL is at the start of the UDP Header. <br> + <br> + MSDN_Ref: <br> +*/ +_When_(return != STATUS_SUCCESS, _At_(*ppUDPHeader, _Post_ _Null_)) +_When_(return == STATUS_SUCCESS, _At_(*ppUDPHeader, _Post_ _Notnull_)) +_IRQL_requires_min_(PASSIVE_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_same_ +_Success_(return == STATUS_SUCCESS) +NTSTATUS KrnlHlprUDPHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList, + _Outptr_result_buffer_(udpHeaderSize) VOID** ppUDPHeader, + _Inout_ BOOLEAN* pNeedToFreeMemory, + _In_ UINT32 udpHeaderSize) /* 0 */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprUDPHeaderGet()\n"); + +#endif /// DBG + + NTSTATUS status = STATUS_SUCCESS; + BYTE* pBuffer = 0; + NET_BUFFER* pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + const UINT32 BUFFER_SIZE = udpHeaderSize ? udpHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + UINT32 bytesNeeded = udpHeaderSize ? udpHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer); + PVOID pContiguousData = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprTransportHeaderDestroy if *pNeedToFreeMemory is TRUE + + HLPR_NEW_ARRAY(pBuffer, + BYTE, + BUFFER_SIZE, + WFPSAMPLER_SYSLIB_TAG); + HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer, + status); + +#pragma warning(pop) + + *pNeedToFreeMemory = TRUE; + + pContiguousData = NdisGetDataBuffer(pNetBuffer, + bytesNeeded, + pBuffer, + 1, + 0); + if(!pContiguousData) + { + status = STATUS_UNSUCCESSFUL; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_ERROR_LEVEL, + " !!!! KrnlHlprUDPHeaderGet : NdisGetDataBuffer() [status: %#x]\n", + status); + + HLPR_BAIL; + } + + if(pBuffer != pContiguousData) + { + HLPR_DELETE_ARRAY(pBuffer, + WFPSAMPLER_SYSLIB_TAG); + + *pNeedToFreeMemory = FALSE; + } + + *ppUDPHeader = pContiguousData; + + HLPR_BAIL_LABEL: + + if(status != STATUS_SUCCESS && + *pNeedToFreeMemory && + pBuffer) + { + KrnlHlprTransportHeaderDestroy((VOID**)&pBuffer); + + *pNeedToFreeMemory = FALSE; + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprUDPHeaderGet() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprUDPHeaderModifySourcePort" + + Purpose: Set the Source Address field in the UDP Header to the provided value. <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the UDP + Header. <br> + <br> + Values should be in Network Byte Order. <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 KrnlHlprUDPHeaderModifySourcePort(_In_ const FWP_VALUE* pValue, + _Inout_ NET_BUFFER_LIST* pNetBufferList, + _In_ UINT32 udpHeaderSize, /* 0 */ + _In_ BOOLEAN convertByteOrder) /* FALSE */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprUDPHeaderModifySourcePort()\n"); + +#endif /// DBG + + NT_ASSERT(pValue); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + UDP_HEADER* pUDPHeader = 0; + BOOLEAN needToFree = FALSE; + UINT16 port = convertByteOrder ? htons(pValue->uint16) : pValue->uint16; + + status = KrnlHlprUDPHeaderGet(pNetBufferList, + (VOID**)&pUDPHeader, + &needToFree, + udpHeaderSize); + HLPR_BAIL_ON_FAILURE(status); + + pUDPHeader->sourcePort = port; + + HLPR_BAIL_LABEL: + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = udpHeaderSize ? udpHeaderSize : UDP_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pUDPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprTransportHeaderDestroy((VOID**)&pUDPHeader); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprUDPHeaderModifySourcePort() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +/** + @kernel_helper_function="KrnlHlprUDPHeaderModifyDestinationPort" + + Purpose: Set the Destination Address field in the UDP Header to the provided value. <br> + <br> + Notes: The NetBufferList parameter is expected to be offset to the start of the UDP + Header. <br> + <br> + Values should be in Network Byte Order. <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 KrnlHlprUDPHeaderModifyDestinationPort(_In_ const FWP_VALUE* pValue, + _Inout_ NET_BUFFER_LIST* pNetBufferList, + _In_ UINT32 udpHeaderSize, /* 0 */ + _In_ BOOLEAN convertByteOrder) /* FALSE */ +{ +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " ---> KrnlHlprUDPHeaderModifyDestinationPort()\n"); + +#endif /// DBG + + NT_ASSERT(pValue); + NT_ASSERT(pNetBufferList); + + NTSTATUS status = STATUS_SUCCESS; + UDP_HEADER* pUDPHeader = 0; + BOOLEAN needToFree = FALSE; + UINT16 port = convertByteOrder ? htons(pValue->uint16) : pValue->uint16; + + status = KrnlHlprUDPHeaderGet(pNetBufferList, + (VOID**)&pUDPHeader, + &needToFree, + udpHeaderSize); + HLPR_BAIL_ON_FAILURE(status); + + pUDPHeader->destinationPort = port; + + HLPR_BAIL_LABEL: + + if(needToFree) + { + /// Copy the contents of the allocated buffer to the NBL's discontiguous buffer + if(status == STATUS_SUCCESS) + { + NET_BUFFER* pFirstNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNetBufferList); + PMDL pCurrentMDL = NET_BUFFER_CURRENT_MDL(pFirstNetBuffer); + SIZE_T currentMDLOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pFirstNetBuffer); + SIZE_T headerSize = udpHeaderSize ? udpHeaderSize : UDP_HEADER_MIN_SIZE; + SIZE_T bytesCopied = 0; + + status = PrvKrnlHlprCopyBufferToMDL((BYTE*)pUDPHeader, + pCurrentMDL, + currentMDLOffset, + headerSize, + &bytesCopied); + if(status == STATUS_SUCCESS && + bytesCopied != headerSize) + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KrnlHlprTransportHeaderDestroy((VOID**)&pUDPHeader); + } + +#if DBG + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, + DPFLTR_INFO_LEVEL, + " <--- KrnlHlprUDPHeaderModifyDestinationPort() [status: %#x]\n", + status); + +#endif /// DBG + + return status; +} + +#endif /// UDP_HEADER____ |
