From 80b31815b24bcc2ca6989e22c97c60aaac6c5186 Mon Sep 17 00:00:00 2001 From: basil00 Date: Mon, 13 Nov 2017 09:38:06 +0800 Subject: [PATCH] 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. --- dll/windivert_helper.c | 12 +- include/windivert.h | 1 + include/windivert_device.h | 3 +- sys/windivert.c | 281 +++++++++++++++++++++---------------- 4 files changed, 175 insertions(+), 122 deletions(-) diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c index 44e3cb8..0cff931 100644 --- a/dll/windivert_helper.c +++ b/dll/windivert_helper.c @@ -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; diff --git a/include/windivert.h b/include/windivert.h index cb38122..8bd80cd 100644 --- a/include/windivert.h +++ b/include/windivert.h @@ -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? */ diff --git a/include/windivert_device.h b/include/windivert_device.h index d84e145..8f6cf3c 100644 --- a/include/windivert_device.h +++ b/include/windivert_device.h @@ -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 diff --git a/sys/windivert.c b/sys/windivert.c index 8b13c51..553df73 100644 --- a/sys/windivert.c +++ b/sys/windivert.c @@ -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: