locked
Delay inbound connection RRS feed

  • Question

  • It is not enough to pend packet at FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4. All packets from FWPM_LAYER_INBOUND_TRANSPORT_V4 also should be pended until authorization verdict. Am I right?
    Monday, February 20, 2012 8:22 AM

Answers

  • I found a bug.

    1)

        acceptContext->interfaceIndex = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_CONNECT_V4_INTERFACE_INDEX ].value.uint32;
        acceptContext->subInterfaceIndex = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_CONNECT_V4_SUB_INTERFACE_INDEX ].value.uint32; T

    2)
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; 

    This sample delays inbound connection for a second

    #include <ntddk.h>
    #include <wdmsec.h>
    #include <ndis.h>
    
    #include <initguid.h>
    
    #define INITGUID
    
    #include <fwpsk.h>
    #include <fwpmk.h>
    
    /////////////////////////////////////////////////////////////////////////////
    
    // {D4980309-28EB-44a3-8FA3-CAA74C824F65}
    DEFINE_GUID(SUBLAYER_KEY, 
    0xd4980309, 0x28eb, 0x44a3, 0x8f, 0xa3, 0xca, 0xa7, 0x4c, 0x82, 0x4f, 0x65);
    
    
    // {A15A1001-4551-4178-AD95-69F78225BDC4}
    DEFINE_GUID(CALLOUT_KEY, 
    0xa15a1001, 0x4551, 0x4178, 0xad, 0x95, 0x69, 0xf7, 0x82, 0x25, 0xbd, 0xc5);
    
    // {3278C545-CA51-4d94-BDEA-13A8FDFE4ABA}
    DEFINE_GUID(FILTER_KEY, 
    0x3278c545, 0xca51, 0x4d94, 0xbd, 0xea, 0x13, 0xa8, 0xfd, 0xfe, 0x4a, 0xba);
    
    /////////////////////////////////////////////////////////////////////////////
    
    typedef struct ALERECV_ACCEPT_CONTEXT_ {
    
        PNET_BUFFER_LIST            netBufferList; 
        
        ADDRESS_FAMILY              addressFamily;
    
        ULONG                       compartmentId;
        
        IF_INDEX                    interfaceIndex;
        
        IF_INDEX                    subInterfaceIndex;  
        
        UINT32                      ipHeaderSize;
        
        UINT32                      transportHeaderSize;      
        
        PVOID                       completionContext;      
        
        PIO_WORKITEM                workItem;
        
    } ALERECV_ACCEPT_CONTEXT, *PALERECV_ACCEPT_CONTEXT;
    
    #define  ACCEPT_CONTEXT_TAG     'ctca'
    
    /////////////////////////////////////////////////////////////////////////////
    
    HANDLE              g_injectHandle = 0;
    
    PDEVICE_OBJECT      g_deviceObject = NULL;
    
    UINT32              g_calloutRegId = 0;
    
    HANDLE              g_engineHandle = NULL;
    
    /////////////////////////////////////////////////////////////////////////////
    
    DRIVER_INITIALIZE       DriverEntry;
    DRIVER_UNLOAD           DriverUnload;
    
    NTSTATUS InitFwpObjects();
    VOID CleanupWfpObjects();
    
    NTSTATUS 
    AleRecvNotify(
        __in FWPS_CALLOUT_NOTIFY_TYPE notifyType,
        __in const GUID *filterKey,
        __in const FWPS_FILTER1 *filter
        ) 
    {
        return STATUS_SUCCESS;
    }   
    
    VOID
    AleRecvAcceptClassify(
        __in const FWPS_INCOMING_VALUES0 *inFixedValues,
        __in const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
        __inout VOID *layerData,
        __in_opt const VOID *classifyContext,
        __in const FWPS_FILTER1 *filter,
        __in UINT64 flowContext,
        __out FWPS_CLASSIFY_OUT0 *classifyOut
        ); 
       
        
    IO_WORKITEM_ROUTINE          AleRecvAcceptPendWork;     
    
    VOID
    AleRecvAcceptInjectComplete(
        __in VOID* context,
        __inout NET_BUFFER_LIST* netBufferList,
        __in BOOLEAN dispatchLevel
        ); 
    
    PALERECV_ACCEPT_CONTEXT    
    AleRecvAcceptContextCreate(
        __in const FWPS_INCOMING_VALUES0 *inFixedValues,
        __in const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
        __in PNET_BUFFER_LIST netBufferList
        );
    
    VOID
    AleRecvAcceptContextFree(
        __in PALERECV_ACCEPT_CONTEXT  acceptContext
        );    
        
    
    /////////////////////////////////////////////////////////////////////////////
    
    NTSTATUS
    DriverEntry(
        __in PDRIVER_OBJECT   driverObject,
        __in PUNICODE_STRING  registryPath
        )
    {
        NTSTATUS    status = STATUS_UNSUCCESSFUL;
        UNREFERENCED_PARAMETER( registryPath );
        
        do {
        
            driverObject->DriverUnload = DriverUnload;
            
            status = InitFwpObjects( driverObject );
            
            if ( !NT_SUCCESS( status ) )
                break;
      
            status = STATUS_SUCCESS;    
        
        } while( FALSE );
        
        if ( !NT_SUCCESS( status ) )
            DriverUnload( driverObject );
        
        return status;
    }
    
    /////////////////////////////////////////////////////////////////////////////
    
    VOID
    DriverUnload(
        __in PDRIVER_OBJECT  driverObject )
    {
        CleanupWfpObjects();    
    } 
    
    /////////////////////////////////////////////////////////////////////////////
    
    NTSTATUS InitFwpObjects(
        __in PDRIVER_OBJECT  driverObject
        )
    {
        NTSTATUS                status = STATUS_UNSUCCESSFUL;
        FWPS_CALLOUT            calloutReg = { 0 }; 
        FWPM_SESSION            session = { 0 };    
        FWPM_SUBLAYER           subLayer = { 0 };   
        FWPM_CALLOUT            callout = { 0 };     
        FWPM_FILTER             filter = { 0 };
        FWPM_FILTER_CONDITION   conditions[0x10];     
            
        do {
        
            status = 
                IoCreateDevice(
                    driverObject,
                    0,
                    NULL,
                    FILE_DEVICE_UNKNOWN,
                    0,
                    FALSE,
                    &g_deviceObject );
                    
            if ( !NT_SUCCESS( status ) )
            {
                ASSERT( 0 );
                break;
            }         
            
            g_deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;    
        
            status =
                FwpsInjectionHandleCreate(
                    AF_INET,
                    FWPS_INJECTION_TYPE_TRANSPORT,
                    &g_injectHandle );
                    
            if ( !NT_SUCCESS( status ) )
            {
                ASSERT( 0 );
                break;
            }      
      
            calloutReg.calloutKey = CALLOUT_KEY;
            calloutReg.classifyFn = AleRecvAcceptClassify; 
            calloutReg.notifyFn = AleRecvNotify;
            
            status = 
                FwpsCalloutRegister(
                    g_deviceObject,
                    &calloutReg,
                    &g_calloutRegId );
                    
            if ( !NT_SUCCESS( status ) )
            {
                ASSERT( 0 );
                break;
            }      
            
            session.flags = FWPM_SESSION_FLAG_DYNAMIC;
    
            status = 
                FwpmEngineOpen(
                    NULL,
                    RPC_C_AUTHN_WINNT,
                    NULL,
                    &session,
                    &g_engineHandle
                    );
                    
            if ( !NT_SUCCESS( status ) )
            {
                ASSERT( 0 );
                break;
            }                     
                    
            status = FwpmTransactionBegin( g_engineHandle, 0);
            
            if (!NT_SUCCESS( status ))
            {
                ASSERT( 0 );
                break;
            }      
            
            do {
            
                subLayer.subLayerKey = SUBLAYER_KEY;
                subLayer.displayData.name = L"Testing sublayer";
                subLayer.displayData.description =  L"Testing sublayer";
                subLayer.flags = 0;
                subLayer.weight = 0;
                
                status = FwpmSubLayerAdd0( g_engineHandle, &subLayer, NULL );
                if (!NT_SUCCESS( status ))
                {
                    ASSERT( 0 );
                    break;
                }       
                
                callout.calloutKey = CALLOUT_KEY;
                callout.displayData.name = L"Testing callout";
                callout.displayData.description =  L"Testing callout";
                callout.applicableLayer = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
    
                status = FwpmCalloutAdd( g_engineHandle, &callout, NULL, NULL );
                if (!NT_SUCCESS( status ))
                {
                    ASSERT( 0 );
                    break;
                } 
           
                filter.filterKey = FILTER_KEY;
                filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
                filter.subLayerKey = SUBLAYER_KEY;
                filter.displayData.name = L"Testing filter";
                filter.displayData.description = L"Testing filter";
                filter.action.type = FWP_ACTION_CALLOUT_TERMINATING; 
                filter.action.calloutKey = CALLOUT_KEY;
                filter.weight.type = FWP_EMPTY;
                
                filter.numFilterConditions = 1;
                filter.filterCondition = conditions;
                conditions[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL;
                conditions[0].matchType = FWP_MATCH_EQUAL;
                conditions[0].conditionValue.type = FWP_UINT8;
                conditions[0].conditionValue.uint8 = IPPROTO_TCP;              
                
                status = FwpmFilterAdd( g_engineHandle, &filter, NULL, NULL );
                if (!NT_SUCCESS( status ))
                {
                    ASSERT( 0 );
                    break;
                } 
                
                status = FwpmTransactionCommit( g_engineHandle );      
                
                if ( !NT_SUCCESS( status ) )
                {
                    ASSERT( 0 );
                    break;
                }           
            
            } while( FALSE );
            
            if ( !NT_SUCCESS( status ) )
            {
                FwpmTransactionAbort( g_engineHandle );
                
                break;
            }
            
            status = STATUS_SUCCESS;                
                    
        } while( FALSE );
        
        return status;                
    }
    
    /////////////////////////////////////////////////////////////////////////////
    
    VOID CleanupWfpObjects()
    {
        FwpmEngineClose0( g_engineHandle) ;
       
        if (  g_calloutRegId )
            FwpsCalloutUnregisterById( g_calloutRegId );
    
        if ( g_injectHandle )
            FwpsInjectionHandleDestroy( g_injectHandle );  
    
        if ( g_deviceObject )
            IoDeleteDevice( g_deviceObject );       
    }
    
    /////////////////////////////////////////////////////////////////////////////
    
    VOID
    AleRecvAcceptClassify(
        __in const FWPS_INCOMING_VALUES0 *inFixedValues,
        __in const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
        __inout VOID *layerData,
        __in_opt const VOID *classifyContext,
        __in const FWPS_FILTER1 *filter,
        __in UINT64 flowContext,
        __out FWPS_CLASSIFY_OUT0 *classifyOut
        )
    {
        NTSTATUS                        status;
        UINT32                          flags = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS ].value.uint32;   
        PALERECV_ACCEPT_CONTEXT         acceptContext = NULL;    
        FWPS_PACKET_INJECTION_STATE     packetState;          
        PNET_BUFFER_LIST                nbl = (PNET_BUFFER_LIST)layerData;           
       
        do {
        
            if ( ( flags & FWP_CONDITION_FLAG_IS_REAUTHORIZE ) != 0 )
            {
                classifyOut->actionType = FWP_ACTION_PERMIT;
                break;
            }
            
            packetState = 
                FwpsQueryPacketInjectionState(
                    g_injectHandle,
                    nbl,
                    NULL );
                    
            if ( (packetState == FWPS_PACKET_INJECTED_BY_SELF) || (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF) )
            {
                classifyOut->actionType = FWP_ACTION_PERMIT;
                break;
            }        
        
            acceptContext =
                AleRecvAcceptContextCreate( 
                    inFixedValues,
                    inMetaValues,
                    nbl );    
                    
            if ( !acceptContext )
            {
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;   
                    
                break;    
            }          
            
            status = 
                FwpsPendOperation( 
                    inMetaValues->completionHandle,
                    &acceptContext->completionContext );
                    
            if ( !NT_SUCCESS(status) )
            {
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;   
                    
                break;    
            }         
            
            IoQueueWorkItem(
                acceptContext->workItem,
                AleRecvAcceptPendWork,
                DelayedWorkQueue,
                acceptContext );                  
    
            acceptContext = NULL; 
    
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;  
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;           
            
        } while( FALSE );       
        
        if ( acceptContext )
            AleRecvAcceptContextFree( acceptContext );
    
    }
    
    /////////////////////////////////////////////////////////////////////////////   
    
    VOID
    AleRecvAcceptPendWork(
        __in PDEVICE_OBJECT deviceObject,
        __in_opt PVOID context
        )
    {
        NTSTATUS                    status;
        PALERECV_ACCEPT_CONTEXT     acceptContext = (PALERECV_ACCEPT_CONTEXT)context;
        LARGE_INTEGER               timeout;
        PNET_BUFFER                 netBuffer = NULL;    
        PNET_BUFFER_LIST            clonedNbl = NULL;         
        
        do {
        
            timeout.QuadPart = -10*1000*1000LL;
            KeDelayExecutionThread( KernelMode, FALSE, &timeout );
            
            netBuffer = NET_BUFFER_LIST_FIRST_NB(acceptContext->netBufferList);
    
            NdisRetreatNetBufferDataStart(
                netBuffer,
                acceptContext->ipHeaderSize + acceptContext->transportHeaderSize,
                0,
                NULL );
                    
            status = 
                FwpsAllocateCloneNetBufferList(
                    acceptContext->netBufferList,
                    NULL,
                    NULL,
                    0,
                    &clonedNbl ); 
                    
            if ( !NT_SUCCESS( status ) )
                break; 
            
            NdisAdvanceNetBufferDataStart(
                netBuffer,    
                acceptContext->ipHeaderSize + acceptContext->transportHeaderSize,
                FALSE,
                NULL );            
    
            FwpsCompleteOperation(
                (PVOID)acceptContext->completionContext,
                clonedNbl );
            
            acceptContext->completionContext = NULL;
                
            status =
                FwpsInjectTransportReceiveAsync(
                    g_injectHandle,
                    NULL,
                    NULL,
                    0,
                    acceptContext->addressFamily,
                    acceptContext->compartmentId,
                    acceptContext->interfaceIndex,
                    acceptContext->subInterfaceIndex,
                    clonedNbl,
                    AleRecvAcceptInjectComplete,
                    acceptContext );
               
            if ( !NT_SUCCESS( status ) )
                break;      
                    
            acceptContext = NULL;                    
            clonedNbl = NULL;                                                       
        
        } while( FALSE );
        
        if ( clonedNbl )
            FwpsFreeCloneNetBufferList0(clonedNbl, 0);   
        
        if ( acceptContext )
            AleRecvAcceptContextFree( acceptContext );    
    }  
    
    
    /////////////////////////////////////////////////////////////////////////////
    
    VOID
    AleRecvAcceptInjectComplete(
        __in VOID* context,
        __inout NET_BUFFER_LIST* netBufferList,
        __in BOOLEAN dispatchLevel
        )
    {
        PALERECV_ACCEPT_CONTEXT   acceptContext = (PALERECV_ACCEPT_CONTEXT)context;
       
        if ( netBufferList )
            FwpsFreeCloneNetBufferList( netBufferList, 0);
        
        AleRecvAcceptContextFree( acceptContext );    
    }    
    
    ///////////////////////////////////////////////////////////////////////////// 
    
    PALERECV_ACCEPT_CONTEXT    
    AleRecvAcceptContextCreate(
        __in const FWPS_INCOMING_VALUES0 *inFixedValues,
        __in const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
        __in PNET_BUFFER_LIST netBufferList  
        )
    {
        PALERECV_ACCEPT_CONTEXT      acceptContext = NULL;
        
        acceptContext = 
            (PALERECV_ACCEPT_CONTEXT)ExAllocatePoolWithTag( 
                NonPagedPool, 
                sizeof(ALERECV_ACCEPT_CONTEXT),
                ACCEPT_CONTEXT_TAG );
                
        if ( !acceptContext )
            return NULL;
            
        RtlZeroMemory( acceptContext, sizeof(ALERECV_ACCEPT_CONTEXT) );
        
        acceptContext->workItem = IoAllocateWorkItem( g_deviceObject );
        if ( !acceptContext->workItem )
        {
            ExFreePoolWithTag( acceptContext, ACCEPT_CONTEXT_TAG );
            return NULL; 
        }
            
        acceptContext->addressFamily = AF_INET; 
        acceptContext->interfaceIndex = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_INTERFACE_INDEX ].value.uint32;
        acceptContext->subInterfaceIndex = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_SUB_INTERFACE_INDEX ].value.uint32; 
        
        acceptContext->compartmentId = inMetaValues->compartmentId;
        acceptContext->ipHeaderSize = inMetaValues->ipHeaderSize;
        acceptContext->transportHeaderSize = inMetaValues->transportHeaderSize;
        
        FwpsReferenceNetBufferList( netBufferList, TRUE );
        acceptContext->netBufferList = netBufferList;
       
        return acceptContext;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    VOID
    AleRecvAcceptContextFree(
        __in PALERECV_ACCEPT_CONTEXT  acceptContext
        )
    {
        FwpsDereferenceNetBufferList(
            acceptContext->netBufferList,
            KeGetCurrentIrql() == DISPATCH_LEVEL );
            
        if ( acceptContext->completionContext )
            FwpsCompleteOperation( acceptContext->completionContext, NULL );                    
            
        IoFreeWorkItem( acceptContext->workItem );         
            
        ExFreePoolWithTag( acceptContext, ACCEPT_CONTEXT_TAG );               
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    Beer for everone! )))))

    • Marked as answer by pykd team Friday, February 24, 2012 12:14 PM
    Friday, February 24, 2012 12:13 PM

All replies

  • It seems like I fail to pend incoming connection.
    I call FwpsPendOperation0 from classifyFn. It returns STATUS_SUCCESS and completion context. Then I set FWP_ACTION_BLOCK and flag FWPS_CLASSIFY_OUT_FLAG_ABSORB and queue a work item for delaying operation. In a work item I make a NBL copy, call FwpsCompleteOperation and then FwpsInjectTransportReceiveAsync. I nearly sure it worked before.

    But now I see SYN-ACK is sent back immediately after classifyFn returns. I suppose a connection wsa authorized inspite of status FWP_ACTION_BLOCK returned from classifyFn. What is wrong? May be filters or sublayer are not properly initialized?
    Monday, February 20, 2012 3:11 PM
  • This code blocks incoming connection:

            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;  
    • Edited by pykd team Monday, February 20, 2012 3:19 PM
    Monday, February 20, 2012 3:19 PM
  • I've wrote a sample. I wait the following:

    SYN  in
    delay 1s ( my callout does )
    SYN+ACK out ( after connection authorization )

    In fact:
    SYN in
    SYN_ACK out ( without any delay )  <-- connection waz authrization inspite of my callout

    What is wrong???  The most interesting thing, I'm nearly sure, this code worked before. I debugged it and saw reauthorization and packet reinjectsiion. Or may be I've gone mad )) Please, help me )))

    #include <ntddk.h>
    #include <wdmsec.h>
    #include <ndis.h>
    
    #include <initguid.h>
    
    #define INITGUID
    
    #include <fwpsk.h>
    #include <fwpmk.h>
    
    /////////////////////////////////////////////////////////////////////////////
    
    // {D4980309-28EB-44a3-8FA3-CAA74C824F65}
    DEFINE_GUID(SUBLAYER_KEY, 
    0xd4980309, 0x28eb, 0x44a3, 0x8f, 0xa3, 0xca, 0xa7, 0x4c, 0x82, 0x4f, 0x65);
    
    
    // {A15A1001-4551-4178-AD95-69F78225BDC4}
    DEFINE_GUID(CALLOUT_KEY, 
    0xa15a1001, 0x4551, 0x4178, 0xad, 0x95, 0x69, 0xf7, 0x82, 0x25, 0xbd, 0xc5);
    
    // {3278C545-CA51-4d94-BDEA-13A8FDFE4ABA}
    DEFINE_GUID(FILTER_KEY, 
    0x3278c545, 0xca51, 0x4d94, 0xbd, 0xea, 0x13, 0xa8, 0xfd, 0xfe, 0x4a, 0xba);
    
    /////////////////////////////////////////////////////////////////////////////
    
    typedef struct ALERECV_ACCEPT_CONTEXT_ {
    
        PNET_BUFFER_LIST            netBufferList; 
        
        ADDRESS_FAMILY              addressFamily;
    
        ULONG                       compartmentId;
        
        IF_INDEX                    interfaceIndex;
        
        IF_INDEX                    subInterfaceIndex;  
        
        UINT32                      ipHeaderSize;
        
        UINT32                      transportHeaderSize;      
        
        PVOID                       completionContext;      
        
        PIO_WORKITEM                workItem;
        
    } ALERECV_ACCEPT_CONTEXT, *PALERECV_ACCEPT_CONTEXT;
    
    #define  ACCEPT_CONTEXT_TAG     'ctca'
    
    /////////////////////////////////////////////////////////////////////////////
    
    HANDLE              g_injectHandle = 0;
    
    PDEVICE_OBJECT      g_deviceObject = NULL;
    
    UINT32              g_calloutRegId = 0;
    
    HANDLE              g_engineHandle = NULL;
    
    /////////////////////////////////////////////////////////////////////////////
    
    DRIVER_INITIALIZE       DriverEntry;
    DRIVER_UNLOAD           DriverUnload;
    
    NTSTATUS InitFwpObjects();
    VOID CleanupWfpObjects();
    
    NTSTATUS 
    AleRecvNotify(
        __in FWPS_CALLOUT_NOTIFY_TYPE notifyType,
        __in const GUID *filterKey,
        __in const FWPS_FILTER1 *filter
        ) 
    {
        return STATUS_SUCCESS;
    }   
    
    VOID
    AleRecvAcceptClassify(
        __in const FWPS_INCOMING_VALUES0 *inFixedValues,
        __in const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
        __inout VOID *layerData,
        __in_opt const VOID *classifyContext,
        __in const FWPS_FILTER1 *filter,
        __in UINT64 flowContext,
        __out FWPS_CLASSIFY_OUT0 *classifyOut
        ); 
       
        
    IO_WORKITEM_ROUTINE          AleRecvAcceptPendWork;     
    
    VOID
    AleRecvAcceptInjectComplete(
        __in VOID* context,
        __inout NET_BUFFER_LIST* netBufferList,
        __in BOOLEAN dispatchLevel
        ); 
    
    PALERECV_ACCEPT_CONTEXT    
    AleRecvAcceptContextCreate(
        __in const FWPS_INCOMING_VALUES0 *inFixedValues,
        __in const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
        __in PNET_BUFFER_LIST netBufferList
        );
    
    VOID
    AleRecvAcceptContextFree(
        __in PALERECV_ACCEPT_CONTEXT  acceptContext
        );    
        
    
    /////////////////////////////////////////////////////////////////////////////
    
    NTSTATUS
    DriverEntry(
        __in PDRIVER_OBJECT   driverObject,
        __in PUNICODE_STRING  registryPath
        )
    {
        NTSTATUS    status = STATUS_UNSUCCESSFUL;
        UNREFERENCED_PARAMETER( registryPath );
        
        do {
        
            driverObject->DriverUnload = DriverUnload;
            
            status = InitFwpObjects( driverObject );
            
            if ( !NT_SUCCESS( status ) )
                break;
      
            status = STATUS_SUCCESS;    
        
        } while( FALSE );
        
        if ( !NT_SUCCESS( status ) )
            DriverUnload( driverObject );
        
        return status;
    }
    
    /////////////////////////////////////////////////////////////////////////////
    
    VOID
    DriverUnload(
        __in PDRIVER_OBJECT  driverObject )
    {
        CleanupWfpObjects();    
    } 
    
    /////////////////////////////////////////////////////////////////////////////
    
    NTSTATUS InitFwpObjects(
        __in PDRIVER_OBJECT  driverObject
        )
    {
        NTSTATUS                status = STATUS_UNSUCCESSFUL;
        FWPS_CALLOUT            calloutReg = { 0 }; 
        FWPM_SESSION            session = { 0 };    
        FWPM_SUBLAYER           subLayer = { 0 };   
        FWPM_CALLOUT            callout = { 0 };     
        FWPM_FILTER             filter = { 0 };
        FWPM_FILTER_CONDITION   conditions[0x10];     
            
        do {
        
            status = 
                IoCreateDevice(
                    driverObject,
                    0,
                    NULL,
                    FILE_DEVICE_UNKNOWN,
                    0,
                    FALSE,
                    &g_deviceObject );
                    
            if ( !NT_SUCCESS( status ) )
            {
                ASSERT( 0 );
                break;
            }         
            
            g_deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;    
        
            status =
                FwpsInjectionHandleCreate(
                    AF_INET,
                    FWPS_INJECTION_TYPE_TRANSPORT,
                    &g_injectHandle );
                    
            if ( !NT_SUCCESS( status ) )
            {
                ASSERT( 0 );
                break;
            }      
      
            calloutReg.calloutKey = CALLOUT_KEY;
            calloutReg.classifyFn = AleRecvAcceptClassify; 
            calloutReg.notifyFn = AleRecvNotify;
            
            status = 
                FwpsCalloutRegister(
                    g_deviceObject,
                    &calloutReg,
                    &g_calloutRegId );
                    
            if ( !NT_SUCCESS( status ) )
            {
                ASSERT( 0 );
                break;
            }      
            
            session.flags = FWPM_SESSION_FLAG_DYNAMIC;
    
            status = 
                FwpmEngineOpen(
                    NULL,
                    RPC_C_AUTHN_WINNT,
                    NULL,
                    &session,
                    &g_engineHandle
                    );
                    
            if ( !NT_SUCCESS( status ) )
            {
                ASSERT( 0 );
                break;
            }                     
                    
            status = FwpmTransactionBegin( g_engineHandle, 0);
            
            if (!NT_SUCCESS( status ))
            {
                ASSERT( 0 );
                break;
            }      
            
            do {
            
                subLayer.subLayerKey = SUBLAYER_KEY;
                subLayer.displayData.name = L"Testing sublayer";
                subLayer.displayData.description =  L"Testing sublayer";
                subLayer.flags = 0;
                subLayer.weight = 0;
                
                status = FwpmSubLayerAdd0( g_engineHandle, &subLayer, NULL );
                if (!NT_SUCCESS( status ))
                {
                    ASSERT( 0 );
                    break;
                }       
                
                callout.calloutKey = CALLOUT_KEY;
                callout.displayData.name = L"Testing callout";
                callout.displayData.description =  L"Testing callout";
                callout.applicableLayer = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
    
                status = FwpmCalloutAdd( g_engineHandle, &callout, NULL, NULL );
                if (!NT_SUCCESS( status ))
                {
                    ASSERT( 0 );
                    break;
                } 
           
                filter.filterKey = FILTER_KEY;
                filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
                filter.subLayerKey = SUBLAYER_KEY;
                filter.displayData.name = L"Testing filter";
                filter.displayData.description = L"Testing filter";
                filter.action.type = FWP_ACTION_CALLOUT_TERMINATING; 
                filter.action.calloutKey = CALLOUT_KEY;
                filter.weight.type = FWP_EMPTY;
                
                filter.numFilterConditions = 1;
                filter.filterCondition = conditions;
                conditions[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL;
                conditions[0].matchType = FWP_MATCH_EQUAL;
                conditions[0].conditionValue.type = FWP_UINT8;
                conditions[0].conditionValue.uint8 = IPPROTO_TCP;              
                
                status = FwpmFilterAdd( g_engineHandle, &filter, NULL, NULL );
                if (!NT_SUCCESS( status ))
                {
                    ASSERT( 0 );
                    break;
                } 
                
                status = FwpmTransactionCommit( g_engineHandle );      
                
                if ( !NT_SUCCESS( status ) )
                {
                    ASSERT( 0 );
                    break;
                }           
            
            } while( FALSE );
            
            if ( !NT_SUCCESS( status ) )
            {
                FwpmTransactionAbort( g_engineHandle );
                
                break;
            }
            
            status = STATUS_SUCCESS;                
                    
        } while( FALSE );
        
        return status;                
    }
    
    /////////////////////////////////////////////////////////////////////////////
    
    VOID CleanupWfpObjects()
    {
        FwpmEngineClose0( g_engineHandle) ;
       
        if (  g_calloutRegId )
            FwpsCalloutUnregisterById( g_calloutRegId );
    
        if ( g_injectHandle )
            FwpsInjectionHandleDestroy( g_injectHandle );  
    
        if ( g_deviceObject )
            IoDeleteDevice( g_deviceObject );       
    }
    
    /////////////////////////////////////////////////////////////////////////////
    
    VOID
    AleRecvAcceptClassify(
        __in const FWPS_INCOMING_VALUES0 *inFixedValues,
        __in const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
        __inout VOID *layerData,
        __in_opt const VOID *classifyContext,
        __in const FWPS_FILTER1 *filter,
        __in UINT64 flowContext,
        __out FWPS_CLASSIFY_OUT0 *classifyOut
        )
    {
        NTSTATUS                        status;
        UINT32                          flags = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS ].value.uint32;   
        PALERECV_ACCEPT_CONTEXT         acceptContext = NULL;    
        FWPS_PACKET_INJECTION_STATE     packetState;          
        PNET_BUFFER_LIST                nbl = (PNET_BUFFER_LIST)layerData;           
       
        do {
        
            if ( ( flags & FWP_CONDITION_FLAG_IS_REAUTHORIZE ) != 0 )
            {
                classifyOut->actionType = FWP_ACTION_PERMIT;
                break;
            }
            
            packetState = 
                FwpsQueryPacketInjectionState(
                    g_injectHandle,
                    nbl,
                    NULL );
                    
            if ( (packetState == FWPS_PACKET_INJECTED_BY_SELF) || (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF) )
            {
                classifyOut->actionType = FWP_ACTION_PERMIT;
                break;
            }        
        
            acceptContext =
                AleRecvAcceptContextCreate( 
                    inFixedValues,
                    inMetaValues,
                    nbl );    
                    
            if ( !acceptContext )
            {
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;   
                    
                break;    
            }          
            
            status = 
                FwpsPendOperation( 
                    inMetaValues->completionHandle,
                    &acceptContext->completionContext );
                    
            if ( !NT_SUCCESS(status) )
            {
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;   
                    
                break;    
            }         
            
            IoQueueWorkItem(
                acceptContext->workItem,
                AleRecvAcceptPendWork,
                DelayedWorkQueue,
                acceptContext );                  
    
            acceptContext = NULL; 
    
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;  
            
        } while( FALSE );       
        
        if ( acceptContext )
            AleRecvAcceptContextFree( acceptContext );
    
    }
    
    /////////////////////////////////////////////////////////////////////////////   
    
    VOID
    AleRecvAcceptPendWork(
        __in PDEVICE_OBJECT deviceObject,
        __in_opt PVOID context
        )
    {
        NTSTATUS                    status;
        PALERECV_ACCEPT_CONTEXT     acceptContext = (PALERECV_ACCEPT_CONTEXT)context;
        LARGE_INTEGER               timeout;
        PNET_BUFFER                 netBuffer = NULL;    
        PNET_BUFFER_LIST            clonedNbl = NULL;         
        
        do {
        
            timeout.QuadPart = -10*1000*1000LL;
            KeDelayExecutionThread( KernelMode, FALSE, &timeout );
            
            netBuffer = NET_BUFFER_LIST_FIRST_NB(acceptContext->netBufferList);
    
            NdisRetreatNetBufferDataStart(
                netBuffer,
                acceptContext->ipHeaderSize + acceptContext->transportHeaderSize,
                0,
                NULL );
                    
            status = 
                FwpsAllocateCloneNetBufferList(
                    acceptContext->netBufferList,
                    NULL,
                    NULL,
                    0,
                    &clonedNbl ); 
                    
            if ( !NT_SUCCESS( status ) )
                break; 
            
            NdisAdvanceNetBufferDataStart(
                netBuffer,    
                acceptContext->ipHeaderSize + acceptContext->transportHeaderSize,
                FALSE,
                NULL );            
    
            FwpsCompleteOperation(
                (PVOID)acceptContext->completionContext,
                clonedNbl );
            
            acceptContext->completionContext = NULL;
                
            status =
                FwpsInjectTransportReceiveAsync(
                    g_injectHandle,
                    NULL,
                    NULL,
                    0,
                    acceptContext->addressFamily,
                    acceptContext->compartmentId,
                    acceptContext->interfaceIndex,
                    acceptContext->subInterfaceIndex,
                    clonedNbl,
                    AleRecvAcceptInjectComplete,
                    acceptContext );
               
            if ( !NT_SUCCESS( status ) )
                break;      
                    
            acceptContext = NULL;                    
            clonedNbl = NULL;                                                       
        
        } while( FALSE );
        
        if ( clonedNbl )
            FwpsFreeCloneNetBufferList0(clonedNbl, 0);   
        
        if ( acceptContext )
            AleRecvAcceptContextFree( acceptContext );    
    }  
    
    
    /////////////////////////////////////////////////////////////////////////////
    
    VOID
    AleRecvAcceptInjectComplete(
        __in VOID* context,
        __inout NET_BUFFER_LIST* netBufferList,
        __in BOOLEAN dispatchLevel
        )
    {
        PALERECV_ACCEPT_CONTEXT   acceptContext = (PALERECV_ACCEPT_CONTEXT)context;
       
        if ( netBufferList )
            FwpsFreeCloneNetBufferList( netBufferList, 0);
        
        AleRecvAcceptContextFree( acceptContext );    
    }    
    
    ///////////////////////////////////////////////////////////////////////////// 
    
    PALERECV_ACCEPT_CONTEXT    
    AleRecvAcceptContextCreate(
        __in const FWPS_INCOMING_VALUES0 *inFixedValues,
        __in const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
        __in PNET_BUFFER_LIST netBufferList  
        )
    {
        PALERECV_ACCEPT_CONTEXT      acceptContext = NULL;
        
        acceptContext = 
            (PALERECV_ACCEPT_CONTEXT)ExAllocatePoolWithTag( 
                NonPagedPool, 
                sizeof(ALERECV_ACCEPT_CONTEXT),
                ACCEPT_CONTEXT_TAG );
                
        if ( !acceptContext )
            return NULL;
            
        RtlZeroMemory( acceptContext, sizeof(ALERECV_ACCEPT_CONTEXT) );
        
        acceptContext->workItem = IoAllocateWorkItem( g_deviceObject );
        if ( !acceptContext->workItem )
        {
            ExFreePoolWithTag( acceptContext, ACCEPT_CONTEXT_TAG );
            return NULL; 
        }
            
        acceptContext->addressFamily = AF_INET; 
        acceptContext->interfaceIndex = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_CONNECT_V4_INTERFACE_INDEX ].value.uint32;
        acceptContext->subInterfaceIndex = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_CONNECT_V4_SUB_INTERFACE_INDEX ].value.uint32; 
        
        acceptContext->compartmentId = inMetaValues->compartmentId;
        acceptContext->ipHeaderSize = inMetaValues->ipHeaderSize;
        acceptContext->transportHeaderSize = inMetaValues->transportHeaderSize;
        
        FwpsReferenceNetBufferList( netBufferList, TRUE );
        acceptContext->netBufferList = netBufferList;
       
        return acceptContext;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    VOID
    AleRecvAcceptContextFree(
        __in PALERECV_ACCEPT_CONTEXT  acceptContext
        )
    {
        FwpsDereferenceNetBufferList(
            acceptContext->netBufferList,
            KeGetCurrentIrql() == DISPATCH_LEVEL );
            
        if ( acceptContext->completionContext )
            FwpsCompleteOperation( acceptContext->completionContext, NULL );                    
            
        IoFreeWorkItem( acceptContext->workItem );         
            
        ExFreePoolWithTag( acceptContext, ACCEPT_CONTEXT_TAG );               
    }
    
    ///////////////////////////////////////////////////////////////////////////////


    Tuesday, February 21, 2012 10:25 AM
  • I tried to set different values to sublayer weight:

    0x0000
    0x8000
    0xF000
    0xFFFF

    The result is the same

    Tuesday, February 21, 2012 2:21 PM
  • No. Pending @ RECV_ACCEPT prevents the handshake from happening, and if its pended long enough, the connect call made by the client will fail.

    Essentially, call FwpsPendOperation (passing in the completionHandle from the metadata, a retrieving the completionContext), queue a workitem (must have access to the completionContext,the original NBL, and some of the metadata and classifyValues),  and set the classifyOut->actionType to FWP_ACTION_BLOCK and the classifyOutFlags with FWPS_CLASSIFY_OUT_FLAG_ABSORB.

    In the workItem, do whatever you need to do, clone the Original NBL (remember to retreat the size of the IPHeader and Transport Header for AUTH_RECV_ACCEPT before cloning, and return it to the original offset after), call FwpsCompleteOperation (passsing the completionContext and the original NBL), finally inject the packet (for RECV_ACCEPT use FwpsInjectTransportReceiveAsync).

    Hope this helps,


    Dusty Harper [MSFT]
    Microsoft Corporation
    ------------------------------------------------------------
    This posting is provided "AS IS", with NO warranties and confers NO rights
    ------------------------------------------------------------


    Tuesday, February 21, 2012 5:39 PM
    Moderator
  • Thank you very much, I feel better ))

    But what's wrong with my code? It does exactly what you say, but it can not pend inbound connection. I suppose if classify code is right, then may be initialization code is wrong? Or may be there is an another filter or callout which overriding my verdict? I've tested this code with two different machine with new installed Win7 SP1

    I hope to your help!!! 

    I tried to get ETW logs but I cannot find wfp.tfm file for reading it. Can it be downloaded form anywhere? I think logs can get me right way

    Thank you!

    Tuesday, February 21, 2012 7:48 PM
  • I found a bug.

    1)

        acceptContext->interfaceIndex = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_CONNECT_V4_INTERFACE_INDEX ].value.uint32;
        acceptContext->subInterfaceIndex = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_CONNECT_V4_SUB_INTERFACE_INDEX ].value.uint32; T

    2)
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; 

    This sample delays inbound connection for a second

    #include <ntddk.h>
    #include <wdmsec.h>
    #include <ndis.h>
    
    #include <initguid.h>
    
    #define INITGUID
    
    #include <fwpsk.h>
    #include <fwpmk.h>
    
    /////////////////////////////////////////////////////////////////////////////
    
    // {D4980309-28EB-44a3-8FA3-CAA74C824F65}
    DEFINE_GUID(SUBLAYER_KEY, 
    0xd4980309, 0x28eb, 0x44a3, 0x8f, 0xa3, 0xca, 0xa7, 0x4c, 0x82, 0x4f, 0x65);
    
    
    // {A15A1001-4551-4178-AD95-69F78225BDC4}
    DEFINE_GUID(CALLOUT_KEY, 
    0xa15a1001, 0x4551, 0x4178, 0xad, 0x95, 0x69, 0xf7, 0x82, 0x25, 0xbd, 0xc5);
    
    // {3278C545-CA51-4d94-BDEA-13A8FDFE4ABA}
    DEFINE_GUID(FILTER_KEY, 
    0x3278c545, 0xca51, 0x4d94, 0xbd, 0xea, 0x13, 0xa8, 0xfd, 0xfe, 0x4a, 0xba);
    
    /////////////////////////////////////////////////////////////////////////////
    
    typedef struct ALERECV_ACCEPT_CONTEXT_ {
    
        PNET_BUFFER_LIST            netBufferList; 
        
        ADDRESS_FAMILY              addressFamily;
    
        ULONG                       compartmentId;
        
        IF_INDEX                    interfaceIndex;
        
        IF_INDEX                    subInterfaceIndex;  
        
        UINT32                      ipHeaderSize;
        
        UINT32                      transportHeaderSize;      
        
        PVOID                       completionContext;      
        
        PIO_WORKITEM                workItem;
        
    } ALERECV_ACCEPT_CONTEXT, *PALERECV_ACCEPT_CONTEXT;
    
    #define  ACCEPT_CONTEXT_TAG     'ctca'
    
    /////////////////////////////////////////////////////////////////////////////
    
    HANDLE              g_injectHandle = 0;
    
    PDEVICE_OBJECT      g_deviceObject = NULL;
    
    UINT32              g_calloutRegId = 0;
    
    HANDLE              g_engineHandle = NULL;
    
    /////////////////////////////////////////////////////////////////////////////
    
    DRIVER_INITIALIZE       DriverEntry;
    DRIVER_UNLOAD           DriverUnload;
    
    NTSTATUS InitFwpObjects();
    VOID CleanupWfpObjects();
    
    NTSTATUS 
    AleRecvNotify(
        __in FWPS_CALLOUT_NOTIFY_TYPE notifyType,
        __in const GUID *filterKey,
        __in const FWPS_FILTER1 *filter
        ) 
    {
        return STATUS_SUCCESS;
    }   
    
    VOID
    AleRecvAcceptClassify(
        __in const FWPS_INCOMING_VALUES0 *inFixedValues,
        __in const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
        __inout VOID *layerData,
        __in_opt const VOID *classifyContext,
        __in const FWPS_FILTER1 *filter,
        __in UINT64 flowContext,
        __out FWPS_CLASSIFY_OUT0 *classifyOut
        ); 
       
        
    IO_WORKITEM_ROUTINE          AleRecvAcceptPendWork;     
    
    VOID
    AleRecvAcceptInjectComplete(
        __in VOID* context,
        __inout NET_BUFFER_LIST* netBufferList,
        __in BOOLEAN dispatchLevel
        ); 
    
    PALERECV_ACCEPT_CONTEXT    
    AleRecvAcceptContextCreate(
        __in const FWPS_INCOMING_VALUES0 *inFixedValues,
        __in const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
        __in PNET_BUFFER_LIST netBufferList
        );
    
    VOID
    AleRecvAcceptContextFree(
        __in PALERECV_ACCEPT_CONTEXT  acceptContext
        );    
        
    
    /////////////////////////////////////////////////////////////////////////////
    
    NTSTATUS
    DriverEntry(
        __in PDRIVER_OBJECT   driverObject,
        __in PUNICODE_STRING  registryPath
        )
    {
        NTSTATUS    status = STATUS_UNSUCCESSFUL;
        UNREFERENCED_PARAMETER( registryPath );
        
        do {
        
            driverObject->DriverUnload = DriverUnload;
            
            status = InitFwpObjects( driverObject );
            
            if ( !NT_SUCCESS( status ) )
                break;
      
            status = STATUS_SUCCESS;    
        
        } while( FALSE );
        
        if ( !NT_SUCCESS( status ) )
            DriverUnload( driverObject );
        
        return status;
    }
    
    /////////////////////////////////////////////////////////////////////////////
    
    VOID
    DriverUnload(
        __in PDRIVER_OBJECT  driverObject )
    {
        CleanupWfpObjects();    
    } 
    
    /////////////////////////////////////////////////////////////////////////////
    
    NTSTATUS InitFwpObjects(
        __in PDRIVER_OBJECT  driverObject
        )
    {
        NTSTATUS                status = STATUS_UNSUCCESSFUL;
        FWPS_CALLOUT            calloutReg = { 0 }; 
        FWPM_SESSION            session = { 0 };    
        FWPM_SUBLAYER           subLayer = { 0 };   
        FWPM_CALLOUT            callout = { 0 };     
        FWPM_FILTER             filter = { 0 };
        FWPM_FILTER_CONDITION   conditions[0x10];     
            
        do {
        
            status = 
                IoCreateDevice(
                    driverObject,
                    0,
                    NULL,
                    FILE_DEVICE_UNKNOWN,
                    0,
                    FALSE,
                    &g_deviceObject );
                    
            if ( !NT_SUCCESS( status ) )
            {
                ASSERT( 0 );
                break;
            }         
            
            g_deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;    
        
            status =
                FwpsInjectionHandleCreate(
                    AF_INET,
                    FWPS_INJECTION_TYPE_TRANSPORT,
                    &g_injectHandle );
                    
            if ( !NT_SUCCESS( status ) )
            {
                ASSERT( 0 );
                break;
            }      
      
            calloutReg.calloutKey = CALLOUT_KEY;
            calloutReg.classifyFn = AleRecvAcceptClassify; 
            calloutReg.notifyFn = AleRecvNotify;
            
            status = 
                FwpsCalloutRegister(
                    g_deviceObject,
                    &calloutReg,
                    &g_calloutRegId );
                    
            if ( !NT_SUCCESS( status ) )
            {
                ASSERT( 0 );
                break;
            }      
            
            session.flags = FWPM_SESSION_FLAG_DYNAMIC;
    
            status = 
                FwpmEngineOpen(
                    NULL,
                    RPC_C_AUTHN_WINNT,
                    NULL,
                    &session,
                    &g_engineHandle
                    );
                    
            if ( !NT_SUCCESS( status ) )
            {
                ASSERT( 0 );
                break;
            }                     
                    
            status = FwpmTransactionBegin( g_engineHandle, 0);
            
            if (!NT_SUCCESS( status ))
            {
                ASSERT( 0 );
                break;
            }      
            
            do {
            
                subLayer.subLayerKey = SUBLAYER_KEY;
                subLayer.displayData.name = L"Testing sublayer";
                subLayer.displayData.description =  L"Testing sublayer";
                subLayer.flags = 0;
                subLayer.weight = 0;
                
                status = FwpmSubLayerAdd0( g_engineHandle, &subLayer, NULL );
                if (!NT_SUCCESS( status ))
                {
                    ASSERT( 0 );
                    break;
                }       
                
                callout.calloutKey = CALLOUT_KEY;
                callout.displayData.name = L"Testing callout";
                callout.displayData.description =  L"Testing callout";
                callout.applicableLayer = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
    
                status = FwpmCalloutAdd( g_engineHandle, &callout, NULL, NULL );
                if (!NT_SUCCESS( status ))
                {
                    ASSERT( 0 );
                    break;
                } 
           
                filter.filterKey = FILTER_KEY;
                filter.layerKey = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
                filter.subLayerKey = SUBLAYER_KEY;
                filter.displayData.name = L"Testing filter";
                filter.displayData.description = L"Testing filter";
                filter.action.type = FWP_ACTION_CALLOUT_TERMINATING; 
                filter.action.calloutKey = CALLOUT_KEY;
                filter.weight.type = FWP_EMPTY;
                
                filter.numFilterConditions = 1;
                filter.filterCondition = conditions;
                conditions[0].fieldKey = FWPM_CONDITION_IP_PROTOCOL;
                conditions[0].matchType = FWP_MATCH_EQUAL;
                conditions[0].conditionValue.type = FWP_UINT8;
                conditions[0].conditionValue.uint8 = IPPROTO_TCP;              
                
                status = FwpmFilterAdd( g_engineHandle, &filter, NULL, NULL );
                if (!NT_SUCCESS( status ))
                {
                    ASSERT( 0 );
                    break;
                } 
                
                status = FwpmTransactionCommit( g_engineHandle );      
                
                if ( !NT_SUCCESS( status ) )
                {
                    ASSERT( 0 );
                    break;
                }           
            
            } while( FALSE );
            
            if ( !NT_SUCCESS( status ) )
            {
                FwpmTransactionAbort( g_engineHandle );
                
                break;
            }
            
            status = STATUS_SUCCESS;                
                    
        } while( FALSE );
        
        return status;                
    }
    
    /////////////////////////////////////////////////////////////////////////////
    
    VOID CleanupWfpObjects()
    {
        FwpmEngineClose0( g_engineHandle) ;
       
        if (  g_calloutRegId )
            FwpsCalloutUnregisterById( g_calloutRegId );
    
        if ( g_injectHandle )
            FwpsInjectionHandleDestroy( g_injectHandle );  
    
        if ( g_deviceObject )
            IoDeleteDevice( g_deviceObject );       
    }
    
    /////////////////////////////////////////////////////////////////////////////
    
    VOID
    AleRecvAcceptClassify(
        __in const FWPS_INCOMING_VALUES0 *inFixedValues,
        __in const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
        __inout VOID *layerData,
        __in_opt const VOID *classifyContext,
        __in const FWPS_FILTER1 *filter,
        __in UINT64 flowContext,
        __out FWPS_CLASSIFY_OUT0 *classifyOut
        )
    {
        NTSTATUS                        status;
        UINT32                          flags = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS ].value.uint32;   
        PALERECV_ACCEPT_CONTEXT         acceptContext = NULL;    
        FWPS_PACKET_INJECTION_STATE     packetState;          
        PNET_BUFFER_LIST                nbl = (PNET_BUFFER_LIST)layerData;           
       
        do {
        
            if ( ( flags & FWP_CONDITION_FLAG_IS_REAUTHORIZE ) != 0 )
            {
                classifyOut->actionType = FWP_ACTION_PERMIT;
                break;
            }
            
            packetState = 
                FwpsQueryPacketInjectionState(
                    g_injectHandle,
                    nbl,
                    NULL );
                    
            if ( (packetState == FWPS_PACKET_INJECTED_BY_SELF) || (packetState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF) )
            {
                classifyOut->actionType = FWP_ACTION_PERMIT;
                break;
            }        
        
            acceptContext =
                AleRecvAcceptContextCreate( 
                    inFixedValues,
                    inMetaValues,
                    nbl );    
                    
            if ( !acceptContext )
            {
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;   
                    
                break;    
            }          
            
            status = 
                FwpsPendOperation( 
                    inMetaValues->completionHandle,
                    &acceptContext->completionContext );
                    
            if ( !NT_SUCCESS(status) )
            {
                classifyOut->actionType = FWP_ACTION_BLOCK;
                classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;   
                    
                break;    
            }         
            
            IoQueueWorkItem(
                acceptContext->workItem,
                AleRecvAcceptPendWork,
                DelayedWorkQueue,
                acceptContext );                  
    
            acceptContext = NULL; 
    
            classifyOut->actionType = FWP_ACTION_BLOCK;
            classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;  
            classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;           
            
        } while( FALSE );       
        
        if ( acceptContext )
            AleRecvAcceptContextFree( acceptContext );
    
    }
    
    /////////////////////////////////////////////////////////////////////////////   
    
    VOID
    AleRecvAcceptPendWork(
        __in PDEVICE_OBJECT deviceObject,
        __in_opt PVOID context
        )
    {
        NTSTATUS                    status;
        PALERECV_ACCEPT_CONTEXT     acceptContext = (PALERECV_ACCEPT_CONTEXT)context;
        LARGE_INTEGER               timeout;
        PNET_BUFFER                 netBuffer = NULL;    
        PNET_BUFFER_LIST            clonedNbl = NULL;         
        
        do {
        
            timeout.QuadPart = -10*1000*1000LL;
            KeDelayExecutionThread( KernelMode, FALSE, &timeout );
            
            netBuffer = NET_BUFFER_LIST_FIRST_NB(acceptContext->netBufferList);
    
            NdisRetreatNetBufferDataStart(
                netBuffer,
                acceptContext->ipHeaderSize + acceptContext->transportHeaderSize,
                0,
                NULL );
                    
            status = 
                FwpsAllocateCloneNetBufferList(
                    acceptContext->netBufferList,
                    NULL,
                    NULL,
                    0,
                    &clonedNbl ); 
                    
            if ( !NT_SUCCESS( status ) )
                break; 
            
            NdisAdvanceNetBufferDataStart(
                netBuffer,    
                acceptContext->ipHeaderSize + acceptContext->transportHeaderSize,
                FALSE,
                NULL );            
    
            FwpsCompleteOperation(
                (PVOID)acceptContext->completionContext,
                clonedNbl );
            
            acceptContext->completionContext = NULL;
                
            status =
                FwpsInjectTransportReceiveAsync(
                    g_injectHandle,
                    NULL,
                    NULL,
                    0,
                    acceptContext->addressFamily,
                    acceptContext->compartmentId,
                    acceptContext->interfaceIndex,
                    acceptContext->subInterfaceIndex,
                    clonedNbl,
                    AleRecvAcceptInjectComplete,
                    acceptContext );
               
            if ( !NT_SUCCESS( status ) )
                break;      
                    
            acceptContext = NULL;                    
            clonedNbl = NULL;                                                       
        
        } while( FALSE );
        
        if ( clonedNbl )
            FwpsFreeCloneNetBufferList0(clonedNbl, 0);   
        
        if ( acceptContext )
            AleRecvAcceptContextFree( acceptContext );    
    }  
    
    
    /////////////////////////////////////////////////////////////////////////////
    
    VOID
    AleRecvAcceptInjectComplete(
        __in VOID* context,
        __inout NET_BUFFER_LIST* netBufferList,
        __in BOOLEAN dispatchLevel
        )
    {
        PALERECV_ACCEPT_CONTEXT   acceptContext = (PALERECV_ACCEPT_CONTEXT)context;
       
        if ( netBufferList )
            FwpsFreeCloneNetBufferList( netBufferList, 0);
        
        AleRecvAcceptContextFree( acceptContext );    
    }    
    
    ///////////////////////////////////////////////////////////////////////////// 
    
    PALERECV_ACCEPT_CONTEXT    
    AleRecvAcceptContextCreate(
        __in const FWPS_INCOMING_VALUES0 *inFixedValues,
        __in const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues,
        __in PNET_BUFFER_LIST netBufferList  
        )
    {
        PALERECV_ACCEPT_CONTEXT      acceptContext = NULL;
        
        acceptContext = 
            (PALERECV_ACCEPT_CONTEXT)ExAllocatePoolWithTag( 
                NonPagedPool, 
                sizeof(ALERECV_ACCEPT_CONTEXT),
                ACCEPT_CONTEXT_TAG );
                
        if ( !acceptContext )
            return NULL;
            
        RtlZeroMemory( acceptContext, sizeof(ALERECV_ACCEPT_CONTEXT) );
        
        acceptContext->workItem = IoAllocateWorkItem( g_deviceObject );
        if ( !acceptContext->workItem )
        {
            ExFreePoolWithTag( acceptContext, ACCEPT_CONTEXT_TAG );
            return NULL; 
        }
            
        acceptContext->addressFamily = AF_INET; 
        acceptContext->interfaceIndex = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_INTERFACE_INDEX ].value.uint32;
        acceptContext->subInterfaceIndex = inFixedValues->incomingValue[ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_SUB_INTERFACE_INDEX ].value.uint32; 
        
        acceptContext->compartmentId = inMetaValues->compartmentId;
        acceptContext->ipHeaderSize = inMetaValues->ipHeaderSize;
        acceptContext->transportHeaderSize = inMetaValues->transportHeaderSize;
        
        FwpsReferenceNetBufferList( netBufferList, TRUE );
        acceptContext->netBufferList = netBufferList;
       
        return acceptContext;
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    
    VOID
    AleRecvAcceptContextFree(
        __in PALERECV_ACCEPT_CONTEXT  acceptContext
        )
    {
        FwpsDereferenceNetBufferList(
            acceptContext->netBufferList,
            KeGetCurrentIrql() == DISPATCH_LEVEL );
            
        if ( acceptContext->completionContext )
            FwpsCompleteOperation( acceptContext->completionContext, NULL );                    
            
        IoFreeWorkItem( acceptContext->workItem );         
            
        ExFreePoolWithTag( acceptContext, ACCEPT_CONTEXT_TAG );               
    }
    
    ///////////////////////////////////////////////////////////////////////////////
    Beer for everone! )))))

    • Marked as answer by pykd team Friday, February 24, 2012 12:14 PM
    Friday, February 24, 2012 12:13 PM
  • this really drives crazy.

    two things you mentioned:

    1.to pend a connect/accept operate,you said just need to code below 

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

     but the true is removing "FWPS_RIGHT_ACTION_WRITE" flag is needed. that's why pykd team finally pend the connection 

    2."call FwpsCompleteOperation (passsing the completionContext and the original NBL), finally inject the packet (for RECV_ACCEPT use FwpsInjectTransportReceiveAsync)."

    but i found out  the sample from wdk does not do that. It pass the Clone NBL to FwpsCompleteOperation .

    Friday, December 27, 2013 9:45 AM