Implement "impostor" packets.
WinDivert will now mark any packet injected by another driver as an "impostor", meaning that it did not originate from the network. Changes are: - User programs may filter impostor packets. - WinDivertSend() automatically decrements the TTL for imposter packets, see #41.
This commit is contained in:
+11
-1
@@ -99,6 +99,7 @@ typedef enum
|
||||
TOKEN_IF_IDX,
|
||||
TOKEN_SUB_IF_IDX,
|
||||
TOKEN_LOOPBACK,
|
||||
TOKEN_IMPOSTOR,
|
||||
TOKEN_OPEN,
|
||||
TOKEN_CLOSE,
|
||||
TOKEN_EQ,
|
||||
@@ -807,6 +808,7 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
|
||||
{"icmpv6.Code", TOKEN_ICMPV6_CODE},
|
||||
{"icmpv6.Type", TOKEN_ICMPV6_TYPE},
|
||||
{"ifIdx", TOKEN_IF_IDX},
|
||||
{"impostor", TOKEN_IMPOSTOR},
|
||||
{"inbound", TOKEN_INBOUND},
|
||||
{"ip", TOKEN_IP},
|
||||
{"ip.Checksum", TOKEN_IP_CHECKSUM},
|
||||
@@ -1139,7 +1141,8 @@ static PEXPR WinDivertMakeVar(PPOOL pool, KIND kind)
|
||||
{{{0}}, TOKEN_OUTBOUND},
|
||||
{{{0}}, TOKEN_IF_IDX},
|
||||
{{{0}}, TOKEN_SUB_IF_IDX},
|
||||
{{{0}}, TOKEN_LOOPBACK}
|
||||
{{{0}}, TOKEN_LOOPBACK},
|
||||
{{{0}}, TOKEN_IMPOSTOR}
|
||||
};
|
||||
|
||||
// Binary search:
|
||||
@@ -1260,6 +1263,7 @@ static PEXPR WinDivertParseTest(PPOOL pool, TOKEN *toks, UINT *i)
|
||||
case TOKEN_IF_IDX:
|
||||
case TOKEN_SUB_IF_IDX:
|
||||
case TOKEN_LOOPBACK:
|
||||
case TOKEN_IMPOSTOR:
|
||||
case TOKEN_IP:
|
||||
case TOKEN_IPV6:
|
||||
case TOKEN_ICMP:
|
||||
@@ -1730,6 +1734,9 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
|
||||
case TOKEN_LOOPBACK:
|
||||
object->field = WINDIVERT_FILTER_FIELD_LOOPBACK;
|
||||
break;
|
||||
case TOKEN_IMPOSTOR:
|
||||
object->field = WINDIVERT_FILTER_FIELD_IMPOSTOR;
|
||||
break;
|
||||
case TOKEN_IP:
|
||||
object->field = WINDIVERT_FILTER_FIELD_IP;
|
||||
break;
|
||||
@@ -2257,6 +2264,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
|
||||
case WINDIVERT_FILTER_FIELD_LOOPBACK:
|
||||
val[0] = addr->Loopback;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_IMPOSTOR:
|
||||
val[0] = addr->Impostor;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_IP:
|
||||
val[0] = (iphdr != NULL);
|
||||
break;
|
||||
|
||||
@@ -62,6 +62,7 @@ typedef struct
|
||||
UINT32 SubIfIdx; /* Packet's sub-interface index. */
|
||||
UINT8 Direction:1; /* Packet's direction. */
|
||||
UINT8 Loopback:1; /* Packet is loopback? */
|
||||
UINT8 Impostor:1; /* Packet is impostor? */
|
||||
UINT8 IPv4Checksum:1; /* Packet has full IPv4 checksum? */
|
||||
UINT8 TCPChecksum:1; /* Packet has full TCP checksum? */
|
||||
UINT8 UDPChecksum:1; /* Packet has full UDP checksum? */
|
||||
|
||||
@@ -105,8 +105,9 @@
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_CHECKSUM 56
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH 57
|
||||
#define WINDIVERT_FILTER_FIELD_LOOPBACK 58
|
||||
#define WINDIVERT_FILTER_FIELD_IMPOSTOR 59
|
||||
#define WINDIVERT_FILTER_FIELD_MAX \
|
||||
WINDIVERT_FILTER_FIELD_LOOPBACK
|
||||
WINDIVERT_FILTER_FIELD_IMPOSTOR
|
||||
|
||||
#define WINDIVERT_FILTER_TEST_EQ 0
|
||||
#define WINDIVERT_FILTER_TEST_NEQ 1
|
||||
|
||||
+161
-120
@@ -203,7 +203,7 @@ struct work_s
|
||||
PNET_BUFFER buffer; // First matching packet.
|
||||
UINT advance; // Bytes to retreat/advance.
|
||||
BOOL is_ipv4:1; // Is IPv4?
|
||||
BOOL hop:1; // Decrement TTL?
|
||||
BOOL impostor:1; // Impostor?
|
||||
BOOL loopback:1; // Is loopback?
|
||||
UINT8 checksums; // Which checksums are valid.
|
||||
UINT8 direction; // Packet direction.
|
||||
@@ -222,13 +222,14 @@ typedef struct work_s *work_t;
|
||||
#define WINDIVERT_UDP_CHECKSUM 0x04
|
||||
#define WINDIVERT_ALL_CHECKSUMS \
|
||||
(WINDIVERT_IP_CHECKSUM | WINDIVERT_TCP_CHECKSUM | WINDIVERT_UDP_CHECKSUM)
|
||||
#define WINDIVERT_FLAG_IMPOSTOR 0x80000000
|
||||
struct packet_s
|
||||
{
|
||||
LIST_ENTRY entry; // Entry for queue.
|
||||
UINT8 checksums; // Which checksums are valid.
|
||||
UINT8 direction; // Packet direction.
|
||||
BOOL is_ipv4:1; // Is IPv4?
|
||||
BOOL hop:1; // Decrement TTL?
|
||||
BOOL impostor:1; // Impostor?
|
||||
BOOL loopback:1; // Is loopback?
|
||||
UINT32 if_idx; // Interface index.
|
||||
UINT32 sub_if_idx; // Sub-interface index.
|
||||
@@ -430,28 +431,27 @@ static void windivert_classify_forward_network_v6_callout(
|
||||
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
|
||||
OUT FWPS_CLASSIFY_OUT0 *result);
|
||||
static void windivert_classify_callout(context_t context, IN UINT8 direction,
|
||||
IN UINT32 if_idx, IN UINT32 sub_if_idx, IN BOOL isipv4,
|
||||
IN UINT32 if_idx, IN UINT32 sub_if_idx, IN BOOL is_ipv4,
|
||||
IN BOOL loopback, IN UINT advance, IN OUT void *data,
|
||||
IN UINT64 flow_context, OUT FWPS_CLASSIFY_OUT0 *result);
|
||||
static BOOL windivert_queue_packet(context_t context, PNET_BUFFER buffer,
|
||||
UINT8 direction, UINT32 if_idx, UINT32 sub_if_idx, BOOL is_ipv4, BOOL hop,
|
||||
BOOL loopback, UINT8 checksums, LONGLONG timestamp);
|
||||
UINT8 direction, UINT32 if_idx, UINT32 sub_if_idx, BOOL is_ipv4,
|
||||
BOOL impostor, BOOL loopback, UINT8 checksums, LONGLONG timestamp);
|
||||
static BOOL windivert_reinject_packet(BOOL sniff_mode, BOOL foward,
|
||||
UINT8 direction, BOOL isipv4, UINT32 if_idx, UINT32 sub_if_idx,
|
||||
UINT32 priority, PNET_BUFFER_LIST buffers, PNET_BUFFER buffer,
|
||||
packet_t packet);
|
||||
UINT8 direction, BOOL is_ipv4, BOOL impostor, UINT32 if_idx,
|
||||
UINT32 sub_if_idx, UINT32 priority, PNET_BUFFER_LIST buffers,
|
||||
PNET_BUFFER buffer, packet_t packet);
|
||||
static void NTAPI windivert_reinject_complete(VOID *context,
|
||||
NET_BUFFER_LIST *buffers, BOOLEAN dispatch_level);
|
||||
static void NTAPI windivert_reinject_clone_complete(VOID *context,
|
||||
NET_BUFFER_LIST *buffers_cpy, BOOLEAN dispatch_level);
|
||||
static void windivert_free_packet(packet_t packet);
|
||||
static BOOL windivert_decrement_ttl(PNET_BUFFER_LIST buffers, BOOL is_ipv4);
|
||||
static UINT8 windivert_skip_headers(UINT8 proto, UINT8 **header, size_t *len);
|
||||
static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b);
|
||||
static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
|
||||
UINT32 sub_if_idx, BOOL outbound, BOOL isipv4, BOOL hop, BOOL loopback,
|
||||
filter_t filter);
|
||||
static NTSTATUS windivert_finalize_packet(void *header, size_t len,
|
||||
BOOL hop);
|
||||
UINT32 sub_if_idx, BOOL outbound, BOOL is_ipv4, BOOL impostor,
|
||||
BOOL loopback, filter_t filter);
|
||||
static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
|
||||
size_t ioctl_filter_len);
|
||||
static void windivert_filter_analyze(filter_t filter, BOOL *is_inbound,
|
||||
@@ -1355,8 +1355,9 @@ windivert_cleanup_error:
|
||||
if (!timeout && ok)
|
||||
{
|
||||
ok = windivert_reinject_packet(sniff_mode, forward,
|
||||
packet->direction, packet->is_ipv4, packet->if_idx,
|
||||
packet->sub_if_idx, priority, NULL, NULL, packet);
|
||||
packet->direction, packet->is_ipv4, packet->impostor,
|
||||
packet->if_idx, packet->sub_if_idx, priority, NULL, NULL,
|
||||
packet);
|
||||
}
|
||||
windivert_free_packet(packet);
|
||||
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
|
||||
@@ -1376,7 +1377,7 @@ windivert_cleanup_error:
|
||||
if (!timeout && ok)
|
||||
{
|
||||
ok = windivert_reinject_packet(sniff_mode, forward,
|
||||
work->direction, work->is_ipv4, work->if_idx,
|
||||
work->direction, work->is_ipv4, work->impostor, work->if_idx,
|
||||
work->sub_if_idx, work->priority, work->buffers, NULL, NULL);
|
||||
}
|
||||
FwpsDereferenceNetBufferList(work->buffers, FALSE);
|
||||
@@ -1493,7 +1494,7 @@ static NTSTATUS windivert_read(context_t context, WDFREQUEST request)
|
||||
*/
|
||||
static void windivert_read_service_request(packet_t packet,
|
||||
PNET_BUFFER buffer, UINT8 direction, UINT32 if_idx, UINT32 sub_if_idx,
|
||||
BOOL hop, BOOL loopback, LONGLONG timestamp, UINT8 checksums,
|
||||
BOOL impostor, BOOL loopback, LONGLONG timestamp, UINT8 checksums,
|
||||
WDFREQUEST request)
|
||||
{
|
||||
PMDL dst_mdl;
|
||||
@@ -1552,15 +1553,13 @@ static void windivert_read_service_request(packet_t packet,
|
||||
addr->SubIfIdx = sub_if_idx;
|
||||
addr->Direction = direction;
|
||||
addr->Loopback = (loopback? 1: 0);
|
||||
addr->Impostor = (impostor? 1: 0);
|
||||
addr->IPv4Checksum = ((checksums & WINDIVERT_IP_CHECKSUM) != 0? 1: 0);
|
||||
addr->TCPChecksum = ((checksums & WINDIVERT_TCP_CHECKSUM) != 0? 1: 0);
|
||||
addr->UDPChecksum = ((checksums & WINDIVERT_UDP_CHECKSUM) != 0? 1: 0);
|
||||
addr->Reserved = 0;
|
||||
}
|
||||
|
||||
// Zero the IP/TCP/UDP checksums and/or decrement the TTL (if required).
|
||||
status = windivert_finalize_packet(dst, dst_len, hop);
|
||||
|
||||
windivert_read_service_request_exit:
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
@@ -1616,7 +1615,7 @@ static void windivert_read_service(context_t context)
|
||||
if (!timeout)
|
||||
{
|
||||
windivert_read_service_request(packet, NULL, packet->direction,
|
||||
packet->if_idx, packet->sub_if_idx, packet->hop,
|
||||
packet->if_idx, packet->sub_if_idx, packet->impostor,
|
||||
packet->loopback, packet->timestamp, packet->checksums,
|
||||
request);
|
||||
}
|
||||
@@ -1640,7 +1639,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
|
||||
UINT data_len;
|
||||
struct iphdr *ip_header;
|
||||
struct ipv6hdr *ipv6_header;
|
||||
BOOL isipv4;
|
||||
BOOL is_ipv4;
|
||||
UINT8 layer, checksums;
|
||||
UINT32 priority;
|
||||
UINT64 flags;
|
||||
@@ -1699,17 +1698,23 @@ windivert_write_bad_packet:
|
||||
{
|
||||
case 4:
|
||||
if (data_len != RtlUshortByteSwap(ip_header->Length))
|
||||
{
|
||||
goto windivert_write_bad_packet;
|
||||
isipv4 = TRUE;
|
||||
}
|
||||
is_ipv4 = TRUE;
|
||||
break;
|
||||
case 6:
|
||||
if (data_len < sizeof(struct ipv6hdr))
|
||||
{
|
||||
goto windivert_write_bad_packet;
|
||||
}
|
||||
ipv6_header = (struct ipv6hdr *)data_copy;
|
||||
if (data_len != RtlUshortByteSwap(ipv6_header->Length) +
|
||||
sizeof(struct ipv6hdr))
|
||||
{
|
||||
goto windivert_write_bad_packet;
|
||||
isipv4 = FALSE;
|
||||
}
|
||||
is_ipv4 = FALSE;
|
||||
break;
|
||||
default:
|
||||
goto windivert_write_bad_packet;
|
||||
@@ -1777,12 +1782,22 @@ windivert_write_bad_packet:
|
||||
checksums_info.Value;
|
||||
}
|
||||
|
||||
handle = (isipv4? inject_handle: injectv6_handle);
|
||||
if (addr->Impostor)
|
||||
{
|
||||
if (!windivert_decrement_ttl(buffers, is_ipv4))
|
||||
{
|
||||
status = STATUS_HOPLIMIT_EXCEEDED;
|
||||
goto windivert_write_exit;
|
||||
}
|
||||
priority |= WINDIVERT_FLAG_IMPOSTOR;
|
||||
}
|
||||
|
||||
handle = (is_ipv4? inject_handle: injectv6_handle);
|
||||
compl_handle = ((flags & WINDIVERT_FLAG_DEBUG) != 0? (HANDLE)request: NULL);
|
||||
if (layer == WINDIVERT_LAYER_NETWORK_FORWARD)
|
||||
{
|
||||
status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0,
|
||||
(isipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID,
|
||||
(is_ipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID,
|
||||
addr->IfIdx, buffers, windivert_inject_complete, compl_handle);
|
||||
}
|
||||
else if (addr->Direction == WINDIVERT_DIRECTION_OUTBOUND)
|
||||
@@ -2398,7 +2413,7 @@ static void windivert_classify_forward_network_v6_callout(
|
||||
* WinDivert classify callout.
|
||||
*/
|
||||
static void windivert_classify_callout(context_t context, IN UINT8 direction,
|
||||
IN UINT32 if_idx, IN UINT32 sub_if_idx, IN BOOL isipv4, IN BOOL loopback,
|
||||
IN UINT32 if_idx, IN UINT32 sub_if_idx, IN BOOL is_ipv4, IN BOOL loopback,
|
||||
IN UINT advance, IN OUT void *data, IN UINT64 flow_context,
|
||||
OUT FWPS_CLASSIFY_OUT0 *result)
|
||||
{
|
||||
@@ -2410,7 +2425,7 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
|
||||
PNET_BUFFER buffer, buffer_fst, buffer_itr;
|
||||
NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksums_info;
|
||||
UINT8 layer, checksums;
|
||||
BOOL outbound, hop;
|
||||
BOOL outbound, impostor;
|
||||
WDFOBJECT object;
|
||||
work_t work;
|
||||
PLIST_ENTRY old_entry;
|
||||
@@ -2433,7 +2448,7 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
|
||||
result->actionType = FWP_ACTION_CONTINUE;
|
||||
return;
|
||||
}
|
||||
if (isipv4)
|
||||
if (is_ipv4)
|
||||
{
|
||||
packet_state = FwpsQueryPacketInjectionState0(inject_handle, buffers,
|
||||
&packet_context);
|
||||
@@ -2458,11 +2473,16 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
|
||||
WdfObjectReference(object);
|
||||
KeReleaseInStackQueuedSpinLock(&lock_handle);
|
||||
|
||||
hop = FALSE;
|
||||
impostor = FALSE;
|
||||
if (packet_state == FWPS_PACKET_INJECTED_BY_SELF ||
|
||||
packet_state == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF)
|
||||
{
|
||||
packet_priority = (UINT32)packet_context;
|
||||
if ((packet_priority & WINDIVERT_FLAG_IMPOSTOR) != 0)
|
||||
{
|
||||
impostor = TRUE;
|
||||
packet_priority &= ~WINDIVERT_FLAG_IMPOSTOR;
|
||||
}
|
||||
if (packet_priority >= priority)
|
||||
{
|
||||
WdfObjectDereference(object);
|
||||
@@ -2474,8 +2494,8 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
|
||||
{
|
||||
// This is a packet injected by another driver, possibly an older
|
||||
// version of WinDivert. To prevent block-clone-reinject infinite
|
||||
// loops, we consider this capture to be a "hop".
|
||||
hop = TRUE;
|
||||
// loops, we mark this packet as an "impostor".
|
||||
impostor = TRUE;
|
||||
}
|
||||
|
||||
// Loopback packets are considered outbound only.
|
||||
@@ -2486,6 +2506,9 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the timestamp.
|
||||
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
|
||||
|
||||
// Determine which checksum fields are present or not.
|
||||
checksums_info.Value = NET_BUFFER_LIST_INFO(buffers,
|
||||
TcpIpChecksumNetBufferListInfo);
|
||||
@@ -2516,8 +2539,6 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
|
||||
WINDIVERT_UDP_CHECKSUM);
|
||||
}
|
||||
|
||||
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
|
||||
|
||||
// Retreat the NET_BUFFER to the IP header, if necessary.
|
||||
// If (advance != 0) then this must be in the inbound path, and the
|
||||
// NET_BUFFER_LIST must contain exactly one NET_BUFFER.
|
||||
@@ -2549,7 +2570,7 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
|
||||
do
|
||||
{
|
||||
BOOL match = windivert_filter(buffer_fst, if_idx, sub_if_idx, outbound,
|
||||
isipv4, hop, loopback, filter);
|
||||
is_ipv4, impostor, loopback, filter);
|
||||
if (match)
|
||||
{
|
||||
break;
|
||||
@@ -2582,8 +2603,8 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
|
||||
work->buffers = buffers;
|
||||
work->buffer = buffer_fst;
|
||||
work->advance = advance;
|
||||
work->is_ipv4 = isipv4;
|
||||
work->hop = hop;
|
||||
work->is_ipv4 = is_ipv4;
|
||||
work->impostor = impostor;
|
||||
work->loopback = loopback;
|
||||
work->checksums = checksums;
|
||||
work->direction = direction;
|
||||
@@ -2605,6 +2626,7 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
|
||||
context->work_queue_length++;
|
||||
if (context->work_queue_length > WINDIVERT_WORK_QUEUE_LEN_MAX)
|
||||
{
|
||||
// The work queue is full; as an emergency we drop packets.
|
||||
old_entry = RemoveHeadList(&context->work_queue);
|
||||
context->work_queue_length--;
|
||||
}
|
||||
@@ -2682,9 +2704,9 @@ VOID windivert_worker(IN WDFWORKITEM item)
|
||||
while (buffer_itr != buffer_fst)
|
||||
{
|
||||
ok = windivert_reinject_packet(sniff_mode, forward,
|
||||
work->direction, work->is_ipv4, work->if_idx,
|
||||
work->sub_if_idx, work->priority, work->buffers,
|
||||
buffer_itr, NULL);
|
||||
work->direction, work->is_ipv4, work->impostor,
|
||||
work->if_idx, work->sub_if_idx, work->priority,
|
||||
work->buffers, buffer_itr, NULL);
|
||||
if (!ok)
|
||||
{
|
||||
goto windivert_worker_complete;
|
||||
@@ -2696,7 +2718,7 @@ VOID windivert_worker(IN WDFWORKITEM item)
|
||||
{
|
||||
// In SNIFF mode, reinject the entire NET_BUFFER_LIST.
|
||||
ok = windivert_reinject_packet(sniff_mode, forward,
|
||||
work->direction, work->is_ipv4, work->if_idx,
|
||||
work->direction, work->is_ipv4, work->impostor, work->if_idx,
|
||||
work->sub_if_idx, work->priority, work->buffers, NULL, NULL);
|
||||
if (!ok)
|
||||
{
|
||||
@@ -2707,7 +2729,7 @@ VOID windivert_worker(IN WDFWORKITEM item)
|
||||
|
||||
// Queue the first matching packet.
|
||||
ok = windivert_queue_packet(context, buffer_itr, work->direction,
|
||||
work->if_idx, work->sub_if_idx, work->is_ipv4, work->hop,
|
||||
work->if_idx, work->sub_if_idx, work->is_ipv4, work->impostor,
|
||||
work->loopback, work->checksums, work->timestamp);
|
||||
if (!ok)
|
||||
{
|
||||
@@ -2720,21 +2742,21 @@ VOID windivert_worker(IN WDFWORKITEM item)
|
||||
while (buffer_itr != NULL)
|
||||
{
|
||||
match = windivert_filter(buffer_itr, work->if_idx,
|
||||
work->sub_if_idx, outbound, work->is_ipv4, work->hop,
|
||||
work->sub_if_idx, outbound, work->is_ipv4, work->impostor,
|
||||
work->loopback, filter);
|
||||
if (match)
|
||||
{
|
||||
ok = windivert_queue_packet(context, buffer_itr,
|
||||
work->direction, work->if_idx, work->sub_if_idx,
|
||||
work->is_ipv4, work->hop, work->loopback, work->checksums,
|
||||
work->timestamp);
|
||||
work->is_ipv4, work->impostor, work->loopback,
|
||||
work->checksums, work->timestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = windivert_reinject_packet(sniff_mode, forward,
|
||||
work->direction, work->is_ipv4, work->if_idx,
|
||||
work->sub_if_idx, work->priority, work->buffers,
|
||||
buffer_itr, NULL);
|
||||
work->direction, work->is_ipv4, work->impostor,
|
||||
work->if_idx, work->sub_if_idx, work->priority,
|
||||
work->buffers, buffer_itr, NULL);
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
@@ -2759,8 +2781,8 @@ windivert_worker_complete:
|
||||
* Queue a NET_BUFFER.
|
||||
*/
|
||||
static BOOL windivert_queue_packet(context_t context, PNET_BUFFER buffer,
|
||||
UINT8 direction, UINT32 if_idx, UINT32 sub_if_idx, BOOL is_ipv4, BOOL hop,
|
||||
BOOL loopback, UINT8 checksums, LONGLONG timestamp0)
|
||||
UINT8 direction, UINT32 if_idx, UINT32 sub_if_idx, BOOL is_ipv4,
|
||||
BOOL impostor, BOOL loopback, UINT8 checksums, LONGLONG timestamp0)
|
||||
{
|
||||
KLOCK_QUEUE_HANDLE lock_handle;
|
||||
PVOID data;
|
||||
@@ -2806,7 +2828,7 @@ static BOOL windivert_queue_packet(context_t context, PNET_BUFFER buffer,
|
||||
{
|
||||
// FAST PATH: Service an I/O request without queueing the packet.
|
||||
windivert_read_service_request(NULL, buffer, direction, if_idx,
|
||||
sub_if_idx, hop, loopback, timestamp0, checksums, request);
|
||||
sub_if_idx, impostor, loopback, timestamp0, checksums, request);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -2834,7 +2856,7 @@ static BOOL windivert_queue_packet(context_t context, PNET_BUFFER buffer,
|
||||
RtlCopyMemory(packet->data, data, data_len);
|
||||
}
|
||||
packet->is_ipv4 = is_ipv4;
|
||||
packet->hop = hop;
|
||||
packet->impostor = impostor;
|
||||
packet->loopback = loopback;
|
||||
packet->checksums = checksums;
|
||||
packet->direction = direction;
|
||||
@@ -2843,7 +2865,6 @@ static BOOL windivert_queue_packet(context_t context, PNET_BUFFER buffer,
|
||||
packet->timestamp = timestamp0;
|
||||
entry = &packet->entry;
|
||||
|
||||
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
|
||||
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
|
||||
while (TRUE)
|
||||
{
|
||||
@@ -2908,9 +2929,9 @@ static BOOL windivert_queue_packet(context_t context, PNET_BUFFER buffer,
|
||||
* Re-inject a packet or packets.
|
||||
*/
|
||||
static BOOL windivert_reinject_packet(BOOL sniff_mode, BOOL forward,
|
||||
UINT8 direction, BOOL isipv4, UINT32 if_idx, UINT32 sub_if_idx,
|
||||
UINT32 priority, PNET_BUFFER_LIST buffers, PNET_BUFFER buffer,
|
||||
packet_t packet)
|
||||
UINT8 direction, BOOL is_ipv4, BOOL impostor, UINT32 if_idx,
|
||||
UINT32 sub_if_idx, UINT32 priority, PNET_BUFFER_LIST buffers,
|
||||
PNET_BUFFER buffer, packet_t packet)
|
||||
{
|
||||
PNET_BUFFER_LIST buffers_cpy;
|
||||
BOOL clone;
|
||||
@@ -3007,11 +3028,21 @@ static BOOL windivert_reinject_packet(BOOL sniff_mode, BOOL forward,
|
||||
else
|
||||
return TRUE;
|
||||
|
||||
handle = (isipv4? inject_handle: injectv6_handle);
|
||||
if (impostor)
|
||||
{
|
||||
if (!windivert_decrement_ttl(buffers_cpy, is_ipv4))
|
||||
{
|
||||
status = STATUS_HOPLIMIT_EXCEEDED;
|
||||
goto windivert_reinject_packet_exit;
|
||||
}
|
||||
priority |= WINDIVERT_FLAG_IMPOSTOR;
|
||||
}
|
||||
|
||||
handle = (is_ipv4? inject_handle: injectv6_handle);
|
||||
if (forward)
|
||||
{
|
||||
status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0,
|
||||
(isipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID,
|
||||
(is_ipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID,
|
||||
if_idx, buffers_cpy, completion, compl_handle);
|
||||
}
|
||||
else if (direction == WINDIVERT_DIRECTION_OUTBOUND)
|
||||
@@ -3027,6 +3058,7 @@ static BOOL windivert_reinject_packet(BOOL sniff_mode, BOOL forward,
|
||||
sub_if_idx, buffers_cpy, completion, compl_handle);
|
||||
}
|
||||
|
||||
windivert_reinject_packet_exit:
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
DEBUG_ERROR("failed to (re)inject packet(s)", status);
|
||||
@@ -3086,6 +3118,71 @@ static void windivert_free_packet(packet_t packet)
|
||||
windivert_free(packet);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement the TTL of a packet.
|
||||
*/
|
||||
static BOOL windivert_decrement_ttl(PNET_BUFFER_LIST buffers, BOOL is_ipv4)
|
||||
{
|
||||
PNET_BUFFER buffer;
|
||||
struct iphdr *ip_header;
|
||||
struct ipv6hdr *ipv6_header;
|
||||
NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksums_info;
|
||||
BOOL checksum = FALSE;
|
||||
|
||||
if (is_ipv4)
|
||||
{
|
||||
checksums_info.Value = NET_BUFFER_LIST_INFO(buffers,
|
||||
TcpIpChecksumNetBufferListInfo);
|
||||
checksum = (checksums_info.Transmit.IpHeaderChecksum != 0);
|
||||
}
|
||||
|
||||
for (buffer = NET_BUFFER_LIST_FIRST_NB(buffers); buffer != NULL;
|
||||
buffer = NET_BUFFER_NEXT_NB(buffer))
|
||||
{
|
||||
if (is_ipv4)
|
||||
{
|
||||
ip_header = (struct iphdr *)NdisGetDataBuffer(buffer,
|
||||
sizeof(struct iphdr), NULL, 1, 0);
|
||||
if (ip_header == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (ip_header->TTL <= 1)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
ip_header->TTL--;
|
||||
if (checksum)
|
||||
{
|
||||
// Incremental checksum update:
|
||||
if (ip_header->Checksum >= 0xFFFE)
|
||||
{
|
||||
ip_header->Checksum -= 0xFFFE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ip_header->Checksum += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ipv6_header = (struct ipv6hdr *)NdisGetDataBuffer(buffer,
|
||||
sizeof(struct ipv6hdr), NULL, 1, 0);
|
||||
if (ipv6_header == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (ipv6_header->HopLimit <= 1)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
ipv6_header->HopLimit--;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip well-known IPv6 extension headers.
|
||||
*/
|
||||
@@ -3133,58 +3230,6 @@ static UINT8 windivert_skip_headers(UINT8 proto, UINT8 **header, size_t *len)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Zero the IP/TCP/UDP checksums and/or decrement the TTL (if required)
|
||||
*/
|
||||
static NTSTATUS windivert_finalize_packet(void *header, size_t len, BOOL hop)
|
||||
{
|
||||
struct iphdr *ip_header = (struct iphdr *)header;
|
||||
struct ipv6hdr *ipv6_header = (struct ipv6hdr *)header;
|
||||
size_t ip_header_len;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
if (!hop)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
if (len < sizeof(struct iphdr))
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
switch (ip_header->Version)
|
||||
{
|
||||
case 4:
|
||||
if (ip_header->TTL <= 1)
|
||||
{
|
||||
status = STATUS_HOPLIMIT_EXCEEDED;
|
||||
}
|
||||
if (ip_header->TTL != 0)
|
||||
{
|
||||
ip_header->TTL--;
|
||||
}
|
||||
return status;
|
||||
|
||||
case 6:
|
||||
if (len < sizeof(struct ipv6hdr))
|
||||
{
|
||||
return status;
|
||||
}
|
||||
if (ipv6_header->HopLimit <= 1)
|
||||
{
|
||||
status = STATUS_HOPLIMIT_EXCEEDED;
|
||||
}
|
||||
if (ipv6_header->HopLimit != 0)
|
||||
{
|
||||
ipv6_header->HopLimit--;
|
||||
}
|
||||
return status;
|
||||
|
||||
default:
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Big number comparison.
|
||||
*/
|
||||
@@ -3229,8 +3274,8 @@ static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b)
|
||||
* Checks if the given packet is of interest.
|
||||
*/
|
||||
static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
|
||||
UINT32 sub_if_idx, BOOL outbound, BOOL isipv4, BOOL hop, BOOL loopback,
|
||||
filter_t filter)
|
||||
UINT32 sub_if_idx, BOOL outbound, BOOL is_ipv4, BOOL impostor,
|
||||
BOOL loopback, filter_t filter)
|
||||
{
|
||||
size_t tot_len, ip_header_len;
|
||||
struct iphdr *ip_header = NULL;
|
||||
@@ -3252,7 +3297,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
|
||||
}
|
||||
|
||||
// Get the IP header.
|
||||
if (isipv4)
|
||||
if (is_ipv4)
|
||||
{
|
||||
// IPv4:
|
||||
if (tot_len < sizeof(struct iphdr))
|
||||
@@ -3442,6 +3487,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
|
||||
case WINDIVERT_FILTER_FIELD_LOOPBACK:
|
||||
field[0] = (UINT32)loopback;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_IMPOSTOR:
|
||||
field[0] = (UINT32)impostor;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_IP:
|
||||
field[0] = (UINT32)(ip_header != NULL);
|
||||
break;
|
||||
@@ -3484,10 +3532,6 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_IP_TTL:
|
||||
field[0] = (UINT32)ip_header->TTL;
|
||||
if (hop)
|
||||
{
|
||||
field[0] = (field[0] == 0? 0: field[0]-1);
|
||||
}
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_IP_PROTOCOL:
|
||||
field[0] = (UINT32)ip_header->Protocol;
|
||||
@@ -3516,10 +3560,6 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT:
|
||||
field[0] = (UINT32)ipv6_header->HopLimit;
|
||||
if (hop)
|
||||
{
|
||||
field[0] = (field[0] == 0? 0: field[0]-1);
|
||||
}
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
|
||||
field[3] =
|
||||
@@ -3980,6 +4020,7 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
|
||||
case WINDIVERT_FILTER_FIELD_IFIDX:
|
||||
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
|
||||
case WINDIVERT_FILTER_FIELD_LOOPBACK:
|
||||
case WINDIVERT_FILTER_FIELD_IMPOSTOR:
|
||||
case WINDIVERT_FILTER_FIELD_IP:
|
||||
case WINDIVERT_FILTER_FIELD_IPV6:
|
||||
case WINDIVERT_FILTER_FIELD_ICMP:
|
||||
|
||||
Reference in New Issue
Block a user