summaryrefslogtreecommitdiff
path: root/network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp')
-rw-r--r--network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp3899
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____