Optimize based on event expressions.
E.g., if "event == CONNECT" then do not install a callout for LISTEN, etc.
This commit is contained in:
+1
-1
@@ -404,7 +404,7 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
filter_flags = WinDivertAnalyzeFilter(object, obj_len);
|
||||
filter_flags = WinDivertAnalyzeFilter(layer, object, obj_len);
|
||||
|
||||
// Attempt to open the WinDivert device:
|
||||
handle = CreateFile(L"\\\\.\\" WINDIVERT_DEVICE_NAME,
|
||||
|
||||
+66
-30
@@ -1960,7 +1960,8 @@ static void WinDivertEmitFilter(PEXPR *stack, UINT len, UINT16 label,
|
||||
/*
|
||||
* Analyze a filter object.
|
||||
*/
|
||||
static UINT64 WinDivertAnalyzeFilter(PWINDIVERT_FILTER filter, UINT length)
|
||||
static UINT64 WinDivertAnalyzeFilter(WINDIVERT_LAYER layer,
|
||||
PWINDIVERT_FILTER filter, UINT length)
|
||||
{
|
||||
BOOL result;
|
||||
UINT64 flags = 0;
|
||||
@@ -1973,45 +1974,80 @@ static UINT64 WinDivertAnalyzeFilter(PWINDIVERT_FILTER filter, UINT length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Inbound?
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_INBOUND, 1);
|
||||
if (result)
|
||||
if (layer == WINDIVERT_LAYER_NETWORK ||
|
||||
layer == WINDIVERT_LAYER_NETWORK_FORWARD)
|
||||
{
|
||||
// Inbound?
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_OUTBOUND, 0);
|
||||
}
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_INBOUND: 0);
|
||||
WINDIVERT_FILTER_FIELD_INBOUND, 1);
|
||||
if (result)
|
||||
{
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_OUTBOUND, 0);
|
||||
}
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_INBOUND: 0);
|
||||
|
||||
// Outbound?
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_OUTBOUND, 1);
|
||||
if (result)
|
||||
// Outbound?
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_OUTBOUND, 1);
|
||||
if (result)
|
||||
{
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_INBOUND, 0);
|
||||
}
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_OUTBOUND: 0);
|
||||
}
|
||||
|
||||
if (layer != WINDIVERT_LAYER_REFLECT)
|
||||
{
|
||||
// IPv4?
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_INBOUND, 0);
|
||||
}
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_OUTBOUND: 0);
|
||||
WINDIVERT_FILTER_FIELD_IP, 1);
|
||||
if (result)
|
||||
{
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_IPV6, 0);
|
||||
}
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_IP: 0);
|
||||
|
||||
// IPv4?
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_IP, 1);
|
||||
if (result)
|
||||
{
|
||||
// Ipv6?
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_IPV6, 0);
|
||||
WINDIVERT_FILTER_FIELD_IPV6, 1);
|
||||
if (result)
|
||||
{
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_IP, 0);
|
||||
}
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_IPV6: 0);
|
||||
}
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_IP: 0);
|
||||
|
||||
// Ipv6?
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_IPV6, 1);
|
||||
if (result)
|
||||
{
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_IP, 0);
|
||||
// Events:
|
||||
switch (layer)
|
||||
{
|
||||
case WINDIVERT_LAYER_FLOW:
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_FLOW_DELETED);
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_FLOW_DELETED: 0);
|
||||
break;
|
||||
|
||||
case WINDIVERT_LAYER_SOCKET:
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_BIND);
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND: 0);
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_CONNECT);
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT: 0);
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_LISTEN);
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN: 0);
|
||||
result = WinDivertCondExecFilter(filter, length,
|
||||
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_ACCEPT);
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT: 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
flags |= (result? WINDIVERT_FILTER_FLAG_IPV6: 0);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
@@ -192,10 +192,20 @@
|
||||
#define WINDIVERT_FILTER_FLAG_OUTBOUND 0x0000000000000002ull
|
||||
#define WINDIVERT_FILTER_FLAG_IP 0x0000000000000004ull
|
||||
#define WINDIVERT_FILTER_FLAG_IPV6 0x0000000000000008ull
|
||||
#define WINDIVERT_FILTER_FLAG_EVENT_FLOW_DELETED 0x0000000000000010ull
|
||||
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND 0x0000000000000020ull
|
||||
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT 0x0000000000000040ull
|
||||
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN 0x0000000000000080ull
|
||||
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT 0x0000000000000100ull
|
||||
|
||||
#define WINDIVERT_FILTER_FLAGS_ALL \
|
||||
(WINDIVERT_FILTER_FLAG_INBOUND | WINDIVERT_FILTER_FLAG_OUTBOUND | \
|
||||
WINDIVERT_FILTER_FLAG_IP | WINDIVERT_FILTER_FLAG_IPV6)
|
||||
WINDIVERT_FILTER_FLAG_IP | WINDIVERT_FILTER_FLAG_IPV6 | \
|
||||
WINDIVERT_FILTER_FLAG_EVENT_FLOW_DELETED | \
|
||||
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND | \
|
||||
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT | \
|
||||
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN | \
|
||||
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT)
|
||||
|
||||
/*
|
||||
* WinDivert priorities.
|
||||
|
||||
+42
-9
@@ -170,7 +170,8 @@ struct context_s
|
||||
BOOL installed[WINDIVERT_CONTEXT_MAXLAYERS];// What is installed?
|
||||
HANDLE engine_handle; // WFP engine handle.
|
||||
const WINDIVERT_FILTER *filter; // Packet filter.
|
||||
UINT8 filter_len; // Length of filter.
|
||||
UINT16 filter_len; // Length of filter.
|
||||
UINT64 filter_flags; // Filter flags.
|
||||
struct reflect_context_s reflect; // Reflection info.
|
||||
};
|
||||
typedef struct context_s context_s;
|
||||
@@ -1264,6 +1265,8 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
|
||||
context->shutdown_send = FALSE;
|
||||
context->priority = windivert_context_priority(WINDIVERT_PRIORITY_DEFAULT);
|
||||
context->filter = NULL;
|
||||
context->filter_len = 0;
|
||||
context->filter_flags = 0;
|
||||
context->worker = NULL;
|
||||
for (i = 0; i < WINDIVERT_CONTEXT_MAXLAYERS; i++)
|
||||
{
|
||||
@@ -1351,13 +1354,17 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
|
||||
UINT8 i, j;
|
||||
layer_t layers[WINDIVERT_CONTEXT_MAXLAYERS];
|
||||
UINT32 *callout_ids[WINDIVERT_CONTEXT_MAXLAYERS] = {NULL};
|
||||
BOOL inbound, outbound, ipv4, ipv6;
|
||||
BOOL inbound, outbound, ipv4, ipv6, bind, connect, listen, accept;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
inbound = ((flags & WINDIVERT_FILTER_FLAG_INBOUND) != 0);
|
||||
outbound = ((flags & WINDIVERT_FILTER_FLAG_OUTBOUND) != 0);
|
||||
ipv4 = ((flags & WINDIVERT_FILTER_FLAG_IP) != 0);
|
||||
ipv6 = ((flags & WINDIVERT_FILTER_FLAG_IPV6) != 0);
|
||||
bind = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND) != 0);
|
||||
connect = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT) != 0);
|
||||
listen = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN) != 0);
|
||||
accept = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT) != 0);
|
||||
|
||||
i = 0;
|
||||
switch (layer)
|
||||
@@ -1406,18 +1413,36 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
|
||||
break;
|
||||
|
||||
case WINDIVERT_LAYER_SOCKET:
|
||||
if (ipv4)
|
||||
if (ipv4 && bind)
|
||||
{
|
||||
layers[i++] = WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4;
|
||||
}
|
||||
if (ipv4 && connect)
|
||||
{
|
||||
layers[i++] = WINDIVERT_LAYER_AUTH_CONNECT_IPV4;
|
||||
}
|
||||
if (ipv4 && listen)
|
||||
{
|
||||
layers[i++] = WINDIVERT_LAYER_AUTH_LISTEN_IPV4;
|
||||
}
|
||||
if (ipv4 && accept)
|
||||
{
|
||||
layers[i++] = WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4;
|
||||
}
|
||||
if (ipv6)
|
||||
if (ipv6 && bind)
|
||||
{
|
||||
layers[i++] = WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6;
|
||||
}
|
||||
if (ipv6 && connect)
|
||||
{
|
||||
layers[i++] = WINDIVERT_LAYER_AUTH_CONNECT_IPV6;
|
||||
}
|
||||
if (ipv6 && listen)
|
||||
{
|
||||
layers[i++] = WINDIVERT_LAYER_AUTH_LISTEN_IPV6;
|
||||
}
|
||||
if (ipv6 && accept)
|
||||
{
|
||||
layers[i++] = WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6;
|
||||
}
|
||||
break;
|
||||
@@ -2750,6 +2775,7 @@ windivert_ioctl_bad_start_state:
|
||||
}
|
||||
context->filter = filter;
|
||||
context->filter_len = filter_len;
|
||||
context->filter_flags = filter_flags;
|
||||
context->reflect.data.Timestamp = timestamp;
|
||||
context->reflect.data.ProcessId = process_id;
|
||||
context->reflect.data.Layer = context->layer;
|
||||
@@ -3507,7 +3533,7 @@ static void windivert_flow_established_classify(context_t context,
|
||||
IN BOOL outbound, IN BOOL loopback, OUT FWPS_CLASSIFY_OUT0 *result)
|
||||
{
|
||||
KLOCK_QUEUE_HANDLE lock_handle;
|
||||
UINT64 flags;
|
||||
UINT64 flags, filter_flags;
|
||||
UINT32 callout_id;
|
||||
UINT16 layer_id;
|
||||
BOOL match, ok;
|
||||
@@ -3537,6 +3563,7 @@ static void windivert_flow_established_classify(context_t context,
|
||||
}
|
||||
filter = context->filter;
|
||||
flags = context->flags;
|
||||
filter_flags = context->filter_flags;
|
||||
callout_id = (ipv4? context->flow_v4_callout_id:
|
||||
context->flow_v6_callout_id);
|
||||
object = (WDFOBJECT)context->object;
|
||||
@@ -3564,8 +3591,14 @@ static void windivert_flow_established_classify(context_t context,
|
||||
}
|
||||
}
|
||||
|
||||
// Associate a context with the flow. This is so we can detect when
|
||||
// the flow is deleted.
|
||||
// Associate a context with the flow. This is so we can detect the
|
||||
// FLOW_DELETED event.
|
||||
if ((filter_flags & WINDIVERT_FILTER_FLAG_EVENT_FLOW_DELETED) == 0)
|
||||
{
|
||||
// We don't care about FLOW_DELETED.
|
||||
WdfObjectDereference(object);
|
||||
return;
|
||||
}
|
||||
flow = windivert_malloc(sizeof(struct flow_s), FALSE);
|
||||
if (flow == NULL)
|
||||
{
|
||||
@@ -5879,7 +5912,7 @@ static PWINDIVERT_IPHDR windivert_reflect_pseudo_packet(context_t context,
|
||||
UINT8 *packet;
|
||||
char *object;
|
||||
const WINDIVERT_FILTER *filter;
|
||||
UINT8 filter_len;
|
||||
UINT16 filter_len;
|
||||
PWINDIVERT_IPHDR iphdr;
|
||||
WINDIVERT_STREAM stream;
|
||||
|
||||
@@ -5901,7 +5934,7 @@ static PWINDIVERT_IPHDR windivert_reflect_pseudo_packet(context_t context,
|
||||
filter_len = context->filter_len;
|
||||
KeReleaseInStackQueuedSpinLock(&lock_handle);
|
||||
|
||||
WinDivertSerializeFilter(&stream, filter, filter_len);
|
||||
WinDivertSerializeFilter(&stream, filter, (UINT8)filter_len);
|
||||
|
||||
total_len = sizeof(WINDIVERT_IPHDR) + (UINT16)stream.pos;
|
||||
RtlZeroMemory(iphdr, sizeof(WINDIVERT_IPHDR));
|
||||
|
||||
Reference in New Issue
Block a user