NTSTATUS KrnlHlprIPHeaderGet()

in network/trans/WFPSampler/syslib/HelperFunctions_Headers.cpp [593:1074]


NTSTATUS KrnlHlprIPHeaderGet(_In_ NET_BUFFER_LIST* pNetBufferList,
                             _In_ const FWPS_INCOMING_VALUES* pClassifyValues,
                             _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata,
                             _Outptr_result_buffer_(*pIPHeaderSize) VOID** ppIPHeader,
                             _Inout_ BOOLEAN* pNeedToFreeMemory,
                             _Inout_opt_ FWP_DIRECTION* pDirection,               /* 0 */
                             _Inout_opt_ UINT32* pIPHeaderSize)                   /* 0 */
{
   NT_ASSERT(pNetBufferList);
   NT_ASSERT(pClassifyValues);
   NT_ASSERT(pMetadata);
   NT_ASSERT(ppIPHeader);
   NT_ASSERT(pNeedToFreeMemory);

   NTSTATUS      status              = STATUS_SUCCESS;
   UINT32        bytesRetreated      = 0;
   UINT32        bytesAdvanced       = 0;
   UINT32        ipHeaderSize        = 0;
   UINT32        transportHeaderSize = 0;
   FWP_DIRECTION direction           = FWP_DIRECTION_MAX;
   BOOLEAN       ipHeaderAvailable   = TRUE;

#if(NTDDI_VERSION >= NTDDI_WIN8)

   UINT32        ethernetHeaderSize  = 0;

   if(FWPS_IS_L2_METADATA_FIELD_PRESENT(pMetadata,
                                        FWPS_L2_METADATA_FIELD_ETHERNET_MAC_HEADER_SIZE))
      ethernetHeaderSize = pMetadata->ethernetMacHeaderSize;

#endif /// (NTDDI_VERSION >= NTDDI_WIN8)

   if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                     FWPS_METADATA_FIELD_IP_HEADER_SIZE))
      ipHeaderSize = pMetadata->ipHeaderSize;

   if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                     FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE))
      transportHeaderSize = pMetadata->transportHeaderSize;

   if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                     FWPS_METADATA_FIELD_PACKET_DIRECTION))
      direction = pMetadata->packetDirection;

   switch(pClassifyValues->layerId)
   {
      case FWPS_LAYER_INBOUND_IPPACKET_V4:
      case FWPS_LAYER_INBOUND_IPPACKET_V6:
      {
         direction = FWP_DIRECTION_INBOUND;

         bytesRetreated = ipHeaderSize;

         break;
      }
      case FWPS_LAYER_INBOUND_IPPACKET_V4_DISCARD:
      case FWPS_LAYER_INBOUND_IPPACKET_V6_DISCARD:
      {
         direction = FWP_DIRECTION_INBOUND;

         if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                           FWPS_METADATA_FIELD_DISCARD_REASON))
         {
            if(pMetadata->discardMetadata.discardModule == FWPS_DISCARD_MODULE_GENERAL &&
               pMetadata->discardMetadata.discardReason == FWPS_DISCARD_FIREWALL_POLICY)
               bytesRetreated = ipHeaderSize;
         }

         break;
      }
      case FWPS_LAYER_OUTBOUND_IPPACKET_V4:
      case FWPS_LAYER_OUTBOUND_IPPACKET_V4_DISCARD:
      case FWPS_LAYER_OUTBOUND_IPPACKET_V6:
      case FWPS_LAYER_OUTBOUND_IPPACKET_V6_DISCARD:
      {
         direction = FWP_DIRECTION_OUTBOUND;

         /// At the IP Header
   
         break;
      }
      case FWPS_LAYER_IPFORWARD_V4:
      case FWPS_LAYER_IPFORWARD_V4_DISCARD:
      case FWPS_LAYER_IPFORWARD_V6:
      case FWPS_LAYER_IPFORWARD_V6_DISCARD:
      {
         /// At the IP Header
   
         break;
      }
      case FWPS_LAYER_INBOUND_TRANSPORT_V4:
      case FWPS_LAYER_INBOUND_TRANSPORT_V4_DISCARD:
      case FWPS_LAYER_INBOUND_TRANSPORT_V6:
      case FWPS_LAYER_INBOUND_TRANSPORT_V6_DISCARD:
      {
         direction = FWP_DIRECTION_INBOUND;

         if(pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMP ||
            pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_TRANSPORT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMPV6)
            bytesRetreated = ipHeaderSize;
         else
            bytesRetreated = ipHeaderSize + transportHeaderSize;

         break;
      }
      case FWPS_LAYER_OUTBOUND_TRANSPORT_V4:
      case FWPS_LAYER_OUTBOUND_TRANSPORT_V4_DISCARD:
      case FWPS_LAYER_OUTBOUND_TRANSPORT_V6:
      case FWPS_LAYER_OUTBOUND_TRANSPORT_V6_DISCARD:
      {
         direction = FWP_DIRECTION_OUTBOUND;

         ipHeaderAvailable = FALSE;
   
         break;
      }
      case FWPS_LAYER_STREAM_V4:
      case FWPS_LAYER_STREAM_V4_DISCARD:
      case FWPS_LAYER_STREAM_V6:
      case FWPS_LAYER_STREAM_V6_DISCARD:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_DATAGRAM_DATA_V4:
      case FWPS_LAYER_DATAGRAM_DATA_V4_DISCARD:
      case FWPS_LAYER_DATAGRAM_DATA_V6:
      case FWPS_LAYER_DATAGRAM_DATA_V6_DISCARD:
      {
         direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].value.uint32;

         if(direction == FWP_DIRECTION_OUTBOUND)
            bytesRetreated = ipHeaderSize;
         else
         {
            if(pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMP ||
               pClassifyValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMPV6)
               bytesRetreated = ipHeaderSize;
            else
               bytesRetreated = ipHeaderSize + transportHeaderSize;
         }
   
         break;
      }
      case FWPS_LAYER_INBOUND_ICMP_ERROR_V4:
      case FWPS_LAYER_INBOUND_ICMP_ERROR_V4_DISCARD:
      case FWPS_LAYER_INBOUND_ICMP_ERROR_V6:
      case FWPS_LAYER_INBOUND_ICMP_ERROR_V6_DISCARD:
      {
         direction = FWP_DIRECTION_INBOUND;

         bytesRetreated = ipHeaderSize + transportHeaderSize;

         break;
      }
      case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4:
      case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V4_DISCARD:
      case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6:
      case FWPS_LAYER_OUTBOUND_ICMP_ERROR_V6_DISCARD:
      {
         direction = FWP_DIRECTION_OUTBOUND;

         bytesRetreated = ipHeaderSize;

         break;
      }
      case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V4:
      case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V4_DISCARD:
      case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V6:
      case FWPS_LAYER_ALE_RESOURCE_ASSIGNMENT_V6_DISCARD:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_AUTH_LISTEN_V4:
      case FWPS_LAYER_ALE_AUTH_LISTEN_V4_DISCARD:
      case FWPS_LAYER_ALE_AUTH_LISTEN_V6:
      case FWPS_LAYER_ALE_AUTH_LISTEN_V6_DISCARD:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4:
      case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4_DISCARD:
      case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6:
      case FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6_DISCARD:
      {
         if(direction == FWP_DIRECTION_OUTBOUND)
         {
            ipHeaderAvailable = FALSE;
         }
         else
         {
            if(pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMP ||
               pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMPV6)
               bytesRetreated = ipHeaderSize;
            else
               bytesRetreated = ipHeaderSize + transportHeaderSize;
         }

         break;
      }
      case FWPS_LAYER_ALE_AUTH_CONNECT_V4:
      case FWPS_LAYER_ALE_AUTH_CONNECT_V4_DISCARD:
      case FWPS_LAYER_ALE_AUTH_CONNECT_V6:
      case FWPS_LAYER_ALE_AUTH_CONNECT_V6_DISCARD:
      {
         if(pClassifyValues->incomingValue[FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8 == IPPROTO_TCP)
            ipHeaderAvailable = FALSE;
         else if(direction == FWP_DIRECTION_INBOUND)
            ipHeaderAvailable = FALSE;
         else
            ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4:
      case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4_DISCARD:
      case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6:
      case FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6_DISCARD:
      {
         direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.uint32;

         if(direction == FWP_DIRECTION_OUTBOUND)
            bytesRetreated = ipHeaderSize;
         else
         {
            if(pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8 == IPPROTO_ICMP ||
               pClassifyValues->incomingValue[FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL].value.uint8 == IPPROTO_ICMPV6)
               bytesRetreated = ipHeaderSize;
            else
               bytesRetreated = ipHeaderSize + transportHeaderSize;
         }
   
         break;
      }

#if(NTDDI_VERSION >= NTDDI_WIN7)

      case FWPS_LAYER_NAME_RESOLUTION_CACHE_V4:
      case FWPS_LAYER_NAME_RESOLUTION_CACHE_V6:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_RESOURCE_RELEASE_V4:
      case FWPS_LAYER_ALE_RESOURCE_RELEASE_V6:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V4:
      case FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V6:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_CONNECT_REDIRECT_V4:
      case FWPS_LAYER_ALE_CONNECT_REDIRECT_V6:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_ALE_BIND_REDIRECT_V4:
      case FWPS_LAYER_ALE_BIND_REDIRECT_V6:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_STREAM_PACKET_V4:
      case FWPS_LAYER_STREAM_PACKET_V6:
      {
         direction = (FWP_DIRECTION)pClassifyValues->incomingValue[FWPS_FIELD_STREAM_PACKET_V4_DIRECTION].value.uint32;

         if(direction == FWP_DIRECTION_OUTBOUND)
            bytesRetreated = ipHeaderSize;
         else
            bytesRetreated = ipHeaderSize + transportHeaderSize;

         break;
      }
   
#if(NTDDI_VERSION >= NTDDI_WIN8)
   
      case FWPS_LAYER_INBOUND_MAC_FRAME_ETHERNET:
      {
         UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_INBOUND_MAC_FRAME_ETHERNET_ETHER_TYPE].value.uint16;

         if(etherType != 0x86DD &&
            etherType != 0x0800)
            ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_OUTBOUND_MAC_FRAME_ETHERNET:
      {
         UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_OUTBOUND_MAC_FRAME_ETHERNET_ETHER_TYPE].value.uint16;

         if(etherType == 0x86DD ||
            etherType == 0x0800)
            bytesAdvanced = ethernetHeaderSize;
         else
            ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_INBOUND_MAC_FRAME_NATIVE:
      case FWPS_LAYER_OUTBOUND_MAC_FRAME_NATIVE:
      {
         ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_INGRESS_VSWITCH_ETHERNET:
      {
         UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_INGRESS_VSWITCH_ETHERNET_ETHER_TYPE].value.uint16;

         if(etherType == 0x86DD ||
            etherType == 0x0800)
            bytesAdvanced = ethernetHeaderSize;
         else
            ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_EGRESS_VSWITCH_ETHERNET:
      {
         UINT16 etherType = pClassifyValues->incomingValue[FWPS_FIELD_EGRESS_VSWITCH_ETHERNET_ETHER_TYPE].value.uint16;

         if(etherType == 0x86DD ||
            etherType == 0x0800)
            bytesAdvanced = ethernetHeaderSize;
         else
            ipHeaderAvailable = FALSE;

         break;
      }
      case FWPS_LAYER_INGRESS_VSWITCH_TRANSPORT_V4:
      case FWPS_LAYER_INGRESS_VSWITCH_TRANSPORT_V6:
      {
         /// At the IP Header

         break;
      }
      case FWPS_LAYER_EGRESS_VSWITCH_TRANSPORT_V4:
      case FWPS_LAYER_EGRESS_VSWITCH_TRANSPORT_V6:
      {
         /// At the IP Header

         break;
      }

#endif /// (NTDDI_VERSION >= NTDDI_WIN8)
#endif /// (NTDDI_VERSION >= NTDDI_WIN7)

   }


   if(ipHeaderAvailable)
   {
      BYTE*        pBuffer         = 0;
      NET_BUFFER*  pNetBuffer      = NET_BUFFER_LIST_FIRST_NB(pNetBufferList);
      UINT32       bytesNeeded     = ipHeaderSize ? ipHeaderSize : NET_BUFFER_DATA_LENGTH(pNetBuffer);
      PVOID        pContiguousData = 0;

#pragma warning(push)
#pragma warning(disable: 6014) /// pBuffer is expected to be cleaned up by caller using KrnlHlprIPHeaderDestroy if *pNeedToFreeMemory is TRUE

      HLPR_NEW_ARRAY(pBuffer,
                     BYTE,
                     bytesNeeded,
                     WFPSAMPLER_SYSLIB_TAG);
      HLPR_BAIL_ON_ALLOC_FAILURE(pBuffer,
                                 status);

#pragma warning(pop)

      *pNeedToFreeMemory = TRUE;

      if(bytesAdvanced)
         NdisAdvanceNetBufferDataStart(pNetBuffer,
                                       bytesAdvanced,
                                       0,
                                       0);
      else if(bytesRetreated)
      {
         status = NdisRetreatNetBufferDataStart(pNetBuffer,
                                                bytesRetreated,
                                                0,
                                                0);
         if(status != STATUS_SUCCESS)
         {
            DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                       DPFLTR_ERROR_LEVEL,
                       " !!!! KrnlHlprIPHeaderGet : NdisRetreatNetBufferDataStart() [status: %#x]\n",
                       status);

            HLPR_BAIL;
         }
      }

      pContiguousData = NdisGetDataBuffer(pNetBuffer,
                                          bytesNeeded,
                                          pBuffer,
                                          1,
                                          0);

      /// Return to the original offset
      if(bytesRetreated)
         NdisAdvanceNetBufferDataStart(pNetBuffer,
                                       bytesRetreated,
                                       0,
                                       0);
      else if(bytesAdvanced)
      {
         status = NdisRetreatNetBufferDataStart(pNetBuffer,
                                                bytesAdvanced,
                                                0,
                                                0);
         if(status != STATUS_SUCCESS)
         {
            DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                       DPFLTR_ERROR_LEVEL,
                       " !!!! KrnlHlprIPHeaderGet : NdisRetreatNetBufferDataStart() [status: %#x]\n",
                       status);

            HLPR_BAIL;
         }
      }

      if(!pContiguousData)
      {
         status = STATUS_UNSUCCESSFUL;
      
         DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                    DPFLTR_ERROR_LEVEL,
                    " !!!! KrnlHlprIPHeaderGet : NdisGetDataBuffer() [status: %#x]\n",
                    status);
      
         HLPR_BAIL;
      }

      if(pBuffer != pContiguousData)
      {
         HLPR_DELETE_ARRAY(pBuffer,
                           WFPSAMPLER_SYSLIB_TAG);

         *pNeedToFreeMemory = FALSE;
      }

      *ppIPHeader = pContiguousData;

      if(pDirection)
         *pDirection = direction;

      if(pIPHeaderSize)
         *pIPHeaderSize = ipHeaderSize;

      HLPR_BAIL_LABEL:

      if(status != STATUS_SUCCESS &&
         *pNeedToFreeMemory &&
         pBuffer)
      {
         KrnlHlprIPHeaderDestroy((VOID**)&pBuffer);

         *pNeedToFreeMemory = FALSE;
      }
   }
   else
      status = STATUS_NO_MATCH;

   return status;
}