Add WINDIVERT_PARAM_VERSION_* parameters.

This makes it possible for the user application
to determine the exact driver version.

Also update documentation and tests.
This commit is contained in:
basil00
2019-02-28 09:23:08 +08:00
parent c084c8239b
commit eb75e63431
6 changed files with 138 additions and 46 deletions
+66 -19
View File
@@ -753,6 +753,16 @@ have a valid digital signature
</tr>
<tr>
<td>
<code>ERROR_DRIVER_FAILED_PRIOR_UNLOAD</code>
</td>
<td>
654
</td>
<td>
An incompatible version of the WinDivert driver is currently loaded.
</td>
<tr>
<td>
<code>ERROR_SERVICE_DOES_NOT_EXIST</code>
</td>
<td>
@@ -1658,14 +1668,14 @@ Description
</tr>
<tr>
<td>
<code>WINDIVERT_PARAM_QUEUE_LEN</code>
<code>WINDIVERT_PARAM_QUEUE_LENGTH</code>
</td>
<td>
Sets the maximum length of the packet queue for
<a href="#divert_recv"><code>WinDivertRecv()</code></a>.
The default value is <code>WINDIVERT_PARAM_QUEUE_LEN_DEFAULT</code>,
the minimum is <code>WINDIVERT_PARAM_QUEUE_LEN_MIN</code>, and the maximum
is <code>WINDIVERT_PARAM_QUEUE_LEN_MAX</code>.
The default value is <code>WINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT</code>,
the minimum is <code>WINDIVERT_PARAM_QUEUE_LENGTH_MIN</code>, and the maximum
is <code>WINDIVERT_PARAM_QUEUE_LENGTH_MAX</code>.
</td>
</tr>
<tr>
@@ -1725,9 +1735,38 @@ Use <code>GetLastError()</code> to get the reason for the error.
</p><p>
<b>Remarks</b><br>
Gets a WinDivert parameter.
See <a href="#divert_set_param"><code>WinDivertSetParam()</code></a> for the list
of parameters.
This function supports all the parameters from
<a href="#divert_set_param"><code>WinDivertSetParam()</code></a>,
and the following additional <q>read-only</q> parameters:
</p>
<center>
<table border="1" cellpadding="5" width="75%">
<tr>
<th>
Parameter
</th>
<th>
Description
</th>
</tr>
<tr>
<td>
<code>WINDIVERT_PARAM_VERSION_MAJOR</code>
</td>
<td>
Returns the major version of the driver.
</td>
</tr>
<tr>
<td>
<code>WINDIVERT_PARAM_VERSION_MINOR</code>
</td>
<td>
Returns the minor version of the driver.
</td>
</tr>
</table>
</center>
</dd></dl>
<hr>
@@ -2576,16 +2615,9 @@ Due to technical limitations, this field is not supported by the
<code>WINDIVERT_LAYER_NETWORK*</code> layers.
That said, it is usually possible to associate process IDs to network packets
matching the same network 5-tuple.
</p><p>
Note that a fundamental race condition exists between the <code>processId</code>
and the termination of the corresponding process.
By the time an event is received using
<a href="#divert_recv"><code>WinDivertRecv()</code></a>,
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
(<code>addr.Timestamp</code>) 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 <a href="#known_issues">know issues</a> listed below.
</p><p>
The <code>packet*[i]</code>, <code>tcp.Payload*[i]</code> and
<code>udp.Payload*[i]</code> fields take an <i>index</i> parameter (<code>i</code>).
@@ -2812,13 +2844,12 @@ See the <code>netdump.exe</code> sample program for an example of this usage.
<a name="known_issues"><h2>9. Known Issues</h2></a>
<p>
There are some limitations to the WinDivert package.
They are:
WinDivert has some known limitations listed below:
</p>
<ul>
<li><i>Injecting inbound ICMP/ICMPv6 messages</i>:
Calling <a href="#divert_send"><code>WinDivertSend()</code></a> will fail with
an error for certain types of inbound ICMP/ICMPv6 messages.
Calling <a href="#divert_send"><code>WinDivertSend()</code></a> will fail
with an error for certain types of inbound ICMP/ICMPv6 messages.
This is probably because the Windows TCP/IP stack does not handle
such messages.
Such errors are harmless and can be ignored.
@@ -2861,6 +2892,22 @@ They are:
(e.g. some buggy NAT implementations)
that incorrectly assume packets to be in-order.
</li>
<li><i>A race condition exists between <q><code>addr.*.processId</code></q> and
process termination.</i>
By the time an event is received using
<a href="#divert_recv"><code>WinDivertRecv()</code></a>,
it is possible that the process responsible for the event has already
terminated.
Furthermore, it is also possible that the <code>processId</code> has been
reassigned to an unrelated process.
This problem can be partly mitigated by comparing the timestamp
(<code>addr.Timestamp</code>) with the creation time of the process.
If the process is newer, then the ID has been reassigned.
This race condition does <b>not</b> affect the
<code>WINDIVERT_EVENT_REFLECT_OPEN</code> event.
In this special case, the <code>addr.Reflect.processId</code> is
guaranteed to be valid until the corresponding close event is
received or dropped.</li>
</ul>
<hr>
+12 -3
View File
@@ -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);
+3 -3
View File
@@ -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;
}
+16 -14
View File
@@ -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 */
+13 -7
View File
@@ -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);
+28
View File
@@ -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);