Various WinDivert improvements.

- Add UNBIND/DISCONNECT events to the SOCKET
  layer.  These events can only be sniffed.
- Remove the RECV_PARTIAL flag.  The user
  application can just ignore the error code
  instead.
- WINDIVERT_ADDRESS is now 64bytes.  Some extra
  padding added for future-proofing.
- Ignore SOCKET-layer REAUTHORIZE.
- The REFLECT layer returns the filter object
  directly (no IPv4 "pseudo" packet).
This commit is contained in:
basil00
2019-02-25 09:15:33 +08:00
parent 32c5aa90f4
commit 7fa04945c0
9 changed files with 512 additions and 148 deletions
+21 -15
View File
@@ -167,10 +167,15 @@ WinDivert 2.0.0-rc
deleted.
* WINDIVERT_EVENT_SOCKET_BIND: (SOCKET layer) a socket bind()
operation occurred.
* WINDIVERT_EVENT_SOCKET_LISTEN: (SOCKET layer) a socket listen()
* WINDIVERT_EVENT_SOCKET_UNBIND: (SOCKET layer) a previous binding
is removed.
operation occurred.
* WINDIVERT_EVENT_SOCKET_CONNECT: (SOCKET layer) a socket connect()
operation occurred.
* WINDIVERT_EVENT_SOCKET_DISCONNECT: (SOCKET layer) a previous
connection is terminated.
* WINDIVERT_EVENT_SOCKET_LISTEN: (SOCKET layer) a socket listen()
operation occurred.
* WINDIVERT_EVENT_SOCKET_ACCEPT: (SOCKET layer) a socket accept()
operation occurred.
* WINDIVERT_EVENT_REFLECT_OPEN: (REFLECT layer) a WinDivertOpen()
@@ -217,28 +222,29 @@ WinDivert 2.0.0-rc
packet/payload.
* Negative, representing addressing from the end of the packet/payload.
- The WinDivert filter language now supports several symbolic values:
* ACCEPT: (SOCKET layer) equal to WINDIVERT_EVENT_SOCKET_ACCEPT.
* BIND: (SOCKET layer) equal to WINDIVERT_EVENT_SOCKET_BIND.
* CLOSE: (REFLECT layer) equal to WINDIVERT_EVENT_REFLECT_CLOSE.
* DELETED: (FLOW LAYER) equal to WINDIVERT_EVENT_FLOW_DELETED.
* ESTABLISHED: (FLOW layer) equal to WINDIVERT_EVENT_FLOW_ESTABLISHED.
* FLOW: (REFLECT layer) equal to WINDIVERT_LAYER_FLOW.
* LISTEN: (SOCKET layer) equal to WINDIVERT_EVENT_SOCKET_LISTEN.
* NETWORK: (REFLECT layer) equal to WINDIVERT_LAYER_NETWORK.
* NETWORK_FORWARD: (REFLECT layer) equal to
WINDIVERT_LAYER_NETWORK_FORWARD.
* OPEN: (REFLECT layer) equal to WINDIVERT_EVENT_REFLECT_OPEN.
* PACKET: (NETWORK/NETWORK_FORWARD layers) equal to
WINDIVERT_EVENT_NETWORK_PACKET
* REFLECT: (REFLECT layer) equal to WINDIVERT_LAYER_REFLECT.
* ESTABLISHED: (FLOW layer) equal to WINDIVERT_EVENT_FLOW_ESTABLISHED.
* DELETED: (FLOW LAYER) equal to WINDIVERT_EVENT_FLOW_DELETED.
* BIND: (SOCKET layer) equal to WINDIVERT_EVENT_SOCKET_BIND.
* UNBIND: (SOCKET layer) equal to WINDIVERT_EVENT_SOCKET_UNBIND.
* CONNECT: (SOCKET layer) equal to WINDIVERT_EVENT_SOCKET_CONNECT.
* DISCONNECT: (SOCKET layer) equal to WINDIVERT_EVENT_SOCKET_DISCONNECT.
* LISTEN: (SOCKET layer) equal to WINDIVERT_EVENT_SOCKET_LISTEN.
* ACCEPT: (SOCKET layer) equal to WINDIVERT_EVENT_SOCKET_ACCEPT.
WINDIVERT_LAYER_NETWORK_FORWARD.
* OPEN: (REFLECT layer) equal to WINDIVERT_EVENT_REFLECT_OPEN.
* CLOSE: (REFLECT layer) equal to WINDIVERT_EVENT_REFLECT_CLOSE.
* NETWORK: (REFLECT layer) equal to WINDIVERT_LAYER_NETWORK.
* NETWORK_FORWARD: (REFLECT layer) equal to
* FLOW: (REFLECT layer) equal to WINDIVERT_LAYER_FLOW.
* SOCKET: (REFLECT layer) equal to WINDIVERT_LAYER_SOCKET.
* REFLECT: (REFLECT layer) equal to WINDIVERT_LAYER_REFLECT.
- WinDivertOpen() now supports several new flags:
* WINDIVERT_FLAG_RECV_ONLY/WINDIVERT_FLAG_READ_ONLY: The handle cannot
be used for send operations.
* WINDIVERT_FLAG_SEND_ONLY/WINDIVERT_FLAG_WRITE_ONLY: The handle cannot
be used for receive operations.
* WINDIVERT_FLAG_RECV_PARTIAL: The handle will support partial receives,
meaning that the buffer can be smaller than the packet.
* WINDIVERT_FLAG_NO_INSTALL: If the WinDivert driver is not already
installed/loaded, then WinDivertOpen() will fail with an error.
- WinDivertRecvEx()/WinDivertSendEx() now support a "batch" mode that
+3 -1
View File
@@ -365,6 +365,7 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
UINT obj_len;
ERROR comp_err;
DWORD err;
BOOL sniff;
HANDLE handle;
SC_HANDLE service;
UINT64 filter_flags;
@@ -404,7 +405,8 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
filter_flags = WinDivertAnalyzeFilter(layer, object, obj_len);
sniff = ((flags & WINDIVERT_FLAG_SNIFF) != 0);
filter_flags = WinDivertAnalyzeFilter(layer, sniff, object, obj_len);
// Attempt to open the WinDivert device:
handle = CreateFile(L"\\\\.\\" WINDIVERT_DEVICE_NAME,
+31 -1
View File
@@ -147,7 +147,9 @@ typedef enum
TOKEN_EVENT_ESTABLISHED,
TOKEN_EVENT_DELETED,
TOKEN_EVENT_BIND,
TOKEN_EVENT_UNBIND,
TOKEN_EVENT_CONNECT,
TOKEN_EVENT_DISCONNECT,
TOKEN_EVENT_LISTEN,
TOKEN_EVENT_ACCEPT,
TOKEN_EVENT_OPEN,
@@ -514,9 +516,15 @@ static BOOL WinDivertExpandMacro(KIND kind, WINDIVERT_LAYER layer,
case TOKEN_EVENT_BIND:
*val = WINDIVERT_EVENT_SOCKET_BIND;
return (layer == WINDIVERT_LAYER_SOCKET);
case TOKEN_EVENT_UNBIND:
*val = WINDIVERT_EVENT_SOCKET_UNBIND;
return (layer == WINDIVERT_LAYER_SOCKET);
case TOKEN_EVENT_CONNECT:
*val = WINDIVERT_EVENT_SOCKET_CONNECT;
return (layer == WINDIVERT_LAYER_SOCKET);
case TOKEN_EVENT_DISCONNECT:
*val = WINDIVERT_EVENT_SOCKET_DISCONNECT;
return (layer == WINDIVERT_LAYER_SOCKET);
case TOKEN_EVENT_LISTEN:
*val = WINDIVERT_EVENT_SOCKET_LISTEN;
return (layer == WINDIVERT_LAYER_SOCKET);
@@ -547,6 +555,7 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{"CLOSE", TOKEN_EVENT_CLOSE, L____R},
{"CONNECT", TOKEN_EVENT_CONNECT, L___S_},
{"DELETED", TOKEN_EVENT_DELETED, L__F__},
{"DISCONNECT", TOKEN_EVENT_DISCONNECT, L___S_},
{"ESTABLISHED", TOKEN_EVENT_ESTABLISHED, L__F__},
{"FLOW", TOKEN_FLOW, L____R},
{"LISTEN", TOKEN_EVENT_LISTEN, L___S_},
@@ -556,6 +565,7 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{"PACKET", TOKEN_EVENT_PACKET, LNM___},
{"REFLECT", TOKEN_REFLECT, L____R},
{"SOCKET", TOKEN_SOCKET, L____R},
{"UNBIND", TOKEN_EVENT_UNBIND, L___S_},
{"and", TOKEN_AND, LNMFSR},
{"event", TOKEN_EVENT, LNMFSR},
{"false", TOKEN_FALSE, LNMFSR},
@@ -1968,7 +1978,7 @@ static void WinDivertEmitFilter(PEXPR *stack, UINT len, UINT16 label,
* Analyze a filter object.
*/
static UINT64 WinDivertAnalyzeFilter(WINDIVERT_LAYER layer,
PWINDIVERT_FILTER filter, UINT length)
BOOL sniff, PWINDIVERT_FILTER filter, UINT length)
{
BOOL result;
UINT64 flags = 0;
@@ -2041,9 +2051,25 @@ static UINT64 WinDivertAnalyzeFilter(WINDIVERT_LAYER layer,
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_BIND);
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND: 0);
if (sniff)
{
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_EVENT,
WINDIVERT_EVENT_SOCKET_UNBIND);
flags |=
(result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_UNBIND: 0);
}
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_CONNECT);
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT: 0);
if (sniff)
{
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_EVENT,
WINDIVERT_EVENT_SOCKET_DISCONNECT);
flags |=
(result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_DISCONNECT: 0);
}
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_LISTEN);
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN: 0);
@@ -4210,8 +4236,12 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
{
case WINDIVERT_EVENT_SOCKET_BIND:
WinDivertPutString(stream, "BIND"); break;
case WINDIVERT_EVENT_SOCKET_UNBIND:
WinDivertPutString(stream, "UNBIND"); break;
case WINDIVERT_EVENT_SOCKET_CONNECT:
WinDivertPutString(stream, "CONNECT"); break;
case WINDIVERT_EVENT_SOCKET_DISCONNECT:
WinDivertPutString(stream, "DISCONNECT"); break;
case WINDIVERT_EVENT_SOCKET_LISTEN:
WinDivertPutString(stream, "LISTEN"); break;
case WINDIVERT_EVENT_SOCKET_ACCEPT:
+25 -29
View File
@@ -401,14 +401,19 @@ correspond to socket operations, such as:
</p>
<ul>
<li> <code>WINDIVERT_EVENT_SOCKET_BIND</code>: A <code>bind()</code> operation.</li>
<li> <code>WINDIVERT_EVENT_SOCKET_LISTEN</code>: A <code>listen()</code> operation.</li>
<li> <code>WINDIVERT_EVENT_SOCKET_UNBIND</code>: A previous binding is
removed.</li>
<li> <code>WINDIVERT_EVENT_SOCKET_CONNECT</code>: A <code>connect()</code>
operation.</li>
<li> <code>WINDIVERT_EVENT_SOCKET_DISCONNECT</code>: A previous connection
is terminated.</li>
<li> <code>WINDIVERT_EVENT_SOCKET_LISTEN</code>: A <code>listen()</code> operation.</li>
<li> <code>WINDIVERT_EVENT_SOCKET_ACCEPT</code>: An <code>accept()</code>
operation.</li>
</ul>
<p>
Socket events can be blocked but not injected.
Socket events, except for <code>UNBIND</code>/<code>DISCONNECT</code>,
can be blocked, and no socket event can be injected.
Process ID information is available at this layer.
Due to technical limitations, the
<code>WINDIVERT_LAYER_SOCKET</code> layer cannot capture events that
@@ -429,8 +434,12 @@ These events can be captured, but not injected nor blocked.
Process ID information is available at this layer,
meaning that it is possible to determine which (if any) process is using
WinDivert.
The layer also returns a <q>pseudo packet</q> that encodes the filter string
associated with the event.
The layer also returns an <q>object</q> representation of the filter string
used to open the handle.
The object representation can be converted back into a human-readable
filter string using the
<a href="#divert_helper_format_filter"><code>WinDivertHelperFormatFilter()</code></a>
function.
The <code>WINDIVERT_LAYER_REFLECT</code> layer can also capture events that
occurred before the handle was opened.
</p>
@@ -626,7 +635,7 @@ fields form the network 5-tuple associated with the operation.
For IPv4, the <code>Socket.LocalAddr</code> and <code>Socket.RemoteAddr</code>
fields will be IPv4-mapped IPv6 addresses.
The <code>WINDIVERT_EVENT_SOCKET_BIND</code> and
<code>WINDIVERT_EVENT_SOCKET_LISTEN</code> events will occur before a
<code>WINDIVERT_EVENT_SOCKET_LISTEN</code> events can occur before a
connection attempt has been made, meaning that the
<code>Socket.RemoteAddr</code> and <code>Socket.RemotePort</code> fields
for these events will be zero.
@@ -955,21 +964,6 @@ An alias for <code>WINDIVERT_FLAG_SEND_ONLY</code>.
</tr>
<tr>
<td>
<code>WINDIVERT_FLAG_RECV_PARTIAL</code>
</td>
<td>
This flags enables <q>partial receives</q>.
By default, if a packet is too big for the buffer passed to
<a href="#divert_recv"><code>WinDivertRecv()</code></a>, the operation
will fail with <code>ERROR_INSUFFICIENT_BUFFER</code>.
This flag silences this error and only copies part of the packet
up to the buffer size.
The <code>WINDIVERT_FLAG_RECV_PARTIAL</code> behavior was the default
on older (pre-2.0) versions of WinDivert.
</td>
</tr>
<tr>
<td>
<code>WINDIVERT_FLAG_NO_INSTALL</code>
</td>
<td>
@@ -985,8 +979,7 @@ This flag is useful for querying the WinDivert state using a
<p>
Note that any combination of
<code>(WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP)</code> or
<code>(WINDIVERT_FLAG_RECV_ONLY | WINDIVERT_FLAG_SEND_ONLY)</code> or
<code>(WINDIVERT_FLAG_RECV_PARTIAL | WINDIVERT_FLAG_SEND_ONLY)</code>
<code>(WINDIVERT_FLAG_RECV_ONLY | WINDIVERT_FLAG_SEND_ONLY)</code>
are considered invalid.
</p>
<p>
@@ -1165,10 +1158,11 @@ For layers that do support capturing, the captured packet will be written to
the <code>pPacket</code> buffer.
If non-<code>NULL</code>, then the total number of bytes
written to <code>pPacket</code> will be written to <code>recvLen</code>.
Partial receives (where the packet data is truncated) is supported provided
the handle was opened with the <code>WINDIVERT_FLAG_RECV_PARTIAL</code> flag set,
otherwise the operation will fail with <code>ERROR_INSUFFICIENT_BUFFER</code>
if the <code>pPacket</code> buffer is too small.
If the <code>pPacket</code> buffer is too small, the packet will be
truncated and the operation will fail with the
<code>ERROR_INSUFFICIENT_BUFFER</code> error code.
This error can be ignored if the application only intends to receive part
of the packet, e.g., the IP headers only.
For layers that do not capture packets, the <code>pPacket</code> parameter
should be <code>NULL</code> and <code>packetLen</code> should be zero.
</p><p>
@@ -2372,8 +2366,8 @@ Formats the given filter string or object.
This function is mainly useful for <q>decompiling</q> the filter object
representation back into a human-readable filter string representation.
One application is the <code>WINDIVERT_LAYER_REFLECT</code> layer,
where a <q>pseudo packet</q> containing a filter object is returned by
<a href="#divert_recv"><code>WinDivertRecv()</code></a>.
where the filter object associated with the reflection event is
returned by <a href="#divert_recv"><code>WinDivertRecv()</code></a>.
</p>
</dd></dl>
@@ -2635,9 +2629,11 @@ The possible macros are:
<tr><td><code>PACKET</code></td><td>&#10004;</td><td>&#10004;</td><td></td><td></td><td></td><td><code>WINDIVERT_EVENT_NETWORK_PACKET</code></td></tr>
<tr><td><code>ESTABLISHED</code></td><td></td><td></td><td>&#10004;</td><td></td><td></td><td><code>WINDIVERT_EVENT_FLOW_ESTABLISHED</code></td></tr>
<tr><td><code>DELETED</code></td><td></td><td></td><td>&#10004;</td><td></td><td></td><td><code>WINDIVERT_EVENT_FLOW_DELETED</code></td></tr>
<tr><td><code>ACCEPT</code></td><td></td><td></td><td></td><td>&#10004;</td><td></td><td><code>WINDIVERT_EVENT_SOCKET_ACCEPT</code></td></tr>
<tr><td><code>BIND</code></td><td></td><td></td><td></td><td>&#10004;</td><td></td><td><code>WINDIVERT_EVENT_SOCKET_BIND</code></td></tr>
<tr><td><code>UNBIND</code></td><td></td><td></td><td></td><td>&#10004;</td><td></td><td><code>WINDIVERT_EVENT_SOCKET_UNBIND</code></td></tr>
<tr><td><code>CONNECT</code></td><td></td><td></td><td></td><td>&#10004;</td><td></td><td><code>WINDIVERT_EVENT_SOCKET_CONNECT</code></td></tr>
<tr><td><code>DISCONNECT</code></td><td></td><td></td><td></td><td>&#10004;</td><td></td><td><code>WINDIVERT_EVENT_SOCKET_DISCONNECT</code></td></tr>
<tr><td><code>ACCEPT</code></td><td></td><td></td><td></td><td>&#10004;</td><td></td><td><code>WINDIVERT_EVENT_SOCKET_ACCEPT</code></td></tr>
<tr><td><code>LISTEN</code></td><td></td><td></td><td></td><td>&#10004;</td><td></td><td><code>WINDIVERT_EVENT_SOCKET_LISTEN</code></td></tr>
<tr><td><code>OPEN</code></td><td></td><td></td><td></td><td></td><td>&#10004;</td><td><code>WINDIVERT_EVENT_REFLECT_OPEN</code></td></tr>
<tr><td><code>CLOSE</code></td><td></td><td></td><td></td><td></td><td>&#10004;</td><td><code>WINDIVERT_EVENT_REFLECT_CLOSE</code></td></tr>
+13 -1
View File
@@ -103,22 +103,34 @@ int __cdecl main(int argc, char **argv)
continue;
}
SetConsoleTextAttribute(console, FOREGROUND_GREEN);
switch (addr.Event)
{
case WINDIVERT_EVENT_SOCKET_BIND:
SetConsoleTextAttribute(console, FOREGROUND_GREEN);
printf("BIND");
break;
case WINDIVERT_EVENT_SOCKET_UNBIND:
SetConsoleTextAttribute(console, FOREGROUND_RED);
printf("UNBIND");
break;
case WINDIVERT_EVENT_SOCKET_LISTEN:
SetConsoleTextAttribute(console, FOREGROUND_GREEN);
printf("LISTEN");
break;
case WINDIVERT_EVENT_SOCKET_CONNECT:
SetConsoleTextAttribute(console, FOREGROUND_GREEN);
printf("CONNECT");
break;
case WINDIVERT_EVENT_SOCKET_DISCONNECT:
SetConsoleTextAttribute(console, FOREGROUND_RED);
printf("DISCONNECT");
break;
case WINDIVERT_EVENT_SOCKET_ACCEPT:
SetConsoleTextAttribute(console, FOREGROUND_GREEN);
printf("ACCEPT");
break;
default:
SetConsoleTextAttribute(console, FOREGROUND_BLUE);
printf("???");
break;
}
+1 -9
View File
@@ -173,7 +173,6 @@ int __cdecl main(int argc, char **argv)
static UINT8 packet[MAX_PACKET];
static char path[MAX_PATH+1];
static char filter_str[MAX_FILTER_LEN];
PVOID object;
DWORD path_len;
BOOL or;
WINDIVERT_ADDRESS addr;
@@ -369,11 +368,6 @@ usage:
printf("%sSEND_ONLY", (or? "|": ""));
or = TRUE;
}
if ((addr.Reflect.Flags & WINDIVERT_FLAG_RECV_PARTIAL) != 0)
{
printf("%sRECV_PARTIAL", (or? "|": ""));
or = TRUE;
}
if ((addr.Reflect.Flags & WINDIVERT_FLAG_NO_INSTALL) != 0)
{
printf("%sNO_INSTALL", (or? "|": ""));
@@ -389,9 +383,7 @@ usage:
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
fputs(" filter=", stdout);
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
WinDivertHelperParsePacket(packet, packet_len, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, &object, NULL, NULL, NULL);
if (WinDivertHelperFormatFilter((char *)object, addr.Reflect.Layer,
if (WinDivertHelperFormatFilter((char *)packet, addr.Reflect.Layer,
filter_str, sizeof(filter_str)))
{
printf("\"%s\"", filter_str);
+10 -7
View File
@@ -143,13 +143,14 @@ typedef struct
UINT64 IPChecksum:1; /* Packet has valid IPv4 checksum? */
UINT64 TCPChecksum:1; /* Packet has valid TCP checksum? */
UINT64 UDPChecksum:1; /* Packet has valid UDP checksum? */
UINT64 Reserved:41;
UINT64 Reserved1:41;
union
{
WINDIVERT_DATA_NETWORK Network; /* Network layer data. */
WINDIVERT_DATA_FLOW Flow; /* Flow layer data. */
WINDIVERT_DATA_SOCKET Socket; /* Socket layer data. */
WINDIVERT_DATA_REFLECT Reflect; /* Reflect layer data. */
UINT8 Reserved2[48];
};
} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
@@ -163,11 +164,14 @@ typedef enum
/* Flow established. */
WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */
WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */
WINDIVERT_EVENT_SOCKET_LISTEN = 4, /* Socket listen. */
WINDIVERT_EVENT_SOCKET_UNBIND = 4, /* Socket unbind. */
WINDIVERT_EVENT_SOCKET_CONNECT = 5, /* Socket connect. */
WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */
WINDIVERT_EVENT_REFLECT_OPEN = 7, /* WinDivert handle opened. */
WINDIVERT_EVENT_REFLECT_CLOSE = 8, /* WinDivert handle closed. */
WINDIVERT_EVENT_SOCKET_DISCONNECT = 6,
/* Socket disconnect. */
WINDIVERT_EVENT_SOCKET_LISTEN = 7, /* Socket listen. */
WINDIVERT_EVENT_SOCKET_ACCEPT = 8, /* Socket accept. */
WINDIVERT_EVENT_REFLECT_OPEN = 9, /* WinDivert handle opened. */
WINDIVERT_EVENT_REFLECT_CLOSE = 10, /* WinDivert handle closed. */
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
/*
@@ -179,8 +183,7 @@ typedef enum
#define WINDIVERT_FLAG_READ_ONLY WINDIVERT_FLAG_RECV_ONLY
#define WINDIVERT_FLAG_SEND_ONLY 0x0008
#define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY
#define WINDIVERT_FLAG_RECV_PARTIAL 0x0010
#define WINDIVERT_FLAG_NO_INSTALL 0x0020
#define WINDIVERT_FLAG_NO_INSTALL 0x0010
/*
* WinDivert parameters.
+9 -7
View File
@@ -177,8 +177,7 @@
*/
#define WINDIVERT_FLAGS_ALL \
(WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP | WINDIVERT_FLAG_RECV_ONLY |\
WINDIVERT_FLAG_SEND_ONLY | WINDIVERT_FLAG_RECV_PARTIAL | \
WINDIVERT_FLAG_NO_INSTALL)
WINDIVERT_FLAG_SEND_ONLY | WINDIVERT_FLAG_NO_INSTALL)
#define WINDIVERT_FLAGS_EXCLUDE(flags, flag1, flag2) \
(((flags) & ((flag1) | (flag2))) != ((flag1) | (flag2)))
#define WINDIVERT_FLAGS_VALID(flags) \
@@ -186,8 +185,6 @@
WINDIVERT_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_SNIFF, \
WINDIVERT_FLAG_DROP) && \
WINDIVERT_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_RECV_ONLY, \
WINDIVERT_FLAG_SEND_ONLY) && \
WINDIVERT_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_RECV_PARTIAL, \
WINDIVERT_FLAG_SEND_ONLY))
/*
@@ -199,16 +196,21 @@
#define WINDIVERT_FILTER_FLAG_IPV6 0x0000000000000008ull
#define WINDIVERT_FILTER_FLAG_EVENT_FLOW_DELETED 0x0000000000000010ull
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND 0x0000000000000020ull
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT 0x0000000000000040ull
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN 0x0000000000000080ull
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT 0x0000000000000100ull
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_UNBIND 0x0000000000000040ull
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT 0x0000000000000080ull
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_DISCONNECT \
0x0000000000000100ull
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN 0x0000000000000200ull
#define WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT 0x0000000000000800ull
#define WINDIVERT_FILTER_FLAGS_ALL \
(WINDIVERT_FILTER_FLAG_INBOUND | WINDIVERT_FILTER_FLAG_OUTBOUND | \
WINDIVERT_FILTER_FLAG_IP | WINDIVERT_FILTER_FLAG_IPV6 | \
WINDIVERT_FILTER_FLAG_EVENT_FLOW_DELETED | \
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND | \
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_UNBIND | \
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT | \
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_DISCONNECT | \
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN | \
WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT)
+399 -78
View File
@@ -129,7 +129,7 @@ struct reflect_context_s
* WinDivert context information.
*/
#define WINDIVERT_CONTEXT_SIZE (sizeof(struct context_s))
#define WINDIVERT_CONTEXT_MAXLAYERS 8
#define WINDIVERT_CONTEXT_MAXLAYERS 12
typedef enum
{
WINDIVERT_CONTEXT_STATE_OPENING = 0xA0, // Context is opening.
@@ -408,6 +408,16 @@ static void windivert_resource_assignment_v6_classify(
IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data,
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result);
static void windivert_resource_release_v4_classify(
IN const FWPS_INCOMING_VALUES0 *fixed_vals,
IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data,
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result);
static void windivert_resource_release_v6_classify(
IN const FWPS_INCOMING_VALUES0 *fixed_vals,
IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data,
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result);
static void windivert_auth_connect_v4_classify(
IN const FWPS_INCOMING_VALUES0 *fixed_vals,
IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data,
@@ -418,6 +428,16 @@ static void windivert_auth_connect_v6_classify(
IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data,
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result);
static void windivert_endpoint_closure_v4_classify(
IN const FWPS_INCOMING_VALUES0 *fixed_vals,
IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data,
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result);
static void windivert_endpoint_closure_v6_classify(
IN const FWPS_INCOMING_VALUES0 *fixed_vals,
IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data,
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result);
static void windivert_auth_listen_v4_classify(
IN const FWPS_INCOMING_VALUES0 *fixed_vals,
IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data,
@@ -516,12 +536,24 @@ DEFINE_GUID(WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV4_GUID,
DEFINE_GUID(WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV6_GUID,
0xF3458E58, 0xD123, 0x439B,
0xB6, 0x40, 0x74, 0x3C, 0xC7, 0x53, 0x9E, 0x36);
DEFINE_GUID(WINDIVERT_SUBLAYER_RESOURCE_RELEASE_IPV4_GUID,
0x02366282, 0x9099, 0x43A7,
0x95, 0xC3, 0xAB, 0x52, 0x87, 0xB3, 0xF2, 0xDC);
DEFINE_GUID(WINDIVERT_SUBLAYER_RESOURCE_RELEASE_IPV6_GUID,
0x60FCA14A, 0x7677, 0x45D2,
0xBB, 0x5C, 0x15, 0xDB, 0xAE, 0x4B, 0x7B, 0x6B);
DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV4_GUID,
0x2F97411F, 0x6350, 0x450A,
0xBF, 0x45, 0x4C, 0x0B, 0xC1, 0xDB, 0x3F, 0x7E);
DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV6_GUID,
0x7BAFEEEB, 0x84F0, 0x4BB0,
0x91, 0x1F, 0x7E, 0x62, 0x2D, 0x73, 0x24, 0x2C);
DEFINE_GUID(WINDIVERT_SUBLAYER_ENDPOINT_CLOSURE_IPV4_GUID,
0x8180D216, 0xB3BD, 0x4014,
0x99, 0x69, 0xA3, 0xDF, 0x0F, 0x3E, 0x61, 0x85);
DEFINE_GUID(WINDIVERT_SUBLAYER_ENDPOINT_CLOSURE_IPV6_GUID,
0x2535A264, 0xEC8B, 0x49CC,
0xA4, 0xD6, 0x83, 0x81, 0xD7, 0x5F, 0xAB, 0xE6);
DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV4_GUID,
0x49F2A9AD, 0x805E, 0x4328,
0xBB, 0xDA, 0x92, 0x57, 0xB5, 0x18, 0x3A, 0x40);
@@ -674,6 +706,40 @@ static const struct layer_s windivert_layer_resource_assignment_ipv6 =
#define WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6 \
(&windivert_layer_resource_assignment_ipv6)
static const struct layer_s windivert_layer_resource_release_ipv4 =
{
L"" WINDIVERT_LAYER_NAME L"_SubLayerResourceReleaseIPv4",
L"" WINDIVERT_LAYER_NAME L" sublayer resource release (IPv4)",
L"" WINDIVERT_LAYER_NAME L"_CalloutResourceReleaseIPv4",
L"" WINDIVERT_LAYER_NAME L" callout resource release (IPv4)",
L"" WINDIVERT_LAYER_NAME L"_FilterResourceReleaseIPv4",
L"" WINDIVERT_LAYER_NAME L" filter resource release (IPv4)",
&FWPM_LAYER_ALE_RESOURCE_RELEASE_V4,
&WINDIVERT_SUBLAYER_RESOURCE_RELEASE_IPV4_GUID,
windivert_resource_release_v4_classify,
NULL,
0
};
#define WINDIVERT_LAYER_RESOURCE_RELEASE_IPV4 \
(&windivert_layer_resource_release_ipv4)
static const struct layer_s windivert_layer_resource_release_ipv6 =
{
L"" WINDIVERT_LAYER_NAME L"_SubLayerResourceReleaseIPv6",
L"" WINDIVERT_LAYER_NAME L" sublayer resource release (IPv6)",
L"" WINDIVERT_LAYER_NAME L"_CalloutResourceReleaseIPv6",
L"" WINDIVERT_LAYER_NAME L" callout resource release (IPv6)",
L"" WINDIVERT_LAYER_NAME L"_FilterResourceReleaseIPv6",
L"" WINDIVERT_LAYER_NAME L" filter resource release (IPv6)",
&FWPM_LAYER_ALE_RESOURCE_RELEASE_V6,
&WINDIVERT_SUBLAYER_RESOURCE_RELEASE_IPV6_GUID,
windivert_resource_release_v6_classify,
NULL,
0
};
#define WINDIVERT_LAYER_RESOURCE_RELEASE_IPV6 \
(&windivert_layer_resource_release_ipv6)
static const struct layer_s windivert_layer_auth_connect_ipv4 =
{
L"" WINDIVERT_LAYER_NAME L"_SubLayerAuthConnectIPv4",
@@ -708,6 +774,40 @@ static const struct layer_s windivert_layer_auth_connect_ipv6 =
#define WINDIVERT_LAYER_AUTH_CONNECT_IPV6 \
(&windivert_layer_auth_connect_ipv6)
static const struct layer_s windivert_layer_endpoint_closure_ipv4 =
{
L"" WINDIVERT_LAYER_NAME L"_SubLayerEndpointClosureIPv4",
L"" WINDIVERT_LAYER_NAME L" sublayer endpoint closure (IPv4)",
L"" WINDIVERT_LAYER_NAME L"_CalloutEndpointClosureIPv4",
L"" WINDIVERT_LAYER_NAME L" callout endpoint closure (IPv4)",
L"" WINDIVERT_LAYER_NAME L"_FilterEndpointClosureIPv4",
L"" WINDIVERT_LAYER_NAME L" filter endpoint closure (IPv4)",
&FWPM_LAYER_ALE_ENDPOINT_CLOSURE_V4,
&WINDIVERT_SUBLAYER_ENDPOINT_CLOSURE_IPV4_GUID,
windivert_endpoint_closure_v4_classify,
NULL,
0
};
#define WINDIVERT_LAYER_ENDPOINT_CLOSURE_IPV4 \
(&windivert_layer_endpoint_closure_ipv4)
static const struct layer_s windivert_layer_endpoint_closure_ipv6 =
{
L"" WINDIVERT_LAYER_NAME L"_SubLayerEndpointClosureIPv6",
L"" WINDIVERT_LAYER_NAME L" sublayer endpoint closure (IPv6)",
L"" WINDIVERT_LAYER_NAME L"_CalloutEndpointClosureIPv6",
L"" WINDIVERT_LAYER_NAME L" callout endpoint closure (IPv6)",
L"" WINDIVERT_LAYER_NAME L"_FilterEndpointClosureIPv6",
L"" WINDIVERT_LAYER_NAME L" filter endpoint closure (IPv6)",
&FWPM_LAYER_ALE_ENDPOINT_CLOSURE_V6,
&WINDIVERT_SUBLAYER_ENDPOINT_CLOSURE_IPV6_GUID,
windivert_endpoint_closure_v6_classify,
NULL,
0
};
#define WINDIVERT_LAYER_ENDPOINT_CLOSURE_IPV6 \
(&windivert_layer_endpoint_closure_ipv6)
static const struct layer_s windivert_layer_auth_listen_ipv4 =
{
L"" WINDIVERT_LAYER_NAME L"_SubLayerAuthListenIPv4",
@@ -1072,6 +1172,16 @@ driver_entry_sublayer_error:
{
goto driver_entry_sublayer_error;
}
status = windivert_install_sublayer(WINDIVERT_LAYER_RESOURCE_RELEASE_IPV4);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
status = windivert_install_sublayer(WINDIVERT_LAYER_RESOURCE_RELEASE_IPV6);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_CONNECT_IPV4);
if (!NT_SUCCESS(status))
{
@@ -1082,6 +1192,16 @@ driver_entry_sublayer_error:
{
goto driver_entry_sublayer_error;
}
status = windivert_install_sublayer(WINDIVERT_LAYER_ENDPOINT_CLOSURE_IPV4);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
status = windivert_install_sublayer(WINDIVERT_LAYER_ENDPOINT_CLOSURE_IPV6);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_LISTEN_IPV4);
if (!NT_SUCCESS(status))
{
@@ -1187,10 +1307,18 @@ static void windivert_driver_unload(void)
WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
WINDIVERT_LAYER_RESOURCE_RELEASE_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
WINDIVERT_LAYER_RESOURCE_RELEASE_IPV6->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
WINDIVERT_LAYER_AUTH_CONNECT_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
WINDIVERT_LAYER_AUTH_CONNECT_IPV6->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
WINDIVERT_LAYER_ENDPOINT_CLOSURE_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
WINDIVERT_LAYER_ENDPOINT_CLOSURE_IPV6->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
WINDIVERT_LAYER_AUTH_LISTEN_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
@@ -1266,6 +1394,7 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
context->shutdown_recv_enabled = FALSE;
context->shutdown_send = FALSE;
context->priority = 0;
context->priority16 = 0;
context->filter = NULL;
context->filter_len = 0;
context->filter_flags = 0;
@@ -1356,17 +1485,20 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
UINT8 i, j;
layer_t layers[WINDIVERT_CONTEXT_MAXLAYERS];
UINT32 *callout_ids[WINDIVERT_CONTEXT_MAXLAYERS] = {NULL};
BOOL inbound, outbound, ipv4, ipv6, bind, connect, listen, accept;
BOOL inbound, outbound, ipv4, ipv6, bind, unbind, connect, disconnect,
listen, accept;
NTSTATUS status = STATUS_SUCCESS;
inbound = ((flags & WINDIVERT_FILTER_FLAG_INBOUND) != 0);
outbound = ((flags & WINDIVERT_FILTER_FLAG_OUTBOUND) != 0);
ipv4 = ((flags & WINDIVERT_FILTER_FLAG_IP) != 0);
ipv6 = ((flags & WINDIVERT_FILTER_FLAG_IPV6) != 0);
bind = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND) != 0);
connect = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT) != 0);
listen = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN) != 0);
accept = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT) != 0);
inbound = ((flags & WINDIVERT_FILTER_FLAG_INBOUND) != 0);
outbound = ((flags & WINDIVERT_FILTER_FLAG_OUTBOUND) != 0);
ipv4 = ((flags & WINDIVERT_FILTER_FLAG_IP) != 0);
ipv6 = ((flags & WINDIVERT_FILTER_FLAG_IPV6) != 0);
bind = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND) != 0);
unbind = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_UNBIND) != 0);
connect = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT) != 0);
disconnect = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_DISCONNECT) != 0);
listen = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN) != 0);
accept = ((flags & WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT) != 0);
i = 0;
switch (layer)
@@ -1419,10 +1551,18 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
{
layers[i++] = WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4;
}
if (ipv4 && unbind)
{
layers[i++] = WINDIVERT_LAYER_RESOURCE_RELEASE_IPV4;
}
if (ipv4 && connect)
{
layers[i++] = WINDIVERT_LAYER_AUTH_CONNECT_IPV4;
}
if (ipv4 && disconnect)
{
layers[i++] = WINDIVERT_LAYER_ENDPOINT_CLOSURE_IPV4;
}
if (ipv4 && listen)
{
layers[i++] = WINDIVERT_LAYER_AUTH_LISTEN_IPV4;
@@ -1435,10 +1575,18 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
{
layers[i++] = WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6;
}
if (ipv6 && unbind)
{
layers[i++] = WINDIVERT_LAYER_RESOURCE_RELEASE_IPV6;
}
if (ipv6 && connect)
{
layers[i++] = WINDIVERT_LAYER_AUTH_CONNECT_IPV6;
}
if (ipv6 && disconnect)
{
layers[i++] = WINDIVERT_LAYER_ENDPOINT_CLOSURE_IPV6;
}
if (ipv6 && listen)
{
layers[i++] = WINDIVERT_LAYER_AUTH_LISTEN_IPV6;
@@ -1899,7 +2047,7 @@ static NTSTATUS windivert_read(context_t context, WDFREQUEST request)
* WinDivert service a single read request.
*/
static void windivert_read_service_request(context_t context, packet_t packet,
BOOL partial, LONGLONG timestamp, WDFREQUEST request)
LONGLONG timestamp, WDFREQUEST request)
{
KLOCK_QUEUE_HANDLE lock_handle;
PLIST_ENTRY entry;
@@ -1989,7 +2137,7 @@ static void windivert_read_service_request(context_t context, packet_t packet,
packet);
}
src_len = packet->packet_len;
if (!partial && src_len > dst_len)
if (src_len > dst_len)
{
status = STATUS_BUFFER_TOO_SMALL;
}
@@ -2017,7 +2165,7 @@ static void windivert_read_service_request(context_t context, packet_t packet,
addr[i].IPChecksum = packet->ip_checksum;
addr[i].TCPChecksum = packet->tcp_checksum;
addr[i].UDPChecksum = packet->udp_checksum;
addr[i].Reserved = 0;
addr[i].Reserved1 = 0;
layer_data = (PVOID)packet->data;
switch (packet->layer)
{
@@ -2175,8 +2323,7 @@ static void windivert_fast_read_service_request(PVOID packet, ULONG packet_len,
{
RtlCopyMemory(dst, src, dst_len);
}
if ((flags & WINDIVERT_FLAG_RECV_PARTIAL) == 0 &&
dst_len < packet_len)
if (dst_len < packet_len)
{
status = STATUS_BUFFER_TOO_SMALL;
}
@@ -2226,7 +2373,7 @@ static void windivert_fast_read_service_request(PVOID packet, ULONG packet_len,
addr->IPChecksum = (ip_checksum? 1: 0);
addr->TCPChecksum = (tcp_checksum? 1: 0);
addr->UDPChecksum = (udp_checksum? 1: 0);
addr->Reserved = 0;
addr->Reserved1 = 0;
switch (layer)
{
case WINDIVERT_LAYER_NETWORK:
@@ -2273,7 +2420,7 @@ static void windivert_read_service(context_t context)
WDFREQUEST request;
PLIST_ENTRY entry;
LONGLONG timestamp;
BOOL partial, timeout;
BOOL timeout;
NTSTATUS status;
packet_t packet;
req_context_t req_context;
@@ -2281,7 +2428,6 @@ static void windivert_read_service(context_t context)
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
partial = ((context->flags & WINDIVERT_FLAG_RECV_PARTIAL) != 0);
while (context->state == WINDIVERT_CONTEXT_STATE_OPEN &&
!IsListEmpty(&context->packet_queue))
{
@@ -2303,8 +2449,7 @@ static void windivert_read_service(context_t context)
context->packet_queue_size -= packet->packet_len;
KeReleaseInStackQueuedSpinLock(&lock_handle);
windivert_read_service_request(context, packet, partial, timestamp,
request);
windivert_read_service_request(context, packet, timestamp, request);
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
@@ -2669,7 +2814,6 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
addr_len_ptr, sizeof(UINT), &memobj);
if (!NT_SUCCESS(status))
{
status = STATUS_INVALID_PARAMETER;
DEBUG_ERROR("invalid address length pointer for RECV ioctl",
status);
goto windivert_caller_context_error;
@@ -3911,6 +4055,11 @@ static void windivert_resource_assignment_v4_classify(
WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
{
return;
}
socket_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv4_addr(fixed_vals,
FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_ADDRESS,
@@ -3943,6 +4092,11 @@ static void windivert_resource_assignment_v6_classify(
WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
{
return;
}
socket_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv6_addr(fixed_vals,
FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_LOCAL_ADDRESS,
@@ -3963,6 +4117,70 @@ static void windivert_resource_assignment_v6_classify(
/*outbound=*/FALSE, loopback, result);
}
/*
* WinDivert classify resource release IPv4 function.
*/
static void windivert_resource_release_v4_classify(
IN const FWPS_INCOMING_VALUES0 *fixed_vals,
IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data,
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
socket_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv4_addr(fixed_vals,
FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_LOCAL_ADDRESS,
socket_data.LocalAddr);
RtlZeroMemory(&socket_data.RemoteAddr, sizeof(socket_data.RemoteAddr));
socket_data.LocalPort = windivert_get_val16(fixed_vals,
FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_LOCAL_PORT);
socket_data.RemotePort = 0;
socket_data.Protocol = windivert_get_val8(fixed_vals,
FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_IP_PROTOCOL);
loopback = ((windivert_get_val32(fixed_vals,
FWPS_FIELD_ALE_RESOURCE_RELEASE_V4_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
&socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_UNBIND, /*ipv4=*/TRUE,
/*outbound=*/FALSE, loopback, result);
}
/*
* WinDivert classify resource release IPv6 function.
*/
static void windivert_resource_release_v6_classify(
IN const FWPS_INCOMING_VALUES0 *fixed_vals,
IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data,
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
socket_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv6_addr(fixed_vals,
FWPS_FIELD_ALE_RESOURCE_RELEASE_V6_IP_LOCAL_ADDRESS,
socket_data.LocalAddr);
RtlZeroMemory(&socket_data.RemoteAddr, sizeof(socket_data.RemoteAddr));
socket_data.LocalPort = windivert_get_val16(fixed_vals,
FWPS_FIELD_ALE_RESOURCE_RELEASE_V6_IP_LOCAL_PORT);
socket_data.RemotePort = 0;
socket_data.Protocol = windivert_get_val8(fixed_vals,
FWPS_FIELD_ALE_RESOURCE_RELEASE_V6_IP_PROTOCOL);
loopback = ((windivert_get_val32(fixed_vals,
FWPS_FIELD_ALE_RESOURCE_RELEASE_V6_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
&socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_UNBIND, /*ipv4=*/FALSE,
/*outbound=*/FALSE, loopback, result);
}
/*
* WinDivert classify auth connect IPv4 function.
*/
@@ -3973,8 +4191,21 @@ static void windivert_auth_connect_v4_classify(
OUT FWPS_CLASSIFY_OUT0 *result)
{
WINDIVERT_DATA_SOCKET socket_data;
UINT32 flags;
BOOL loopback;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
{
return;
}
flags = windivert_get_val32(fixed_vals,
FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS);
if ((flags & FWP_CONDITION_FLAG_IS_REAUTHORIZE) != 0)
{
result->actionType = FWP_ACTION_CONTINUE;
return;
}
socket_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv4_addr(fixed_vals,
FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS,
@@ -3989,9 +4220,7 @@ static void windivert_auth_connect_v4_classify(
socket_data.Protocol = windivert_get_val8(fixed_vals,
FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL);
loopback = ((windivert_get_val32(fixed_vals,
FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
loopback = ((flags & FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
&socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_CONNECT, /*ipv4=*/TRUE,
@@ -4008,8 +4237,21 @@ static void windivert_auth_connect_v6_classify(
OUT FWPS_CLASSIFY_OUT0 *result)
{
WINDIVERT_DATA_SOCKET socket_data;
UINT32 flags;
BOOL loopback;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
{
return;
}
flags = windivert_get_val32(fixed_vals,
FWPS_FIELD_ALE_AUTH_CONNECT_V6_FLAGS);
if ((flags & FWP_CONDITION_FLAG_IS_REAUTHORIZE) != 0)
{
result->actionType = FWP_ACTION_CONTINUE;
return;
}
socket_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv6_addr(fixed_vals,
FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_ADDRESS,
@@ -4024,15 +4266,84 @@ static void windivert_auth_connect_v6_classify(
socket_data.Protocol = windivert_get_val8(fixed_vals,
FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_PROTOCOL);
loopback = ((windivert_get_val32(fixed_vals,
FWPS_FIELD_ALE_AUTH_CONNECT_V6_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
loopback = ((flags & FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
&socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_CONNECT, /*ipv4=*/FALSE,
/*outbound=*/TRUE, loopback, result);
}
/*
* WinDivert classify endpoint closure IPv4 function.
*/
static void windivert_endpoint_closure_v4_classify(
IN const FWPS_INCOMING_VALUES0 *fixed_vals,
IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data,
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
socket_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv4_addr(fixed_vals,
FWPS_FIELD_ALE_ENDPOINT_CLOSURE_V4_IP_LOCAL_ADDRESS,
socket_data.LocalAddr);
windivert_get_ipv4_addr(fixed_vals,
FWPS_FIELD_ALE_ENDPOINT_CLOSURE_V4_IP_REMOTE_ADDRESS,
socket_data.RemoteAddr);
socket_data.LocalPort = windivert_get_val16(fixed_vals,
FWPS_FIELD_ALE_ENDPOINT_CLOSURE_V4_IP_LOCAL_PORT);
socket_data.RemotePort = windivert_get_val16(fixed_vals,
FWPS_FIELD_ALE_ENDPOINT_CLOSURE_V4_IP_REMOTE_PORT);
socket_data.Protocol = windivert_get_val8(fixed_vals,
FWPS_FIELD_ALE_ENDPOINT_CLOSURE_V4_IP_PROTOCOL);
loopback = ((windivert_get_val32(fixed_vals,
FWPS_FIELD_ALE_ENDPOINT_CLOSURE_V4_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
&socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_DISCONNECT,
/*ipv4=*/TRUE, /*outbound=*/TRUE, loopback, result);
}
/*
* WinDivert classify endpoint closure IPv6 function.
*/
static void windivert_endpoint_closure_v6_classify(
IN const FWPS_INCOMING_VALUES0 *fixed_vals,
IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data,
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
socket_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv6_addr(fixed_vals,
FWPS_FIELD_ALE_ENDPOINT_CLOSURE_V6_IP_LOCAL_ADDRESS,
socket_data.LocalAddr);
windivert_get_ipv6_addr(fixed_vals,
FWPS_FIELD_ALE_ENDPOINT_CLOSURE_V6_IP_REMOTE_ADDRESS,
socket_data.RemoteAddr);
socket_data.LocalPort = windivert_get_val16(fixed_vals,
FWPS_FIELD_ALE_ENDPOINT_CLOSURE_V6_IP_LOCAL_PORT);
socket_data.RemotePort = windivert_get_val16(fixed_vals,
FWPS_FIELD_ALE_ENDPOINT_CLOSURE_V6_IP_REMOTE_PORT);
socket_data.Protocol = windivert_get_val8(fixed_vals,
FWPS_FIELD_ALE_ENDPOINT_CLOSURE_V6_IP_PROTOCOL);
loopback = ((windivert_get_val32(fixed_vals,
FWPS_FIELD_ALE_ENDPOINT_CLOSURE_V6_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
&socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_DISCONNECT,
/*ipv4=*/FALSE, /*outbound=*/TRUE, loopback, result);
}
/*
* WinDivert classify auth listen IPv4 function.
*/
@@ -4045,6 +4356,11 @@ static void windivert_auth_listen_v4_classify(
WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
{
return;
}
socket_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv4_addr(fixed_vals,
FWPS_FIELD_ALE_AUTH_LISTEN_V4_IP_LOCAL_ADDRESS,
@@ -4076,6 +4392,11 @@ static void windivert_auth_listen_v6_classify(
WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
{
return;
}
socket_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv6_addr(fixed_vals,
FWPS_FIELD_ALE_AUTH_LISTEN_V6_IP_LOCAL_ADDRESS,
@@ -4105,8 +4426,21 @@ static void windivert_auth_recv_accept_v4_classify(
OUT FWPS_CLASSIFY_OUT0 *result)
{
WINDIVERT_DATA_SOCKET socket_data;
UINT32 flags;
BOOL loopback;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
{
return;
}
flags = windivert_get_val32(fixed_vals,
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS);
if ((flags & FWP_CONDITION_FLAG_IS_REAUTHORIZE) != 0)
{
result->actionType = FWP_ACTION_CONTINUE;
return;
}
socket_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv4_addr(fixed_vals,
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS,
@@ -4121,9 +4455,7 @@ static void windivert_auth_recv_accept_v4_classify(
socket_data.Protocol = windivert_get_val8(fixed_vals,
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL);
loopback = ((windivert_get_val32(fixed_vals,
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
loopback = ((flags & FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
&socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_ACCEPT, /*ipv4=*/TRUE,
@@ -4140,7 +4472,20 @@ static void windivert_auth_recv_accept_v6_classify(
OUT FWPS_CLASSIFY_OUT0 *result)
{
WINDIVERT_DATA_SOCKET socket_data;
UINT32 flags;
BOOL loopback;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0)
{
return;
}
flags = windivert_get_val32(fixed_vals,
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_FLAGS);
if ((flags & FWP_CONDITION_FLAG_IS_REAUTHORIZE) != 0)
{
result->actionType = FWP_ACTION_CONTINUE;
return;
}
socket_data.ProcessId = (UINT32)meta_vals->processId;
windivert_get_ipv6_addr(fixed_vals,
@@ -4156,9 +4501,7 @@ static void windivert_auth_recv_accept_v6_classify(
socket_data.Protocol = windivert_get_val8(fixed_vals,
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_PROTOCOL);
loopback = ((windivert_get_val32(fixed_vals,
FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
loopback = ((flags & FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
&socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_ACCEPT, /*ipv4=*/FALSE,
@@ -4180,16 +4523,13 @@ static void windivert_socket_classify(context_t context,
LONGLONG timestamp;
NTSTATUS status;
// Basic checks:
if (!(result->rights & FWPS_RIGHT_ACTION_WRITE))
{
return;
}
// Get the timestamp.
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
result->actionType = FWP_ACTION_CONTINUE;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) != 0)
{
result->actionType = FWP_ACTION_CONTINUE;
}
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
@@ -4221,7 +4561,10 @@ static void windivert_socket_classify(context_t context,
}
WdfObjectDereference(object);
if ((flags & WINDIVERT_FLAG_SNIFF) == 0)
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) != 0 &&
event != WINDIVERT_EVENT_SOCKET_UNBIND &&
event != WINDIVERT_EVENT_SOCKET_DISCONNECT &&
(flags & WINDIVERT_FLAG_SNIFF) == 0)
{
result->actionType = FWP_ACTION_BLOCK;
result->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
@@ -4906,7 +5249,7 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
*udp_header_ptr = udp_header;
*proto_ptr = proto;
*header_len_ptr = header_len;
*payload_len_ptr = tot_len - header_len;
*payload_len_ptr = (header_len > tot_len? 0: tot_len - header_len);
return TRUE;
}
@@ -5976,7 +6319,7 @@ windivert_filter_compile_error:
/* WINDIVERT REFLECT MANAGER IMPLEMENTATION */
/****************************************************************************/
#define WINDIVERT_REFLECT_PSEUDO_PACKET_MAX 12288
#define WINDIVERT_REFLECT_PACKET_MAX 12288
/*
* WinDivert reflect state.
@@ -5989,7 +6332,7 @@ static LIST_ENTRY reflect_contexts; // All open (non-REFLECT) contexts.
static LIST_ENTRY reflect_waiters; // All open REFLECT contexts.
static WDFWORKITEM reflect_worker; // Reflect work item.
#pragma data_seg(push, stack, "PAGE")
static UINT8 reflect_pseudo_packet[WINDIVERT_REFLECT_PSEUDO_PACKET_MAX];
static UINT8 reflect_packet[WINDIVERT_REFLECT_PACKET_MAX];
#pragma data_seg(pop, stack)
/*
@@ -6095,31 +6438,19 @@ static void windivert_reflect_close_event(context_t context)
}
/*
* Create REFLECT layer "pseudo" packet to pass the filter.
* Create REFLECT layer packet to pass the filter.
*/
static PWINDIVERT_IPHDR windivert_reflect_pseudo_packet(context_t context,
ULONG *len_ptr)
static PVOID windivert_reflect_packet(context_t context, ULONG *len_ptr)
{
KLOCK_QUEUE_HANDLE lock_handle;
UINT16 total_len;
UINT8 *packet;
char *object;
const WINDIVERT_FILTER *filter;
UINT16 filter_len;
PWINDIVERT_IPHDR iphdr;
WINDIVERT_STREAM stream;
// The filter is returned in a pseudo-IP packet. This is just to make
// the interface consistent, i.e., WinDivertRecv() always receives IP
// packets.
packet = reflect_pseudo_packet;
iphdr = (PWINDIVERT_IPHDR)packet;
object = (char *)(iphdr + 1);
stream.data = object;
stream.data = reflect_packet;
stream.pos = 0;
stream.max = sizeof(reflect_pseudo_packet) - sizeof(WINDIVERT_IPHDR);
stream.max = sizeof(reflect_packet) - 1;
stream.overflow = FALSE;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
@@ -6128,18 +6459,8 @@ static PWINDIVERT_IPHDR windivert_reflect_pseudo_packet(context_t context,
KeReleaseInStackQueuedSpinLock(&lock_handle);
WinDivertSerializeFilter(&stream, filter, (UINT8)filter_len);
total_len = sizeof(WINDIVERT_IPHDR) + (UINT16)stream.pos;
RtlZeroMemory(iphdr, sizeof(WINDIVERT_IPHDR));
iphdr->Version = 4;
iphdr->HdrLength = sizeof(WINDIVERT_IPHDR) / sizeof(UINT32);
iphdr->Length = RtlUshortByteSwap(total_len);
iphdr->TTL = 1;
iphdr->Protocol = 254; // "experimental"
*len_ptr = total_len;
return iphdr;
*len_ptr = stream.pos;
return (PVOID)stream.data;
}
/*
@@ -6152,7 +6473,7 @@ static void windivert_reflect_event_notify(context_t context,
PLIST_ENTRY entry;
context_t waiter;
const WINDIVERT_FILTER *filter;
PWINDIVERT_IPHDR packet = NULL;
PVOID packet = NULL;
ULONG packet_len;
BOOL match;
@@ -6174,9 +6495,9 @@ static void windivert_reflect_event_notify(context_t context,
}
if (packet == NULL)
{
packet = windivert_reflect_pseudo_packet(context, &packet_len);
packet = windivert_reflect_packet(context, &packet_len);
}
(VOID)windivert_queue_work(waiter, (PVOID)packet, packet_len,
(VOID)windivert_queue_work(waiter, packet, packet_len,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT,
(PVOID)&context->reflect.data, event, /*flags=*/0, /*priority=*/0,
/*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE,
@@ -6195,7 +6516,7 @@ static void windivert_reflect_established_notify(context_t context,
BOOL match, ok;
context_t waiter;
const WINDIVERT_FILTER *filter;
PWINDIVERT_IPHDR packet;
PVOID packet;
ULONG packet_len;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
@@ -6220,8 +6541,8 @@ static void windivert_reflect_established_notify(context_t context,
{
continue;
}
packet = windivert_reflect_pseudo_packet(waiter, &packet_len);
ok = windivert_queue_work(context, (PVOID)packet, packet_len,
packet = windivert_reflect_packet(waiter, &packet_len);
ok = windivert_queue_work(context, packet, packet_len,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT,
(PVOID)&waiter->reflect.data,
/*event=*/WINDIVERT_EVENT_REFLECT_OPEN, /*flags=*/0,