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!