Add a new WinDivertShutdown() function (#156).

This function allows the user application to
"shutdown" a handle in anticipation of a
call to WinDivertClose().  When a handle has
been shutdown, new packets will no longer be
queued.  However, existing queued packets can
still be read by WinDivertRecv().  When the
queue is emptied, WinDivertRecv() will fail
with ERROR_NO_DATA.

The WinDivertShutdown() function is analogous
to the shutdown() socket function.

This change also simplifies events.
This commit is contained in:
basil00
2018-11-11 09:44:24 +08:00
parent 0a74b5528c
commit 312050accb
7 changed files with 194 additions and 77 deletions
+9
View File
@@ -567,6 +567,15 @@ extern BOOL WinDivertSendEx(HANDLE handle, const VOID *pPacket, UINT packetLen,
}
}
/*
* Shutdown a WinDivert handle.
*/
extern BOOL WinDivertShutdown(HANDLE handle, WINDIVERT_SHUTDOWN how)
{
return WinDivertIoControl(handle, IOCTL_WINDIVERT_SHUTDOWN,
(UINT64)how, 0, NULL, 0, NULL);
}
/*
* Close a WinDivert handle.
*/
+1
View File
@@ -6,6 +6,7 @@ EXPORTS
WinDivertRecvEx
WinDivertSend
WinDivertSendEx
WinDivertShutdown
WinDivertClose
WinDivertSetParam
WinDivertGetParam
+3 -14
View File
@@ -514,23 +514,14 @@ static BOOL WinDivertExpandMacro(KIND kind, WINDIVERT_LAYER layer,
*val = WINDIVERT_EVENT_NETWORK_PACKET;
return (layer == WINDIVERT_LAYER_NETWORK);
case TOKEN_EVENT_ESTABLISHED:
if (layer == WINDIVERT_LAYER_FLOW)
{
*val = WINDIVERT_EVENT_FLOW_ESTABLISHED;
return TRUE;
}
else if (layer == WINDIVERT_LAYER_REFLECT)
{
*val = WINDIVERT_EVENT_REFLECT_ESTABLISHED;
return TRUE;
}
return FALSE;
*val = WINDIVERT_EVENT_FLOW_ESTABLISHED;
return (layer == WINDIVERT_LAYER_FLOW);
case TOKEN_EVENT_DELETED:
*val = WINDIVERT_EVENT_FLOW_DELETED;
return (layer == WINDIVERT_LAYER_FLOW);
case TOKEN_EVENT_BIND:
*val = WINDIVERT_EVENT_SOCKET_BIND;
return (layer == WINDIVERT_LAYER_FLOW);
return (layer == WINDIVERT_LAYER_SOCKET);
case TOKEN_EVENT_CONNECT:
*val = WINDIVERT_EVENT_SOCKET_CONNECT;
return (layer == WINDIVERT_LAYER_SOCKET);
@@ -4055,8 +4046,6 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
case WINDIVERT_LAYER_REFLECT:
switch (val->val[0])
{
case WINDIVERT_EVENT_REFLECT_ESTABLISHED:
WinDivertPutString(stream, "ESTABLISHED"); break;
case WINDIVERT_EVENT_REFLECT_OPEN:
WinDivertPutString(stream, "OPEN"); break;
case WINDIVERT_EVENT_REFLECT_CLOSE:
+17 -5
View File
@@ -238,6 +238,12 @@ usage:
GetLastError());
return EXIT_FAILURE;
}
if (mode != WATCH && !WinDivertShutdown(handle, WINDIVERT_SHUTDOWN_BOTH))
{
fprintf(stderr, "error: failed to shutdown WinDivert handle (%d)\n",
GetLastError());
return EXIT_FAILURE;
}
// Main loop:
console = GetStdHandle(STD_OUTPUT_HANDLE);
@@ -245,13 +251,16 @@ usage:
{
if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len))
{
if (mode != WATCH && GetLastError() == ERROR_NO_DATA)
{
break;
}
fprintf(stderr, "failed to event (%d)\n", GetLastError());
continue;
}
switch (addr.Event)
{
case WINDIVERT_EVENT_REFLECT_ESTABLISHED:
case WINDIVERT_EVENT_REFLECT_OPEN:
// Open handle:
process = add_process(addr.Reflect.ProcessId);
@@ -395,10 +404,13 @@ usage:
{
remove_process(addr.Reflect.ProcessId);
}
if (mode != WATCH && addr.Final)
{
break;
}
}
if (!WinDivertClose(handle))
{
fprintf(stderr, "error: failed to close WinDivert handle (%d)\n",
GetLastError());
return EXIT_FAILURE;
}
return 0;
+29 -22
View File
@@ -135,7 +135,7 @@ typedef struct
{
INT64 Timestamp; /* Packet's timestamp. */
UINT64 Layer:8; /* Packet's layer. */
UINT64 Event:24; /* Packet event. */
UINT64 Event:8; /* Packet event. */
UINT64 Outbound:1; /* Packet is outound? */
UINT64 Loopback:1; /* Packet is loopback? */
UINT64 Impostor:1; /* Packet is impostor? */
@@ -143,8 +143,7 @@ typedef struct
UINT64 PseudoIPChecksum:1; /* Packet has pseudo IPv4 checksum? */
UINT64 PseudoTCPChecksum:1; /* Packet has pseudo TCP checksum? */
UINT64 PseudoUDPChecksum:1; /* Packet has pseudo UDP checksum? */
UINT64 Final:1; /* Packet is final event? */
UINT64 Reserved:24;
UINT64 Reserved:41;
union
{
WINDIVERT_DATA_NETWORK Network; /* Network layer data. */
@@ -159,26 +158,16 @@ typedef struct
*/
typedef enum
{
WINDIVERT_EVENT_NETWORK_PACKET = 0x0001,
/* Network packet. */
WINDIVERT_EVENT_FLOW_ESTABLISHED = 0x0002,
WINDIVERT_EVENT_NETWORK_PACKET = 0, /* Network packet. */
WINDIVERT_EVENT_FLOW_ESTABLISHED = 1,
/* Flow established. */
WINDIVERT_EVENT_FLOW_DELETED = 0x0004,
/* Flow deleted. */
WINDIVERT_EVENT_SOCKET_BIND = 0x0008,
/* Socket bind. */
WINDIVERT_EVENT_SOCKET_LISTEN = 0x0010,
/* Socket listen. */
WINDIVERT_EVENT_SOCKET_CONNECT = 0x0020,
/* Socket connect. */
WINDIVERT_EVENT_SOCKET_ACCEPT = 0x0040,
/* Socket accept. */
WINDIVERT_EVENT_REFLECT_ESTABLISHED = 0x0080,
/* Previously open WinDivert handle. */
WINDIVERT_EVENT_REFLECT_OPEN = 0x0100,
/* Open new WinDivert handle. */
WINDIVERT_EVENT_REFLECT_CLOSE = 0x0200,
/* Close existing WinDivert handle. */
WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */
WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */
WINDIVERT_EVENT_SOCKET_LISTEN = 4, /* Socket listen. */
WINDIVERT_EVENT_SOCKET_CONNECT = 5, /* Socket connect. */
WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */
WINDIVERT_EVENT_REFLECT_OPEN = 7, /* Open new WinDivert handle. */
WINDIVERT_EVENT_REFLECT_CLOSE = 8, /* Close existing WinDivert handle. */
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
/*
@@ -204,6 +193,17 @@ typedef enum
} WINDIVERT_PARAM, *PWINDIVERT_PARAM;
#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_QUEUE_SIZE
/*
* WinDivert shutdown parameter.
*/
typedef enum
{
WINDIVERT_SHUTDOWN_RECV = 0x1, /* Shutdown recv. */
WINDIVERT_SHUTDOWN_SEND = 0x2, /* Shutdown send. */
WINDIVERT_SHUTDOWN_BOTH = 0x3, /* Shutdown recv and send. */
} WINDIVERT_SHUTDOWN, *PWINDIVERT_SHUTDOWN;
#define WINDIVERT_SHUTDOWN_MAX WINDIVERT_SHUTDOWN_BOTH
#ifndef WINDIVERT_KERNEL
/*
@@ -261,6 +261,13 @@ extern WINDIVERTEXPORT BOOL WinDivertSendEx(
__in UINT addrLen,
__inout_opt LPOVERLAPPED lpOverlapped);
/*
* Shutdown a WinDivert handle.
*/
extern WINDIVERTEXPORT BOOL WinDivertShutdown(
__in HANDLE handle,
__in WINDIVERT_SHUTDOWN how);
/*
* Close a WinDivert handle.
*/
+5 -1
View File
@@ -161,7 +161,8 @@
/*
* WinDivert events.
*/
#define WINDIVERT_EVENT_MAX 0x8000
#define WINDIVERT_EVENT_MAX \
WINDIVERT_EVENT_REFLECT_CLOSE
/*
* WinDivert flags.
@@ -244,6 +245,9 @@ typedef struct
/*
* IOCTL codes.
*/
#define IOCTL_WINDIVERT_SHUTDOWN \
CTL_CODE(FILE_DEVICE_NETWORK, 0x917, METHOD_IN_DIRECT, FILE_READ_DATA | \
FILE_WRITE_DATA)
#define IOCTL_WINDIVERT_RECV \
CTL_CODE(FILE_DEVICE_NETWORK, 0x918, METHOD_OUT_DIRECT, FILE_READ_DATA)
#define IOCTL_WINDIVERT_SEND \
+130 -35
View File
@@ -158,6 +158,9 @@ struct context_s
WDFWORKITEM worker; // Read worker.
WINDIVERT_LAYER layer; // Context's layer.
UINT64 flags; // Context's flags.
BOOL shutdown_recv; // Shutdown recv.
BOOL shutdown_send; // Shutdown send.
BOOL shutdown_recv_enabled; // Shutdown recv enabled?
UINT32 priority; // Context (internal) priority.
INT16 priority16; // Context (user) priority.
GUID callout_guid[WINDIVERT_CONTEXT_MAXLAYERS];
@@ -241,7 +244,7 @@ struct packet_s
LIST_ENTRY entry; // Entry for queue.
LONGLONG timestamp; // Packet timestamp.
UINT64 layer:8; // Layer.
UINT64 event:24; // Event.
UINT64 event:8; // Event.
UINT64 outbound:1; // Packet is outound?
UINT64 loopback:1; // Packet is loopback?
UINT64 impostor:1; // Packet is impostor?
@@ -249,7 +252,6 @@ struct packet_s
UINT64 pseudo_ip_checksum:1; // Packet has pseudo IPv4 check?
UINT64 pseudo_tcp_checksum:1; // Packet has pseudo TCP check?
UINT64 pseudo_udp_checksum:1; // Packet has pseudo UDP check?
UINT64 final:1; // Packet is final event?
UINT64 match:1; // Packet matches filter?
UINT32 priority; // Packet priority.
UINT32 packet_len; // Length of the packet.
@@ -448,8 +450,8 @@ static void windivert_network_classify(context_t context,
static BOOL windivert_queue_work(context_t context, PVOID packet,
ULONG packet_len, PNET_BUFFER_LIST buffers, WINDIVERT_LAYER layer,
PVOID layer_data, WINDIVERT_EVENT event, UINT64 flags, UINT32 priority,
BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, BOOL final,
BOOL match, LONGLONG timestamp);
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 void windivert_free_packet(packet_t packet);
@@ -1256,6 +1258,9 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
context->packet_queue_maxtime = WINDIVERT_PARAM_QUEUE_TIME_DEFAULT;
context->layer = WINDIVERT_LAYER_DEFAULT;
context->flags = 0;
context->shutdown_recv = FALSE;
context->shutdown_recv_enabled = FALSE;
context->shutdown_send = FALSE;
context->priority = windivert_context_priority(WINDIVERT_PRIORITY_DEFAULT);
context->filter = NULL;
context->worker = NULL;
@@ -1982,7 +1987,6 @@ static void windivert_read_service_request(context_t context, packet_t packet,
addr[i].PseudoIPChecksum = packet->pseudo_ip_checksum;
addr[i].PseudoTCPChecksum = packet->pseudo_tcp_checksum;
addr[i].PseudoUDPChecksum = packet->pseudo_udp_checksum;
addr[i].Final = packet->final;
addr[i].Reserved = 0;
layer_data = (PVOID)packet->data;
switch (packet->layer)
@@ -2114,6 +2118,26 @@ static void windivert_read_service(context_t context)
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
}
if (context->shutdown_recv && context->shutdown_recv_enabled &&
IsListEmpty(&context->packet_queue) &&
IsListEmpty(&context->work_queue))
{
// The handle has shutdown, the queue is empty, and no more packets
// will be queued. Notify any remaining requests.
while (context->state == WINDIVERT_CONTEXT_STATE_OPEN)
{
status = WdfIoQueueRetrieveNextRequest(context->read_queue,
&request);
if (!NT_SUCCESS(status))
{
break;
}
KeReleaseInStackQueuedSpinLock(&lock_handle);
WdfRequestComplete(request, STATUS_PIPE_EMPTY);
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
}
}
KeReleaseInStackQueuedSpinLock(&lock_handle);
}
@@ -2149,6 +2173,12 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
status = STATUS_INVALID_DEVICE_STATE;
goto windivert_write_hard_error;
}
if (context->shutdown_send)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
status = STATUS_PIPE_EMPTY;
goto windivert_write_hard_error;
}
layer = context->layer;
priority = context->priority;
flags = context->flags;
@@ -2506,6 +2536,7 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
addr = (PWINDIVERT_ADDRESS)WdfMemoryGetBuffer(memobj, NULL);
break;
case IOCTL_WINDIVERT_SHUTDOWN:
case IOCTL_WINDIVERT_START_FILTER:
case IOCTL_WINDIVERT_SET_LAYER:
case IOCTL_WINDIVERT_SET_PRIORITY:
@@ -2605,7 +2636,43 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
return;
}
break;
case IOCTL_WINDIVERT_SHUTDOWN:
{
UINT64 how;
ioctl = (PWINDIVERT_IOCTL)inbuf;
how = ioctl->arg1;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
status = STATUS_INVALID_DEVICE_STATE;
goto windivert_ioctl_exit;
}
switch (how)
{
case WINDIVERT_SHUTDOWN_RECV:
context->shutdown_recv = TRUE;
break;
case WINDIVERT_SHUTDOWN_SEND:
context->shutdown_send = TRUE;
break;
case WINDIVERT_SHUTDOWN_BOTH:
context->shutdown_recv = context->shutdown_send = TRUE;
break;
default:
KeReleaseInStackQueuedSpinLock(&lock_handle);
status = STATUS_INVALID_PARAMETER;
DEBUG_ERROR("failed to shutdown handle; invalid how",
status);
goto windivert_ioctl_exit;
}
KeReleaseInStackQueuedSpinLock(&lock_handle);
windivert_read_service(context);
break;
}
case IOCTL_WINDIVERT_START_FILTER:
{
BOOL inbound, outbound, ipv4, ipv6;
@@ -2688,6 +2755,8 @@ windivert_ioctl_bad_start_state:
context->reflect.data.Flags = context->flags;
context->reflect.data.Priority = context->priority16;
context->reflect.open = FALSE;
context->shutdown_recv_enabled =
(layer != WINDIVERT_LAYER_REFLECT);
KeReleaseInStackQueuedSpinLock(&lock_handle);
windivert_reflect_open_event(context);
@@ -3197,7 +3266,8 @@ static void windivert_network_classify(context_t context,
}
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
context->shutdown_recv)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
return;
@@ -3293,7 +3363,7 @@ static void windivert_network_classify(context_t context,
NET_BUFFER_DATA_LENGTH(buffer_itr), buffers, layer,
(PVOID)network_data, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
flags, priority, ipv4, outbound, loopback, impostor,
/*final=*/FALSE, /*match=*/FALSE, timestamp);
/*match=*/FALSE, timestamp);
if (!ok)
{
goto windivert_network_classify_exit;
@@ -3305,8 +3375,8 @@ static void windivert_network_classify(context_t context,
ok = windivert_queue_work(context, (PVOID)buffer_itr,
NET_BUFFER_DATA_LENGTH(buffer_itr), buffers, layer,
(PVOID)network_data, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
flags, priority, ipv4, outbound, loopback, impostor, /*final=*/FALSE,
/*match=*/TRUE, timestamp);
flags, priority, ipv4, outbound, loopback, impostor, /*match=*/TRUE,
timestamp);
if (advance != 0)
{
// Advance the NET_BUFFER to its original position. Note that we can
@@ -3330,8 +3400,8 @@ static void windivert_network_classify(context_t context,
ok = windivert_queue_work(context, (PVOID)buffer_itr,
NET_BUFFER_DATA_LENGTH(buffer_itr), buffers, layer,
(PVOID)network_data, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
flags, priority, ipv4, outbound, loopback, impostor,
/*FINAL=*/FALSE, match, timestamp);
flags, priority, ipv4, outbound, loopback, impostor, match,
timestamp);
if (!ok)
{
goto windivert_network_classify_exit;
@@ -3458,7 +3528,8 @@ static void windivert_flow_established_classify(context_t context,
result->actionType = FWP_ACTION_CONTINUE;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
context->shutdown_recv)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
return;
@@ -3483,8 +3554,7 @@ static void windivert_flow_established_classify(context_t context,
ok = windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW, (PVOID)flow_data,
/*event=*/WINDIVERT_EVENT_FLOW_ESTABLISHED, flags, /*priority=*/0,
ipv4, outbound, loopback, /*impostor=*/FALSE, /*final=*/FALSE,
match, timestamp);
ipv4, outbound, loopback, /*impostor=*/FALSE, match, timestamp);
if (!ok)
{
WdfObjectDereference(object);
@@ -3523,7 +3593,8 @@ static void windivert_flow_established_classify(context_t context,
}
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
context->shutdown_recv)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
windivert_free(flow);
@@ -3578,7 +3649,8 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
}
flow->deleted = TRUE;
cleanup = flow->inserted;
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
context->shutdown_recv)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
goto windivert_flow_delete_notify_exit;
@@ -3597,7 +3669,7 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW,
(PVOID)&flow->data, /*event=*/WINDIVERT_EVENT_FLOW_DELETED, flags,
/*priority=*/0, !flow->ipv6, flow->outbound, flow->loopback,
/*impostor=*/FALSE, /*final=*/FALSE, match, timestamp);
/*impostor=*/FALSE, match, timestamp);
}
windivert_flow_delete_notify_exit:
@@ -3902,7 +3974,8 @@ static void windivert_socket_classify(context_t context,
result->actionType = FWP_ACTION_CONTINUE;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
context->shutdown_recv)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
return;
@@ -3921,7 +3994,7 @@ static void windivert_socket_classify(context_t context,
ok = windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_SOCKET,
(PVOID)socket_data, event, flags, /*priority=*/0, ipv4, outbound,
loopback, /*impostor=*/FALSE, /*final=*/FALSE, match, timestamp);
loopback, /*impostor=*/FALSE, match, timestamp);
if (!ok)
{
WdfObjectDereference(object);
@@ -3970,6 +4043,8 @@ VOID windivert_worker(IN WDFWORKITEM item)
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
}
KeReleaseInStackQueuedSpinLock(&lock_handle);
windivert_read_service(context);
}
/*
@@ -3978,8 +4053,8 @@ VOID windivert_worker(IN WDFWORKITEM item)
static BOOL windivert_queue_work(context_t context, PVOID packet,
ULONG packet_len, PNET_BUFFER_LIST buffers, WINDIVERT_LAYER layer,
PVOID layer_data, WINDIVERT_EVENT event, UINT64 flags, UINT32 priority,
BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, BOOL final,
BOOL match, LONGLONG timestamp)
BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, BOOL match,
LONGLONG timestamp)
{
KLOCK_QUEUE_HANDLE lock_handle;
PNET_BUFFER buffer;
@@ -4115,7 +4190,6 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
work->pseudo_ip_checksum = (pseudo_ip_checksum? 1: 0);
work->pseudo_tcp_checksum = (pseudo_tcp_checksum? 1: 0);
work->pseudo_udp_checksum = (pseudo_udp_checksum? 1: 0);
work->final = (final? 1: 0);
work->match = match;
work->priority = priority;
work->timestamp = timestamp;
@@ -4128,6 +4202,16 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
windivert_free_packet(work);
return FALSE;
}
if (context->shutdown_recv && context->shutdown_recv_enabled)
{
if ((flags & WINDIVERT_FLAG_SNIFF) != 0)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
windivert_free_packet(work);
return FALSE;
}
work->match = FALSE;
}
context->work_queue_length++;
if (context->work_queue_length > WINDIVERT_WORK_QUEUE_LEN_MAX)
{
@@ -4214,9 +4298,6 @@ static void windivert_queue_packet(context_t context, packet_t packet)
DEBUG("PACKET: queued packet (packet=%p)", packet);
// Service any pending I/O request.
windivert_read_service(context);
return;
}
@@ -5541,8 +5622,7 @@ static const WINDIVERT_FILTER *windivert_filter_compile(
}
break;
case WINDIVERT_LAYER_REFLECT:
if (event != WINDIVERT_EVENT_REFLECT_ESTABLISHED &&
event != WINDIVERT_EVENT_REFLECT_OPEN &&
if (event != WINDIVERT_EVENT_REFLECT_OPEN &&
event != WINDIVERT_EVENT_REFLECT_CLOSE)
{
goto windivert_filter_compile_error;
@@ -5846,7 +5926,7 @@ static void windivert_reflect_event_notify(context_t context,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT,
(PVOID)&context->reflect.data, event, /*flags=*/0, /*priority=*/0,
/*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE,
/*impostor=*/FALSE, /*final=*/FALSE, /*match=*/TRUE, timestamp);
/*impostor=*/FALSE, /*match=*/TRUE, timestamp);
}
}
@@ -5858,13 +5938,18 @@ static void windivert_reflect_established_notify(context_t context,
{
KLOCK_QUEUE_HANDLE lock_handle;
PLIST_ENTRY entry;
BOOL match, ok, final;
BOOL match, ok;
context_t waiter;
const WINDIVERT_FILTER *filter;
PWINDIVERT_IPHDR packet;
ULONG packet_len;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
return;
}
filter = context->filter;
KeReleaseInStackQueuedSpinLock(&lock_handle);
@@ -5875,26 +5960,36 @@ static void windivert_reflect_established_notify(context_t context,
entry = entry->Flink;
match = windivert_filter(/*buffer=*/NULL,
/*layer=*/WINDIVERT_LAYER_REFLECT, (PVOID)&waiter->reflect.data,
/*event=*/WINDIVERT_EVENT_REFLECT_ESTABLISHED, /*ipv4=*/TRUE,
/*event=*/WINDIVERT_EVENT_REFLECT_OPEN, /*ipv4=*/TRUE,
/*outbound=*/FALSE, /*loopback=*/FALSE, /*impostor=*/FALSE, filter);
if (!match)
{
continue;
}
packet = windivert_reflect_pseudo_packet(waiter, &packet_len);
final = (entry == &reflect_contexts);
ok = windivert_queue_work(context, (PVOID)packet, packet_len,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT,
(PVOID)&waiter->reflect.data,
/*event=*/WINDIVERT_EVENT_REFLECT_ESTABLISHED, /*flags=*/0,
/*event=*/WINDIVERT_EVENT_REFLECT_OPEN, /*flags=*/0,
/*priority=*/0, /*ipv4=*/TRUE, /*outbound=*/FALSE,
/*loopback=*/FALSE, /*impostor=*/FALSE, final, /*match=*/TRUE,
timestamp);
/*loopback=*/FALSE, /*impostor=*/FALSE, /*match=*/TRUE, timestamp);
if (!ok)
{
break;
}
}
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
return;
}
// REFLECT layer shutdown is disabled until all previously open handles
// have been queued.
context->shutdown_recv_enabled = TRUE;
KeReleaseInStackQueuedSpinLock(&lock_handle);
windivert_read_service(context);
}
/*