From eb75e63431543277355887f36c02c52d1a16fc24 Mon Sep 17 00:00:00 2001 From: basil00 Date: Thu, 28 Feb 2019 09:23:08 +0800 Subject: [PATCH] Add WINDIVERT_PARAM_VERSION_* parameters. This makes it possible for the user application to determine the exact driver version. Also update documentation and tests. --- doc/windivert.html | 85 +++++++++++++++++++++------- examples/netdump/netdump.c | 15 ++++- examples/windivertctl/windivertctl.c | 6 +- include/windivert.h | 30 +++++----- sys/windivert.c | 20 ++++--- test/test.c | 28 +++++++++ 6 files changed, 138 insertions(+), 46 deletions(-) diff --git a/doc/windivert.html b/doc/windivert.html index a4b2670..ca9dec3 100644 --- a/doc/windivert.html +++ b/doc/windivert.html @@ -753,6 +753,16 @@ have a valid digital signature +ERROR_DRIVER_FAILED_PRIOR_UNLOAD + + +654 + + +An incompatible version of the WinDivert driver is currently loaded. + + + ERROR_SERVICE_DOES_NOT_EXIST @@ -1658,14 +1668,14 @@ Description -WINDIVERT_PARAM_QUEUE_LEN +WINDIVERT_PARAM_QUEUE_LENGTH Sets the maximum length of the packet queue for WinDivertRecv(). -The default value is WINDIVERT_PARAM_QUEUE_LEN_DEFAULT, -the minimum is WINDIVERT_PARAM_QUEUE_LEN_MIN, and the maximum -is WINDIVERT_PARAM_QUEUE_LEN_MAX. +The default value is WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT, +the minimum is WINDIVERT_PARAM_QUEUE_LENGTH_MIN, and the maximum +is WINDIVERT_PARAM_QUEUE_LENGTH_MAX. @@ -1725,9 +1735,38 @@ Use GetLastError() to get the reason for the error.

Remarks
Gets a WinDivert parameter. -See WinDivertSetParam() for the list -of parameters. +This function supports all the parameters from +WinDivertSetParam(), +and the following additional read-only parameters:

+
+ + + + + + + + + + + + + +
+Parameter + +Description +
+WINDIVERT_PARAM_VERSION_MAJOR + +Returns the major version of the driver. +
+WINDIVERT_PARAM_VERSION_MINOR + +Returns the minor version of the driver. +
+

@@ -2576,16 +2615,9 @@ Due to technical limitations, this field is not supported by the WINDIVERT_LAYER_NETWORK* layers. That said, it is usually possible to associate process IDs to network packets matching the same network 5-tuple. -

Note that a fundamental race condition exists between the processId -and the termination of the corresponding process. -By the time an event is received using -WinDivertRecv(), -it is possible that the process has already terminated and -the ID has been reassigned to an unrelated process. -This problem can be partly mitigated by comparing the timestamp -(addr.Timestamp) with the creation time of the process. -If the process is newer, then the ID has been reassigned. +and the termination of the corresponding process, see +the know issues listed below.

The packet*[i], tcp.Payload*[i] and udp.Payload*[i] fields take an index parameter (i). @@ -2812,13 +2844,12 @@ See the netdump.exe sample program for an example of this usage.

9. Known Issues

-There are some limitations to the WinDivert package. -They are: +WinDivert has some known limitations listed below:


diff --git a/examples/netdump/netdump.c b/examples/netdump/netdump.c index ad8566d..8811c03 100644 --- a/examples/netdump/netdump.c +++ b/examples/netdump/netdump.c @@ -1,6 +1,6 @@ /* * netdump.c - * (C) 2018, all rights reserved, + * (C) 2019, all rights reserved, * * This file is part of WinDivert. * @@ -118,18 +118,27 @@ int __cdecl main(int argc, char **argv) } // Max-out the packet queue: - if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_LEN, 8192)) + if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_LENGTH, + WINDIVERT_PARAM_QUEUE_LENGTH_MAX)) { fprintf(stderr, "error: failed to set packet queue length (%d)\n", GetLastError()); exit(EXIT_FAILURE); } - if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_TIME, 2048)) + if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_TIME, + WINDIVERT_PARAM_QUEUE_TIME_MAX)) { fprintf(stderr, "error: failed to set packet queue time (%d)\n", GetLastError()); exit(EXIT_FAILURE); } + if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_SIZE, + WINDIVERT_PARAM_QUEUE_SIZE_MAX)) + { + fprintf(stderr, "error: failed to set packet queue size (%d)\n", + GetLastError()); + exit(EXIT_FAILURE); + } // Set up timing: QueryPerformanceFrequency(&freq); diff --git a/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c index 93a0c93..a34d5ec 100644 --- a/examples/windivertctl/windivertctl.c +++ b/examples/windivertctl/windivertctl.c @@ -141,8 +141,8 @@ usage: GetLastError()); return EXIT_FAILURE; } - if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_LEN, - WINDIVERT_PARAM_QUEUE_LEN_MAX) || + if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_LENGTH, + WINDIVERT_PARAM_QUEUE_LENGTH_MAX) || !WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_SIZE, WINDIVERT_PARAM_QUEUE_SIZE_MAX) || !WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_TIME, @@ -163,7 +163,7 @@ usage: { break; } - fprintf(stderr, "failed to event (%d)\n", GetLastError()); + fprintf(stderr, "failed to receive event (%d)\n", GetLastError()); continue; } diff --git a/include/windivert.h b/include/windivert.h index 524c720..e930c54 100644 --- a/include/windivert.h +++ b/include/windivert.h @@ -190,11 +190,13 @@ typedef enum */ typedef enum { - WINDIVERT_PARAM_QUEUE_LEN = 0, /* Packet queue length. */ + WINDIVERT_PARAM_QUEUE_LENGTH = 0, /* Packet queue length. */ WINDIVERT_PARAM_QUEUE_TIME = 1, /* Packet queue time. */ WINDIVERT_PARAM_QUEUE_SIZE = 2, /* Packet queue size. */ + WINDIVERT_PARAM_VERSION_MAJOR = 3, /* Driver version (major). */ + WINDIVERT_PARAM_VERSION_MINOR = 4, /* Driver version (minor). */ } WINDIVERT_PARAM, *PWINDIVERT_PARAM; -#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_QUEUE_SIZE +#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_VERSION_MINOR /* * WinDivert shutdown parameter. @@ -298,18 +300,18 @@ extern WINDIVERTEXPORT BOOL WinDivertGetParam( /* * WinDivert constants. */ -#define WINDIVERT_PRIORITY_LOWEST 30000 -#define WINDIVERT_PRIORITY_HIGHEST (-WINDIVERT_PRIORITY_LOWEST) -#define WINDIVERT_PARAM_QUEUE_LEN_DEFAULT 4096 -#define WINDIVERT_PARAM_QUEUE_LEN_MIN 32 -#define WINDIVERT_PARAM_QUEUE_LEN_MAX 16384 -#define WINDIVERT_PARAM_QUEUE_TIME_DEFAULT 2000 /* 2s */ -#define WINDIVERT_PARAM_QUEUE_TIME_MIN 100 /* 100ms */ -#define WINDIVERT_PARAM_QUEUE_TIME_MAX 16000 /* 16s */ -#define WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT 4194304 /* 4MB */ -#define WINDIVERT_PARAM_QUEUE_SIZE_MIN 65535 /* 64KB */ -#define WINDIVERT_PARAM_QUEUE_SIZE_MAX 33554432 /* 32MB */ -#define WINDIVERT_BATCH_MAX 0xFF /* 255 */ +#define WINDIVERT_PRIORITY_LOWEST 30000 +#define WINDIVERT_PRIORITY_HIGHEST (-WINDIVERT_PRIORITY_LOWEST) +#define WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT 4096 +#define WINDIVERT_PARAM_QUEUE_LENGTH_MIN 32 +#define WINDIVERT_PARAM_QUEUE_LENGTH_MAX 16384 +#define WINDIVERT_PARAM_QUEUE_TIME_DEFAULT 2000 /* 2s */ +#define WINDIVERT_PARAM_QUEUE_TIME_MIN 100 /* 100ms */ +#define WINDIVERT_PARAM_QUEUE_TIME_MAX 16000 /* 16s */ +#define WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT 4194304 /* 4MB */ +#define WINDIVERT_PARAM_QUEUE_SIZE_MIN 65535 /* 64KB */ +#define WINDIVERT_PARAM_QUEUE_SIZE_MAX 33554432 /* 32MB */ +#define WINDIVERT_BATCH_MAX 0xFF /* 255 */ /****************************************************************************/ /* WINDIVERT HELPER API */ diff --git a/sys/windivert.c b/sys/windivert.c index 732f97b..ba830be 100644 --- a/sys/windivert.c +++ b/sys/windivert.c @@ -234,7 +234,7 @@ WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(req_context_s, windivert_req_context_get); * * Note the packet data must be pointer-aligned. */ -#define WINDIVERT_WORK_QUEUE_LEN_MAX 4096 +#define WINDIVERT_WORK_QUEUE_LENGTH_MAX 4096 #ifdef _WIN64 #define WINDIVERT_ALIGN_SIZE 8 #define WINDIVERT_DATA_ALIGN __declspec(align(8)) @@ -1385,7 +1385,7 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request, context->object = object; context->work_queue_length = 0; context->packet_queue_length = 0; - context->packet_queue_maxlength = WINDIVERT_PARAM_QUEUE_LEN_DEFAULT; + context->packet_queue_maxlength = WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT; context->packet_queue_size = 0; context->packet_queue_maxsize = WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT; context->packet_queue_maxcounts = @@ -3240,9 +3240,9 @@ windivert_ioctl_bad_flags: } switch ((UINT32)param) { - case WINDIVERT_PARAM_QUEUE_LEN: - if (value < WINDIVERT_PARAM_QUEUE_LEN_MIN || - value > WINDIVERT_PARAM_QUEUE_LEN_MAX) + case WINDIVERT_PARAM_QUEUE_LENGTH: + if (value < WINDIVERT_PARAM_QUEUE_LENGTH_MIN || + value > WINDIVERT_PARAM_QUEUE_LENGTH_MAX) { KeReleaseInStackQueuedSpinLock(&lock_handle); status = STATUS_INVALID_PARAMETER; @@ -3315,7 +3315,7 @@ windivert_ioctl_bad_flags: } switch ((UINT32)param) { - case WINDIVERT_PARAM_QUEUE_LEN: + case WINDIVERT_PARAM_QUEUE_LENGTH: *valptr = context->packet_queue_maxlength; break; case WINDIVERT_PARAM_QUEUE_TIME: @@ -3324,6 +3324,12 @@ windivert_ioctl_bad_flags: case WINDIVERT_PARAM_QUEUE_SIZE: *valptr = context->packet_queue_maxsize; break; + case WINDIVERT_PARAM_VERSION_MAJOR: + *valptr = WINDIVERT_VERSION_MAJOR; + break; + case WINDIVERT_PARAM_VERSION_MINOR: + *valptr = WINDIVERT_VERSION_MINOR; + break; default: KeReleaseInStackQueuedSpinLock(&lock_handle); status = STATUS_INVALID_PARAMETER; @@ -4819,7 +4825,7 @@ static BOOL windivert_queue_work(context_t context, PVOID packet, work->match = FALSE; } context->work_queue_length++; - if (context->work_queue_length > WINDIVERT_WORK_QUEUE_LEN_MAX) + if (context->work_queue_length > WINDIVERT_WORK_QUEUE_LENGTH_MAX) { // The work queue is full; as an emergency we drop packets. old_entry = RemoveHeadList(&context->work_queue); diff --git a/test/test.c b/test/test.c index 79d60bf..3e13a28 100644 --- a/test/test.c +++ b/test/test.c @@ -1004,6 +1004,7 @@ static BOOL run_test(HANDLE inject_handle, const char *filter, HANDLE event[2] = {NULL, NULL}; BOOL random, result, ipv4; LARGE_INTEGER end; + UINT64 val; *diff = 0; @@ -1031,6 +1032,33 @@ static BOOL run_test(HANDLE inject_handle, const char *filter, "(err = %d)\n", GetLastError()); goto failed; } + if (!WinDivertSetParam(handle[0], WINDIVERT_PARAM_QUEUE_LENGTH, + WINDIVERT_PARAM_QUEUE_LENGTH_MAX) || + !WinDivertGetParam(handle[0], WINDIVERT_PARAM_QUEUE_LENGTH, &val) || + val != WINDIVERT_PARAM_QUEUE_LENGTH_MAX) + { + fprintf(stderr, "error: failed to set WINDIVERT_PARAM_QUEUE_LENGTH " + "parameter (err = %d)\n", GetLastError()); + goto failed; + } + if (!WinDivertSetParam(handle[0], WINDIVERT_PARAM_QUEUE_SIZE, + WINDIVERT_PARAM_QUEUE_SIZE_MAX) || + !WinDivertGetParam(handle[0], WINDIVERT_PARAM_QUEUE_SIZE, &val) || + val != WINDIVERT_PARAM_QUEUE_SIZE_MAX) + { + fprintf(stderr, "error: failed to set WINDIVERT_PARAM_QUEUE_SIZE " + "parameter (err = %d)\n", GetLastError()); + goto failed; + } + if (!WinDivertSetParam(handle[0], WINDIVERT_PARAM_QUEUE_TIME, + WINDIVERT_PARAM_QUEUE_TIME_MAX) || + !WinDivertGetParam(handle[0], WINDIVERT_PARAM_QUEUE_TIME, &val) || + val != WINDIVERT_PARAM_QUEUE_TIME_MAX) + { + fprintf(stderr, "error: failed to set WINDIVERT_PARAM_QUEUE_TIME " + "parameter (err = %d)\n", GetLastError()); + goto failed; + } // (2) Create pended recv requests: event[0] = CreateEvent(NULL, FALSE, FALSE, NULL);