WinDivert filter language improvements.
- Add "length" for total packet length. - Add "timestamp" for timestamp filtering. - All filter language numbers are now signed. - Add new macros: TRUE, FALSE, TCP, UDP, ICMP & ICMPV6. - Future-proof the WINDIVERT_FILTER struct.
This commit is contained in:
@@ -186,7 +186,10 @@ WinDivert 2.0.0-rc
|
||||
operation occurred.
|
||||
- The WinDivert filter language has been expanded with new fields:
|
||||
* event: The event value.
|
||||
* processId: (FLOW/SOCKET/REFLECT layers) the process Id.
|
||||
* timestamp: The event timestamp.
|
||||
* endpointId: (FLOW/SOCKET layers) the endpoint ID.
|
||||
* parentEndpointId: (FLOW/SOCKET layers) the parent endpoint ID.
|
||||
* processId: (FLOW/SOCKET/REFLECT layers) the process ID.
|
||||
* localAddr: (NETWORK/NETWORK_FORWARD/FLOW/SOCKET layers) the local
|
||||
address.
|
||||
* localPort: (NETWORK/NETWORK_FORWARD/FLOW/SOCKET layers) the local
|
||||
@@ -204,6 +207,7 @@ WinDivert 2.0.0-rc
|
||||
number.
|
||||
* random32: (NETWORK/NETWORK_FORWARD layers) a 32-bit pseudo random
|
||||
number.
|
||||
* length: (NETWORK/NETWORK_FORWARD layers) the packet length.
|
||||
* zero: The value "0".
|
||||
- The WinDivert filter language can now address packet/payload data for
|
||||
the NETWORK/NETWORK_FORWARD layers:
|
||||
@@ -241,6 +245,12 @@ WinDivert 2.0.0-rc
|
||||
* FLOW: (REFLECT layer) equal to WINDIVERT_LAYER_FLOW.
|
||||
* SOCKET: (REFLECT layer) equal to WINDIVERT_LAYER_SOCKET.
|
||||
* REFLECT: (REFLECT layer) equal to WINDIVERT_LAYER_REFLECT.
|
||||
* TRUE: equal to 1.
|
||||
* FALSE: equal to 0.
|
||||
* TCP: equal to IPPROTO_TCP (6).
|
||||
* UDP: equal to IPPROTO_UDP (17).
|
||||
* ICMP: equal to IPPROTO_ICMP (1).
|
||||
* ICMPV6: equal to IPPROTO_ICMPV6 (58).
|
||||
- WinDivertOpen() now supports several new flags:
|
||||
* WINDIVERT_FLAG_RECV_ONLY/WINDIVERT_FLAG_READ_ONLY: The handle cannot
|
||||
be used for send operations.
|
||||
|
||||
+14
-1
@@ -386,7 +386,20 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
|
||||
WINDIVERT_IOCTL ioctl;
|
||||
WINDIVERT_VERSION version;
|
||||
|
||||
// Parameter checking.
|
||||
// Static checks (should be compiled away if TRUE):
|
||||
if (sizeof(WINDIVERT_ADDRESS) != 80 ||
|
||||
sizeof(WINDIVERT_DATA_NETWORK) != 8 ||
|
||||
offsetof(WINDIVERT_DATA_FLOW, Protocol) != 56 ||
|
||||
offsetof(WINDIVERT_DATA_SOCKET, Protocol) != 56 ||
|
||||
offsetof(WINDIVERT_DATA_REFLECT, Priority) != 24 ||
|
||||
sizeof(WINDIVERT_FILTER) != 24 ||
|
||||
offsetof(WINDIVERT_ADDRESS, Reserved2) != 16)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
// Parameter checking:
|
||||
switch (layer)
|
||||
{
|
||||
case WINDIVERT_LAYER_NETWORK:
|
||||
|
||||
+214
-82
@@ -122,6 +122,8 @@ typedef enum
|
||||
TOKEN_PACKET,
|
||||
TOKEN_PACKET16,
|
||||
TOKEN_PACKET32,
|
||||
TOKEN_LENGTH,
|
||||
TOKEN_TIMESTAMP,
|
||||
TOKEN_TRUE,
|
||||
TOKEN_FALSE,
|
||||
TOKEN_INBOUND,
|
||||
@@ -154,6 +156,12 @@ typedef enum
|
||||
TOKEN_EVENT_ACCEPT,
|
||||
TOKEN_EVENT_OPEN,
|
||||
TOKEN_EVENT_CLOSE,
|
||||
TOKEN_MACRO_TRUE,
|
||||
TOKEN_MACRO_FALSE,
|
||||
TOKEN_MACRO_TCP,
|
||||
TOKEN_MACRO_UDP,
|
||||
TOKEN_MACRO_ICMP,
|
||||
TOKEN_MACRO_ICMPV6,
|
||||
TOKEN_OPEN,
|
||||
TOKEN_CLOSE,
|
||||
TOKEN_SQUARE_OPEN,
|
||||
@@ -285,7 +293,8 @@ static PEXPR WinDivertParseFilter(HANDLE pool, TOKEN *toks, UINT *i,
|
||||
INT depth, BOOL and, PERROR error);
|
||||
static BOOL WinDivertCondExecFilter(PWINDIVERT_FILTER filter, UINT length,
|
||||
UINT8 field, UINT32 arg);
|
||||
static int WinDivertBigNumCompare(const UINT32 *a, const UINT32 *b, BOOL big);
|
||||
static int WinDivertCompare128(BOOL neg_a, const UINT32 *a, BOOL neg_b,
|
||||
const UINT32 *b, BOOL big);
|
||||
static BOOL WinDivertDeserializeFilter(PWINDIVERT_STREAM stream,
|
||||
PWINDIVERT_FILTER filter, UINT *length);
|
||||
static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
|
||||
@@ -545,6 +554,24 @@ static BOOL WinDivertExpandMacro(KIND kind, WINDIVERT_LAYER layer,
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
case TOKEN_MACRO_TRUE:
|
||||
*val = 1;
|
||||
return TRUE;
|
||||
case TOKEN_MACRO_FALSE:
|
||||
*val = 0;
|
||||
return TRUE;
|
||||
case TOKEN_MACRO_TCP:
|
||||
*val = IPPROTO_TCP;
|
||||
return TRUE;
|
||||
case TOKEN_MACRO_UDP:
|
||||
*val = IPPROTO_UDP;
|
||||
return TRUE;
|
||||
case TOKEN_MACRO_ICMP:
|
||||
*val = IPPROTO_ICMP;
|
||||
return TRUE;
|
||||
case TOKEN_MACRO_ICMPV6:
|
||||
*val = IPPROTO_ICMPV6;
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
@@ -564,7 +591,10 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
|
||||
{"CONNECT", TOKEN_EVENT_CONNECT, L___S_},
|
||||
{"DELETED", TOKEN_EVENT_DELETED, L__F__},
|
||||
{"ESTABLISHED", TOKEN_EVENT_ESTABLISHED, L__F__},
|
||||
{"FALSE", TOKEN_MACRO_FALSE, LNMFSR},
|
||||
{"FLOW", TOKEN_FLOW, L____R},
|
||||
{"ICMP", TOKEN_MACRO_ICMP, LNMFSR},
|
||||
{"ICMPV6", TOKEN_MACRO_ICMPV6, LNMFSR},
|
||||
{"LISTEN", TOKEN_EVENT_LISTEN, L___S_},
|
||||
{"NETWORK", TOKEN_NETWORK, L____R},
|
||||
{"NETWORK_FORWARD", TOKEN_NETWORK_FORWARD, L____R},
|
||||
@@ -572,6 +602,9 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
|
||||
{"PACKET", TOKEN_EVENT_PACKET, LNM___},
|
||||
{"REFLECT", TOKEN_REFLECT, L____R},
|
||||
{"SOCKET", TOKEN_SOCKET, L____R},
|
||||
{"TCP", TOKEN_MACRO_TCP, LNMFSR},
|
||||
{"TRUE", TOKEN_MACRO_TRUE, LNMFSR},
|
||||
{"UDP", TOKEN_MACRO_UDP, LNMFSR},
|
||||
{"and", TOKEN_AND, LNMFSR},
|
||||
{"endpointId", TOKEN_ENDPOINT_ID, L__FS_},
|
||||
{"event", TOKEN_EVENT, LNMFSR},
|
||||
@@ -611,6 +644,7 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
|
||||
{"ipv6.SrcAddr", TOKEN_IPV6_SRC_ADDR, LNM___},
|
||||
{"ipv6.TrafficClass", TOKEN_IPV6_TRAFFIC_CLASS, LNM___},
|
||||
{"layer", TOKEN_LAYER, L____R},
|
||||
{"length", TOKEN_LENGTH, LNM___},
|
||||
{"localAddr", TOKEN_LOCAL_ADDR, LN_FS_},
|
||||
{"localPort", TOKEN_LOCAL_PORT, LN_FS_},
|
||||
{"loopback", TOKEN_LOOPBACK, LN_FS_},
|
||||
@@ -649,6 +683,7 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
|
||||
{"tcp.Urg", TOKEN_TCP_URG, LNM___},
|
||||
{"tcp.UrgPtr", TOKEN_TCP_URG_PTR, LNM___},
|
||||
{"tcp.Window", TOKEN_TCP_WINDOW, LNM___},
|
||||
{"timestamp", TOKEN_TIMESTAMP, LNMFSR},
|
||||
{"true", TOKEN_TRUE, LNMFSR},
|
||||
{"udp", TOKEN_UDP, LNMFS_},
|
||||
{"udp.Checksum", TOKEN_UDP_CHECKSUM, LNM___},
|
||||
@@ -947,6 +982,8 @@ static PEXPR WinDivertMakeVar(KIND kind, PERROR error)
|
||||
{{{0}}, TOKEN_RANDOM8},
|
||||
{{{0}}, TOKEN_RANDOM16},
|
||||
{{{0}}, TOKEN_RANDOM32},
|
||||
{{{0}}, TOKEN_LENGTH},
|
||||
{{{0}}, TOKEN_TIMESTAMP},
|
||||
{{{0}}, TOKEN_TRUE},
|
||||
{{{0}}, TOKEN_FALSE},
|
||||
{{{0}}, TOKEN_INBOUND},
|
||||
@@ -1082,7 +1119,7 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error)
|
||||
{
|
||||
PEXPR var, val;
|
||||
KIND kind;
|
||||
BOOL not = FALSE, neg, priority = FALSE;
|
||||
BOOL not = FALSE, neg;
|
||||
UINT idx, size;
|
||||
while (toks[*i].kind == TOKEN_NOT)
|
||||
{
|
||||
@@ -1091,9 +1128,8 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error)
|
||||
}
|
||||
switch (toks[*i].kind)
|
||||
{
|
||||
case TOKEN_TIMESTAMP:
|
||||
case TOKEN_PRIORITY:
|
||||
priority = TRUE;
|
||||
/* fallthough */
|
||||
case TOKEN_ZERO:
|
||||
case TOKEN_EVENT:
|
||||
case TOKEN_RANDOM8:
|
||||
@@ -1121,6 +1157,7 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error)
|
||||
case TOKEN_PROTOCOL:
|
||||
case TOKEN_ENDPOINT_ID:
|
||||
case TOKEN_PARENT_ENDPOINT_ID:
|
||||
case TOKEN_LENGTH:
|
||||
case TOKEN_LAYER:
|
||||
case TOKEN_IP_HDR_LENGTH:
|
||||
case TOKEN_IP_TOS:
|
||||
@@ -1285,7 +1322,7 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error)
|
||||
}
|
||||
*i = *i + 1;
|
||||
neg = FALSE;
|
||||
if (priority && toks[*i].kind == TOKEN_MINUS)
|
||||
if (toks[*i].kind == TOKEN_MINUS)
|
||||
{
|
||||
neg = TRUE;
|
||||
*i = *i + 1;
|
||||
@@ -1304,8 +1341,8 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error)
|
||||
/*
|
||||
* Parse a filter argument to an (and) (or) operator.
|
||||
*/
|
||||
static PEXPR WinDivertParseArg(HANDLE pool, TOKEN *toks, UINT *i, INT depth,
|
||||
PERROR error)
|
||||
static PEXPR WinDivertParseAndOrArg(HANDLE pool, TOKEN *toks, UINT *i,
|
||||
INT depth, PERROR error)
|
||||
{
|
||||
PEXPR arg, th, el;
|
||||
if (depth-- < 0)
|
||||
@@ -1373,7 +1410,7 @@ static PEXPR WinDivertParseFilter(HANDLE pool, TOKEN *toks, UINT *i, INT depth,
|
||||
return NULL;
|
||||
}
|
||||
if (and)
|
||||
expr = WinDivertParseArg(pool, toks, i, depth, error);
|
||||
expr = WinDivertParseAndOrArg(pool, toks, i, depth, error);
|
||||
else
|
||||
expr = WinDivertParseFilter(pool, toks, i, depth, TRUE, error);
|
||||
do
|
||||
@@ -1386,7 +1423,7 @@ static PEXPR WinDivertParseFilter(HANDLE pool, TOKEN *toks, UINT *i, INT depth,
|
||||
{
|
||||
case TOKEN_AND:
|
||||
*i = *i + 1;
|
||||
arg = WinDivertParseArg(pool, toks, i, depth, error);
|
||||
arg = WinDivertParseAndOrArg(pool, toks, i, depth, error);
|
||||
expr = WinDivertMakeBinOp(pool, TOKEN_AND, expr, arg, error);
|
||||
continue;
|
||||
case TOKEN_OR:
|
||||
@@ -1408,6 +1445,7 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
|
||||
{
|
||||
PEXPR var = test->arg[0];
|
||||
PEXPR val = test->arg[1];
|
||||
BOOL neg_lb = FALSE, neg_ub = FALSE, neg;
|
||||
UINT32 lb[4] = {0}, ub[4] = {0};
|
||||
int result_lb, result_ub;
|
||||
BOOL eq = FALSE;
|
||||
@@ -1427,7 +1465,8 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
|
||||
lb[0] = 0; ub[0] = WINDIVERT_LAYER_MAX;
|
||||
break;
|
||||
case TOKEN_PRIORITY:
|
||||
lb[0] = 0; ub[0] = WINDIVERT_PRIORITY_MAX;
|
||||
neg_lb = TRUE;
|
||||
lb[0] = ub[0] = WINDIVERT_PRIORITY_MAX;
|
||||
break;
|
||||
case TOKEN_EVENT:
|
||||
lb[0] = 0; ub[0] = WINDIVERT_EVENT_MAX;
|
||||
@@ -1499,6 +1538,9 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
|
||||
case TOKEN_RANDOM16:
|
||||
lb[0] = 0; ub[0] = 0xFFFF;
|
||||
break;
|
||||
case TOKEN_LENGTH:
|
||||
lb[0] = sizeof(WINDIVERT_IPHDR); ub[0] = WINDIVERT_MTU_MAX;
|
||||
break;
|
||||
case TOKEN_IPV6_FLOW_LABEL:
|
||||
lb[0] = 0; ub[0] = 0x000FFFFF;
|
||||
break;
|
||||
@@ -1516,6 +1558,13 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
|
||||
lb[0] = lb[1] = lb[2] = lb[3] = 0;
|
||||
ub[0] = ub[1] = ub[2] = ub[3] = 0xFFFFFFFF;
|
||||
break;
|
||||
case TOKEN_TIMESTAMP:
|
||||
lb[0] = 0;
|
||||
lb[1] = 0x80000000;
|
||||
ub[0] = 0xFFFFFFFF;
|
||||
ub[1] = 0x7FFFFFFF;
|
||||
neg_lb = TRUE;
|
||||
break;
|
||||
case TOKEN_ENDPOINT_ID:
|
||||
case TOKEN_PARENT_ENDPOINT_ID:
|
||||
lb[0] = lb[1] = 0;
|
||||
@@ -1525,8 +1574,9 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
|
||||
lb[0] = 0; ub[0] = 0xFFFFFFFF;
|
||||
break;
|
||||
}
|
||||
result_lb = WinDivertBigNumCompare(val->val, lb, /*big=*/TRUE);
|
||||
result_ub = WinDivertBigNumCompare(val->val, ub, /*big=*/TRUE);
|
||||
neg = (val->neg? TRUE: FALSE);
|
||||
result_lb = WinDivertCompare128(neg, val->val, neg_lb, lb, /*big=*/TRUE);
|
||||
result_ub = WinDivertCompare128(neg, val->val, neg_ub, ub, /*big=*/TRUE);
|
||||
switch (test->kind)
|
||||
{
|
||||
case TOKEN_EQ:
|
||||
@@ -1718,6 +1768,13 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
|
||||
object->field = WINDIVERT_FILTER_FIELD_PACKET32;
|
||||
object->arg[1] = var->val[0];
|
||||
break;
|
||||
case TOKEN_LENGTH:
|
||||
object->field = WINDIVERT_FILTER_FIELD_LENGTH;
|
||||
break;
|
||||
case TOKEN_TIMESTAMP:
|
||||
big = TRUE;
|
||||
object->field = WINDIVERT_FILTER_FIELD_TIMESTAMP;
|
||||
break;
|
||||
case TOKEN_TCP_PAYLOAD:
|
||||
object->field = WINDIVERT_FILTER_FIELD_TCP_PAYLOAD;
|
||||
object->arg[1] = var->val[0];
|
||||
@@ -1793,8 +1850,6 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
|
||||
break;
|
||||
case TOKEN_PRIORITY:
|
||||
object->field = WINDIVERT_FILTER_FIELD_PRIORITY;
|
||||
val0 = (val->neg? WINDIVERT_PRIORITY_MAX - val0:
|
||||
WINDIVERT_PRIORITY_MAX + val0);
|
||||
break;
|
||||
case TOKEN_IP:
|
||||
object->field = WINDIVERT_FILTER_FIELD_IP;
|
||||
@@ -1969,6 +2024,7 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
|
||||
object->arg[2] = val->val[2];
|
||||
object->arg[3] = val->val[3];
|
||||
}
|
||||
object->neg = (val->neg? 1: 0);
|
||||
switch (test->succ)
|
||||
{
|
||||
case WINDIVERT_FILTER_RESULT_ACCEPT:
|
||||
@@ -2003,10 +2059,13 @@ static void WinDivertEmitFilter(PEXPR *stack, UINT len, UINT16 label,
|
||||
{
|
||||
case WINDIVERT_FILTER_RESULT_ACCEPT:
|
||||
case WINDIVERT_FILTER_RESULT_REJECT:
|
||||
object[0].field = WINDIVERT_FILTER_FIELD_ZERO;
|
||||
object[0].test = WINDIVERT_FILTER_TEST_EQ;
|
||||
object[0].arg[0] = object[0].arg[1] = object[0].arg[2] =
|
||||
object[0].arg[3] = 0;
|
||||
object[0].field = WINDIVERT_FILTER_FIELD_ZERO;
|
||||
object[0].test = WINDIVERT_FILTER_TEST_EQ;
|
||||
object[0].neg = 0;
|
||||
object[0].arg[0] = 0;
|
||||
object[0].arg[1] = 0;
|
||||
object[0].arg[2] = 0;
|
||||
object[0].arg[3] = 0;
|
||||
object[0].success = label;
|
||||
object[0].failure = label;
|
||||
*obj_len = 1;
|
||||
@@ -2178,28 +2237,36 @@ static BOOL WinDivertCondExecFilter(PWINDIVERT_FILTER filter, UINT length,
|
||||
}
|
||||
else if (filter[ip].field == field)
|
||||
{
|
||||
switch (filter[ip].test)
|
||||
if (filter[ip].neg || filter[ip].arg[1] != 0 ||
|
||||
filter[ip].arg[2] != 0 || filter[ip].arg[3] != 0)
|
||||
{
|
||||
case WINDIVERT_FILTER_TEST_EQ:
|
||||
result_test = (arg == filter[ip].arg[0]);
|
||||
break;
|
||||
case WINDIVERT_FILTER_TEST_NEQ:
|
||||
result_test = (arg != filter[ip].arg[0]);
|
||||
break;
|
||||
case WINDIVERT_FILTER_TEST_LT:
|
||||
result_test = (arg < filter[ip].arg[0]);
|
||||
break;
|
||||
case WINDIVERT_FILTER_TEST_LEQ:
|
||||
result_test = (arg <= filter[ip].arg[0]);
|
||||
break;
|
||||
case WINDIVERT_FILTER_TEST_GT:
|
||||
result_test = (arg > filter[ip].arg[0]);
|
||||
break;
|
||||
case WINDIVERT_FILTER_TEST_GEQ:
|
||||
result_test = (arg >= filter[ip].arg[0]);
|
||||
break;
|
||||
default:
|
||||
return TRUE; // abort.
|
||||
result_test = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (filter[ip].test)
|
||||
{
|
||||
case WINDIVERT_FILTER_TEST_EQ:
|
||||
result_test = (arg == filter[ip].arg[0]);
|
||||
break;
|
||||
case WINDIVERT_FILTER_TEST_NEQ:
|
||||
result_test = (arg != filter[ip].arg[0]);
|
||||
break;
|
||||
case WINDIVERT_FILTER_TEST_LT:
|
||||
result_test = (arg < filter[ip].arg[0]);
|
||||
break;
|
||||
case WINDIVERT_FILTER_TEST_LEQ:
|
||||
result_test = (arg <= filter[ip].arg[0]);
|
||||
break;
|
||||
case WINDIVERT_FILTER_TEST_GT:
|
||||
result_test = (arg > filter[ip].arg[0]);
|
||||
break;
|
||||
case WINDIVERT_FILTER_TEST_GEQ:
|
||||
result_test = (arg >= filter[ip].arg[0]);
|
||||
break;
|
||||
default:
|
||||
return TRUE; // abort.
|
||||
}
|
||||
}
|
||||
result[ip] = (result_test? result_succ: result_fail);
|
||||
}
|
||||
@@ -2222,7 +2289,7 @@ static ERROR WinDivertCompileFilter(const char *filter,
|
||||
PEXPR *stack;
|
||||
HANDLE pool;
|
||||
PEXPR expr;
|
||||
UINT i, max_depth;
|
||||
UINT i, max_depth, pos;
|
||||
INT16 label;
|
||||
const SIZE_T min_pool_size = 8192;
|
||||
const SIZE_T tokens_size = 5 * WINDIVERT_FILTER_MAXLEN;
|
||||
@@ -2279,8 +2346,9 @@ static ERROR WinDivertCompileFilter(const char *filter,
|
||||
}
|
||||
if (tokens[i].kind != TOKEN_END)
|
||||
{
|
||||
pos = tokens[i].pos;
|
||||
HeapDestroy(pool);
|
||||
return MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, tokens[i].pos);
|
||||
return MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, pos);
|
||||
}
|
||||
|
||||
// Construct the filter tree:
|
||||
@@ -2391,42 +2459,53 @@ extern BOOL WinDivertHelperCompileFilter(const char *filter_str,
|
||||
/*
|
||||
* Big number comparison.
|
||||
*/
|
||||
static int WinDivertBigNumCompare(const UINT32 *a, const UINT32 *b, BOOL big)
|
||||
static int WinDivertCompare128(BOOL neg_a, const UINT32 *a, BOOL neg_b,
|
||||
const UINT32 *b, BOOL big)
|
||||
{
|
||||
int neg;
|
||||
if (neg_a && !neg_b)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (!neg_a && neg_b)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
neg = (neg_a? -1: 1);
|
||||
if (big)
|
||||
{
|
||||
if (a[3] < b[3])
|
||||
{
|
||||
return -1;
|
||||
return -neg;
|
||||
}
|
||||
if (a[3] > b[3])
|
||||
{
|
||||
return 1;
|
||||
return neg;
|
||||
}
|
||||
if (a[2] < b[2])
|
||||
{
|
||||
return -1;
|
||||
return -neg;
|
||||
}
|
||||
if (a[2] > b[2])
|
||||
{
|
||||
return 1;
|
||||
return neg;
|
||||
}
|
||||
if (a[1] < b[1])
|
||||
{
|
||||
return -1;
|
||||
return -neg;
|
||||
}
|
||||
if (a[1] > b[1])
|
||||
{
|
||||
return 1;
|
||||
return neg;
|
||||
}
|
||||
}
|
||||
if (a[0] < b[0])
|
||||
{
|
||||
return -1;
|
||||
return -neg;
|
||||
}
|
||||
if (a[0] > b[0])
|
||||
{
|
||||
return 1;
|
||||
return neg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -2470,6 +2549,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
|
||||
UINT8 protocol = 0;
|
||||
UINT header_len = 0, payload_len = 0;
|
||||
UINT64 random64 = 0;
|
||||
BOOL neg;
|
||||
UINT32 val[4];
|
||||
UINT8 data8;
|
||||
UINT16 data16;
|
||||
@@ -2553,6 +2633,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
|
||||
{
|
||||
case WINDIVERT_FILTER_FIELD_ZERO:
|
||||
case WINDIVERT_FILTER_FIELD_EVENT:
|
||||
case WINDIVERT_FILTER_FIELD_TIMESTAMP:
|
||||
pass = TRUE;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_INBOUND:
|
||||
@@ -2587,6 +2668,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
|
||||
case WINDIVERT_FILTER_FIELD_PACKET:
|
||||
case WINDIVERT_FILTER_FIELD_PACKET16:
|
||||
case WINDIVERT_FILTER_FIELD_PACKET32:
|
||||
case WINDIVERT_FILTER_FIELD_LENGTH:
|
||||
pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
|
||||
addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
|
||||
break;
|
||||
@@ -2699,6 +2781,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
|
||||
pc = object[pc].failure;
|
||||
continue;
|
||||
}
|
||||
neg = FALSE;
|
||||
switch (object[pc].field)
|
||||
{
|
||||
case WINDIVERT_FILTER_FIELD_ZERO:
|
||||
@@ -2711,9 +2794,12 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
|
||||
val[0] = addr->Reflect.Layer;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_PRIORITY:
|
||||
val[0] = (UINT32)((INT32)addr->Reflect.Layer +
|
||||
WINDIVERT_PRIORITY_MAX);
|
||||
{
|
||||
neg = (addr->Reflect.Priority < 0);
|
||||
val[0] = (UINT32)(neg? -addr->Reflect.Priority:
|
||||
addr->Reflect.Priority);
|
||||
break;
|
||||
}
|
||||
case WINDIVERT_FILTER_FIELD_RANDOM8:
|
||||
val[0] = (UINT32)((random64 >> 48) & 0xFF);
|
||||
break;
|
||||
@@ -2738,6 +2824,20 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
|
||||
object[pc].arg[1], sizeof(data32), &data32);
|
||||
val[0] = ntohl(data32);
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_LENGTH:
|
||||
val[0] = packet_len;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_TIMESTAMP:
|
||||
{
|
||||
UINT64 val64;
|
||||
neg = (addr->Timestamp < 0);
|
||||
val64 = (UINT64)(neg? -addr->Timestamp: addr->Timestamp);
|
||||
big = TRUE;
|
||||
val[0] = (UINT32)val64;
|
||||
val[1] = (UINT32)(val64 >> 32);
|
||||
val[2] = val[3] = 0;
|
||||
break;
|
||||
}
|
||||
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
|
||||
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
|
||||
pass = WinDivertGetData(packet, packet_len, header_len,
|
||||
@@ -3250,7 +3350,8 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
|
||||
pc = object[pc].failure;
|
||||
continue;
|
||||
}
|
||||
cmp = WinDivertBigNumCompare(val, object[pc].arg, big);
|
||||
cmp = WinDivertCompare128(neg, val, (object[pc].neg? TRUE: FALSE),
|
||||
object[pc].arg, big);
|
||||
switch (object[pc].test)
|
||||
{
|
||||
case WINDIVERT_FILTER_TEST_EQ:
|
||||
@@ -3372,6 +3473,34 @@ static BOOL WinDivertDeserializeNumber(PWINDIVERT_STREAM stream, UINT max_len,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deserialize a label.
|
||||
*/
|
||||
static BOOL WinDivertDeserializeLabel(PWINDIVERT_STREAM stream, UINT16 *label)
|
||||
{
|
||||
UINT32 val;
|
||||
|
||||
switch (WinDivertGetChar(stream))
|
||||
{
|
||||
case 'A':
|
||||
*label = WINDIVERT_FILTER_RESULT_ACCEPT;
|
||||
return TRUE;
|
||||
case 'X':
|
||||
*label = WINDIVERT_FILTER_RESULT_REJECT;
|
||||
return TRUE;
|
||||
case 'L':
|
||||
if (!WinDivertDeserializeNumber(stream, 2, &val) ||
|
||||
val > WINDIVERT_FILTER_MAXLEN)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
*label = (UINT16)val;
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deserialize a test.
|
||||
*/
|
||||
@@ -3391,14 +3520,20 @@ static BOOL WinDivertDeserializeTest(PWINDIVERT_STREAM stream,
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
filter->field = (UINT8)val;
|
||||
filter->field = (UINT16)val;
|
||||
|
||||
if (!WinDivertDeserializeNumber(stream, 2, &val) ||
|
||||
val > WINDIVERT_FILTER_TEST_MAX)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
filter->test = (UINT8)val;
|
||||
filter->test = (UINT16)val;
|
||||
|
||||
if (!WinDivertDeserializeNumber(stream, 1, &val) || val > 1)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
filter->neg = (UINT16)val;
|
||||
|
||||
if (!WinDivertDeserializeNumber(stream, 7, &filter->arg[0]))
|
||||
{
|
||||
@@ -3421,6 +3556,7 @@ static BOOL WinDivertDeserializeTest(PWINDIVERT_STREAM stream,
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_ENDPOINTID:
|
||||
case WINDIVERT_FILTER_FIELD_PARENTENDPOINTID:
|
||||
case WINDIVERT_FILTER_FIELD_TIMESTAMP:
|
||||
if (!WinDivertDeserializeNumber(stream, 7, &filter->arg[1]))
|
||||
{
|
||||
return FALSE;
|
||||
@@ -3453,18 +3589,11 @@ static BOOL WinDivertDeserializeTest(PWINDIVERT_STREAM stream,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!WinDivertDeserializeNumber(stream, 2, &val) || val > UINT8_MAX)
|
||||
if (!WinDivertDeserializeLabel(stream, &filter->success) ||
|
||||
!WinDivertDeserializeLabel(stream, &filter->failure))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
filter->success = (UINT8)val - 2;
|
||||
|
||||
if (!WinDivertDeserializeNumber(stream, 2, &val) || val > UINT8_MAX)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
filter->failure = (UINT8)val - 2;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -3582,6 +3711,10 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test)
|
||||
kind = TOKEN_PACKET16; break;
|
||||
case WINDIVERT_FILTER_FIELD_PACKET32:
|
||||
kind = TOKEN_PACKET32; break;
|
||||
case WINDIVERT_FILTER_FIELD_LENGTH:
|
||||
kind = TOKEN_LENGTH; break;
|
||||
case WINDIVERT_FILTER_FIELD_TIMESTAMP:
|
||||
kind = TOKEN_TIMESTAMP; break;
|
||||
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
|
||||
kind = TOKEN_TCP_PAYLOAD; break;
|
||||
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
|
||||
@@ -3771,6 +3904,10 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (test->neg)
|
||||
{
|
||||
val->neg = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3805,7 +3942,7 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test)
|
||||
/*
|
||||
* Dereference an expression.
|
||||
*/
|
||||
static void WinDivertDerefExpr(PEXPR *exprs, UINT8 i)
|
||||
static void WinDivertDerefExpr(PEXPR *exprs, UINT16 i)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
@@ -3826,7 +3963,7 @@ static void WinDivertDerefExpr(PEXPR *exprs, UINT8 i)
|
||||
* Apply an and/or simplification for WinDivertCoalesceAndOr().
|
||||
*/
|
||||
static PEXPR WinDivertSimplifyAndOr(HANDLE pool, PEXPR *exprs, PEXPR expr,
|
||||
BOOL and, UINT8 next, UINT8 other)
|
||||
BOOL and, UINT16 next, UINT16 other)
|
||||
{
|
||||
PEXPR next_expr = exprs[next], new_expr;
|
||||
ERROR error;
|
||||
@@ -3848,7 +3985,7 @@ static PEXPR WinDivertSimplifyAndOr(HANDLE pool, PEXPR *exprs, PEXPR expr,
|
||||
/*
|
||||
* Detect and coalesce and/or (& (?:)) expression patterns.
|
||||
*/
|
||||
static PEXPR WinDivertCoalesceAndOr(HANDLE pool, PEXPR *exprs, UINT8 i,
|
||||
static PEXPR WinDivertCoalesceAndOr(HANDLE pool, PEXPR *exprs, UINT16 i,
|
||||
ERROR *error)
|
||||
{
|
||||
PEXPR expr, next_expr, new_expr;
|
||||
@@ -3989,7 +4126,7 @@ static PEXPR WinDivertCoalesceAndOr(HANDLE pool, PEXPR *exprs, UINT8 i,
|
||||
/*
|
||||
* Coalesce all remaining expressions.
|
||||
*/
|
||||
static PEXPR WinDivertCoalesceExpr(HANDLE pool, PEXPR *exprs, UINT8 i)
|
||||
static PEXPR WinDivertCoalesceExpr(HANDLE pool, PEXPR *exprs, UINT16 i)
|
||||
{
|
||||
PEXPR expr, succ_expr, fail_expr, new_expr;
|
||||
static const EXPR true_expr = {{{0}}, TOKEN_TRUE};
|
||||
@@ -4226,7 +4363,7 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
|
||||
{
|
||||
PEXPR field = expr->arg[0], val = expr->arg[1];
|
||||
BOOL is_ipv4_addr = FALSE, is_ipv6_addr = FALSE, is_layer = FALSE,
|
||||
is_priority = FALSE, is_event = FALSE, is_hex = FALSE;
|
||||
is_event = FALSE, is_hex = FALSE;
|
||||
|
||||
switch (field->kind)
|
||||
{
|
||||
@@ -4283,9 +4420,6 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
|
||||
case TOKEN_LAYER:
|
||||
is_layer = TRUE;
|
||||
break;
|
||||
case TOKEN_PRIORITY:
|
||||
is_priority = TRUE;
|
||||
break;
|
||||
case TOKEN_EVENT:
|
||||
is_event = TRUE;
|
||||
break;
|
||||
@@ -4327,6 +4461,10 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
|
||||
case TOKEN_GEQ:
|
||||
WinDivertPutString(stream, " >= "); break;
|
||||
}
|
||||
if (val->neg)
|
||||
{
|
||||
WinDivertPutChar(stream, '-');
|
||||
}
|
||||
if (is_ipv4_addr)
|
||||
{
|
||||
WinDivertFormatIPv4Addr(stream, val->val[0]);
|
||||
@@ -4353,16 +4491,6 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
|
||||
WinDivertFormatDecNumber(stream, val->val[0]); break;
|
||||
}
|
||||
}
|
||||
else if (is_priority)
|
||||
{
|
||||
INT32 val32 = (INT32)val->val[0];
|
||||
val32 -= WINDIVERT_PRIORITY_MAX;
|
||||
if (val32 < 0)
|
||||
{
|
||||
WinDivertPutChar(stream, '-');
|
||||
}
|
||||
WinDivertFormatDecNumber(stream, (val32 < 0? -val32: val32));
|
||||
}
|
||||
else if (is_event)
|
||||
{
|
||||
switch (layer)
|
||||
@@ -4519,6 +4647,10 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
|
||||
WinDivertPutString(stream, "packet16"); break;
|
||||
case TOKEN_PACKET32:
|
||||
WinDivertPutString(stream, "packet32"); break;
|
||||
case TOKEN_LENGTH:
|
||||
WinDivertPutString(stream, "length"); return;
|
||||
case TOKEN_TIMESTAMP:
|
||||
WinDivertPutString(stream, "timestamp"); return;
|
||||
case TOKEN_TCP_PAYLOAD:
|
||||
WinDivertPutString(stream, "tcp.Payload"); break;
|
||||
case TOKEN_TCP_PAYLOAD16:
|
||||
|
||||
+25
-3
@@ -33,7 +33,7 @@
|
||||
*/
|
||||
|
||||
#define WINDIVERT_OBJECT_MAXLEN \
|
||||
(8 + 4 + 2 + WINDIVERT_FILTER_MAXLEN * (1 + 2 + 2 + 4*7 + 2 + 2) + 1)
|
||||
(8 + 4 + 2 + WINDIVERT_FILTER_MAXLEN * (1 + 1 + 2 + 2 + 4*7 + 3 + 3) + 1)
|
||||
|
||||
#define MAX(a, b) ((a) > (b)? (a): (b))
|
||||
|
||||
@@ -183,6 +183,26 @@ static void WinDivertSerializeNumber(PWINDIVERT_STREAM stream, UINT32 val)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize a label.
|
||||
*/
|
||||
static void WinDivertSerializeLabel(PWINDIVERT_STREAM stream, UINT16 label)
|
||||
{
|
||||
switch (label)
|
||||
{
|
||||
case WINDIVERT_FILTER_RESULT_ACCEPT:
|
||||
WinDivertPutChar(stream, 'A');
|
||||
break;
|
||||
case WINDIVERT_FILTER_RESULT_REJECT:
|
||||
WinDivertPutChar(stream, 'X');
|
||||
break;
|
||||
default:
|
||||
WinDivertPutChar(stream, 'L');
|
||||
WinDivertSerializeNumber(stream, label);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Serialize a test.
|
||||
*/
|
||||
@@ -195,6 +215,7 @@ static void WinDivertSerializeTest(PWINDIVERT_STREAM stream,
|
||||
WinDivertPutChar(stream, '_');
|
||||
WinDivertSerializeNumber(stream, filter->field);
|
||||
WinDivertSerializeNumber(stream, filter->test);
|
||||
WinDivertSerializeNumber(stream, filter->neg);
|
||||
WinDivertSerializeNumber(stream, filter->arg[0]);
|
||||
switch (filter->field)
|
||||
{
|
||||
@@ -209,6 +230,7 @@ static void WinDivertSerializeTest(PWINDIVERT_STREAM stream,
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_ENDPOINTID:
|
||||
case WINDIVERT_FILTER_FIELD_PARENTENDPOINTID:
|
||||
case WINDIVERT_FILTER_FIELD_TIMESTAMP:
|
||||
WinDivertSerializeNumber(stream, filter->arg[1]);
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_PACKET:
|
||||
@@ -227,8 +249,8 @@ static void WinDivertSerializeTest(PWINDIVERT_STREAM stream,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
WinDivertSerializeNumber(stream, (UINT8)(filter->success + 2));
|
||||
WinDivertSerializeNumber(stream, (UINT8)(filter->failure + 2));
|
||||
WinDivertSerializeLabel(stream, filter->success);
|
||||
WinDivertSerializeLabel(stream, filter->failure);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -2730,6 +2730,7 @@ The possible fields are:
|
||||
<tr><th>Field</th><th colspan="5">Layer</th><th>Description</th></tr>
|
||||
<tr><th></th><th><code>NETWORK</code></th><th><code>FORWARD</code></th><th><code>FLOW </code></th><th><code>SOCKET </code></th><th><code>REFLECT</code></th><th></th></tr>
|
||||
<tr><td><code>zero</code></td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>The value zero</td></tr>
|
||||
<tr><td><code>timestamp</code></td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>The packet/event timestamp</td></tr>
|
||||
<tr><td><code>event</code></td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>The event</td></tr>
|
||||
<tr><td><code>outbound</code></td><td>✔</td><td></td><td>✔</td><td></td><td></td><td>Is outbound?</td></tr>
|
||||
<tr><td><code>inbound</code></td><td>✔</td><td></td><td>✔</td><td></td><td></td><td>Is inbound?</td></tr>
|
||||
@@ -2748,6 +2749,7 @@ The possible fields are:
|
||||
<tr><td><code>packet[i]</code></td><td>✔</td><td>✔</td><td></td><td></td><td></td><td>The <code>i</code><sup>th</sup> 8-bit word of the packet</td></tr>
|
||||
<tr><td><code>packet16[i]</code></td><td>✔</td><td>✔</td><td></td><td></td><td></td><td>The <code>i</code><sup>th</sup> 16-bit word of the packet</td></tr>
|
||||
<tr><td><code>packet32[i]</code></td><td>✔</td><td>✔</td><td></td><td></td><td></td><td>The <code>i</code><sup>th</sup> 32-bit word of the packet</td></tr>
|
||||
<tr><td><code>length</code></td><td>✔</td><td>✔</td><td></td><td></td><td></td><td>The packet length</td></tr>
|
||||
<tr><td><code>ip</code></td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td></td><td>Is IPv4?</td></tr>
|
||||
<tr><td><code>ipv6</code></td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td></td><td>Is IPv6?</td></tr>
|
||||
<tr><td><code>icmp</code></td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td></td><td>Is ICMP?</td></tr>
|
||||
@@ -2829,6 +2831,12 @@ The possible macros are:
|
||||
<table border="1" cellpadding="5" width="75%">
|
||||
<tr><th>Macro</th><th colspan="5">Layer</th><th>Value</th></tr>
|
||||
<tr><th></th><th><code>NETWORK</code></th><th><code>FORWARD</code></th><th><code>FLOW </code></th><th><code>SOCKET </code></th><th><code>REFLECT</code></th><th></th></tr>
|
||||
<tr><td><code>TRUE</code></td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td><code>1</code></td></tr>
|
||||
<tr><td><code>FALSE</code></td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td><code>0</code></td></tr>
|
||||
<tr><td><code>TCP</code></td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td><code>IPPROTO_TCP</code> (<code>6</code>)</td></tr>
|
||||
<tr><td><code>UDP</code></td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td><code>IPPROTO_UDP</code> (<code>17</code>)</td></tr>
|
||||
<tr><td><code>ICMP</code></td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td><code>IPPROTO_ICMP</code> (<code>1</code>)</td></tr>
|
||||
<tr><td><code>ICMPV6</code></td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td><code>IPPROTO_ICMPV6</code> (<code>58</code>)</td></tr>
|
||||
<tr><td><code>PACKET</code></td><td>✔</td><td>✔</td><td></td><td></td><td></td><td><code>WINDIVERT_EVENT_NETWORK_PACKET</code></td></tr>
|
||||
<tr><td><code>ESTABLISHED</code></td><td></td><td></td><td>✔</td><td></td><td></td><td><code>WINDIVERT_EVENT_FLOW_ESTABLISHED</code></td></tr>
|
||||
<tr><td><code>DELETED</code></td><td></td><td></td><td>✔</td><td></td><td></td><td><code>WINDIVERT_EVENT_FLOW_DELETED</code></td></tr>
|
||||
|
||||
@@ -184,13 +184,13 @@ int __cdecl main(int argc, char **argv)
|
||||
|
||||
printf(" endpoint=");
|
||||
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
|
||||
printf("%lu", addr.Socket.Endpoint);
|
||||
printf("%lu", addr.Socket.EndpointId);
|
||||
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN |
|
||||
FOREGROUND_BLUE);
|
||||
|
||||
printf(" parent=");
|
||||
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
|
||||
printf("%lu", addr.Socket.ParentEndpoint);
|
||||
printf("%lu", addr.Socket.ParentEndpointId);
|
||||
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN |
|
||||
FOREGROUND_BLUE);
|
||||
|
||||
|
||||
@@ -314,6 +314,10 @@ usage:
|
||||
{
|
||||
printf("\"%s\"", filter_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\"%s\"", (char *)packet);
|
||||
}
|
||||
SetConsoleTextAttribute(console,
|
||||
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||
putchar('\n');
|
||||
|
||||
+21
-12
@@ -47,8 +47,8 @@
|
||||
#define WINDIVERT_VERSION_MAJOR 2
|
||||
#define WINDIVERT_VERSION_MINOR 0
|
||||
|
||||
#define WINDIVERT_MAGIC_DLL 0xB9B4733C65DCE2C6ull
|
||||
#define WINDIVERT_MAGIC_SYS 0x3A55EB5F1C9584F1ull
|
||||
#define WINDIVERT_MAGIC_DLL 0x4C4C447669645724ull
|
||||
#define WINDIVERT_MAGIC_SYS 0x5359537669645723ull
|
||||
|
||||
#define WINDIVERT_STR2(s) #s
|
||||
#define WINDIVERT_STR(s) WINDIVERT_STR2(s)
|
||||
@@ -144,9 +144,11 @@
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD 77
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16 78
|
||||
#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32 79
|
||||
#define WINDIVERT_FILTER_FIELD_RANDOM8 80
|
||||
#define WINDIVERT_FILTER_FIELD_RANDOM16 81
|
||||
#define WINDIVERT_FILTER_FIELD_RANDOM32 82
|
||||
#define WINDIVERT_FILTER_FIELD_LENGTH 80
|
||||
#define WINDIVERT_FILTER_FIELD_TIMESTAMP 81
|
||||
#define WINDIVERT_FILTER_FIELD_RANDOM8 82
|
||||
#define WINDIVERT_FILTER_FIELD_RANDOM16 83
|
||||
#define WINDIVERT_FILTER_FIELD_RANDOM32 84
|
||||
#define WINDIVERT_FILTER_FIELD_MAX \
|
||||
WINDIVERT_FILTER_FIELD_RANDOM32
|
||||
|
||||
@@ -158,10 +160,10 @@
|
||||
#define WINDIVERT_FILTER_TEST_GEQ 5
|
||||
#define WINDIVERT_FILTER_TEST_MAX WINDIVERT_FILTER_TEST_GEQ
|
||||
|
||||
#define WINDIVERT_FILTER_MAXLEN (0xFF-2)
|
||||
#define WINDIVERT_FILTER_MAXLEN 256
|
||||
|
||||
#define WINDIVERT_FILTER_RESULT_ACCEPT (WINDIVERT_FILTER_MAXLEN+1)
|
||||
#define WINDIVERT_FILTER_RESULT_REJECT (WINDIVERT_FILTER_MAXLEN+2)
|
||||
#define WINDIVERT_FILTER_RESULT_ACCEPT 0x7FFE
|
||||
#define WINDIVERT_FILTER_RESULT_REJECT 0x7FFF
|
||||
|
||||
/*
|
||||
* WinDivert layers.
|
||||
@@ -221,6 +223,11 @@
|
||||
#define WINDIVERT_PRIORITY_MAX WINDIVERT_PRIORITY_HIGHEST
|
||||
#define WINDIVERT_PRIORITY_MIN WINDIVERT_PRIORITY_LOWEST
|
||||
|
||||
/*
|
||||
* WinDivert timestamps.
|
||||
*/
|
||||
#define WINDIVERT_TIMESTAMP_MAX 0x7FFFFFFFFFFFFFFFull
|
||||
|
||||
/*
|
||||
* WinDivert message definitions.
|
||||
*/
|
||||
@@ -280,10 +287,12 @@ typedef struct
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
UINT8 field; // WINDIVERT_FILTER_FIELD_*
|
||||
UINT8 test; // WINDIVERT_FILTER_TEST_*
|
||||
UINT8 success; // Success continuation.
|
||||
UINT8 failure; // Fail continuation.
|
||||
UINT16 field:11; // WINDIVERT_FILTER_FIELD_*
|
||||
UINT16 test:5; // WINDIVERT_FILTER_TEST_*
|
||||
UINT16 success; // Success continuation.
|
||||
UINT16 failure; // Fail continuation.
|
||||
UINT16 neg:1; // Argument negative?
|
||||
UINT16 reserved:15;
|
||||
UINT32 arg[4]; // Argument.
|
||||
} WINDIVERT_FILTER, *PWINDIVERT_FILTER;
|
||||
#pragma pack(pop)
|
||||
|
||||
+6
-1
@@ -39,6 +39,11 @@ set -e
|
||||
|
||||
ENVS="i686-w64-mingw32 x86_64-w64-mingw32"
|
||||
|
||||
if [ "$1" = "debug" ]
|
||||
then
|
||||
MSVCRT=-lmsvcrt
|
||||
fi
|
||||
|
||||
for ENV in $ENVS
|
||||
do
|
||||
if [ $ENV = "i686-w64-mingw32" ]
|
||||
@@ -61,7 +66,7 @@ do
|
||||
CC="$ENV-gcc"
|
||||
COPTS="-fno-ident -shared -Wall -Wno-pointer-to-int-cast -Os -Iinclude/
|
||||
-Wl,--enable-stdcall-fixup -Wl,--entry=${MANGLE}WinDivertDllEntry"
|
||||
CLIBS="-lgcc -lkernel32 -ladvapi32"
|
||||
CLIBS="-lgcc -lkernel32 -ladvapi32 $MSVCRT"
|
||||
STRIP="$ENV-strip"
|
||||
DLLTOOL="$ENV-dlltool"
|
||||
if [ -x "`which $CC`" ]
|
||||
|
||||
+85
-17
@@ -488,8 +488,8 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
|
||||
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);
|
||||
static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b,
|
||||
BOOL big);
|
||||
static int windivert_big_num_compare(BOOL neg_a, const UINT32 *a, BOOL neg_b,
|
||||
const UINT32 *b, BOOL big);
|
||||
static BOOL windivert_copy_data(PNET_BUFFER buffer, PVOID data, UINT size);
|
||||
static BOOL windivert_lookup_data(PNET_BUFFER buffer, UINT offset, INT idx,
|
||||
PVOID data, UINT size);
|
||||
@@ -5062,42 +5062,53 @@ static void windivert_free_packet(packet_t packet)
|
||||
/*
|
||||
* Big number comparison.
|
||||
*/
|
||||
static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b, BOOL big)
|
||||
static int windivert_big_num_compare(BOOL neg_a, const UINT32 *a, BOOL neg_b,
|
||||
const UINT32 *b, BOOL big)
|
||||
{
|
||||
int neg;
|
||||
if (neg_a && !neg_b)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (!neg_a && neg_b)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
neg = (neg_a? -1: 1);
|
||||
if (big)
|
||||
{
|
||||
if (a[3] < b[3])
|
||||
{
|
||||
return -1;
|
||||
return -neg;
|
||||
}
|
||||
if (a[3] > b[3])
|
||||
{
|
||||
return 1;
|
||||
return neg;
|
||||
}
|
||||
if (a[2] < b[2])
|
||||
{
|
||||
return -1;
|
||||
return -neg;
|
||||
}
|
||||
if (a[2] > b[2])
|
||||
{
|
||||
return 1;
|
||||
return neg;
|
||||
}
|
||||
if (a[1] < b[1])
|
||||
{
|
||||
return -1;
|
||||
return -neg;
|
||||
}
|
||||
if (a[1] > b[1])
|
||||
{
|
||||
return 1;
|
||||
return neg;
|
||||
}
|
||||
}
|
||||
if (a[0] < b[0])
|
||||
{
|
||||
return -1;
|
||||
return -neg;
|
||||
}
|
||||
if (a[0] > b[0])
|
||||
{
|
||||
return 1;
|
||||
return neg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -5406,6 +5417,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
|
||||
{
|
||||
BOOL result = FALSE;
|
||||
BOOL big = FALSE;
|
||||
BOOL neg = FALSE;
|
||||
int cmp;
|
||||
UINT32 field[4];
|
||||
|
||||
@@ -5413,6 +5425,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
|
||||
{
|
||||
case WINDIVERT_FILTER_FIELD_ZERO:
|
||||
case WINDIVERT_FILTER_FIELD_EVENT:
|
||||
case WINDIVERT_FILTER_FIELD_TIMESTAMP:
|
||||
result = TRUE;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_INBOUND:
|
||||
@@ -5448,6 +5461,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
|
||||
case WINDIVERT_FILTER_FIELD_PACKET:
|
||||
case WINDIVERT_FILTER_FIELD_PACKET16:
|
||||
case WINDIVERT_FILTER_FIELD_PACKET32:
|
||||
case WINDIVERT_FILTER_FIELD_LENGTH:
|
||||
result = (layer == WINDIVERT_LAYER_NETWORK ||
|
||||
layer == WINDIVERT_LAYER_NETWORK_FORWARD);
|
||||
break;
|
||||
@@ -5564,6 +5578,29 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
|
||||
case WINDIVERT_FILTER_FIELD_EVENT:
|
||||
field[0] = (UINT32)event;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_LENGTH:
|
||||
if (ipv4)
|
||||
{
|
||||
field[0] = (UINT32)RtlUshortByteSwap(ip_header->Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
field[0] =
|
||||
(UINT32)RtlUshortByteSwap(ipv6_header->Length) +
|
||||
sizeof(WINDIVERT_IPV6HDR);
|
||||
}
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_TIMESTAMP:
|
||||
{
|
||||
UINT64 val64;
|
||||
neg = (timestamp < 0);
|
||||
val64 = (UINT64)(neg? -timestamp: timestamp);
|
||||
big = TRUE;
|
||||
field[3] = field[2] = 0;
|
||||
field[0] = (UINT32)val64;
|
||||
field[1] = (UINT32)(val64 >> 32);
|
||||
break;
|
||||
}
|
||||
case WINDIVERT_FILTER_FIELD_RANDOM8:
|
||||
field[0] = (UINT32)((random64 >> 48) & 0xFF);
|
||||
break;
|
||||
@@ -6129,8 +6166,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
|
||||
field[0] = (UINT32)reflect_data->Layer;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_PRIORITY:
|
||||
field[0] = (UINT32)((INT32)reflect_data->Priority +
|
||||
WINDIVERT_PRIORITY_MAX);
|
||||
neg = (reflect_data->Priority < 0);
|
||||
field[0] = (UINT32)(neg? -reflect_data->Priority:
|
||||
reflect_data->Priority);
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
@@ -6138,7 +6176,8 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
|
||||
}
|
||||
if (result)
|
||||
{
|
||||
cmp = windivert_big_num_compare(field, filter[ip].arg, big);
|
||||
cmp = windivert_big_num_compare(neg, field,
|
||||
(filter[ip].neg? TRUE: FALSE), filter[ip].arg, big);
|
||||
switch (filter[ip].test)
|
||||
{
|
||||
case WINDIVERT_FILTER_TEST_EQ:
|
||||
@@ -6187,6 +6226,7 @@ static const WINDIVERT_FILTER *windivert_filter_compile(
|
||||
{
|
||||
PWINDIVERT_FILTER filter = NULL;
|
||||
WINDIVERT_EVENT event;
|
||||
BOOL neg_lb, neg_ub, neg;
|
||||
UINT32 lb[4], ub[4];
|
||||
int result;
|
||||
UINT16 i;
|
||||
@@ -6244,6 +6284,7 @@ static const WINDIVERT_FILTER *windivert_filter_compile(
|
||||
}
|
||||
|
||||
// Enforce ranges:
|
||||
neg_lb = neg_ub = 0;
|
||||
lb[0] = lb[1] = lb[2] = lb[3] = 0;
|
||||
ub[0] = ub[1] = ub[2] = ub[3] = 0;
|
||||
switch (ioctl_filter[i].field)
|
||||
@@ -6259,6 +6300,10 @@ static const WINDIVERT_FILTER *windivert_filter_compile(
|
||||
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
|
||||
{
|
||||
INT idx = (INT)ioctl_filter[i].arg[1];
|
||||
if (ioctl_filter[i].neg)
|
||||
{
|
||||
goto windivert_filter_compile_error;
|
||||
}
|
||||
if (idx > WINDIVERT_MTU_MAX || idx < -WINDIVERT_MTU_MAX)
|
||||
{
|
||||
goto windivert_filter_compile_error;
|
||||
@@ -6294,7 +6339,8 @@ static const WINDIVERT_FILTER *windivert_filter_compile(
|
||||
ub[0] = WINDIVERT_LAYER_MAX;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_PRIORITY:
|
||||
ub[0] = 2 * WINDIVERT_PRIORITY_MAX;
|
||||
neg_lb = TRUE;
|
||||
lb[0] = ub[0] = WINDIVERT_PRIORITY_MAX;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_EVENT:
|
||||
event = (WINDIVERT_EVENT)ioctl_filter[i].arg[0];
|
||||
@@ -6385,6 +6431,10 @@ static const WINDIVERT_FILTER *windivert_filter_compile(
|
||||
case WINDIVERT_FILTER_FIELD_RANDOM16:
|
||||
ub[0] = 0xFFFF;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_LENGTH:
|
||||
lb[0] = sizeof(WINDIVERT_IPHDR);
|
||||
ub[0] = WINDIVERT_MTU_MAX;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL:
|
||||
ub[0] = 0x000FFFFF;
|
||||
break;
|
||||
@@ -6393,6 +6443,12 @@ static const WINDIVERT_FILTER *windivert_filter_compile(
|
||||
ub[0] = 0xFFFFFFFF;
|
||||
ub[1] = lb[1] = 0x0000FFFF;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_TIMESTAMP:
|
||||
lb[1] = 0x80000000;
|
||||
ub[0] = 0xFFFFFFFF;
|
||||
ub[1] = 0x7FFFFFFF;
|
||||
neg_lb = TRUE;
|
||||
break;
|
||||
case WINDIVERT_FILTER_FIELD_ENDPOINTID:
|
||||
case WINDIVERT_FILTER_FIELD_PARENTENDPOINTID:
|
||||
ub[0] = ub[1] = 0xFFFFFFFF;
|
||||
@@ -6407,21 +6463,33 @@ static const WINDIVERT_FILTER *windivert_filter_compile(
|
||||
ub[0] = 0xFFFFFFFF;
|
||||
break;
|
||||
}
|
||||
result = windivert_big_num_compare(ioctl_filter[i].arg, lb, TRUE);
|
||||
neg = (ioctl_filter[i].neg? TRUE: FALSE);
|
||||
result = windivert_big_num_compare(neg, ioctl_filter[i].arg, neg_lb,
|
||||
lb, /*big=*/TRUE);
|
||||
if (result < 0)
|
||||
{
|
||||
goto windivert_filter_compile_error;
|
||||
}
|
||||
result = windivert_big_num_compare(ioctl_filter[i].arg, ub, TRUE);
|
||||
result = windivert_big_num_compare(neg, ioctl_filter[i].arg, neg_ub,
|
||||
ub, /*big=*/TRUE);
|
||||
if (result > 0)
|
||||
{
|
||||
goto windivert_filter_compile_error;
|
||||
}
|
||||
|
||||
// Disallow negative zero:
|
||||
if (neg &&
|
||||
ioctl_filter[i].arg[0] == 0 && ioctl_filter[i].arg[1] == 0 &&
|
||||
ioctl_filter[i].arg[2] == 0 && ioctl_filter[i].arg[3] == 0)
|
||||
{
|
||||
goto windivert_filter_compile_error;
|
||||
}
|
||||
|
||||
filter[i].field = ioctl_filter[i].field;
|
||||
filter[i].test = ioctl_filter[i].test;
|
||||
filter[i].success = ioctl_filter[i].success;
|
||||
filter[i].failure = ioctl_filter[i].failure;
|
||||
filter[i].neg = ioctl_filter[i].neg;
|
||||
filter[i].arg[0] = ioctl_filter[i].arg[0];
|
||||
filter[i].arg[1] = ioctl_filter[i].arg[1];
|
||||
filter[i].arg[2] = ioctl_filter[i].arg[2];
|
||||
|
||||
+12
@@ -153,6 +153,8 @@ static const struct test tests[] =
|
||||
{"ip or ipv6", &pkt_echo_request, TRUE},
|
||||
{"inbound", &pkt_echo_request, FALSE},
|
||||
{"tcp", &pkt_echo_request, FALSE},
|
||||
{"tcp == TRUE", &pkt_echo_request, FALSE},
|
||||
{"tcp == FALSE", &pkt_echo_request, TRUE},
|
||||
{"icmp.Type == 8", &pkt_echo_request, TRUE},
|
||||
{"icmp.Type == 9", &pkt_echo_request, FALSE},
|
||||
{"(tcp? ip.Checksum == 0: icmp)", &pkt_echo_request, TRUE},
|
||||
@@ -308,6 +310,7 @@ static const struct test tests[] =
|
||||
"remotePort == 0 && protocol == 1", &pkt_echo_request, TRUE},
|
||||
{"packet[0] == 0x45", &pkt_echo_request, TRUE},
|
||||
{"tcp", &pkt_http_request, TRUE},
|
||||
{"protocol == TCP", &pkt_http_request, TRUE},
|
||||
{"outbound and tcp and tcp.DstPort == 80", &pkt_http_request, TRUE},
|
||||
{"outbound and tcp and tcp.DstPort == 81", &pkt_http_request, FALSE},
|
||||
{"outbound and tcp and tcp.DstPort != 80", &pkt_http_request, FALSE},
|
||||
@@ -530,6 +533,9 @@ static const struct test tests[] =
|
||||
&pkt_dns_request, TRUE},
|
||||
{"tcp.Payload32[0] > 0", &pkt_dns_request, FALSE},
|
||||
{"udp.Payload32[1] > 0", &pkt_dns_request, TRUE},
|
||||
{"length == 57", &pkt_dns_request, TRUE},
|
||||
{"(length > 57? udp: tcp)", &pkt_dns_request, FALSE},
|
||||
{"protocol == UDP", &pkt_dns_request, TRUE},
|
||||
{"random8 < 128", &pkt_dns_request, TRUE},
|
||||
{"(random8 < 128? random16 < 0x8000: random32 < 0x80000000)",
|
||||
&pkt_dns_request, TRUE},
|
||||
@@ -705,6 +711,8 @@ static const struct test tests[] =
|
||||
{"packet[0] == 0x60", &pkt_ipv6_tcp_syn, TRUE},
|
||||
{"icmpv6", &pkt_ipv6_echo_reply, TRUE},
|
||||
{"icmp", &pkt_ipv6_echo_reply, FALSE},
|
||||
{"protocol == ICMPV6", &pkt_ipv6_echo_reply, TRUE},
|
||||
{"protocol == ICMP", &pkt_ipv6_echo_reply, FALSE},
|
||||
{"icmp or icmpv6", &pkt_ipv6_echo_reply, TRUE},
|
||||
{"not icmp", &pkt_ipv6_echo_reply, TRUE},
|
||||
{"icmpv6.Type == 129", &pkt_ipv6_echo_reply, TRUE},
|
||||
@@ -776,6 +784,7 @@ static const struct test tests[] =
|
||||
{"ipv6.SrcAddr != abcd::1", &pkt_ipv6_exthdrs_udp, TRUE},
|
||||
{"ipv6.SrcAddr >= abcd::1", &pkt_ipv6_exthdrs_udp, FALSE},
|
||||
{"ipv6.SrcAddr > abcd::1", &pkt_ipv6_exthdrs_udp, FALSE},
|
||||
{"timestamp > -1", &pkt_ipv6_exthdrs_udp, TRUE},
|
||||
{"udp.SrcPort == 4660 and udp.DstPort == 43690",
|
||||
&pkt_ipv6_exthdrs_udp, TRUE},
|
||||
{"udp.SrcPort == 4660 and udp.DstPort == 12345",
|
||||
@@ -801,6 +810,9 @@ static const struct test tests[] =
|
||||
{"random8 < 128", &pkt_ipv6_exthdrs_udp, TRUE},
|
||||
{"(random8 < 128? random16 < 0x8000: random32 < 0x80000000)",
|
||||
&pkt_ipv6_exthdrs_udp, TRUE},
|
||||
{"timestamp != -0x8000000000000000", &pkt_ipv6_exthdrs_udp, TRUE},
|
||||
{"timestamp != 0x7fffffffffffffff", &pkt_ipv6_exthdrs_udp, TRUE},
|
||||
{"timestamp == -0x1deadbeef1234567", &pkt_ipv6_exthdrs_udp, FALSE},
|
||||
{"((packet[2] <= 0x00 or (((packet[29] < 0x00 or "
|
||||
"not packet[35] != 0x00) and packet[32] != 0x00) and "
|
||||
"((not packet[31] != 0x00 and packet[52] > 0x00) and "
|
||||
|
||||
Reference in New Issue
Block a user