I?ve implemented a network packet inspection driver using the Windows
Filtering Platform (WFP).
Within this framework, I run into a problem whenever I attempt to
receive-inject out-of-band UDP data on Win7 at the transport layer. When
the original UDP/IP packets’ source and destination are both the loopback
IP ( i.e. 127.0.0.1), I get a STATUS_DATA_NOT_ACCEPTED in my completion
routine.
If I swap out both the source and destination IPs with my (one and only)
NIC?s IP (using a call to FwpsConstructIpHeaderForTransportPacket() before
invoking FwpsInjectTransportReceiveAsync()), I find my reinjected packet at
the INBOUND_IPPACKET_DISCARD layer with reason IpDiscardNotLocallyDestined.
If I swap only the destination IP with my NIC?s IP, the
FwpsConstructIpHeaderForTransportPacket() returns
STATUS_NETWORK_UNREACHABLE.
If I swap only the source IP with my NIC?s IP, the packet arrives at the
INBOUND_IPPACKET layer and is then swallowed by the system. It does not
show up at either the INBOUND_TRANSPORT, INBOUND_IPPACKET_DISCARD or
INBOUND_TRANSPORT_DISCARD layers.
What gives? This is perplexing because this re-injection scenario and all
else works just fine if either the source or destination IP addresses are
not localhost related.
Following is my current packet packet re-injection code. What can I change
for WFP or the TCP/IP stack to accept my reinjected ‘localhost’ packets?
NTSTATUS
CloneReinjectTransportInbound(
In PendedPacket* packet
)
{
NTSTATUS status;
NET_BUFFER_LIST* clonedNetBufferList = NULL;
NET_BUFFER* netBuffer;
LONG dataOffset;
UINT32 transportHeaderSize;
NDIS_STATUS ndisStatus;
// For inbound net buffer list, we can assume it contains only one net
buffer.
netBuffer = NET_BUFFER_LIST_FIRST_NB(packet->NetBufferList);
NT_ASSERT(NULL != netBuffer);
dataOffset = NET_BUFFER_DATA_OFFSET(netBuffer);
// According to MS: The TCP/IP stack could have retreated the net
buffer list by the
// ‘transport header size’ amount; detect the condition here to avoid
retreating twice.
transportHeaderSize = packet->TransportHeaderSize;
if (dataOffset != packet->DataOffset) {
transportHeaderSize = 0;
}
// Adjust the net buffer list offset to the start of the IP header.
ndisStatus = NdisRetreatNetBufferDataStart(
netBuffer, packet->IpHeaderSize + transportHeaderSize, 0, NULL);
#if (_MSC_VER >= 1700)
Analysis_assume(ndisStatus == NDIS_STATUS_SUCCESS);
#endif
status = FwpsAllocateCloneNetBufferList(
packet->NetBufferList, NULL, NULL, 0, &clonedNetBufferList);
// Undo the adjustment on the original net buffer list.
NdisAdvanceNetBufferDataStart(
netBuffer, packet->IpHeaderSize + transportHeaderSize, FALSE, NULL);
if (!NT_SUCCESS(status)) {
goto Exit;
}
// Special handling for loopback traffic.
if (0x7F == (packet->LocalAddr & 0xFF) && (0x7f == (packet->RemoteAddr
& 0xFF))) {
// Hard coded NIC for now.
UINT32 nicIp = 0xA877A8C0; // 192.168.119.168
status = FwpsConstructIpHeaderForTransportPacket(
clonedNetBufferList,
packet->IpHeaderSize,
AF_INET,
(UINT8*)&nicIp,
(UINT8*)&nicIp,
IPPROTO_UDP,
packet->EndpointHandle,
NULL,
0,
0,
NULL,
packet->InterfaceIndex,
packet->SubInterfaceIndex);
if (!NT_SUCCESS(status)) {
goto Exit;
}
// Send-inject the cloned net buffer list.
status = FwpsInjectTransportSendAsync(
gDriver->InjectionHandle,
NULL,
packet->EndpointHandle,
0,
NULL,
AF_INET,
packet->CompartmentId,
clonedNetBufferList,
InjectTransportComplete,
packet);
if (!NT_SUCCESS(status)) {
goto Exit;
}
} else {
status = FwpsInjectTransportReceiveAsync(
gDriver->InjectionHandle,
NULL,
NULL,
0,
AF_INET,
packet->CompartmentId,
packet->InterfaceIndex,
packet->SubInterfaceIndex,
clonedNetBufferList,
InjectTransportComplete,
packet);
if (!NT_SUCCESS(status)) {
goto Exit;
}
}
// Ownership transferred to the completion function.
clonedNetBufferList = NULL;
packet = NULL;
Exit:
if (clonedNetBufferList != NULL) {
FwpsFreeCloneNetBufferList(clonedNetBufferList, 0);
}
if (packet != NULL) {
FreePendedPacket(packet);
}
return status;
}
Thanks a lot for your help and patience!