in network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketModificationCallouts.cpp [2370:2984]
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 = DEFAULT_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;
UINT64 endpointHandle = 0;
IPPROTO protocol = IPPROTO_MAX;
FWP_VALUE* pInterfaceIndex = 0;
FWP_VALUE* pSubInterfaceIndex = 0;
FWP_VALUE* pFlags = 0;
BYTE* pSourceAddress = 0;
BYTE* pDestinationAddress = 0;
NDIS_TCP_IP_CHECKSUM_PACKET_INFO checksumInfo = {0};
#if DBG
KIRQL irql = KeGetCurrentIrql();
#endif /// DBG
#pragma warning(push)
#pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using BasicPacketModificationCompletionDataDestroy
HLPR_NEW(pCompletionData,
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_TRANSPORT_ENDPOINT_HANDLE))
endpointHandle = pMetadata->transportEndpointHandle;
pInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
&FWPM_CONDITION_INTERFACE_INDEX);
if(pInterfaceIndex &&
pInterfaceIndex->type == FWP_UINT32)
interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32;
pSubInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
&FWPM_CONDITION_SUB_INTERFACE_INDEX);
if(pSubInterfaceIndex &&
pSubInterfaceIndex->type == FWP_UINT32)
subInterfaceIndex = (IF_INDEX)pSubInterfaceIndex->uint32;
pFlags = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
&FWPM_CONDITION_FLAGS);
if(pFlags &&
pFlags->type == FWP_UINT32)
flags = pFlags->uint32;
if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
FWPS_METADATA_FIELD_IP_HEADER_SIZE))
bytesRetreated = ipHeaderSize = pMetadata->ipHeaderSize;
checksumInfo.Value = (ULONG)(ULONG_PTR)NET_BUFFER_LIST_INFO((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket,
TcpIpChecksumNetBufferListInfo);
/// Initial offset is at the Transport Header, so retreat the size of the IP Header ...
status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket),
bytesRetreated,
0,
0);
if(status != STATUS_SUCCESS)
{
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_ERROR_LEVEL,
" !!!! 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);
/// ... and advance the offset back to the original position.
NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pCompletionData->pClassifyData->pPacket),
bytesRetreated,
FALSE,
0);
if(status != STATUS_SUCCESS ||
!pNetBufferList)
{
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_ERROR_LEVEL,
" !!!! PerformBasicPacketModificationAtInboundNetwork: FwpsAllocateCloneNetBufferList() [status: %#x]\n",
status);
HLPR_BAIL;
}
/// Handle if this packet had the IP checksum offloaded or if it's loopback
if(checksumInfo.Receive.NdisPacketIpChecksumSucceeded ||
flags & FWP_CONDITION_FLAG_IS_LOOPBACK)
{
/// Prevent TCP/IP Zone crossing and recalculate the checksums
if(flags & FWP_CONDITION_FLAG_IS_LOOPBACK)
{
FWP_VALUE* pLocalAddress = 0;
FWP_VALUE* pRemoteAddress = 0;
FWP_VALUE* pLoopbackAddress = 0;
pLocalAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
&FWPM_CONDITION_IP_REMOTE_ADDRESS);
if(pLocalAddress &&
((pLocalAddress->type == FWP_UINT32 &&
RtlCompareMemory(&(pLocalAddress->uint32),
IPV4_LOOPBACK_ADDRESS,
IPV4_ADDRESS_SIZE)) ||
(pLocalAddress->type == FWP_BYTE_ARRAY16_TYPE &&
RtlCompareMemory(pLocalAddress->byteArray16->byteArray16,
IPV6_LOOPBACK_ADDRESS,
IPV6_ADDRESS_SIZE))))
pLoopbackAddress = pLocalAddress;
if(!pLoopbackAddress)
{
pRemoteAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
&FWPM_CONDITION_IP_REMOTE_ADDRESS);
if(pRemoteAddress &&
((pRemoteAddress->type == FWP_UINT32 &&
RtlCompareMemory(&(pRemoteAddress->uint32),
IPV4_LOOPBACK_ADDRESS,
IPV4_ADDRESS_SIZE)) ||
(pRemoteAddress->type == FWP_BYTE_ARRAY16_TYPE &&
RtlCompareMemory(pRemoteAddress->byteArray16->byteArray16,
IPV6_LOOPBACK_ADDRESS,
IPV6_ADDRESS_SIZE))))
pLoopbackAddress = pRemoteAddress;
}
if(pLoopbackAddress)
{
status = KrnlHlprIPHeaderModifyLoopbackToLocal(pMetadata,
pLoopbackAddress,
ipHeaderSize,
pNetBufferList,
(const WSACMSGHDR*)pCompletionData->pInjectionData->pControlData,
pCompletionData->pInjectionData->controlDataLength);
if(status != STATUS_SUCCESS)
{
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_ERROR_LEVEL,
" !!!! PerformBasicPacketModificationAtInboundNetwork: KrnlHlprIPHeaderModifyLoopbackToLocal() [status: %#x]\n",
status);
HLPR_BAIL;
}
}
}
else
{
/// Recalculate the checksum
if(pCompletionData->pInjectionData->addressFamily == AF_INET)
KrnlHlprIPHeaderCalculateV4Checksum(pNetBufferList,
ipHeaderSize);
}
}
pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList);
protocol = KrnlHlprIPHeaderGetProtocolField(pNetBufferList,
pCompletionData->pInjectionData->addressFamily);
if(pModificationData->flags)
{
if(pModificationData->flags & PCPMDF_MODIFY_TRANSPORT_HEADER)
{
NTSTATUS tmpStatus = STATUS_SUCCESS;
/// 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 = KrnlHlprTCPHeaderModifyDestinationPort(&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 = KrnlHlprUDPHeaderModifyDestinationPort(&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,
" !!!! 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_INTERFACE_INDEX)
interfaceIndex = pModificationData->ipData.interfaceIndex;
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,
(const WSACMSGHDR*)pCompletionData->pInjectionData->pControlData,
pCompletionData->pInjectionData->controlDataLength);
if(status != STATUS_SUCCESS)
{
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_ERROR_LEVEL,
" !!!! PerformBasicPacketModificationAtInboundNetwork: KrnlHlprIPHeaderModifyLoopbackToLocal() [status: %#x]\n",
status);
HLPR_BAIL;
}
}
}
pSourceAddress = KrnlHlprIPHeaderGetSourceAddressField(pNetBufferList,
pCompletionData->pInjectionData->addressFamily);
pDestinationAddress = KrnlHlprIPHeaderGetDestinationAddressField(pNetBufferList,
pCompletionData->pInjectionData->addressFamily);
status = FwpsConstructIpHeaderForTransportPacket(pNetBufferList,
ipHeaderSize,
pCompletionData->pInjectionData->addressFamily,
(UCHAR*)pSourceAddress,
(UCHAR*)pDestinationAddress,
protocol,
endpointHandle,
(const WSACMSGHDR*)pCompletionData->pInjectionData->pControlData,
pCompletionData->pInjectionData->controlDataLength,
0,
0,
interfaceIndex,
subInterfaceIndex);
if(status != STATUS_SUCCESS)
{
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_ERROR_LEVEL,
" !!!! PerformBasicPacketModificationAtInboundNetwork: NdisRetreatNetBufferDataStart() [status: %#x]\n",
status);
HLPR_BAIL;
}
status = FwpsInjectNetworkReceiveAsync(pCompletionData->pInjectionData->injectionHandle,
pCompletionData->pInjectionData->injectionContext,
0,
compartmentID,
interfaceIndex,
subInterfaceIndex,
pNetBufferList,
CompleteBasicPacketModification,
pCompletionData);
NT_ASSERT(irql == KeGetCurrentIrql());
if(status != STATUS_SUCCESS)
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_ERROR_LEVEL,
" !!!! 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;
}