Optimize based on event expressions.

E.g., if "event == CONNECT" then do not install
a callout for LISTEN, etc.
This commit is contained in:
basil00
2018-11-15 07:58:44 +08:00
parent 67ad628a1f
commit edbe5ea942
4 changed files with 120 additions and 41 deletions
+1 -1
View File
@@ -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
View File
@@ -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;
}
+11 -1
View File
@@ -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
View File
@@ -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));