From e306d0058bc0b4ad625351c5cfdeba940d66b6d0 Mon Sep 17 00:00:00 2001 From: basil00 Date: Fri, 15 Mar 2019 08:01:10 +0800 Subject: [PATCH] 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. --- CHANGELOG | 12 +- dll/windivert.c | 15 +- dll/windivert_helper.c | 296 +++++++++++++++++++-------- dll/windivert_shared.c | 28 ++- doc/windivert.html | 8 + examples/socketdump/socketdump.c | 4 +- examples/windivertctl/windivertctl.c | 4 + include/windivert_device.h | 33 +-- mingw-build.sh | 7 +- sys/windivert.c | 102 +++++++-- test/test.c | 12 ++ 11 files changed, 402 insertions(+), 119 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c2bd62b..127f5b7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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. diff --git a/dll/windivert.c b/dll/windivert.c index 0885e3f..af220e5 100644 --- a/dll/windivert.c +++ b/dll/windivert.c @@ -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: diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c index 4dac77b..61b41a3 100644 --- a/dll/windivert_helper.c +++ b/dll/windivert_helper.c @@ -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: diff --git a/dll/windivert_shared.c b/dll/windivert_shared.c index c3cdf83..6122405 100644 --- a/dll/windivert_shared.c +++ b/dll/windivert_shared.c @@ -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); } /* diff --git a/doc/windivert.html b/doc/windivert.html index 6ca08b7..23e69c6 100644 --- a/doc/windivert.html +++ b/doc/windivert.html @@ -2730,6 +2730,7 @@ The possible fields are: FieldLayerDescription NETWORKFORWARDFLOW   SOCKET REFLECT zero✔✔✔✔✔The value zero +timestamp✔✔✔✔✔The packet/event timestamp event✔✔✔✔✔The event outbound✔✔Is outbound? inbound✔✔Is inbound? @@ -2748,6 +2749,7 @@ The possible fields are: packet[i]✔✔The ith 8-bit word of the packet packet16[i]✔✔The ith 16-bit word of the packet packet32[i]✔✔The ith 32-bit word of the packet +length✔✔The packet length ip✔✔✔✔Is IPv4? ipv6✔✔✔✔Is IPv6? icmp✔✔✔✔Is ICMP? @@ -2829,6 +2831,12 @@ The possible macros are: + + + + + + diff --git a/examples/socketdump/socketdump.c b/examples/socketdump/socketdump.c index 13233da..b4518db 100644 --- a/examples/socketdump/socketdump.c +++ b/examples/socketdump/socketdump.c @@ -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); diff --git a/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c index 354dc92..7859420 100644 --- a/examples/windivertctl/windivertctl.c +++ b/examples/windivertctl/windivertctl.c @@ -314,6 +314,10 @@ usage: { printf("\"%s\"", filter_str); } + else + { + printf("\"%s\"", (char *)packet); + } SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); putchar('\n'); diff --git a/include/windivert_device.h b/include/windivert_device.h index 8659bc7..02783e4 100644 --- a/include/windivert_device.h +++ b/include/windivert_device.h @@ -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) diff --git a/mingw-build.sh b/mingw-build.sh index 8178790..6ef91f1 100644 --- a/mingw-build.sh +++ b/mingw-build.sh @@ -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`" ] diff --git a/sys/windivert.c b/sys/windivert.c index b8b102f..66f4c3b 100644 --- a/sys/windivert.c +++ b/sys/windivert.c @@ -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]; diff --git a/test/test.c b/test/test.c index 0ce8eb1..3065214 100644 --- a/test/test.c +++ b/test/test.c @@ -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 "
MacroLayerValue
NETWORKFORWARDFLOW   SOCKET REFLECT
TRUE✔✔✔✔✔1
FALSE✔✔✔✔✔0
TCP✔✔✔✔✔IPPROTO_TCP (6)
UDP✔✔✔✔✔IPPROTO_UDP (17)
ICMP✔✔✔✔✔IPPROTO_ICMP (1)
ICMPV6✔✔✔✔✔IPPROTO_ICMPV6 (58)
PACKET✔✔WINDIVERT_EVENT_NETWORK_PACKET
ESTABLISHED✔WINDIVERT_EVENT_FLOW_ESTABLISHED
DELETED✔WINDIVERT_EVENT_FLOW_DELETED