none
Cannot inject cloned net buffer list at FWPM_LAYER_OUTBOUND_IPPACKET_V4 WFP layer RRS feed

  • Question

  • Hello

    The problem is reproduced in Windows Vista SP1 Ultimate for x64.
    I do the following steps.

    1. Register callout at mentioned layer and add filter for it.

            ntStatus = m_handler.AddCallout(GUID_TCPV4_OUT_PACKET_CALLOUT, FWPM_LAYER_OUTBOUND_IPPACKET_V4,
                TCPV4_OUT_PACKET_CALLOUT_NAME, 0, m_nAddOutPacketV4Id);

           // ...

            memset(&filter, 0, sizeof(FWPM_FILTER0));
            memset(&condition, 0, sizeof(FWPM_FILTER_CONDITION0));
            memset(&provider_data, 0, sizeof(FWP_BYTE_BLOB));

            // add main data
            filter.filterKey = GUID_TCPV4_OUT_PACKET_FILTER;   
            filter.displayData.name = TCPV4_OUT_PACKET_FILTER_NAME;   
            filter.displayData.description = TCPV4_OUT_PACKET_FILTER_NAME;   
            filter.flags = FWPM_FILTER_FLAG_NONE;   
            filter.providerKey = NULL;   
            filter.providerData.data = (UINT8*)&provider_data;   
            filter.providerData.size = 0;   
            filter.layerKey = FWPM_LAYER_OUTBOUND_IPPACKET_V4;   

            filter.weight.type = FWP_EMPTY;   
            filter.action.type = FWP_ACTION_CALLOUT_TERMINATING;   
            filter.action.calloutKey = GUID_TCPV4_OUT_PACKET_CALLOUT;   

            ntStatus = m_handler.AddFilter(filter, m_nFilterOutPacketV4Id);

    2. At this layer parse net buffer list and, in case where certain  packet satisfied  my condition, redirect  it to  the TCP server, listening at 9000 port.

            FWPS_PACKET_INJECTION_STATE state = FwpsQueryPacketInjectionState0(m_hInjectionNetwork, pNbl, NULL);
            if((state == FWPS_PACKET_INJECTED_BY_SELF) || (state == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF))
            {
                break;
            }

            if (!TEST_FLAG(classifyOut->rights, FWPS_RIGHT_ACTION_WRITE))
                break;

            if((InterlockedCompareExchange(&m_bShutdown, FALSE, FALSE) == TRUE))
                break;

            // Analyze IP header in order to determine source/destination addresses and protocol.
            // If protocol is not TCP, just do nothing.

            for(pNetBuffer = NET_BUFFER_LIST_FIRST_NB(pNbl); pNetBuffer != NULL; pNetBuffer = NET_BUFFER_NEXT_NB(pNetBuffer))
            {
                struct ip* pIpHdr = (struct ip*)NdisGetDataBuffer(pNetBuffer, sizeof(struct ip), NULL, 1, 0);
                if(!pIpHdr)
                    continue;

                SIZE_T nIpHdrSize = (pIpHdr->ip_verlen & 0xF) << 2;
                USHORT nPacketLen = RtlUshortByteSwap(pIpHdr->ip_len);
                USHORT nTcpLength = nPacketLen - sizeof(struct ip);
               
                nSrcAddr = pIpHdr->ip_src;
                nDstAddr = pIpHdr->ip_dst;

                if(pIpHdr->ip_p != IPPROTO_TCP)
                    continue;

                // Analyze TCP header in order to determine source/destination ports.
                // For the client we should change source address and source port.
                // For the server, however, we should change destination address and destination port.

                NdisAdvanceNetBufferDataStart(pNetBuffer, inMetaValues->ipHeaderSize, FALSE, NULL);

                struct tcphdr* pTcpHdr = (struct tcphdr*)NdisGetDataBuffer(pNetBuffer, sizeof(struct tcphdr), NULL, 1, 0);
                if(!pTcpHdr)
                {
                    NdisRetreatNetBufferDataStart(pNetBuffer, inMetaValues->ipHeaderSize, 0, NULL);
                    continue;
                }

                nSrcPort = RtlUshortByteSwap(pTcpHdr->th_sport);
                nDstPort = RtlUshortByteSwap(pTcpHdr->th_dport);

                if((nSrcAddr == nDstAddr) && (nSrcPort == KFilterLogic::GetListener().GetListeningPort()))
                {
                    NdisRetreatNetBufferDataStart(pNetBuffer, inMetaValues->ipHeaderSize, 0, NULL);

                    {
                        // Obtain an necessary socket.   
                        KLocker<> locker(connections);

                        conn::SOCKET_LIST_ITEM* pSockItem = connections.GetTcpSocket(false, (PByte)&nDstAddr, nDstPort);
                        if(!pSockItem)
                            break;

                        conn::CONN_LIST& connList = pSockItem->second.GetConnectionList();
                        if(connList.empty())
                            break;

                        conn::CONN_LIST_ITEM* pConnItem = connList[0];
                        if(!pConnItem)
                            break;

                        memcpy((PByte)&nTargetAddr, pConnItem->first.m_address, sizeof(nTargetAddr));
                        nTargetPort = pConnItem->first.m_nPort;
                    }
                   
                    packetType = optServer;
                    break;
                }

                {
                    KLocker<> locker(connections);
                    if(connections.IsConnectionBlocked(false, (PByte)&nSrcAddr, nSrcPort, (PByte)&nDstAddr, nDstPort))
                    {
                        NdisRetreatNetBufferDataStart(pNetBuffer, inMetaValues->ipHeaderSize, 0, NULL);
                       
                        packetType = optClient;
                        nTargetAddr = nDstAddr;
                        nTargetPort = nDstPort;
                        break;
                    }
                }

                NdisRetreatNetBufferDataStart(pNetBuffer, inMetaValues->ipHeaderSize, 0, NULL);
            }

            if(packetType != optOther)
            {
                // clone existing NBL
                ntStatus = FwpsAllocateCloneNetBufferList0(pNbl, NULL, NULL, 0, &pClonedNbl);

                 // replace remote address/port

                 // inject cloned NBL
                 ntStatus = FwpsInjectNetworkSendAsync0(m_hInjectionNetwork,    
                    NULL, (COMPARTMENT_ID)inMetaValues->compartmentId,
                    pClonedNbl, sNetworkInjectCompletion, NULL);

                     classifyOut->actionType = FWP_ACTION_BLOCK;
                    CLEAR_FLAG(classifyOut->rights, FWPS_RIGHT_ACTION_WRITE);
                    SET_FLAG(classifyOut->flags, FWPS_CLASSIFY_OUT_FLAG_ABSORB);
            }

        } while(0);
    }

    FwpsInjectNetworkSendAsync0 returns STATUS_SUCCESS, but in the inject completion function netBufferList->Status  is STATUS_NOT_ACCEPTED.  I tried  to inject cloned NBL without any modifications, but result is the same. Why? Please give
    me hint what this error  consisted  in.

    Note that this error isn't reproduced in Windows Vista x32.

    Thanks

     
    Friday, February 13, 2009 2:11 PM

Answers