From 4b7e6a08bbb5069409654953183d52167be78e85 Mon Sep 17 00:00:00 2001 From: basil00 Date: Mon, 7 Oct 2013 22:57:16 +0800 Subject: [PATCH] - Simplify the WinDivert callout code: no longer handles multiple NET_BUFFERs in a single NET_BUFFER_LIST. Apparently this should only ever occur in the FORWARD layer in certain circumstances, and even then each fragment should be indicated individually anyway. This change removes a lot of needless complexity. --- sys/windivert.c | 190 ++++++++---------------------------------------- 1 file changed, 32 insertions(+), 158 deletions(-) diff --git a/sys/windivert.c b/sys/windivert.c index 370aabf..9031091 100644 --- a/sys/windivert.c +++ b/sys/windivert.c @@ -368,11 +368,6 @@ static void windivert_classify_callout(IN UINT8 direction, IN UINT32 if_idx, IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, const FWPS_FILTER0 *filter, IN UINT64 flow_context, OUT FWPS_CLASSIFY_OUT0 *result); -static BOOL windivert_reinject_packet(context_t context, UINT8 direction, - BOOL isipv4, UINT32 if_idx, UINT32 sub_if_idx, UINT32 priority, - PNET_BUFFER_LIST buffers, PNET_BUFFER buffer); -static void NTAPI windivert_reinject_complete(VOID *context, - NET_BUFFER_LIST *buffers_cpy, BOOLEAN dispatch_level); static BOOL windivert_queue_packet(context_t context, PNET_BUFFER_LIST buffers, PNET_BUFFER buffer, UINT8 direction, UINT32 if_idx, UINT32 sub_if_idx); static void windivert_free_packet(packet_t packet); @@ -1916,7 +1911,6 @@ static void windivert_classify_forward_network_v6_callout( 0, FALSE, fixed_vals, meta_vals, data, filter, flow_context, result); } - /* * WinDivert classify callout. */ @@ -1930,9 +1924,9 @@ static void windivert_classify_callout(IN UINT8 direction, IN UINT32 if_idx, FWPS_PACKET_INJECTION_STATE packet_state; HANDLE packet_context; UINT32 priority; - PNET_BUFFER_LIST buffers, buffers_fst, buffers_itr; + PNET_BUFFER_LIST buffers; PNET_BUFFER buffer; - BOOL outbound; + BOOL outbound, queued; context_t context; packet_t packet; @@ -1943,7 +1937,22 @@ static void windivert_classify_callout(IN UINT8 direction, IN UINT32 if_idx, } context = (context_t)filter->context; + if (!windivert_context_verify(context, WINDIVERT_CONTEXT_STATE_OPEN)) + { + result->actionType = FWP_ACTION_PERMIT; + return; + } buffers = (PNET_BUFFER_LIST)data; + buffer = NET_BUFFER_LIST_FIRST_NB(buffers); + if (NET_BUFFER_LIST_NEXT_NBL(buffers) != NULL) + { + /* + * This is a fragment group. This can be ignored since each + * fragment should already have been indicated. + */ + result->actionType = FWP_ACTION_PERMIT; + return; + } if (isipv4) { packet_state = FwpsQueryPacketInjectionState0(inject_handle, buffers, @@ -1954,11 +1963,6 @@ static void windivert_classify_callout(IN UINT8 direction, IN UINT32 if_idx, packet_state = FwpsQueryPacketInjectionState0(injectv6_handle, buffers, &packet_context); } - if (!windivert_context_verify(context, WINDIVERT_CONTEXT_STATE_OPEN)) - { - result->actionType = FWP_ACTION_PERMIT; - return; - } if (packet_state == FWPS_PACKET_INJECTED_BY_SELF || packet_state == FWPS_PACKET_PREVIOUSLY_INJECTED_BY_SELF) { @@ -1969,97 +1973,36 @@ static void windivert_classify_callout(IN UINT8 direction, IN UINT32 if_idx, return; } } - else - { - priority = 0; - } /* - * This code is complicated by the fact the a single NET_BUFFER_LIST - * may contain several NET_BUFFER structures. Each NET_BUFFER needs to - * be filtered independently. To achieve this we do the following: - * 1) First check if any NET_BUFFER passes the filter. - * 2) If no, then CONTINUE the entire NET_BUFFER_LIST. - * 3) Else, split the NET_BUFFER_LIST into individual NET_BUFFERs; and - * either queue or re-inject based on the filter. + * Test if the packet matches the filter or not. If so, queue the + * packet; otherwise permit the packet. */ - - // Find the first NET_BUFFER we need to queue: - buffers_fst = buffers; + queued = FALSE; outbound = (direction == WINDIVERT_DIRECTION_OUTBOUND); - do - { - buffer = NET_BUFFER_LIST_FIRST_NB(buffers_fst); - if (windivert_filter(buffer, if_idx, sub_if_idx, outbound, + if (windivert_filter(buffer, if_idx, sub_if_idx, outbound, context->filter)) - { - break; - } - buffers_fst= NET_BUFFER_LIST_NEXT_NBL(buffers_fst); - } - while (buffers_fst != NULL); - - // No NET_BUFFER needs to be queued, permit the entire NET_BUFFER_LIST: - if (buffers_fst == NULL) { - result->actionType = FWP_ACTION_PERMIT; - return; - } - - if ((context->flags & WINDIVERT_FLAG_SNIFF) == 0) - { - // Re-inject all packets up to 'buffers_fst' - buffers_itr = buffers; - while (buffers_itr != buffers_fst) - { - buffer = NET_BUFFER_LIST_FIRST_NB(buffers_itr); - if (!windivert_reinject_packet(context, direction, isipv4, if_idx, - sub_if_idx, priority, buffers, buffer)) - { - goto windivert_classify_callout_exit; - } - buffers_itr = NET_BUFFER_LIST_NEXT_NBL(buffers_itr); - } - } - else - { - buffers_itr = buffers_fst; - } - - // Queue buffers_itr = buffers_fst, which matched our filter. - buffer = NET_BUFFER_LIST_FIRST_NB(buffers_itr); - if (!windivert_queue_packet(context, buffers, buffer, direction, if_idx, - sub_if_idx)) - { - goto windivert_classify_callout_exit; - } - buffers_itr = NET_BUFFER_LIST_NEXT_NBL(buffers_itr); - - // Queue or re-inject remaining packets. - while (buffers_itr != NULL) - { - buffer = NET_BUFFER_LIST_FIRST_NB(buffers_itr); - if (windivert_filter(buffer, if_idx, sub_if_idx, outbound, - context->filter)) + if ((context->flags & WINDIVERT_FLAG_DROP) == 0) { if (!windivert_queue_packet(context, buffers, buffer, direction, if_idx, sub_if_idx)) { goto windivert_classify_callout_exit; } - } - else if ((context->flags & WINDIVERT_FLAG_SNIFF) == 0) - { - if (!windivert_reinject_packet(context, direction, isipv4, if_idx, - sub_if_idx, priority, buffers, buffer)) - { - goto windivert_classify_callout_exit; - } + queued = TRUE; } } + else + { + result->actionType = FWP_ACTION_PERMIT; + return; + } - // Since new packets have been queued, service any read. - if ((context->flags & WINDIVERT_FLAG_DROP) == 0) + /* + * If the packet was queued, then service any pending read. + */ + if (queued) { KeSetEvent(&context->read_event, IO_NO_INCREMENT, FALSE); } @@ -2092,11 +2035,6 @@ static BOOL windivert_queue_packet(context_t context, PNET_BUFFER_LIST buffers, packet_t packet; NTSTATUS status; - if ((context->flags & WINDIVERT_FLAG_DROP) != 0) - { - return TRUE; - } - length = NET_BUFFER_DATA_LENGTH(buffer); packet = (packet_t)ExAllocatePoolWithTag(NonPagedPool, WINDIVERT_PACKET_SIZE + length, WINDIVERT_TAG); @@ -2174,70 +2112,6 @@ static void windivert_free_packet(packet_t packet) ExFreePoolWithTag(packet, WINDIVERT_TAG); } -/* - * Re-inject a NET_BUFFER. - */ -static BOOL windivert_reinject_packet(context_t context, UINT8 direction, - BOOL isipv4, UINT32 if_idx, UINT32 sub_if_idx, UINT32 priority, - PNET_BUFFER_LIST buffers, PNET_BUFFER buffer) -{ - PNET_BUFFER_LIST buffers_cpy; - HANDLE handle; - NTSTATUS status; - - status = FwpsAllocateNetBufferAndNetBufferList0( - pool_handle, 0, 0, NET_BUFFER_FIRST_MDL(buffer), - NET_BUFFER_DATA_OFFSET(buffer), NET_BUFFER_DATA_LENGTH(buffer), - &buffers_cpy); - if (!NT_SUCCESS(status)) - { - return FALSE; - } - FwpsReferenceNetBufferList0(buffers, FALSE); - handle = (isipv4? inject_handle: injectv6_handle); - if (context->layer == WINDIVERT_LAYER_NETWORK_FORWARD) - { - status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0, - (isipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID, - if_idx, buffers_cpy, windivert_reinject_complete, (HANDLE)buffers); - } - else if (direction == WINDIVERT_DIRECTION_OUTBOUND) - { - status = FwpsInjectNetworkSendAsync0(handle, (HANDLE)priority, 0, - UNSPECIFIED_COMPARTMENT_ID, buffers_cpy, - windivert_reinject_complete, (HANDLE)buffers); - } - else - { - // NOTE: this case should never occur since inbound net buffers only - // ever contain one packet. We keep for completeness. - status = FwpsInjectNetworkReceiveAsync0(handle, (HANDLE)priority, 0, - UNSPECIFIED_COMPARTMENT_ID, if_idx, sub_if_idx, buffers_cpy, - windivert_reinject_complete, (HANDLE)buffers); - } - if (!NT_SUCCESS(status)) - { - FwpsDereferenceNetBufferList0(buffers, FALSE); - FwpsFreeNetBufferList0(buffers_cpy); - return FALSE; - } - return TRUE; -} - -/* - * WinDivert (re)inject complete. - */ -static void NTAPI windivert_reinject_complete(VOID *context, - NET_BUFFER_LIST *buffers_cpy, BOOLEAN dispatch_level) -{ - PNET_BUFFER_LIST buffers; - UNREFERENCED_PARAMETER(dispatch_level); - - buffers = (PNET_BUFFER_LIST)context; - FwpsDereferenceNetBufferList0(buffers, FALSE); - FwpsFreeNetBufferList0(buffers_cpy); -} - /* * Generic checksum calculation. */