diff --git a/CHANGELOG b/CHANGELOG
index 2cca026..3e585ff 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -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
diff --git a/dll/windivert.c b/dll/windivert.c
index b623c52..f882bfe 100644
--- a/dll/windivert.c
+++ b/dll/windivert.c
@@ -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,
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index 628b1e1..b2412f0 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -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:
diff --git a/doc/windivert.html b/doc/windivert.html
index f502de1..a4b2670 100644
--- a/doc/windivert.html
+++ b/doc/windivert.html
@@ -401,14 +401,19 @@ correspond to socket operations, such as:
-
WINDIVERT_EVENT_SOCKET_BIND: A bind() operation.
--
WINDIVERT_EVENT_SOCKET_LISTEN: A listen() operation.
+-
WINDIVERT_EVENT_SOCKET_UNBIND: A previous binding is
+ removed.
-
WINDIVERT_EVENT_SOCKET_CONNECT: A connect()
operation.
+-
WINDIVERT_EVENT_SOCKET_DISCONNECT: A previous connection
+ is terminated.
+-
WINDIVERT_EVENT_SOCKET_LISTEN: A listen() operation.
-
WINDIVERT_EVENT_SOCKET_ACCEPT: An accept()
operation.
-Socket events can be blocked but not injected.
+Socket events, except for UNBIND/DISCONNECT,
+can be blocked, and no socket event can be injected.
Process ID information is available at this layer.
Due to technical limitations, the
WINDIVERT_LAYER_SOCKET 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 pseudo packet
that encodes the filter string
-associated with the event.
+The layer also returns an object
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
+WinDivertHelperFormatFilter()
+function.
The WINDIVERT_LAYER_REFLECT layer can also capture events that
occurred before the handle was opened.
@@ -626,7 +635,7 @@ fields form the network 5-tuple associated with the operation.
For IPv4, the Socket.LocalAddr and Socket.RemoteAddr
fields will be IPv4-mapped IPv6 addresses.
The WINDIVERT_EVENT_SOCKET_BIND and
-WINDIVERT_EVENT_SOCKET_LISTEN events will occur before a
+WINDIVERT_EVENT_SOCKET_LISTEN events can occur before a
connection attempt has been made, meaning that the
Socket.RemoteAddr and Socket.RemotePort fields
for these events will be zero.
@@ -955,21 +964,6 @@ An alias for WINDIVERT_FLAG_SEND_ONLY.
-WINDIVERT_FLAG_RECV_PARTIAL
- |
-
-This flags enables partial receives .
-By default, if a packet is too big for the buffer passed to
-WinDivertRecv(), the operation
-will fail with ERROR_INSUFFICIENT_BUFFER.
-This flag silences this error and only copies part of the packet
-up to the buffer size.
-The WINDIVERT_FLAG_RECV_PARTIAL behavior was the default
-on older (pre-2.0) versions of WinDivert.
- |
-
-
-
WINDIVERT_FLAG_NO_INSTALL
|
@@ -985,8 +979,7 @@ This flag is useful for querying the WinDivert state using a
Note that any combination of
(WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP) or
-(WINDIVERT_FLAG_RECV_ONLY | WINDIVERT_FLAG_SEND_ONLY) or
-(WINDIVERT_FLAG_RECV_PARTIAL | WINDIVERT_FLAG_SEND_ONLY)
+(WINDIVERT_FLAG_RECV_ONLY | WINDIVERT_FLAG_SEND_ONLY)
are considered invalid.
@@ -1165,10 +1158,11 @@ For layers that do support capturing, the captured packet will be written to
the pPacket buffer.
If non-NULL, then the total number of bytes
written to pPacket will be written to recvLen.
-Partial receives (where the packet data is truncated) is supported provided
-the handle was opened with the WINDIVERT_FLAG_RECV_PARTIAL flag set,
-otherwise the operation will fail with ERROR_INSUFFICIENT_BUFFER
-if the pPacket buffer is too small.
+If the pPacket buffer is too small, the packet will be
+truncated and the operation will fail with the
+ERROR_INSUFFICIENT_BUFFER 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 pPacket parameter
should be NULL and packetLen should be zero.
@@ -2372,8 +2366,8 @@ Formats the given filter string or object.
This function is mainly useful for decompiling the filter object
representation back into a human-readable filter string representation.
One application is the WINDIVERT_LAYER_REFLECT layer,
-where a pseudo packet containing a filter object is returned by
-WinDivertRecv().
+where the filter object associated with the reflection event is
+returned by WinDivertRecv().
@@ -2635,9 +2629,11 @@ The possible macros are:
|
PACKET | ✔ | ✔ | | | | WINDIVERT_EVENT_NETWORK_PACKET |
ESTABLISHED | | | ✔ | | | WINDIVERT_EVENT_FLOW_ESTABLISHED |
DELETED | | | ✔ | | | WINDIVERT_EVENT_FLOW_DELETED |
-ACCEPT | | | | ✔ | | WINDIVERT_EVENT_SOCKET_ACCEPT |
BIND | | | | ✔ | | WINDIVERT_EVENT_SOCKET_BIND |
+UNBIND | | | | ✔ | | WINDIVERT_EVENT_SOCKET_UNBIND |
CONNECT | | | | ✔ | | WINDIVERT_EVENT_SOCKET_CONNECT |
+DISCONNECT | | | | ✔ | | WINDIVERT_EVENT_SOCKET_DISCONNECT |
+ACCEPT | | | | ✔ | | WINDIVERT_EVENT_SOCKET_ACCEPT |
LISTEN | | | | ✔ | | WINDIVERT_EVENT_SOCKET_LISTEN |
OPEN | | | | | ✔ | WINDIVERT_EVENT_REFLECT_OPEN |
CLOSE | | | | | ✔ | WINDIVERT_EVENT_REFLECT_CLOSE |
diff --git a/examples/socketdump/socketdump.c b/examples/socketdump/socketdump.c
index 705b73a..27af548 100644
--- a/examples/socketdump/socketdump.c
+++ b/examples/socketdump/socketdump.c
@@ -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;
}
diff --git a/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c
index 8bc30a2..b6bc9f8 100644
--- a/examples/windivertctl/windivertctl.c
+++ b/examples/windivertctl/windivertctl.c
@@ -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);
diff --git a/include/windivert.h b/include/windivert.h
index ae93e81..6c5fad3 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -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.
diff --git a/include/windivert_device.h b/include/windivert_device.h
index c3312b6..1d8588d 100644
--- a/include/windivert_device.h
+++ b/include/windivert_device.h
@@ -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)
diff --git a/sys/windivert.c b/sys/windivert.c
index 09ce16b..dca3692 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -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,