locked
FwpsCompleteClassify not working? RRS feed

  • Question

  • Hello,

    I'm trying to pend classify requests at FWPS_LAYER_ALE_CONNECT_REDIRECT_V4 (in Windows 7).

    Pending (FwpsPendClassify) seems to work fine, but later on, completion (FwpsCompleteClassify) seems to fail.

    The FwpsCompleteClassify call returns successfully, no exceptions, no crashes, but the classify request doesn't actually complete. It's like FwpsCompleteClassify has no effect at all.

    Questions:

    1. Is there any way to verify whether FwpsCompleteClassify succeeds (since it doesn't return any error code)?

    2. The "pClassifyOut" parameter of FwpsCompleteClassify must point to the exact structure received in classifyFn, or to a clone of it?  In case of out-of-band classification, what is the lifetime of data received in classifyFn?

    Thanks!

    Thursday, July 5, 2012 6:50 AM

Answers

  • After days of struggling, I've finally came to a working out-of-band redirection (on Win7 as well as Win8).

    The trick was to call FwpsAcquireWritableLayerDataPointer after FwpsPendClassify (from the work item), contrary to what the documentation says.

    If this turns out to be the correct solution, then both the documentation and WFPSampler (the oob redirection part) seem to be incorrect...

    ________________________________________________

    The new pseudo code looks like:

    classifyFn

    {

        FwpsAcquireClassifyHandle

        FwpsRedirectHandleCreate (Win8 only)

        FwpsPendClassify

        IoQueueWorkItem( classifyFn_WorkItem )

    }

    classifyFn_WorkItem

    {

        FwpsAcquireWritableLayerDataPointer

            Perform the redirection. Modify the writable data.

        FwpsApplyModifiedLayerData

        FwpsCompleteClassify

        FwpsRedirectHandleDestroy (Win8 only)

        FwpsReleaseClassifyHandle

    }

    Good luck, it seems you need it when working with WFP..

    Monday, July 23, 2012 3:27 PM

All replies

  • 1) After the Completion call, you should see the changes made to the connection, and a new connect request for the new tuple.

    2) The lifetime for these is guaranteed only for the duration of the classifyFn, so for Out of band, you will need to clone the passed in values (either making deep clones or taking references).  You can see This in the WFPSampler (http://code.msdn.microsoft.com/Windows-Filtering-Platform-27553baa/sourcecode?fileId=51338&pathId=1593545230 syslib\HelperFunctions_ClassifyData.cpp::KrnlHlprClassifyDataCreateLocalCopy)

    Hope this helps,


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

    Thursday, July 5, 2012 5:38 PM
    Moderator
  • Same result after cloning data.

    On Win7, FwpsCompleteClassify has no effect. The request remains pended.

    It's curious, because the exact same code is working perfectly on Win8.

    Still looking...

    Friday, July 6, 2012 10:51 AM
  • Hi guys,

    My classifyFn looks like this.

    Does anyone know why the following code works correctly on Win8 and *doesn't* work on Win7?

    Am I doing something wrong?

    (The following snippet was stripped out of error checking, to reduce its size...)

       
    // ----------------------------------------------------------
    typedef struct _PENDED_CONNECT_REDIRECT_CONTEXT {
    	UINT64 iClassifyHandle;				/// Returned by FwpsAcquireClassifyHandle
    #if ( NTDDI_VERSION >= NTDDI_WIN8 )
    	HANDLE hRedirectHandle;				/// Returned by FwpsRedirectHandleCreate
    #endif
    	FWPS_CLASSIFY_OUT ClassifyOut;		/// Clone of the structure received in classifyFn
    	FWPS_CONNECT_REQUEST *pConnectData;	/// Returned by FwpsAcquireWritableLayerDataPointer
    	PIO_WORKITEM pWorkItem;				/// Returned by IoAllocateWorkItem
    } PENDED_CONNECT_REDIRECT_CONTEXT, *PPENDED_CONNECT_REDIRECT_CONTEXT;
    
    // ----------------------------------------------------------
    VOID MyClassifyFn_WorkItem(
    	_In_ PDEVICE_OBJECT pDeviceObject,
    	_In_opt_ PVOID pContext
    	)
    {
    	PENDED_CONNECT_REDIRECT_CONTEXT *pRdrCtx = (PENDED_CONNECT_REDIRECT_CONTEXT*)pContext;
    
    	// Perform the redirection
    	Internal_ModifyConnectTuple( pRdrCtx );
    
    	// Permit the connection
    	pRdrCtx->ClassifyOut.actionType = FWP_ACTION_PERMIT;
    
    	FwpsApplyModifiedLayerData( pRdrCtx->iClassifyHandle, pRdrCtx->pConnectData, FWPS_CLASSIFY_FLAG_REAUTHORIZE_IF_MODIFIED_BY_OTHERS );
    	FwpsCompleteClassify( pRdrCtx->iClassifyHandle, 0, &pRdrCtx->ClassifyOut );
    #if ( NTDDI_VERSION >= NTDDI_WIN8 )
    	FwpsRedirectHandleDestroy( pRdrCtx->hRedirectHandle );
    #endif
    	FwpsReleaseClassifyHandle( pRdrCtx->iClassifyHandle );
    
    	IoFreeWorkItem( pRdrCtx->pWorkItem );
    	ExFreePoolWithTag( pRdrCtx, 'uQdB' );
    }
    
    // ----------------------------------------------------------
    VOID MyClassifyFn(
    	_In_ const FWPS_INCOMING_VALUES* pClassifyValues,
    	_In_ const FWPS_INCOMING_METADATA_VALUES* pMetadata,
    	_Inout_opt_ VOID* pLayerData,
    	_In_opt_ const VOID* pClassifyContext,
    	_In_ const FWPS_FILTER* pFilter,
    	_In_ UINT64 flowContext,
    	_Inout_ FWPS_CLASSIFY_OUT* pClassifyOut
    	)
    {
    	if ( (pClassifyOut->rights & FWPS_RIGHT_ACTION_WRITE) ||
    		!(pClassifyValues->incomingValue[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_FLAGS].value.uint32 & FWP_CONDITION_FLAG_IS_REAUTHORIZE))	/// The connection is not reauthorizing
    	{
    		PENDED_CONNECT_REDIRECT_CONTEXT *pRdrCtx = NULL;
    
    		// Don't redirect connections created by my proxy process
    		if ( FWPS_IS_METADATA_FIELD_PRESENT( pMetadata, FWPS_METADATA_FIELD_PROCESS_ID ))
    			if ( pMetadata->processId == g_iMyProxyPID )
    				return;
    
    		// Allocate a transient PENDED_CONNECT_REDIRECT_CONTEXT structure
    		pRdrCtx = (PPENDED_CONNECT_REDIRECT_CONTEXT)ExAllocatePoolWithTag( NonPagedPoolNx, sizeof( PENDED_CONNECT_REDIRECT_CONTEXT ), 'uQdB' );
    		RtlZeroBytes( pRdrCtx, sizeof( PENDED_CONNECT_REDIRECT_CONTEXT ));
    
    		FwpsAcquireClassifyHandle((void*)pClassifyContext, 0, &pRdrCtx->iClassifyHandle );
    #if ( NTDDI_VERSION >= NTDDI_WIN8 )
    		FwpsRedirectHandleCreate( &GUID_BDNET_PROVIDER, 0, &pRdrCtx->hRedirectHandle );
    #endif
    		FwpsAcquireWritableLayerDataPointer( pRdrCtx->iClassifyHandle, pFilter->filterId, 0, &pRdrCtx->pConnectData, pClassifyOut );
    		FwpsPendClassify( pRdrCtx->iClassifyHandle, pFilter->filterId, 0, pClassifyOut );
    
    		// Remember the pClassifyOut
    		RtlCopyMemory( &pRdrCtx->ClassifyOut, pClassifyOut, sizeof( FWPS_CLASSIFY_OUT ));
    
    		// Reroute the execution to a work item
    		pRdrCtx->pWorkItem = IoAllocateWorkItem( g_pDeviceObj );
    		IoQueueWorkItem( pRdrCtx->pWorkItem, Redirect_classifyFn_WorkItem, DelayedWorkQueue, pRdrCtx );
       	}
    }


    Wednesday, July 18, 2012 6:45 PM
  • After days of struggling, I've finally came to a working out-of-band redirection (on Win7 as well as Win8).

    The trick was to call FwpsAcquireWritableLayerDataPointer after FwpsPendClassify (from the work item), contrary to what the documentation says.

    If this turns out to be the correct solution, then both the documentation and WFPSampler (the oob redirection part) seem to be incorrect...

    ________________________________________________

    The new pseudo code looks like:

    classifyFn

    {

        FwpsAcquireClassifyHandle

        FwpsRedirectHandleCreate (Win8 only)

        FwpsPendClassify

        IoQueueWorkItem( classifyFn_WorkItem )

    }

    classifyFn_WorkItem

    {

        FwpsAcquireWritableLayerDataPointer

            Perform the redirection. Modify the writable data.

        FwpsApplyModifiedLayerData

        FwpsCompleteClassify

        FwpsRedirectHandleDestroy (Win8 only)

        FwpsReleaseClassifyHandle

    }

    Good luck, it seems you need it when working with WFP..

    Monday, July 23, 2012 3:27 PM
  • Our sustained engineering team is investigating this.  I will reply with their findings.

    Thanks,


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

    Tuesday, July 24, 2012 5:34 PM
    Moderator
  • You can look at this thread:
    http://social.msdn.microsoft.com/Forums/br/wfp/thread/d87a9374-f31e-488d-b92b-a0efdd3f149a

    In summary, the API calls should be:

    Async:

    From classifyFn --

    1) FwpsAcquireClassifyHandle0
    2) [optional] allocate a FWPS_CLASSIFY_OUT0 sized object and copy all fields from the classifyOut param to the driver- allocated object.
    3) FwpsPendClassify0(..., classifyOut);


    From worker thread --

    3) FwpsAcquireWritableLayerDataPointer0(..., NULL);
    4) modify writable fields of FWPS_CONNECT_REQUEST0 (after casting from the OUT writableLayerData parameter) as desired.
    5) FwpsApplyModifiedLayerData0 (Set the FWPS_CLASSIFY_FLAG_REAUTHORIZE_IF_MODIFIED_BY_OTHERS flag if you wish to be re-authorized should your modification is furthur modified by another callout)
    6) FwpsCompleteClassify0 (Pass in the driver-allocated classifyOut object if you wish to avoid completion- triggered re-auth; set the actionType to PERMIT before passing the pointer)
    7) FwpsReleaseClassifyHandle0 

    We will be updating the documentation and WFPSampler as appropriate.

    Thanks,


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

    Tuesday, September 18, 2012 3:14 PM
    Moderator