in network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketModificationCallouts.cpp [5959:6316]
VOID NTAPI 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)
{
NT_ASSERT(pClassifyValues);
NT_ASSERT(pMetadata);
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));
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_INFO_LEVEL,
" ---> ClassifyBasicPacketModification() [Layer: %s][FilterID: %#I64x][Rights: %#x]",
KrnlHlprFwpsLayerIDToString(pClassifyValues->layerId),
pFilter->filterId,
pClassifyOut->rights);
if(pClassifyOut->rights & FWPS_RIGHT_ACTION_WRITE)
{
/// Packets are not available for TCP @ ALE_AUTH_CONNECT, so skip over as there is nothing to inject
if(pNetBufferList)
{
PC_BASIC_PACKET_MODIFICATION_DATA* pData = (PC_BASIC_PACKET_MODIFICATION_DATA*)pFilter->providerContext->dataBuffer->data;
if(pData)
{
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;
}
if(pData->flags & PCPMDF_MODIFY_TRANSPORT_HEADER &&
(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))
{
UINT32 bytesRetreated = 0;
UINT8 version = 0;
IPPROTO protocol = IPPROTO_MAX;
if(pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 ||
pClassifyValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6)
{
if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
FWPS_METADATA_FIELD_IP_HEADER_SIZE))
bytesRetreated = pMetadata->ipHeaderSize;
}
if(bytesRetreated)
{
/// Initial offset is at the Transport Header for INBOUND_IPPACKET, so retreat the size of the IP Header ...
status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pNetBufferList),
bytesRetreated,
0,
0);
if(status != STATUS_SUCCESS)
{
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_ERROR_LEVEL,
" !!!! ClassifyBasicPacketModification: NdisRetreatNetBufferDataStart() [status: %#x]\n",
status);
HLPR_BAIL;
}
}
version = KrnlHlprIPHeaderGetVersionField((NET_BUFFER_LIST*)pNetBufferList);
protocol = KrnlHlprIPHeaderGetProtocolField((NET_BUFFER_LIST*)pNetBufferList,
version == IPV4 ? AF_INET : AF_INET6);
if(bytesRetreated)
{
/// ... and advance the offset back to the original position.
NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pNetBufferList),
bytesRetreated,
FALSE,
0);
}
/// Exit if this isn't the protocol we are looking for
if(protocol != pData->originalTransportData.protocol)
HLPR_BAIL;
else
{
UINT16 sourcePort = 0;
UINT16 destinationPort = 0;
UINT32 bytesAdvanced = 0;
if(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)
{
if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
FWPS_METADATA_FIELD_IP_HEADER_SIZE))
bytesAdvanced = pMetadata->ipHeaderSize;
}
if(bytesAdvanced)
{
/// Initial offset is at the IP Header for OUTBOUND_IPPACKET and IPFORWARD, so
/// advance the size of the IP Header ...
NdisAdvanceNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pNetBufferList),
bytesAdvanced,
FALSE,
0);
}
sourcePort = KrnlHlprTransportHeaderGetSourcePortField((NET_BUFFER_LIST*)pNetBufferList,
protocol);
destinationPort = KrnlHlprTransportHeaderGetDestinationPortField((NET_BUFFER_LIST*)pNetBufferList,
protocol);
/// Exit if the ports are not what we are looking for
if(pData->originalTransportData.sourcePort &&
sourcePort != pData->originalTransportData.sourcePort)
HLPR_BAIL;
if(pData->originalTransportData.destinationPort &&
destinationPort != pData->originalTransportData.destinationPort)
HLPR_BAIL;
if(bytesAdvanced)
{
/// ... and retreat the offset back to the original position.
status = NdisRetreatNetBufferDataStart(NET_BUFFER_LIST_FIRST_NB((NET_BUFFER_LIST*)pNetBufferList),
bytesAdvanced,
0,
0);
if(status != STATUS_SUCCESS)
{
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_ERROR_LEVEL,
" !!!! ClassifyBasicPacketModification: NdisRetreatNetBufferDataStart() [status: %#x]\n",
status);
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,
pFilter);
HLPR_BAIL_ON_FAILURE(status);
#pragma warning(pop)
if(pInjectionData->injectionState != FWPS_PACKET_INJECTED_BY_SELF &&
pInjectionData->injectionState != FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF)
{
BOOLEAN performOutOfBand = TRUE;
FWP_VALUE* pProtocolValue = 0;
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) ||
pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V4 ||
pClassifyValues->layerId == FWPS_LAYER_STREAM_PACKET_V6)
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
{
pClassifyOut->actionType = FWP_ACTION_PERMIT;
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);
}
}
}
else
pClassifyOut->actionType = FWP_ACTION_PERMIT;
}
DbgPrintEx(DPFLTR_IHVNETWORK_ID,
DPFLTR_INFO_LEVEL,
" <--- ClassifyBasicPacketModification() [Layer: %s][FilterID: %#I64x][Action: %#x][Rights: %#x][Absorb: %s]\n",
KrnlHlprFwpsLayerIDToString(pClassifyValues->layerId),
pFilter->filterId,
pClassifyOut->actionType,
pClassifyOut->rights,
(pClassifyOut->flags & FWPS_CLASSIFY_OUT_FLAG_ABSORB) ? "TRUE" : "FALSE");
return;
}