locked
I wanna log the NEW connection of UDP, but it does not work well RRS feed

  • Question

  • here's the code snippet:

        callout.calloutKey      = IN_ACCEPT_CALLOUT_V4 ;
        callout.applicableLayer = FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4 ;
        status = FwpmCalloutAdd0(hEngine, &callout, NULL, NULL) ;

     

    ...............................

     

        callout.calloutKey = IN_ACCEPT_CALLOUT_V4 ;
        callout.classifyFn = EvtInboundAccept ;
        status = FwpsCalloutRegister0(pDeviceObject, &callout, NULL) ;

     

    .....................................................

     

    VOID NTAPI EvtInboundAccept(IN const FWPS_INCOMING_VALUES0 *pFixedValues,
                                IN const FWPS_INCOMING_METADATA_VALUES0 *pMetaValues,
                                IN OUT VOID *pLayerData,
                                IN const FWPS_FILTER0 *pFilter,
                                IN UINT64 flowContext,
                                OUT FWPS_CLASSIFY_OUT0 *pClassifyOut)
    {
        FWPS_PACKET_INJECTION_STATE injectionState = 0 ;
        NTSTATUS   status          = STATUS_SUCCESS ;
        UINT8      protocol        = 0,
                   addressType     = 0 ;
        UINT16     localPort       = 0,
                   remotePort      = 0 ;
        UINT32     localAddress    = 0,
                   remoteAddress   = 0;
        UINT64     processId       = 0 ;
        LListItem* pListItem       = NULL ;
        IORule*    pRule           = NULL ;
        BOOLEAN    zSignalUserMode = FALSE ;
        KIRQL      irql ;

     UNREFERENCED_PARAMETER(flowContext);

     /* Layer is FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 i.e. pFixedValues->layerId = FWPS_LAYER_ALE_AUTH_RECV_ACCEPT_V4 */

        localAddress  = pFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS].value.uint32 ;
        localPort     = pFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT].value.uint16 ;
        remoteAddress = pFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS].value.uint32 ;
        remotePort    = pFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT].value.uint16 ;
        protocol      = pFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8 ;
        addressType   = pFixedValues->incomingValue[FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS_TYPE].value.uint8 ;
        processId     = pMetaValues->processId ;

        DPRINT(WA_DEBUG_CLASSIFY, ("Accept: loc=%d.%d.%d.%d:%x rem=%d.%d.%d.%d:%x prot=%d pid=%llu nl=%d iph=%d tph=%d meta=%d",
         dbg_ip_port(localAddress, localPort),
         dbg_ip_port(remoteAddress, remotePort),
                  protocol,
                  processId,
                  addressType,
                  pMetaValues->ipHeaderSize,
                  pMetaValues->transportHeaderSize,
                  pMetaValues->currentMetadataValues)) ;

     if ( protocol == PROTOCOL_UDP )
     {
      DbgPrint( "Accept: loc=%d.%d.%d.%d:%x rem=%d.%d.%d.%d:%x prot=%d pid=%llu nl=%d iph=%d tph=%d meta=%d",
       dbg_ip_port(localAddress, localPort),
       dbg_ip_port(remoteAddress, remotePort),
       protocol,
       processId,
       addressType,
       pMetaValues->ipHeaderSize,
       pMetaValues->transportHeaderSize,
       pMetaValues->currentMetadataValues );
     }

        injectionState = FwpsQueryPacketInjectionState0(ghInjection,
                                                        (PNET_BUFFER_LIST)pLayerData,
                                                        NULL) ;
        if( injectionState == FWPS_PACKET_INJECTED_BY_SELF ||
            injectionState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF )
        {
            DPRINT(WA_DEBUG_CLASSIFY, ("Info: Accept packet previously injected by self, ignoring")) ;
            pClassifyOut->actionType = FWP_ACTION_PERMIT ;
            goto done ;
        }

        if( !(pClassifyOut->rights & FWPS_RIGHT_ACTION_WRITE) )
        {
            DPRINT(WA_DEBUG_CLASSIFY, ("Info: No permission to write")) ;
            return ;
        }

        pClassifyOut->actionType = FWP_ACTION_BLOCK ;

        if( (protocol != PROTOCOL_TCP && protocol != PROTOCOL_UDP) ||
            addressType == NlatAnycast   ||
            addressType == NlatBroadcast ||
            addressType == NlatMulticast ||
            addressType == NlatInvalid   ||
            (pMetaValues->currentMetadataValues & FWPS_METADATA_FIELD_FLOW_HANDLE) )
        {
            DPRINT(WA_DEBUG_CLASSIFY, ("Info: Unmanaged protocol, invalid or ***cast address, permitting")) ;
            pClassifyOut->actionType = FWP_ACTION_PERMIT ;
            goto done ;
        }


        LOCK(&gDriverMutex, &irql) ;
     //from gpUDPRules find the rules
        pListItem = FindIORule(protocol,
                               OT_IO_RULE,
                               localAddress,
                               localPort,
                               remoteAddress,
                               remotePort,
                               0, 0, 0, 0) ;
        UNLOCK(&gDriverMutex, irql);

        if( pListItem == NULL )
        {
      //Address exclusion, permitting accept packet
            if( IsInExcludeRange(localAddress, remoteAddress) )
            {
                DPRINT(WA_DEBUG_CLASSIFY, ("Info: Address exclusion, permitting accept packet")) ;
                pClassifyOut->actionType = FWP_ACTION_PERMIT ;
                goto done ;
            }
        }
        else
        {
            pRule = (IORule*)pListItem->pObject ;

            if( IsDriverActive() && pRule->type == IOR_TYPE_PASSIVE )
            {
                DPRINT(WA_DEBUG_CLASSIFY, ("Info: Deleting passive rule in accept for loc=0x%x:%x rem=0x%x:%x",
                          localAddress, localPort, remoteAddress, remotePort)) ;

                LOCK(&gDriverMutex, &irql) ;
                LListDelete( (protocol == PROTOCOL_TCP) ? gpTCPRules : gpUDPRules, pListItem) ;
                UNLOCK(&gDriverMutex, irql) ;
            }
            else
            {

                if( pRule->decision == POLICY_DECISION_ACCEPT )
                {
                    if( pLayerData != NULL &&
                        pRule->in.rewriteLocalAddr  != 0 &&
                        pRule->in.rewriteLocalPort  != 0 &&
                        pRule->in.rewriteRemoteAddr != 0 &&
                        pRule->in.rewriteRemotePort != 0 )
                    {
                        InjectInfo* pInjectInfo = NULL ;

                        status = CreateInjectInfo(pFixedValues,
                                                  pMetaValues,
                                                  (PNET_BUFFER_LIST)pLayerData,
                                                  localAddress,
                                                  localPort,
                                                  remoteAddress,
                                                  remotePort,
                                                  pRule,
                                                  INJECT_ACCEPT,
                                                  &pInjectInfo) ;
                        if( !NT_SUCCESS(status) )
                        {
                            DPRINT(WA_DEBUG_ERR, ("Error: Failed to create inject info for accept packet, status=%d", status)) ;
                            goto done ;
                        }

                        DPRINT(WA_DEBUG_CLASSIFY, ("Info: Queue'ing accept packet for re-injection")) ;

                        LOCK(&gDriverMutex, &irql) ;
                        LListAddObject(gpInjectQueue, pInjectInfo, OT_INJECT_SEND, NULL) ;
                        UNLOCK(&gDriverMutex, irql) ;

                        KeInsertQueueDpc(&gInjectDpc, NULL, NULL) ;

                        pClassifyOut->actionType = FWP_ACTION_BLOCK ;
                        pClassifyOut->flags     |= FWPS_CLASSIFY_OUT_FLAG_ABSORB ;
                    }
                    else
                    {
                        pClassifyOut->actionType = FWP_ACTION_PERMIT ;
                    }
                }
                goto done ;
            }
        }

        status = CreateIORule(protocol,
                              DIRECTION_INCOMING,
                              localAddress,
                              localPort,
                              remoteAddress,
                              remotePort,
                              processId,
                              &pRule) ;
        if( !NT_SUCCESS(status) )
        {
            DPRINT(WA_DEBUG_ERR ,("Error: Failed to create new rule for accept, status %d", status)) ;
            goto done ;
        }

        if( !IsDriverActive() )
        {
            DPRINT(WA_DEBUG_CLASSIFY ,("Info: Creating rule for passive accept")) ;

            pRule->decision = POLICY_DECISION_ACCEPT ;
            pRule->type     = IOR_TYPE_PASSIVE ;

            LOCK(&gDriverMutex, &irql) ;
            LListAddObject( (pRule->protocol == PROTOCOL_TCP) ? gpTCPRules : gpUDPRules,
                            pRule, OT_IO_RULE, &pRule->uniqueId) ;
            UNLOCK(&gDriverMutex, irql) ;

            pClassifyOut->actionType = FWP_ACTION_PERMIT ;
            goto done ;
        }

        status = CreateInjectInfo(pFixedValues,
                                  pMetaValues,
                                  (PNET_BUFFER_LIST)pLayerData,
                                  localAddress,
                                  localPort,
                                  remoteAddress,
                                  remotePort,
                                  pRule,
                                  INJECT_ACCEPT,
                                  (InjectInfo**)&pRule->pCompletionArgument) ;
        if( !NT_SUCCESS(status) )
        {
            DPRINT(WA_DEBUG_ERR ,("Error: Failed to create inject info for accept packet, status=%d", status)) ;
            goto done ;
        }
        pRule->pfnCompletionFunc  = CompleteAccept ;
        pRule->hCompletionContext = NULL ;

        LOCK(&gDriverMutex, &irql) ;
        status = LListAddObject(gpPendingRules, pRule, OT_PENDING_RULE, &pRule->uniqueId) ;
        UNLOCK(&gDriverMutex, irql) ;
        if( !NT_SUCCESS(status) )
        {
            DPRINT(WA_DEBUG_ERR ,("Error: Failed to add accept request to pending list. %d", status)) ;

            if( pRule->pCompletionArgument != NULL )
                DeleteInjectInfo( (InjectInfo**)&pRule->pCompletionArgument ) ;

            goto done ;
        }

        zSignalUserMode = TRUE ;

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

    done:

        if( pClassifyOut->actionType == FWP_ACTION_PERMIT )
        {
            DPRINT(WA_DEBUG_CLASSIFY ,("Info: PERMIT'ting accept packet")) ;

            // Check whether the FWPS_RIGHT_ACTION_WRITE flag should be cleared
            if( pFilter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT ) {
                // Clear the FWPS_RIGHT_ACTION_WRITE flag
                pClassifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE ;
            }
        }
        else  
        {
            DPRINT(WA_DEBUG_CLASSIFY ,("Info: BLOCK'ing accept packet")) ;

            pClassifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE ;
        }

        if( zSignalUserMode )
            SIGNAL_USERMODE() ;
    }

     

    it does not call CreateIORule , what's wrong? thanks

     

     

    Tuesday, July 6, 2010 3:45 AM

Answers

  • The line you are referring to is probably an attempt to verify this was the first packet of the flow.  This methodology is not correct.  A better way to do this would be to sit at FLOW_ESTABLISHED.  this can tell you when the TCP Connection gets established (the 3 way handshake has completed) or non TCP connections come up (either a non tcp packet is received, or sent, creating a new flow).

     

    Hope this helps,


    Dusty Harper [MSFT]
    Microsoft Corporation
    ------------------------------------------------------------
    This posting is provided "AS IS", with NO warranties and confers NO rights
    ------------------------------------------------------------
    Thursday, July 8, 2010 4:14 AM
    Moderator

All replies

  • Have you walked this through a Kernel Debugger?  Set a breakpoint on your classify function and walk your code.

    There are multiple jumps and returns in your code which could be the reason CreateIORule() is not called.  If you can supply more details, then we may be able to assist further.

     

    Hope this helps,

     


    Dusty Harper [MSFT]
    Microsoft Corporation
    ------------------------------------------------------------
    This posting is provided "AS IS", with NO warranties and confers NO rights
    ------------------------------------------------------------
    Tuesday, July 6, 2010 6:34 PM
    Moderator
  • hi Dusty:

    I worked this through windbg ,  I found  most return by this code:

        if( (protocol != PROTOCOL_TCP && protocol != PROTOCOL_UDP) ||
            addressType == NlatAnycast   ||
            addressType == NlatBroadcast ||
            addressType == NlatMulticast ||
            addressType == NlatInvalid   ||
            (pMetaValues->currentMetadataValues & FWPS_METADATA_FIELD_FLOW_HANDLE) )
        {
            DPRINT(WA_DEBUG_CLASSIFY, ("Info: Unmanaged protocol, invalid or ***cast address, permitting")) ;
            pClassifyOut->actionType = FWP_ACTION_PERMIT ;
            goto done ;
        }

    just the code :

    (pMetaValues->currentMetadataValues & FWPS_METADATA_FIELD_FLOW_HANDLE)

    is it necessary?

    but I think it is  not  using flowhandle in this callout.

    here is some functions:

    NTSTATUS CreateIORule(IN UINT protocol,
                          IN UINT direction,
                          IN UINT32 localAddress,
                          IN UINT16 localPort,
                          IN UINT32 remoteAddress,
                          IN UINT16 remotePort,
                          IN UINT64 processId,
                          OUT IORule** ppRule)
    {
        (*ppRule) = KMalloc( sizeof(IORule) ) ;
        if( (*ppRule) == NULL )
            return STATUS_INSUFFICIENT_RESOURCES ;

     // DPRINT(WA_DEBUG_CLASSIFY,
        memset((*ppRule), 0, sizeof(IORule)) ;

        (*ppRule)->protocol           = (UINT8)protocol ;
        (*ppRule)->direction          = direction ;
        (*ppRule)->processId          = processId ;
        (*ppRule)->decision           = POLICY_DECISION_UNKNOWN ;
        (*ppRule)->cacheTimeout       = GetCurrentTimeMillis() + RULE_VALID_IN_CACHE_MILLISEC ;
       
        /*Mukund J - making it explicit */
        (*ppRule)->type                = 0;
        (*ppRule)->hCompletionContext  = NULL;
        (*ppRule)->pCompletionArgument = NULL;

        (*ppRule)->out.localAddr      = localAddress ;
        (*ppRule)->out.localPort      = localPort ;
        (*ppRule)->out.remoteAddr     = remoteAddress ;
        (*ppRule)->out.remotePort     = remotePort ;

        (*ppRule)->in.localAddr       = localAddress ;
        (*ppRule)->in.localPort       = localPort ;
        (*ppRule)->in.remoteAddr      = remoteAddress ;
        (*ppRule)->in.remotePort      = remotePort ;

        return STATUS_SUCCESS ;
    }

     

    BOOLEAN IsDriverActive()
    {
        return zDriverActive ;
    }

    NTSTATUS CreateInjectInfo(IN const FWPS_INCOMING_VALUES0 *pFixedValues,
                              IN const FWPS_INCOMING_METADATA_VALUES0 *pMetaValues,
                              IN PNET_BUFFER_LIST pNetBufList,
                              IN UINT32 localAddr,
                              IN UINT16 localPort,
                              IN UINT32 remoteAddr,
                              IN UINT16 remotePort,
                              IN IORule* pRule,
                              IN UINT8 type,
                              IN OUT InjectInfo** ppInjectInfo)
    {
        NTSTATUS status = STATUS_SUCCESS ;

        // DPRINT(WA_DEBUG_DPC / WA_DEBUG_CLASSIFY
        *ppInjectInfo = (InjectInfo*)KMalloc( sizeof(InjectInfo) ) ;
        if( *ppInjectInfo == NULL )
        {
            DPRINT(WA_DEBUG_ERR, ("Error: Failed to allocate memory for injection info %d", STATUS_NO_MEMORY)) ;
            return STATUS_INSUFFICIENT_RESOURCES ;
        }
        memset(*ppInjectInfo, 0, sizeof(InjectInfo)) ;

     DPRINT(WA_DEBUG_DPC, ("*ppInjectInfo = 0x%p", *ppInjectInfo));


        if( pNetBufList != NULL )
            FwpsReferenceNetBufferList0(pNetBufList, TRUE) ;

        (*ppInjectInfo)->pNetBufList       = pNetBufList ;
        (*ppInjectInfo)->compartmentId     = pMetaValues->compartmentId ;
        (*ppInjectInfo)->transportEndpoint = pMetaValues->transportEndpointHandle ;
        (*ppInjectInfo)->pRule             = pRule ;
        (*ppInjectInfo)->ipHeaderSize      = (pMetaValues->ipHeaderSize == 0) ? 20 : pMetaValues->ipHeaderSize ;
        (*ppInjectInfo)->trpHeaderSize     = pMetaValues->transportHeaderSize ;
        (*ppInjectInfo)->pEsspRecord       = NULL ;
        (*ppInjectInfo)->type              = type ;
        (*ppInjectInfo)->adjustTcpAckNo    = 0 ;
        (*ppInjectInfo)->adjustTcpSeqNo    = 0 ;
        (*ppInjectInfo)->localAddr         = localAddr ;
        (*ppInjectInfo)->localPort         = localPort ;
        (*ppInjectInfo)->remoteAddr        = remoteAddr ;
        (*ppInjectInfo)->remotePort        = remotePort ;

     //adjust header start offset
        if( pFixedValues->layerId == FWPS_LAYER_INBOUND_TRANSPORT_V4 )
            (*ppInjectInfo)->startOffset  = (*ppInjectInfo)->ipHeaderSize + (*ppInjectInfo)->trpHeaderSize ;
        else  
            (*ppInjectInfo)->startOffset  = (*ppInjectInfo)->ipHeaderSize ;

        (*ppInjectInfo)->zFirstDataPacket = FALSE ;

        if( pRule->protocol == PROTOCOL_UDP &&
            (*ppInjectInfo)->type == INJECT_CONNECT )
        {
            (*ppInjectInfo)->zFirstDataPacket = TRUE ;
        }

     //NET_BUFFER_LIST_FIRST_NB is a macro that NDIS drivers use to get the first NET_BUFFER structure in a NET_BUFFER_LIST structure
        if( pRule->protocol == PROTOCOL_TCP &&
            pRule->hCompletionContext != NULL &&     
            (*ppInjectInfo)->type == INJECT_SEND &&
            IsTcpControlFlag( NET_BUFFER_LIST_FIRST_NB(pNetBufList),
                              pMetaValues->ipHeaderSize,
                              pMetaValues->transportHeaderSize,
                              TCP_CONTROL_ACK ) )
        {
            (*ppInjectInfo)->zFirstDataPacket = TRUE ;
        }

        return status ;
    }

     

    this code runs in win 7

    • Edited by taianmonkey Wednesday, July 7, 2010 2:41 AM
    Wednesday, July 7, 2010 1:36 AM
  • The line you are referring to is probably an attempt to verify this was the first packet of the flow.  This methodology is not correct.  A better way to do this would be to sit at FLOW_ESTABLISHED.  this can tell you when the TCP Connection gets established (the 3 way handshake has completed) or non TCP connections come up (either a non tcp packet is received, or sent, creating a new flow).

     

    Hope this helps,


    Dusty Harper [MSFT]
    Microsoft Corporation
    ------------------------------------------------------------
    This posting is provided "AS IS", with NO warranties and confers NO rights
    ------------------------------------------------------------
    Thursday, July 8, 2010 4:14 AM
    Moderator