Sample Code
Windows Driver Samples/ Windows Filtering Platform Sample/ C++/ sys/ ClassifyFunctions_BasicPacketModificationCallouts.cpp/
//////////////////////////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2012 Microsoft Corporation. All Rights Reserved. // // Module Name: // ClassifyFunctions_BasicPacketModificationCallouts.cpp // // Abstract: // This module contains WFP Classify functions for modifying and injecting packets back into /// the data path using the clone / block / inject method. // // Naming Convention: // // <Module><Scenario> // // i.e. // ClassifyBasicPacketModification // // <Module> // Classify - Function is an FWPS_CALLOUT_CLASSIFY_FN // <Scenario> // BasicPacketModification - Function demonstrates the clone / block / modify / inject // model. // // <Action><Scenario><Modifier> // // i.e. // TriggerBasicPacketModificationOutOfBand // // <Action> // { // - // Trigger - Initiates the desired scenario. // Perform - Executes the desired scenario. // } // <Scenario> // BasicPacketModification - Function demonstrates the clone / block / modify / inject // model. // <Modifier> // DeferredProcedureCall - DPC routine for Out of Band injection which dispatches the // proper Perform Function. // WorkItemRoutine - WorkItem Routine for Out of Band Injection which dispatches // the proper Perform Function. // AtInboundMACFrame - Function operates on: // FWPM_LAYER_INBOUND_MAC_FRAME_ETHERNET, and // FWPM_LAYER_INBOUND_MAC_NATIVE. // AtOutboundMACFrame - Function operates on: // FWPM_LAYER_OUTBOUND_MAC_FRAME_ETHERNET, and // FWPM_LAYER_OUTBOUND_MAC_NATIVE. // AtEgressVSwitchEthernet - Function operates on: // FWPM_LAYER_EGRESS_VSWITCH_ETHERNET. // AtIngressVSwitchEthernet - Function operates on: // FWPM_LAYER_INGRESS_VSWITCH_ETHERNET. // AtInboundNetwork - Function operates on: // FWPM_LAYER_INBOUND_IPPACKET_V{4/6} // AtOutboundNetwork - Function operates on: // FWPM_LAYER_OUTBOUND_IPPACKET_V{4/6} // AtForward - Function operates on: // FWPM_LAYER_IPFORWARD_V{4/6} // AtInboundTransport - Function operates on: // FWPM_LAYER_INBOUND_TRANSPORT_V{4/6}, // FWPM_LAYER_INBOUND_ICMP_ERROR_V{4/6}, // FWPM_LAYER_DATAGRAM_DATA_V{4/6}, // FWPM_LAYER_STREAM_PACKET_V{4/6}, and // FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V{4/6} // FWPM_LAYER_ALE_FLOW_ESTABLISHED_V{4/6} // AtOutboundTransport - Function operates on: // FWPM_LAYER_OUTBOUND_TRANSPORT_V{4/6}, // FWPM_LAYER_OUTBOUND_ICMP_ERROR_V{4/6}, // FWPM_LAYER_DATAGRAM_DATA_V{4/6}, // FWPM_LAYER_STREAM_PACKET_V{4/6}, and // FWPM_LAYER_ALE_AUTH_CONNECT_V{4/6} // FWPM_LAYER_ALE_FLOW_ESTABLISHED_V{4/6} // // Private Functions: // BasicPacketModificationDeferredProcedureCall(), // BasicPacketModificationWorkItemRoutine(), // PerformBasicPacketModificationAtEgressVSwitchEthernet(), // PerformBasicPacketModificationAtForward(), // PerformBasicPacketModificationAtInboundMACFrame(), // PerformBasicPacketModificationAtInboundNetwork(), // PerformBasicPacketModificationAtInboundTransport(), // PerformBasicPacketModificationAtIngressVSwitchEthernet(), // PerformBasicPacketModificationAtOutboundMACFrame(), // PerformBasicPacketModificationAtOutboundNetwork(), // PerformBasicPacketModificationAtOutboundTransport(), // TriggerBasicPacketModificationInline(), // TriggerBasicPacketModificationOutOfBand(), // // Public Functions: // ClassifyBasicPacketModification(), // // Author: // Dusty Harper (DHarper) // // Revision History: // // [ Month ][Day] [Year] - [Revision]-[ Comments ] // May 01, 2010 - 1.0 - Creation // /////////////////////////////////////////////////////////////////////////////// #include "Framework_WFPSamplerCalloutDriver.h" /// . #include "ClassifyFunctions_BasicPacketModificationCallouts.tmh" /// $(OBJ_PATH)\$(O)\ #if(NTDDI_VERSION >= NTDDI_WIN8) /** @private_function="PerformBasicPacketModificationAtInboundMACFrame" Purpose: Clones the NET_BUFFER_LIST, modifies it with data from the associated context and injects the clone back to the stack's inbound path from the incoming MAC Layers using FwpsInjectMacReceiveAsync(). <br> <br> Notes: Applies to the following inbound layers: <br> FWPM_LAYER_INBOUND_MAC_FRAME_ETHERNET <br> FWPM_LAYER_INBOUND_MAC_FRAME_NATIVE <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/HH439588.aspx <br> HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ _Check_return_ NTSTATUS PerformBasicPacketModificationAtInboundMACFrame(_In_ CLASSIFY_DATA** ppClassifyData, _In_ INJECTION_DATA** ppInjectionData, _In_ PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData, _In_ BOOLEAN isInline = FALSE) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> PerformBasicPacketModificationAtInboundMACFrame()\n"); #endif /// DBG NT_ASSERT(ppClassifyData); NT_ASSERT(ppInjectionData); NT_ASSERT(pModificationData); NT_ASSERT(*ppClassifyData); NT_ASSERT(*ppInjectionData); NTSTATUS status = STATUS_SUCCESS; FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; IF_INDEX interfaceIndex = 0; NDIS_PORT_NUMBER ndisPort = 0; NET_BUFFER_LIST* pNetBufferList = 0; BASIC_PACKET_MODIFICATION_COMPLETION_DATA* pCompletionData = 0; UINT32 bytesRetreated = 0; FWP_VALUE* pInterfaceIndex = 0; FWP_VALUE* pNDISPort = 0; #if DBG KIRQL irql = KeGetCurrentIrql(); #endif /// DBG #pragma warning(push) #pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy HLPR_NEW(pCompletionData, BASIC_PACKET_MODIFICATION_COMPLETION_DATA, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, status); #pragma warning(pop) KeInitializeSpinLock(&(pCompletionData->spinLock)); pCompletionData->performedInline = isInline; pCompletionData->pClassifyData = *ppClassifyData; pCompletionData->pInjectionData = *ppInjectionData; /// Responsibility for freeing this memory has been transferred to the pCompletionData *ppClassifyData = 0; *ppInjectionData = 0; pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_INTERFACE_INDEX); if(pInterfaceIndex && pInterfaceIndex->type == FWP_UINT32) interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32; pNDISPort = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_NDIS_PORT); if(pNDISPort && pNDISPort->type == FWP_UINT32) ndisPort = (NDIS_PORT_NUMBER)pNDISPort->uint32; /// If NATIVE, initial offset is at the MAC Header ... if(pClassifyValues->layerId != FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE && FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata, FWPS_L2_METADATA_FIELD_ETHERNET_MAC_HEADER_SIZE)) bytesRetreated = pMetadata->ethernetMacHeaderSize; if(bytesRetreated) { /// ... otherwise the offset is at the IP Header, so retreat the size of the MAC Header ... status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), bytesRetreated, 0, 0); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundMACFrame: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } } /// ... clone the entire NET_BUFFER_LIST ... status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, g_pNDISPoolData->nblPoolHandle, g_pNDISPoolData->nbPoolHandle, 0, &pNetBufferList); if(bytesRetreated) { /// ... and advance the offset back to the original position. NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), bytesRetreated, FALSE, 0); } if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundMACFrame: FwpsAllocateCloneNetBufferList() [status: %#x]\n", status); HLPR_BAIL; } if(pModificationData->flags) { /// Various checks and balances must be performed to modify the IP and Transport headers at this modification point. /// Parsing of the headers will need to occur, as well as spot checking to verify everything is as it should be. /// Additionally, checksum routines will need to be written to recalculate checksums for some of the headers. /// The following block of code is to get you started with modifying the headers with info not readily available /// (i.e. header parsing has not occurred so there is no relevant classifiable data nor metadata present). /* if(pModificationData->flags & PCPMDF_MODIFY_TRANSPORT_HEADER) { UINT32 tmpStatus = STATUS_SUCCESS; UINT8 protocol = 0; /// The clone is at the Ethernet Header, so advance by the size of the Ethernet Header... NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ethernetHeaderSize, FALSE, 0); protocol = KrnlHlprIPHeaderGetProtocolField(pNetBufferList, pCompletionData->pInjectionData->addressFamily); /// No Transport Modification if IPsec encrypted if(protocol != IPPROTO_ESP && protocol != IPPROTO_AH) { /// ... advance by the size of the IP Header. NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, FALSE, 0); switch(protocol) { case IPPROTO_ICMP: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv4HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv4HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_TCP: { UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) tcpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprTCPHeaderModifySourcePort(&srcPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprTCPHeaderModifySourcePort(&dstPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_UDP: { UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) udpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprUDPHeaderModifySourcePort(&srcPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprUDPHeaderModifySourcePort(&dstPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_ICMPV6: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv6HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv6HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } } /// ToDo: Recalculate the Transport Checksum Here HLPR_BAIL_LABEL_2: /// return the data offset to the beginning of the IP Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundMACFrame: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } HLPR_BAIL_ON_FAILURE(status); } /// return the data offset to the beginning of the Ethernet Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundMACFrame: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } } if(pModificationData->flags & PCPMDF_MODIFY_IP_HEADER) { /// The clone is at the Ethernet Header, so advance by the size of the Ethernet Header... NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ethernetHeaderSize, FALSE, 0); if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_SOURCE_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.sourceAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE_WITH_LABEL(value.byteArray16, status, HLPR_BAIL_LABEL_3); value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.sourceAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifySourceAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE_WITH_LABEL(status, HLPR_BAIL_LABEL_3); } if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_DESTINATION_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.destinationAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE_WITH_LABEL(value.byteArray16, status, HLPR_BAIL_LABEL_3); value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.destinationAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifyDestinationAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE_WITH_LABEL(status, HLPR_BAIL_LABEL_3); } HLPR_BAIL_LABEL_3: /// return the data offset to the beginning of the Ethernet Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundMACFrame: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } } */ if(pModificationData->flags & PCPMDF_MODIFY_MAC_HEADER) { if(pModificationData->macData.flags & PCPMDF_MODIFY_MAC_HEADER_SOURCE_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); HLPR_NEW(value.byteArray6, FWP_BYTE_ARRAY6, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray6, status); value.type = FWP_BYTE_ARRAY6_TYPE; RtlCopyMemory(value.byteArray6->byteArray6, pModificationData->macData.pSourceMACAddress, ETHERNET_ADDRESS_SIZE); status = KrnlHlprMACHeaderModifySourceAddress(&value, pNetBufferList); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->macData.flags & PCPMDF_MODIFY_MAC_HEADER_DESTINATION_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); #pragma warning(push) #pragma warning(disable: 6014) /// value.byteArray6 will be freed in with call to KrnlHlprFwpValuePurgeLocalCopy HLPR_NEW(value.byteArray6, FWP_BYTE_ARRAY6, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray6, status); #pragma warning(pop) value.type = FWP_BYTE_ARRAY6_TYPE; RtlCopyMemory(value.byteArray6->byteArray6, pModificationData->macData.pDestinationMACAddress, ETHERNET_ADDRESS_SIZE); status = KrnlHlprMACHeaderModifyDestinationAddress(&value, pNetBufferList); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } } } pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList, TRUE); status = FwpsInjectMacReceiveAsync(pCompletionData->pInjectionData->injectionHandle, pCompletionData->pInjectionData->injectionContext, 0, pClassifyValues->layerId, interfaceIndex, ndisPort, pNetBufferList, CompleteBasicPacketModification, pCompletionData); NT_ASSERT(irql == KeGetCurrentIrql()); if(status != STATUS_SUCCESS) DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundMACFrame: FwpsInjectMacReceiveAsync() [status: %#x]\n", status); HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); if(status != STATUS_SUCCESS) { if(pNetBufferList) { FwpsFreeCloneNetBufferList(pNetBufferList, 0); pNetBufferList = 0; } if(pCompletionData) BasicPacketModificationCompletionDataDestroy(&pCompletionData, TRUE); } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- PerformBasicPacketModificationAtInboundMACFrame() [status: %#x]\n", status); #endif /// DBG return status; } /** @private_function="PerformBasicPacketInjectionAtOutboundMACFrame" Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the stack from the outgoing MAC Layers using FwpsInjectMacSendAsync(). <br> <br> Notes: Applies to the following inbound layers: <br> FWPM_LAYER_OUTBOUND_MAC_FRAME_ETHERNET <br> FWPM_LAYER_OUTBOUND_MAC_FRAME_NATIVE <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/HH439593.aspx <br> HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ _Check_return_ NTSTATUS PerformBasicPacketModificationAtOutboundMACFrame(_In_ CLASSIFY_DATA** ppClassifyData, _In_ INJECTION_DATA** ppInjectionData, _In_ PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData, _In_ BOOLEAN isInline = FALSE) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> PerformBasicPacketModificationAtOutboundMACFrame()\n"); #endif /// DBG NT_ASSERT(ppClassifyData); NT_ASSERT(ppInjectionData); NT_ASSERT(pModificationData); NT_ASSERT(*ppClassifyData); NT_ASSERT(*ppInjectionData); NTSTATUS status = STATUS_SUCCESS; FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; IF_INDEX interfaceIndex = 0; NDIS_PORT_NUMBER ndisPort = 0; NET_BUFFER_LIST* pNetBufferList = 0; BASIC_PACKET_MODIFICATION_COMPLETION_DATA* pCompletionData = 0; FWP_VALUE* pInterfaceIndex = 0; FWP_VALUE* pNDISPort = 0; #if DBG KIRQL irql = KeGetCurrentIrql(); #endif /// DBG #pragma warning(push) #pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy HLPR_NEW(pCompletionData, BASIC_PACKET_MODIFICATION_COMPLETION_DATA, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, status); #pragma warning(pop) KeInitializeSpinLock(&(pCompletionData->spinLock)); pCompletionData->performedInline = isInline; pCompletionData->pClassifyData = *ppClassifyData; pCompletionData->pInjectionData = *ppInjectionData; /// Responsibility for freeing this memory has been transferred to the pCompletionData *ppClassifyData = 0; *ppInjectionData = 0; pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_INTERFACE_INDEX); if(pInterfaceIndex && pInterfaceIndex->type == FWP_UINT32) interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32; pNDISPort = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_NDIS_PORT); if(pNDISPort && pNDISPort->type == FWP_UINT32) ndisPort = (NDIS_PORT_NUMBER)pNDISPort->uint32; /// Initial offset is at the MAC Header, so just clone the entire NET_BUFFER_LIST. status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, g_pNDISPoolData->nblPoolHandle, g_pNDISPoolData->nbPoolHandle, 0, &pNetBufferList); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtOutboundMACFrame: FwpsAllocateCloneNetBufferList() [status: %#x]\n", status); HLPR_BAIL; } pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList, TRUE); if(pModificationData->flags) { /// Various checks and balances must be performed to modify the IP and Transport headers at this modification point. /// Parsing of the headers will need to occur, as well as spot checking to verify everything is as it should be. /// Additionally, checksum routines will need to be written to recalculate checksums for some of the headers. /// The following block of code is to get you started with modifying the headers with info not readily available. /// (i.e. header parsing has not occurred so there is no relevant classifiable data nor metadata present). /* if(pModificationData->flags & PCPMDF_MODIFY_TRANSPORT_HEADER) { UINT32 tmpStatus = STATUS_SUCCESS; UINT8 protocol = 0; /// The clone is at the Ethernet Header, so advance by the size of the Ethernet Header... NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ethernetHeaderSize, FALSE, 0); protocol = KrnlHlprIPHeaderGetProtocolField(pNetBufferList, pCompletionData->pInjectionData->addressFamily); /// No Transport Modification if IPsec encrypted if(protocol != IPPROTO_ESP && protocol != IPPROTO_AH) { /// ... advance by the size of the IP Header. NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, FALSE, 0); switch(protocol) { case IPPROTO_ICMP: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv4HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv4HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_TCP: { UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) tcpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprTCPHeaderModifySourcePort(&srcPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprTCPHeaderModifySourcePort(&dstPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_UDP: { UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) udpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprUDPHeaderModifySourcePort(&srcPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprUDPHeaderModifySourcePort(&dstPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_ICMPV6: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv6HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv6HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } } /// ToDo: Recalculate the Transport Checksum Here HLPR_BAIL_LABEL_2: /// return the data offset to the beginning of the IP Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtOutboundMacFrame: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } HLPR_BAIL_ON_FAILURE(status); } /// return the data offset to the beginning of the Ethernet Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtOutboundMACFrame: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } } if(pModificationData->flags & PCPMDF_MODIFY_IP_HEADER) { /// The clone is at the Ethernet Header, so advance by the size of the Ethernet Header... NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ethernetHeaderSize, FALSE, 0); if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_SOURCE_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.sourceAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE_WITH_LABEL(value.byteArray16, status, HLPR_BAIL_LABEL_3); value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.sourceAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifySourceAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE_WITH_LABEL(status, HLPR_BAIL_LABEL_3); } if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_DESTINATION_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.destinationAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE_WITH_LABEL(value.byteArray16, status, HLPR_BAIL_LABEL_3); value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.destinationAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifyDestinationAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE_WITH_LABEL(status, HLPR_BAIL_LABEL_3); } HLPR_BAIL_LABEL_3: /// return the data offset to the beginning of the Ethernet Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtOutboundMACFrame: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } } */ if(pModificationData->flags & PCPMDF_MODIFY_MAC_HEADER) { if(pModificationData->macData.flags & PCPMDF_MODIFY_MAC_HEADER_SOURCE_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); HLPR_NEW(value.byteArray6, FWP_BYTE_ARRAY6, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray6, status); value.type = FWP_BYTE_ARRAY6_TYPE; RtlCopyMemory(value.byteArray6->byteArray6, pModificationData->macData.pSourceMACAddress, ETHERNET_ADDRESS_SIZE); status = KrnlHlprMACHeaderModifySourceAddress(&value, pNetBufferList); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->macData.flags & PCPMDF_MODIFY_MAC_HEADER_DESTINATION_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); #pragma warning(push) #pragma warning(disable: 6014) /// value.byteArray6 will be freed in with call to KrnlHlprFwpValuePurgeLocalCopy HLPR_NEW(value.byteArray6, FWP_BYTE_ARRAY6, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray6, status); #pragma warning(pop) value.type = FWP_BYTE_ARRAY6_TYPE; RtlCopyMemory(value.byteArray6->byteArray6, pModificationData->macData.pDestinationMACAddress, ETHERNET_ADDRESS_SIZE); status = KrnlHlprMACHeaderModifyDestinationAddress(&value, pNetBufferList); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } } } status = FwpsInjectMacSendAsync(pCompletionData->pInjectionData->injectionHandle, pCompletionData->pInjectionData->injectionContext, 0, pClassifyValues->layerId, interfaceIndex, ndisPort, pNetBufferList, CompleteBasicPacketModification, pCompletionData); NT_ASSERT(irql == KeGetCurrentIrql()); if(status != STATUS_SUCCESS) DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtOutboundMACFrame: FwpsInjectMacSendAsync() [status: %#x]\n", status); HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); if(status != STATUS_SUCCESS) { if(pNetBufferList) { FwpsFreeCloneNetBufferList(pNetBufferList, 0); pNetBufferList = 0; } if(pCompletionData) BasicPacketModificationCompletionDataDestroy(&pCompletionData, TRUE); } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- PerformBasicPacketModificationAtOutboundMACFrame() [status: %#x]\n", status); #endif /// DBG return status; } /** @private_function="PerformBasicPacketModificationAtIngressVSwitchEthernet" Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the virtual switch's ingress path from the ingress VSwitch Layers using FwpsInjectvSwitchEthernetIngressAsync0(). <br> <br> Notes: Applies to the following ingress layers: <br> FWPM_LAYER_INGRESS_VSWITCH_ETHERNET <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/HH439669.aspx <br> HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ _Check_return_ NTSTATUS PerformBasicPacketModificationAtIngressVSwitchEthernet(_In_ CLASSIFY_DATA** ppClassifyData, _In_ INJECTION_DATA** ppInjectionData, _In_ PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData, _In_ BOOLEAN isInline = FALSE) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> PerformBasicPacketModificationAtIngressVSwitchEthernet()\n"); #endif /// DBG NT_ASSERT(ppClassifyData); NT_ASSERT(ppInjectionData); NT_ASSERT(pModificationData); NT_ASSERT(*ppClassifyData); NT_ASSERT(*ppInjectionData); NTSTATUS status = STATUS_SUCCESS; FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; FWP_VALUE* pVSwitchIDValue = 0; FWP_BYTE_BLOB* pVSwitchID = 0; NDIS_SWITCH_PORT_ID sourcePortID = 0; NDIS_SWITCH_NIC_INDEX sourceNICIndex = 0; NET_BUFFER_LIST* pNetBufferList = 0; BASIC_PACKET_MODIFICATION_COMPLETION_DATA* pCompletionData = 0; #if DBG KIRQL irql = KeGetCurrentIrql(); #endif /// DBG #pragma warning(push) #pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy HLPR_NEW(pCompletionData, BASIC_PACKET_MODIFICATION_COMPLETION_DATA, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, status); #pragma warning(pop) KeInitializeSpinLock(&(pCompletionData->spinLock)); pCompletionData->performedInline = isInline; pCompletionData->pClassifyData = *ppClassifyData; pCompletionData->pInjectionData = *ppInjectionData; /// Responsibility for freeing this memory has been transferred to the pCompletionData *ppClassifyData = 0; *ppInjectionData = 0; if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata, FWPS_L2_METADATA_FIELD_VSWITCH_SOURCE_PORT_ID)) sourcePortID = pMetadata->vSwitchSourcePortId; if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata, FWPS_L2_METADATA_FIELD_VSWITCH_SOURCE_NIC_INDEX)) sourceNICIndex = (NDIS_SWITCH_NIC_INDEX)pMetadata->vSwitchSourceNicIndex; pVSwitchIDValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_VSWITCH_ID); if(pVSwitchIDValue) pVSwitchID = pVSwitchIDValue->byteBlob; if(pVSwitchID == 0) { status = STATUS_INVALID_MEMBER; DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtIngressVSwitchEthernet() [status: %#x][pVSwitchID: %#p]\n", status, pVSwitchID); HLPR_BAIL; } /// Initial offset is at the MAC Header, so just clone the entire NET_BUFFER_LIST. status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, g_pNDISPoolData->nblPoolHandle, g_pNDISPoolData->nbPoolHandle, 0, &pNetBufferList); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtIngressVSwitchEthernet: FwpsAllocateCloneNetBufferList() [status: %#x]\n", status); HLPR_BAIL; } pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList, TRUE); if(pModificationData->flags) { /// Various checks and balances must be performed to modify the IP and Transport headers at this modification point. /// Parsing of the headers will need to occur, as well as spot checking to verify everything is as it should be. /// Additionally, checksum routines will need to be written to recalculate checksums for some of the headers. /// The following block of code is to get you started with modifying the headers with info not readily available. /// (i.e. header parsing has not occurred so there is no relevant classifiable data nor metadata present). /* if(pModificationData->flags & PCPMDF_MODIFY_TRANSPORT_HEADER) { UINT32 tmpStatus = STATUS_SUCCESS; UINT8 protocol = 0; /// The clone is at the Ethernet Header, so advance by the size of the Ethernet Header... NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ethernetHeaderSize, FALSE, 0); protocol = KrnlHlprIPHeaderGetProtocolField(pNetBufferList, pCompletionData->pInjectionData->addressFamily); /// No Transport Modification if IPsec encrypted if(protocol != IPPROTO_ESP && protocol != IPPROTO_AH) { /// ... advance by the size of the IP Header. NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, FALSE, 0); switch(protocol) { case IPPROTO_ICMP: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv4HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv4HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_TCP: { UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) tcpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprTCPHeaderModifySourcePort(&srcPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprTCPHeaderModifySourcePort(&dstPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_UDP: { UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) udpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprUDPHeaderModifySourcePort(&srcPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprUDPHeaderModifySourcePort(&dstPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_ICMPV6: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv6HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv6HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } } /// ToDo: Recalculate the Transport Checksum Here HLPR_BAIL_LABEL_2: /// return the data offset to the beginning of the IP Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtIngressVSwitchEthernet: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } HLPR_BAIL_ON_FAILURE(status); } /// return the data offset to the beginning of the Ethernet Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtIngressVSwitchEthernet: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } } if(pModificationData->flags & PCPMDF_MODIFY_IP_HEADER) { /// The clone is at the Ethernet Header, so advance by the size of the Ethernet Header... NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ethernetHeaderSize, FALSE, 0); if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_SOURCE_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.sourceAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE_WITH_LABEL(value.byteArray16, status, HLPR_BAIL_LABEL_3); value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.sourceAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifySourceAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE_WITH_LABEL(status, HLPR_BAIL_LABEL_3); } if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_DESTINATION_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.destinationAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE_WITH_LABEL(value.byteArray16, status, HLPR_BAIL_LABEL_3); value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.destinationAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifyDestinationAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE_WITH_LABEL(status, HLPR_BAIL_LABEL_3); } HLPR_BAIL_LABEL_3: /// return the data offset to the beginning of the Ethernet Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtIngressVSwitchEthernet: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } } */ if(pModificationData->flags & PCPMDF_MODIFY_MAC_HEADER) { if(pModificationData->macData.flags & PCPMDF_MODIFY_MAC_HEADER_SOURCE_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); HLPR_NEW(value.byteArray6, FWP_BYTE_ARRAY6, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray6, status); value.type = FWP_BYTE_ARRAY6_TYPE; RtlCopyMemory(value.byteArray6->byteArray6, pModificationData->macData.pSourceMACAddress, ETHERNET_ADDRESS_SIZE); status = KrnlHlprMACHeaderModifySourceAddress(&value, pNetBufferList); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->macData.flags & PCPMDF_MODIFY_MAC_HEADER_DESTINATION_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); #pragma warning(push) #pragma warning(disable: 6014) /// value.byteArray6 will be freed in with call to KrnlHlprFwpValuePurgeLocalCopy HLPR_NEW(value.byteArray6, FWP_BYTE_ARRAY6, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray6, status); #pragma warning(pop) value.type = FWP_BYTE_ARRAY6_TYPE; RtlCopyMemory(value.byteArray6->byteArray6, pModificationData->macData.pDestinationMACAddress, ETHERNET_ADDRESS_SIZE); status = KrnlHlprMACHeaderModifyDestinationAddress(&value, pNetBufferList); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } } } status = FwpsInjectvSwitchEthernetIngressAsync(pCompletionData->pInjectionData->injectionHandle, pCompletionData->pInjectionData->injectionContext, 0, 0, pVSwitchID, sourcePortID, sourceNICIndex, pNetBufferList, CompleteBasicPacketModification, pCompletionData); NT_ASSERT(irql == KeGetCurrentIrql()); if(status != STATUS_SUCCESS) DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtIngressVSwitchEthernet: FwpsInjectvSwitchEthernetIngressAsync() [status: %#x]\n", status); HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); if(status != STATUS_SUCCESS) { if(pNetBufferList) { FwpsFreeCloneNetBufferList(pNetBufferList, 0); pNetBufferList = 0; } if(pCompletionData) BasicPacketModificationCompletionDataDestroy(&pCompletionData, TRUE); } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- PerformBasicPacketModificationAtIngressVSwitchEthernet() [status: %#x]\n", status); #endif /// DBG return status; } /** @private_function="PerformBasicPacketModificationAtEgressVSwitchEthernet" Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the virtual switch's ingress path from the egress VSwitch Layers using FwpsInjectvSwitchEthernetIngressAsync0(). <br> <br> Notes: Applies to the following egress layers: <br> FWPM_LAYER_EGRESS_VSWITCH_ETHERNET <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/HH439669.aspx <br> HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ _Check_return_ NTSTATUS PerformBasicPacketModificationAtEgressVSwitchEthernet(_In_ CLASSIFY_DATA** ppClassifyData, _In_ INJECTION_DATA** ppInjectionData, _In_ PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData, _In_ BOOLEAN isInline = FALSE) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> PerformBasicPacketModificationAtEgressVSwitchEthernet()\n"); #endif /// DBG NT_ASSERT(ppClassifyData); NT_ASSERT(ppInjectionData); NT_ASSERT(pModificationData); NT_ASSERT(*ppClassifyData); NT_ASSERT(*ppInjectionData); NTSTATUS status = STATUS_SUCCESS; FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; FWP_VALUE* pVSwitchIDValue = 0; FWP_BYTE_BLOB* pVSwitchID = 0; NDIS_SWITCH_PORT_ID sourcePortID = 0; NDIS_SWITCH_NIC_INDEX sourceNICIndex = 0; NET_BUFFER_LIST* pNetBufferList = 0; BASIC_PACKET_MODIFICATION_COMPLETION_DATA* pCompletionData = 0; #if DBG KIRQL irql = KeGetCurrentIrql(); #endif /// DBG #pragma warning(push) #pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy HLPR_NEW(pCompletionData, BASIC_PACKET_MODIFICATION_COMPLETION_DATA, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, status); #pragma warning(pop) KeInitializeSpinLock(&(pCompletionData->spinLock)); pCompletionData->performedInline = isInline; pCompletionData->pClassifyData = *ppClassifyData; pCompletionData->pInjectionData = *ppInjectionData; /// Responsibility for freeing this memory has been transferred to the pCompletionData *ppClassifyData = 0; *ppInjectionData = 0; if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata, FWPS_L2_METADATA_FIELD_VSWITCH_SOURCE_PORT_ID)) sourcePortID = pMetadata->vSwitchSourcePortId; if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata, FWPS_L2_METADATA_FIELD_VSWITCH_SOURCE_NIC_INDEX)) sourceNICIndex = (NDIS_SWITCH_NIC_INDEX)pMetadata->vSwitchSourceNicIndex; pVSwitchIDValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_VSWITCH_ID); if(pVSwitchIDValue) pVSwitchID = pVSwitchIDValue->byteBlob; if(pVSwitchID == 0) { status = STATUS_INVALID_MEMBER; DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtEgressVSwitchEthernet() [status: %#x][pVSwitchID: %#p]\n", status, pVSwitchID); HLPR_BAIL; } /// Initial offset is at the MAC Header, so just clone the entire NET_BUFFER_LIST. status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, g_pNDISPoolData->nblPoolHandle, g_pNDISPoolData->nbPoolHandle, 0, &pNetBufferList); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtEgressVSwitchEthernet: FwpsAllocateCloneNetBufferList() [status: %#x]\n", status); HLPR_BAIL; } pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList, TRUE); if(pModificationData->flags) { /// Various checks and balances must be performed to modify the IP and Transport headers at this modification point. /// Parsing of the headers will need to occur, as well as spot checking to verify everything is as it should be. /// Additionally, checksum routines will need to be written to recalculate checksums for some of the headers. /// The following block of code is to get you started with modifying the headers with info not readily available. /// (i.e. header parsing has not occurred so there is no relevant classifiable data nor metadata present). /* if(pModificationData->flags & PCPMDF_MODIFY_TRANSPORT_HEADER) { UINT32 tmpStatus = STATUS_SUCCESS; UINT8 protocol = 0; /// The clone is at the Ethernet Header, so advance by the size of the Ethernet Header... NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ethernetHeaderSize, FALSE, 0); protocol = KrnlHlprIPHeaderGetProtocolField(pNetBufferList, pCompletionData->pInjectionData->addressFamily); /// No Transport Modification if IPsec encrypted if(protocol != IPPROTO_ESP && protocol != IPPROTO_AH) { /// ... advance by the size of the IP Header. NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, FALSE, 0); switch(protocol) { case IPPROTO_ICMP: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv4HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv4HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_TCP: { UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) tcpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprTCPHeaderModifySourcePort(&srcPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprTCPHeaderModifySourcePort(&dstPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_UDP: { UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) udpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprUDPHeaderModifySourcePort(&srcPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprUDPHeaderModifySourcePort(&dstPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_ICMPV6: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv6HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv6HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } } /// ToDo: Recalculate the Transport Checksum Here HLPR_BAIL_LABEL_2: /// return the data offset to the beginning of the IP Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtEgressVSwitchEthernet: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } HLPR_BAIL_ON_FAILURE(status); } /// return the data offset to the beginning of the Ethernet Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtEgressVSwitchEthernet: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } } if(pModificationData->flags & PCPMDF_MODIFY_IP_HEADER) { /// The clone is at the Ethernet Header, so advance by the size of the Ethernet Header... NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ethernetHeaderSize, FALSE, 0); if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_SOURCE_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.sourceAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE_WITH_LABEL(value.byteArray16, status, HLPR_BAIL_LABEL_3); value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.sourceAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifySourceAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE_WITH_LABEL(status, HLPR_BAIL_LABEL_3); } if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_DESTINATION_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.destinationAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE_WITH_LABEL(value.byteArray16, status, HLPR_BAIL_LABEL_3); value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.destinationAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifyDestinationAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE_WITH_LABEL(status, HLPR_BAIL_LABEL_3); } HLPR_BAIL_LABEL_3: /// return the data offset to the beginning of the Ethernet Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtEgressVSwitchEthernet: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } } */ if(pModificationData->flags & PCPMDF_MODIFY_MAC_HEADER) { if(pModificationData->macData.flags & PCPMDF_MODIFY_MAC_HEADER_SOURCE_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); HLPR_NEW(value.byteArray6, FWP_BYTE_ARRAY6, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray6, status); value.type = FWP_BYTE_ARRAY6_TYPE; RtlCopyMemory(value.byteArray6->byteArray6, pModificationData->macData.pSourceMACAddress, ETHERNET_ADDRESS_SIZE); status = KrnlHlprMACHeaderModifySourceAddress(&value, pNetBufferList); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->macData.flags & PCPMDF_MODIFY_MAC_HEADER_DESTINATION_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); #pragma warning(push) #pragma warning(disable: 6014) /// value.byteArray6 will be freed in with call to KrnlHlprFwpValuePurgeLocalCopy HLPR_NEW(value.byteArray6, FWP_BYTE_ARRAY6, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray6, status); #pragma warning(pop) value.type = FWP_BYTE_ARRAY6_TYPE; RtlCopyMemory(value.byteArray6->byteArray6, pModificationData->macData.pDestinationMACAddress, ETHERNET_ADDRESS_SIZE); status = KrnlHlprMACHeaderModifyDestinationAddress(&value, pNetBufferList); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } } } status = FwpsInjectvSwitchEthernetIngressAsync(pCompletionData->pInjectionData->injectionHandle, pCompletionData->pInjectionData->injectionContext, 0, 0, pVSwitchID, sourcePortID, sourceNICIndex, pNetBufferList, CompleteBasicPacketModification, pCompletionData); NT_ASSERT(irql == KeGetCurrentIrql()); if(status != STATUS_SUCCESS) DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtEgressVSwitchEthernet: FwpsInjectvSwitchEthernetIngressAsync() [status: %#x]\n", status); HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); if(status != STATUS_SUCCESS) { if(pNetBufferList) { FwpsFreeCloneNetBufferList(pNetBufferList, 0); pNetBufferList = 0; } if(pCompletionData) BasicPacketModificationCompletionDataDestroy(&pCompletionData, TRUE); } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- PerformBasicPacketModificationAtEgressVSwitchEthernet() [status: %#x]\n", status); #endif /// DBG return status; } #endif // (NTDDI_VERSION >= NTDDI_WIN8) /** @private_function="PerformBasicPacketModificationAtInboundNetwork" Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the stack from the incoming Network Layers using FwpsInjectNetworkReceiveAsync(). <br> <br> Notes: Applies to the following inbound layers: <br> FWPM_LAYER_INBOUND_IPPACKET_V{4/6} <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF551183.aspx <br> HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ _Check_return_ NTSTATUS PerformBasicPacketModificationAtInboundNetwork(_In_ CLASSIFY_DATA** ppClassifyData, _In_ INJECTION_DATA** ppInjectionData, _In_ PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData, _In_ BOOLEAN isInline = FALSE) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> PerformBasicPacketModificationAtInboundNetwork()\n"); #endif /// DBG NT_ASSERT(ppClassifyData); NT_ASSERT(ppInjectionData); NT_ASSERT(pModificationData); NT_ASSERT(*ppClassifyData); NT_ASSERT(*ppInjectionData); NTSTATUS status = STATUS_SUCCESS; FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; COMPARTMENT_ID compartmentID = UNSPECIFIED_COMPARTMENT_ID; IF_INDEX interfaceIndex = 0; IF_INDEX subInterfaceIndex = 0; UINT32 flags = 0; NET_BUFFER_LIST* pNetBufferList = 0; BASIC_PACKET_MODIFICATION_COMPLETION_DATA* pCompletionData = 0; UINT32 ipHeaderSize = 0; UINT32 bytesRetreated = 0; FWP_VALUE* pInterfaceIndex = 0; FWP_VALUE* pSubInterfaceIndex = 0; FWP_VALUE* pFlags = 0; NDIS_TCP_IP_CHECKSUM_PACKET_INFO checksumInfo = {0}; #if DBG KIRQL irql = KeGetCurrentIrql(); #endif /// DBG #pragma warning(push) #pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy HLPR_NEW(pCompletionData, BASIC_PACKET_MODIFICATION_COMPLETION_DATA, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, status); #pragma warning(pop) KeInitializeSpinLock(&(pCompletionData->spinLock)); pCompletionData->performedInline = isInline; pCompletionData->pClassifyData = *ppClassifyData; pCompletionData->pInjectionData = *ppInjectionData; /// Responsibility for freeing this memory has been transferred to the pCompletionData *ppClassifyData = 0; *ppInjectionData = 0; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_COMPARTMENT_ID)) compartmentID = (COMPARTMENT_ID)pMetadata->compartmentId; pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_INTERFACE_INDEX); if(pInterfaceIndex && pInterfaceIndex->type == FWP_UINT32) interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32; pSubInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_SUB_INTERFACE_INDEX); if(pSubInterfaceIndex && pSubInterfaceIndex->type == FWP_UINT32) subInterfaceIndex = (IF_INDEX)pSubInterfaceIndex->uint32; pFlags = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_FLAGS); if(pFlags && pFlags->type == FWP_UINT32) flags = pFlags->uint32; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_IP_HEADER_SIZE)) bytesRetreated = ipHeaderSize = pMetadata->ipHeaderSize; checksumInfo.Value = (ULONG)(ULONG_PTR)NET_BUFFER_LIST_INFO((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, TcpIpChecksumNetBufferListInfo); /// Initial offset is at the Transport Header, so retreat the size of the IP Header ... status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), bytesRetreated, 0, 0); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundNetwork: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } /// ... clone the entire NET_BUFFER_LIST ... status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, g_pNDISPoolData->nblPoolHandle, g_pNDISPoolData->nbPoolHandle, 0, &pNetBufferList); /// Handle if this packet had the IP checksum offloaded or if it's loopback if(KrnlHlprFwpmLayerIsIPv4(pClassifyValues->layerId) && pNetBufferList && (checksumInfo.Receive.NdisPacketIpChecksumSucceeded || flags & FWP_CONDITION_FLAG_IS_LOOPBACK)) { NTSTATUS tempStatus = STATUS_SUCCESS; IP_HEADER_V4* pIPv4Header = 0; BOOLEAN needToFree = FALSE; tempStatus = KrnlHlprIPHeaderGet(pNetBufferList, (VOID**)&pIPv4Header, &needToFree, ipHeaderSize); if(tempStatus == STATUS_SUCCESS) { /// prevent TCP/IP Zone crossing if(flags & FWP_CONDITION_FLAG_IS_LOOPBACK) RtlCopyMemory(pIPv4Header->pDestinationAddress, pIPv4Header->pSourceAddress, sizeof(UINT32)); KrnlHlprIPHeaderCalculateV4Checksum(pIPv4Header, ipHeaderSize); } if(needToFree) KrnlHlprIPHeaderDestroy((VOID**)&pIPv4Header); } /// ... and advance the offset back to the original position. NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), bytesRetreated, FALSE, 0); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundNetwork: FwpsAllocateCloneNetBufferList() [status: %#x]\n", status); HLPR_BAIL; } pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList); if(pModificationData->flags) { /// Various checks and balances must be performed to modify the Transport header at this modification point. /// Parsing of the headers will need to occur, as well as spot checking to verify everything is as it should be. /// Additionally, checksum routines will need to be written to recalculate checksums for some of the headers. /// The following block of code is to get you started with modifying the headers with info not readily available. /// (i.e. header parsing has not occurred so there is no relevant classifiable data nor metadata present). /* if(pModificationData->flags & PCPMDF_MODIFY_TRANSPORT_HEADER) { UINT32 tmpStatus = STATUS_SUCCESS; UINT8 protocol = 0; protocol = KrnlHlprIPHeaderGetProtocolField(pNetBufferList, pCompletionData->pInjectionData->addressFamily); /// The clone is at the IP Header, so advance by the size of the IP Header. NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, FALSE, 0); switch(protocol) { case IPPROTO_ICMP: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv4HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv4HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_TCP: { UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) tcpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprTCPHeaderModifySourcePort(&srcPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprTCPHeaderModifySourcePort(&dstPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_UDP: { UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) udpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprUDPHeaderModifySourcePort(&srcPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprUDPHeaderModifySourcePort(&dstPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_ICMPV6: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv6HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv6HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } } /// ToDo: Recalculate the Transport Checksum Here HLPR_BAIL_LABEL_2: /// return the data offset to the beginning of the IP Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundNetwork: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } HLPR_BAIL_ON_FAILURE(status); } */ if(pModificationData->flags & PCPMDF_MODIFY_IP_HEADER) { if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_SOURCE_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.sourceAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray16, status); value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.sourceAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifySourceAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_DESTINATION_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.destinationAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { #pragma warning(push) #pragma warning(disable: 6014) /// value.byteArray16 will be freed in with call to KrnlHlprFwpValuePurgeLocalCopy HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray16, status); #pragma warning(pop) value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.destinationAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifyDestinationAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } } } /// Handle if this packet is destined for the software loopback if(flags & FWP_CONDITION_FLAG_IS_LOOPBACK) { FWP_VALUE* pLocalAddress = 0; FWP_VALUE* pRemoteAddress = 0; FWP_VALUE* pLoopbackAddress = 0; pLocalAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_REMOTE_ADDRESS); if(pLocalAddress && ((pLocalAddress->type == FWP_UINT32 && RtlCompareMemory(&(pLocalAddress->uint32), IPV4_LOOPBACK_ADDRESS, IPV4_ADDRESS_SIZE)) || (pLocalAddress->type == FWP_BYTE_ARRAY16_TYPE && RtlCompareMemory(pLocalAddress->byteArray16->byteArray16, IPV6_LOOPBACK_ADDRESS, IPV6_ADDRESS_SIZE)))) pLoopbackAddress = pLocalAddress; if(!pLoopbackAddress) { pRemoteAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_REMOTE_ADDRESS); if(pRemoteAddress && ((pRemoteAddress->type == FWP_UINT32 && RtlCompareMemory(&(pRemoteAddress->uint32), IPV4_LOOPBACK_ADDRESS, IPV4_ADDRESS_SIZE)) || (pRemoteAddress->type == FWP_BYTE_ARRAY16_TYPE && RtlCompareMemory(pRemoteAddress->byteArray16->byteArray16, IPV6_LOOPBACK_ADDRESS, IPV6_ADDRESS_SIZE)))) pLoopbackAddress = pRemoteAddress; } if(pLoopbackAddress) { status = KrnlHlprIPHeaderModifyLoopbackToLocal(pMetadata, pLoopbackAddress, ipHeaderSize, pNetBufferList); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundNetwork: KrnlHlprIPHeaderModifyLoopbackToLocal() [status: %#x]\n", status); HLPR_BAIL; } } } status = FwpsInjectNetworkReceiveAsync(pCompletionData->pInjectionData->injectionHandle, pCompletionData->pInjectionData->injectionContext, 0, compartmentID, interfaceIndex, subInterfaceIndex, pNetBufferList, CompleteBasicPacketModification, pCompletionData); NT_ASSERT(irql == KeGetCurrentIrql()); if(status != STATUS_SUCCESS) DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundNetwork: FwpsInjectNetworkReceiveAsync() [status: %#x]\n", status); HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); if(status != STATUS_SUCCESS) { if(pNetBufferList) { FwpsFreeCloneNetBufferList(pNetBufferList, 0); pNetBufferList = 0; } if(pCompletionData) BasicPacketModificationCompletionDataDestroy(&pCompletionData, TRUE); } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- PerformBasicPacketModificationAtInboundNetwork() [status: %#x]\n", status); #endif /// DBG return status; } /** @private_function="PerformBasicPacketModificationAtOutboundNetwork" Purpose: Clones the NET_BUFFER_LIST and injects the clone back to the stack from the outgoing Network Layers using FwpsInjectNetworkSendAsync(). <br> <br> Notes: Applies to the following inbound layers: <br> FWPM_LAYER_OUTBOUND_IPPACKET_V{4/6} <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF551185.aspx <br> HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ _Check_return_ NTSTATUS PerformBasicPacketModificationAtOutboundNetwork(_In_ CLASSIFY_DATA** ppClassifyData, _In_ INJECTION_DATA** ppInjectionData, _In_ PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData, _In_ BOOLEAN isInline = FALSE) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> PerformBasicPacketModificationAtOutboundNetwork()\n"); #endif /// DBG NT_ASSERT(ppClassifyData); NT_ASSERT(ppInjectionData); NT_ASSERT(pModificationData); NT_ASSERT(*ppClassifyData); NT_ASSERT(*ppInjectionData); NTSTATUS status = STATUS_SUCCESS; FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; COMPARTMENT_ID compartmentID = UNSPECIFIED_COMPARTMENT_ID; NET_BUFFER_LIST* pNetBufferList = 0; BASIC_PACKET_MODIFICATION_COMPLETION_DATA* pCompletionData = 0; #if DBG KIRQL irql = KeGetCurrentIrql(); #endif /// DBG #pragma warning(push) #pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy HLPR_NEW(pCompletionData, BASIC_PACKET_MODIFICATION_COMPLETION_DATA, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, status); #pragma warning(pop) KeInitializeSpinLock(&(pCompletionData->spinLock)); pCompletionData->performedInline = isInline; pCompletionData->pClassifyData = *ppClassifyData; pCompletionData->pInjectionData = *ppInjectionData; /// Responsibility for freeing this memory has been transferred to the pCompletionData *ppClassifyData = 0; *ppInjectionData = 0; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_COMPARTMENT_ID)) compartmentID = (COMPARTMENT_ID)pMetadata->compartmentId; /// Initial offset is at the IP Header, so just clone the entire NET_BUFFER_LIST. status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, g_pNDISPoolData->nblPoolHandle, g_pNDISPoolData->nbPoolHandle, 0, &pNetBufferList); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtOutboundNetwork: FwpsAllocateCloneNetBufferList() [status: %#x]\n", status); HLPR_BAIL; } pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList); if(pModificationData->flags) { /// Various checks and balances must be performed to modify the Transport header at this modification point. /// Parsing of the headers will need to occur, as well as spot checking to verify everything is as it should be. /// Additionally, checksum routines will need to be written to recalculate checksums for some of the headers. /// The following block of code is to get you started with modifying the headers with info not readily available. /// (i.e. header parsing has not occurred so there is no relevant classifiable data nor metadata present). /* if(pModificationData->flags & PCPMDF_MODIFY_TRANSPORT_HEADER) { UINT32 tmpStatus = STATUS_SUCCESS; UINT8 protocol = 0; protocol = KrnlHlprIPHeaderGetProtocolField(pNetBufferList, pCompletionData->pInjectionData->addressFamily); /// The clone is at the IP Header, so advance by the size of the IP Header. NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, FALSE, 0); switch(protocol) { case IPPROTO_ICMP: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv4HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv4HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_TCP: { UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) tcpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprTCPHeaderModifySourcePort(&srcPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprTCPHeaderModifySourcePort(&dstPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_UDP: { UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) udpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprUDPHeaderModifySourcePort(&srcPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprUDPHeaderModifySourcePort(&dstPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_ICMPV6: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv6HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv6HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } } /// ToDo: Recalculate the Transport Checksum Here HLPR_BAIL_LABEL_2: /// return the data offset to the beginning of the IP Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtOutboundNetwork: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } HLPR_BAIL_ON_FAILURE(status); } */ if(pModificationData->flags & PCPMDF_MODIFY_IP_HEADER) { if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_SOURCE_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.sourceAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray16, status); value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.sourceAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifySourceAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_DESTINATION_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.destinationAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { #pragma warning(push) #pragma warning(disable: 6014) /// value.byteArray16 will be freed in with call to KrnlHlprFwpValuePurgeLocalCopy HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray16, status); #pragma warning(pop) value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.destinationAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifyDestinationAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } } } status = FwpsInjectNetworkSendAsync(pCompletionData->pInjectionData->injectionHandle, pCompletionData->pInjectionData->injectionContext, 0, compartmentID, pNetBufferList, CompleteBasicPacketModification, pCompletionData); NT_ASSERT(irql == KeGetCurrentIrql()); if(status != STATUS_SUCCESS) DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtOutboundNetwork: FwpsInjectNetworkSendAsync() [status: %#x]\n", status); HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); if(status != STATUS_SUCCESS) { if(pNetBufferList) { FwpsFreeCloneNetBufferList(pNetBufferList, 0); pNetBufferList = 0; } if(pCompletionData) BasicPacketModificationCompletionDataDestroy(&pCompletionData, TRUE); } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- PerformBasicPacketModificationAtOutboundNetwork() [status: %#x]\n", status); #endif /// DBG return status; } /** @private_function="PerformBasicPacketModificationAtForward" Purpose: Clones the NET_BUFFER_LIST, modifies it with data from the associated context and injects the clone back to the stack's forward path using FwpsInjectForwardAsync(). <br> <br> Notes: Applies to the following forwarding layers: <br> FWPM_LAYER_IPFORWARD_V{4/6} <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF551186.aspx <br> HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ _Check_return_ NTSTATUS PerformBasicPacketModificationAtForward(_In_ CLASSIFY_DATA** ppClassifyData, _In_ INJECTION_DATA** ppInjectionData, _In_ PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData, _In_ BOOLEAN isInline = FALSE) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> PerformBasicPacketModificationAtForward()\n"); #endif /// DBG NT_ASSERT(ppClassifyData); NT_ASSERT(ppInjectionData); NT_ASSERT(pModificationData); NT_ASSERT(*ppClassifyData); NT_ASSERT(*ppInjectionData); NTSTATUS status = STATUS_SUCCESS; FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; COMPARTMENT_ID compartmentID = UNSPECIFIED_COMPARTMENT_ID; IF_INDEX interfaceIndex = 0; UINT32 flags = 0; NET_BUFFER_LIST* pNetBufferList = 0; BASIC_PACKET_MODIFICATION_COMPLETION_DATA* pCompletionData = 0; UINT32 ipHeaderSize = 0; FWP_VALUE* pInterfaceIndex = 0; FWP_VALUE* pFlags = 0; NDIS_TCP_IP_CHECKSUM_PACKET_INFO checksumInfo = {0}; #if DBG KIRQL irql = KeGetCurrentIrql(); #endif /// DBG #pragma warning(push) #pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy HLPR_NEW(pCompletionData, BASIC_PACKET_MODIFICATION_COMPLETION_DATA, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, status); #pragma warning(pop) KeInitializeSpinLock(&(pCompletionData->spinLock)); pCompletionData->performedInline = isInline; pCompletionData->pClassifyData = *ppClassifyData; pCompletionData->pInjectionData = *ppInjectionData; /// Responsibility for freeing this memory has been transferred to the pCompletionData *ppClassifyData = 0; *ppInjectionData = 0; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_COMPARTMENT_ID)) compartmentID = (COMPARTMENT_ID)pMetadata->compartmentId; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_IP_HEADER_SIZE)) ipHeaderSize = pMetadata->ipHeaderSize; pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_DESTINATION_INTERFACE_INDEX); if(pInterfaceIndex && pInterfaceIndex->type == FWP_UINT32) interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32; pFlags = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_FLAGS); if(pFlags && pFlags->type == FWP_UINT32) flags = pFlags->uint32; /// Initial offset is at the IP Header, so just clone the entire NET_BUFFER_LIST. status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, g_pNDISPoolData->nblPoolHandle, g_pNDISPoolData->nbPoolHandle, 0, &pNetBufferList); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtForward: FwpsAllocateCloneNetBufferList() [status: %#x]\n", status); HLPR_BAIL; } checksumInfo.Value = (ULONG)(ULONG_PTR)NET_BUFFER_LIST_INFO((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, TcpIpChecksumNetBufferListInfo); /// Handle if this packet had the IP checksum offloaded or if it's loopback if(KrnlHlprFwpmLayerIsIPv4(pClassifyValues->layerId) && checksumInfo.Receive.NdisPacketIpChecksumSucceeded || flags & FWP_CONDITION_FLAG_IS_LOOPBACK) { IP_HEADER_V4* pIPv4Header = 0; BOOLEAN needToFree = FALSE; status = KrnlHlprIPHeaderGet(pNetBufferList, (VOID**)&pIPv4Header, &needToFree, ipHeaderSize); if(status == STATUS_SUCCESS) { /// prevent TCP/IP Zone crossing if(flags & FWP_CONDITION_FLAG_IS_LOOPBACK) RtlCopyMemory(pIPv4Header->pDestinationAddress, pIPv4Header->pSourceAddress, sizeof(UINT32)); KrnlHlprIPHeaderCalculateV4Checksum(pIPv4Header, ipHeaderSize); } if(needToFree) KrnlHlprIPHeaderDestroy((VOID**)&pIPv4Header); } pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList); if(pModificationData->flags) { /// Various checks and balances must be performed to modify the Transport header at this modification point. /// Parsing of the headers will need to occur, as well as spot checking to verify everything is as it should be. /// Additionally, checksum routines will need to be written to recalculate checksums for some of the headers. /// The following block of code is to get you started with modifying the headers with info not readily available. /// (i.e. header parsing has not occurred so there is no relevant classifiable data nor metadata present). /* if(pModificationData->flags & PCPMDF_MODIFY_TRANSPORT_HEADER) { UINT32 tmpStatus = STATUS_SUCCESS; UINT8 protocol = 0; protocol = KrnlHlprIPHeaderGetProtocolField(pNetBufferList, pCompletionData->pInjectionData->addressFamily); /// The clone is at the IP Header, so advance by the size of the IP Header. NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, FALSE, 0); switch(protocol) { case IPPROTO_ICMP: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv4HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv4HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_TCP: { UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) tcpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprTCPHeaderModifySourcePort(&srcPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprTCPHeaderModifySourcePort(&dstPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_UDP: { UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) udpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprUDPHeaderModifySourcePort(&srcPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprUDPHeaderModifySourcePort(&dstPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_ICMPV6: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv6HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv6HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } } /// ToDo: Recalculate the Transport Checksum Here HLPR_BAIL_LABEL_2: /// return the data offset to the beginning of the IP Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtForward: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } HLPR_BAIL_ON_FAILURE(status); } */ if(pModificationData->flags & PCPMDF_MODIFY_IP_HEADER) { if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_SOURCE_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.sourceAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray16, status); value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.sourceAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifySourceAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_DESTINATION_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.destinationAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { #pragma warning(push) #pragma warning(disable: 6014) /// value.byteArray16 will be freed in with call to KrnlHlprFwpValuePurgeLocalCopy HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray16, status); #pragma warning(pop) value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.destinationAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifyDestinationAddress(&value, pNetBufferList, TRUE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } } } status = FwpsInjectForwardAsync(pCompletionData->pInjectionData->injectionHandle, pCompletionData->pInjectionData->injectionContext, 0, pCompletionData->pInjectionData->addressFamily, compartmentID, interfaceIndex, pNetBufferList, CompleteBasicPacketModification, pCompletionData); NT_ASSERT(irql == KeGetCurrentIrql()); if(status != STATUS_SUCCESS) DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtForward: FwpsInjectForwardAsync() [status: %#x]\n", status); HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); if(status != STATUS_SUCCESS) { if(pNetBufferList) { FwpsFreeCloneNetBufferList(pNetBufferList, 0); pNetBufferList = 0; } if(pCompletionData) BasicPacketModificationCompletionDataDestroy(&pCompletionData, TRUE); } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- PerformBasicPacketModificationAtForward() [status: %#x]\n", status); #endif /// DBG return status; } /** @private_function="PerformBasicPacketModificationAtInboundTransport" Purpose: Clones the NET_BUFFER_LIST, modifies it with data from the associated context, and injects the clone back to the stack's inbound path from the incoming Transport Layers using FwpsInjectTransportRecveiveAsync(). <br> <br> Notes: Applies to the following inbound layers: <br> FWPM_LAYER_INBOUND_TRANSPORT_V{4/6} <br> FWPM_LAYER_INBOUND_ICMP_ERROR_V{4/6} <br> FWPM_LAYER_DATAGRAM_DATA_V{4/6} (Inbound only) <br> FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V{4/6} (Inbound only) <br> FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V{4/6} (Inbound only) <br> FWPM_LAYER_ALE_AUTH_CONNECT_V{4/6} (Inbound, reauthorization only) <br> FWPM_LAYER_ALE_FLOW_ESTABLISHED_V{4/6} (Inbound, non-TCP only) <br> FWPM_LAYER_STREAM_PACKET_V{4/6} (Inbound only) <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF551186.aspx <br> HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ _Check_return_ NTSTATUS PerformBasicPacketModificationAtInboundTransport(_In_ CLASSIFY_DATA** ppClassifyData, _In_ INJECTION_DATA** ppInjectionData, _In_ PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData, _In_ BOOLEAN isInline = FALSE) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> PerformBasicPacketModificationAtInboundTransport()\n"); #endif /// DBG NT_ASSERT(ppClassifyData); NT_ASSERT(ppInjectionData); NT_ASSERT(pModificationData); NT_ASSERT(*ppClassifyData); NT_ASSERT(*ppInjectionData); NTSTATUS status = STATUS_SUCCESS; FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; COMPARTMENT_ID compartmentID = UNSPECIFIED_COMPARTMENT_ID; IF_INDEX interfaceIndex = 0; IF_INDEX subInterfaceIndex = 0; UINT32 flags = 0; NET_BUFFER_LIST* pNetBufferList = 0; BASIC_PACKET_MODIFICATION_COMPLETION_DATA* pCompletionData = 0; UINT32 ipHeaderSize = 0; UINT32 bytesRetreated = 0; UINT8 protocol = 0; FWP_VALUE* pProtocol = 0; FWP_VALUE* pInterfaceIndex = 0; FWP_VALUE* pSubInterfaceIndex = 0; FWP_VALUE* pFlags = 0; FWPS_PACKET_LIST_INFORMATION* pPacketInformation = 0; BOOLEAN bypassInjection = FALSE; UINT64 endpointHandle = 0; BYTE* pSourceAddress = 0; BYTE* pDestinationAddress = 0; NDIS_TCP_IP_CHECKSUM_PACKET_INFO checksumInfo = {0}; #if DBG KIRQL irql = KeGetCurrentIrql(); #endif /// DBG #pragma warning(push) #pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy HLPR_NEW(pCompletionData, BASIC_PACKET_MODIFICATION_COMPLETION_DATA, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, status); #pragma warning(pop) KeInitializeSpinLock(&(pCompletionData->spinLock)); pCompletionData->performedInline = isInline; pCompletionData->pClassifyData = *ppClassifyData; pCompletionData->pInjectionData = *ppInjectionData; /// Responsibility for freeing this memory has been transferred to the pCompletionData *ppClassifyData = 0; *ppInjectionData = 0; HLPR_NEW(pPacketInformation, FWPS_PACKET_LIST_INFORMATION, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pPacketInformation, status); pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_INTERFACE_INDEX); if(pInterfaceIndex && pInterfaceIndex->type == FWP_UINT32) interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32; pSubInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_SUB_INTERFACE_INDEX); if(pSubInterfaceIndex && pSubInterfaceIndex->type == FWP_UINT32) subInterfaceIndex = (IF_INDEX)pSubInterfaceIndex->uint32; pFlags = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_FLAGS); if(pFlags && pFlags->type == FWP_UINT32) flags = pFlags->uint32; if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4) protocol = ICMPV4; else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6) protocol = ICMPV6; #if(NTDDI_VERSION >= NTDDI_WIN7) else if(pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6) protocol = TCP; #endif /// (NTDDI_VERSION >= NTDDI_WIN7) else { pProtocol = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_PROTOCOL); HLPR_BAIL_ON_NULL_POINTER(pProtocol); protocol = pProtocol->uint8; } if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_COMPARTMENT_ID)) compartmentID = (COMPARTMENT_ID)pMetadata->compartmentId; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_IP_HEADER_SIZE)) bytesRetreated = ipHeaderSize = pMetadata->ipHeaderSize; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE) && protocol != ICMPV4 && protocol != ICMPV6) bytesRetreated += pMetadata->transportHeaderSize; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE)) endpointHandle = pMetadata->transportEndpointHandle; /// Query to see if IPsec has applied tunnel mode SA's to this NET_BUFFER_LIST ... status = FwpsGetPacketListSecurityInformation((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, FWPS_PACKET_LIST_INFORMATION_QUERY_ALL_INBOUND, pPacketInformation); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundTransport: FwpsGetPacketListSecurityInformation() [status: %#x]\n", status); HLPR_BAIL; } /// ... if it has, then bypass the injection until the NET_BUFFER_LIST has come out of the tunnel if((pPacketInformation->ipsecInformation.inbound.isTunnelMode && !(pPacketInformation->ipsecInformation.inbound.isDeTunneled)) || pPacketInformation->ipsecInformation.inbound.isSecure) { bypassInjection = TRUE; HLPR_BAIL; } /// Initial offset is at the data, so retreat the size of the IP Header and Transport Header ... /// except for ICMP, offset is at the ICMP Header, so retreat the size of the IP Header ... status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), bytesRetreated, 0, 0); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundTransport: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } /// ... clone the entire NET_BUFFER_LIST ... status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, g_pNDISPoolData->nblPoolHandle, g_pNDISPoolData->nbPoolHandle, 0, &pNetBufferList); /// ... and advance the offset back to the original position. NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket), bytesRetreated, FALSE, 0); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundTransport: FwpsAllocateCloneNetBufferList() [status: %#x]\n", status); HLPR_BAIL; } checksumInfo.Value = (ULONG)(ULONG_PTR)NET_BUFFER_LIST_INFO((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, TcpIpChecksumNetBufferListInfo); /// Handle if the packet was IPsec secured if(pCompletionData->pInjectionData->isIPsecSecured) { /// For performance reasons, IPsec leaves the original ESP / AH information in the IP Header ... UINT32 headerIncludeSize = 0; IPPROTO protocol = IPPROTO_MAX; UINT32 ipv4Address = 0; UINT32 addressSize = 0; FWP_VALUE* pRemoteAddressValue = 0; FWP_VALUE* pLocalAddressValue = 0; FWP_VALUE* pProtocolValue = 0; pRemoteAddressValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_REMOTE_ADDRESS); if(pRemoteAddressValue) { if(pRemoteAddressValue->type == FWP_BYTE_ARRAY16_TYPE) addressSize = IPV6_ADDRESS_SIZE; else addressSize = IPV4_ADDRESS_SIZE; HLPR_NEW_ARRAY(pSourceAddress, BYTE, addressSize, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pSourceAddress, status); if(pRemoteAddressValue->type == FWP_BYTE_ARRAY16_TYPE) RtlCopyMemory(pSourceAddress, pRemoteAddressValue->byteArray16->byteArray16, addressSize); else { ipv4Address = htonl(pRemoteAddressValue->uint32); RtlCopyMemory(pSourceAddress, &ipv4Address, addressSize); } } pLocalAddressValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_LOCAL_ADDRESS); if(pLocalAddressValue) { if(pLocalAddressValue->type == FWP_BYTE_ARRAY16_TYPE) addressSize = IPV6_ADDRESS_SIZE; else addressSize = IPV4_ADDRESS_SIZE; HLPR_NEW_ARRAY(pDestinationAddress, BYTE, addressSize, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pDestinationAddress, status); if(pLocalAddressValue->type == FWP_BYTE_ARRAY16_TYPE) RtlCopyMemory(pDestinationAddress, pLocalAddressValue->byteArray16->byteArray16, addressSize); else { ipv4Address = htonl(pLocalAddressValue->uint32); RtlCopyMemory(pDestinationAddress, &ipv4Address, addressSize); } } pProtocolValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_PROTOCOL); if(pProtocolValue && pProtocolValue->type == FWP_UINT8) protocol = (IPPROTO)pProtocolValue->uint8; #if (NTDDI_VERSION >= NTDDI_WIN6SP1) if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_INCLUDE_HEADER)) headerIncludeSize = pMetadata->headerIncludeHeaderLength; #endif // (NTDDI_VERSION >= NTDDI_WIN6SP1) if(pSourceAddress == 0 || pDestinationAddress == 0) { status = STATUS_INVALID_MEMBER; DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundTransport() [status: %#x][pSourceAddress: %#p][pDestinationAddress: %#p]\n", status, pSourceAddress, pDestinationAddress); HLPR_BAIL; } /// ... so we must re-construct the IPHeader with the appropriate information /// for checksum offload, this will recalculate the checksums status = FwpsConstructIpHeaderForTransportPacket(pNetBufferList, headerIncludeSize, pCompletionData->pInjectionData->addressFamily, pSourceAddress, pDestinationAddress, protocol, endpointHandle, 0, 0, 0, 0, interfaceIndex, subInterfaceIndex); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketInjectionAtInboundTransport: FwpsConstructIpHeaderForTransportPacket() [status: %#x]\n", status); HLPR_BAIL; } } /// Handle if this packet had the IP or Transport checksums offloaded or if it's loopback else if(checksumInfo.Receive.NdisPacketIpChecksumSucceeded || checksumInfo.Receive.NdisPacketTcpChecksumSucceeded || checksumInfo.Receive.NdisPacketUdpChecksumSucceeded || flags & FWP_CONDITION_FLAG_IS_LOOPBACK) { NTSTATUS tempStatus = STATUS_SUCCESS; IP_HEADER_V4* pIPv4Header = 0; BOOLEAN needToFree = FALSE; tempStatus = KrnlHlprIPHeaderGet(pNetBufferList, (VOID**)&pIPv4Header, &needToFree, ipHeaderSize); if(tempStatus == STATUS_SUCCESS) { /// prevent TCP/IP Zone crossing if(flags & FWP_CONDITION_FLAG_IS_LOOPBACK) RtlCopyMemory(pIPv4Header->pDestinationAddress, pIPv4Header->pSourceAddress, sizeof(UINT32)); KrnlHlprIPHeaderCalculateV4Checksum(pIPv4Header, ipHeaderSize); } if(needToFree) KrnlHlprIPHeaderDestroy((VOID**)&pIPv4Header); } pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList); if(pModificationData->flags) { FWP_VALUE* pLocalAddressValue = 0; FWP_VALUE* pRemoteAddressValue = 0; BYTE pIPDestinationAddress[16] = {0}; BYTE pIPSourceAddress[16] = {0}; pRemoteAddressValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_REMOTE_ADDRESS); HLPR_BAIL_ON_NULL_POINTER_WITH_STATUS(pRemoteAddressValue, status); pLocalAddressValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_LOCAL_ADDRESS); HLPR_BAIL_ON_NULL_POINTER_WITH_STATUS(pLocalAddressValue, status); if(pCompletionData->pInjectionData->addressFamily == AF_INET6) { RtlCopyMemory(pIPSourceAddress, pRemoteAddressValue->byteArray16->byteArray16, IPV6_ADDRESS_SIZE); RtlCopyMemory(pIPDestinationAddress, pLocalAddressValue->byteArray16->byteArray16, IPV6_ADDRESS_SIZE); } else { RtlCopyMemory(pIPSourceAddress, &(pRemoteAddressValue->uint32), IPV4_ADDRESS_SIZE); RtlCopyMemory(pIPDestinationAddress, &(pLocalAddressValue->uint32), IPV4_ADDRESS_SIZE); } if(pModificationData->flags & PCPMDF_MODIFY_TRANSPORT_HEADER) { UINT32 tmpStatus = STATUS_SUCCESS; FWP_VALUE* pProtocolValue = 0; UINT8 protocol = 0; /// The clone is at the IP Header, so advance by the size of the IP Header. NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, FALSE, 0); pProtocolValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_PROTOCOL); if(pProtocolValue && pProtocolValue->type == FWP_UINT8) protocol = pProtocolValue->uint8; if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4) protocol = IPPROTO_ICMP; else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6) protocol = IPPROTO_ICMPV6; switch(protocol) { case IPPROTO_ICMP: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv4HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv4HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_TCP: { UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) tcpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprTCPHeaderModifySourcePort(&srcPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprTCPHeaderModifySourcePort(&dstPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_UDP: { UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) udpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprUDPHeaderModifySourcePort(&srcPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprUDPHeaderModifySourcePort(&dstPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } case IPPROTO_ICMPV6: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv6HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv6HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE_2(status); } break; } } HLPR_BAIL_LABEL_2: /// return the data offset to the beginning of the IP Header tmpStatus = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB(pNetBufferList), ipHeaderSize, 0, 0); if(tmpStatus != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtInboundTransport: NdisRetreatNetBufferDataStart() [status: %#x]\n", status); HLPR_BAIL; } HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->flags & PCPMDF_MODIFY_IP_HEADER) { if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_SOURCE_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.sourceAddress.pIPv4, IPV4_ADDRESS_SIZE); RtlCopyMemory(pIPSourceAddress, pModificationData->ipData.sourceAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray16, status); value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.sourceAddress.pIPv6, IPV6_ADDRESS_SIZE); RtlCopyMemory(pIPSourceAddress, pModificationData->ipData.sourceAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifySourceAddress(&value, pNetBufferList, FALSE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_DESTINATION_ADDRESS) { FWP_VALUE value; RtlZeroMemory(&value, sizeof(FWP_VALUE)); if(pCompletionData->pInjectionData->addressFamily == AF_INET) { value.type = FWP_UINT32; RtlCopyMemory(&(value.uint32), pModificationData->ipData.destinationAddress.pIPv4, IPV4_ADDRESS_SIZE); RtlCopyMemory(pIPDestinationAddress, pModificationData->ipData.destinationAddress.pIPv4, IPV4_ADDRESS_SIZE); } else { #pragma warning(push) #pragma warning(disable: 6014) /// value.byteArray16 will be freed in with call to KrnlHlprFwpValuePurgeLocalCopy HLPR_NEW(value.byteArray16, FWP_BYTE_ARRAY16, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(value.byteArray16, status); #pragma warning(pop) value.type = FWP_BYTE_ARRAY16_TYPE; RtlCopyMemory(value.byteArray16->byteArray16, pModificationData->ipData.destinationAddress.pIPv6, IPV6_ADDRESS_SIZE); RtlCopyMemory(pIPDestinationAddress, pModificationData->ipData.destinationAddress.pIPv6, IPV6_ADDRESS_SIZE); } status = KrnlHlprIPHeaderModifyDestinationAddress(&value, pNetBufferList, FALSE); KrnlHlprFwpValuePurgeLocalCopy(&value); HLPR_BAIL_ON_FAILURE(status); } } status = FwpsConstructIpHeaderForTransportPacket(pNetBufferList, ipHeaderSize, pCompletionData->pInjectionData->addressFamily, (UCHAR*)pIPSourceAddress, (UCHAR*)pIPDestinationAddress, (IPPROTO)protocol, endpointHandle, 0, 0, 0, 0, interfaceIndex, subInterfaceIndex); HLPR_BAIL_ON_FAILURE(status); } status = FwpsInjectTransportReceiveAsync(pCompletionData->pInjectionData->injectionHandle, pCompletionData->pInjectionData->injectionContext, 0, 0, pCompletionData->pInjectionData->addressFamily, compartmentID, interfaceIndex, subInterfaceIndex, pNetBufferList, CompleteBasicPacketModification, pCompletionData); NT_ASSERT(irql == KeGetCurrentIrql()); if(status != STATUS_SUCCESS) DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketInjectionAtInboundTransport: FwpsInjectTransportReceiveAsync() [status: %#x]\n", status); HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); if(status != STATUS_SUCCESS || bypassInjection) { if(pNetBufferList) { FwpsFreeCloneNetBufferList(pNetBufferList, 0); pNetBufferList = 0; } if(pCompletionData) BasicPacketModificationCompletionDataDestroy(&pCompletionData, TRUE); } HLPR_DELETE_ARRAY(pSourceAddress, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_DELETE_ARRAY(pDestinationAddress, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_DELETE(pPacketInformation, WFPSAMPLER_CALLOUT_DRIVER_TAG); #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- PerformBasicPacketModificationAtInboundTransport() [status: %#x]\n", status); #endif /// DBG return status; } /** @private_function="PerformBasicPacketModificationAtOutboundTransport" Purpose: Clones the NET_BUFFER_LIST, modifies it with data from the associated context, and injects the clone back to the stack's outbound path from the outgoing Transport Layers using FwpsInjectTransportSendAsync(). <br> <br> Notes: Applies to the following outbound layers: <br> FWPM_LAYER_OUTBOUND_TRANSPORT_V{4/6} <br> FWPM_LAYER_OUTBOUND_ICMP_ERROR_V{4/6} <br> FWPM_LAYER_DATAGRAM_DATA_V{4/6} (Outbound only) <br> FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V{4/6} (Outbound only) <br> FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V{4/6} (Outbound only) <br> FWPM_LAYER_ALE_AUTH_CONNECT_V{4/6} (Outbound, reauthorization only) <br> FWPM_LAYER_ALE_FLOW_ESTABLISHED_V{4/6} (Outbound, non-TCP only) <br> FWPM_LAYER_STREAM_PACKET_V{4/6} (Outbound only) <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF551188.aspx <br> HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF546324.aspx <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ _Check_return_ NTSTATUS PerformBasicPacketModificationAtOutboundTransport(_In_ CLASSIFY_DATA** ppClassifyData, _In_ INJECTION_DATA** ppInjectionData, _In_ PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData, _In_ BOOLEAN isInline = FALSE) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> PerformBasicPacketModificationAtOutboundTransport()\n"); #endif /// DBG NT_ASSERT(ppClassifyData); NT_ASSERT(ppInjectionData); NT_ASSERT(pModificationData); NT_ASSERT(*ppClassifyData); NT_ASSERT(*ppInjectionData); NTSTATUS status = STATUS_SUCCESS; FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)(*ppClassifyData)->pClassifyValues; FWPS_INCOMING_METADATA_VALUES* pMetadata = (FWPS_INCOMING_METADATA_VALUES*)(*ppClassifyData)->pMetadataValues; UINT64 endpointHandle = 0; FWPS_TRANSPORT_SEND_PARAMS* pSendParams = 0; COMPARTMENT_ID compartmentID = UNSPECIFIED_COMPARTMENT_ID; NET_BUFFER_LIST* pNetBufferList = 0; BASIC_PACKET_MODIFICATION_COMPLETION_DATA* pCompletionData = 0; BYTE* pRemoteAddress = 0; FWP_VALUE* pAddressValue = 0; #if DBG KIRQL irql = KeGetCurrentIrql(); #endif /// DBG #pragma warning(push) #pragma warning(disable: 6014) /// pCompletionData & pSendArgs will be freed in completionFn using BasicPacketModificationCompletionDataDestroy HLPR_NEW(pCompletionData, BASIC_PACKET_MODIFICATION_COMPLETION_DATA, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pCompletionData, status); HLPR_NEW(pSendParams, FWPS_TRANSPORT_SEND_PARAMS, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pSendParams, status); #pragma warning(pop) KeInitializeSpinLock(&(pCompletionData->spinLock)); pCompletionData->performedInline = isInline; pCompletionData->pClassifyData = *ppClassifyData; pCompletionData->pInjectionData = *ppInjectionData; pCompletionData->pSendParams = pSendParams; /// Responsibility for freeing this memory has been transferred to the pCompletionData *ppClassifyData = 0; *ppInjectionData = 0; pSendParams = 0; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE)) endpointHandle = pMetadata->transportEndpointHandle; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_COMPARTMENT_ID)) compartmentID = (COMPARTMENT_ID)pMetadata->compartmentId; pAddressValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_REMOTE_ADDRESS); if(pAddressValue) { if(pCompletionData->pInjectionData->addressFamily == AF_INET) { UINT32 tempAddress = htonl(pAddressValue->uint32); HLPR_NEW_ARRAY(pRemoteAddress, BYTE, IPV4_ADDRESS_SIZE, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pRemoteAddress, status); RtlCopyMemory(pRemoteAddress, &tempAddress, IPV4_ADDRESS_SIZE); } else { #pragma warning(push) #pragma warning(disable: 6014) /// pRemoteAddress will be freed in completionFn using BasicPacketModificationCompletionDataDestroy HLPR_NEW_ARRAY(pRemoteAddress, BYTE, IPV6_ADDRESS_SIZE, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pRemoteAddress, status); #pragma warning(pop) RtlCopyMemory(pRemoteAddress, pAddressValue->byteArray16->byteArray16, IPV6_ADDRESS_SIZE); if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_REMOTE_SCOPE_ID)) pCompletionData->pSendParams->remoteScopeId = pMetadata->remoteScopeId; } pCompletionData->pSendParams->remoteAddress = pRemoteAddress; } /// Initial offset is at Transport Header, so just clone entire NET_BUFFER_LIST. status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket, g_pNDISPoolData->nblPoolHandle, g_pNDISPoolData->nbPoolHandle, 0, &pNetBufferList); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtOutboundTransport: FwpsAllocateCloneNetBufferList() [status: %#x]\n", status); HLPR_BAIL; } pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList); if(pModificationData->flags) { if(pModificationData->flags & PCPMDF_MODIFY_TRANSPORT_HEADER) { FWP_VALUE* pProtocolValue = 0; UINT8 protocol = 0; pProtocolValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_PROTOCOL); if(pProtocolValue && pProtocolValue->type == FWP_UINT8) protocol = pProtocolValue->uint8; if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4) protocol = IPPROTO_ICMP; else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6) protocol = IPPROTO_ICMPV6; switch(protocol) { case IPPROTO_ICMP: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv4HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv4HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE(status); } break; } case IPPROTO_TCP: { UINT32 tcpHeaderSize = TCP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) tcpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprTCPHeaderModifySourcePort(&srcPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprTCPHeaderModifySourcePort(&dstPort, pNetBufferList, tcpHeaderSize); HLPR_BAIL_ON_FAILURE(status); } break; } case IPPROTO_UDP: { UINT32 udpHeaderSize = UDP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) udpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_SOURCE_PORT) { FWP_VALUE0 srcPort; srcPort.type = FWP_UINT16; srcPort.uint16 = pModificationData->transportData.sourcePort; status = KrnlHlprUDPHeaderModifySourcePort(&srcPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_DESTINATION_PORT) { FWP_VALUE0 dstPort; dstPort.type = FWP_UINT16; dstPort.uint16 = pModificationData->transportData.destinationPort; status = KrnlHlprUDPHeaderModifySourcePort(&dstPort, pNetBufferList, udpHeaderSize); HLPR_BAIL_ON_FAILURE(status); } break; } case IPPROTO_ICMPV6: { UINT32 icmpHeaderSize = ICMP_HEADER_MIN_SIZE; if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE)) icmpHeaderSize = pMetadata->transportHeaderSize; if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_TYPE) { FWP_VALUE0 icmpType; icmpType.type = FWP_UINT8; icmpType.uint8 = (UINT8)ntohs(pModificationData->transportData.sourcePort); status = KrnlHlprICMPv6HeaderModifyType(&icmpType, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE(status); } if(pModificationData->transportData.flags & PCPMDF_MODIFY_TRANSPORT_HEADER_ICMP_CODE) { FWP_VALUE0 icmpCode; icmpCode.type = FWP_UINT8; icmpCode.uint8 = (UINT8)ntohs(pModificationData->transportData.destinationPort); status = KrnlHlprICMPv6HeaderModifyCode(&icmpCode, pNetBufferList, icmpHeaderSize); HLPR_BAIL_ON_FAILURE(status); } break; } } } /// As there is no IP Header yet, we can only modify the destination IP address via the FWPS_TRANSPORT_SEND_PARAMS if(pModificationData->flags & PCPMDF_MODIFY_IP_HEADER) { if(pModificationData->ipData.flags & PCPMDF_MODIFY_IP_HEADER_DESTINATION_ADDRESS) { if(pCompletionData->pInjectionData->addressFamily == AF_INET) RtlCopyMemory(pCompletionData->pSendParams->remoteAddress, pModificationData->ipData.destinationAddress.pIPv4, IPV4_ADDRESS_SIZE); else RtlCopyMemory(pCompletionData->pSendParams->remoteAddress, pModificationData->ipData.destinationAddress.pIPv6, IPV6_ADDRESS_SIZE); } } } status = FwpsInjectTransportSendAsync(pCompletionData->pInjectionData->injectionHandle, pCompletionData->pInjectionData->injectionContext, endpointHandle, 0, pCompletionData->pSendParams, pCompletionData->pInjectionData->addressFamily, compartmentID, pNetBufferList, CompleteBasicPacketModification, pCompletionData); NT_ASSERT(irql == KeGetCurrentIrql()); if(status != STATUS_SUCCESS) DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! PerformBasicPacketModificationAtOutboundTransport: FwpsInjectTransportSendAsync() [status: %#x]\n", status); HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); if(status != STATUS_SUCCESS) { if(pNetBufferList) { FwpsFreeCloneNetBufferList(pNetBufferList, 0); pNetBufferList = 0; } if(pCompletionData) BasicPacketModificationCompletionDataDestroy(&pCompletionData, TRUE); } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- PerformBasicPacketModificationAtOutboundTransport() [status: %#x]\n", status); #endif /// DBG return status; } /** @private_function="BasicPacketModificationDeferredProcedureCall" Purpose: Invokes the appropriate private injection routine to perform the injection at DISPATCH_LEVEL. <br> <br> Notes: <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF542972.aspx <br> */ _IRQL_requires_(DISPATCH_LEVEL) _IRQL_requires_same_ _Function_class_(KDEFERRED_ROUTINE) VOID BasicPacketModificationDeferredProcedureCall(_In_ KDPC* pDPC, _In_opt_ PVOID pContext, _In_opt_ PVOID pArg1, _In_opt_ PVOID pArg2) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> BasicPacketModificationDeferredProcedureCall()\n"); #endif /// DBG UNREFERENCED_PARAMETER(pDPC); UNREFERENCED_PARAMETER(pContext); UNREFERENCED_PARAMETER(pArg2); NT_ASSERT(pDPC); NT_ASSERT(pArg1); NT_ASSERT(((DPC_DATA*)pArg1)->pClassifyData); NT_ASSERT(((DPC_DATA*)pArg1)->pInjectionData); DPC_DATA* pDPCData = (DPC_DATA*)pArg1; if(pDPCData) { NTSTATUS status = STATUS_SUCCESS; FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)pDPCData->pClassifyData->pClassifyValues; FWPS_FILTER* pFilter = (FWPS_FILTER*)pDPCData->pClassifyData->pFilter; PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData = (PC_BASIC_PACKET_MODIFICATION_DATA*)pFilter->providerContext->dataBuffer->data; if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) status = PerformBasicPacketModificationAtInboundNetwork(&(pDPCData->pClassifyData), &(pDPCData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6) status = PerformBasicPacketModificationAtOutboundNetwork(&(pDPCData->pClassifyData), &(pDPCData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6) status = PerformBasicPacketModificationAtForward(&(pDPCData->pClassifyData), &(pDPCData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V6 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || (pDPCData->pInjectionData->direction == FWP_DIRECTION_INBOUND && (pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || /// Policy Change Reauthorization pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || /// Policy Change Reauthorization pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6))) status = PerformBasicPacketModificationAtInboundTransport(&(pDPCData->pClassifyData), &(pDPCData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6 || (pDPCData->pInjectionData->direction == FWP_DIRECTION_OUTBOUND && (pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || /// Policy Change Reauthorization pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || /// Policy Change Reauthorization pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6))) status = PerformBasicPacketModificationAtOutboundTransport(&(pDPCData->pClassifyData), &(pDPCData->pInjectionData), pModificationData, FALSE); #if(NTDDI_VERSION >= NTDDI_WIN7) else if(pDPCData->pInjectionData->direction == FWP_DIRECTION_INBOUND && (pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)) status = PerformBasicPacketModificationAtInboundTransport(&(pDPCData->pClassifyData), &(pDPCData->pInjectionData), pModificationData, FALSE); else if(pDPCData->pInjectionData->direction == FWP_DIRECTION_OUTBOUND && (pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)) status = PerformBasicPacketModificationAtOutboundTransport(&(pDPCData->pClassifyData), &(pDPCData->pInjectionData), pModificationData, FALSE); #if(NTDDI_VERSION >= NTDDI_WIN8) else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET || pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE) status = PerformBasicPacketModificationAtInboundMACFrame(&(pDPCData->pClassifyData), &(pDPCData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE) status = PerformBasicPacketModificationAtOutboundMACFrame(&(pDPCData->pClassifyData), &(pDPCData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_INGRESS_VSWITCH_ETHERNET) status = PerformBasicPacketModificationAtIngressVSwitchEthernet(&(pDPCData->pClassifyData), &(pDPCData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_EGRESS_VSWITCH_ETHERNET) status = PerformBasicPacketModificationAtEgressVSwitchEthernet(&(pDPCData->pClassifyData), &(pDPCData->pInjectionData), pModificationData, FALSE); #endif // (NTDDI_VERSION >= NTDDI_WIN8) #endif // (NTDDI_VERSION >= NTDDI_WIN7) else DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! BasicPacketModificationDeferredProcedureCall() [status: %#x]\n", (UINT32)STATUS_NOT_SUPPORTED); if(status != STATUS_SUCCESS) { if(pDPCData->pClassifyData) KrnlHlprClassifyDataDestroyLocalCopy(&(pDPCData->pClassifyData)); if(pDPCData->pInjectionData) KrnlHlprInjectionDataDestroy(&(pDPCData->pInjectionData)); DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! BasicPacketModificationDeferredProcedureCall: PerformBasicPacketModification() [status: %#x]\n", status); } KrnlHlprDPCDataDestroy(&pDPCData); } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- BasicPacketModificationDeferredProcedureCall()\n"); #endif /// DBG return; } /** @private_function="BasicPacketModificationWorkItemRoutine" Purpose: Invokes the appropriate private routine to perform the modification and injection at PASSIVE_LEVEL. <br> <br> Notes: <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF566380.aspx <br> */ _IRQL_requires_(PASSIVE_LEVEL) _IRQL_requires_same_ _Function_class_(IO_WORKITEM_ROUTINE) VOID BasicPacketModificationWorkItemRoutine(_In_ PDEVICE_OBJECT pDeviceObject, _Inout_opt_ PVOID pContext) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> BasicPacketModificationWorkItemRoutine()\n"); #endif /// DBG UNREFERENCED_PARAMETER(pDeviceObject); NT_ASSERT(pContext); NT_ASSERT(((WORKITEM_DATA*)pContext)->pClassifyData); NT_ASSERT(((WORKITEM_DATA*)pContext)->pInjectionData); WORKITEM_DATA* pWorkItemData = (WORKITEM_DATA*)pContext; if(pWorkItemData) { NTSTATUS status = STATUS_SUCCESS; FWPS_INCOMING_VALUES* pClassifyValues = (FWPS_INCOMING_VALUES*)pWorkItemData->pClassifyData->pClassifyValues; FWPS_FILTER* pFilter = (FWPS_FILTER*)pWorkItemData->pClassifyData->pFilter; PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData = (PC_BASIC_PACKET_MODIFICATION_DATA*)pFilter->providerContext->dataBuffer->data; if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) status = PerformBasicPacketModificationAtInboundNetwork(&(pWorkItemData->pClassifyData), &(pWorkItemData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6) status = PerformBasicPacketModificationAtOutboundNetwork(&(pWorkItemData->pClassifyData), &(pWorkItemData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6) status = PerformBasicPacketModificationAtForward(&(pWorkItemData->pClassifyData), &(pWorkItemData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V6 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || (pWorkItemData->pInjectionData->direction == FWP_DIRECTION_INBOUND && (pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || /// Policy Change Reauthorization pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || /// Policy Change Reauthorization pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6))) status = PerformBasicPacketModificationAtInboundTransport(&(pWorkItemData->pClassifyData), &(pWorkItemData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6 || (pWorkItemData->pInjectionData->direction == FWP_DIRECTION_OUTBOUND && (pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || /// Policy Change Reauthorization pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || /// Policy Change Reauthorization pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6))) status = PerformBasicPacketModificationAtOutboundTransport(&(pWorkItemData->pClassifyData), &(pWorkItemData->pInjectionData), pModificationData, FALSE); #if(NTDDI_VERSION >= NTDDI_WIN7) else if(pWorkItemData->pInjectionData->direction == FWP_DIRECTION_INBOUND && (pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)) status = PerformBasicPacketModificationAtInboundTransport(&(pWorkItemData->pClassifyData), &(pWorkItemData->pInjectionData), pModificationData, FALSE); else if(pWorkItemData->pInjectionData->direction == FWP_DIRECTION_OUTBOUND && (pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)) status = PerformBasicPacketModificationAtOutboundTransport(&(pWorkItemData->pClassifyData), &(pWorkItemData->pInjectionData), pModificationData, FALSE); #if(NTDDI_VERSION >= NTDDI_WIN8) else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET || pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE) status = PerformBasicPacketModificationAtInboundMACFrame(&(pWorkItemData->pClassifyData), &(pWorkItemData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE) status = PerformBasicPacketModificationAtOutboundMACFrame(&(pWorkItemData->pClassifyData), &(pWorkItemData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_INGRESS_VSWITCH_ETHERNET) status = PerformBasicPacketModificationAtIngressVSwitchEthernet(&(pWorkItemData->pClassifyData), &(pWorkItemData->pInjectionData), pModificationData, FALSE); else if(pClassifyValues->layerId == FWPS_LAYER_EGRESS_VSWITCH_ETHERNET) status = PerformBasicPacketModificationAtEgressVSwitchEthernet(&(pWorkItemData->pClassifyData), &(pWorkItemData->pInjectionData), pModificationData, FALSE); #endif // (NTDDI_VERSION >= NTDDI_WIN8) #endif // (NTDDI_VERSION >= NTDDI_WIN7) else DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! BasicPacketModificationWorkItemRoutine() [status: %#x]\n", (UINT32)STATUS_NOT_SUPPORTED); if(status != STATUS_SUCCESS) { if(pWorkItemData->pClassifyData) KrnlHlprClassifyDataDestroyLocalCopy(&(pWorkItemData->pClassifyData)); if(pWorkItemData->pInjectionData) KrnlHlprInjectionDataDestroy(&(pWorkItemData->pInjectionData)); DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! BasicPacketModificationWorkItemRoutine: PerformBasicPacketModification() [status: %#x]\n", status); } KrnlHlprWorkItemDataDestroy(&pWorkItemData); } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- BasicPacketModificationWorkItemRoutine()\n"); #endif /// DBG return; } /** @private_function="TriggerBasicPacketModificationInline" Purpose: Makes a reference to all the classification data structures and invokes the appropriate private routine to perform the modification and injection. <br> <br> Notes: <br> <br> MSDN_Ref: <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ _Check_return_ NTSTATUS TriggerBasicPacketModificationInline(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, _Inout_opt_ VOID* pNetBufferList, _In_opt_ const VOID* pClassifyContext, _In_ const FWPS_FILTER* pFilter, _In_ UINT64 flowContext, _Inout_ FWPS_CLASSIFY_OUT* pClassifyOut, _In_ INJECTION_DATA** ppInjectionData) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> TriggerBasicPacketModificationInline()\n"); #endif /// DBG NT_ASSERT(pClassifyValues); NT_ASSERT(pMetadata); NT_ASSERT(pNetBufferList); NT_ASSERT(pFilter); NT_ASSERT(pClassifyOut); NT_ASSERT(ppInjectionData); NT_ASSERT(*ppInjectionData); NTSTATUS status = STATUS_SUCCESS; CLASSIFY_DATA* pClassifyData = 0; PC_BASIC_PACKET_MODIFICATION_DATA* pModificationData = (PC_BASIC_PACKET_MODIFICATION_DATA*)pFilter->providerContext->dataBuffer->data; #pragma warning(push) #pragma warning(disable: 6014) /// pClassifyData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy HLPR_NEW(pClassifyData, CLASSIFY_DATA, WFPSAMPLER_CALLOUT_DRIVER_TAG); HLPR_BAIL_ON_ALLOC_FAILURE(pClassifyData, status); #pragma warning(pop) pClassifyData->pClassifyValues = pClassifyValues; pClassifyData->pMetadataValues = pMetadata; pClassifyData->pPacket = pNetBufferList; pClassifyData->pClassifyContext = pClassifyContext; pClassifyData->pFilter = pFilter; pClassifyData->flowContext = flowContext; pClassifyData->pClassifyOut = pClassifyOut; if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6) status = PerformBasicPacketModificationAtInboundNetwork(&pClassifyData, ppInjectionData, pModificationData, TRUE); else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6) status = PerformBasicPacketModificationAtOutboundNetwork(&pClassifyData, ppInjectionData, pModificationData, TRUE); else if(pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6) status = PerformBasicPacketModificationAtForward(&pClassifyData, ppInjectionData, pModificationData, TRUE); else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V6 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || ((*ppInjectionData)->direction == FWP_DIRECTION_INBOUND && (pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || /// Policy Change Reauthorization pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || /// Policy Change Reauthorization pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6))) status = PerformBasicPacketModificationAtInboundTransport(&pClassifyData, ppInjectionData, pModificationData, TRUE); else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6 || ((*ppInjectionData)->direction == FWP_DIRECTION_OUTBOUND && (pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || /// Policy Change Reauthorization pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || /// Policy Change Reauthorization pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6))) status = PerformBasicPacketModificationAtOutboundTransport(&pClassifyData, ppInjectionData, pModificationData, TRUE); #if(NTDDI_VERSION >= NTDDI_WIN7) else if((*ppInjectionData)->direction == FWP_DIRECTION_INBOUND && (pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)) status = PerformBasicPacketModificationAtInboundTransport(&pClassifyData, ppInjectionData, pModificationData, TRUE); else if((*ppInjectionData)->direction == FWP_DIRECTION_OUTBOUND && (pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)) status = PerformBasicPacketModificationAtOutboundTransport(&pClassifyData, ppInjectionData, pModificationData, TRUE); #if(NTDDI_VERSION >= NTDDI_WIN8) else if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET || pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE) status = PerformBasicPacketModificationAtInboundMACFrame(&pClassifyData, ppInjectionData, pModificationData, TRUE); else if(pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE) status = PerformBasicPacketModificationAtOutboundMACFrame(&pClassifyData, ppInjectionData, pModificationData, TRUE); else if(pClassifyValues->layerId == FWPS_LAYER_INGRESS_VSWITCH_ETHERNET) status = PerformBasicPacketModificationAtIngressVSwitchEthernet(&pClassifyData, ppInjectionData, pModificationData, TRUE); else if(pClassifyValues->layerId == FWPS_LAYER_EGRESS_VSWITCH_ETHERNET) status = PerformBasicPacketModificationAtEgressVSwitchEthernet(&pClassifyData, ppInjectionData, pModificationData, TRUE); #endif // (NTDDI_VERSION >= NTDDI_WIN8) #endif // (NTDDI_VERSION >= NTDDI_WIN7) else { status = STATUS_NOT_SUPPORTED; DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! TriggerBasicPacketModificationInline() [status: %#x]\n", status); } HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- TriggerBasicPacketModificationInline() [status: %#x]\n", status); #endif /// DBG return status; } /** @private_function="TriggerBasicPacketModificationOutOfBand" Purpose: Creates a local copy of the classification data structures and queues a WorkItem to perform the modification and injection at PASSIVE_LEVEL. <br> <br> Notes: <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF550679.aspx <br> HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF566380.aspx <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ _Check_return_ NTSTATUS TriggerBasicPacketModificationOutOfBand(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, _Inout_opt_ VOID* pNetBufferList, _In_opt_ const VOID* pClassifyContext, _In_ const FWPS_FILTER* pFilter, _In_ UINT64 flowContext, _In_ FWPS_CLASSIFY_OUT* pClassifyOut, _In_ INJECTION_DATA* pInjectionData, _In_ PC_BASIC_PACKET_MODIFICATION_DATA* pPCData) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> TriggerBasicPacketModificationOutOfBand()\n"); #endif /// DBG NT_ASSERT(pClassifyValues); NT_ASSERT(pMetadata); NT_ASSERT(pNetBufferList); NT_ASSERT(pFilter); NT_ASSERT(pClassifyOut); NT_ASSERT(pInjectionData); NT_ASSERT(pPCData); NTSTATUS status = STATUS_SUCCESS; CLASSIFY_DATA* pClassifyData = 0; #pragma warning(push) #pragma warning(disable: 6014) /// pClassifyData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy status = KrnlHlprClassifyDataCreateLocalCopy(&pClassifyData, pClassifyValues, pMetadata, pNetBufferList, pClassifyContext, pFilter, flowContext, pClassifyOut); HLPR_BAIL_ON_FAILURE(status); #pragma warning(pop) if(pPCData->useWorkItems) status = KrnlHlprWorkItemQueue(g_pWDMDevice, BasicPacketModificationWorkItemRoutine, pClassifyData, pInjectionData, 0); else if(pPCData->useThreadedDPC) status = KrnlHlprThreadedDPCQueue(BasicPacketModificationDeferredProcedureCall, pClassifyData, pInjectionData, 0); else status = KrnlHlprDPCQueue(BasicPacketModificationDeferredProcedureCall, pClassifyData, pInjectionData, 0); HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); if(status != STATUS_SUCCESS) { if(pClassifyData) KrnlHlprClassifyDataDestroyLocalCopy(&pClassifyData); } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- TriggerBasicPacketModificationOutOfBand() [status: %#x]\n", status); #endif /// DBG return status; } #if(NTDDI_VERSION >= NTDDI_WIN7) /** @classify_function="ClassifyBasicPacketModification" Purpose: Blocks the current NET_BUFFER_LIST, modifies a clone of the NBL with the specified data and injects the clone back to the stack's data path. <br> <br> Notes: <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF544893.aspx <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ VOID ClassifyBasicPacketModification(_In_ const FWPS_INCOMING_VALUES0* pClassifyValues, _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, _Inout_opt_ VOID* pNetBufferList, _In_opt_ const VOID* pClassifyContext, _In_ const FWPS_FILTER* pFilter, _In_ UINT64 flowContext, _Inout_ FWPS_CLASSIFY_OUT* pClassifyOut) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> ClassifyBasicPacketModification()\n"); #endif /// DBG NT_ASSERT(pClassifyValues); NT_ASSERT(pMetadata); NT_ASSERT(pNetBufferList); NT_ASSERT(pFilter); NT_ASSERT(pClassifyOut); NT_ASSERT(pFilter->providerContext); NT_ASSERT(pFilter->providerContext->type == FWPM_GENERAL_CONTEXT); NT_ASSERT(pFilter->providerContext->dataBuffer); NT_ASSERT(pFilter->providerContext->dataBuffer->size == sizeof(PC_BASIC_PACKET_MODIFICATION_DATA)); #if(NTDDI_VERSION >= NTDDI_WIN8) NT_ASSERT(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6 || pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6 || pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6 || pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET || pClassifyValues->layerId == FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE || pClassifyValues->layerId == FWPS_LAYER_INGRESS_VSWITCH_ETHERNET || pClassifyValues->layerId == FWPS_LAYER_EGRESS_VSWITCH_ETHERNET); #else NT_ASSERT(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6 || pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6 || pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6 || pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6); #endif /// (NTDDI_VERSION >= NTDDI_WIN8) NT_ASSERT(pFilter->providerContext); NT_ASSERT(pFilter->providerContext->type == FWPM_GENERAL_CONTEXT); NT_ASSERT(pFilter->providerContext->dataBuffer); NT_ASSERT(pFilter->providerContext->dataBuffer->size == sizeof(PC_BASIC_PACKET_MODIFICATION_DATA)); if(pClassifyOut->rights & FWPS_RIGHT_ACTION_WRITE) { NTSTATUS status = STATUS_SUCCESS; FWP_VALUE* pFlags = 0; INJECTION_DATA* pInjectionData = 0; pClassifyOut->actionType = FWP_ACTION_CONTINUE; pFlags = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_FLAGS); if(pFlags && pFlags->type == FWP_UINT32) { /// For IPsec interop, if ALE classification is required, bypass the injection if(pFlags->uint32 & FWP_CONDITION_FLAG_IS_IPSEC_SECURED && FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED)) HLPR_BAIL; /// Inject the individual fragments, but not the fragment grouping of those fragments if(pFlags->uint32 & FWP_CONDITION_FLAG_IS_FRAGMENT_GROUP) HLPR_BAIL; } #pragma warning(push) #pragma warning(disable: 6014) /// pInjectionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy status = KrnlHlprInjectionDataCreate(&pInjectionData, pClassifyValues, pMetadata, (NET_BUFFER_LIST*)pNetBufferList); HLPR_BAIL_ON_FAILURE(status); #pragma warning(pop) if(pInjectionData->injectionState != FWPS_PACKET_INJECTED_BY_SELF && pInjectionData->injectionState != FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF) { BOOLEAN performOutOfBand = TRUE; FWP_VALUE* pProtocolValue = 0; PC_BASIC_PACKET_MODIFICATION_DATA* pData = (PC_BASIC_PACKET_MODIFICATION_DATA*)pFilter->providerContext->dataBuffer->data; pClassifyOut->actionType = FWP_ACTION_BLOCK; pClassifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; pClassifyOut->rights ^= FWPS_RIGHT_ACTION_WRITE; if(pFlags && pFlags->type == FWP_UINT32 && pFlags->uint32 & FWP_CONDITION_FLAG_IS_IPSEC_SECURED) pInjectionData->isIPsecSecured = TRUE; /// Override the default of performing Out of Band with the user's specified setting ... if(pData->performInline) performOutOfBand = FALSE; /// ... however, due to TCP's locking semantics, TCP can only be injected Out of Band at any transport layer or equivalent, ... pProtocolValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_PROTOCOL); if(pProtocolValue && pProtocolValue->uint8 == IPPROTO_TCP && pClassifyValues->layerId > FWPS_LAYER_IPFORWARD_V6_DISCARD) performOutOfBand = TRUE; /// ... and inbound injection of loopback traffic requires us to use Out of Band modification as well due to address lookups. if(!performOutOfBand && pInjectionData->direction == FWP_DIRECTION_INBOUND) { FWP_VALUE* pRemoteAddress = 0; pRemoteAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_REMOTE_ADDRESS); if(pRemoteAddress && ((pRemoteAddress->type == FWP_UINT32 && RtlCompareMemory(&(pRemoteAddress->uint32), IPV4_LOOPBACK_ADDRESS, IPV4_ADDRESS_SIZE)) || (pRemoteAddress->type == FWP_BYTE_ARRAY16_TYPE && RtlCompareMemory(&(pRemoteAddress->byteArray16->byteArray16), IPV6_LOOPBACK_ADDRESS, IPV6_ADDRESS_SIZE)))) performOutOfBand = TRUE; } if(performOutOfBand) status = TriggerBasicPacketModificationOutOfBand(pClassifyValues, pMetadata, pNetBufferList, pClassifyContext, pFilter, flowContext, pClassifyOut, pInjectionData, pData); else status = TriggerBasicPacketModificationInline(pClassifyValues, pMetadata, pNetBufferList, pClassifyContext, pFilter, flowContext, pClassifyOut, &pInjectionData); } else { KrnlHlprInjectionDataDestroy(&pInjectionData); DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " -- Injection previously performed.\n"); } HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); if(status != STATUS_SUCCESS) { KrnlHlprInjectionDataDestroy(&pInjectionData); DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! ClassifyBasicPacketModification() [status: %#x]\n", status); } } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- ClassifyBasicPacketModification()\n"); #endif /// DBG return; } #else /** @classify_function="ClassifyBasicPacketModification" Purpose: Blocks the current NET_BUFFER_LIST, modifies a clone of the NBL with the specified data and injects the clone back to the stack's data path. <br> <br> Notes: <br> <br> MSDN_Ref: HTTP://MSDN.Microsoft.com/En-US/Library/Windows/Hardware/FF544890.aspx <br> */ _IRQL_requires_min_(PASSIVE_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_same_ VOID ClassifyBasicPacketModification(_In_ const FWPS_INCOMING_VALUES* pClassifyValues, _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata, _Inout_opt_ VOID* pNetBufferList, _In_ const FWPS_FILTER* pFilter, _In_ UINT64 flowContext, _Inout_ FWPS_CLASSIFY_OUT* pClassifyOut) { #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " ---> ClassifyBasicPacketModification()\n"); #endif /// DBG NT_ASSERT(pClassifyValues); NT_ASSERT(pMetadata); NT_ASSERT(pNetBufferList); NT_ASSERT(pFilter); NT_ASSERT(pClassifyOut); NT_ASSERT(pFilter->providerContext); NT_ASSERT(pFilter->providerContext->type == FWPM_GENERAL_CONTEXT); NT_ASSERT(pFilter->providerContext->dataBuffer); NT_ASSERT(pFilter->providerContext->dataBuffer->size == sizeof(PC_BASIC_PACKET_MODIFICATION_DATA)); NT_ASSERT(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6 || pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V4 || pClassifyValues->layerId == FWPS_LAYER_IPFORWARD_V6 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_TRANSPORT_V6 || pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4 || pClassifyValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_INBOUND_ICMP_ERROR_V6 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4 || pClassifyValues->layerId == FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 || pClassifyValues->layerId == FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6); NT_ASSERT(pFilter->providerContext); NT_ASSERT(pFilter->providerContext->type == FWPM_GENERAL_CONTEXT); NT_ASSERT(pFilter->providerContext->dataBuffer); NT_ASSERT(pFilter->providerContext->dataBuffer->size == sizeof(PC_BASIC_PACKET_MODIFICATION_DATA)); if(pClassifyOut->rights & FWPS_RIGHT_ACTION_WRITE) { NTSTATUS status = STATUS_SUCCESS; FWP_VALUE* pFlags = 0; INJECTION_DATA* pInjectionData = 0; pClassifyOut->actionType = FWP_ACTION_CONTINUE; pFlags = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_FLAGS); if(pFlags && pFlags->type == FWP_UINT32) { /// For IPsec interop, if ALE classification is required, bypass the injection if(pFlags->uint32 & FWP_CONDITION_FLAG_IS_IPSEC_SECURED && #if(NTDDI_VERSION >= NTDDI_WIN6SP1) FWPS_IS_METADATA_FIELD_PRESENT(pMetadata, FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED)) #else pFlags->uint32 & FWP_CONDITION_FLAG_REQUIRES_ALE_CLASSIFY) #endif // (NTDDI_VERSION >= NTDDI_WIN6SP1) HLPR_BAIL; /// Inject the individual fragments, but not the fragment grouping of those fragments if(pFlags->uint32 & FWP_CONDITION_FLAG_IS_FRAGMENT_GROUP) HLPR_BAIL; } #pragma warning(push) #pragma warning(disable: 6014) /// pInjectionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy status = KrnlHlprInjectionDataCreate(&pInjectionData, pClassifyValues, pMetadata, (NET_BUFFER_LIST*)pNetBufferList); HLPR_BAIL_ON_FAILURE(status); #pragma warning(pop) if(pInjectionData->injectionState != FWPS_PACKET_INJECTED_BY_SELF && pInjectionData->injectionState != FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF) { BOOLEAN performOutOfBand = TRUE; FWP_VALUE* pProtocolValue = 0; PC_BASIC_PACKET_MODIFICATION_DATA* pData = (PC_BASIC_PACKET_MODIFICATION_DATA*)pFilter->providerContext->dataBuffer->data; pClassifyOut->actionType = FWP_ACTION_BLOCK; pClassifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; pClassifyOut->rights ^= FWPS_RIGHT_ACTION_WRITE; if(pFlags && pFlags->type == FWP_UINT32 && pFlags->uint32 & FWP_CONDITION_FLAG_IS_IPSEC_SECURED) pInjectionData->isIPsecSecured = TRUE; /// Override the default of performing Out of Band with the user's specified setting ... if(pData->performInline) performOutOfBand = FALSE; /// Due to TCP's locking semantics, TCP can only be injected Out of Band at any transport layer or equivalent pProtocolValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues, &FWPM_CONDITION_IP_PROTOCOL); if(pProtocolValue && pProtocolValue->uint8 == IPPROTO_TCP && pClassifyValues->layerId > FWPS_LAYER_IPFORWARD_V6_DISCARD) performOutOfBand = TRUE; if(performOutOfBand) status = TriggerBasicPacketModificationOutOfBand(pClassifyValues, pMetadata, pNetBufferList, 0, pFilter, flowContext, pClassifyOut, pInjectionData, pData); else status = TriggerBasicPacketModificationInline(pClassifyValues, pMetadata, pNetBufferList, 0, pFilter, flowContext, pClassifyOut, &pInjectionData); } else DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " -- Injection previously performed.\n"); HLPR_BAIL_LABEL: NT_ASSERT(status == STATUS_SUCCESS); if(status != STATUS_SUCCESS) { DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, " !!!! ClassifyBasicPacketModification() [status: %#x]\n", status); if(pInjectionData) KrnlHlprInjectionDataDestroy(&pInjectionData); } } #if DBG DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_INFO_LEVEL, " <--- ClassifyBasicPacketModification()\n"); #endif /// DBG return; } #endif // (NTDDI_VERSION >= NTDDI_WIN7)
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials