BOOLEAN
IsAleClassifyRequired(
   _In_ const FWPS_INCOMING_VALUES* inFixedValues,
   _In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues
   )
{
   //
   // Note that use of FWP_CONDITION_FLAG_REQUIRES_ALE_CLASSIFY has been
   // deprecated in Vista SP1 and Windows Server 2008.
   //
   UNREFERENCED_PARAMETER(inFixedValues);
   return FWPS_IS_METADATA_FIELD_PRESENT(
             inMetaValues,
             FWPS_METADATA_FIELD_ALE_CLASSIFY_REQUIRED
             );
}
Beispiel #2
0
void 
NTAPI
WallALERecvAcceptClassify(
   IN const FWPS_INCOMING_VALUES* inFixedValues,
   IN const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
   IN OUT void* layerData,
   IN const void* classifyContext,
   IN const FWPS_FILTER* filter,
   IN UINT64 flowContext,
   OUT FWPS_CLASSIFY_OUT* classifyOut
   )
/*++
--*/
{
    NTSTATUS                status = STATUS_SUCCESS;
    UNICODE_STRING          devName,dosName;
    WCHAR                   buffer[MAX_PATH_LEN];
    PMY_UNICODE_STRING      logData;
    PWALL_PENDED_PACKET     pendedRecv = NULL;
    BOOLEAN                 bWakeUp = FALSE;
    ADDRESS_FAMILY          addressFamily;

    LOG("into\n");


    if(!(classifyOut->rights & FWPS_RIGHT_ACTION_WRITE))
    {
        KdPrint(("write right not set!\n"));
        return;
    }

    if( layerData != NULL )
    {
        FWPS_PACKET_INJECTION_STATE state;
        state = FwpsQueryPacketInjectionState( gInjectHandle,
                                       layerData,
                                       NULL);
        KdPrint(("inject state:%x\n",state ));
        if( state == FWPS_PACKET_INJECTED_BY_SELF ||
            state == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF )
        {
            classifyOut->actionType = FWP_ACTION_PERMIT;
            KdPrint(("inject by self\n"));
            goto exit;
        }
    }
    addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId);

    if(!IsAleReauthorize(inFixedValues))
    {
        pendedRecv = WallAllocateAndInitPendedPacket( inFixedValues,
                                                    inMetaValues,
                                                    addressFamily,
                                                    layerData,
                                                    WALL_DATA_PACKET,
                                                    FWP_DIRECTION_INBOUND );
        if(pendedRecv == NULL )
        {
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            goto exit;
        }

        ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, 
                                            FWPS_METADATA_FIELD_COMPLETION_HANDLE));

        status = FwpsPendOperation0(
                  inMetaValues->completionHandle,
                  &pendedRecv->completionContext
                  );

        if (!NT_SUCCESS(status))
        {
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
            goto exit;
        }

        bWakeUp = IsListEmpty(&gPacketList->list) &&
                                       IsListEmpty(&gConnList->list);

        ExInterlockedInsertTailList( &gPacketList->list,&pendedRecv->list,&gPacketList->lock );
        pendedRecv = NULL;

        if( bWakeUp )
        {
            RunMyProcess( WallInspectWallPackets,NULL );
        }

        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
    }
    else
    {//reauth

        FWP_DIRECTION packetDirection;
        KIRQL         irql,irql2;


        KdPrint(("recv reauth!\n"));
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
    }


exit:
    if( classifyOut->actionType == FWP_ACTION_PERMIT )
    {
        RtlInitUnicodeString( &devName,(PWCHAR)inMetaValues->processPath->data );
        RtlInitEmptyUnicodeString( &dosName,buffer,MAX_PATH_LEN * sizeof(WCHAR));
        logData = MyExAllocatePool( sizeof( MY_UNICODE_STRING) + inMetaValues->processPath->size);
        if( logData != NULL)
        {
            logData->str.Buffer = logData->buffer;
            logData->str.MaximumLength = (USHORT)inMetaValues->processPath->size;
            status = DevicePathToDosPath( &devName,&dosName );
            if( NT_SUCCESS( status ))
            {
                RtlCopyUnicodeString( (PUNICODE_STRING)logData,&dosName );
            }
            else
            {
                RtlCopyUnicodeString( (PUNICODE_STRING)logData,&devName );
            }
            RunMyProcess( WallWriteConnectLogData,logData );
            logData = NULL;
        }
        
    }
    return;
}
Beispiel #3
0
void 
NTAPI
WallALEConnectClassify(
   IN const FWPS_INCOMING_VALUES* inFixedValues,
   IN const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
   IN OUT void* layerData,
   IN const void* classifyContext,
   IN const FWPS_FILTER* filter,
   IN UINT64 flowContext,
   OUT FWPS_CLASSIFY_OUT* classifyOut
   )
/*++

注意:此回调的Irql <= DISPATCH_LEVEL!!!!!
--*/
{
    NTSTATUS                status = STATUS_SUCCESS;
    PWALL_PENDED_PACKET     pendedConn = NULL;
    BOOLEAN                 bWakeUp = FALSE;
    ADDRESS_FAMILY          addressFamily;
    UNICODE_STRING          devName,dosName;
    WCHAR                   buffer[MAX_PATH_LEN];
    PMY_UNICODE_STRING      logData = NULL;

    LOG("into\n");

    if(!(classifyOut->rights & FWPS_RIGHT_ACTION_WRITE))
    {
        KdPrint(("write right not set!\n"));
        return;
    }

     if( layerData != NULL )
     {
         FWPS_PACKET_INJECTION_STATE state;
         state = FwpsQueryPacketInjectionState( gInjectHandle,
                                        layerData,
                                        NULL);
         if( state == FWPS_PACKET_INJECTED_BY_SELF ||
             state == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF )
         {
             classifyOut->actionType = FWP_ACTION_PERMIT;
             goto exit;
         }
     }

    addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId);

    if(!IsAleReauthorize(inFixedValues))
    {
        pendedConn = WallAllocateAndInitPendedPacket( inFixedValues,
                                                    inMetaValues,
                                                    addressFamily,
                                                    layerData,
                                                    WALL_CONNECT_PACKET,
                                                    FWP_DIRECTION_OUTBOUND );
        if(pendedConn == NULL )
        {
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            goto exit;
        }

        ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, 
                                            FWPS_METADATA_FIELD_COMPLETION_HANDLE));

        status = FwpsPendOperation0(
                  inMetaValues->completionHandle,
                  &pendedConn->completionContext
                  );

        if (!NT_SUCCESS(status))
        {
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
            goto exit;
        }

        bWakeUp = IsListEmpty(&gPacketList->list) &&
                                       IsListEmpty(&gConnList->list);

        ExInterlockedInsertTailList( &gConnList->list,&pendedConn->list,&gConnList->lock );
        pendedConn = NULL;

        if( bWakeUp )
        {
            RunMyProcess( WallInspectWallPackets,NULL );
        }

        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
    }
    else
    {//reauth

        FWP_DIRECTION packetDirection;
        KIRQL         irql,irql2;

        LOG("1\n");

        ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, 
                                            FWPS_METADATA_FIELD_PACKET_DIRECTION));
        packetDirection = inMetaValues->packetDirection;

        if (packetDirection == FWP_DIRECTION_OUTBOUND)
        {
            LIST_ENTRY* listEntry;
            BOOLEAN authComplete = FALSE;
            
             LOG("2\n");
            KeAcquireSpinLock( &gConnList->lock,&irql );
            LOG("22\n");
            for (listEntry = gConnList->list.Flink;
              listEntry != (PLIST_ENTRY)gConnList;
              )
            {   
                pendedConn = (PWALL_PENDED_PACKET)listEntry;
                listEntry = listEntry->Flink;

                if (IsMatchingConnectPacket(
                     inFixedValues,
                     addressFamily,
                     packetDirection,
                     pendedConn
                  ) && (pendedConn->authConnectDecision != 0))
                {

                    ASSERT((pendedConn->authConnectDecision == FWP_ACTION_PERMIT) ||
                      (pendedConn->authConnectDecision == FWP_ACTION_BLOCK));
                LOG("3\n");
                    classifyOut->actionType = pendedConn->authConnectDecision;
                    if( classifyOut->actionType == FWP_ACTION_BLOCK ){
                        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
                        classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
                    }

                    RemoveEntryList(&pendedConn->list);
               
                    if (/*!gDriverUnloading &&*/
                       (pendedConn->netBufferList != NULL) &&
                       (pendedConn->authConnectDecision == FWP_ACTION_PERMIT))
                    {
                  
                        pendedConn->type = WALL_DATA_PACKET;
                         LOG("4\n");
                        KeAcquireSpinLock( &gPacketList->lock,&irql2 );

                        bWakeUp = IsListEmpty(&gPacketList->list) &&
                                       IsListEmpty(&gConnList->list);

                        InsertTailList(&gPacketList->list, &pendedConn->list);
                        pendedConn = NULL; // ownership transferred

                        KeReleaseSpinLock( &gPacketList->lock,irql2 );

                        if (bWakeUp)
                        {
                            RunMyProcess( WallInspectWallPackets,NULL );
                        }
                    }//end if permit

                    authComplete = TRUE;
                    break;
                }//end if match
            }//end if for

            KeReleaseSpinLock( &gConnList->lock,irql );
            if (authComplete)
            {
                 LOG("5\n");
                goto exit;
            }
            else
            {
                pendedConn = NULL;
            }
        }//end if outbound

        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
    }
exit:
    if( pendedConn != NULL )
    {
        LOG("free packet\n");
        WallFreePendedPacket( pendedConn );
        pendedConn = NULL;
    }

    if( classifyOut->actionType == FWP_ACTION_PERMIT )
    {
        RtlInitUnicodeString( &devName,(PWCHAR)inMetaValues->processPath->data );
        RtlInitEmptyUnicodeString( &dosName,buffer,MAX_PATH_LEN * sizeof(WCHAR));
        logData = MyExAllocatePool( sizeof( MY_UNICODE_STRING) + inMetaValues->processPath->size);
        if( logData != NULL)
        {
            logData->str.Buffer = logData->buffer;
            logData->str.MaximumLength = (USHORT)inMetaValues->processPath->size;
            status = DevicePathToDosPath( &devName,&dosName );
            if( NT_SUCCESS( status ))
            {
                RtlCopyUnicodeString( (PUNICODE_STRING)logData,&dosName );
            }
            else
            {
                RtlCopyUnicodeString( (PUNICODE_STRING)logData,&devName );
            }
            KdPrint(("logData:%wZ\n",logData ));

            RunMyProcess( WallWriteConnectLogData,logData );
            logData = NULL;
        }
        
    }
    return;
}
Beispiel #4
0
void
TLInspectALERecvAcceptClassify(
   IN const FWPS_INCOMING_VALUES0* inFixedValues,
   IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
   IN OUT void* layerData,
   IN const FWPS_FILTER0* filter,
   IN UINT64 flowContext,
   OUT FWPS_CLASSIFY_OUT0* classifyOut
   )
/* ++

   This is the classifyFn function for the ALE Recv-Accept (v4 and v6) callout.
   For an initial classify (where the FWP_CONDITION_FLAG_IS_REAUTHORIZE flag
   is not set), it is queued to the connection list for inspection by the
   worker thread. For re-auth, it is queued to the packet queue to be process 
   by the worker thread like any other regular packets.

-- */
{
   NTSTATUS status;

   KLOCK_QUEUE_HANDLE connListLockHandle;
   KLOCK_QUEUE_HANDLE packetQueueLockHandle;

   TL_INSPECT_PENDED_PACKET* pendedRecvAccept = NULL;
   TL_INSPECT_PENDED_PACKET* pendedPacket = NULL;

   ADDRESS_FAMILY addressFamily;
   FWPS_PACKET_INJECTION_STATE packetState;
   BOOLEAN signalWorkerThread;

   UNREFERENCED_PARAMETER(flowContext);
   UNREFERENCED_PARAMETER(filter);


   //
   // We don't have the necessary right to alter the classify, exit.
   //
   if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
   {
      goto Exit;
   }

  ASSERT(layerData != NULL);

   //
   // We don't re-inspect packets that we've inspected earlier.
   //
   packetState = FwpsQueryPacketInjectionState0(
                     gInjectionHandle,
                     layerData,
                     NULL
                     );

   if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
       (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
   {
      classifyOut->actionType = FWP_ACTION_PERMIT;
      goto Exit;
   }

   addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId);

   if (!IsAleReauthorize(inFixedValues))
   {
      //
      // If the classify is the initial authorization for a connection, we 
      // queue it to the pended connection list and notify the worker thread
      // for out-of-band processing.
      //
      pendedRecvAccept = AllocateAndInitializePendedPacket(
                              inFixedValues,
                              inMetaValues,
                              addressFamily,
                              layerData,
                              TL_INSPECT_CONNECT_PACKET,
                              FWP_DIRECTION_INBOUND
                              );

      if (pendedRecvAccept == NULL)
      {
         classifyOut->actionType = FWP_ACTION_BLOCK;
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         goto Exit;
      }

      ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, 
                                            FWPS_METADATA_FIELD_COMPLETION_HANDLE));

      //
      // Pend the ALE_AUTH_RECV_ACCEPT classify.
      //
      status = FwpsPendOperation0(
                  inMetaValues->completionHandle,
                  &pendedRecvAccept->completionContext
                  );

      if (!NT_SUCCESS(status))
      {
         classifyOut->actionType = FWP_ACTION_BLOCK;
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         goto Exit;
      }

      KeAcquireInStackQueuedSpinLock(
         &gConnListLock,
         &connListLockHandle
         );
      KeAcquireInStackQueuedSpinLock(
         &gPacketQueueLock,
         &packetQueueLockHandle
         );

      signalWorkerThread = IsListEmpty(&gConnList) && 
                           IsListEmpty(&gPacketQueue);

      InsertTailList(&gConnList, &pendedRecvAccept->listEntry);
      pendedRecvAccept = NULL; // ownership transferred

      KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
      KeReleaseInStackQueuedSpinLock(&connListLockHandle);

      classifyOut->actionType = FWP_ACTION_BLOCK;
      classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;

      if (signalWorkerThread)
      {
         KeSetEvent(
            &gWorkerEvent, 
            0, 
            FALSE
            );
      }

   }
   else // re-auth @ ALE_AUTH_RECV_ACCEPT
   {
      FWP_DIRECTION packetDirection;
      //
      // The classify is the re-authorization for a existing connection, it 
      // could have been triggered for one of the two cases --
      //
      //    1) The re-auth is triggered by an outbound packet sent immediately
      //       after a policy change at ALE_AUTH_RECV_ACCEPT layer.
      //    2) The re-auth is triggered by an inbound packet received 
      //       immediately after a policy change at ALE_AUTH_RECV_ACCEPT layer.
      //

      ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, 
                                            FWPS_METADATA_FIELD_PACKET_DIRECTION));
      packetDirection = inMetaValues->packetDirection;

      pendedPacket = AllocateAndInitializePendedPacket(
                        inFixedValues,
                        inMetaValues,
                        addressFamily,
                        layerData,
                        TL_INSPECT_REAUTH_PACKET,
                        packetDirection
                        );

      if (pendedPacket == NULL)
      {
         classifyOut->actionType = FWP_ACTION_BLOCK;
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         goto Exit;
      }

      if (packetDirection == FWP_DIRECTION_INBOUND)
      {
         pendedPacket->ipSecProtected = IsSecureConnection(inFixedValues);
      }

      KeAcquireInStackQueuedSpinLock(
         &gConnListLock,
         &connListLockHandle
         );
      KeAcquireInStackQueuedSpinLock(
         &gPacketQueueLock,
         &packetQueueLockHandle
         );

      if (!gDriverUnloading)
      {
         signalWorkerThread = IsListEmpty(&gPacketQueue) &&
                              IsListEmpty(&gConnList);

         InsertTailList(&gPacketQueue, &pendedPacket->listEntry);
         pendedPacket = NULL; // ownership transferred

         classifyOut->actionType = FWP_ACTION_BLOCK;
         classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
      }
      else
      {
         //
         // Driver is being unloaded, permit any connect classify.
         //
         signalWorkerThread = FALSE;

         classifyOut->actionType = FWP_ACTION_PERMIT;
      }

      KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
      KeReleaseInStackQueuedSpinLock(&connListLockHandle);

      if (signalWorkerThread)
      {
         KeSetEvent(
            &gWorkerEvent, 
            0, 
            FALSE
            );
      }
   }

Exit:

   if (pendedPacket != NULL)
   {
      FreePendedPacket(pendedPacket);
   }
   if (pendedRecvAccept != NULL)
   {
      FreePendedPacket(pendedRecvAccept);
   }

   return;
}
Beispiel #5
0
void
TLInspectALEConnectClassify(
   IN const FWPS_INCOMING_VALUES0* inFixedValues,
   IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
   IN OUT void* layerData,
   IN const FWPS_FILTER0* filter,
   IN UINT64 flowContext,
   OUT FWPS_CLASSIFY_OUT0* classifyOut
   )
/* ++

   This is the classifyFn function for the ALE connect (v4 and v6) callout.
   For an initial classify (where the FWP_CONDITION_FLAG_IS_REAUTHORIZE flag
   is not set), it is queued to the connection list for inspection by the
   worker thread. For re-auth, we first check if it is triggered by an ealier
   FwpsCompleteOperation0 call by looking for an pended connect that has been
   inspected. If found, we remove it from the connect list and return the 
   inspection result; otherwise we can conclude that the re-auth is triggered 
   by policy change so we queue it to the packet queue to be process by the 
   worker thread like any other regular packets.

-- */
{
   NTSTATUS status;

   KLOCK_QUEUE_HANDLE connListLockHandle;
   KLOCK_QUEUE_HANDLE packetQueueLockHandle;

   TL_INSPECT_PENDED_PACKET* pendedConnect = NULL;
   TL_INSPECT_PENDED_PACKET* pendedPacket = NULL;

   ADDRESS_FAMILY addressFamily;
   FWPS_PACKET_INJECTION_STATE packetState;
   BOOLEAN signalWorkerThread;

   UNREFERENCED_PARAMETER(flowContext);
   UNREFERENCED_PARAMETER(filter);

   //
   // We don't have the necessary right to alter the classify, exit.
   //
   if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
   {
      goto Exit;
   }

   if (layerData != NULL)
   {
      //
      // We don't re-inspect packets that we've inspected earlier.
      //
      packetState = FwpsQueryPacketInjectionState0(
                     gInjectionHandle,
                     layerData,
                     NULL
                     );

      if ((packetState == FWPS_PACKET_INJECTED_BY_SELF) ||
          (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
      {
         classifyOut->actionType = FWP_ACTION_PERMIT;
         goto Exit;
      }
   }

   addressFamily = GetAddressFamilyForLayer(inFixedValues->layerId);

   if (!IsAleReauthorize(inFixedValues))
   {
      //
      // If the classify is the initial authorization for a connection, we 
      // queue it to the pended connection list and notify the worker thread
      // for out-of-band processing.
      //
      pendedConnect = AllocateAndInitializePendedPacket(
                           inFixedValues,
                           inMetaValues,
                           addressFamily,
                           layerData,
                           TL_INSPECT_CONNECT_PACKET,
                           FWP_DIRECTION_OUTBOUND
                           );

      if (pendedConnect == NULL)
      {
         classifyOut->actionType = FWP_ACTION_BLOCK;
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         goto Exit;
      }

      ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, 
                                            FWPS_METADATA_FIELD_COMPLETION_HANDLE));

      //
      // Pend the ALE_AUTH_CONNECT classify.
      //
      status = FwpsPendOperation0(
                  inMetaValues->completionHandle,
                  &pendedConnect->completionContext
                  );

      if (!NT_SUCCESS(status))
      {
         classifyOut->actionType = FWP_ACTION_BLOCK;
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         goto Exit;
      }

      KeAcquireInStackQueuedSpinLock(
         &gConnListLock,
         &connListLockHandle
         );
      KeAcquireInStackQueuedSpinLock(
         &gPacketQueueLock,
         &packetQueueLockHandle
         );

      signalWorkerThread = IsListEmpty(&gConnList) && 
                           IsListEmpty(&gPacketQueue);

      InsertTailList(&gConnList, &pendedConnect->listEntry);
      pendedConnect = NULL; // ownership transferred

      KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
      KeReleaseInStackQueuedSpinLock(&connListLockHandle);

      classifyOut->actionType = FWP_ACTION_BLOCK;
      classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;

      if (signalWorkerThread)
      {
         KeSetEvent(
            &gWorkerEvent, 
            0, 
            FALSE
            );
      }
   }
   else // re-auth @ ALE_AUTH_CONNECT
   {
      FWP_DIRECTION packetDirection;
      //
      // The classify is the re-authorization for an existing connection, it 
      // could have been triggered for one of the three cases --
      //
      //    1) The re-auth is triggered by a FwpsCompleteOperation0 call to
      //       complete a ALE_AUTH_CONNECT classify pended earlier. 
      //    2) The re-auth is triggered by an outbound packet sent immediately
      //       after a policy change at ALE_AUTH_CONNECT layer.
      //    3) The re-auth is triggered by an inbound packet received 
      //       immediately after a policy change at ALE_AUTH_CONNECT layer.
      //

      ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues, 
                                            FWPS_METADATA_FIELD_PACKET_DIRECTION));
      packetDirection = inMetaValues->packetDirection;

      if (packetDirection == FWP_DIRECTION_OUTBOUND)
      {
         LIST_ENTRY* listEntry;
         BOOLEAN authComplete = FALSE;

         //
         // We first check whether this is a FwpsCompleteOperation0- triggered
         // reauth by looking for a pended connect that has the inspection
         // decision recorded. If found, we return that decision and remove
         // the pended connect from the list.
         //

         KeAcquireInStackQueuedSpinLock(
            &gConnListLock,
            &connListLockHandle
            );

         for (listEntry = gConnList.Flink;
              listEntry != &gConnList;
              listEntry = listEntry->Flink)
         {
            pendedConnect = CONTAINING_RECORD(
                              listEntry,
                              TL_INSPECT_PENDED_PACKET,
                              listEntry
                              );

            if (IsMatchingConnectPacket(
                     inFixedValues,
                     addressFamily,
                     packetDirection,
                     pendedConnect
                  ) && (pendedConnect->authConnectDecision != 0))
            {
               ASSERT((pendedConnect->authConnectDecision == FWP_ACTION_PERMIT) ||
                      (pendedConnect->authConnectDecision == FWP_ACTION_BLOCK));
               
               classifyOut->actionType = pendedConnect->authConnectDecision;

               RemoveEntryList(&pendedConnect->listEntry);
               
               if (!gDriverUnloading &&
                   (pendedConnect->netBufferList != NULL) &&
                   (pendedConnect->authConnectDecision == FWP_ACTION_PERMIT))
               {
                  //
                  // Now the outbound connection has been authorized. If the
                  // pended connect has a net buffer list in it, we need it
                  // morph it into a data packet and queue it to the packet
                  // queue for send injecition.
                  //
                  pendedConnect->type = TL_INSPECT_DATA_PACKET;

                  KeAcquireInStackQueuedSpinLock(
                     &gPacketQueueLock,
                     &packetQueueLockHandle
                     );

                  signalWorkerThread = IsListEmpty(&gPacketQueue) &&
                                       IsListEmpty(&gConnList);

                  InsertTailList(&gPacketQueue, &pendedConnect->listEntry);
                  pendedConnect = NULL; // ownership transferred

                  KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
                  
                  if (signalWorkerThread)
                  {
                     KeSetEvent(
                        &gWorkerEvent, 
                        0, 
                        FALSE
                        );
                  }
               }

               authComplete = TRUE;
               break;
            }
         }

         KeReleaseInStackQueuedSpinLock(&connListLockHandle);

         if (authComplete)
         {
            goto Exit;
         }
      }

      //
      // If we reach here it means this is a policy change triggered re-auth
      // for an pre-existing connection. For such a packet (inbound or 
      // outbound) we queue it to the packet queue and inspect it just like
      // other regular data packets from TRANSPORT layers.
      //

      ASSERT(layerData != NULL);

      pendedPacket = AllocateAndInitializePendedPacket(
                        inFixedValues,
                        inMetaValues,
                        addressFamily,
                        layerData,
                        TL_INSPECT_REAUTH_PACKET,
                        packetDirection
                        );

      if (pendedPacket == NULL)
      {
         classifyOut->actionType = FWP_ACTION_BLOCK;
         classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
         goto Exit;
      }

      if (packetDirection == FWP_DIRECTION_INBOUND)
      {
         pendedPacket->ipSecProtected = IsSecureConnection(inFixedValues);
      }

      KeAcquireInStackQueuedSpinLock(
         &gConnListLock,
         &connListLockHandle
         );
      KeAcquireInStackQueuedSpinLock(
         &gPacketQueueLock,
         &packetQueueLockHandle
         );

      if (!gDriverUnloading)
      {
         signalWorkerThread = IsListEmpty(&gPacketQueue) &&
                              IsListEmpty(&gConnList);

         InsertTailList(&gPacketQueue, &pendedPacket->listEntry);
         pendedPacket = NULL; // ownership transferred

         classifyOut->actionType = FWP_ACTION_BLOCK;
         classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
      }
      else
      {
         //
         // Driver is being unloaded, permit any connect classify.
         //
         signalWorkerThread = FALSE;

         classifyOut->actionType = FWP_ACTION_PERMIT;
      }

      KeReleaseInStackQueuedSpinLock(&packetQueueLockHandle);
      KeReleaseInStackQueuedSpinLock(&connListLockHandle);

      if (signalWorkerThread)
      {
         KeSetEvent(
            &gWorkerEvent, 
            0, 
            FALSE
            );
      }

   }

Exit:

   if (pendedPacket != NULL)
   {
      FreePendedPacket(pendedPacket);
   }
   if (pendedConnect != NULL)
   {
      FreePendedPacket(pendedConnect);
   }

   return;
}
Beispiel #6
0
/*
 * --------------------------------------------------------------------------
 * This is the classifyFn function of the datagram-data callout. It
 * allocates a packet structure to store the classify and meta data and
 * it references the net buffer list for out-of-band modification and
 * re-injection. The packet structure will be queued to the global packet
 * queue. The worker thread will then be signaled, if idle, to process
 * the queue.
 * --------------------------------------------------------------------------
 */
VOID
OvsTunnelClassify(const FWPS_INCOMING_VALUES *inFixedValues,
                  const FWPS_INCOMING_METADATA_VALUES *inMetaValues,
                  VOID *layerData,
                  const VOID *classifyContext,
                  const FWPS_FILTER *filter,
                  UINT64 flowContext,
                  FWPS_CLASSIFY_OUT *classifyOut)
{
    OVS_TUNNEL_PENDED_PACKET packetStorage;
    OVS_TUNNEL_PENDED_PACKET *packet = &packetStorage;
    FWP_DIRECTION  direction;

    UNREFERENCED_PARAMETER(classifyContext);
    UNREFERENCED_PARAMETER(filter);
    UNREFERENCED_PARAMETER(flowContext);

    ASSERT(layerData != NULL);

    /* We don't have the necessary right to alter the packet flow */
    if ((classifyOut->rights & FWPS_RIGHT_ACTION_WRITE) == 0) {
        /* XXX TBD revisit protect against other filters owning this packet */
        ASSERT(FALSE);
        goto Exit;
    }

    RtlZeroMemory(packet, sizeof(OVS_TUNNEL_PENDED_PACKET));

    /* classifyOut cannot be accessed from a different thread context */
    packet->classifyOut = classifyOut;

    if (inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V4) {
        direction =
            inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].\
            value.uint32;
    }
    else {
        ASSERT(inFixedValues->layerId == FWPS_LAYER_DATAGRAM_DATA_V6);
        direction =
            inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V6_DIRECTION].\
            value.uint32;
    }

    packet->netBufferList = layerData;

    ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
        FWPS_METADATA_FIELD_COMPARTMENT_ID));

    ASSERT(direction == FWP_DIRECTION_INBOUND);

    ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
        inMetaValues,
        FWPS_METADATA_FIELD_IP_HEADER_SIZE));
    ASSERT(FWPS_IS_METADATA_FIELD_PRESENT(
        inMetaValues,
        FWPS_METADATA_FIELD_TRANSPORT_HEADER_SIZE));

    packet->ipHeaderSize = inMetaValues->ipHeaderSize;
    packet->transportHeaderSize = inMetaValues->transportHeaderSize;

    ASSERT(inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_PROTOCOL].value.uint8 == IPPROTO_UDP );
    OvsTunnelAnalyzePacket(packet);

Exit:
    ;
}
NTSTATUS PrvCloneAuthorizedNBLAndInject(_Inout_ CLASSIFY_DATA** ppClassifyData,
                                        _Inout_ INJECTION_DATA** ppInjectionData)
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> PrvCloneAuthorizedNBLAndInject()\n");

#endif /// DBG
   
   NT_ASSERT(ppClassifyData);
   NT_ASSERT(ppInjectionData);
   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;
   UINT32                              bytesRetreated  = 0;
   COMPARTMENT_ID                      compartmentID   = UNSPECIFIED_COMPARTMENT_ID;
   BOOLEAN                             isInbound       = FALSE;
   NET_BUFFER_LIST*                    pNetBufferList  = 0;
   PEND_AUTHORIZATION_COMPLETION_DATA* pCompletionData = 0;
   FWPS_TRANSPORT_SEND_PARAMS*         pSendParams     = 0;
   BYTE*                               pRemoteAddress  = 0;

#pragma warning(push)
#pragma warning(disable: 6014) /// pCompletionData will be freed in completionFn using PendAuthorizationCompletionDataDestroy

   HLPR_NEW(pCompletionData,
            PEND_AUTHORIZATION_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 = FALSE;
   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(pCompletionData->pInjectionData->direction == FWP_DIRECTION_INBOUND)
      isInbound = TRUE;

   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 = pMetadata->ipHeaderSize;

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

   if(pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 ||
      pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V6)
   {
      if(isInbound) /// NBL offset is at the start of the transport header ...
      {
         if(bytesRetreated)
         {
            /// so retreat (size of IP Header) to clone the whole NBL
            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,
                          " !!!! PrvCloneAuthorizedNBLAndInject: NdisRetreatNetBufferDataStart() [status: %#x]\n",
                          status);

               HLPR_BAIL;
            }
         }
      }
   }
   else if(pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V4 ||
           pClassifyValues->layerId == FWPS_LAYER_ALE_AUTH_CONNECT_V6)
   {
      /// NBL offset is at the Transport Header, and no IP Header is present yet
      bytesRetreated = 0;

      isInbound = FALSE;
   }
   else
   {
      status = STATUS_FWP_INCOMPATIBLE_LAYER;

      HLPR_BAIL;
   }

   status = FwpsAllocateCloneNetBufferList((NET_BUFFER_LIST*)(pCompletionData->pClassifyData->pPacket),
                                           g_pNDISPoolData->nblPoolHandle,
                                           g_pNDISPoolData->nbPoolHandle,
                                           0,
                                           &pNetBufferList);

   if(bytesRetreated)
   {
      /// Advance the NBL offset so we are back at the expected position in the NET_BUFFER_LIST
      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,
                 " !!!! PrvCloneAuthorizedNBLAndInject : FwpsAllocateCloneNetBufferList() [status: %#x]\n",
                 status);

      HLPR_BAIL;
   }

   if(isInbound)
   {
      FWP_VALUE* pInterfaceIndex    = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
                                                                                &FWPM_CONDITION_INTERFACE_INDEX);
      FWP_VALUE* pSubInterfaceIndex = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
                                                                                &FWPM_CONDITION_SUB_INTERFACE_INDEX);
      IF_INDEX   interfaceIndex     = 0;
      IF_INDEX   subInterfaceIndex  = 0;

      if(pInterfaceIndex &&
         pInterfaceIndex->type == FWP_UINT32)
         interfaceIndex = (IF_INDEX)pInterfaceIndex->uint32;

      if(pSubInterfaceIndex &&
         pSubInterfaceIndex->type == FWP_UINT32)
         subInterfaceIndex = (IF_INDEX)pSubInterfaceIndex->uint32;

      status = FwpsInjectTransportReceiveAsync(pCompletionData->pInjectionData->injectionHandle,
                                               pCompletionData->pInjectionData->injectionContext,
                                               0,
                                               0,
                                               pCompletionData->pInjectionData->addressFamily,
                                               compartmentID,
                                               interfaceIndex,
                                               subInterfaceIndex,
                                               pNetBufferList,
                                               CompletePendAuthorization,
                                               pCompletionData);
   }
   else
   {
      UINT64     endpointHandle = 0;
      FWP_VALUE* pAddressValue  = 0;

      if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                        FWPS_METADATA_FIELD_TRANSPORT_ENDPOINT_HANDLE))
         endpointHandle = pMetadata->transportEndpointHandle;

      pAddressValue = KrnlHlprFwpValueGetFromFwpsIncomingValues(pClassifyValues,
                                                                &FWPM_CONDITION_IP_REMOTE_ADDRESS);
      if(pAddressValue)
      {
         if(pCompletionData->pInjectionData->addressFamily == AF_INET)
         {
            UINT32 tempAddress = htonl(pAddressValue->uint32);

#pragma warning(push)
#pragma warning(disable: 6014) /// pRemoteAddress will be freed in completionFn using PendAuthorizationCompletionDataDestroy

            HLPR_NEW_ARRAY(pRemoteAddress,
                           BYTE,
                           IPV4_ADDRESS_SIZE,
                           WFPSAMPLER_CALLOUT_DRIVER_TAG);
            HLPR_BAIL_ON_ALLOC_FAILURE(pRemoteAddress,
                                       status);

#pragma warning(pop)

            RtlCopyMemory(pRemoteAddress,
                          &tempAddress,
                          IPV4_ADDRESS_SIZE);
         }
         else
         {

#pragma warning(push)
#pragma warning(disable: 6014) /// pRemoteAddress will be freed in completionFn using PendAuthorizationCompletionDataDestroy

            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;
      }

      pCompletionData->refCount = KrnlHlprNBLGetRequiredRefCount(pNetBufferList);

      status = FwpsInjectTransportSendAsync(pCompletionData->pInjectionData->injectionHandle,
                                            pCompletionData->pInjectionData->injectionContext,
                                            endpointHandle,
                                            0,
                                            pCompletionData->pSendParams,
                                            pCompletionData->pInjectionData->addressFamily,
                                            compartmentID,
                                            pNetBufferList,
                                            CompletePendAuthorization,
                                            pCompletionData);
   }

   HLPR_BAIL_LABEL:

   if(status != STATUS_SUCCESS)
   {
      if(pNetBufferList)
      {
         FwpsFreeCloneNetBufferList(pNetBufferList,
                                    0);

         pNetBufferList = 0;
      }

      if(pCompletionData)
         PendAuthorizationCompletionDataDestroy(&pCompletionData,
                                                TRUE);
   }

#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- PrvCloneAuthorizedNBLAndInject() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}
Beispiel #8
0
void
NPF_NetworkClassify(
	_In_ const FWPS_INCOMING_VALUES* inFixedValues,
	_In_ const FWPS_INCOMING_METADATA_VALUES* inMetaValues,
	_Inout_opt_ void* layerData,
	_In_ const FWPS_FILTER* filter,
	_In_ UINT64 flowContext,
	_Inout_ FWPS_CLASSIFY_OUT* classifyOut
	)

#endif

{
	POPEN_INSTANCE		GroupOpen;
	POPEN_INSTANCE		TempOpen;
	NTSTATUS			status = STATUS_SUCCESS;
	UINT32				ipHeaderSize = 0;
	UINT32				bytesRetreated = 0;
	UINT32				bytesRetreatedEthernet = 0;
	INT32				iIPv4 = -1;
	INT32				iDrection = -1;
	BOOLEAN				bSelfSent = FALSE;
	PVOID				pContiguousData = NULL;
	NET_BUFFER*			pNetBuffer = 0;
	UCHAR				pPacketData[ETHER_HDR_LEN];
	PNET_BUFFER_LIST	pNetBufferList = (NET_BUFFER_LIST*) layerData;
	COMPARTMENT_ID		compartmentID = UNSPECIFIED_COMPARTMENT_ID;
	FWPS_PACKET_INJECTION_STATE injectionState = FWPS_PACKET_INJECTION_STATE_MAX;

#if(NTDDI_VERSION >= NTDDI_WIN7)
	UNREFERENCED_PARAMETER(classifyContext);
#endif
	UNREFERENCED_PARAMETER(filter);
	UNREFERENCED_PARAMETER(flowContext);

	// Make the default action.
	if (classifyOut->rights & FWPS_RIGHT_ACTION_WRITE)
		classifyOut->actionType = FWP_ACTION_CONTINUE;

#if(NTDDI_VERSION >= NTDDI_WIN7)
	// Filter out fragment packets and reassembled packets.
	if (inMetaValues->currentMetadataValues & FWPS_METADATA_FIELD_FRAGMENT_DATA)
	{
		return;
	}
	if (inMetaValues->currentMetadataValues & FWP_CONDITION_FLAG_IS_REASSEMBLED)
	{
		return;
	}
#endif

	TRACE_ENTER();

	// Get the packet protocol (IPv4 or IPv6) and the direction (Inbound or Outbound).
	if (inFixedValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || inFixedValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4)
	{
		iIPv4 = 1;
	}
	else // if (inFixedValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6 || inFixedValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6)
	{
		iIPv4 = 0;
	}
	if (inFixedValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V4 || inFixedValues->layerId == FWPS_LAYER_OUTBOUND_IPPACKET_V6)
	{
		iDrection = 0;
	}
	else // if (inFixedValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V4 || inFixedValues->layerId == FWPS_LAYER_INBOUND_IPPACKET_V6)
	{
		iDrection = 1;
	}

	if (inMetaValues->currentMetadataValues & FWPS_METADATA_FIELD_IP_HEADER_SIZE)
	{
		ipHeaderSize = inMetaValues->ipHeaderSize;
	}

	injectionState = FwpsQueryPacketInjectionState(iIPv4 ? g_InjectionHandle_IPv4 : g_InjectionHandle_IPv6,
		pNetBufferList,
		NULL);
	if (injectionState == FWPS_PACKET_INJECTED_BY_SELF ||
		injectionState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF)
	{
		TRACE_MESSAGE(PACKET_DEBUG_LOUD,
			"NPF_NetworkClassify: this packet is injected by ourself, let it go\n");

		TRACE_EXIT();
		return;
	}

	// Inbound: Initial offset is at the Transport Header, so retreat the size of the Ethernet Header and IP Header.
	// Outbound: Initial offset is at the IP Header, so just retreat the size of the Ethernet Header.
	// We retreated the packet in two phases: 1) retreat the IP Header (if has), 2) clone the packet and retreat the Ethernet Header.
	// We must NOT retreat the Ethernet Header on the original packet, or this will lead to BAD_POOL_CALLER Bluescreen.
	bytesRetreated = iDrection ? ipHeaderSize : 0;

	status = NdisRetreatNetBufferListDataStart(pNetBufferList,
		bytesRetreated,
		0,
		NULL,
		NULL);

	if (status != STATUS_SUCCESS)
	{
		TRACE_MESSAGE1(PACKET_DEBUG_LOUD,
			"NPF_NetworkClassify: NdisRetreatNetBufferListDataStart(bytesRetreated) [status: %#x]\n",
			status);

		TRACE_EXIT();
		return;
	}

	//bSelfSent = NPF_IsPacketSelfSent(pNetBufferList, (BOOLEAN)iIPv4);
	bSelfSent = (iDrection == 0) ? FALSE : NPF_IsPacketSelfSent(pNetBufferList, (BOOLEAN) iIPv4);
	TRACE_MESSAGE1(PACKET_DEBUG_LOUD,
		"NPF_NetworkClassify: NPF_IsPacketSelfSent() [bSelfSent: %#x]\n",
		bSelfSent);

	if (bSelfSent)
	{
		NdisAdvanceNetBufferListDataStart(pNetBufferList,
			iIPv4 ? IP_HDR_LEN : IPV6_HDR_LEN,
			FALSE,
			0);
	}

	// Here if this NBL is sent by ourself, we will clone it starting from IP header and inject it into Network Layer send path.
	if (bSelfSent)
	{
		PNET_BUFFER_LIST pClonedNetBufferList_Injection;
		status = FwpsAllocateCloneNetBufferList(pNetBufferList, NULL, NULL, 0, &pClonedNetBufferList_Injection);
		if (status != STATUS_SUCCESS)
		{
			TRACE_MESSAGE1(PACKET_DEBUG_LOUD,
				"NPF_NetworkClassify: FwpsAllocateCloneNetBufferList(pClonedNetBufferList_Injection) [status: %#x]\n",
				status);

			goto Exit_WSK_IP_Retreated;
		}

		if (FWPS_IS_METADATA_FIELD_PRESENT(inMetaValues,
			FWPS_METADATA_FIELD_COMPARTMENT_ID))
			compartmentID = (COMPARTMENT_ID)inMetaValues->compartmentId;

		// This cloned NBL will be freed in NPF_NetworkInjectionComplete function.
		status = FwpsInjectNetworkSendAsync(iIPv4 ? g_InjectionHandle_IPv4 : g_InjectionHandle_IPv6,
			NULL,
			0,
			compartmentID,
			pClonedNetBufferList_Injection,
			NPF_NetworkInjectionComplete,
			NULL);
		if (status != STATUS_SUCCESS)
		{
			TRACE_MESSAGE1(PACKET_DEBUG_LOUD,
				"NPF_NetworkClassify: FwpsInjectNetworkSendAsync() [status: %#x]\n",
				status);

			FwpsFreeCloneNetBufferList(pClonedNetBufferList_Injection, 0);
			goto Exit_WSK_IP_Retreated;
		}

		// We have successfully re-inject the cloned NBL, so remove this one.
		classifyOut->actionType = FWP_ACTION_BLOCK;
		classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
		classifyOut->rights ^= FWPS_RIGHT_ACTION_WRITE;
	}

	// We clone this NBL again, for packet reading operation.
	PNET_BUFFER_LIST pClonedNetBufferList;
	status = FwpsAllocateCloneNetBufferList(pNetBufferList, NULL, NULL, 0, &pClonedNetBufferList);
	if (status != STATUS_SUCCESS)
	{
		TRACE_MESSAGE1(PACKET_DEBUG_LOUD,
			"NPF_NetworkClassify: FwpsAllocateCloneNetBufferList() [status: %#x]\n",
			status);

		goto Exit_WSK_IP_Retreated;
	}

	bytesRetreatedEthernet = g_DltNullMode ? DLT_NULL_HDR_LEN : ETHER_HDR_LEN;
	status = NdisRetreatNetBufferListDataStart(pClonedNetBufferList,
		bytesRetreatedEthernet,
		0,
		0,
		0);
	if (status != STATUS_SUCCESS)
	{
		bytesRetreatedEthernet = 0;

		TRACE_MESSAGE1(PACKET_DEBUG_LOUD,
			"NPF_NetworkClassify: NdisRetreatNetBufferListDataStart(bytesRetreatedEthernet) [status: %#x]\n",
			status);

		goto Exit_Packet_Cloned;
	}

	pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pClonedNetBufferList);
	while (pNetBuffer)
	{
		pContiguousData = NdisGetDataBuffer(pNetBuffer,
			bytesRetreatedEthernet,
			pPacketData,
			1,
			0);
		if (!pContiguousData)
		{
			status = STATUS_UNSUCCESSFUL;

			TRACE_MESSAGE1(PACKET_DEBUG_LOUD,
				"NPF_NetworkClassify: NdisGetDataBuffer() [status: %#x]\n",
				status);

			goto Exit_Ethernet_Retreated;
		}
		else
		{
			if (g_DltNullMode)
			{
				((PDLT_NULL_HEADER) pContiguousData)->null_type = iIPv4 ? DLTNULLTYPE_IP : DLTNULLTYPE_IPV6;
			}
			else
			{
				RtlZeroMemory(pContiguousData, ETHER_ADDR_LEN * 2);
				((PETHER_HEADER) pContiguousData)->ether_type = iIPv4 ? RtlUshortByteSwap(ETHERTYPE_IP) : RtlUshortByteSwap(ETHERTYPE_IPV6);
			}
		}

		pNetBuffer = pNetBuffer->Next;
	}

	// Send the loopback packets data to the user-mode code.
	if (g_LoopbackOpenGroupHead)
	{
		//get the 1st group adapter child
		GroupOpen = g_LoopbackOpenGroupHead->GroupNext;
	}
	else
	{
		// Should not come here
		GroupOpen = NULL;
	}

	while (GroupOpen != NULL)
	{
		TempOpen = GroupOpen;
		if (TempOpen->AdapterBindingStatus == ADAPTER_BOUND)
		{
			//let every group adapter receive the packets
			NPF_TapExForEachOpen(TempOpen, pClonedNetBufferList);
		}

		GroupOpen = TempOpen->GroupNext;
	}

Exit_Ethernet_Retreated:
	// Advance the offset back to the original position.
	NdisAdvanceNetBufferListDataStart(pClonedNetBufferList,
		bytesRetreatedEthernet,
		FALSE,
		0);

Exit_Packet_Cloned:
	FwpsFreeCloneNetBufferList(pClonedNetBufferList, 0);

Exit_WSK_IP_Retreated:
	if (bSelfSent)
	{
		status = NdisRetreatNetBufferListDataStart(pNetBufferList,
			iIPv4 ? IP_HDR_LEN : IPV6_HDR_LEN,
			0,
			NULL,
			NULL);

// 		if (status != STATUS_SUCCESS)
// 		{
// 			TRACE_MESSAGE1(PACKET_DEBUG_LOUD,
// 				"NPF_NetworkClassify: NdisRetreatNetBufferListDataStart(IP_HDR_LEN) [status: %#x]\n",
// 				status);
//
// 			goto Exit_IP_Retreated;
// 		}
	}

/*Exit_IP_Retreated:*/
	NdisAdvanceNetBufferListDataStart(pNetBufferList,
		bytesRetreated,
		FALSE,
		0);

// 	// print "protocol, direction, fragment, reassembled" info for the current packet.
// 
// 	int iFragment = -1;
// 	if (inMetaValues->currentMetadataValues & FWPS_METADATA_FIELD_FRAGMENT_DATA)
// 	{
// 		iFragment = 1;
// 	}
// 	else
// 	{
// 		iFragment = 0;
// 	}
// 
// 	int iReassembled = -1;
// 	if (inMetaValues->currentMetadataValues & FWP_CONDITION_FLAG_IS_REASSEMBLED)
// 	{
// 		iReassembled = 1;
// 	}
// 	else
// 	{
// 		iReassembled = 0;
// 	}
// 	IF_LOUD(DbgPrint("\n\nNPF_NetworkClassify: Loopback packet found !!! protocol=[%d] (ipv4=0, ipv6=1), direction=[%d] (out=0, in=1), fragment=[%d], reassembled=[%d]\n", iProtocol, iDrection, iFragment, iReassembled);)


	TRACE_EXIT();
	return;
}
NTSTATUS KrnlHlprPendDataPopulate(_Inout_ PEND_DATA* pPendData,
                                  _In_ const FWPS_INCOMING_VALUES* pClassifyValues,
                                  _In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata,
                                  _In_opt_ NET_BUFFER_LIST* pNBL,
                                  _In_ const FWPS_FILTER* pFilter,
                                  _In_opt_ VOID* pClassifyContext,                         /* 0 */
                                  _In_opt_ FWPS_CLASSIFY_OUT* pClassifyOut)                /* 0 */
{
#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " ---> KrnlHlprPendDataPopulate()\n");

#endif /// DBG
   
   NT_ASSERT(pPendData);
   NT_ASSERT(pClassifyValues);
   NT_ASSERT(pMetadata);
   NT_ASSERT(pFilter);

   NTSTATUS status = STATUS_SUCCESS;

   pPendData->layerID = pClassifyValues->layerId;

#if(NTDDI_VERSION >= NTDDI_WIN7)

   if(pPendData->layerID == FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V4 ||
      pPendData->layerID == FWPS_LAYER_ALE_ENDPOINT_CLOSURE_V6)
   {
      NT_ASSERT(pClassifyContext);
      NT_ASSERT(pClassifyOut);

      if(pClassifyContext &&
         pClassifyOut)
      {
         status = FwpsAcquireClassifyHandle(pClassifyContext,
                                            0,
                                            &(pPendData->classifyHandle));
         if(status != STATUS_SUCCESS)
         {
            DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                       DPFLTR_ERROR_LEVEL,
                       " !!!! KrnlHlprPendDataPopulate : FwpsAcquireClassifyHandle() [status: %#x]\n",
                       status);
         
            HLPR_BAIL;
         }

         status = FwpsPendClassify(pPendData->classifyHandle,
                                   pFilter->filterId,
                                   0,
                                   pClassifyOut);
         if(status != STATUS_SUCCESS)
         {
            DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                       DPFLTR_ERROR_LEVEL,
                       " !!!! KrnlHlprPendDataPopulate : FwpsPendClassify() [status: %#x]\n",
                       status);
         
            HLPR_BAIL;
         }

         RtlCopyMemory(&(pPendData->classifyOut),
                       pClassifyOut,
                       sizeof(FWPS_CLASSIFY_OUT));

         pPendData->pPCPendData = pFilter->providerContext->dataBuffer->data;
         pPendData->isPended    = TRUE;
      }
      else
      {
         status = STATUS_INVALID_PARAMETER;

         DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                    DPFLTR_ERROR_LEVEL,
                    " !!!! KrnlHlprPendDataPopulate : [status: %#x][pClassifyContext: %#p][pClassifyOut: %#p]\n",
                    status,
                    pClassifyContext,
                    pClassifyOut);

         HLPR_BAIL;
      }
   }
   else

#else

   UNREFERENCED_PARAMETER(pClassifyContext);
   UNREFERENCED_PARAMETER(pClassifyOut);

#endif /// (NTDDI_VERSION >= NTDDI_WIN7)

   {


      if(FWPS_IS_METADATA_FIELD_PRESENT(pMetadata,
                                        FWPS_METADATA_FIELD_COMPLETION_HANDLE))
      {
         status = FwpsPendOperation(pMetadata->completionHandle,
                                    &(pPendData->completionContext));
         if(status != STATUS_SUCCESS)
         {
            DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                       DPFLTR_ERROR_LEVEL,
                       " !!!! KrnlHlprPendDataPopulate : FwpsPendOperation() [status: %#x]\n",
                       status);

            HLPR_BAIL;
         }

         pPendData->pNBL        = pNBL;
         pPendData->pPCPendData = pFilter->providerContext->dataBuffer->data;
         pPendData->isPended    = TRUE;
      }
      else
      {
         status = STATUS_INVALID_HANDLE;

         DbgPrintEx(DPFLTR_IHVNETWORK_ID,
                    DPFLTR_ERROR_LEVEL,
                    " !!!! KrnlHlprPendDataPopulate() [status: %#x]\n",
                    status);
      }
   }

   HLPR_BAIL_LABEL:

   if(status != STATUS_SUCCESS)
      KrnlHlprPendDataPurge(pPendData);


#if DBG
   
   DbgPrintEx(DPFLTR_IHVNETWORK_ID,
              DPFLTR_INFO_LEVEL,
              " <--- KrnlHlprPendDataPopulate() [status: %#x]\n",
              status);

#endif /// DBG
   
   return status;
}