0

I'm writing a wfp driver which redirect all tcp/udp traffic to a local proxy service. I tried to modified the dest ip and port of outbound udp packets to my local proxy in the FWPM_LAYER_ALE_CONNECT_REDIRECT_V4 layer, and it works well. But when I'm trying to modify the inbound udp packets in the FWPM_LAYER_DATAGRAM_DATA_V4 layer. My proxy service runs in the loopback(127.0.0.1:9999), and test udp server runs in 127.0.0.1:9870. I replaced the src ip and port of inbound packet from my local proxy address(127.0.0.1:9870) to the original request address(127.0.0.1:9999), it failed with STATUS_DATA_NOT_ACCEPTED in the completion of FwpsInjectTransportReceiveAsync. I have tested the ddproxy sample provided by microsoft and configured proxy address like 127.0.0.1:9999, it also returns the same error code.

Is it possible to modify the loopback inbound udp packet in FWPM_LAYER_DATAGRAM_DATA_V4? If not, how can I modify it?

My test callout code is something like:

NTSTATUS status;
UINT32 RemoteAddress = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_ADDRESS].value.uint32;
UINT16 RemotePort = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_IP_REMOTE_PORT].value.uint16;
IF_INDEX InterfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_INTERFACE_INDEX].value.uint32;
IF_INDEX SubInterfaceIndex = inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_SUB_INTERFACE_INDEX].value.uint32;
FWP_DIRECTION Direction = (FWP_DIRECTION)inFixedValues->incomingValue[FWPS_FIELD_DATAGRAM_DATA_V4_DIRECTION].value.uint32;
UINT16 ConnectProtocol = inFixedValues->incomingValue[FWPS_FIELD_ALE_CONNECT_REDIRECT_V4_IP_PROTOCOL].value.uint8;

FWPS_PACKET_INJECTION_STATE PacketInjectionState = FwpsQueryPacketInjectionState0(InjectHandle, (const NET_BUFFER_LIST*)layerData, NULL);

if (ConnectProtocol == 0x06)
    return;
if ((Direction == FWP_DIRECTION_INBOUND) && (PacketInjectionState == FWPS_PACKET_NOT_INJECTED) && RemotePort == 9870)
{
    auto remoteaddr = *reinterpret_cast<IN_ADDR*>(&RemoteAddress);
    DbgPrint("udp inbound, %d.%d.%d.%d:%hu\n",
        FORMAT_ADDR4(remoteaddr), RemotePort);

    UINT32 IpHeaderSize = inMetaValues->ipHeaderSize;
    UINT32 TransportHeaderSize = inMetaValues->transportHeaderSize;
    PNET_BUFFER_LIST NetBufferList = NULL;
    PNET_BUFFER NetBuffer = NET_BUFFER_LIST_FIRST_NB((PNET_BUFFER_LIST)layerData);
    NDIS_STATUS ndisStatus = NdisRetreatNetBufferDataStart(NetBuffer, IpHeaderSize + TransportHeaderSize, 0, NULL);
    if (ndisStatus != NDIS_STATUS_SUCCESS)
        DbgPrint("get net buffer data failed: %x\n", ndisStatus);
    NTSTATUS Status = FwpsAllocateCloneNetBufferList((PNET_BUFFER_LIST)layerData, NULL, NULL, 0, &NetBufferList);
    if (!NT_SUCCESS(Status))
    {
        DbgPrint("FwpsAllocateCloneNetBufferList() Status=%!STATUS!\n", Status);
    }
    if (!NetBufferList)
    {
        DbgPrint("NetBufferList empty\n");
        return;
    }
    NdisAdvanceNetBufferDataStart(NetBuffer, IpHeaderSize + TransportHeaderSize, FALSE, NULL);
    NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
    NdisAdvanceNetBufferDataStart(NetBuffer, IpHeaderSize, FALSE, NULL);
    UDP_HEADER* udpHeader = (UDP_HEADER*)NdisGetDataBuffer(NetBuffer, sizeof(UDP_HEADER), NULL, sizeof(UINT16), 0);
    if (!udpHeader)
    {
        return;
    }
    udpHeader->srcPort = RtlUshortByteSwap(9999);
    udpHeader->checksum = 0;

    //
    // Undo the advance. Net buffer list needs to be positioned at the 
    // beginning of IP header for address modification and/or receive-
    // injection.
    //
    ndisStatus = NdisRetreatNetBufferDataStart(
        NetBuffer,
        IpHeaderSize,
        0,
        NULL
    );

    FWP_BYTE_ARRAY16 tep;
    IN_ADDR RedirectAddress{ 0 };
    RedirectAddress.S_un.S_addr = IPADDRESS_TO_KERNEL(MAKE_IPADDRESS_V4(127, 0, 0, 1));
    status = FwpsConstructIpHeaderForTransportPacket(
        NetBufferList,
        IpHeaderSize,
        AF_INET,
        (const UCHAR*)&RedirectAddress,
        // This is our new source address --
        // or the destination address of the
        // original outbound traffic.
        (UINT8*)&tep,
        // This is the destination address of
        // the clone -- or the source of the
        // original outbound traffic.
        IPPROTO_UDP,
        0,
        NULL,
        0,
        0,
        NULL,
        0,
        0
    );
    if (!NT_SUCCESS(Status))
    {
        DbgPrint("FwpsConstructIpHeaderForTransportPacket() Status=%!STATUS!\n", Status);
        FwpsFreeCloneNetBufferList(NetBufferList, 0);
        return;
    }
    Status = FwpsInjectTransportReceiveAsync(InjectHandle, NULL, NULL, 0, AF_INET, (COMPARTMENT_ID)inMetaValues->compartmentId, InterfaceIndex, SubInterfaceIndex, NetBufferList, DriverDatagramDataInjectComplete, NULL);
    if (!NT_SUCCESS(Status))
    {
        DbgPrint("FwpsInjectTransportReceiveAsync() Status=%!STATUS!\n", Status);
        FwpsFreeCloneNetBufferList(NetBufferList, 0);
        return;
    }

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

}

Any helpful reply would be appreciated!

6
  • Your code doesn't make sense to me. Let's assume some process is making a DNS request over UDP to 8.8.8.8:53. In your connect redirect callout you redirect it to 127.0.0.1:9999. Your proxy receives the request and sends a reply. Your datagram data callout will give you the source as 127.0.0.1:9999 and the destination as 127.0.0.1:random. You want to modify the packet in two ways: 1) change the source port to 53 and 2) change the source address to 8.8.8.8. You seem to be doing the opposite in your code: changing the source port to 9999 and the source address to 127.0.0.1. Commented Oct 15 at 8:08
  • Also your target address is uninitialized so it's probably got garbage data. Commented Oct 15 at 8:12
  • Also, I'm not sure this approach even makes sense. When you redirect a connection it's "sticky"; you don't need to modify the inbound source address since the packet will be delivered to the originating socket. If you are not doing redirection then you can achieve similar behavior by modifying outbound target address and inbound source address. It's been a while since I've worked with WFP so I may not remember all the details. Commented Oct 15 at 8:30
  • The difference is that connect redirect is visible to the process whereas modifying address at inbound/outbound is not. Commented Oct 15 at 8:37
  • Thanks for your reply Luke. I'm writing a local proxy which tranparent to application. Both my proxy service(127.0.0.1:9870) and the test udp server(127.0.0.1:9999) are in localhost. When my proxy(127.0.0.1:9870) forward reply from server(127.0.0.1:9999) to client (127.0.0.1:12345) , I caputure this packet in driver and modify the src port, so that my test udp client can see the recvfrom() func return with the correct original udp server address(127.0.0.1:9999). Now I can't modify the src port, so my client revc the reply and recvfrom() return with(127.0.0.1:9870). Commented Oct 15 at 9:15

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.