VOID NTAPI ClassifyBasicPacketInjection()

in network/trans/WFPSampler/sys/ClassifyFunctions_BasicPacketInjectionCallouts.cpp [3686:3970]


VOID NTAPI ClassifyBasicPacketInjection(_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)
{
   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_INJECTION_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)


   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> ClassifyBasicPacketInjection() [Layer: %s][FilterID: %#I64x][Rights: %#x]",
              KrnlHlprFwpsLayerIDToString(pClassifyValues->layerId),
              pFilter->filterId,
              pClassifyOut->rights);

#if DBG

   PrvBasicPacketInjectionCountersIncrement(pClassifyValues,
                                            pMetadata,
                                            &g_bpiTotalClassifies);

#endif /// DBG

   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)
      {
         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 BasicPacketInjectionCompletionDataDestroy

         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;
            PC_BASIC_PACKET_INJECTION_DATA* pData            = (PC_BASIC_PACKET_INJECTION_DATA*)pFilter->providerContext->dataBuffer->data;

            pClassifyOut->actionType  = FWP_ACTION_BLOCK;
            pClassifyOut->flags      |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
            pClassifyOut->rights     ^= FWPS_RIGHT_ACTION_WRITE;

#if(NTDDI_VERSION >= NTDDI_WIN8)

            /// This indicates that we have already acted on the 1st NBL of the distributed set.
            /// We can ignore injecting the rest of the individual distributed NBLs because the
            /// injected NBL will get redistributed.  Flag is only set for FWPM_LAYER_EGRESS_VSWITCH.
            if(pMetadata->l2Flags & FWPS_L2_INCOMING_FLAG_RECLASSIFY_MULTI_DESTINATION)
               HLPR_BAIL;

#endif /// (NTDDI_VERSION >= NTDDI_WIN8)

            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 &&
               pFlags &&
               pFlags->type == FWP_UINT32 &&
               pFlags->uint32 & FWP_CONDITION_FLAG_IS_LOOPBACK &&
               pInjectionData->direction == FWP_DIRECTION_INBOUND)
            {
               FWP_VALUE* pLocalAddress = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
                                                                                    &FWPM_CONDITION_IP_LOCAL_ADDRESS);
               FWP_VALUE* pRemoteAddress = 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 &&
                   pLocalAddress->byteArray16 &&
                   RtlCompareMemory(&(pLocalAddress->byteArray16->byteArray16),
                                 IPV6_LOOPBACK_ADDRESS,
                                 IPV6_ADDRESS_SIZE)))) ||
                  (pRemoteAddress &&
                  ((pRemoteAddress->type == FWP_UINT32 &&
                  RtlCompareMemory(&(pRemoteAddress->uint32),
                                   IPV4_LOOPBACK_ADDRESS,
                                   IPV4_ADDRESS_SIZE)) ||
                  (pRemoteAddress->type == FWP_BYTE_ARRAY16_TYPE &&
                   pRemoteAddress->byteArray16 &&
                   RtlCompareMemory(&(pRemoteAddress->byteArray16->byteArray16),
                                 IPV6_LOOPBACK_ADDRESS,
                                 IPV6_ADDRESS_SIZE)))))
                  performOutOfBand = TRUE;
            }

            if(performOutOfBand)
               status = TriggerBasicPacketInjectionOutOfBand(pClassifyValues,
                                                             pMetadata,
                                                             pNetBufferList,
                                                             pClassifyContext,
                                                             pFilter,
                                                             flowContext,
                                                             pClassifyOut,
                                                             pInjectionData,
                                                             pData);
            else
               status = TriggerBasicPacketInjectionInline(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,
                       " !!!! ClassifyBasicPacketInjection() [status: %#x]\n",
                       status);
         }

#if(NTDDI_VERSION >= NTDDI_WIN8)

         else if(pMetadata->l2Flags & FWPS_L2_INCOMING_FLAG_RECLASSIFY_MULTI_DESTINATION)
            KrnlHlprInjectionDataDestroy(&pInjectionData);

#endif /// (NTDDI_VERSION >= NTDDI_WIN8)

      }
      else
         pClassifyOut->actionType = FWP_ACTION_PERMIT;
   }

#if DBG

   PrvBasicPacketInjectionCountersIncrementTotalActionResults(pClassifyValues,
                                                              pMetadata,
                                                              pClassifyOut);

#endif /// DBG

   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- ClassifyBasicPacketInjection() [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;
}