diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c index 86b39b6..24d7ac0 100644 --- a/dll/windivert_helper.c +++ b/dll/windivert_helper.c @@ -109,6 +109,7 @@ typedef enum TOKEN_UDP_PAYLOAD_LENGTH, TOKEN_UDP_SRC_PORT, TOKEN_ZERO, + TOKEN_EVENT, TOKEN_TRUE, TOKEN_FALSE, TOKEN_INBOUND, @@ -128,6 +129,12 @@ typedef enum TOKEN_NETWORK, TOKEN_NETWORK_FORWARD, TOKEN_REFLECT, + TOKEN_NETWORK_PACKET, + TOKEN_FLOW_ESTABLISHED, + TOKEN_FLOW_DELETED, + TOKEN_REFLECT_ESTABLISHED, + TOKEN_REFLECT_OPEN, + TOKEN_REFLECT_CLOSE, TOKEN_OPEN, TOKEN_CLOSE, TOKEN_EQ, @@ -820,6 +827,11 @@ static BOOL WinDivertCheckTokenKindForLayer(WINDIVERT_LAYER layer, KIND kind) case TOKEN_NETWORK: case TOKEN_NETWORK_FORWARD: case TOKEN_REFLECT: + case TOKEN_FLOW_ESTABLISHED: + case TOKEN_FLOW_DELETED: + case TOKEN_REFLECT_ESTABLISHED: + case TOKEN_REFLECT_OPEN: + case TOKEN_REFLECT_CLOSE: return FALSE; default: return TRUE; @@ -882,6 +894,10 @@ static BOOL WinDivertCheckTokenKindForLayer(WINDIVERT_LAYER layer, KIND kind) case TOKEN_NETWORK: case TOKEN_NETWORK_FORWARD: case TOKEN_REFLECT: + case TOKEN_NETWORK_PACKET: + case TOKEN_REFLECT_ESTABLISHED: + case TOKEN_REFLECT_OPEN: + case TOKEN_REFLECT_CLOSE: return FALSE; default: return TRUE; @@ -953,6 +969,9 @@ static BOOL WinDivertCheckTokenKindForLayer(WINDIVERT_LAYER layer, KIND kind) case TOKEN_LOCAL_PORT: case TOKEN_REMOTE_PORT: case TOKEN_PROTOCOL: + case TOKEN_NETWORK_PACKET: + case TOKEN_FLOW_ESTABLISHED: + case TOKEN_FLOW_DELETED: return FALSE; default: return TRUE; @@ -981,6 +1000,24 @@ static BOOL WinDivertExpandMacro(KIND kind, UINT32 *val) case TOKEN_REFLECT: *val = WINDIVERT_LAYER_REFLECT; return TRUE; + case TOKEN_NETWORK_PACKET: + *val = WINDIVERT_EVENT_NETWORK_PACKET; + return TRUE; + case TOKEN_FLOW_ESTABLISHED: + *val = WINDIVERT_EVENT_FLOW_ESTABLISHED; + return TRUE; + case TOKEN_FLOW_DELETED: + *val = WINDIVERT_EVENT_FLOW_DELETED; + return TRUE; + case TOKEN_REFLECT_ESTABLISHED: + *val = WINDIVERT_EVENT_REFLECT_ESTABLISHED; + return TRUE; + case TOKEN_REFLECT_OPEN: + *val = WINDIVERT_EVENT_REFLECT_OPEN; + return TRUE; + case TOKEN_REFLECT_CLOSE: + *val = WINDIVERT_EVENT_REFLECT_CLOSE; + return TRUE; default: return FALSE; } @@ -995,10 +1032,17 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, static const TOKEN_NAME token_names[] = { {"FLOW", TOKEN_FLOW}, + {"FLOW_DELETED", TOKEN_FLOW_DELETED}, + {"FLOW_ESTABLISHED", TOKEN_FLOW_ESTABLISHED}, {"NETWORK", TOKEN_NETWORK}, {"NETWORK_FORWARD", TOKEN_NETWORK_FORWARD}, + {"NETWORK_PACKET", TOKEN_NETWORK_PACKET}, {"REFLECT", TOKEN_REFLECT}, + {"REFLECT_CLOSE", TOKEN_REFLECT_CLOSE}, + {"REFLECT_ESTABLISHED", TOKEN_REFLECT_ESTABLISHED}, + {"REFLECT_OPEN", TOKEN_REFLECT_OPEN}, {"and", TOKEN_AND}, + {"event", TOKEN_EVENT}, {"false", TOKEN_FALSE}, {"icmp", TOKEN_ICMP}, {"icmp.Body", TOKEN_ICMP_BODY}, @@ -1322,6 +1366,7 @@ static PEXPR WinDivertMakeVar(KIND kind, PERROR error) {{{0}}, TOKEN_UDP_PAYLOAD_LENGTH}, {{{0}}, TOKEN_UDP_SRC_PORT}, {{{0}}, TOKEN_ZERO}, + {{{0}}, TOKEN_EVENT}, {{{0}}, TOKEN_TRUE}, {{{0}}, TOKEN_FALSE}, {{{0}}, TOKEN_INBOUND}, @@ -1446,6 +1491,7 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error) switch (toks[*i].kind) { case TOKEN_ZERO: + case TOKEN_EVENT: case TOKEN_TRUE: case TOKEN_FALSE: case TOKEN_OUTBOUND: @@ -1696,6 +1742,9 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) case TOKEN_LAYER: lb = 0; ub = WINDIVERT_LAYER_MAX; break; + case TOKEN_EVENT: + lb = 0; ub = WINDIVERT_EVENT_MAX; + break; case TOKEN_INBOUND: case TOKEN_OUTBOUND: case TOKEN_IP: @@ -1930,6 +1979,9 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset, case TOKEN_ZERO: object->field = WINDIVERT_FILTER_FIELD_ZERO; break; + case TOKEN_EVENT: + object->field = WINDIVERT_FILTER_FIELD_EVENT; + break; case TOKEN_OUTBOUND: object->field = WINDIVERT_FILTER_FIELD_OUTBOUND; break; @@ -2728,6 +2780,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, case WINDIVERT_FILTER_FIELD_ZERO: val[0] = 0; break; + case WINDIVERT_FILTER_FIELD_EVENT: + val[0] = addr->Event; + break; case WINDIVERT_FILTER_FIELD_INBOUND: val[0] = !addr->Outbound; break; @@ -3173,6 +3228,8 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test) { case WINDIVERT_FILTER_FIELD_ZERO: kind = TOKEN_ZERO; break; + case WINDIVERT_FILTER_FIELD_EVENT: + kind = TOKEN_EVENT; break; case WINDIVERT_FILTER_FIELD_INBOUND: kind = TOKEN_INBOUND; break; case WINDIVERT_FILTER_FIELD_OUTBOUND: @@ -3685,7 +3742,7 @@ static void WinDivertFormatIPv6Addr(PWINDIVERT_STREAM stream, static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr) { PEXPR field = expr->arg[0], val = expr->arg[1]; - BOOL ipv4_addr = FALSE, ipv6_addr = FALSE, layer = FALSE; + BOOL ipv4_addr = FALSE, ipv6_addr = FALSE, layer = FALSE, event = FALSE; switch (field->kind) { @@ -3742,6 +3799,9 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr) case TOKEN_LAYER: layer = TRUE; break; + case TOKEN_EVENT: + event = TRUE; + break; default: break; } @@ -3786,6 +3846,26 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr) WinDivertFormatNumber(stream, val->val[0]); break; } } + else if (event) + { + switch (val->val[0]) + { + case WINDIVERT_EVENT_NETWORK_PACKET: + WinDivertPutString(stream, "NETWORK_PACKET"); break; + case WINDIVERT_EVENT_FLOW_ESTABLISHED: + WinDivertPutString(stream, "FLOW_ESTABLISHED"); break; + case WINDIVERT_EVENT_FLOW_DELETED: + WinDivertPutString(stream, "FLOW_DELETED"); break; + case WINDIVERT_EVENT_REFLECT_ESTABLISHED: + WinDivertPutString(stream, "REFLECT_ESTABLISHED"); break; + case WINDIVERT_EVENT_REFLECT_OPEN: + WinDivertPutString(stream, "REFLECT_OPEN"); break; + case WINDIVERT_EVENT_REFLECT_CLOSE: + WinDivertPutString(stream, "REFLECT_CLOSE"); break; + default: + WinDivertFormatNumber(stream, val->val[0]); break; + } + } else { WinDivertFormatNumber(stream, val->val[0]); @@ -3863,6 +3943,8 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr, return; case TOKEN_ZERO: WinDivertPutString(stream, "zero"); return; + case TOKEN_EVENT: + WinDivertPutString(stream, "event"); return; case TOKEN_INBOUND: WinDivertPutString(stream, "inbound"); return; case TOKEN_OUTBOUND: diff --git a/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c index f01111d..7be5d34 100644 --- a/examples/windivertctl/windivertctl.c +++ b/examples/windivertctl/windivertctl.c @@ -1,5 +1,5 @@ /* - * streamdump.c + * windivertctl.c * (C) 2018, all rights reserved, * * This file is part of WinDivert. @@ -73,15 +73,6 @@ typedef enum KILLALL } MODE; -/* - * Months. - */ -static const char *months[12] = -{ - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", - "Nov", "Dec" -}; - /* * Add a new process. */ @@ -387,7 +378,7 @@ usage: if (WinDivertHelperFormatFilter((char *)object, addr.Reflect.Layer, filter_str, sizeof(filter_str))) { - printf("\"%s\" \"%s\"", filter_str, (char *)object); // XXX + printf("\"%s\"", filter_str); } SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); diff --git a/include/windivert_device.h b/include/windivert_device.h index 2741402..9ff6c7d 100644 --- a/include/windivert_device.h +++ b/include/windivert_device.h @@ -129,8 +129,9 @@ #define WINDIVERT_FILTER_FIELD_REMOTEPORT 64 #define WINDIVERT_FILTER_FIELD_PROTOCOL 65 #define WINDIVERT_FILTER_FIELD_LAYER 66 +#define WINDIVERT_FILTER_FIELD_EVENT 67 #define WINDIVERT_FILTER_FIELD_MAX \ - WINDIVERT_FILTER_FIELD_LAYER + WINDIVERT_FILTER_FIELD_EVENT #define WINDIVERT_FILTER_TEST_EQ 0 #define WINDIVERT_FILTER_TEST_NEQ 1 @@ -151,6 +152,12 @@ #define WINDIVERT_LAYER_DEFAULT WINDIVERT_LAYER_NETWORK #define WINDIVERT_LAYER_MAX WINDIVERT_LAYER_REFLECT +/* + * WinDivert events. + */ +#define WINDIVERT_EVENT_MAX \ + WINDIVERT_EVENT_REFLECT_CLOSE + /* * WinDivert flags. */ diff --git a/sys/windivert.c b/sys/windivert.c index 08212d9..d174986 100644 --- a/sys/windivert.c +++ b/sys/windivert.c @@ -432,8 +432,8 @@ static void windivert_free_packet(packet_t packet); static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4, BOOL checksum); static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b); static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, - PVOID layer_data, BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, - PWINDIVERT_FILTER filter); + PVOID layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound, + BOOL loopback, BOOL impostor, PWINDIVERT_FILTER filter); static PWINDIVERT_FILTER windivert_filter_compile( PWINDIVERT_FILTER ioctl_filter, size_t ioctl_filter_len); static NTSTATUS windivert_reflect_init(WDFOBJECT parent); @@ -1834,7 +1834,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request, case WINDIVERT_LAYER_FLOW: case WINDIVERT_LAYER_REFLECT: status = STATUS_INVALID_PARAMETER; - DEBUG_ERROR("failed to inject at FLOW layer", status); + DEBUG_ERROR("failed to inject at layer", status); goto windivert_write_exit; default: break; @@ -2796,7 +2796,8 @@ static void windivert_network_classify(context_t context, do { BOOL match = windivert_filter(buffer_fst, layer, (PVOID)network_data, - ipv4, outbound, loopback, impostor, filter); + /*event=*/WINDIVERT_EVENT_NETWORK_PACKET, ipv4, outbound, loopback, + impostor, filter); if (match) { break; @@ -2860,7 +2861,8 @@ static void windivert_network_classify(context_t context, while (buffer_itr != NULL) { BOOL match = windivert_filter(buffer_itr, layer, (PVOID)network_data, - ipv4, outbound, loopback, impostor, filter); + /*event=*/WINDIVERT_EVENT_NETWORK_PACKET, ipv4, outbound, + loopback, impostor, filter); ok = windivert_queue_work(context, (PVOID)buffer_itr, NET_BUFFER_DATA_LENGTH(buffer_itr), buffers, layer, (PVOID)network_data, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET, @@ -3024,7 +3026,8 @@ static void windivert_flow_established_classify(context_t context, KeReleaseInStackQueuedSpinLock(&lock_handle); match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW, - (PVOID)flow_data, ipv4, outbound, loopback, /*impostor=*/FALSE, filter); + (PVOID)flow_data, /*event=*/WINDIVERT_EVENT_FLOW_ESTABLISHED, ipv4, + outbound, loopback, /*impostor=*/FALSE, filter); if (match) { ok = windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0, @@ -3135,8 +3138,9 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id, KeReleaseInStackQueuedSpinLock(&lock_handle); match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW, - (PVOID)&flow->data, !flow->ipv6, flow->outbound, flow->loopback, - /*impostor=*/FALSE, filter); + (PVOID)&flow->data, /*event=*/WINDIVERT_EVENT_FLOW_DELETED, + !flow->ipv6, flow->outbound, flow->loopback, /*impostor=*/FALSE, + filter); if (match) { (VOID)windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0, @@ -3772,8 +3776,8 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4, * Checks if the given network packet is of interest. */ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, - PVOID layer_data, BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, - PWINDIVERT_FILTER filter) + PVOID layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound, + BOOL loopback, BOOL impostor, PWINDIVERT_FILTER filter) { PWINDIVERT_IPHDR ip_header = NULL; PWINDIVERT_IPV6HDR ipv6_header = NULL; @@ -3827,6 +3831,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, switch (filter[ip].field) { case WINDIVERT_FILTER_FIELD_ZERO: + case WINDIVERT_FILTER_FIELD_EVENT: result = TRUE; break; case WINDIVERT_FILTER_FIELD_INBOUND: @@ -3948,6 +3953,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, case WINDIVERT_FILTER_FIELD_ZERO: field[0] = 0; break; + case WINDIVERT_FILTER_FIELD_EVENT: + field[0] = (UINT32)event; + break; case WINDIVERT_FILTER_FIELD_INBOUND: field[0] = (UINT32)!outbound; break; @@ -4354,6 +4362,12 @@ static PWINDIVERT_FILTER windivert_filter_compile( goto windivert_filter_compile_error; } break; + case WINDIVERT_FILTER_FIELD_EVENT: + if (ioctl_filter[i].arg[0] > WINDIVERT_EVENT_MAX) + { + goto windivert_filter_compile_error; + } + break; case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH: case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH: if (ioctl_filter[i].arg[0] > 0x0F) @@ -4609,7 +4623,7 @@ static void windivert_reflect_event_notify(context_t context, KeReleaseInStackQueuedSpinLock(&lock_handle); match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT, (PVOID)&context->reflect.data, - /*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE, + event, /*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE, /*impostor=*/FALSE, filter); if (!match) { @@ -4658,8 +4672,8 @@ static void windivert_reflect_established_notify(context_t context, entry = entry->Flink; match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT, (PVOID)&waiter->reflect.data, - /*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE, - /*impostor=*/FALSE, filter); + /*event=*/WINDIVERT_EVENT_REFLECT_ESTABLISHED, /*ipv4=*/TRUE, + /*outbound=*/FALSE, /*loopback=*/FALSE, /*impostor=*/FALSE, filter); if (!match) { continue; diff --git a/test/test.c b/test/test.c index f2bd160..f6511fc 100644 --- a/test/test.c +++ b/test/test.c @@ -113,6 +113,7 @@ static struct packet pkt_ipv6_exthdrs_udp = }; static struct test tests[] = { + {"event = NETWORK_PACKET", &pkt_echo_request, TRUE}, {"outbound and icmp", &pkt_echo_request, TRUE}, {"outbound", &pkt_echo_request, TRUE}, {"outbound and inbound", &pkt_echo_request, FALSE},