none
Re-inject in forward classify function. RRS feed

  • Question

  • On host with NAT enabled I try clone packet and do re-inject in forward classify function, but re-injected packet is not received.  I don`t understand where is mistakeSad. "status" variable is always success. Re-inject is made in next way:

    void NTAPI IpforwardV4Classify(
        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
    )
    {
    .............
        injectionState = FwpsQueryPacketInjectionState0(g_hInjectionForwardV4,pNetBufferList,NULL);
        if (injectionState == FWPS_PACKET_INJECTED_BY_SELF ||
            injectionState == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF)
        {
    // We never get packet here
            dprintf("IpforwardV4Classify. FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF.");
            classifyOut->actionType = FWP_ACTION_PERMIT;
            return;
        }
    ...............
        status = FwpsAllocateCloneNetBufferList0(
            pNetBufferList,
            NULL,
            NULL,
            0,
            &pClonedNetBufferList);
      
        status = FwpsInjectForwardAsync0(
            g_hInjectionForwardV4,
            (HANDLE)NULL,
            (UINT32)0,
            AF_INET,
            inMetaValues->compartmentId,
            inFixedValues->incomingValue[FWPS_FIELD_IPFORWARD_V4_SOURCE_INTERFACE_INDEX].value.uint16,
            pClonedNetBufferList,
            (FWPS_INJECT_COMPLETE0)IpInjectionCompletion,
            0);

        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
        return;
    }

    NTSTATUS CreateInjectionHandles()
    {
    .........
        status = FwpsInjectionHandleCreate0(
            AF_UNSPEC,
            FWPS_INJECTION_TYPE_FORWARD,
            &g_hInjectionForwardV4
            );
    ..........
    }

    void NTAPI IpInjectionCompletion(
        IN void* context,
        IN OUT NET_BUFFER_LIST* pNetBufferList,
        IN BOOLEAN  dispatchLevel
    )
    {
        if (pNetBufferList)
            FwpsFreeCloneNetBufferList0(pNetBufferList,0);   
    }

    Wednesday, December 19, 2007 9:48 AM

Answers

  • In order to block pre-NAT traffic when ICS is enabled, you would need to register your callout (of type FWP_ACTION_CALLOUT_TERMINATING, of course) at the same sublayer that the ICS filter resides; *and* the weight of your filter would need to be higher than that of the ICS filter. I am not an expert on the ICS filter but I believe it is sitting at the FWPM_SUBLAYER_UNIVERSAL w/ a very high weight (you can use the WFP management api to enumerate all filters at the FORWARD layers to confirm this).

     

    We actually don't recommend this approach because it does not follow the preferred WFP arbitartion model (i.e. a "terminating" callout should register at its own sub-layer).

     

    Therefore If your firewall must block such packets, you should consider developing a NDIS LightWeight Filter (LWF) for the time being -- LWF drivers can intercept packets before TCPIP/WFP processing.

     

    Thanks,

    Biao.W.

    Tuesday, January 1, 2008 10:11 AM

All replies

  •  Alexander Lototsky wrote:
    On host with NAT enabled I try clone packet and do re-inject in forward classify function, but re-injected packet is not received.  I don`t understand where is mistake. "status" variable is always success.

     

    I don't know anything about your issue, but for a proper error code from injection you should check the Status member of the pNetBufferList in your InjectionCompletion function, something like this:

     

    Code Block
    void NTAPI IpInjectionCompletion(
        IN void* context,
        IN OUT NET_BUFFER_LIST* pNetBufferList,
        IN BOOLEAN  dispatchLevel
    )
    {
        if (pNetBufferList)
        {
            KdPrint(("Reinjection status %08x\n", pNetBufferList->Status));
            FwpsFreeCloneNetBufferList0(pNetBufferList,0);
        }
    }

     

     


    Wednesday, December 19, 2007 6:05 PM
  • The interfaceIndex parameter of the FwpsInjectForwardAsync0 function is that of the destination interface. And IF_INDEX is a 32-bit value.

     

    So change this code

     

        inFixedValues->incomingValue[FWPS_FIELD_IPFORWARD_V4_SOURCE_INTERFACE_INDEX].value.uint16

     

    to

     

        inFixedValues->incomingValue[FWPS_FIELD_IPFORWARD_V4_DESTINATION_INTERFACE_INDEX].value.uint32

     

    to see if it addresses the problem.

     

    Biao.W.

    Thursday, December 20, 2007 1:33 AM
  • Thank you for helpful advices, guys.

    It seems that forward classify don`t get re-injected packet, but packet is permited in some other place. So packet goes out after re-injection. I think it is not bad.

    But opposite problem was detected Smile : I can`t block NAT packet in forward classify function.

    Code Snippet

    void NTAPI IpforwardV4Classify(
        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
    )
    {
    .........
        classifyOut->actionType = FWP_ACTION_BLOCK;
        classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
        classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
        return;
    }



    This code called, and blocks routed packets but doesn`t block NAT packets.
    Thursday, December 20, 2007 1:18 PM
  • Yes forward- injected packet does not re-enter the forwarding layer, hence you won't be reclassified.

     

    For the second issue, are you registering at your own sublayer? If not can you give that a try?

     

    Biao.W.

    Thursday, December 20, 2007 10:34 PM
  •  Biao Wang [MSFT] wrote:

    Yes forward- injected packet does not re-enter the forwarding layer, hence you won't be reclassified.

     

    For the second issue, are you registering at your own sublayer? If not can you give that a try?

     

    Biao.W.



    Sure, as you recomended in some previous thread, I created my own provider and sublayer for my fitlers:

    Code Snippet

                    myProvider.displayData.name = L"Provider Name";
                    myProvider.displayData.description = L"Provider Description";
                    myProvider.serviceName = L"Windows Time";
                    myProvider.providerKey = MY_PROVIDER;
                    status = FwpmProviderAdd0(hEngine,
                        &myProvider,
                        0);

                    mySubLayer.displayData.name = L"Sublayer Name";
                    mySubLayer.displayData.description = L"Sublayer Description";
                    mySubLayer.providerKey = &(myProvider.providerKey);
                    mySubLayer.weight = 0xFFFF;
                    mySubLayer.subLayerKey = MY_SUBLAYER;
                    status = FwpmSubLayerAdd0(hEngine,
                        &mySubLayer,
                        0);



    Than add and register callouts. Than add filters in new sublayer with FwpmFilterAdd0:

    Code Snippet

        sCallout.calloutKey = *pCalloutKey;
        sCallout.classifyFn = pfClassify;
        sCallout.notifyFn = pfNotify;
        status = FwpsCalloutRegister0(                
            pDeviceObject,
            &sCallout,
            &calloutId
            );


        mCallout.calloutKey = *pCalloutKey;
        mCallout.displayData.name = pDescription;
        mCallout.displayData.description = pDescription;
        mCallout.applicableLayer = *pLayerKey;   // FWPM_LAYER_IPFORWARD_V4
        status = FwpmCalloutAdd0(
            hEngine,
            &mCallout,
            NULL,
            NULL
            );


        filter.filterKey = *pFilterKey;
        filter.layerKey = *pLayerKey;       // FWPM_LAYER_IPFORWARD_V4
        filter.displayData.name = pDescription;
        filter.displayData.description = pDescription;
        filter.action.type = FWP_ACTION_CALLOUT_TERMINATING;
        filter.action.calloutKey = *pCalloutKey;
        filter.subLayerKey = *pSublayerKey; // MY_SUBLAYER
        status = FwpmFilterAdd0(
            hEngine,
            &filter,
            NULL,
            NULL);



    Forward classify function just block all packets:

    Code Snippet

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

        return;



    FWP_ACTION_BLOCK works for routed packets, that are resended without NAT processing (involve just one network interface on host with NAT). But doesn`t work for packets that are resended via "another" NIC after NATing.

    It is interesting: in both cases forward classify function was called.
    Friday, December 21, 2007 3:03 PM
  • I think this is what happened --

     

    The NAT callout driver grabs the packet before your callout is invoked, it makes a clone and performs a send- injection directly into the public interface. Since send- injections don't traverse the FORWARD layer, your callout doesn't see it. To block such packets, you will need to register at OUTBOUND_IPPACKET layers as well.

     

    Ideally WFP callout drivers (NAT included) should perform recv- injections (FwpsInjectNetworkReceiveAsync or FwpsInjectTransportReceiveAsync) with packets that it captures and clones from the FORWARD layers. Recv- injected packets will traverse FORWRD layers again such that other callouts there can have a opportunity to inspect re-injected clones.

     

    [Note: FwpsInjectForwardAsync0 should only be used when a callout is the only callout register at FORWRD since forward- injected packets don't re-enter FORWRAD layers. FwpsInjectForwardAsync was designed to be a perf optimization over the recv- injection functions in the single-callout scenarios.]

     

    We will suggest a design change to the NAT team in their future releases.

     

    Hope this helps,

    Biao.W.

    Saturday, December 22, 2007 9:27 AM
  • So I can`t block NATed packets by (for example) sender ip. Right?
    Friday, December 28, 2007 1:03 PM
  • In order to block pre-NAT traffic when ICS is enabled, you would need to register your callout (of type FWP_ACTION_CALLOUT_TERMINATING, of course) at the same sublayer that the ICS filter resides; *and* the weight of your filter would need to be higher than that of the ICS filter. I am not an expert on the ICS filter but I believe it is sitting at the FWPM_SUBLAYER_UNIVERSAL w/ a very high weight (you can use the WFP management api to enumerate all filters at the FORWARD layers to confirm this).

     

    We actually don't recommend this approach because it does not follow the preferred WFP arbitartion model (i.e. a "terminating" callout should register at its own sub-layer).

     

    Therefore If your firewall must block such packets, you should consider developing a NDIS LightWeight Filter (LWF) for the time being -- LWF drivers can intercept packets before TCPIP/WFP processing.

     

    Thanks,

    Biao.W.

    Tuesday, January 1, 2008 10:11 AM