From 33a461eef66ca823f4eb134acda50f23f18d734d Mon Sep 17 00:00:00 2001 From: basil00 Date: Wed, 7 Nov 2018 07:54:32 +0800 Subject: [PATCH] Add packet/payload matching to WinDivert (#156). Adds the follow terms to the filter language: - packet[idx]: 8bit packet value at idx. - packet16[idx]: 16bit packet value at idx. - packet32[idx]: 32bit packet value at idx. - PROTO.Payload[idx]: 8bit payload value at idx. - PROTO.Payload16[idx]: 16bit payload value at idx. - PROTO.Payload32[idx]: 32bit payload value at idx. where PROTO is {tcp,udp}. 16 and 32bit values assume network byte ordering. The index may be: - An undecorated integer, in which case the packet or payload is treated as a 8/16/32bit value array, similar to C arrays. - A 'b' decorated integer, (e.g, packet32[17b]), in which case the integer is interpreted as a byte offset. - A negative (un)decorated integer, in which case indexing begins at the *end* of the packet or payload. E.g., packet32[-1] is the last 32bits of the packet. If the index is out-of-bounds, then the test is deemed to be equivalent to "false". --- dll/windivert_helper.c | 486 +++++++++++++++++++++++++++++++++---- dll/windivert_shared.c | 14 ++ include/windivert_device.h | 11 +- sys/windivert.c | 268 +++++++++++++------- test/test.c | 90 ++++++- 5 files changed, 724 insertions(+), 145 deletions(-) diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c index 5c3b224..5057d08 100644 --- a/dll/windivert_helper.c +++ b/dll/windivert_helper.c @@ -93,6 +93,9 @@ typedef enum TOKEN_TCP_DST_PORT, TOKEN_TCP_FIN, TOKEN_TCP_HDR_LENGTH, + TOKEN_TCP_PAYLOAD, + TOKEN_TCP_PAYLOAD16, + TOKEN_TCP_PAYLOAD32, TOKEN_TCP_PAYLOAD_LENGTH, TOKEN_TCP_PSH, TOKEN_TCP_RST, @@ -106,10 +109,16 @@ typedef enum TOKEN_UDP_CHECKSUM, TOKEN_UDP_DST_PORT, TOKEN_UDP_LENGTH, + TOKEN_UDP_PAYLOAD, + TOKEN_UDP_PAYLOAD16, + TOKEN_UDP_PAYLOAD32, TOKEN_UDP_PAYLOAD_LENGTH, TOKEN_UDP_SRC_PORT, TOKEN_ZERO, TOKEN_EVENT, + TOKEN_PACKET, + TOKEN_PACKET16, + TOKEN_PACKET32, TOKEN_TRUE, TOKEN_FALSE, TOKEN_INBOUND, @@ -141,6 +150,10 @@ typedef enum TOKEN_EVENT_CLOSE, TOKEN_OPEN, TOKEN_CLOSE, + TOKEN_SQUARE_OPEN, + TOKEN_SQUARE_CLOSE, + TOKEN_MINUS, + TOKEN_BYTES, TOKEN_EQ, TOKEN_NEQ, TOKEN_LT, @@ -239,9 +252,10 @@ typedef UINT64 ERROR, *PERROR; #define WINDIVERT_ERROR_BAD_TOKEN 4 #define WINDIVERT_ERROR_BAD_TOKEN_FOR_LAYER 5 #define WINDIVERT_ERROR_UNEXPECTED_TOKEN 6 -#define WINDIVERT_ERROR_OUTPUT_TOO_SHORT 7 -#define WINDIVERT_ERROR_BAD_OBJECT 8 -#define WINDIVERT_ERROR_ASSERTION_FAILED 9 +#define WINDIVERT_ERROR_INDEX_OOB 7 +#define WINDIVERT_ERROR_OUTPUT_TOO_SHORT 8 +#define WINDIVERT_ERROR_BAD_OBJECT 9 +#define WINDIVERT_ERROR_ASSERTION_FAILED 10 #define MAKE_ERROR(code, pos) \ (((ERROR)(code) << 32) | (ERROR)(pos)); @@ -603,6 +617,9 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, {"not", TOKEN_NOT, LNMFSR}, {"or", TOKEN_OR, LNMFSR}, {"outbound", TOKEN_OUTBOUND, LN_F__}, + {"packet", TOKEN_PACKET, LNM___}, + {"packet16", TOKEN_PACKET16, LNM___}, + {"packet32", TOKEN_PACKET32, LNM___}, {"processId", TOKEN_PROCESS_ID, L__FSR}, {"protocol", TOKEN_PROTOCOL, LN_FS_}, {"remoteAddr", TOKEN_REMOTE_ADDR, LN_FS_}, @@ -615,6 +632,9 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, {"tcp.DstPort", TOKEN_TCP_DST_PORT, LNM___}, {"tcp.Fin", TOKEN_TCP_FIN, LNM___}, {"tcp.HdrLength", TOKEN_TCP_HDR_LENGTH, LNM___}, + {"tcp.Payload", TOKEN_TCP_PAYLOAD, LNM___}, + {"tcp.Payload16", TOKEN_TCP_PAYLOAD16, LNM___}, + {"tcp.Payload32", TOKEN_TCP_PAYLOAD32, LNM___}, {"tcp.PayloadLength", TOKEN_TCP_PAYLOAD_LENGTH, LNM___}, {"tcp.Psh", TOKEN_TCP_PSH, LNM___}, {"tcp.Rst", TOKEN_TCP_RST, LNM___}, @@ -629,6 +649,9 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, {"udp.Checksum", TOKEN_UDP_CHECKSUM, LNM___}, {"udp.DstPort", TOKEN_UDP_DST_PORT, LNM___}, {"udp.Length", TOKEN_UDP_LENGTH, LNM___}, + {"udp.Payload", TOKEN_UDP_PAYLOAD, LNM___}, + {"udp.Payload16", TOKEN_UDP_PAYLOAD16, LNM___}, + {"udp.Payload32", TOKEN_UDP_PAYLOAD32, LNM___}, {"udp.PayloadLength", TOKEN_UDP_PAYLOAD_LENGTH, LNM___}, {"udp.SrcPort", TOKEN_UDP_SRC_PORT, LNM___}, {"zero", TOKEN_ZERO, LNMFSR}, @@ -663,6 +686,15 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, case ')': tokens[tp++].kind = TOKEN_CLOSE; continue; + case '[': + tokens[tp++].kind = TOKEN_SQUARE_OPEN; + continue; + case ']': + tokens[tp++].kind = TOKEN_SQUARE_CLOSE; + continue; + case '-': + tokens[tp++].kind = TOKEN_MINUS; + continue; case '!': if (filter[i] == '=') { @@ -780,16 +812,26 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, } // Check for base 10 number: - if (WinDivertAToI(token, &end, &num) && *end == '\0') + if (WinDivertAToI(token, &end, &num)) { - tokens[tp].kind = TOKEN_NUMBER; - tokens[tp].val[0] = num; - tp++; - continue; + BOOL b = (*end == 'b' && *(end+1) == '\0'); + if (*end == '\0' || b) + { + tokens[tp].kind = TOKEN_NUMBER; + tokens[tp].val[0] = num; + tp++; + if (b) + { + tokens[tp].kind = TOKEN_BYTES; + tp++; + } + continue; + } } // Check for base 16 number: - if (WinDivertAToX(token, &end, &num) && *end == '\0') + if (token[0] == '0' && token[1] == 'x' && + WinDivertAToX(token, &end, &num) && *end == '\0') { tokens[tp].kind = TOKEN_NUMBER; tokens[tp].val[0] = num; @@ -924,6 +966,23 @@ static PEXPR WinDivertMakeVar(KIND kind, PERROR error) return NULL; } +/* + * Construct array varable. + */ +static PEXPR WinDivertMakeArrayVar(HANDLE pool, KIND kind, INT idx, + PERROR error) +{ + PEXPR var = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR)); + if (var == NULL) + { + *error = MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0); + return NULL; + } + var->kind = kind; + var->val[0] = (UINT32)idx; + return var; +} + /* * Construct zero. */ @@ -938,6 +997,10 @@ static PEXPR WinDivertMakeZero(void) */ static PEXPR WinDivertMakeNumber(HANDLE pool, UINT32 *val, PERROR error) { + if (val[0] == 0 && val[1] == 0 && val[2] == 0 && val[3] == 0) + { + return WinDivertMakeZero(); + } PEXPR expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR)); if (expr == NULL) { @@ -1001,7 +1064,8 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error) { PEXPR var, val; KIND kind; - BOOL not = FALSE; + BOOL not = FALSE, neg; + UINT idx, size; while (toks[*i].kind == TOKEN_NOT) { not = !not; @@ -1079,13 +1143,80 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error) case TOKEN_UDP_LENGTH: case TOKEN_UDP_CHECKSUM: case TOKEN_UDP_PAYLOAD_LENGTH: + var = WinDivertMakeVar(toks[*i].kind, error); + *i = *i + 1; + break; + case TOKEN_PACKET: + case TOKEN_TCP_PAYLOAD: + case TOKEN_UDP_PAYLOAD: + size = sizeof(UINT8); + goto array; + case TOKEN_PACKET16: + case TOKEN_TCP_PAYLOAD16: + case TOKEN_UDP_PAYLOAD16: + size = sizeof(UINT16); + goto array; + case TOKEN_PACKET32: + case TOKEN_TCP_PAYLOAD32: + case TOKEN_UDP_PAYLOAD32: + size = sizeof(UINT32); + array: + kind = toks[*i].kind; + *i = *i + 1; + if (toks[*i].kind != TOKEN_SQUARE_OPEN) + { + goto unexpected_token; + } + *i = *i + 1; + neg = FALSE; + if (toks[*i].kind == TOKEN_MINUS) + { + neg = TRUE; + *i = *i + 1; + } + if (toks[*i].kind != TOKEN_NUMBER) + { + goto unexpected_token; + } + if (toks[*i].val[3] != 0 || toks[*i].val[2] != 0 || + toks[*i].val[1] != 0 || toks[*i].val[0] > UINT16_MAX) + { + *error = MAKE_ERROR(WINDIVERT_ERROR_INDEX_OOB, toks[*i].pos); + return NULL; + } + idx = toks[*i].val[0]; + *i = *i + 1; + if (toks[*i].kind == TOKEN_BYTES) + { + *i = *i + 1; + } + else + { + idx *= size; + } + if ((!neg && idx > UINT16_MAX - size) || + (neg && idx > UINT16_MAX) || (neg && idx < size)) + { + *error = MAKE_ERROR(WINDIVERT_ERROR_INDEX_OOB, toks[*i].pos); + return NULL; + } + var = WinDivertMakeArrayVar(pool, kind, (neg? -(INT)idx: (INT)idx), + error); + if (var == NULL) + { + return NULL; + } + if (toks[*i].kind != TOKEN_SQUARE_CLOSE) + { + goto unexpected_token; + } + *i = *i + 1; break; default: + unexpected_token: *error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, toks[*i].pos); return NULL; } - var = WinDivertMakeVar(toks[*i].kind, error); - *i = *i + 1; switch (toks[*i].kind) { case TOKEN_EQ: @@ -1296,6 +1427,9 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) case TOKEN_ICMPV6_TYPE: case TOKEN_ICMPV6_CODE: case TOKEN_PROTOCOL: + case TOKEN_PACKET: + case TOKEN_TCP_PAYLOAD: + case TOKEN_UDP_PAYLOAD: lb = 0; ub = 0xFF; break; case TOKEN_IP_FRAG_OFF: @@ -1321,6 +1455,9 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) case TOKEN_UDP_PAYLOAD_LENGTH: case TOKEN_LOCAL_PORT: case TOKEN_REMOTE_PORT: + case TOKEN_PACKET16: + case TOKEN_TCP_PAYLOAD16: + case TOKEN_UDP_PAYLOAD16: lb = 0; ub = 0xFFFF; break; case TOKEN_IPV6_FLOW_LABEL: @@ -1469,6 +1606,7 @@ static INT16 WinDivertFlattenExpr(PEXPR expr, INT16 *label, INT16 succ, static void WinDivertEmitTest(PEXPR test, UINT16 offset, PWINDIVERT_FILTER object) { + BOOL big; PEXPR var = test->arg[0], val = test->arg[1]; switch (test->kind) { @@ -1493,6 +1631,8 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset, default: return; } + big = FALSE; + object->arg[1] = object->arg[2] = object->arg[3] = 0; switch (var->kind) { case TOKEN_ZERO: @@ -1501,6 +1641,42 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset, case TOKEN_EVENT: object->field = WINDIVERT_FILTER_FIELD_EVENT; break; + case TOKEN_PACKET: + object->field = WINDIVERT_FILTER_FIELD_PACKET; + object->arg[1] = var->val[0]; + break; + case TOKEN_PACKET16: + object->field = WINDIVERT_FILTER_FIELD_PACKET16; + object->arg[1] = var->val[0]; + break; + case TOKEN_PACKET32: + object->field = WINDIVERT_FILTER_FIELD_PACKET32; + object->arg[1] = var->val[0]; + break; + case TOKEN_TCP_PAYLOAD: + object->field = WINDIVERT_FILTER_FIELD_TCP_PAYLOAD; + object->arg[1] = var->val[0]; + break; + case TOKEN_TCP_PAYLOAD16: + object->field = WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16; + object->arg[1] = var->val[0]; + break; + case TOKEN_TCP_PAYLOAD32: + object->field = WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32; + object->arg[1] = var->val[0]; + break; + case TOKEN_UDP_PAYLOAD: + object->field = WINDIVERT_FILTER_FIELD_UDP_PAYLOAD; + object->arg[1] = var->val[0]; + break; + case TOKEN_UDP_PAYLOAD16: + object->field = WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16; + object->arg[1] = var->val[0]; + break; + case TOKEN_UDP_PAYLOAD32: + object->field = WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32; + object->arg[1] = var->val[0]; + break; case TOKEN_OUTBOUND: object->field = WINDIVERT_FILTER_FIELD_OUTBOUND; break; @@ -1524,9 +1700,11 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset, break; case TOKEN_LOCAL_ADDR: object->field = WINDIVERT_FILTER_FIELD_LOCALADDR; + big = TRUE; break; case TOKEN_REMOTE_ADDR: object->field = WINDIVERT_FILTER_FIELD_REMOTEADDR; + big = TRUE; break; case TOKEN_LOCAL_PORT: object->field = WINDIVERT_FILTER_FIELD_LOCALPORT; @@ -1590,9 +1768,11 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset, break; case TOKEN_IP_SRC_ADDR: object->field = WINDIVERT_FILTER_FIELD_IP_SRCADDR; + big = TRUE; break; case TOKEN_IP_DST_ADDR: object->field = WINDIVERT_FILTER_FIELD_IP_DSTADDR; + big = TRUE; break; case TOKEN_IPV6_TRAFFIC_CLASS: object->field = WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS; @@ -1611,9 +1791,11 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset, break; case TOKEN_IPV6_SRC_ADDR: object->field = WINDIVERT_FILTER_FIELD_IPV6_SRCADDR; + big = TRUE; break; case TOKEN_IPV6_DST_ADDR: object->field = WINDIVERT_FILTER_FIELD_IPV6_DSTADDR; + big = TRUE; break; case TOKEN_ICMP_TYPE: object->field = WINDIVERT_FILTER_FIELD_ICMP_TYPE; @@ -1703,9 +1885,12 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset, return; } object->arg[0] = val->val[0]; - object->arg[1] = val->val[1]; - object->arg[2] = val->val[2]; - object->arg[3] = val->val[3]; + if (big) + { + object->arg[1] = val->val[1]; + object->arg[2] = val->val[2]; + object->arg[3] = val->val[3]; + } switch (test->succ) { case WINDIVERT_FILTER_RESULT_ACCEPT: @@ -2021,6 +2206,8 @@ static const char *WinDivertErrorString(UINT code) return "Filter expression contains a bad token for layer"; case WINDIVERT_ERROR_UNEXPECTED_TOKEN: return "Filter expression parse error"; + case WINDIVERT_ERROR_INDEX_OOB: + return "Filter expression array index is out-of-bounds"; case WINDIVERT_ERROR_OUTPUT_TOO_SHORT: return "Filter object buffer is too short"; case WINDIVERT_ERROR_BAD_OBJECT: @@ -2086,31 +2273,34 @@ extern BOOL WinDivertHelperCompileFilter(const char *filter_str, /* * Big number comparison. */ -static int WinDivertBigNumCompare(const UINT32 *a, const UINT32 *b) +static int WinDivertBigNumCompare(const UINT32 *a, const UINT32 *b, BOOL big) { - if (a[3] < b[3]) + if (big) { - return -1; - } - if (a[3] > b[3]) - { - return 1; - } - if (a[2] < b[2]) - { - return -1; - } - if (a[2] > b[2]) - { - return 1; - } - if (a[1] < b[1]) - { - return -1; - } - if (a[1] > b[1]) - { - return 1; + if (a[3] < b[3]) + { + return -1; + } + if (a[3] > b[3]) + { + return 1; + } + if (a[2] < b[2]) + { + return -1; + } + if (a[2] > b[2]) + { + return 1; + } + if (a[1] < b[1]) + { + return -1; + } + if (a[1] > b[1]) + { + return 1; + } } if (a[0] < b[0]) { @@ -2123,6 +2313,28 @@ static int WinDivertBigNumCompare(const UINT32 *a, const UINT32 *b) return 0; } +/* + * Get packet/payload data. + */ +static BOOL WinDivertGetData(PVOID packet, UINT packet_len, UINT offset, + INT idx, UINT size, PVOID data) +{ + if (idx < 0) + { + idx += (INT)packet_len; + } + else + { + idx += (INT)offset; + } + if (idx < (INT)offset || idx > (INT)(packet_len - size)) + { + return FALSE; + } + memcpy(data, (UINT8 *)packet + idx, size); + return TRUE; +} + /* * Evaluate the given filter with the given packet as input. */ @@ -2138,9 +2350,12 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, PWINDIVERT_TCPHDR tcphdr = NULL; PWINDIVERT_UDPHDR udphdr = NULL; UINT8 protocol = 0; - UINT payload_len; + UINT header_len = 0, payload_len = 0; UINT32 val[4]; - BOOL pass; + UINT8 data8; + UINT16 data16; + UINT32 data32; + BOOL pass, big; int cmp; WINDIVERT_FILTER object[WINDIVERT_FILTER_MAXLEN]; UINT obj_len; @@ -2162,6 +2377,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, WinDivertParsePacket(packet, packet_len, &iphdr, &ipv6hdr, &icmphdr, &icmpv6hdr, &tcphdr, &udphdr, &protocol, NULL, &payload_len); + header_len = packet_len - payload_len; if ((addr->IPv6 && ipv6hdr == NULL) || (!addr->IPv6 && iphdr == NULL)) { @@ -2209,6 +2425,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, break; } pass = TRUE; + big = FALSE; switch (object[pc].field) { case WINDIVERT_FILTER_FIELD_ZERO: @@ -2232,6 +2449,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, break; case WINDIVERT_FILTER_FIELD_IFIDX: case WINDIVERT_FILTER_FIELD_SUBIFIDX: + case WINDIVERT_FILTER_FIELD_PACKET: + case WINDIVERT_FILTER_FIELD_PACKET16: + case WINDIVERT_FILTER_FIELD_PACKET32: pass = (addr->Layer == WINDIVERT_LAYER_NETWORK || addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD); break; @@ -2309,6 +2529,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, case WINDIVERT_FILTER_FIELD_TCP_WINDOW: case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM: case WINDIVERT_FILTER_FIELD_TCP_URGPTR: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32: case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH: pass = (addr->Layer == WINDIVERT_LAYER_NETWORK || addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD); @@ -2318,6 +2541,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, case WINDIVERT_FILTER_FIELD_UDP_DSTPORT: case WINDIVERT_FILTER_FIELD_UDP_LENGTH: case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32: case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH: pass = (addr->Layer == WINDIVERT_LAYER_NETWORK || addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD); @@ -2332,7 +2558,6 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, pc = object[pc].failure; continue; } - val[1] = val[2] = val[3] = 0; switch (object[pc].field) { case WINDIVERT_FILTER_FIELD_ZERO: @@ -2341,6 +2566,39 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, case WINDIVERT_FILTER_FIELD_EVENT: val[0] = addr->Event; break; + case WINDIVERT_FILTER_FIELD_PACKET: + pass = WinDivertGetData(packet, packet_len, /*offset=*/0, + object[pc].arg[1], sizeof(data8), &data8); + val[0] = data8; + break; + case WINDIVERT_FILTER_FIELD_PACKET16: + pass = WinDivertGetData(packet, packet_len, /*offset=*/0, + object[pc].arg[1], sizeof(data16), &data16); + val[0] = ntohs(data16); + break; + case WINDIVERT_FILTER_FIELD_PACKET32: + pass = WinDivertGetData(packet, packet_len, /*offset=*/0, + object[pc].arg[1], sizeof(data32), &data32); + val[0] = ntohl(data32); + break; + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD: + pass = WinDivertGetData(packet, packet_len, header_len, + object[pc].arg[1], sizeof(data8), &data8); + val[0] = data8; + break; + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16: + pass = WinDivertGetData(packet, packet_len, header_len, + object[pc].arg[1], sizeof(data16), &data16); + val[0] = ntohs(data16); + break; + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32: + pass = WinDivertGetData(packet, packet_len, header_len, + object[pc].arg[1], sizeof(data32), &data32); + val[0] = ntohl(data32); + break; case WINDIVERT_FILTER_FIELD_INBOUND: val[0] = !addr->Outbound; break; @@ -2495,12 +2753,14 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, val[0] = ipv6hdr->HopLimit; break; case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR: + big = TRUE; val[3] = ntohl(ipv6hdr->SrcAddr[0]); val[2] = ntohl(ipv6hdr->SrcAddr[1]); val[1] = ntohl(ipv6hdr->SrcAddr[2]); val[0] = ntohl(ipv6hdr->SrcAddr[3]); break; case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR: + big = TRUE; val[3] = ntohl(ipv6hdr->DstAddr[0]); val[2] = ntohl(ipv6hdr->DstAddr[1]); val[1] = ntohl(ipv6hdr->DstAddr[2]); @@ -2591,6 +2851,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, val[0] = payload_len; break; case WINDIVERT_FILTER_FIELD_LOCALADDR: + big = TRUE; switch (addr->Layer) { case WINDIVERT_LAYER_NETWORK: @@ -2633,6 +2894,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, } break; case WINDIVERT_FILTER_FIELD_REMOTEADDR: + big = TRUE; switch (addr->Layer) { case WINDIVERT_LAYER_NETWORK: @@ -2772,7 +3034,12 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - cmp = WinDivertBigNumCompare(val, object[pc].arg); + if (!pass) + { + pc = object[pc].failure; + continue; + } + cmp = WinDivertBigNumCompare(val, object[pc].arg, big); switch (object[pc].test) { case WINDIVERT_FILTER_TEST_EQ: @@ -2903,6 +3170,22 @@ static BOOL WinDivertDeserializeTest(PWINDIVERT_STREAM stream, filter->arg[1] = 0x0000FFFF; filter->arg[2] = filter->arg[3] = 0; break; + case WINDIVERT_FILTER_FIELD_PACKET: + case WINDIVERT_FILTER_FIELD_PACKET16: + case WINDIVERT_FILTER_FIELD_PACKET32: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32: + if (!WinDivertDeserializeNumber(stream, 7, &val)) + { + return FALSE; + } + filter->arg[1] = (UINT32)((INT)val - UINT16_MAX); + filter->arg[2] = filter->arg[3] = 0; + break; default: filter->arg[1] = filter->arg[2] = filter->arg[3] = 0; break; @@ -2994,6 +3277,7 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test) { KIND kind; PEXPR var, val, expr; + UINT32 tmp[4]; ERROR error; switch (test->field) @@ -3002,6 +3286,24 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test) kind = TOKEN_ZERO; break; case WINDIVERT_FILTER_FIELD_EVENT: kind = TOKEN_EVENT; break; + case WINDIVERT_FILTER_FIELD_PACKET: + kind = TOKEN_PACKET; break; + case WINDIVERT_FILTER_FIELD_PACKET16: + kind = TOKEN_PACKET16; break; + case WINDIVERT_FILTER_FIELD_PACKET32: + kind = TOKEN_PACKET32; break; + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD: + kind = TOKEN_TCP_PAYLOAD; break; + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16: + kind = TOKEN_TCP_PAYLOAD16; break; + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32: + kind = TOKEN_TCP_PAYLOAD32; break; + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD: + kind = TOKEN_UDP_PAYLOAD; break; + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16: + kind = TOKEN_UDP_PAYLOAD16; break; + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32: + kind = TOKEN_UDP_PAYLOAD32; break; case WINDIVERT_FILTER_FIELD_INBOUND: kind = TOKEN_INBOUND; break; case WINDIVERT_FILTER_FIELD_OUTBOUND: @@ -3138,15 +3440,42 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test) return NULL; } - var = WinDivertMakeVar(kind, &error); - if (var == NULL) + switch (kind) { - return NULL; - } - val = WinDivertMakeNumber(pool, test->arg, &error); - if (val == NULL) - { - return NULL; + case TOKEN_PACKET: + case TOKEN_PACKET16: + case TOKEN_PACKET32: + case TOKEN_TCP_PAYLOAD: + case TOKEN_TCP_PAYLOAD16: + case TOKEN_TCP_PAYLOAD32: + case TOKEN_UDP_PAYLOAD: + case TOKEN_UDP_PAYLOAD16: + case TOKEN_UDP_PAYLOAD32: + var = WinDivertMakeArrayVar(pool, kind, test->arg[1], &error); + if (var == NULL) + { + return NULL; + } + tmp[0] = test->arg[0]; + tmp[1] = tmp[2] = tmp[3] = 0; + val = WinDivertMakeNumber(pool, tmp, &error); + if (val == NULL) + { + return NULL; + } + break; + default: + var = WinDivertMakeVar(kind, &error); + if (var == NULL) + { + return NULL; + } + val = WinDivertMakeNumber(pool, test->arg, &error); + if (val == NULL) + { + return NULL; + } + break; } switch (test->test) @@ -3558,7 +3887,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_event = FALSE; + is_event = FALSE, is_hex = FALSE; switch (field->kind) { @@ -3618,6 +3947,23 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr, case TOKEN_EVENT: is_event = TRUE; break; + case TOKEN_PACKET: + case TOKEN_PACKET16: + case TOKEN_PACKET32: + case TOKEN_IP_ID: + case TOKEN_IP_CHECKSUM: + case TOKEN_TCP_CHECKSUM: + case TOKEN_TCP_PAYLOAD: + case TOKEN_TCP_PAYLOAD16: + case TOKEN_TCP_PAYLOAD32: + case TOKEN_UDP_CHECKSUM: + case TOKEN_UDP_PAYLOAD: + case TOKEN_UDP_PAYLOAD16: + case TOKEN_UDP_PAYLOAD32: + case TOKEN_ICMP_CHECKSUM: + case TOKEN_ICMPV6_CHECKSUM: + is_hex = TRUE; + break; default: break; } @@ -3723,6 +4069,11 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr, WinDivertFormatNumber(stream, val->val[0]); break; } } + else if (is_hex) + { + WinDivertPutString(stream, "0x"); + WinDivertFormatHexNumber(stream, val->val[0]); + } else { WinDivertFormatNumber(stream, val->val[0]); @@ -3735,6 +4086,8 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr, static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr, WINDIVERT_LAYER layer, BOOL top_level, BOOL and) { + INT idx; + if (stream->pos >= stream->max) { return; @@ -3802,6 +4155,24 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr, WinDivertPutString(stream, "zero"); return; case TOKEN_EVENT: WinDivertPutString(stream, "event"); return; + case TOKEN_PACKET: + WinDivertPutString(stream, "packet"); break; + case TOKEN_PACKET16: + WinDivertPutString(stream, "packet16"); break; + case TOKEN_PACKET32: + WinDivertPutString(stream, "packet32"); break; + case TOKEN_TCP_PAYLOAD: + WinDivertPutString(stream, "tcp.Payload"); break; + case TOKEN_TCP_PAYLOAD16: + WinDivertPutString(stream, "tcp.Payload16"); break; + case TOKEN_TCP_PAYLOAD32: + WinDivertPutString(stream, "tcp.Payload32"); break; + case TOKEN_UDP_PAYLOAD: + WinDivertPutString(stream, "udp.Payload"); break; + case TOKEN_UDP_PAYLOAD16: + WinDivertPutString(stream, "udp.Payload16"); break; + case TOKEN_UDP_PAYLOAD32: + WinDivertPutString(stream, "udp.Payload32"); break; case TOKEN_INBOUND: WinDivertPutString(stream, "inbound"); return; case TOKEN_OUTBOUND: @@ -3935,9 +4306,18 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr, case TOKEN_LAYER: WinDivertPutString(stream, "layer"); return; case TOKEN_NUMBER: - WinDivertFormatNumber(stream, expr->val[0]); - return; + WinDivertFormatNumber(stream, expr->val[0]); return; } + + WinDivertPutChar(stream, '['); + idx = (INT)expr->val[0]; + if (idx < 0) + { + WinDivertPutChar(stream, '-'); + idx = -idx; + } + WinDivertFormatNumber(stream, (UINT32)idx); + WinDivertPutString(stream, "b]"); } /* diff --git a/dll/windivert_shared.c b/dll/windivert_shared.c index 337064c..bd6b9e0 100644 --- a/dll/windivert_shared.c +++ b/dll/windivert_shared.c @@ -167,6 +167,7 @@ static void WinDivertSerializeNumber(PWINDIVERT_STREAM stream, UINT32 val) static void WinDivertSerializeTest(PWINDIVERT_STREAM stream, PWINDIVERT_FILTER filter) { + INT idx; UINT i; WinDivertPutChar(stream, '_'); @@ -184,6 +185,19 @@ static void WinDivertSerializeTest(PWINDIVERT_STREAM stream, WinDivertSerializeNumber(stream, filter->arg[i]); } break; + case WINDIVERT_FILTER_FIELD_PACKET: + case WINDIVERT_FILTER_FIELD_PACKET16: + case WINDIVERT_FILTER_FIELD_PACKET32: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32: + idx = (INT)filter->arg[1]; + idx += UINT16_MAX; + WinDivertSerializeNumber(stream, (UINT32)idx); + break; default: break; } diff --git a/include/windivert_device.h b/include/windivert_device.h index 65e194f..3efd822 100644 --- a/include/windivert_device.h +++ b/include/windivert_device.h @@ -127,8 +127,17 @@ #define WINDIVERT_FILTER_FIELD_PROTOCOL 65 #define WINDIVERT_FILTER_FIELD_LAYER 66 #define WINDIVERT_FILTER_FIELD_EVENT 67 +#define WINDIVERT_FILTER_FIELD_PACKET 68 +#define WINDIVERT_FILTER_FIELD_PACKET16 69 +#define WINDIVERT_FILTER_FIELD_PACKET32 70 +#define WINDIVERT_FILTER_FIELD_TCP_PAYLOAD 71 +#define WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16 72 +#define WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32 73 +#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD 74 +#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16 75 +#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32 76 #define WINDIVERT_FILTER_FIELD_MAX \ - WINDIVERT_FILTER_FIELD_EVENT + WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32 #define WINDIVERT_FILTER_TEST_EQ 0 #define WINDIVERT_FILTER_TEST_NEQ 1 diff --git a/sys/windivert.c b/sys/windivert.c index 4f2e817..175991c 100644 --- a/sys/windivert.c +++ b/sys/windivert.c @@ -457,13 +457,14 @@ 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 BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4); -static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b); +static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b, + BOOL big); static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4, PWINDIVERT_IPHDR *ip_header_ptr, PWINDIVERT_IPV6HDR *ipv6_header_ptr, PWINDIVERT_ICMPHDR *icmp_header_ptr, PWINDIVERT_ICMPV6HDR *icmpv6_header_ptr, PWINDIVERT_TCPHDR *tcp_header_ptr, PWINDIVERT_UDPHDR *udp_header_ptr, - UINT8 *proto_ptr, UINT *payload_len_ptr); + UINT8 *proto_ptr, UINT *header_len_ptr, UINT *payload_len_ptr); static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, PVOID layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, PWINDIVERT_FILTER filter); @@ -3014,7 +3015,7 @@ static void windivert_get_ipv6_addr(const FWPS_INCOMING_VALUES0 *fixed_vals, UINT8 *addr8 = (UINT8 *)addr; INT i; FWP_VALUE0 value = fixed_vals->incomingValue[idx].value; - if (value.type != FWP_BYTE_ARRAY16_TYPE) + if (value.type != FWP_BYTE_ARRAY16_TYPE) { RtlZeroMemory(&addr, 16); return; @@ -4431,31 +4432,34 @@ static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4) /* * Big number comparison. */ -static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b) +static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b, BOOL big) { - if (a[3] < b[3]) + if (big) { - return -1; - } - if (a[3] > b[3]) - { - return 1; - } - if (a[2] < b[2]) - { - return -1; - } - if (a[2] > b[2]) - { - return 1; - } - if (a[1] < b[1]) - { - return -1; - } - if (a[1] > b[1]) - { - return 1; + if (a[3] < b[3]) + { + return -1; + } + if (a[3] > b[3]) + { + return 1; + } + if (a[2] < b[2]) + { + return -1; + } + if (a[2] > b[2]) + { + return 1; + } + if (a[1] < b[1]) + { + return -1; + } + if (a[1] > b[1]) + { + return 1; + } } if (a[0] < b[0]) { @@ -4468,6 +4472,44 @@ static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b) return 0; } +/* + * Get packet/payload data. + */ +static BOOL windivert_get_data(PNET_BUFFER buffer, UINT offset, INT idx, + UINT size, PVOID data) +{ + PVOID ptr; + UINT length = NET_BUFFER_DATA_LENGTH(buffer); + + if (idx < 0) + { + idx += (INT)length; + } + else + { + idx += (INT)offset; + } + if (idx < (INT)offset || idx > (INT)(length - size)) + { + return FALSE; // OOB + } + + if (idx > 0) + { + NdisAdvanceNetBufferDataStart(buffer, idx, FALSE, NULL); + } + ptr = NdisGetDataBuffer(buffer, size, data, 1, 0); + if (ptr != NULL && ptr != data) + { + RtlCopyMemory(data, ptr, size); // Non-contiguous case + } + if (idx > 0) + { + (VOID)NdisRetreatNetBufferDataStart(buffer, idx, 0, NULL); + } + return TRUE; +} + /* * Parse packet headers. */ @@ -4476,7 +4518,7 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4, PWINDIVERT_ICMPHDR *icmp_header_ptr, PWINDIVERT_ICMPV6HDR *icmpv6_header_ptr, PWINDIVERT_TCPHDR *tcp_header_ptr, PWINDIVERT_UDPHDR *udp_header_ptr, - UINT8 *proto_ptr, UINT *payload_len_ptr) + UINT8 *proto_ptr, UINT *header_len_ptr, UINT *payload_len_ptr) { UINT tot_len, ip_header_len; PWINDIVERT_IPHDR ip_header = NULL; @@ -4487,7 +4529,7 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4, PWINDIVERT_UDPHDR udp_header = NULL; UINT16 ip, ttl; UINT8 proto = 0; - UINT payload_len = 0; + UINT header_len = 0, payload_len = 0; NTSTATUS status; // Parse the headers: @@ -4609,23 +4651,25 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4, case IPPROTO_ICMP: icmp_header = (PWINDIVERT_ICMPHDR)NdisGetDataBuffer(buffer, sizeof(WINDIVERT_ICMPHDR), NULL, 1, 0); + header_len = ip_header_len + sizeof(WINDIVERT_ICMPHDR); break; case IPPROTO_ICMPV6: icmpv6_header = (PWINDIVERT_ICMPV6HDR)NdisGetDataBuffer(buffer, sizeof(WINDIVERT_ICMPV6HDR), NULL, 1, 0); + header_len = ip_header_len + sizeof(WINDIVERT_ICMPV6HDR); break; case IPPROTO_TCP: tcp_header = (PWINDIVERT_TCPHDR)NdisGetDataBuffer(buffer, sizeof(WINDIVERT_TCPHDR), NULL, 1, 0); - payload_len = tot_len - ip_header_len - - tcp_header->HdrLength*sizeof(UINT32); + header_len = ip_header_len + tcp_header->HdrLength*sizeof(UINT32); break; case IPPROTO_UDP: udp_header = (PWINDIVERT_UDPHDR)NdisGetDataBuffer(buffer, sizeof(WINDIVERT_UDPHDR), NULL, 1, 0); - payload_len = tot_len - ip_header_len - sizeof(WINDIVERT_UDPHDR); + header_len = ip_header_len + sizeof(WINDIVERT_UDPHDR); break; default: + header_len = ip_header_len; break; } @@ -4644,7 +4688,8 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4, *tcp_header_ptr = tcp_header; *udp_header_ptr = udp_header; *proto_ptr = proto; - *payload_len_ptr = payload_len; + *header_len_ptr = header_len; + *payload_len_ptr = tot_len - header_len; return TRUE; } @@ -4663,12 +4708,15 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, PWINDIVERT_TCPHDR tcp_header = NULL; PWINDIVERT_UDPHDR udp_header = NULL; UINT8 protocol = 0; - UINT payload_len = 0; + UINT header_len = 0, payload_len = 0; UINT16 ip, ttl; PWINDIVERT_DATA_NETWORK network_data = NULL; PWINDIVERT_DATA_FLOW flow_data = NULL; PWINDIVERT_DATA_SOCKET socket_data = NULL; PWINDIVERT_DATA_REFLECT reflect_data = NULL; + UINT8 data8; + UINT16 data16; + UINT32 data32; NTSTATUS status; switch (layer) @@ -4677,7 +4725,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, case WINDIVERT_LAYER_NETWORK_FORWARD: if (!windivert_parse_headers(buffer, ipv4, &ip_header, &ipv6_header, &icmp_header, &icmpv6_header, &tcp_header, &udp_header, - &protocol, &payload_len)) + &protocol, &header_len, &payload_len)) { return FALSE; } @@ -4703,12 +4751,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, while (ttl-- != 0) { BOOL result = FALSE; - BOOL error = FALSE; + BOOL big = FALSE; int cmp; UINT32 field[4]; - field[1] = 0; - field[2] = 0; - field[3] = 0; switch (filter[ip].field) { @@ -4733,6 +4778,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, break; case WINDIVERT_FILTER_FIELD_IFIDX: case WINDIVERT_FILTER_FIELD_SUBIFIDX: + case WINDIVERT_FILTER_FIELD_PACKET: + case WINDIVERT_FILTER_FIELD_PACKET16: + case WINDIVERT_FILTER_FIELD_PACKET32: result = (layer == WINDIVERT_LAYER_NETWORK || layer == WINDIVERT_LAYER_NETWORK_FORWARD); break; @@ -4810,6 +4858,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, case WINDIVERT_FILTER_FIELD_TCP_WINDOW: case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM: case WINDIVERT_FILTER_FIELD_TCP_URGPTR: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32: case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH: result = (layer == WINDIVERT_LAYER_NETWORK || layer == WINDIVERT_LAYER_NETWORK_FORWARD); @@ -4819,15 +4870,16 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, case WINDIVERT_FILTER_FIELD_UDP_DSTPORT: case WINDIVERT_FILTER_FIELD_UDP_LENGTH: case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32: case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH: result = (layer == WINDIVERT_LAYER_NETWORK || layer == WINDIVERT_LAYER_NETWORK_FORWARD); result = result && (udp_header != NULL); break; default: - result = FALSE; - error = TRUE; - break; + return FALSE; } if (result) { @@ -4839,6 +4891,39 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, case WINDIVERT_FILTER_FIELD_EVENT: field[0] = (UINT32)event; break; + case WINDIVERT_FILTER_FIELD_PACKET: + result = windivert_get_data(buffer, /*offset=*/0, + (INT)filter[ip].arg[1], sizeof(data8), &data8); + field[0] = (UINT32)data8; + break; + case WINDIVERT_FILTER_FIELD_PACKET16: + result = windivert_get_data(buffer, /*offset=*/0, + (INT)filter[ip].arg[1], sizeof(data16), &data16); + field[0] = (UINT32)RtlUshortByteSwap(data16); + break; + case WINDIVERT_FILTER_FIELD_PACKET32: + result = windivert_get_data(buffer, /*offset=*/0, + (INT)filter[ip].arg[1], sizeof(data32), &data32); + field[0] = (UINT32)RtlUlongByteSwap(data32); + break; + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD: + result = windivert_get_data(buffer, header_len, + (INT)filter[ip].arg[1], sizeof(data8), &data8); + field[0] = (UINT32)data8; + break; + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16: + result = windivert_get_data(buffer, header_len, + (INT)filter[ip].arg[1], sizeof(data16), &data16); + field[0] = (UINT32)RtlUshortByteSwap(data16); + break; + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32: + result = windivert_get_data(buffer, header_len, + (INT)filter[ip].arg[1], sizeof(data32), &data32); + field[0] = (UINT32)RtlUlongByteSwap(data32); + break; case WINDIVERT_FILTER_FIELD_INBOUND: field[0] = (UINT32)!outbound; break; @@ -4879,9 +4964,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, flow_data->Protocol == IPPROTO_ICMP); break; default: - error = TRUE; - result = FALSE; - break; + return FALSE; } break; case WINDIVERT_FILTER_FIELD_ICMPV6: @@ -4900,9 +4983,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, flow_data->Protocol == IPPROTO_ICMPV6); break; default: - error = TRUE; - result = FALSE; - break; + return FALSE; } break; case WINDIVERT_FILTER_FIELD_TCP: @@ -4921,9 +5002,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, (UINT32)(flow_data->Protocol == IPPROTO_TCP); break; default: - error = TRUE; - result = FALSE; - break; + return FALSE; } break; case WINDIVERT_FILTER_FIELD_UDP: @@ -4942,9 +5021,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, (UINT32)(flow_data->Protocol == IPPROTO_UDP); break; default: - error = TRUE; - result = FALSE; - break; + return FALSE; } break; case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH: @@ -5004,6 +5081,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, field[0] = (UINT32)ipv6_header->HopLimit; break; case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR: + big = TRUE; field[3] = (UINT32)RtlUlongByteSwap(ipv6_header->SrcAddr[0]); field[2] = @@ -5014,6 +5092,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, (UINT32)RtlUlongByteSwap(ipv6_header->SrcAddr[3]); break; case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR: + big = TRUE; field[3] = (UINT32)RtlUlongByteSwap(ipv6_header->DstAddr[0]); field[2] = @@ -5111,6 +5190,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, field[0] = (UINT32)payload_len; break; case WINDIVERT_FILTER_FIELD_LOCALADDR: + big = TRUE; switch (layer) { case WINDIVERT_LAYER_NETWORK: @@ -5157,12 +5237,11 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, field[3] = socket_data->LocalAddr[3]; break; default: - error = TRUE; - result = FALSE; - break; + return FALSE; } break; case WINDIVERT_FILTER_FIELD_REMOTEADDR: + big = TRUE; switch (layer) { case WINDIVERT_LAYER_NETWORK: @@ -5209,9 +5288,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, field[3] = socket_data->RemoteAddr[3]; break; default: - error = TRUE; - result = FALSE; - break; + return FALSE; } break; case WINDIVERT_FILTER_FIELD_LOCALPORT: @@ -5242,9 +5319,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, field[0] = (UINT32)socket_data->LocalPort; break; default: - error = TRUE; - result = FALSE; - break; + return FALSE; } break; case WINDIVERT_FILTER_FIELD_REMOTEPORT: @@ -5275,9 +5350,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, field[0] = (UINT32)socket_data->RemotePort; break; default: - error = TRUE; - result = FALSE; - break; + return FALSE; } break; case WINDIVERT_FILTER_FIELD_PROTOCOL: @@ -5293,9 +5366,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, field[0] = (UINT32)socket_data->Protocol; break; default: - error = TRUE; - result = FALSE; - break; + return FALSE; } break; case WINDIVERT_FILTER_FIELD_PROCESSID: @@ -5311,22 +5382,19 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, field[0] = reflect_data->ProcessId; break; default: - error = TRUE; - result = FALSE; + return FALSE; } break; case WINDIVERT_FILTER_FIELD_LAYER: field[0] = reflect_data->Layer; break; default: - error = TRUE; - result = FALSE; - break; + return FALSE; } } if (result) { - cmp = windivert_big_num_compare(field, filter[ip].arg); + cmp = windivert_big_num_compare(field, filter[ip].arg, big); switch (filter[ip].test) { case WINDIVERT_FILTER_TEST_EQ: @@ -5348,16 +5416,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, result = (cmp >= 0); break; default: - error = TRUE; - result = FALSE; - break; + return FALSE; } } - if (error) - { - DEBUG("FILTER: REJECT (bad filter)"); - return FALSE; - } ip = (result? filter[ip].success: filter[ip].failure); if (ip == WINDIVERT_FILTER_RESULT_ACCEPT) { @@ -5447,17 +5508,38 @@ static PWINDIVERT_FILTER windivert_filter_compile( { goto windivert_filter_compile_error; } - if ((ioctl_filter[i].field == WINDIVERT_FILTER_FIELD_IP_SRCADDR || - ioctl_filter[i].field == WINDIVERT_FILTER_FIELD_IP_DSTADDR)) + switch (ioctl_filter[i].field) { - if (ioctl_filter[i].arg[1] != 0x0000FFFF) + case WINDIVERT_FILTER_FIELD_IP_SRCADDR: + case WINDIVERT_FILTER_FIELD_IP_DSTADDR: + if (ioctl_filter[i].arg[1] != 0x0000FFFF) + { + goto windivert_filter_compile_error; + } + break; + case WINDIVERT_FILTER_FIELD_PACKET: + case WINDIVERT_FILTER_FIELD_PACKET16: + case WINDIVERT_FILTER_FIELD_PACKET32: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32: { - goto windivert_filter_compile_error; + INT idx = (INT)ioctl_filter[i].arg[1]; + if (idx > UINT16_MAX || idx < -UINT16_MAX) + { + goto windivert_filter_compile_error; + } + break; } - } - else if (ioctl_filter[i].arg[1] != 0) - { - goto windivert_filter_compile_error; + default: + if (ioctl_filter[i].arg[1] != 0) + { + goto windivert_filter_compile_error; + } + break; } } switch (ioctl_filter[i].field) @@ -5547,6 +5629,9 @@ static PWINDIVERT_FILTER windivert_filter_compile( case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE: case WINDIVERT_FILTER_FIELD_ICMPV6_CODE: case WINDIVERT_FILTER_FIELD_PROTOCOL: + case WINDIVERT_FILTER_FIELD_PACKET: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD: if (ioctl_filter[i].arg[0] > UINT8_MAX) { goto windivert_filter_compile_error; @@ -5577,6 +5662,9 @@ static PWINDIVERT_FILTER windivert_filter_compile( case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH: case WINDIVERT_FILTER_FIELD_LOCALPORT: case WINDIVERT_FILTER_FIELD_REMOTEPORT: + case WINDIVERT_FILTER_FIELD_PACKET16: + case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16: + case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16: if (ioctl_filter[i].arg[0] > UINT16_MAX) { goto windivert_filter_compile_error; diff --git a/test/test.c b/test/test.c index ed8b590..7dde63a 100644 --- a/test/test.c +++ b/test/test.c @@ -114,6 +114,22 @@ static struct packet pkt_ipv6_exthdrs_udp = static struct test tests[] = { {"event = PACKET", &pkt_echo_request, TRUE}, + {"packet[0] == 0x45", &pkt_echo_request, TRUE}, + {"packet[0] == 0x33", &pkt_echo_request, FALSE}, + {"packet[55] == 0x1b", &pkt_echo_request, TRUE}, + {"packet[55b] == 0x1b", &pkt_echo_request, TRUE}, + {"packet[1000] <= 0 || packet[-1000] = 7", &pkt_echo_request, FALSE}, + {"packet[-1] == 0x37 && packet[-2] == 0x36 && packet[-3] == 0x35 && " + "packet[-4] == 0x34", &pkt_echo_request, TRUE}, + {"packet16[0] == 0x4500", &pkt_echo_request, TRUE}, + {"packet16[0] == 0x0045", &pkt_echo_request, FALSE}, + {"packet16[2b] == 0x0054", &pkt_echo_request, TRUE}, + {"packet16[1] == 0x0054", &pkt_echo_request, TRUE}, + {"packet16[0] == 0x4500 && packet16[1] == 0x0054 && " + "packet16[-1] == 0x3637", &pkt_echo_request, TRUE}, + {"packet32[0b] == 0x45000054 && packet32[3b] == 0x54123440 && " + "packet32[-4b] == 0x34353637 && packet32[-5b] == 0x33343536", + &pkt_echo_request, TRUE}, {"outbound and icmp", &pkt_echo_request, TRUE}, {"outbound", &pkt_echo_request, TRUE}, {"outbound and inbound", &pkt_echo_request, FALSE}, @@ -245,6 +261,74 @@ static struct test tests[] = {"(ipv6? tcp and tcp.DstPort = 1234 and (tcp.SrcPort = 999? !tcp.UrgPtr: " "tcp.Syn) or udp: ip and tcp.DstPort == 80)", &pkt_http_request, TRUE}, + {"packet32[0] = 0x45000209 && packet32[1] = 0x482d4000 && " + "packet16[8b] = 0x4006 && packet32[3] = 0x0a0a0a0a && " + "packet32[4] = 0x5db8d877 && packet32[5] = 0xa31a0050 && " + "packet32[6] = 0x5338ccc2 && packet32[7] = 0x5637b355 && " + "packet32[8] = 0x80180073 && packet16[38b] = 0x0000 && " + "packet32[10] = 0x0101080a && packet32[11] = 0x002c851b && " + "packet32[12] = 0x1b7f3a71 && packet32[13] = 0x47455420 && " + "packet32[14] = 0x2f204854 && packet32[15] = 0x54502f31 && " + "packet32[16] = 0x2e310d0a && packet32[17] = 0x486f7374 && " + "packet32[18] = 0x3a207777 && packet32[19] = 0x772e6578 && " + "packet32[20] = 0x616d706c && packet32[21] = 0x652e636f && " + "packet32[22] = 0x6d0d0a43 && packet32[23] = 0x6f6e6e65 && " + "packet32[24] = 0x6374696f && packet32[25] = 0x6e3a206b && " + "packet32[26] = 0x6565702d && packet32[27] = 0x616c6976 && " + "packet32[28] = 0x650d0a43 && packet32[29] = 0x61636865 && " + "packet32[30] = 0x2d436f6e && packet32[31] = 0x74726f6c && " + "packet32[32] = 0x3a206d61 && packet32[33] = 0x782d6167 && " + "packet32[34] = 0x653d300d && packet32[35] = 0x0a416363 && " + "packet32[36] = 0x6570743a && packet32[37] = 0x20746578 && " + "packet32[38] = 0x742f6874 && packet32[39] = 0x6d6c2c61 && " + "packet32[40] = 0x70706c69 && packet32[41] = 0x63617469 && " + "packet32[42] = 0x6f6e2f78 && packet32[43] = 0x68746d6c && " + "packet32[44] = 0x2b786d6c && packet32[45] = 0x2c617070 && " + "packet32[46] = 0x6c696361 && packet32[47] = 0x74696f6e && " + "packet32[48] = 0x2f786d6c && packet32[49] = 0x3b713d30 && " + "packet32[50] = 0x2e392c69 && packet32[51] = 0x6d616765 && " + "packet32[52] = 0x2f776562 && packet32[53] = 0x702c2a2f && " + "packet32[54] = 0x2a3b713d && packet32[55] = 0x302e380d && " + "packet32[56] = 0x0a557365 && packet32[57] = 0x722d4167 && " + "packet32[58] = 0x656e743a && packet32[59] = 0x20585858 && " + "packet32[60] = 0x58585858 && packet32[61] = 0x58585858 && " + "packet32[62] = 0x58585858 && packet32[63] = 0x58585858 && " + "packet32[64] = 0x58585858 && packet32[65] = 0x58585858 && " + "packet32[66] = 0x58585858 && packet32[67] = 0x58585858 && " + "packet32[68] = 0x58585858 && packet32[69] = 0x58585858 && " + "packet32[70] = 0x58585858 && packet32[71] = 0x58585858 && " + "packet32[72] = 0x58585858 && packet32[73] = 0x58585858 && " + "packet32[74] = 0x58585858 && packet32[75] = 0x58585858 && " + "packet32[76] = 0x58585858 && packet32[77] = 0x58585858 && " + "packet32[78] = 0x58585858 && packet32[79] = 0x58585858 && " + "packet32[80] = 0x58585858 && packet32[81] = 0x58585858 && " + "packet32[82] = 0x58585858 && packet32[83] = 0x58585858 && " + "packet32[84] = 0x58585858 && packet32[85] = 0x58585858 && " + "packet32[86] = 0x58585858 && packet32[87] = 0x58585858 && " + "packet32[88] = 0x58585858 && packet32[89] = 0x58585858 && " + "packet32[90] = 0x58585858 && packet32[91] = 0x58585858 && " + "packet32[92] = 0x58580d0a && packet32[93] = 0x41636365 && " + "packet32[94] = 0x70742d45 && packet32[95] = 0x6e636f64 && " + "packet32[96] = 0x696e673a && packet32[97] = 0x20677a69 && " + "packet32[98] = 0x702c6465 && packet32[99] = 0x666c6174 && " + "packet32[100] = 0x652c7364 && packet32[101] = 0x63680d0a && " + "packet32[102] = 0x41636365 && packet32[103] = 0x70742d4c && " + "packet32[104] = 0x616e6775 && packet32[105] = 0x6167653a && " + "packet32[106] = 0x20656e2d && packet32[107] = 0x55532c65 && " + "packet32[108] = 0x6e3b713d && packet32[109] = 0x302e380d && " + "packet32[110] = 0x0a49662d && packet32[111] = 0x4e6f6e65 && " + "packet32[112] = 0x2d4d6174 && packet32[113] = 0x63683a20 && " + "packet32[114] = 0x22333333 && packet32[115] = 0x33333333 && " + "packet32[116] = 0x3333220d && packet32[117] = 0x0a49662d && " + "packet32[118] = 0x4d6f6469 && packet32[119] = 0x66696564 && " + "packet32[120] = 0x2d53696e && packet32[121] = 0x63653a20 && " + "packet32[122] = 0x4672692c && packet32[123] = 0x20303320 && " + "packet32[124] = 0x41756720 && packet32[125] = 0x32303134 && " + "packet32[126] = 0x2031333a && packet32[127] = 0x33333a33 && " + "packet32[128] = 0x3320474d && packet32[129] = 0x540d0a0d && " + "packet[-1] = 0x0a", &pkt_http_request, TRUE}, + {"tcp.Payload16[-1] == 0x0d0a", &pkt_http_request, TRUE}, + {"tcp.Payload32[-2] == 0x20474d54", &pkt_http_request, TRUE}, {"udp", &pkt_dns_request, TRUE}, {"udp && udp.SrcPort > 1 && ipv6", &pkt_dns_request, FALSE}, {"udp.DstPort == 53", &pkt_dns_request, TRUE}, @@ -260,6 +344,10 @@ static struct test tests[] = {"ip.DstAddr == ::ffff:8.8.4.4", &pkt_dns_request, TRUE}, {"ip.DstAddr == ::0:ffff:8.8.4.4", &pkt_dns_request, TRUE}, {"udp.PayloadLength == 29", &pkt_dns_request, TRUE}, + {"udp.Payload16[-1] == 0x0001 && udp.Payload16[-2] == 0x0001", + &pkt_dns_request, TRUE}, + {"packet16[-1] == 0x0001 && packet16[-2] == 0x0001", + &pkt_dns_request, TRUE}, {"ipv6", &pkt_ipv6_tcp_syn, TRUE}, {"ip", &pkt_ipv6_tcp_syn, FALSE}, {"tcp.Syn", &pkt_ipv6_tcp_syn, TRUE}, @@ -351,7 +439,7 @@ int main(void) // Run the test: BOOL res = run_test(upper_handle, filter, packet, packet_len, match); - printf("%.2u ", i); + printf("%.3u ", i); if (res) { SetConsoleTextAttribute(console, FOREGROUND_GREEN);