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:
+66
-19
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user