|
|
|
@@ -242,8 +242,9 @@ struct packet_s
|
|
|
|
|
UINT32 ip_checksum:1; // Packet has IPv4 checksum?
|
|
|
|
|
UINT32 tcp_checksum:1; // Packet has TCP checksum?
|
|
|
|
|
UINT32 udp_checksum:1; // Packet has UDP checksum?
|
|
|
|
|
UINT32 icmp_checksum:1; // Packet has ICMP(V6) checksum?
|
|
|
|
|
UINT32 match:1; // Packet matches filter?
|
|
|
|
|
UINT32 padding:7; // Padding for alignment.
|
|
|
|
|
UINT32 padding:6; // Padding for alignment.
|
|
|
|
|
UINT32 packet_size; // Packet total size.
|
|
|
|
|
PVOID object; // Object associated with packet.
|
|
|
|
|
UINT32 priority; // Packet priority.
|
|
|
|
@@ -273,6 +274,8 @@ struct flow_s
|
|
|
|
|
UINT64 flow_id; // WFP flow ID.
|
|
|
|
|
UINT32 callout_id; // WFP callout ID.
|
|
|
|
|
UINT16 layer_id; // WFP layout ID.
|
|
|
|
|
BOOL inserted:1; // Flow inserted into context?
|
|
|
|
|
BOOL deleted:1; // Flow deleted from context?
|
|
|
|
|
BOOL outbound:1; // Flow is outound?
|
|
|
|
|
BOOL loopback:1; // Flow is loopback?
|
|
|
|
|
BOOL ipv6:1; // Flow is ipv6?
|
|
|
|
@@ -345,8 +348,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
|
|
|
|
|
req_context_t req_context);
|
|
|
|
|
static void NTAPI windivert_inject_complete(VOID *context,
|
|
|
|
|
NET_BUFFER_LIST *packets, BOOLEAN dispatch_level);
|
|
|
|
|
static void NTAPI windivert_reinject_complete(VOID *context,
|
|
|
|
|
NET_BUFFER_LIST *packets, BOOLEAN dispatch_level);
|
|
|
|
|
static void windivert_inject_packet_too_big(packet_t packet);
|
|
|
|
|
static NTSTATUS windivert_notify(IN FWPS_CALLOUT_NOTIFY_TYPE type,
|
|
|
|
|
IN const GUID *filter_key, IN const FWPS_FILTER0 *filter);
|
|
|
|
|
static void windivert_outbound_network_v4_classify(
|
|
|
|
@@ -467,7 +469,7 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
|
|
|
|
|
UINT64 flags, UINT32 priority, BOOL ipv4, BOOL outbound, BOOL loopback,
|
|
|
|
|
BOOL impostor, BOOL match, LONGLONG timestamp);
|
|
|
|
|
static void windivert_queue_packet(context_t context, packet_t packet);
|
|
|
|
|
static void windivert_reinject_packet(packet_t packet);
|
|
|
|
|
static NTSTATUS windivert_inject_packet(packet_t packet);
|
|
|
|
|
static void windivert_free_packet(packet_t packet);
|
|
|
|
|
static BOOL windivert_copy_data(PNET_BUFFER buffer, PVOID data, UINT size);
|
|
|
|
|
static BOOL windivert_get_data(PNET_BUFFER buffer, UINT length, INT min,
|
|
|
|
@@ -1979,20 +1981,17 @@ windivert_cleanup_error:
|
|
|
|
|
context->state = WINDIVERT_CONTEXT_STATE_CLOSING;
|
|
|
|
|
sniff_mode = ((context->flags & WINDIVERT_FLAG_SNIFF) != 0);
|
|
|
|
|
forward = (context->layer == WINDIVERT_LAYER_NETWORK_FORWARD);
|
|
|
|
|
entry = context->flow_set.Flink;
|
|
|
|
|
if (entry != &context->flow_set)
|
|
|
|
|
while (!IsListEmpty(&context->flow_set))
|
|
|
|
|
{
|
|
|
|
|
entry = RemoveHeadList(&context->flow_set);
|
|
|
|
|
flow = CONTAINING_RECORD(entry, struct flow_s, entry);
|
|
|
|
|
flow->deleted = TRUE;
|
|
|
|
|
KeReleaseInStackQueuedSpinLock(&lock_handle);
|
|
|
|
|
for (; entry != &context->flow_set; entry = entry->Flink)
|
|
|
|
|
status = FwpsFlowRemoveContext0(flow->flow_id, flow->layer_id,
|
|
|
|
|
flow->callout_id);
|
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
flow = CONTAINING_RECORD(entry, struct flow_s, entry);
|
|
|
|
|
status = FwpsFlowRemoveContext0(flow->flow_id, flow->layer_id,
|
|
|
|
|
flow->callout_id);
|
|
|
|
|
if (!NT_SUCCESS(status) && status != STATUS_UNSUCCESSFUL)
|
|
|
|
|
{
|
|
|
|
|
// For STATUS_UNSUCCESSFUL, flow_delete() is still called.
|
|
|
|
|
WdfObjectDereference((WDFOBJECT)object);
|
|
|
|
|
}
|
|
|
|
|
windivert_free(flow);
|
|
|
|
|
}
|
|
|
|
|
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
|
|
|
|
|
}
|
|
|
|
@@ -2006,7 +2005,7 @@ windivert_cleanup_error:
|
|
|
|
|
timeout = WINDIVERT_TIMEOUT(context, packet->timestamp, timestamp);
|
|
|
|
|
if (!sniff_mode && !timeout)
|
|
|
|
|
{
|
|
|
|
|
windivert_reinject_packet(packet);
|
|
|
|
|
windivert_inject_packet(packet);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@@ -2028,7 +2027,7 @@ windivert_cleanup_error:
|
|
|
|
|
timeout = WINDIVERT_TIMEOUT(context, work->timestamp, timestamp);
|
|
|
|
|
if (!sniff_mode && !timeout)
|
|
|
|
|
{
|
|
|
|
|
windivert_reinject_packet(work);
|
|
|
|
|
windivert_inject_packet(work);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@@ -2087,8 +2086,6 @@ extern VOID windivert_destroy(IN WDFOBJECT object)
|
|
|
|
|
KLOCK_QUEUE_HANDLE lock_handle;
|
|
|
|
|
context_t context = windivert_context_get((WDFFILEOBJECT)object);
|
|
|
|
|
const WINDIVERT_FILTER *filter;
|
|
|
|
|
PLIST_ENTRY entry;
|
|
|
|
|
flow_t flow;
|
|
|
|
|
NTSTATUS status;
|
|
|
|
|
|
|
|
|
|
DEBUG("DESTROY: destroying WinDivert context (context=%p)", context);
|
|
|
|
@@ -2109,12 +2106,6 @@ extern VOID windivert_destroy(IN WDFOBJECT object)
|
|
|
|
|
FwpmEngineClose0(context->engine_handle);
|
|
|
|
|
}
|
|
|
|
|
windivert_free((PVOID)filter);
|
|
|
|
|
while (!IsListEmpty(&context->flow_set))
|
|
|
|
|
{
|
|
|
|
|
entry = RemoveHeadList(&context->flow_set);
|
|
|
|
|
flow = CONTAINING_RECORD(entry, struct flow_s, entry);
|
|
|
|
|
windivert_free(flow);
|
|
|
|
|
}
|
|
|
|
|
if (context->process != NULL)
|
|
|
|
|
{
|
|
|
|
|
ObDereferenceObject(context->process);
|
|
|
|
@@ -2599,19 +2590,20 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
|
|
|
|
|
req_context_t req_context)
|
|
|
|
|
{
|
|
|
|
|
KLOCK_QUEUE_HANDLE lock_handle;
|
|
|
|
|
PMDL mdl = NULL, mdl_copy = NULL;
|
|
|
|
|
PVOID data, data_copy = NULL;
|
|
|
|
|
UINT data_len, packet_len, inject_len;
|
|
|
|
|
PMDL mdl = NULL;
|
|
|
|
|
PVOID data, data_copy;
|
|
|
|
|
packet_t packet;
|
|
|
|
|
UINT data_len, packet_len, packet_size, inject_len;
|
|
|
|
|
PWINDIVERT_DATA_NETWORK network_data;
|
|
|
|
|
PWINDIVERT_IPHDR ip_header;
|
|
|
|
|
PWINDIVERT_IPV6HDR ipv6_header;
|
|
|
|
|
BOOL ipv4;
|
|
|
|
|
UINT8 layer;
|
|
|
|
|
UINT32 priority;
|
|
|
|
|
UINT64 flags, checksums;
|
|
|
|
|
HANDLE handle;
|
|
|
|
|
PNET_BUFFER_LIST buffers = NULL;
|
|
|
|
|
PWINDIVERT_ADDRESS addr;
|
|
|
|
|
UINT i, addr_len, addr_len_max;
|
|
|
|
|
UINT i, addr_len, addr_len_max, version;
|
|
|
|
|
NTSTATUS status = STATUS_SUCCESS, status_soft_error = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
|
|
DEBUG("WRITE: writing/injecting a packet (context=%p, request=%p)",
|
|
|
|
@@ -2680,10 +2672,6 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
|
|
|
|
|
i < WINDIVERT_BATCH_MAX;
|
|
|
|
|
i++, addr_len += sizeof(WINDIVERT_ADDRESS))
|
|
|
|
|
{
|
|
|
|
|
buffers = NULL;
|
|
|
|
|
mdl_copy = NULL;
|
|
|
|
|
data_copy = NULL;
|
|
|
|
|
|
|
|
|
|
// Get the packet length:
|
|
|
|
|
if (data_len < sizeof(WINDIVERT_IPHDR))
|
|
|
|
|
{
|
|
|
|
@@ -2693,11 +2681,15 @@ windivert_write_too_small_packet:
|
|
|
|
|
goto windivert_write_hard_error;
|
|
|
|
|
}
|
|
|
|
|
ip_header = (PWINDIVERT_IPHDR)data;
|
|
|
|
|
switch (ip_header->Version)
|
|
|
|
|
version = ip_header->Version;
|
|
|
|
|
switch (version)
|
|
|
|
|
{
|
|
|
|
|
case 4:
|
|
|
|
|
packet_len = RtlUshortByteSwap(ip_header->Length);
|
|
|
|
|
ipv4 = TRUE;
|
|
|
|
|
if (packet_len < sizeof(WINDIVERT_IPHDR))
|
|
|
|
|
{
|
|
|
|
|
goto windivert_write_invalid_packet;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 6:
|
|
|
|
|
if (data_len < sizeof(WINDIVERT_IPV6HDR))
|
|
|
|
@@ -2707,11 +2699,11 @@ windivert_write_too_small_packet:
|
|
|
|
|
ipv6_header = (PWINDIVERT_IPV6HDR)data;
|
|
|
|
|
packet_len = RtlUshortByteSwap(ipv6_header->Length) +
|
|
|
|
|
sizeof(WINDIVERT_IPV6HDR);
|
|
|
|
|
ipv4 = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
windivert_write_invalid_packet:
|
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
|
DEBUG_ERROR("failed to inject non-IP packet", status);
|
|
|
|
|
DEBUG_ERROR("failed to inject invalid packet", status);
|
|
|
|
|
goto windivert_write_hard_error;
|
|
|
|
|
}
|
|
|
|
|
if (data_len < packet_len)
|
|
|
|
@@ -2719,100 +2711,77 @@ windivert_write_too_small_packet:
|
|
|
|
|
goto windivert_write_too_small_packet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy packet data:
|
|
|
|
|
data_copy = windivert_malloc(packet_len, FALSE);
|
|
|
|
|
if (data_copy == NULL)
|
|
|
|
|
// Copy packet & data:
|
|
|
|
|
packet_size = WINDIVERT_PACKET_SIZE(WINDIVERT_DATA_NETWORK,
|
|
|
|
|
packet_len);
|
|
|
|
|
packet = (packet_t)windivert_malloc(packet_size, FALSE);
|
|
|
|
|
if (packet == NULL)
|
|
|
|
|
{
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
DEBUG_ERROR("failed to allocate memory for injected packet data",
|
|
|
|
|
DEBUG_ERROR("failed to allocate memory for injected packet",
|
|
|
|
|
status);
|
|
|
|
|
goto windivert_write_hard_error;
|
|
|
|
|
}
|
|
|
|
|
packet->layer = layer;
|
|
|
|
|
packet->event = WINDIVERT_EVENT_NETWORK_PACKET;
|
|
|
|
|
packet->sniffed = 0; // Unused
|
|
|
|
|
packet->outbound = addr[i].Outbound;
|
|
|
|
|
packet->loopback = 0; // Unused
|
|
|
|
|
packet->impostor = addr[i].Impostor;
|
|
|
|
|
packet->ipv6 = (version == 6? 1: 0);
|
|
|
|
|
packet->ip_checksum = addr[i].IPChecksum;
|
|
|
|
|
packet->tcp_checksum = addr[i].TCPChecksum;
|
|
|
|
|
packet->udp_checksum = addr[i].UDPChecksum;
|
|
|
|
|
packet->icmp_checksum = 1; // Assumed valid
|
|
|
|
|
packet->match = 0; // Unused
|
|
|
|
|
packet->packet_size = packet_size;
|
|
|
|
|
packet->packet_len = packet_len;
|
|
|
|
|
packet->priority = priority;
|
|
|
|
|
packet->timestamp = 0; // Unused
|
|
|
|
|
packet->object = NULL;
|
|
|
|
|
network_data =
|
|
|
|
|
(PWINDIVERT_DATA_NETWORK)WINDIVERT_LAYER_DATA_PTR(packet);
|
|
|
|
|
RtlCopyMemory(network_data, &addr[i].Network, sizeof(network_data));
|
|
|
|
|
data_copy = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_NETWORK, packet);
|
|
|
|
|
RtlCopyMemory(data_copy, data, packet_len);
|
|
|
|
|
switch (version)
|
|
|
|
|
{
|
|
|
|
|
case 4:
|
|
|
|
|
ip_header = (PWINDIVERT_IPHDR)data_copy;
|
|
|
|
|
if (ip_header->Version != 4 ||
|
|
|
|
|
packet_len != RtlUshortByteSwap(ip_header->Length))
|
|
|
|
|
{
|
|
|
|
|
windivert_free(packet);
|
|
|
|
|
goto windivert_write_invalid_packet;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 6:
|
|
|
|
|
ipv6_header = (PWINDIVERT_IPV6HDR)data_copy;
|
|
|
|
|
if (ipv6_header->Version != 6 ||
|
|
|
|
|
packet_len != RtlUshortByteSwap(ipv6_header->Length) +
|
|
|
|
|
sizeof(WINDIVERT_IPV6HDR))
|
|
|
|
|
{
|
|
|
|
|
windivert_free(packet);
|
|
|
|
|
goto windivert_write_invalid_packet;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check bounds:
|
|
|
|
|
DEBUG_BOUNDS_CHECK((PVOID)addr, (UINT8 *)addr + addr_len_max,
|
|
|
|
|
(PVOID)&addr[i], (PVOID)&addr[i+1]);
|
|
|
|
|
|
|
|
|
|
// Fix checksums:
|
|
|
|
|
if (addr[i].IPChecksum == 0 || addr[i].TCPChecksum == 0 ||
|
|
|
|
|
addr[i].UDPChecksum == 0)
|
|
|
|
|
{
|
|
|
|
|
checksums =
|
|
|
|
|
(addr[i].IPChecksum == 0? 0:
|
|
|
|
|
WINDIVERT_HELPER_NO_IP_CHECKSUM) |
|
|
|
|
|
(addr[i].TCPChecksum == 0? 0:
|
|
|
|
|
WINDIVERT_HELPER_NO_TCP_CHECKSUM) |
|
|
|
|
|
(addr[i].UDPChecksum == 0? 0:
|
|
|
|
|
WINDIVERT_HELPER_NO_UDP_CHECKSUM) |
|
|
|
|
|
WINDIVERT_HELPER_NO_ICMP_CHECKSUM |
|
|
|
|
|
WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM;
|
|
|
|
|
WinDivertHelperCalcChecksums(data_copy, packet_len, NULL,
|
|
|
|
|
checksums);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Decrement TTL for impostor packets:
|
|
|
|
|
if (addr[i].Impostor &&
|
|
|
|
|
!WinDivertHelperDecrementTTL(data_copy, packet_len))
|
|
|
|
|
{
|
|
|
|
|
status_soft_error = STATUS_HOPLIMIT_EXCEEDED;
|
|
|
|
|
windivert_free(data_copy);
|
|
|
|
|
goto windivert_write_loop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allocate packet:
|
|
|
|
|
mdl_copy = IoAllocateMdl(data_copy, packet_len, FALSE, FALSE, NULL);
|
|
|
|
|
if (mdl_copy == NULL)
|
|
|
|
|
{
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
DEBUG_ERROR("failed to allocate MDL for injected packet", status);
|
|
|
|
|
goto windivert_write_hard_error;
|
|
|
|
|
}
|
|
|
|
|
MmBuildMdlForNonPagedPool(mdl_copy);
|
|
|
|
|
status = FwpsAllocateNetBufferAndNetBufferList0(nbl_pool_handle, 0, 0,
|
|
|
|
|
mdl_copy, 0, packet_len, &buffers);
|
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
DEBUG_ERROR("failed to create NET_BUFFER_LIST for injected packet",
|
|
|
|
|
status);
|
|
|
|
|
goto windivert_write_hard_error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Inject packet:
|
|
|
|
|
if (layer == WINDIVERT_LAYER_NETWORK_FORWARD)
|
|
|
|
|
{
|
|
|
|
|
handle = (ipv4? inject_handle_forward: injectv6_handle_forward);
|
|
|
|
|
status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0,
|
|
|
|
|
(ipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID,
|
|
|
|
|
addr[i].Network.IfIdx, buffers, windivert_inject_complete,
|
|
|
|
|
data_copy);
|
|
|
|
|
}
|
|
|
|
|
else if (addr[i].Outbound != 0)
|
|
|
|
|
{
|
|
|
|
|
handle = (ipv4? inject_handle_out: injectv6_handle_out);
|
|
|
|
|
status = FwpsInjectNetworkSendAsync0(handle, (HANDLE)priority, 0,
|
|
|
|
|
UNSPECIFIED_COMPARTMENT_ID, buffers, windivert_inject_complete,
|
|
|
|
|
data_copy);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
handle = (ipv4? inject_handle_in: injectv6_handle_in);
|
|
|
|
|
status = FwpsInjectNetworkReceiveAsync0(handle, (HANDLE)priority, 0,
|
|
|
|
|
UNSPECIFIED_COMPARTMENT_ID, addr[i].Network.IfIdx,
|
|
|
|
|
addr[i].Network.SubIfIdx, buffers, windivert_inject_complete,
|
|
|
|
|
data_copy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status = windivert_inject_packet(packet);
|
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
if (status == STATUS_INSUFFICIENT_RESOURCES)
|
|
|
|
|
{
|
|
|
|
|
goto windivert_write_hard_error;
|
|
|
|
|
}
|
|
|
|
|
status_soft_error = status;
|
|
|
|
|
FwpsFreeNetBufferList0(buffers);
|
|
|
|
|
IoFreeMdl(mdl_copy);
|
|
|
|
|
windivert_free(data_copy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
windivert_write_loop:
|
|
|
|
|
|
|
|
|
|
// Reset state:
|
|
|
|
|
inject_len += packet_len;
|
|
|
|
|
data = (PVOID)((UINT8 *)data + packet_len);
|
|
|
|
@@ -2827,54 +2796,9 @@ windivert_write_loop:
|
|
|
|
|
windivert_write_hard_error:
|
|
|
|
|
|
|
|
|
|
// Request to be completed in windivert_ioctl()
|
|
|
|
|
if (buffers != NULL)
|
|
|
|
|
{
|
|
|
|
|
FwpsFreeNetBufferList0(buffers);
|
|
|
|
|
}
|
|
|
|
|
if (mdl_copy != NULL)
|
|
|
|
|
{
|
|
|
|
|
IoFreeMdl(mdl_copy);
|
|
|
|
|
}
|
|
|
|
|
windivert_free(data_copy);
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* WinDivert inject complete routine.
|
|
|
|
|
*/
|
|
|
|
|
static void NTAPI windivert_inject_complete(VOID *data,
|
|
|
|
|
NET_BUFFER_LIST *buffers, BOOLEAN dispatch_level)
|
|
|
|
|
{
|
|
|
|
|
PMDL mdl;
|
|
|
|
|
PNET_BUFFER buffer;
|
|
|
|
|
UNREFERENCED_PARAMETER(dispatch_level);
|
|
|
|
|
|
|
|
|
|
buffer = NET_BUFFER_LIST_FIRST_NB(buffers);
|
|
|
|
|
mdl = NET_BUFFER_FIRST_MDL(buffer);
|
|
|
|
|
windivert_free(data);
|
|
|
|
|
IoFreeMdl(mdl);
|
|
|
|
|
FwpsFreeNetBufferList0(buffers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* WinDivert reinject complete routine.
|
|
|
|
|
*/
|
|
|
|
|
static void NTAPI windivert_reinject_complete(VOID *context,
|
|
|
|
|
NET_BUFFER_LIST *buffers, BOOLEAN dispatch_level)
|
|
|
|
|
{
|
|
|
|
|
PMDL mdl;
|
|
|
|
|
PNET_BUFFER buffer;
|
|
|
|
|
packet_t packet;
|
|
|
|
|
UNREFERENCED_PARAMETER(dispatch_level);
|
|
|
|
|
|
|
|
|
|
buffer = NET_BUFFER_LIST_FIRST_NB(buffers);
|
|
|
|
|
packet = (packet_t)context;
|
|
|
|
|
mdl = NET_BUFFER_FIRST_MDL(buffer);
|
|
|
|
|
windivert_free_packet(packet);
|
|
|
|
|
IoFreeMdl(mdl);
|
|
|
|
|
FwpsFreeNetBufferList0(buffers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* WinDivert caller context preprocessing.
|
|
|
|
@@ -4188,11 +4112,22 @@ static void windivert_flow_established_classify(context_t context,
|
|
|
|
|
flow->flow_id = flow_id;
|
|
|
|
|
flow->callout_id = callout_id;
|
|
|
|
|
flow->layer_id = layer_id;
|
|
|
|
|
flow->inserted = FALSE;
|
|
|
|
|
flow->deleted = FALSE;
|
|
|
|
|
flow->outbound = outbound;
|
|
|
|
|
flow->loopback = loopback;
|
|
|
|
|
flow->ipv6 = !ipv4;
|
|
|
|
|
RtlCopyMemory(&flow->data, flow_data, sizeof(flow->data));
|
|
|
|
|
|
|
|
|
|
status = FwpsFlowAssociateContext0(flow_id, layer_id, callout_id,
|
|
|
|
|
(UINT64)flow);
|
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
windivert_free(flow);
|
|
|
|
|
WdfObjectDereference(object);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
|
|
|
|
|
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
|
|
|
|
|
context->shutdown_recv)
|
|
|
|
@@ -4202,16 +4137,19 @@ static void windivert_flow_established_classify(context_t context,
|
|
|
|
|
WdfObjectDereference(object);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
status = FwpsFlowAssociateContext0(flow_id, layer_id, callout_id,
|
|
|
|
|
(UINT64)flow);
|
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
|
if (!flow->deleted)
|
|
|
|
|
{
|
|
|
|
|
InsertTailList(&context->flow_set, &flow->entry);
|
|
|
|
|
flow->inserted = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Flow was deleted before insertion; we are responsible for cleanup.
|
|
|
|
|
KeReleaseInStackQueuedSpinLock(&lock_handle);
|
|
|
|
|
windivert_free(flow);
|
|
|
|
|
WdfObjectDereference(object);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
InsertTailList(&context->flow_set, &flow->entry);
|
|
|
|
|
KeReleaseInStackQueuedSpinLock(&lock_handle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -4238,16 +4176,18 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
|
|
|
|
|
context = flow->context;
|
|
|
|
|
|
|
|
|
|
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
|
|
|
|
|
object = (WDFOBJECT)context->object; // referenced in flow_established.
|
|
|
|
|
cleanup = (context->state == WINDIVERT_CONTEXT_STATE_OPEN);
|
|
|
|
|
if (cleanup)
|
|
|
|
|
if (flow->inserted && !flow->deleted)
|
|
|
|
|
{
|
|
|
|
|
RemoveEntryList(&flow->entry);
|
|
|
|
|
}
|
|
|
|
|
flow->deleted = TRUE;
|
|
|
|
|
cleanup = flow->inserted;
|
|
|
|
|
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
|
|
|
|
|
context->shutdown_recv)
|
|
|
|
|
{
|
|
|
|
@@ -4272,12 +4212,12 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
windivert_flow_delete_notify_exit:
|
|
|
|
|
|
|
|
|
|
if (cleanup)
|
|
|
|
|
{
|
|
|
|
|
// If context->state != OPEN, then destroy() will free the flow.
|
|
|
|
|
windivert_free(flow);
|
|
|
|
|
WdfObjectDereference(object);
|
|
|
|
|
}
|
|
|
|
|
WdfObjectDereference(object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -4904,7 +4844,7 @@ VOID windivert_worker(IN WDFWORKITEM item)
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
windivert_reinject_packet(work);
|
|
|
|
|
windivert_inject_packet(work);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
|
|
|
|
@@ -5065,21 +5005,22 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
work->layer = layer;
|
|
|
|
|
work->event = event;
|
|
|
|
|
work->sniffed = (sniffed? 1: 0);
|
|
|
|
|
work->outbound = (outbound? 1: 0);
|
|
|
|
|
work->loopback = (loopback? 1: 0);
|
|
|
|
|
work->impostor = (impostor? 1: 0);
|
|
|
|
|
work->ipv6 = (!ipv4? 1: 0);
|
|
|
|
|
work->ip_checksum = (ip_checksum? 1: 0);
|
|
|
|
|
work->tcp_checksum = (tcp_checksum? 1: 0);
|
|
|
|
|
work->udp_checksum = (udp_checksum? 1: 0);
|
|
|
|
|
work->match = match;
|
|
|
|
|
work->packet_size = packet_size;
|
|
|
|
|
work->priority = priority;
|
|
|
|
|
work->timestamp = timestamp;
|
|
|
|
|
work->object = object;
|
|
|
|
|
work->layer = layer;
|
|
|
|
|
work->event = event;
|
|
|
|
|
work->sniffed = (sniffed? 1: 0);
|
|
|
|
|
work->outbound = (outbound? 1: 0);
|
|
|
|
|
work->loopback = (loopback? 1: 0);
|
|
|
|
|
work->impostor = (impostor? 1: 0);
|
|
|
|
|
work->ipv6 = (!ipv4? 1: 0);
|
|
|
|
|
work->ip_checksum = (ip_checksum? 1: 0);
|
|
|
|
|
work->tcp_checksum = (tcp_checksum? 1: 0);
|
|
|
|
|
work->udp_checksum = (udp_checksum? 1: 0);
|
|
|
|
|
work->icmp_checksum = 1;
|
|
|
|
|
work->match = match;
|
|
|
|
|
work->packet_size = packet_size;
|
|
|
|
|
work->priority = priority;
|
|
|
|
|
work->timestamp = timestamp;
|
|
|
|
|
work->object = object;
|
|
|
|
|
if (object != NULL)
|
|
|
|
|
{
|
|
|
|
|
ObfReferenceObject(object);
|
|
|
|
@@ -5141,7 +5082,7 @@ static void windivert_queue_packet(context_t context, packet_t packet)
|
|
|
|
|
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
|
|
|
|
|
{
|
|
|
|
|
KeReleaseInStackQueuedSpinLock(&lock_handle);
|
|
|
|
|
windivert_reinject_packet(packet);
|
|
|
|
|
windivert_inject_packet(packet);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (packet->packet_size > context->packet_queue_maxsize)
|
|
|
|
@@ -5193,9 +5134,9 @@ static void windivert_queue_packet(context_t context, packet_t packet)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Re-inject a packet.
|
|
|
|
|
* Inject a packet.
|
|
|
|
|
*/
|
|
|
|
|
static void windivert_reinject_packet(packet_t packet)
|
|
|
|
|
static NTSTATUS windivert_inject_packet(packet_t packet)
|
|
|
|
|
{
|
|
|
|
|
UINT8 *packet_data;
|
|
|
|
|
UINT32 packet_len;
|
|
|
|
@@ -5211,7 +5152,7 @@ static void windivert_reinject_packet(packet_t packet)
|
|
|
|
|
packet->layer != WINDIVERT_LAYER_NETWORK_FORWARD)
|
|
|
|
|
{
|
|
|
|
|
windivert_free_packet(packet);
|
|
|
|
|
return;
|
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
network_data = (PWINDIVERT_DATA_NETWORK)WINDIVERT_LAYER_DATA_PTR(packet);
|
|
|
|
@@ -5219,47 +5160,43 @@ static void windivert_reinject_packet(packet_t packet)
|
|
|
|
|
packet_len = packet->packet_len;
|
|
|
|
|
|
|
|
|
|
// Fix checksums:
|
|
|
|
|
if (packet->ip_checksum == 0 || packet->tcp_checksum == 0 ||
|
|
|
|
|
packet->udp_checksum == 0)
|
|
|
|
|
{
|
|
|
|
|
checksums =
|
|
|
|
|
(packet->ip_checksum == 0? 0: WINDIVERT_HELPER_NO_IP_CHECKSUM) |
|
|
|
|
|
(packet->tcp_checksum == 0? 0: WINDIVERT_HELPER_NO_TCP_CHECKSUM) |
|
|
|
|
|
(packet->udp_checksum == 0? 0: WINDIVERT_HELPER_NO_UDP_CHECKSUM) |
|
|
|
|
|
WINDIVERT_HELPER_NO_ICMP_CHECKSUM |
|
|
|
|
|
WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM;
|
|
|
|
|
WinDivertHelperCalcChecksums(packet_data, packet_len, NULL, checksums);
|
|
|
|
|
}
|
|
|
|
|
checksums =
|
|
|
|
|
(packet->ip_checksum == 0? 0: WINDIVERT_HELPER_NO_IP_CHECKSUM) |
|
|
|
|
|
(packet->tcp_checksum == 0? 0: WINDIVERT_HELPER_NO_TCP_CHECKSUM) |
|
|
|
|
|
(packet->udp_checksum == 0? 0: WINDIVERT_HELPER_NO_UDP_CHECKSUM) |
|
|
|
|
|
(packet->icmp_checksum == 0? 0: WINDIVERT_HELPER_NO_ICMP_CHECKSUM |
|
|
|
|
|
WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM);
|
|
|
|
|
WinDivertHelperCalcChecksums(packet_data, packet_len, NULL, checksums);
|
|
|
|
|
|
|
|
|
|
// Decrement TTL for impostor packets:
|
|
|
|
|
if (packet->impostor != 0 &&
|
|
|
|
|
!WinDivertHelperDecrementTTL(packet_data, packet_len))
|
|
|
|
|
{
|
|
|
|
|
status = STATUS_HOPLIMIT_EXCEEDED;
|
|
|
|
|
DEBUG_ERROR("failed to reinject ttl-exceeded impostor packet", status);
|
|
|
|
|
DEBUG_ERROR("failed to inject ttl-exceeded impostor packet", status);
|
|
|
|
|
windivert_free_packet(packet);
|
|
|
|
|
return;
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reinject packet:
|
|
|
|
|
// Inject packet:
|
|
|
|
|
mdl = IoAllocateMdl(packet_data, packet_len, FALSE, FALSE, NULL);
|
|
|
|
|
if (mdl == NULL)
|
|
|
|
|
{
|
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
|
DEBUG_ERROR("failed to allocate MDL for reinjected packet", status);
|
|
|
|
|
DEBUG_ERROR("failed to allocate MDL for injected packet", status);
|
|
|
|
|
windivert_free_packet(packet);
|
|
|
|
|
return;
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
MmBuildMdlForNonPagedPool(mdl);
|
|
|
|
|
status = FwpsAllocateNetBufferAndNetBufferList0(nbl_pool_handle, 0, 0,
|
|
|
|
|
mdl, 0, packet_len, &buffers);
|
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
DEBUG_ERROR("failed to create NET_BUFFER_LIST for reinjected packet",
|
|
|
|
|
DEBUG_ERROR("failed to create NET_BUFFER_LIST for injected packet",
|
|
|
|
|
status);
|
|
|
|
|
IoFreeMdl(mdl);
|
|
|
|
|
windivert_free_packet(packet);
|
|
|
|
|
return;
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
priority = packet->priority;
|
|
|
|
|
if (packet->layer == WINDIVERT_LAYER_NETWORK_FORWARD)
|
|
|
|
@@ -5267,14 +5204,14 @@ static void windivert_reinject_packet(packet_t packet)
|
|
|
|
|
handle = (packet->ipv6? injectv6_handle_forward: inject_handle_forward);
|
|
|
|
|
status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0,
|
|
|
|
|
(packet->ipv6? AF_INET6: AF_INET), UNSPECIFIED_COMPARTMENT_ID,
|
|
|
|
|
network_data->IfIdx, buffers, windivert_reinject_complete,
|
|
|
|
|
network_data->IfIdx, buffers, windivert_inject_complete,
|
|
|
|
|
(HANDLE)packet);
|
|
|
|
|
}
|
|
|
|
|
else if (packet->outbound)
|
|
|
|
|
{
|
|
|
|
|
handle = (packet->ipv6? injectv6_handle_out: inject_handle_out);
|
|
|
|
|
status = FwpsInjectNetworkSendAsync0(handle, (HANDLE)priority, 0,
|
|
|
|
|
UNSPECIFIED_COMPARTMENT_ID, buffers, windivert_reinject_complete,
|
|
|
|
|
UNSPECIFIED_COMPARTMENT_ID, buffers, windivert_inject_complete,
|
|
|
|
|
(HANDLE)packet);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@@ -5282,17 +5219,18 @@ static void windivert_reinject_packet(packet_t packet)
|
|
|
|
|
handle = (packet->ipv6? injectv6_handle_in: inject_handle_in);
|
|
|
|
|
status = FwpsInjectNetworkReceiveAsync0(handle, (HANDLE)priority, 0,
|
|
|
|
|
UNSPECIFIED_COMPARTMENT_ID, network_data->IfIdx,
|
|
|
|
|
network_data->SubIfIdx, buffers, windivert_reinject_complete,
|
|
|
|
|
network_data->SubIfIdx, buffers, windivert_inject_complete,
|
|
|
|
|
(HANDLE)packet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(status))
|
|
|
|
|
{
|
|
|
|
|
DEBUG_ERROR("failed to reinject (packet=%p)", status, packet);
|
|
|
|
|
DEBUG_ERROR("failed to inject (packet=%p)", status, packet);
|
|
|
|
|
FwpsFreeNetBufferList0(buffers);
|
|
|
|
|
IoFreeMdl(mdl);
|
|
|
|
|
windivert_free_packet(packet);
|
|
|
|
|
}
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -5307,6 +5245,172 @@ static void windivert_free_packet(packet_t packet)
|
|
|
|
|
windivert_free(packet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* WinDivert inject complete routine.
|
|
|
|
|
*/
|
|
|
|
|
static void NTAPI windivert_inject_complete(VOID *context,
|
|
|
|
|
NET_BUFFER_LIST *buffers, BOOLEAN dispatch_level)
|
|
|
|
|
{
|
|
|
|
|
PMDL mdl;
|
|
|
|
|
PNET_BUFFER buffer;
|
|
|
|
|
packet_t packet;
|
|
|
|
|
UNREFERENCED_PARAMETER(dispatch_level);
|
|
|
|
|
|
|
|
|
|
packet = (packet_t)context;
|
|
|
|
|
if (buffers->Status == STATUS_INVALID_BUFFER_SIZE)
|
|
|
|
|
{
|
|
|
|
|
// STATUS_INVALID_BUFFER_SIZE indicates that the send failed because
|
|
|
|
|
// the packet was larger than the MTU. We generate an ICMP
|
|
|
|
|
// Fragmentation Needed (for IPv4) or an ICMPV6 Packet Too Big (for
|
|
|
|
|
// IPv6) message to allow for PMTU discovery.
|
|
|
|
|
windivert_inject_packet_too_big(packet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer = NET_BUFFER_LIST_FIRST_NB(buffers);
|
|
|
|
|
mdl = NET_BUFFER_FIRST_MDL(buffer);
|
|
|
|
|
IoFreeMdl(mdl);
|
|
|
|
|
FwpsFreeNetBufferList0(buffers);
|
|
|
|
|
windivert_free_packet(packet);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* WinDivert inject an ICMP(V6) Packet Too Big message.
|
|
|
|
|
*/
|
|
|
|
|
static void windivert_inject_packet_too_big(packet_t packet)
|
|
|
|
|
{
|
|
|
|
|
const UINT mtus[] =
|
|
|
|
|
{
|
|
|
|
|
568, 768, 1024, 1192, 1280, 1372, 1452, 1500, 4096, UINT16_MAX,
|
|
|
|
|
UINT32_MAX
|
|
|
|
|
};
|
|
|
|
|
PWINDIVERT_IPHDR ip_header, ip_header_2;
|
|
|
|
|
PWINDIVERT_IPV6HDR ipv6_header, ipv6_header_2;
|
|
|
|
|
PWINDIVERT_ICMPHDR icmp_header;
|
|
|
|
|
PWINDIVERT_ICMPV6HDR icmpv6_header;
|
|
|
|
|
packet_t icmp;
|
|
|
|
|
UINT version, packet_len, copy_len, icmp_len;
|
|
|
|
|
UINT icmp_size;
|
|
|
|
|
UINT i, min_mtu = /*ipv4 min MTU=*/568, mtu;
|
|
|
|
|
UINT32 flowlabel;
|
|
|
|
|
UINT8 *data;
|
|
|
|
|
|
|
|
|
|
if (packet->layer != WINDIVERT_LAYER_NETWORK || !packet->outbound ||
|
|
|
|
|
packet->loopback)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
ip_header = (PWINDIVERT_IPHDR)WINDIVERT_PACKET_DATA_PTR(
|
|
|
|
|
WINDIVERT_DATA_NETWORK, packet);
|
|
|
|
|
version = ip_header->Version;
|
|
|
|
|
switch (version)
|
|
|
|
|
{
|
|
|
|
|
case 4:
|
|
|
|
|
packet_len = RtlUshortByteSwap(ip_header->Length);
|
|
|
|
|
copy_len = ip_header->HdrLength * sizeof(UINT32) + 8;
|
|
|
|
|
copy_len = (packet_len < copy_len? packet_len: copy_len);
|
|
|
|
|
icmp_len = sizeof(WINDIVERT_IPHDR) + sizeof(WINDIVERT_ICMPHDR) +
|
|
|
|
|
copy_len;
|
|
|
|
|
break;
|
|
|
|
|
case 6:
|
|
|
|
|
ipv6_header = (PWINDIVERT_IPV6HDR)ip_header;
|
|
|
|
|
packet_len = RtlUshortByteSwap(ipv6_header->Length) +
|
|
|
|
|
sizeof(WINDIVERT_IPV6HDR);
|
|
|
|
|
min_mtu = /*ipv6 min MTU=*/1280;
|
|
|
|
|
copy_len = min_mtu - sizeof(WINDIVERT_IPV6HDR) -
|
|
|
|
|
sizeof(WINDIVERT_ICMPV6HDR);
|
|
|
|
|
copy_len = (packet_len < copy_len? packet_len: copy_len);
|
|
|
|
|
icmp_len = sizeof(WINDIVERT_IPV6HDR) +
|
|
|
|
|
sizeof(WINDIVERT_ICMPV6HDR) + copy_len;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (packet_len <= min_mtu)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We do not actually know the MTU value, so we make an educated guess.
|
|
|
|
|
for (i = 0; packet_len > mtus[i]; i++)
|
|
|
|
|
;
|
|
|
|
|
mtu = (i == 0? min_mtu: mtus[i-1]);
|
|
|
|
|
mtu = (mtu < min_mtu? min_mtu: mtu);
|
|
|
|
|
|
|
|
|
|
icmp_size = WINDIVERT_PACKET_SIZE(WINDIVERT_DATA_NETWORK, icmp_len);
|
|
|
|
|
icmp = (packet_t)windivert_malloc(icmp_size, FALSE);
|
|
|
|
|
if (icmp == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
icmp->layer = WINDIVERT_LAYER_NETWORK;
|
|
|
|
|
icmp->event = WINDIVERT_EVENT_NETWORK_PACKET;
|
|
|
|
|
icmp->sniffed = 0; // Unused
|
|
|
|
|
icmp->outbound = 0; // Inbound
|
|
|
|
|
icmp->loopback = 0; // Unused
|
|
|
|
|
icmp->impostor = 0; // Treat as non-impostor
|
|
|
|
|
icmp->ipv6 = (version == 6? 1: 0);
|
|
|
|
|
icmp->ip_checksum = 0; // IP checksum valid
|
|
|
|
|
icmp->tcp_checksum = 0; // Unused
|
|
|
|
|
icmp->udp_checksum = 0; // Unused
|
|
|
|
|
icmp->icmp_checksum = 0; // ICMP(V6) checksum invalid
|
|
|
|
|
icmp->match = 0; // Unused
|
|
|
|
|
icmp->packet_size = icmp_size;
|
|
|
|
|
icmp->packet_len = icmp_len;
|
|
|
|
|
icmp->priority = packet->priority;
|
|
|
|
|
icmp->timestamp = 0; // Unused
|
|
|
|
|
icmp->object = NULL;
|
|
|
|
|
RtlCopyMemory(WINDIVERT_LAYER_DATA_PTR(icmp),
|
|
|
|
|
WINDIVERT_LAYER_DATA_PTR(packet), sizeof(WINDIVERT_DATA_NETWORK));
|
|
|
|
|
data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_NETWORK, icmp);
|
|
|
|
|
switch (version)
|
|
|
|
|
{
|
|
|
|
|
case 4:
|
|
|
|
|
ip_header_2 = (PWINDIVERT_IPHDR)data;
|
|
|
|
|
ip_header_2->Version = 4;
|
|
|
|
|
ip_header_2->HdrLength = sizeof(WINDIVERT_IPHDR) / sizeof(UINT32);
|
|
|
|
|
ip_header_2->TOS = 0x0;
|
|
|
|
|
ip_header_2->Length = RtlUshortByteSwap(icmp_len);
|
|
|
|
|
ip_header_2->Id = 0x0;
|
|
|
|
|
ip_header_2->TTL = 64;
|
|
|
|
|
ip_header_2->Protocol = IPPROTO_ICMP;
|
|
|
|
|
ip_header_2->SrcAddr = ip_header->DstAddr;
|
|
|
|
|
ip_header_2->DstAddr = ip_header->SrcAddr;
|
|
|
|
|
WINDIVERT_IPHDR_SET_FRAGOFF(ip_header_2, 0x0);
|
|
|
|
|
WINDIVERT_IPHDR_SET_MF(ip_header_2, 0);
|
|
|
|
|
WINDIVERT_IPHDR_SET_DF(ip_header_2, 1);
|
|
|
|
|
WINDIVERT_IPHDR_SET_RESERVED(ip_header_2, 0x0);
|
|
|
|
|
icmp_header = (PWINDIVERT_ICMPHDR)(ip_header_2 + 1);
|
|
|
|
|
icmp_header->Type = /*Destination Unreachable=*/3;
|
|
|
|
|
icmp_header->Code = /*Fragmentation required=*/4;
|
|
|
|
|
icmp_header->Body = ((UINT32)RtlUshortByteSwap(mtu)) << 16;
|
|
|
|
|
data = (UINT8 *)(icmp_header + 1);
|
|
|
|
|
RtlCopyMemory(data, ip_header, copy_len);
|
|
|
|
|
break;
|
|
|
|
|
case 6:
|
|
|
|
|
icmp_len -= sizeof(WINDIVERT_IPV6HDR);
|
|
|
|
|
ipv6_header_2 = (PWINDIVERT_IPV6HDR)data;
|
|
|
|
|
ipv6_header_2->Version = 6;
|
|
|
|
|
ipv6_header_2->Length = RtlUshortByteSwap(icmp_len);
|
|
|
|
|
ipv6_header_2->NextHdr = IPPROTO_ICMPV6;
|
|
|
|
|
ipv6_header_2->HopLimit = 64;
|
|
|
|
|
RtlCopyMemory(ipv6_header_2->SrcAddr, ipv6_header->DstAddr,
|
|
|
|
|
sizeof(ipv6_header_2->SrcAddr));
|
|
|
|
|
RtlCopyMemory(ipv6_header_2->DstAddr, ipv6_header->SrcAddr,
|
|
|
|
|
sizeof(ipv6_header_2->DstAddr));
|
|
|
|
|
WINDIVERT_IPV6HDR_SET_TRAFFICCLASS(ipv6_header_2, 0x0);
|
|
|
|
|
flowlabel = WINDIVERT_IPV6HDR_GET_FLOWLABEL(ipv6_header);
|
|
|
|
|
WINDIVERT_IPV6HDR_SET_FLOWLABEL(ipv6_header_2, flowlabel);
|
|
|
|
|
icmpv6_header = (PWINDIVERT_ICMPV6HDR)(ipv6_header_2 + 1);
|
|
|
|
|
icmpv6_header->Type = /*Packet Too Big=*/2;
|
|
|
|
|
icmpv6_header->Code = 0;
|
|
|
|
|
icmpv6_header->Body = RtlUlongByteSwap(mtu);
|
|
|
|
|
data = (UINT8 *)(icmpv6_header + 1);
|
|
|
|
|
RtlCopyMemory(data, ipv6_header, copy_len);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
windivert_inject_packet(icmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Copy data from a NET_BUFFER.
|
|
|
|
|
*/
|
|
|
|
|