From 62505689740c419bb91e83b1d08fe3be58e46d09 Mon Sep 17 00:00:00 2001
From: basil00
Date: Sun, 30 Sep 2018 09:07:16 +0800
Subject: [PATCH 01/23] Add a new FLOW layer into WinDivert.
Adds a new WINDIVERT_LAYER_FLOW layer that can:
- Track when flows are established
- Track when existing flows are deleted
---
VERSION | 2 +-
dll/windivert.c | 17 +-
dll/windivert_helper.c | 283 ++++-
doc/windivert.html | 23 +-
examples/flowtrack/flowtrack.c | 350 ++++++
examples/netdump/netdump.c | 5 +-
examples/netfilter/netfilter.c | 8 +-
examples/streamdump/streamdump.c | 66 +-
examples/webfilter/webfilter.c | 2 +-
include/windivert.h | 86 +-
include/windivert_device.h | 43 +-
mingw-build.sh | 4 +
release-build.sh | 4 +
sys/windivert.c | 1742 +++++++++++++++++++++---------
14 files changed, 1964 insertions(+), 671 deletions(-)
create mode 100644 examples/flowtrack/flowtrack.c
diff --git a/VERSION b/VERSION
index 1c99cf0..227cea2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.4.4
+2.0.0
diff --git a/dll/windivert.c b/dll/windivert.c
index 3e773c7..e593e31 100644
--- a/dll/windivert.c
+++ b/dll/windivert.c
@@ -411,11 +411,26 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
UINT32 priority32;
// Parameter checking.
- if (!WINDIVERT_FLAGS_VALID(flags) || layer > WINDIVERT_LAYER_MAX)
+ if (layer == 0)
+ {
+ layer = WINDIVERT_LAYER_NETWORK;
+ }
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ case WINDIVERT_LAYER_FLOW:
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return INVALID_HANDLE_VALUE;
+ }
+ if (!WINDIVERT_FLAGS_VALID(flags))
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
+
priority32 = WINDIVERT_PRIORITY(priority);
if (priority32 < WINDIVERT_PRIORITY_MIN ||
priority32 > WINDIVERT_PRIORITY_MAX)
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index 917c803..2b0c40a 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -116,6 +116,12 @@ typedef enum
TOKEN_SUB_IF_IDX,
TOKEN_LOOPBACK,
TOKEN_IMPOSTOR,
+ TOKEN_PROCESS_ID,
+ TOKEN_LOCAL_ADDR,
+ TOKEN_REMOTE_ADDR,
+ TOKEN_LOCAL_PORT,
+ TOKEN_REMOTE_PORT,
+ TOKEN_PROTOCOL,
TOKEN_OPEN,
TOKEN_CLOSE,
TOKEN_EQ,
@@ -504,7 +510,7 @@ extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
tcp_header->Checksum = WinDivertHelperCalcChecksum(
pseudo_header, pseudo_header_len, tcp_header, checksum_len);
}
- else if (pAddr->Direction == WINDIVERT_DIRECTION_OUTBOUND)
+ else if (pAddr->Outbound)
{
// Pseudo TCP checksum
tcp_header->Checksum = 0;
@@ -533,7 +539,7 @@ extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
udp_header->Checksum = 0xFFFF;
}
}
- else if (pAddr->Direction == WINDIVERT_DIRECTION_OUTBOUND)
+ else if (pAddr->Outbound)
{
// Pseudo UDP checksum
udp_header->Checksum = 0;
@@ -748,7 +754,7 @@ extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr)
l = k + 1;
k = (k >= 8? k - 8: k);
l = (l >= 8? l - 8: l);
- addr_ptr[i] =
+ addr_ptr[3 - i] =
(UINT32)laddr[2 * i + 1] |
(UINT32)laddr[2 * i] << 16 |
(UINT32)raddr[l] |
@@ -785,6 +791,91 @@ static PTOKEN_NAME WinDivertTokenLookup(PTOKEN_NAME token_names,
return NULL;
}
+/*
+ * Validate token for layer.
+ */
+static BOOL WinDivertCheckTokenKindForLayer(WINDIVERT_LAYER layer, KIND kind)
+{
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ switch (kind)
+ {
+ case TOKEN_INBOUND:
+ case TOKEN_OUTBOUND:
+ return (layer != WINDIVERT_LAYER_NETWORK_FORWARD);
+ case TOKEN_PROCESS_ID:
+ case TOKEN_LOCAL_ADDR:
+ case TOKEN_REMOTE_ADDR:
+ case TOKEN_LOCAL_PORT:
+ case TOKEN_REMOTE_PORT:
+ return FALSE;
+ default:
+ return TRUE;
+ }
+ case WINDIVERT_LAYER_FLOW:
+ switch (kind)
+ {
+ case TOKEN_ICMP_BODY:
+ case TOKEN_ICMP_CHECKSUM:
+ case TOKEN_ICMP_CODE:
+ case TOKEN_ICMP_TYPE:
+ case TOKEN_ICMPV6_BODY:
+ case TOKEN_ICMPV6_CHECKSUM:
+ case TOKEN_ICMPV6_CODE:
+ case TOKEN_ICMPV6_TYPE:
+ case TOKEN_IP_CHECKSUM:
+ case TOKEN_IP_DF:
+ case TOKEN_IP_DST_ADDR:
+ case TOKEN_IP_FRAG_OFF:
+ case TOKEN_IP_HDR_LENGTH:
+ case TOKEN_IP_ID:
+ case TOKEN_IP_LENGTH:
+ case TOKEN_IP_MF:
+ case TOKEN_IP_PROTOCOL:
+ case TOKEN_IP_SRC_ADDR:
+ case TOKEN_IP_TOS:
+ case TOKEN_IP_TTL:
+ case TOKEN_IPV6_DST_ADDR:
+ case TOKEN_IPV6_FLOW_LABEL:
+ case TOKEN_IPV6_HOP_LIMIT:
+ case TOKEN_IPV6_LENGTH:
+ case TOKEN_IPV6_NEXT_HDR:
+ case TOKEN_IPV6_SRC_ADDR:
+ case TOKEN_IPV6_TRAFFIC_CLASS:
+ case TOKEN_TCP_ACK:
+ case TOKEN_TCP_ACK_NUM:
+ case TOKEN_TCP_CHECKSUM:
+ case TOKEN_TCP_DST_PORT:
+ case TOKEN_TCP_FIN:
+ case TOKEN_TCP_HDR_LENGTH:
+ case TOKEN_TCP_PAYLOAD_LENGTH:
+ case TOKEN_TCP_PSH:
+ case TOKEN_TCP_RST:
+ case TOKEN_TCP_SEQ_NUM:
+ case TOKEN_TCP_SRC_PORT:
+ case TOKEN_TCP_SYN:
+ case TOKEN_TCP_URG:
+ case TOKEN_TCP_URG_PTR:
+ case TOKEN_TCP_WINDOW:
+ case TOKEN_UDP_CHECKSUM:
+ case TOKEN_UDP_DST_PORT:
+ case TOKEN_UDP_LENGTH:
+ case TOKEN_UDP_PAYLOAD_LENGTH:
+ case TOKEN_UDP_SRC_PORT:
+ case TOKEN_IF_IDX:
+ case TOKEN_SUB_IF_IDX:
+ case TOKEN_IMPOSTOR:
+ return FALSE;
+ default:
+ return TRUE;
+ }
+ default:
+ return FALSE;
+ }
+}
+
/*
* Tokenize the given filter string.
*/
@@ -829,10 +920,16 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{"ipv6.NextHdr", TOKEN_IPV6_NEXT_HDR},
{"ipv6.SrcAddr", TOKEN_IPV6_SRC_ADDR},
{"ipv6.TrafficClass", TOKEN_IPV6_TRAFFIC_CLASS},
+ {"localAddr", TOKEN_LOCAL_ADDR},
+ {"localPort", TOKEN_LOCAL_PORT},
{"loopback", TOKEN_LOOPBACK},
{"not", TOKEN_NOT},
{"or", TOKEN_OR},
{"outbound", TOKEN_OUTBOUND},
+ {"processId", TOKEN_PROCESS_ID},
+ {"protocol", TOKEN_PROTOCOL},
+ {"remoteAddr", TOKEN_REMOTE_ADDR},
+ {"remotePort", TOKEN_REMOTE_PORT},
{"subIfIdx", TOKEN_SUB_IF_IDX},
{"tcp", TOKEN_TCP},
{"tcp.Ack", TOKEN_TCP_ACK},
@@ -986,18 +1083,9 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
sizeof(token_names) / sizeof(TOKEN_NAME), token);
if (result != NULL)
{
- switch (layer)
+ if (!WinDivertCheckTokenKindForLayer(layer, result->kind))
{
- case WINDIVERT_LAYER_NETWORK_FORWARD:
- if (result->kind == TOKEN_INBOUND ||
- result->kind == TOKEN_OUTBOUND)
- {
- return MAKE_ERROR(
- WINDIVERT_ERROR_BAD_TOKEN_FOR_LAYER, i-j);
- }
- break;
- default:
- break;
+ return MAKE_ERROR(WINDIVERT_ERROR_BAD_TOKEN_FOR_LAYER, i-j);
}
tokens[tp++].kind = result->kind;
continue;
@@ -1023,6 +1111,7 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
// Check for IPv4 address:
if (WinDivertHelperParseIPv4Address(token, tokens[tp].val))
{
+ tokens[tp].val[1] = 0x0000FFFF;
tokens[tp].kind = TOKEN_NUMBER;
tp++;
continue;
@@ -1032,16 +1121,6 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
SetLastError(0);
if (WinDivertHelperParseIPv6Address(token, tokens[tp].val))
{
- // Work-around the different word orderings between the
- // DLL vs SYS.
- UINT32 tmp;
- tmp = tokens[tp].val[0];
- tokens[tp].val[0] = tokens[tp].val[3];
- tokens[tp].val[3] = tmp;
- tmp = tokens[tp].val[1];
- tokens[tp].val[1] = tokens[tp].val[2];
- tokens[tp].val[2] = tmp;
-
tokens[tp].kind = TOKEN_NUMBER;
tp++;
continue;
@@ -1140,7 +1219,13 @@ static PEXPR WinDivertMakeVar(PPOOL pool, KIND kind)
{{{0}}, TOKEN_IF_IDX},
{{{0}}, TOKEN_SUB_IF_IDX},
{{{0}}, TOKEN_LOOPBACK},
- {{{0}}, TOKEN_IMPOSTOR}
+ {{{0}}, TOKEN_IMPOSTOR},
+ {{{0}}, TOKEN_PROCESS_ID},
+ {{{0}}, TOKEN_LOCAL_ADDR},
+ {{{0}}, TOKEN_REMOTE_ADDR},
+ {{{0}}, TOKEN_LOCAL_PORT},
+ {{{0}}, TOKEN_REMOTE_PORT},
+ {{{0}}, TOKEN_PROTOCOL},
};
// Binary search:
@@ -1268,6 +1353,12 @@ static PEXPR WinDivertParseTest(PPOOL pool, TOKEN *toks, UINT *i)
case TOKEN_ICMPV6:
case TOKEN_TCP:
case TOKEN_UDP:
+ case TOKEN_PROCESS_ID:
+ case TOKEN_LOCAL_ADDR:
+ case TOKEN_REMOTE_ADDR:
+ case TOKEN_LOCAL_PORT:
+ case TOKEN_REMOTE_PORT:
+ case TOKEN_PROTOCOL:
case TOKEN_IP_HDR_LENGTH:
case TOKEN_IP_TOS:
case TOKEN_IP_LENGTH:
@@ -1524,6 +1615,7 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
case TOKEN_ICMP_CODE:
case TOKEN_ICMPV6_TYPE:
case TOKEN_ICMPV6_CODE:
+ case TOKEN_PROCESS_ID:
lb = 0; ub = 0xFF;
break;
case TOKEN_IP_FRAG_OFF:
@@ -1547,13 +1639,19 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
case TOKEN_UDP_LENGTH:
case TOKEN_UDP_CHECKSUM:
case TOKEN_UDP_PAYLOAD_LENGTH:
+ case TOKEN_LOCAL_PORT:
+ case TOKEN_REMOTE_PORT:
lb = 0; ub = 0xFFFF;
break;
case TOKEN_IPV6_FLOW_LABEL:
lb = 0; ub = 0x000FFFFF;
break;
+ case TOKEN_IP_SRC_ADDR:
+ case TOKEN_IP_DST_ADDR:
case TOKEN_IPV6_SRC_ADDR:
case TOKEN_IPV6_DST_ADDR:
+ case TOKEN_LOCAL_ADDR:
+ case TOKEN_REMOTE_ADDR:
return FALSE;
default:
lb = 0; ub = 0xFFFFFFFF;
@@ -1735,6 +1833,21 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
case TOKEN_IMPOSTOR:
object->field = WINDIVERT_FILTER_FIELD_IMPOSTOR;
break;
+ case TOKEN_PROCESS_ID:
+ object->field = WINDIVERT_FILTER_FIELD_PROCESSID;
+ break;
+ case TOKEN_LOCAL_ADDR:
+ object->field = WINDIVERT_FILTER_FIELD_LOCALADDR;
+ break;
+ case TOKEN_REMOTE_ADDR:
+ object->field = WINDIVERT_FILTER_FIELD_REMOTEADDR;
+ break;
+ case TOKEN_LOCAL_PORT:
+ object->field = WINDIVERT_FILTER_FIELD_LOCALPORT;
+ break;
+ case TOKEN_REMOTE_PORT:
+ object->field = WINDIVERT_FILTER_FIELD_REMOTEPORT;
+ break;
case TOKEN_IP:
object->field = WINDIVERT_FILTER_FIELD_IP;
break;
@@ -2118,18 +2231,17 @@ static int WinDivertBigNumCompare(const UINT32 *a, const UINT32 *b)
/*
* Evaluate the given filter with the given packet as input.
*/
-extern BOOL WinDivertHelperEvalFilter(const char *filter,
- WINDIVERT_LAYER layer, PVOID packet, UINT packet_len,
- PWINDIVERT_ADDRESS addr)
+extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
+ UINT packet_len, PWINDIVERT_ADDRESS addr)
{
UINT16 pc;
ERROR err;
- PWINDIVERT_IPHDR iphdr;
- PWINDIVERT_IPV6HDR ipv6hdr;
- PWINDIVERT_ICMPHDR icmphdr;
- PWINDIVERT_ICMPV6HDR icmpv6hdr;
- PWINDIVERT_TCPHDR tcphdr;
- PWINDIVERT_UDPHDR udphdr;
+ PWINDIVERT_IPHDR iphdr = NULL;
+ PWINDIVERT_IPV6HDR ipv6hdr = NULL;
+ PWINDIVERT_ICMPHDR icmphdr = NULL;
+ PWINDIVERT_ICMPV6HDR icmpv6hdr = NULL;
+ PWINDIVERT_TCPHDR tcphdr = NULL;
+ PWINDIVERT_UDPHDR udphdr = NULL;
UINT payload_len;
UINT32 val[4];
BOOL pass;
@@ -2137,22 +2249,48 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
struct windivert_ioctl_filter_s object[WINDIVERT_FILTER_MAXLEN];
UINT obj_len;
- if (filter == NULL || packet == NULL || addr == NULL)
+ if (filter == NULL || addr == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
+ switch (addr->Layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ if (packet == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ WinDivertHelperParsePacket(packet, packet_len, &iphdr, &ipv6hdr,
+ &icmphdr, &icmpv6hdr, &tcphdr, &udphdr, NULL, &payload_len);
+ if ((addr->IPv6 && ipv6hdr == NULL) ||
+ (!addr->IPv6 && iphdr == NULL))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ if (packet != NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
- err = WinDivertCompileFilter(filter, layer, object, &obj_len);
+ err = WinDivertCompileFilter(filter, addr->Layer, object, &obj_len);
if (IS_ERROR(err))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- WinDivertHelperParsePacket(packet, packet_len, &iphdr, &ipv6hdr, &icmphdr,
- &icmpv6hdr, &tcphdr, &udphdr, NULL, &payload_len);
-
pc = 0;
while (TRUE)
{
@@ -2232,6 +2370,23 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
pass = (udphdr != NULL);
break;
+ case WINDIVERT_FILTER_FIELD_INBOUND:
+ case WINDIVERT_FILTER_FIELD_OUTBOUND:
+ pass = (addr->Layer != WINDIVERT_LAYER_NETWORK_FORWARD);
+ break;
+ case WINDIVERT_FILTER_FIELD_IFIDX:
+ case WINDIVERT_FILTER_FIELD_SUBIFIDX:
+ pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
+ addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ break;
+ case WINDIVERT_FILTER_FIELD_PROCESSID:
+ case WINDIVERT_FILTER_FIELD_LOCALADDR:
+ case WINDIVERT_FILTER_FIELD_REMOTEADDR:
+ case WINDIVERT_FILTER_FIELD_LOCALPORT:
+ case WINDIVERT_FILTER_FIELD_REMOTEPORT:
+ case WINDIVERT_FILTER_FIELD_PROTOCOL:
+ pass = (addr->Layer == WINDIVERT_LAYER_FLOW);
+ break;
default:
pass = TRUE;
break;
@@ -2248,16 +2403,16 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
val[0] = 0;
break;
case WINDIVERT_FILTER_FIELD_INBOUND:
- val[0] = (addr->Direction == WINDIVERT_DIRECTION_INBOUND);
+ val[0] = !addr->Outbound;
break;
case WINDIVERT_FILTER_FIELD_OUTBOUND:
- val[0] = (addr->Direction == WINDIVERT_DIRECTION_OUTBOUND);
+ val[0] = addr->Outbound;
break;
case WINDIVERT_FILTER_FIELD_IFIDX:
- val[0] = addr->IfIdx;
+ val[0] = addr->Network.IfIdx;
break;
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
- val[0] = addr->SubIfIdx;
+ val[0] = addr->Network.SubIfIdx;
break;
case WINDIVERT_FILTER_FIELD_LOOPBACK:
val[0] = addr->Loopback;
@@ -2266,22 +2421,26 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
val[0] = addr->Impostor;
break;
case WINDIVERT_FILTER_FIELD_IP:
- val[0] = (iphdr != NULL);
+ val[0] = !addr->IPv6;
break;
case WINDIVERT_FILTER_FIELD_IPV6:
- val[0] = (ipv6hdr != NULL);
+ val[0] = addr->IPv6;
break;
case WINDIVERT_FILTER_FIELD_ICMP:
- val[0] = (icmphdr != NULL);
+ val[0] = (addr->Layer == WINDIVERT_LAYER_FLOW?
+ addr->Flow.Protocol == IPPROTO_ICMP: icmphdr != NULL);
break;
case WINDIVERT_FILTER_FIELD_ICMPV6:
- val[0] = (icmpv6hdr != NULL);
+ val[0] = (addr->Layer == WINDIVERT_LAYER_FLOW?
+ addr->Flow.Protocol == IPPROTO_ICMPV6: icmpv6hdr != NULL);
break;
case WINDIVERT_FILTER_FIELD_TCP:
- val[0] = (tcphdr != NULL);
+ val[0] = (addr->Layer == WINDIVERT_LAYER_FLOW?
+ addr->Flow.Protocol == IPPROTO_TCP: tcphdr != NULL);
break;
case WINDIVERT_FILTER_FIELD_UDP:
- val[0] = (udphdr != NULL);
+ val[0] = (addr->Layer == WINDIVERT_LAYER_FLOW?
+ addr->Flow.Protocol == IPPROTO_UDP: udphdr != NULL);
break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
val[0] = iphdr->HdrLength;
@@ -2314,9 +2473,11 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
val[0] = ntohs(iphdr->Checksum);
break;
case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
+ val[1] = 0x0000FFFF;
val[0] = ntohl(iphdr->SrcAddr);
break;
case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
+ val[1] = 0x0000FFFF;
val[0] = ntohl(iphdr->DstAddr);
break;
case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS:
@@ -2430,6 +2591,30 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
val[0] = payload_len;
break;
+ case WINDIVERT_FILTER_FIELD_PROCESSID:
+ val[0] = addr->Flow.ProcessId;
+ break;
+ case WINDIVERT_FILTER_FIELD_LOCALADDR:
+ val[0] = addr->Flow.LocalAddr[0];
+ val[1] = addr->Flow.LocalAddr[1];
+ val[2] = addr->Flow.LocalAddr[2];
+ val[3] = addr->Flow.LocalAddr[3];
+ break;
+ case WINDIVERT_FILTER_FIELD_REMOTEADDR:
+ val[0] = addr->Flow.RemoteAddr[0];
+ val[1] = addr->Flow.RemoteAddr[1];
+ val[2] = addr->Flow.RemoteAddr[2];
+ val[3] = addr->Flow.RemoteAddr[3];
+ break;
+ case WINDIVERT_FILTER_FIELD_LOCALPORT:
+ val[0] = addr->Flow.LocalPort;
+ break;
+ case WINDIVERT_FILTER_FIELD_REMOTEPORT:
+ val[0] = addr->Flow.RemotePort;
+ break;
+ case WINDIVERT_FILTER_FIELD_PROTOCOL:
+ val[0] = addr->Flow.Protocol;
+ break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
diff --git a/doc/windivert.html b/doc/windivert.html
index 0f7b1e0..67d36d0 100644
--- a/doc/windivert.html
+++ b/doc/windivert.html
@@ -1260,8 +1260,8 @@ Use GetLastError() to get the reason for the error.
Remarks
Parses an IPv4 address stored in addrStr.
-If non-NULL, the result is stored in pAddr
-in host-byte-order.
+If pAddr is non-NULL, the is be stored in
+host-byte-order.
Use htonl() to convert the result into network-byte-order.
@@ -1289,21 +1289,22 @@ Use GetLastError() to get the reason for the error.
Remarks
Parses an IPv6 address stored in addrStr.
-If non-NULL, the result is stored in pAddr.
-The pAddr parameter is assumed to point to a buffer large enough
-to hold a 16-byte IPv6 address.
-Given an IPv6 address of the form
+If pAddr is non-NULL, the buffer assumed
+to be large enough to hold a 16-byte IPv6 address.
+The result is stored in host-byte-order.
+For example, given an IPv6 address of the form
0011:2233:4455:6677:8899:aabb:ccdd:eeff, then
the result is ordered as follows:
-pAddr[0] = 0x00112233
-pAddr[1] = 0x44556677
-pAddr[2] = 0x8899aabb
-pAddr[3] = 0xccddeeff
+pAddr[0] = 0xccddeeff
+pAddr[1] = 0x8899aabb
+pAddr[2] = 0x44556677
+pAddr[3] = 0x00112233
where each pAddr[i] is in host-byte-order.
The result can be converted into network-byte-order by setting
-pAddr[i] = htonl(pAddr[i]) for each i.
+pAddr[i] = htonl(pAddr[i]) for each i and
+swapping the array indexes.
diff --git a/examples/flowtrack/flowtrack.c b/examples/flowtrack/flowtrack.c
new file mode 100644
index 0000000..f705cae
--- /dev/null
+++ b/examples/flowtrack/flowtrack.c
@@ -0,0 +1,350 @@
+/*
+ * streamdump.c
+ * (C) 2018, all rights reserved,
+ *
+ * This file is part of WinDivert.
+ *
+ * WinDivert is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * WinDivert is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * DESCRIPTION:
+ *
+ * usage: flowtrack.exe [filter]
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "windivert.h"
+
+#define MAX_FLOWS 256
+
+/*
+ * Flow tracking.
+ */
+typedef struct FLOW
+{
+ WINDIVERT_ADDRESS addr;
+ struct FLOW *next;
+} FLOW, *PFLOW;
+
+static HANDLE lock;
+static PFLOW flows = NULL;
+
+/*
+ * Print an IP address.
+ */
+static void print_address(const UINT32 *addr)
+{
+ if (addr[3] == 0 && addr[2] == 0 && addr[1] == 0x0000FFFF)
+ {
+ // IPv4 address:
+ UINT32 a, b, c, d;
+ a = (addr[0] >> 24) & 0xFF;
+ b = (addr[0] >> 16) & 0xFF;
+ c = (addr[0] >> 8) & 0xFF;
+ d = (addr[0] >> 0) & 0xFF;
+ printf("%u.%u.%u.%u", a, b, c, d);
+ }
+ else
+ {
+ // IPv6 address:
+ int i;
+ for (i = 3; i >= 0; i--)
+ {
+ UINT32 a, b;
+ a = (addr[i] >> 16) & 0xFFFF;
+ b = (addr[i] >> 0) & 0xFFFF;
+ printf("%x:%x", a, b);
+ if (i != 0)
+ {
+ putchar(':');
+ }
+ }
+ }
+}
+
+/*
+ * Draw flows to console in a delayed loop.
+ *
+ * This function does minimal error checking.
+ */
+static DWORD draw(LPVOID arg)
+{
+ const COORD top_left = {0, 0};
+ HANDLE process, console = GetStdHandle(STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO screen;
+ char path[MAX_PATH+1];
+ char *filename;
+ const char header[] = "PID PROGRAM PROT FLOW";
+ DWORD rows, columns, written, fill_len, path_len, i;
+ PFLOW flow;
+ WINDIVERT_ADDRESS addrs[MAX_FLOWS], *addr;
+ UINT num_addrs;
+
+ while (TRUE)
+ {
+ GetConsoleScreenBufferInfo(console, &screen);
+ SetConsoleCursorPosition(console, top_left);
+
+ rows = screen.srWindow.Bottom - screen.srWindow.Top + 1;
+ columns = screen.srWindow.Right - screen.srWindow.Left + 1;
+
+ // Copy a snapshot of the current flows:
+ WaitForSingleObject(lock, INFINITE);
+ flow = flows;
+ num_addrs = 0;
+ for (i = 0; flow != NULL && i < rows && i < MAX_FLOWS; i++)
+ {
+ memcpy(&addrs[i], &flow->addr, sizeof(addrs[i]));
+ num_addrs++;
+ flow = flow->next;
+ }
+ ReleaseMutex(lock);
+
+ // Print the flows:
+ SetConsoleTextAttribute(console, BACKGROUND_RED | BACKGROUND_GREEN |
+ BACKGROUND_BLUE);
+ WriteConsole(console, header, sizeof(header)-1, &written, NULL);
+ fill_len = columns - (sizeof(header)-1);
+ if (fill_len > 0)
+ {
+ COORD pos = {sizeof(header)-1, 0};
+ FillConsoleOutputCharacterA(console, ' ', fill_len, pos,
+ &written);
+ FillConsoleOutputAttribute(console,
+ BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
+ fill_len, pos, &written);
+ }
+ putchar('\n');
+ SetConsoleTextAttribute(console,
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ for (i = 0; i < num_addrs && i < rows-1; i++)
+ {
+ COORD pos = {0, i+1};
+ addr = &addrs[i];
+ FillConsoleOutputCharacterA(console, ' ', columns, pos, &written);
+ FillConsoleOutputAttribute(console,
+ FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE,
+ columns, pos, &written);
+ SetConsoleCursorPosition(console, pos);
+ if (i == rows-2 && (i+1) < num_addrs)
+ {
+ fputs("...", stdout);
+ fflush(stdout);
+ continue;
+ }
+
+ printf("%-10d ", addr->Flow.ProcessId);
+
+ process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
+ addr->Flow.ProcessId);
+ path_len = 0;
+ if (process != NULL)
+ {
+ path_len = GetProcessImageFileName(process, path, sizeof(path));
+ CloseHandle(process);
+ }
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
+ if (path_len != 0)
+ {
+ filename = PathFindFileName(path);
+ printf("%-20.20s ", filename);
+ }
+ else if (addr->Flow.ProcessId == 4)
+ {
+ fputs("Windows ", stdout);
+ }
+ else
+ {
+ fputs("??? ", stdout);
+ }
+ SetConsoleTextAttribute(console,
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ switch (addr->Flow.Protocol)
+ {
+ case IPPROTO_TCP:
+ SetConsoleTextAttribute(console, FOREGROUND_GREEN);
+ printf("TCP ");
+ break;
+ case IPPROTO_UDP:
+ SetConsoleTextAttribute(console,
+ FOREGROUND_RED | FOREGROUND_GREEN);
+ printf("UDP ");
+ break;
+ case IPPROTO_ICMP:
+ SetConsoleTextAttribute(console, FOREGROUND_RED);
+ printf("ICMP ");
+ break;
+ case IPPROTO_ICMPV6:
+ SetConsoleTextAttribute(console, FOREGROUND_RED);
+ printf("ICMPV6 ");
+ break;
+ default:
+ printf("%-6u ", addr->Flow.Protocol);
+ break;
+ }
+ SetConsoleTextAttribute(console,
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ print_address(addr->Flow.LocalAddr);
+ printf(":%u %s ", addr->Flow.LocalPort,
+ (addr->Outbound? "---->": "<----"));
+ print_address(addr->Flow.RemoteAddr);
+ printf(":%u", addr->Flow.RemotePort);
+ fflush(stdout);
+ }
+ for (; i < rows-1; i++)
+ {
+ COORD pos = {0, i+1};
+ FillConsoleOutputCharacterA(console, ' ', columns, pos, &written);
+ FillConsoleOutputAttribute(console,
+ FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE,
+ columns, pos, &written);
+ }
+
+ Sleep(1000);
+ }
+}
+
+/*
+ * Entry.
+ */
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE handle, thread;
+ INT16 priority = 776; // Arbitrary.
+ const char *filter = "true", *err_str;
+ UINT packet_len;
+ WINDIVERT_ADDRESS addr;
+ PFLOW flow, prev;
+
+ switch (argc)
+ {
+ case 1:
+ break;
+ case 2:
+ filter = argv[1];
+ break;
+ default:
+ fprintf(stderr, "usage: %s [filter]\n");
+ exit(EXIT_FAILURE);
+ }
+
+ // Spawn the draw() thread.
+ lock = CreateMutex(NULL, FALSE, NULL);
+ thread = CreateThread(NULL, 1, (LPTHREAD_START_ROUTINE)draw, NULL, 0,
+ NULL);
+ if (thread == NULL)
+ {
+ fprintf(stderr, "error: failed to create thread (%d)\n",
+ GetLastError());
+ return EXIT_FAILURE;
+ }
+ CloseHandle(thread);
+
+ // Open WinDivert FLOW handle:
+ handle = WinDivertOpen(filter, WINDIVERT_LAYER_FLOW, priority,
+ WINDIVERT_FLAGS_LAYER_FLOW);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ if (GetLastError() == ERROR_INVALID_PARAMETER &&
+ !WinDivertHelperCheckFilter(filter, WINDIVERT_LAYER_FLOW,
+ &err_str, NULL))
+ {
+ fprintf(stderr, "error: invalid filter \"%s\"\n", err_str);
+ exit(EXIT_FAILURE);
+ }
+ fprintf(stderr, "error: failed to open the WinDivert device (%d)\n",
+ GetLastError());
+ return EXIT_FAILURE;
+ }
+
+ // Main loop:
+ while (TRUE)
+ {
+ if (!WinDivertRecv(handle, NULL, 0, &addr, &packet_len))
+ {
+ fprintf(stderr, "failed to read packet (%d)\n", GetLastError());
+ continue;
+ }
+
+ switch (addr.Event)
+ {
+ case WINDIVERT_EVENT_FLOW_ESTABLISHED:
+
+ // Flow established:
+ flow = (PFLOW)malloc(sizeof(FLOW));
+ if (flow == NULL)
+ {
+ fprintf(stderr, "error: failed to allocate memory\n");
+ exit(EXIT_FAILURE);
+ }
+ memcpy(&flow->addr, &addr, sizeof(flow->addr));
+ WaitForSingleObject(lock, INFINITE);
+ flow->next = flows;
+ flows = flow;
+ ReleaseMutex(lock);
+ break;
+
+ case WINDIVERT_EVENT_FLOW_DELETED:
+
+ // Flow deleted:
+ prev = NULL;
+ WaitForSingleObject(lock, INFINITE);
+ flow = flows;
+ while (flow != NULL)
+ {
+ if (memcmp(&addr.Flow, &flow->addr.Flow,
+ sizeof(addr.Flow)) == 0)
+ {
+ if (prev != NULL)
+ {
+ prev->next = flow->next;
+ }
+ else
+ {
+ flows = flow->next;
+ }
+ break;
+ }
+ prev = flow;
+ flow = flow->next;
+ }
+ ReleaseMutex(lock);
+ free(flow);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/examples/netdump/netdump.c b/examples/netdump/netdump.c
index 6c51848..ee1f46d 100644
--- a/examples/netdump/netdump.c
+++ b/examples/netdump/netdump.c
@@ -156,9 +156,8 @@ int __cdecl main(int argc, char **argv)
(double)freq.QuadPart;
printf("Packet [Timestamp=%.8g, Direction=%s IfIdx=%u SubIfIdx=%u "
"Loopback=%u]\n",
- time_passed, (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND?
- "outbound": "inbound"), addr.IfIdx, addr.SubIfIdx,
- addr.Loopback);
+ time_passed, (addr.Outbound? "outbound": "inbound"),
+ addr.Network.IfIdx, addr.Network.SubIfIdx, addr.Loopback);
if (ip_header != NULL)
{
UINT8 *src_addr = (UINT8 *)&ip_header->SrcAddr;
diff --git a/examples/netfilter/netfilter.c b/examples/netfilter/netfilter.c
index 0e990ba..b8e3fc1 100644
--- a/examples/netfilter/netfilter.c
+++ b/examples/netfilter/netfilter.c
@@ -287,7 +287,7 @@ int __cdecl main(int argc, char **argv)
htonl(ntohl(tcp_header->SeqNum) + payload_len));
memcpy(&send_addr, &recv_addr, sizeof(send_addr));
- send_addr.Direction = !recv_addr.Direction;
+ send_addr.Outbound = !recv_addr.Outbound;
WinDivertHelperCalcChecksums((PVOID)reset, sizeof(TCPPACKET),
&send_addr, 0);
if (!WinDivertSend(handle, (PVOID)reset, sizeof(TCPPACKET),
@@ -314,7 +314,7 @@ int __cdecl main(int argc, char **argv)
htonl(ntohl(tcp_header->SeqNum) + payload_len));
memcpy(&send_addr, &recv_addr, sizeof(send_addr));
- send_addr.Direction = !recv_addr.Direction;
+ send_addr.Outbound = !recv_addr.Outbound;
WinDivertHelperCalcChecksums((PVOID)resetv6,
sizeof(TCPV6PACKET), &send_addr, 0);
if (!WinDivertSend(handle, (PVOID)resetv6, sizeof(TCPV6PACKET),
@@ -340,7 +340,7 @@ int __cdecl main(int argc, char **argv)
dnr->ip.DstAddr = ip_header->SrcAddr;
memcpy(&send_addr, &recv_addr, sizeof(send_addr));
- send_addr.Direction = !recv_addr.Direction;
+ send_addr.Outbound = !recv_addr.Outbound;
WinDivertHelperCalcChecksums((PVOID)dnr, icmp_length,
&send_addr, 0);
if (!WinDivertSend(handle, (PVOID)dnr, icmp_length, &send_addr,
@@ -363,7 +363,7 @@ int __cdecl main(int argc, char **argv)
sizeof(dnrv6->ipv6.DstAddr));
memcpy(&send_addr, &recv_addr, sizeof(send_addr));
- send_addr.Direction = !recv_addr.Direction;
+ send_addr.Outbound = !recv_addr.Outbound;
WinDivertHelperCalcChecksums((PVOID)dnrv6, icmpv6_length,
&send_addr, 0);
if (!WinDivertSend(handle, (PVOID)dnrv6, icmpv6_length,
diff --git a/examples/streamdump/streamdump.c b/examples/streamdump/streamdump.c
index c8c9164..48315fa 100644
--- a/examples/streamdump/streamdump.c
+++ b/examples/streamdump/streamdump.c
@@ -257,41 +257,39 @@ read_failed:
continue;
}
- switch (addr.Direction)
+ if (addr.Outbound)
{
- case WINDIVERT_DIRECTION_OUTBOUND:
- if (tcp_header->DstPort == htons(port))
- {
- // Reflect: PORT ---> PROXY
- UINT32 dst_addr = ip_header->DstAddr;
- tcp_header->DstPort = htons(proxy_port);
- ip_header->DstAddr = ip_header->SrcAddr;
- ip_header->SrcAddr = dst_addr;
- addr.Direction = WINDIVERT_DIRECTION_INBOUND;
- }
- else if (tcp_header->SrcPort == htons(proxy_port))
- {
- // Reflect: PROXY ---> PORT
- UINT32 dst_addr = ip_header->DstAddr;
- tcp_header->SrcPort = htons(port);
- ip_header->DstAddr = ip_header->SrcAddr;
- ip_header->SrcAddr = dst_addr;
- addr.Direction = WINDIVERT_DIRECTION_INBOUND;
- }
- else if (tcp_header->DstPort == htons(alt_port))
- {
- // Redirect: ALT ---> PORT
- tcp_header->DstPort = htons(port);
- }
- break;
-
- case WINDIVERT_DIRECTION_INBOUND:
- if (tcp_header->SrcPort == htons(port))
- {
- // Redirect: PORT ---> ALT
- tcp_header->SrcPort = htons(alt_port);
- }
- break;
+ if (tcp_header->DstPort == htons(port))
+ {
+ // Reflect: PORT ---> PROXY
+ UINT32 dst_addr = ip_header->DstAddr;
+ tcp_header->DstPort = htons(proxy_port);
+ ip_header->DstAddr = ip_header->SrcAddr;
+ ip_header->SrcAddr = dst_addr;
+ addr.Outbound = FALSE;
+ }
+ else if (tcp_header->SrcPort == htons(proxy_port))
+ {
+ // Reflect: PROXY ---> PORT
+ UINT32 dst_addr = ip_header->DstAddr;
+ tcp_header->SrcPort = htons(port);
+ ip_header->DstAddr = ip_header->SrcAddr;
+ ip_header->SrcAddr = dst_addr;
+ addr.Outbound = FALSE;
+ }
+ else if (tcp_header->DstPort == htons(alt_port))
+ {
+ // Redirect: ALT ---> PORT
+ tcp_header->DstPort = htons(port);
+ }
+ }
+ else
+ {
+ if (tcp_header->SrcPort == htons(port))
+ {
+ // Redirect: PORT ---> ALT
+ tcp_header->SrcPort = htons(alt_port);
+ }
}
WinDivertHelperCalcChecksums(packet, packet_len, &addr, 0);
diff --git a/examples/webfilter/webfilter.c b/examples/webfilter/webfilter.c
index 2f04b00..860970b 100644
--- a/examples/webfilter/webfilter.c
+++ b/examples/webfilter/webfilter.c
@@ -238,7 +238,7 @@ int __cdecl main(int argc, char **argv)
blockpage->header.tcp.SeqNum = tcp_header->AckNum;
blockpage->header.tcp.AckNum =
htonl(ntohl(tcp_header->SeqNum) + payload_len);
- addr.Direction = !addr.Direction; // Reverse direction.
+ addr.Outbound = !addr.Outbound; // Reverse direction.
WinDivertHelperCalcChecksums((PVOID)blockpage, blockpage_len, &addr, 0);
if (!WinDivertSend(handle, (PVOID)blockpage, blockpage_len, &addr,
NULL))
diff --git a/include/windivert.h b/include/windivert.h
index 6f344fa..49029f2 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -70,43 +70,90 @@ extern "C" {
/****************************************************************************/
/*
- * Divert address.
+ * WinDivert NETWORK and NETWORK_FORWARD layer data.
+ */
+typedef struct
+{
+ UINT32 IfIdx; /* Packet's interface index. */
+ UINT32 SubIfIdx; /* Packet's sub-interface index. */
+} WINDIVERT_NETWORK_DATA, *PWINDIVERT_NETWORK_DATA;
+
+/*
+ * WinDivert FLOW layer data.
+ */
+typedef struct
+{
+ UINT32 ProcessId; /* Process ID. */
+ UINT32 LocalAddr[4]; /* Local address. */
+ UINT32 RemoteAddr[4]; /* Remote address. */
+ UINT16 LocalPort; /* Local port. */
+ UINT16 RemotePort; /* Remote port. */
+ UINT8 Protocol; /* Protocol. */
+} WINDIVERT_FLOW_DATA, *PWINDIVERT_FLOW_DATA;
+
+/*
+ * WinDivert address.
*/
typedef struct
{
INT64 Timestamp; /* Packet's timestamp. */
- UINT32 IfIdx; /* Packet's interface index. */
- UINT32 SubIfIdx; /* Packet's sub-interface index. */
- UINT8 Direction:1; /* Packet's direction. */
- UINT8 Loopback:1; /* Packet is loopback? */
- UINT8 Impostor:1; /* Packet is impostor? */
- UINT8 PseudoIPChecksum:1; /* Packet has pseudo IPv4 checksum? */
- UINT8 PseudoTCPChecksum:1; /* Packet has pseudo TCP checksum? */
- UINT8 PseudoUDPChecksum:1; /* Packet has pseudo UDP checksum? */
- UINT8 Reserved:2;
+ UINT32 Layer:8; /* Packet's layer. */
+ UINT32 Event:8; /* Packet event. */
+ UINT32 Outbound:1; /* Packet is outound? */
+ UINT32 Loopback:1; /* Packet is loopback? */
+ UINT32 Impostor:1; /* Packet is impostor? */
+ UINT32 IPv6:1; /* Packet is IPv6? */
+ UINT32 PseudoIPChecksum:1; /* Packet has pseudo IPv4 checksum? */
+ UINT32 PseudoTCPChecksum:1; /* Packet has pseudo TCP checksum? */
+ UINT32 PseudoUDPChecksum:1; /* Packet has pseudo UDP checksum? */
+ UINT32 Reserved:9;
+ union
+ {
+ WINDIVERT_NETWORK_DATA Network; /* Network layer data. */
+ WINDIVERT_FLOW_DATA Flow; /* Flow layer data. */
+ };
} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
-#define WINDIVERT_DIRECTION_OUTBOUND 0
-#define WINDIVERT_DIRECTION_INBOUND 1
-
/*
- * Divert layers.
+ * WinDivert layers.
*/
typedef enum
{
- WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */
- WINDIVERT_LAYER_NETWORK_FORWARD = 1 /* Network layer (forwarded packets) */
+ WINDIVERT_LAYER_NETWORK = 1, /* Network layer. */
+ WINDIVERT_LAYER_NETWORK_FORWARD = 2,/* Network layer (forwarded packets) */
+ WINDIVERT_LAYER_FLOW = 3 /* Flow layer. */
} WINDIVERT_LAYER, *PWINDIVERT_LAYER;
/*
- * Divert flags.
+ * WinDivert events.
+ */
+typedef enum
+{
+ WINDIVERT_EVENT_NETWORK_PACKET = 0, /* Network packet. */
+ WINDIVERT_EVENT_FLOW_ESTABLISHED = 1,
+ /* Flow established. */
+ WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */
+} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
+
+/*
+ * WinDivert flags.
*/
#define WINDIVERT_FLAG_SNIFF 1
#define WINDIVERT_FLAG_DROP 2
-#define WINDIVERT_FLAG_DEBUG 4
+#define WINDIVERT_FLAG_RECV_ONLY 4
+#define WINDIVERT_FLAG_READ_ONLY WINDIVERT_FLAG_RECV_ONLY
+#define WINDIVERT_FLAG_SEND_ONLY 8
+#define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY
+#define WINDIVERT_FLAG_DEBUG 16
+
+#define WINDIVERT_FLAGS_LAYER_NETWORK 0
+#define WINDIVERT_FLAGS_LAYER_NETWORK_FORWARD \
+ 0
+#define WINDIVERT_FLAGS_LAYER_FLOW \
+ (WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_RECV_ONLY)
/*
- * Divert parameters.
+ * WinDivert parameters.
*/
typedef enum
{
@@ -396,7 +443,6 @@ extern WINDIVERTEXPORT BOOL WinDivertHelperCheckFilter(
*/
extern WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter(
__in const char *filter,
- __in WINDIVERT_LAYER layer,
__in PVOID pPacket,
__in UINT packetLen,
__in PWINDIVERT_ADDRESS pAddr);
diff --git a/include/windivert_device.h b/include/windivert_device.h
index 0036461..73cc45f 100644
--- a/include/windivert_device.h
+++ b/include/windivert_device.h
@@ -44,8 +44,8 @@
#define WINDIVERT_KERNEL
#include "windivert.h"
-#define WINDIVERT_VERSION 1
-#define WINDIVERT_VERSION_MINOR 4
+#define WINDIVERT_VERSION 2
+#define WINDIVERT_VERSION_MINOR 0
#define WINDIVERT_STR2(s) #s
#define WINDIVERT_STR(s) WINDIVERT_STR2(s)
@@ -59,8 +59,8 @@
#define WINDIVERT_DEVICE_NAME \
L"WinDivert" WINDIVERT_VERSION_LSTR
-#define WINDIVERT_IOCTL_VERSION 6
-#define WINDIVERT_IOCTL_MAGIC 0xA2BF
+#define WINDIVERT_IOCTL_VERSION 7
+#define WINDIVERT_IOCTL_MAGIC 0xC7C9
#define WINDIVERT_FILTER_FIELD_ZERO 0
#define WINDIVERT_FILTER_FIELD_INBOUND 1
@@ -122,8 +122,14 @@
#define WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH 57
#define WINDIVERT_FILTER_FIELD_LOOPBACK 58
#define WINDIVERT_FILTER_FIELD_IMPOSTOR 59
+#define WINDIVERT_FILTER_FIELD_PROCESSID 60
+#define WINDIVERT_FILTER_FIELD_LOCALADDR 61
+#define WINDIVERT_FILTER_FIELD_REMOTEADDR 62
+#define WINDIVERT_FILTER_FIELD_LOCALPORT 63
+#define WINDIVERT_FILTER_FIELD_REMOTEPORT 64
+#define WINDIVERT_FILTER_FIELD_PROTOCOL 65
#define WINDIVERT_FILTER_FIELD_MAX \
- WINDIVERT_FILTER_FIELD_IMPOSTOR
+ WINDIVERT_FILTER_FIELD_PROTOCOL
#define WINDIVERT_FILTER_TEST_EQ 0
#define WINDIVERT_FILTER_TEST_NEQ 1
@@ -142,20 +148,21 @@
* WinDivert layers.
*/
#define WINDIVERT_LAYER_DEFAULT WINDIVERT_LAYER_NETWORK
-#define WINDIVERT_LAYER_MAX \
- WINDIVERT_LAYER_NETWORK_FORWARD
/*
* WinDivert flags.
*/
#define WINDIVERT_FLAGS_ALL \
- (WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP | WINDIVERT_FLAG_DEBUG)
+ (WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP | WINDIVERT_FLAG_RECV_ONLY |\
+ WINDIVERT_FLAG_SEND_ONLY | WINDIVERT_FLAG_DEBUG)
#define WINDIVERT_FLAGS_EXCLUDE(flags, flag1, flag2) \
(((flags) & ((flag1) | (flag2))) != ((flag1) | (flag2)))
#define WINDIVERT_FLAGS_VALID(flags) \
((((flags) & ~WINDIVERT_FLAGS_ALL) == 0) && \
WINDIVERT_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_SNIFF, \
- WINDIVERT_FLAG_DROP))
+ WINDIVERT_FLAG_DROP) && \
+ WINDIVERT_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_RECV_ONLY, \
+ WINDIVERT_FLAG_SEND_ONLY))
/*
* WinDivert priorities.
@@ -197,7 +204,7 @@ typedef struct windivert_ioctl_s *windivert_ioctl_t;
*/
struct windivert_ioctl_filter_s
{
- UINT8 field; // WINDIVERT_FILTER_FIELD_IP_*
+ UINT8 field; // WINDIVERT_FILTER_FIELD_*
UINT8 test; // WINDIVERT_FILTER_TEST_*
UINT16 success; // Success continuation.
UINT16 failure; // Fail continuation.
@@ -210,20 +217,20 @@ typedef struct windivert_ioctl_filter_s *windivert_ioctl_filter_t;
* IOCTL codes.
*/
#define IOCTL_WINDIVERT_RECV \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x908, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x918, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_WINDIVERT_SEND \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x909, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x919, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_WINDIVERT_START_FILTER \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x90A, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x91A, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_WINDIVERT_SET_LAYER \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x90B, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x91B, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_WINDIVERT_SET_PRIORITY \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x90C, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x91C, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_WINDIVERT_SET_FLAGS \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x90D, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x91D, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_WINDIVERT_SET_PARAM \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x90E, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x91E, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_WINDIVERT_GET_PARAM \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x90F, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x91F, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#endif /* __WINDIVERT_DEVICE_H */
diff --git a/mingw-build.sh b/mingw-build.sh
index 1fcbee4..74ca900 100644
--- a/mingw-build.sh
+++ b/mingw-build.sh
@@ -97,6 +97,10 @@ do
$CC -s -O2 -Iinclude/ examples/streamdump/streamdump.c \
-o "install/MINGW/$CPU/streamdump.exe" -lWinDivert -lws2_32 \
-L"install/MINGW/$CPU/"
+ echo "\tcopy install/MINGW/$CPU/flowtrack.exe..."
+ $CC -s -O2 -Iinclude/ examples/flowtrack/flowtrack.c \
+ -o "install/MINGW/$CPU/flowtrack.exe" -lWinDivert -lws2_32 -lpsapi \
+ -lshlwapi -L"install/MINGW/$CPU/"
echo "\tcopy install/MINGW/$CPU/WinDivert$BITS.sys..."
cp install/WDDK/$CPU/WinDivert$BITS.sys install/MINGW/$CPU
else
diff --git a/release-build.sh b/release-build.sh
index 80cd0fe..21a7750 100644
--- a/release-build.sh
+++ b/release-build.sh
@@ -90,6 +90,8 @@ do
cp install/$TARGET/i386/webfilter.exe $INSTALL/x86
echo "\tcopy $INSTALL/x86/streamdump.exe..."
cp install/$TARGET/i386/streamdump.exe $INSTALL/x86
+ echo "\tcopy $INSTALL/i386/flowtrack.exe..."
+ cp install/$TARGET/i386/flowtrack.exe $INSTALL/amd64
if [ -d "install/$TARGET/amd64" ]
then
echo "\tmake $INSTALL/amd64..."
@@ -115,6 +117,8 @@ do
cp install/$TARGET/amd64/webfilter.exe $INSTALL/amd64
echo "\tcopy $INSTALL/amd64/streamdump.exe..."
cp install/$TARGET/amd64/streamdump.exe $INSTALL/amd64
+ echo "\tcopy $INSTALL/amd64/flowtrack.exe..."
+ cp install/$TARGET/amd64/flowtrack.exe $INSTALL/amd64
else
echo "\tWARNING: skipping missing AMD64 build..."
fi
diff --git a/sys/windivert.c b/sys/windivert.c
index 2ab6476..9d4bcc2 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -59,7 +59,7 @@ EVT_WDF_WORKITEM windivert_worker;
/*
* Debugging macros.
*/
-// #define DEBUG_ON
+#define DEBUG_ON
#define DEBUG_BUFSIZE 256
#ifdef DEBUG_ON
@@ -116,6 +116,8 @@ typedef struct filter_s *filter_t;
#define WINDIVERT_FILTER_PROTOCOL_ICMPV6 4
#define WINDIVERT_FILTER_PROTOCOL_TCP 5
#define WINDIVERT_FILTER_PROTOCOL_UDP 6
+#define WINDIVERT_FILTER_PROTOCOL_NETWORK 7
+#define WINDIVERT_FILTER_PROTOCOL_FLOW 8
/*
* WinDivert context information.
@@ -123,10 +125,6 @@ typedef struct filter_s *filter_t;
#define WINDIVERT_CONTEXT_SIZE (sizeof(struct context_s))
#define WINDIVERT_CONTEXT_MAXLAYERS 4
#define WINDIVERT_CONTEXT_MAXWORKERS 1
-#define WINDIVERT_CONTEXT_OUTBOUND_IPV4_LAYER 0
-#define WINDIVERT_CONTEXT_INBOUND_IPV4_LAYER 1
-#define WINDIVERT_CONTEXT_OUTBOUND_IPV6_LAYER 2
-#define WINDIVERT_CONTEXT_INBOUND_IPV6_LAYER 3
typedef enum
{
WINDIVERT_CONTEXT_STATE_OPENING = 0xA0, // Context is opening.
@@ -141,6 +139,9 @@ struct context_s
KSPIN_LOCK lock; // Context-wide lock.
WDFDEVICE device; // Context's device.
WDFFILEOBJECT object; // Context's parent object.
+ LIST_ENTRY flow_set; // All active flows.
+ UINT32 flow_v4_callout_id; // Flow established callout id.
+ UINT32 flow_v6_callout_id; // Flow established callout id.
LIST_ENTRY work_queue; // Work queue.
ULONG work_queue_length; // Work queue length.
LIST_ENTRY packet_queue; // Packet queue.
@@ -161,9 +162,7 @@ struct context_s
// Callout GUIDs.
GUID filter_guid[WINDIVERT_CONTEXT_MAXLAYERS];
// Filter GUIDs.
- BOOL installed[WINDIVERT_CONTEXT_MAXLAYERS];
- // What is installed?
- BOOL on; // Is filtering on?
+ BOOL installed[WINDIVERT_CONTEXT_MAXLAYERS];// What is installed?
HANDLE engine_handle; // WFP engine handle.
filter_t filter; // Packet filter.
};
@@ -178,11 +177,13 @@ WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(context_s, windivert_context_get);
/*
* WinDivert Layer information.
*/
-typedef void (*windivert_callout_t)(
+typedef void (*windivert_classify_t)(
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);
+typedef void (*windivert_flow_delete_notify_t)(
+ IN UINT16 layer_id, IN UINT32 callout_id, IN UINT64 flow_context);
struct layer_s
{
wchar_t *sublayer_name; // Sub-layer name.
@@ -193,7 +194,10 @@ struct layer_s
wchar_t *filter_desc; // Filter description.
GUID layer_guid; // WFP layer GUID.
GUID sublayer_guid; // Sub-layer GUID.
- windivert_callout_t callout; // Call-out.
+ windivert_classify_t classify; // Classify function.
+ windivert_flow_delete_notify_t flow_delete;
+ // Flow delete function.
+ UINT16 sublayer_weight; // Sub-layer weight.
};
typedef struct layer_s *layer_t;
@@ -209,29 +213,72 @@ typedef struct req_context_s *req_context_t;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(req_context_s, windivert_req_context_get);
/*
- * WinDivert packet structure.
+ * WinDivert packet structure. Layout is as follows:
+ *
+ * +-----------------+------------+-------------+
+ * | struct packet_s | layer data | packet data |
+ * +-----------------+------------+-------------+
+ *
+ * Note the packet data must be pointer-aligned.
*/
-#define WINDIVERT_WORK_QUEUE_LEN_MAX 2048
+#define WINDIVERT_WORK_QUEUE_LEN_MAX 4096
+#ifdef _WIN64
+#define WINDIVERT_ALIGN_SIZE 8
+#define WINDIVERT_DATA_ALIGN __declspec(align(8))
+#else
+#define WINDIVERT_ALIGN_SIZE 4
+#define WINDIVERT_DATA_ALIGN __declspec(align(4))
+#endif
struct packet_s
{
LIST_ENTRY entry; // Entry for queue.
- UINT8 direction; // Packet direction.
- BOOL is_ipv4:1; // Is IPv4?
- BOOL forward:1; // Is forward?
- BOOL impostor:1; // Is Impostor?
- BOOL loopback:1; // Is loopback?
- BOOL match:1; // Matches filter?
- UINT32 if_idx; // Interface index.
- UINT32 sub_if_idx; // Sub-interface index.
- UINT32 priority; // Packet priority.
LONGLONG timestamp; // Packet timestamp.
- NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksums;
- // Checksum information.
- size_t data_len; // Length of `data'.
- char *data; // Packet data.
+ UINT32 layer:8; // Layer.
+ UINT32 event:8; // Event.
+ UINT32 outbound:1; // Packet is outound?
+ UINT32 loopback:1; // Packet is loopback?
+ UINT32 impostor:1; // Packet is impostor?
+ UINT32 ipv6:1; // Packet is IPv6?
+ UINT32 pseudo_ip_checksum:1; // Packet has pseudo IPv4 check?
+ UINT32 pseudo_tcp_checksum:1; // Packet has pseudo TCP check?
+ UINT32 pseudo_udp_checksum:1; // Packet has pseudo UDP check?
+ UINT32 match:1; // Packet matches filter?
+ UINT32 priority; // Packet priority.
+ UINT32 packet_len; // Length of the packet.
+ WINDIVERT_DATA_ALIGN UINT8 data[]; // Packet/layer data.
};
typedef struct packet_s *packet_t;
+#define WINDIVERT_DATA_SIZE(size) \
+ ((((size) + WINDIVERT_ALIGN_SIZE - 1) / WINDIVERT_ALIGN_SIZE) * \
+ WINDIVERT_ALIGN_SIZE)
+#define WINDIVERT_PACKET_SIZE(layer_type, packet_len) \
+ (sizeof(struct packet_s) + WINDIVERT_DATA_SIZE(sizeof(layer_type)) + \
+ (packet_len))
+#define WINDIVERT_LAYER_DATA_PTR(packet) \
+ ((packet)->data)
+#define WINDIVERT_PACKET_DATA_PTR(layer_type, packet) \
+ ((packet)->data + WINDIVERT_DATA_SIZE(sizeof(layer_type)))
+
+/*
+ * WinDivert flow structure.
+ */
+struct flow_s
+{
+ LIST_ENTRY entry; // Entry for tracking.
+ context_t context; // Context.
+ UINT64 flow_id; // WFP flow ID.
+ UINT32 callout_id; // WFP callout ID.
+ UINT16 layer_id; // WFP layout ID.
+ BOOL inserted:1; // Flow inserted into context?
+ BOOL deleted:1; // Flow deleted from context?
+ BOOL outbound:1; // Flow is outound?
+ BOOL loopback:1; // Flow is loopback?
+ BOOL ipv6:1; // Flow is ipv6?
+ WINDIVERT_FLOW_DATA data; // Flow data.
+};
+typedef struct flow_s *flow_t;
+
/*
* IPv4/IPv6 pseudo headers.
*/
@@ -300,9 +347,9 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
IN WDFFILEOBJECT object);
static NTSTATUS windivert_install_sublayer(layer_t layer);
static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
- BOOL is_inbound, BOOL is_outbound, BOOL is_ipv4, BOOL is_ipv6);
+ BOOL inbound, BOOL outbound, BOOL ipv4, BOOL ipv6);
static NTSTATUS windivert_install_callout(context_t context, UINT idx,
- layer_t layer);
+ layer_t layer, UINT32 *callout_id_ptr);
static void windivert_uninstall_callouts(context_t context,
context_state_t state);
extern VOID windivert_cleanup(IN WDFFILEOBJECT object);
@@ -312,60 +359,77 @@ extern NTSTATUS windivert_write(context_t context, WDFREQUEST request,
PWINDIVERT_ADDRESS addr);
extern void NTAPI windivert_inject_complete(VOID *context,
NET_BUFFER_LIST *packets, BOOLEAN dispatch_level);
-static NTSTATUS windivert_notify_callout(IN FWPS_CALLOUT_NOTIFY_TYPE type,
+extern void NTAPI windivert_reinject_complete(VOID *context,
+ NET_BUFFER_LIST *packets, BOOLEAN dispatch_level);
+static NTSTATUS windivert_notify(IN FWPS_CALLOUT_NOTIFY_TYPE type,
IN const GUID *filter_key, IN const FWPS_FILTER0 *filter);
-static void windivert_classify_outbound_network_v4_callout(
+static void windivert_outbound_network_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_classify_inbound_network_v4_callout(
+static void windivert_inbound_network_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_classify_outbound_network_v6_callout(
+static void windivert_outbound_network_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_classify_inbound_network_v6_callout(
+static void windivert_inbound_network_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_classify_forward_network_v4_callout(
+static void windivert_forward_network_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_classify_forward_network_v6_callout(
+static void windivert_forward_network_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_classify_callout(context_t context, IN UINT8 direction,
- IN UINT32 if_idx, IN UINT32 sub_if_idx, IN BOOL is_ipv4,
+static void windivert_flow_established_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_flow_established_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_flow_established_classify(context_t context,
+ IN UINT64 flow_id, IN PWINDIVERT_FLOW_DATA flow_data, IN BOOL ipv4,
+ IN BOOL outbound, IN BOOL loopback, OUT FWPS_CLASSIFY_OUT0 *result);
+static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
+ UINT64 flow_context);
+static void windivert_network_classify(context_t context,
+ IN PWINDIVERT_NETWORK_DATA network_data, IN BOOL ipv4, IN BOOL outbound,
IN BOOL loopback, IN UINT advance, IN OUT void *data,
- IN UINT64 flow_context, OUT FWPS_CLASSIFY_OUT0 *result);
-static BOOL windivert_queue_work(context_t context, BOOL sniff_mode,
- BOOL drop_mode, PNET_BUFFER_LIST buffers, PNET_BUFFER buffer,
- UINT8 direction, UINT32 if_idx, UINT32 sub_if_idx, BOOL is_ipv4,
- BOOL forward, BOOL impostor, BOOL loopback, BOOL match, UINT32 priority,
+ OUT FWPS_CLASSIFY_OUT0 *result);
+static BOOL windivert_queue_work(context_t context, PNET_BUFFER buffer,
+ PNET_BUFFER_LIST buffers, PWINDIVERT_NETWORK_DATA network_data,
+ PWINDIVERT_FLOW_DATA flow_data, WINDIVERT_LAYER layer,
+ WINDIVERT_EVENT event, UINT64 flags, UINT32 priority, BOOL ipv4,
+ BOOL outbound, BOOL loopback, BOOL impostor, BOOL match,
LONGLONG timestamp);
static void windivert_queue_packet(context_t context, packet_t packet);
static void windivert_reinject_packet(packet_t packet);
static void windivert_free_packet(packet_t packet);
-static BOOL windivert_decrement_ttl(PVOID data, BOOL is_ipv4, BOOL checksum);
-static UINT8 windivert_skip_headers(UINT8 proto, UINT8 **header, size_t *len);
+static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4, BOOL checksum);
static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b);
-static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
- UINT32 sub_if_idx, BOOL outbound, BOOL is_ipv4, BOOL impostor,
- BOOL loopback, filter_t filter);
+static BOOL windivert_filter(PNET_BUFFER buffer,
+ PWINDIVERT_NETWORK_DATA network_data, PWINDIVERT_FLOW_DATA flow_data,
+ BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, filter_t filter);
static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
size_t ioctl_filter_len);
-static void windivert_filter_analyze(filter_t filter, BOOL *is_inbound,
- BOOL *is_outbound, BOOL *ip_ipv4, BOOL *is_ipv6);
+static void windivert_filter_analyze(filter_t filter, UINT64 flags,
+ BOOL *inbound, BOOL *outbound, BOOL *ipv4, BOOL *ipv6);
static BOOL windivert_filter_test(filter_t filter, UINT16 ip, UINT8 protocol,
UINT8 field, UINT32 arg);
@@ -390,6 +454,12 @@ DEFINE_GUID(WINDIVERT_SUBLAYER_FORWARD_IPV4_GUID,
DEFINE_GUID(WINDIVERT_SUBLAYER_FORWARD_IPV6_GUID,
0xE70D0973, 0x935F, 0x4790,
0x8E, 0x64, 0xF7, 0xF7, 0x36, 0x27, 0xA5, 0x8F);
+DEFINE_GUID(WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV4_GUID,
+ 0x168A6CF7, 0x6080, 0x4905,
+ 0xAA, 0x72, 0x03, 0x74, 0x67, 0xCD, 0x4F, 0x19);
+DEFINE_GUID(WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV6_GUID,
+ 0x9EAAEB28, 0xC1BB, 0x41F5,
+ 0x9F, 0x27, 0x18, 0xD4, 0xDF, 0xE1, 0x31, 0xEE);
/*
* WinDivert supported layers.
@@ -404,7 +474,9 @@ static struct layer_s layer_inbound_network_ipv4_0 =
L"" WINDIVERT_DEVICE_NAME L" filter network (inbound IPv4)",
{0},
{0},
- windivert_classify_inbound_network_v4_callout,
+ windivert_inbound_network_v4_classify,
+ NULL,
+ UINT16_MAX
};
static layer_t layer_inbound_network_ipv4 = &layer_inbound_network_ipv4_0;
@@ -418,7 +490,9 @@ static struct layer_s layer_outbound_network_ipv4_0 =
L"" WINDIVERT_DEVICE_NAME L" filter network (outbound IPv4)",
{0},
{0},
- windivert_classify_outbound_network_v4_callout,
+ windivert_outbound_network_v4_classify,
+ NULL,
+ UINT16_MAX
};
static layer_t layer_outbound_network_ipv4 = &layer_outbound_network_ipv4_0;
@@ -432,7 +506,9 @@ static struct layer_s layer_inbound_network_ipv6_0 =
L"" WINDIVERT_DEVICE_NAME L" filter network (inbound IPv6)",
{0},
{0},
- windivert_classify_inbound_network_v6_callout,
+ windivert_inbound_network_v6_classify,
+ NULL,
+ UINT16_MAX
};
static layer_t layer_inbound_network_ipv6 = &layer_inbound_network_ipv6_0;
@@ -446,7 +522,9 @@ static struct layer_s layer_outbound_network_ipv6_0 =
L"" WINDIVERT_DEVICE_NAME L" filter network (outbound IPv6)",
{0},
{0},
- windivert_classify_outbound_network_v6_callout,
+ windivert_outbound_network_v6_classify,
+ NULL,
+ UINT16_MAX
};
static layer_t layer_outbound_network_ipv6 = &layer_outbound_network_ipv6_0;
@@ -460,7 +538,9 @@ static struct layer_s layer_forward_network_ipv4_0 =
L"" WINDIVERT_DEVICE_NAME L" filter network (forward IPv4)",
{0},
{0},
- windivert_classify_forward_network_v4_callout,
+ windivert_forward_network_v4_classify,
+ NULL,
+ UINT16_MAX
};
static layer_t layer_forward_network_ipv4 = &layer_forward_network_ipv4_0;
@@ -474,16 +554,54 @@ static struct layer_s layer_forward_network_ipv6_0 =
L"" WINDIVERT_DEVICE_NAME L" filter network (forward IPv6)",
{0},
{0},
- windivert_classify_forward_network_v6_callout,
+ windivert_forward_network_v6_classify,
+ NULL,
+ UINT16_MAX
};
static layer_t layer_forward_network_ipv6 = &layer_forward_network_ipv6_0;
+static struct layer_s layer_flow_established_ipv4_0 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerFlowEstablishedIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutFlowEstablishedIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterFlowEstablishedIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)",
+ {0},
+ {0},
+ windivert_flow_established_v4_classify,
+ windivert_flow_delete_notify,
+ 0
+};
+static layer_t layer_flow_established_ipv4 = &layer_flow_established_ipv4_0;
+
+static struct layer_s layer_flow_established_ipv6_0 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerFlowEstablishedIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutFlowEstablishedIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterFlowEstablishedIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)",
+ {0},
+ {0},
+ windivert_flow_established_v6_classify,
+ windivert_flow_delete_notify,
+ 0
+};
+static layer_t layer_flow_established_ipv6 = &layer_flow_established_ipv6_0;
+
/*
* WinDivert malloc/free.
*/
static PVOID windivert_malloc(SIZE_T size, BOOL paged)
{
POOL_TYPE pool = (paged? PagedPool: non_paged_pool);
+ if (size == 0)
+ {
+ return NULL;
+ }
return ExAllocatePoolWithTag(pool, size, WINDIVERT_TAG);
}
static VOID windivert_free(PVOID ptr)
@@ -543,6 +661,10 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj,
layer_outbound_network_ipv6->layer_guid = FWPM_LAYER_OUTBOUND_IPPACKET_V6;
layer_forward_network_ipv4->layer_guid = FWPM_LAYER_IPFORWARD_V4;
layer_forward_network_ipv6->layer_guid = FWPM_LAYER_IPFORWARD_V6;
+ layer_flow_established_ipv4->layer_guid =
+ FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
+ layer_flow_established_ipv6->layer_guid =
+ FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6;
layer_inbound_network_ipv4->sublayer_guid =
WINDIVERT_SUBLAYER_INBOUND_IPV4_GUID;
layer_outbound_network_ipv4->sublayer_guid =
@@ -555,6 +677,10 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj,
WINDIVERT_SUBLAYER_FORWARD_IPV4_GUID;
layer_forward_network_ipv6->sublayer_guid =
WINDIVERT_SUBLAYER_FORWARD_IPV6_GUID;
+ layer_flow_established_ipv4->sublayer_guid =
+ WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV4_GUID;
+ layer_flow_established_ipv6->sublayer_guid =
+ WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV6_GUID;
// Configure ourself as a non-PnP driver:
WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
@@ -725,6 +851,16 @@ driver_entry_sublayer_error:
{
goto driver_entry_sublayer_error;
}
+ status = windivert_install_sublayer(layer_flow_established_ipv4);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(layer_flow_established_ipv6);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
status = FwpmTransactionCommit0(engine_handle);
if (!NT_SUCCESS(status))
{
@@ -796,6 +932,10 @@ static void windivert_driver_unload(void)
&layer_forward_network_ipv4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
&layer_forward_network_ipv6->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ &layer_flow_established_ipv4->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ &layer_flow_established_ipv6->sublayer_guid);
status = FwpmTransactionCommit0(engine_handle);
if (!NT_SUCCESS(status))
{
@@ -814,10 +954,10 @@ static NTSTATUS windivert_install_sublayer(layer_t layer)
NTSTATUS status;
RtlZeroMemory(&sublayer, sizeof(sublayer));
- sublayer.subLayerKey = layer->sublayer_guid;
+ sublayer.subLayerKey = layer->sublayer_guid;
sublayer.displayData.name = layer->sublayer_name;
sublayer.displayData.description = layer->sublayer_desc;
- sublayer.weight = UINT16_MAX;
+ sublayer.weight = layer->sublayer_weight;
status = FwpmSubLayerAdd0(engine_handle, &sublayer, NULL);
if (!NT_SUCCESS(status))
@@ -869,8 +1009,10 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
{
context->installed[i] = FALSE;
}
- context->on = FALSE;
KeInitializeSpinLock(&context->lock);
+ InitializeListHead(&context->flow_set);
+ context->flow_v4_callout_id = 0;
+ context->flow_v6_callout_id = 0;
InitializeListHead(&context->work_queue);
InitializeListHead(&context->packet_queue);
for (i = 0; i < WINDIVERT_CONTEXT_MAXLAYERS; i++)
@@ -919,7 +1061,6 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
DEBUG_ERROR("failed to create WFP engine handle", status);
goto windivert_create_exit;
}
- context->state = WINDIVERT_CONTEXT_STATE_OPEN;
windivert_create_exit:
@@ -951,44 +1092,58 @@ windivert_create_exit:
* Register all WFP callouts.
*/
static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
- BOOL is_inbound, BOOL is_outbound, BOOL is_ipv4, BOOL is_ipv6)
+ BOOL inbound, BOOL outbound, BOOL ipv4, BOOL ipv6)
{
UINT8 i, j;
layer_t layers[WINDIVERT_CONTEXT_MAXLAYERS];
+ UINT32 *callout_ids[WINDIVERT_CONTEXT_MAXLAYERS] = {NULL};
NTSTATUS status = STATUS_SUCCESS;
i = 0;
switch (layer)
{
case WINDIVERT_LAYER_NETWORK:
- if (is_inbound && is_ipv4)
+ if (inbound && ipv4)
{
layers[i++] = layer_inbound_network_ipv4;
}
- if (is_outbound && is_ipv4)
+ if (outbound && ipv4)
{
layers[i++] = layer_outbound_network_ipv4;
}
- if (is_inbound && is_ipv6)
+ if (inbound && ipv6)
{
layers[i++] = layer_inbound_network_ipv6;
}
- if (is_outbound && is_ipv6)
+ if (outbound && ipv6)
{
layers[i++] = layer_outbound_network_ipv6;
}
break;
case WINDIVERT_LAYER_NETWORK_FORWARD:
- if (is_ipv4)
+ if (ipv4)
{
layers[i++] = layer_forward_network_ipv4;
}
- if (is_ipv6)
+ if (ipv6)
{
layers[i++] = layer_forward_network_ipv6;
}
break;
+
+ case WINDIVERT_LAYER_FLOW:
+ if (ipv4)
+ {
+ callout_ids[i] = &context->flow_v4_callout_id;
+ layers[i++] = layer_flow_established_ipv4;
+ }
+ if (ipv6)
+ {
+ callout_ids[i] = &context->flow_v6_callout_id;
+ layers[i++] = layer_flow_established_ipv6;
+ }
+ break;
default:
return STATUS_INVALID_PARAMETER;
@@ -996,7 +1151,8 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
for (j = 0; j < i; j++)
{
- status = windivert_install_callout(context, j, layers[j]);
+ status = windivert_install_callout(context, j, layers[j],
+ callout_ids[j]);
if (!NT_SUCCESS(status))
{
goto windivert_install_callouts_exit;
@@ -1017,7 +1173,7 @@ windivert_install_callouts_exit:
* Register a WFP callout.
*/
static NTSTATUS windivert_install_callout(context_t context, UINT idx,
- layer_t layer)
+ layer_t layer, UINT32 *callout_id_ptr)
{
KLOCK_QUEUE_HANDLE lock_handle;
FWPS_CALLOUT0 scallout;
@@ -1026,6 +1182,7 @@ static NTSTATUS windivert_install_callout(context_t context, UINT idx,
UINT64 weight;
UINT32 priority;
GUID callout_guid, filter_guid;
+ UINT32 callout_id;
WDFDEVICE device;
HANDLE engine_handle;
NTSTATUS status;
@@ -1048,9 +1205,9 @@ static NTSTATUS windivert_install_callout(context_t context, UINT idx,
RtlZeroMemory(&scallout, sizeof(scallout));
scallout.calloutKey = callout_guid;
- scallout.classifyFn = layer->callout;
- scallout.notifyFn = windivert_notify_callout;
- scallout.flowDeleteFn = NULL;
+ scallout.classifyFn = layer->classify;
+ scallout.notifyFn = windivert_notify;
+ scallout.flowDeleteFn = layer->flow_delete;
RtlZeroMemory(&mcallout, sizeof(mcallout));
mcallout.calloutKey = callout_guid;
mcallout.displayData.name = layer->callout_name;
@@ -1068,12 +1225,18 @@ static NTSTATUS windivert_install_callout(context_t context, UINT idx,
filter.weight.uint64 = &weight;
filter.rawContext = (UINT64)context;
status = FwpsCalloutRegister0(WdfDeviceWdmGetDeviceObject(device),
- &scallout, NULL);
+ &scallout, &callout_id);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to install WFP callout", status);
return status;
}
+ if (callout_id_ptr != NULL)
+ {
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ *callout_id_ptr = callout_id;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ }
status = FwpmTransactionBegin0(engine_handle, 0);
if (!NT_SUCCESS(status))
{
@@ -1153,7 +1316,7 @@ windivert_uninstall_callouts_error:
// RPC handle was closed first. So, this path is "normal" if
// the user's app crashed or never closed the WinDivert handle.
DEBUG_ERROR("failed to begin WFP transaction", status);
- goto unregister_callouts;
+ goto windivert_uninstall_callouts_unregister;
}
for (i = 0; i < WINDIVERT_CONTEXT_MAXLAYERS; i++)
{
@@ -1171,10 +1334,10 @@ windivert_uninstall_callouts_error:
filter_guid = context->filter_guid[i];
KeReleaseInStackQueuedSpinLock(&lock_handle);
- if (!installed)
- {
- continue;
- }
+ if (!installed)
+ {
+ continue;
+ }
status = FwpmFilterDeleteByKey0(engine_handle, &filter_guid);
if (!NT_SUCCESS(status))
{
@@ -1191,15 +1354,16 @@ windivert_uninstall_callouts_error:
if (!NT_SUCCESS(status))
{
FwpmTransactionAbort0(engine_handle);
- goto unregister_callouts;
+ goto windivert_uninstall_callouts_unregister;
}
status = FwpmTransactionCommit0(engine_handle);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to commit WFP transaction", status);
- //fallthrough
+ // continue
}
-unregister_callouts:
+
+windivert_uninstall_callouts_unregister:
for (i = 0; i < WINDIVERT_CONTEXT_MAXLAYERS; i++)
{
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
@@ -1215,7 +1379,12 @@ unregister_callouts:
{
continue;
}
- FwpsCalloutUnregisterByKey0(&callout_guid);
+ status = FwpsCalloutUnregisterByKey0(&callout_guid);
+ if (!NT_SUCCESS(status))
+ {
+ DEBUG_ERROR("failed to delete callout", status);
+ continue;
+ }
}
}
@@ -1228,6 +1397,7 @@ extern VOID windivert_cleanup(IN WDFFILEOBJECT object)
PLIST_ENTRY entry;
UINT i;
context_t context = windivert_context_get(object);
+ flow_t flow;
packet_t work, packet;
WDFQUEUE read_queue;
WDFWORKITEM worker;
@@ -1240,7 +1410,8 @@ extern VOID windivert_cleanup(IN WDFFILEOBJECT object)
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPENING &&
+ context->state != WINDIVERT_CONTEXT_STATE_OPEN)
{
windivert_cleanup_error:
KeReleaseInStackQueuedSpinLock(&lock_handle);
@@ -1252,15 +1423,29 @@ windivert_cleanup_error:
sniff_mode = ((context->flags & WINDIVERT_FLAG_SNIFF) != 0);
forward = (context->layer == WINDIVERT_LAYER_NETWORK_FORWARD);
priority = context->priority;
+ while (!IsListEmpty(&context->flow_set))
+ {
+ entry = RemoveHeadList(&context->flow_set);
+ flow = CONTAINING_RECORD(entry, struct flow_s, entry);
+ flow->deleted = TRUE;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ status = FwpsFlowRemoveContext0(flow->flow_id, flow->layer_id,
+ flow->callout_id);
+ if (!NT_SUCCESS(status))
+ {
+ windivert_free(flow);
+ }
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ }
while (!IsListEmpty(&context->packet_queue))
{
entry = RemoveHeadList(&context->packet_queue);
packet = CONTAINING_RECORD(entry, struct packet_s, entry);
context->packet_queue_length--;
- context->packet_queue_size -= packet->data_len;
+ context->packet_queue_size -= packet->packet_len;
KeReleaseInStackQueuedSpinLock(&lock_handle);
timeout = WINDIVERT_TIMEOUT(context, packet->timestamp, timestamp);
- if (!timeout)
+ if (!sniff_mode && !timeout)
{
windivert_reinject_packet(packet);
}
@@ -1282,7 +1467,7 @@ windivert_cleanup_error:
KeReleaseInStackQueuedSpinLock(&lock_handle);
work = CONTAINING_RECORD(entry, struct packet_s, entry);
timeout = WINDIVERT_TIMEOUT(context, work->timestamp, timestamp);
- if (!timeout)
+ if (!sniff_mode && !timeout)
{
windivert_reinject_packet(work);
}
@@ -1313,8 +1498,6 @@ windivert_cleanup_error:
WdfWorkItemFlush(worker);
WdfObjectDelete(worker);
}
- windivert_uninstall_callouts(context, WINDIVERT_CONTEXT_STATE_CLOSING);
- FwpmEngineClose0(context->engine_handle);
}
/*
@@ -1362,6 +1545,8 @@ extern VOID windivert_destroy(IN WDFOBJECT object)
}
filter = context->filter;
KeReleaseInStackQueuedSpinLock(&lock_handle);
+ windivert_uninstall_callouts(context, WINDIVERT_CONTEXT_STATE_CLOSED);
+ FwpmEngineClose0(context->engine_handle);
windivert_free(filter);
}
@@ -1383,6 +1568,13 @@ static NTSTATUS windivert_read(context_t context, WDFREQUEST request)
KeReleaseInStackQueuedSpinLock(&lock_handle);
return STATUS_INVALID_DEVICE_STATE;
}
+ if ((context->flags & WINDIVERT_FLAG_SEND_ONLY) != 0)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ status = STATUS_INVALID_PARAMETER;
+ DEBUG_ERROR("failed to inject; send-only flag is set", status);
+ return status;
+ }
status = WdfRequestForwardToIoQueue(request, context->read_queue);
KeReleaseInStackQueuedSpinLock(&lock_handle);
if (!NT_SUCCESS(status))
@@ -1403,7 +1595,7 @@ static NTSTATUS windivert_read(context_t context, WDFREQUEST request)
static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
{
PMDL dst_mdl;
- PVOID dst, src;
+ UINT8 *layer_data, *src, *dst;
ULONG dst_len, src_len;
req_context_t req_context;
PWINDIVERT_ADDRESS addr;
@@ -1412,69 +1604,81 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
DEBUG("SERVICE: servicing read request (request=%p, packet=%p)", request,
packet);
- status = WdfRequestRetrieveOutputWdmMdl(request, &dst_mdl);
- if (!NT_SUCCESS(status))
+ layer_data = (PVOID)packet->data;
+ switch (packet->layer)
{
- DEBUG_ERROR("failed to retrieve output MDL", status);
- goto windivert_read_service_request_exit;
- }
- dst = MmGetSystemAddressForMdlSafe(dst_mdl, NormalPagePriority);
- if (dst == NULL)
- {
- status = STATUS_INSUFFICIENT_RESOURCES;
- DEBUG_ERROR("failed to get address of output MDL", status);
- goto windivert_read_service_request_exit;
- }
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
- dst_len = MmGetMdlByteCount(dst_mdl);
- src_len = packet->data_len;
- dst_len = (src_len < dst_len? src_len: dst_len);
- src = packet->data;
- RtlCopyMemory(dst, src, dst_len);
+ status = WdfRequestRetrieveOutputWdmMdl(request, &dst_mdl);
+ if (!NT_SUCCESS(status))
+ {
+ DEBUG_ERROR("failed to retrieve output MDL", status);
+ goto windivert_read_service_request_exit;
+ }
+ dst = MmGetSystemAddressForMdlSafe(dst_mdl, NormalPagePriority);
+ if (dst == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ DEBUG_ERROR("failed to get address of output MDL", status);
+ goto windivert_read_service_request_exit;
+ }
+
+ src = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_NETWORK_DATA, packet);
+ src_len = packet->packet_len;
+ dst_len = MmGetMdlByteCount(dst_mdl);
+ dst_len = (src_len < dst_len? src_len: dst_len);
+ RtlCopyMemory(dst, src, dst_len);
+ break;
+
+ case WINDIVERT_LAYER_FLOW:
+
+ status = STATUS_SUCCESS;
+ dst_len = 0;
+ break;
+
+ default:
+ status = STATUS_INVALID_DEVICE_STATE;
+ DEBUG_ERROR("invalid packet layer", status);
+ goto windivert_read_service_request_exit;
+ }
// Write the address information.
req_context = windivert_req_context_get(request);
addr = req_context->addr;
if (addr != NULL)
{
- addr->Timestamp = (INT64)packet->timestamp;
- addr->IfIdx = packet->if_idx;
- addr->SubIfIdx = packet->sub_if_idx;
- addr->Direction = packet->direction;
- addr->Loopback = (packet->loopback? 1: 0);
- addr->Impostor = (packet->impostor? 1: 0);
- if (packet->loopback)
+ addr->Timestamp = (INT64)packet->timestamp;
+ addr->Layer = packet->layer;
+ addr->Event = packet->event;
+ addr->Outbound = (packet->outbound? 1: 0);
+ addr->Loopback = (packet->loopback? 1: 0);
+ addr->Impostor = (packet->impostor? 1: 0);
+ addr->IPv6 = (packet->ipv6? 1: 0);
+ addr->PseudoIPChecksum = (packet->pseudo_ip_checksum? 1: 0);
+ addr->PseudoTCPChecksum = (packet->pseudo_tcp_checksum? 1: 0);
+ addr->PseudoUDPChecksum = (packet->pseudo_udp_checksum? 1: 0);
+ addr->Reserved = 0;
+ switch (packet->layer)
{
- addr->PseudoIPChecksum = addr->PseudoTCPChecksum =
- addr->PseudoUDPChecksum = 1;
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ RtlCopyMemory(&addr->Network, layer_data,
+ sizeof(WINDIVERT_NETWORK_DATA));
+ break;
+
+ case WINDIVERT_LAYER_FLOW:
+ RtlCopyMemory(&addr->Flow, layer_data,
+ sizeof(WINDIVERT_FLOW_DATA));
+ break;
+
+ default:
+ break;
}
- else if (packet->forward)
- {
- addr->PseudoIPChecksum = addr->PseudoTCPChecksum =
- addr->PseudoUDPChecksum = 0;
- }
- else if (packet->direction == WINDIVERT_DIRECTION_OUTBOUND)
- {
- addr->PseudoIPChecksum =
- (UINT8)packet->checksums.Transmit.IpHeaderChecksum;
- addr->PseudoTCPChecksum =
- (UINT8)packet->checksums.Transmit.TcpChecksum;
- addr->PseudoUDPChecksum =
- (UINT8)packet->checksums.Transmit.UdpChecksum;
- }
- else
- {
- addr->PseudoIPChecksum =
- (UINT8)packet->checksums.Receive.IpChecksumSucceeded;
- addr->PseudoTCPChecksum =
- (UINT8)packet->checksums.Receive.TcpChecksumSucceeded;
- addr->PseudoUDPChecksum =
- (UINT8)packet->checksums.Receive.UdpChecksumSucceeded;
- }
- addr->Reserved = 0;
}
windivert_read_service_request_exit:
+
if (NT_SUCCESS(status))
{
WdfRequestCompleteWithInformation(request, status, dst_len);
@@ -1523,7 +1727,7 @@ static void windivert_read_service(context_t context)
}
}
context->packet_queue_length--;
- context->packet_queue_size -= packet->data_len;
+ context->packet_queue_size -= packet->packet_len;
KeReleaseInStackQueuedSpinLock(&lock_handle);
if (!timeout)
@@ -1550,23 +1754,40 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
UINT data_len;
PWINDIVERT_IPHDR ip_header;
PWINDIVERT_IPV6HDR ipv6_header;
- BOOL is_ipv4;
+ BOOL ipv4;
UINT8 layer;
UINT32 priority;
UINT64 flags;
HANDLE handle, compl_handle;
PNET_BUFFER_LIST buffers = NULL;
- NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksums_info;
NTSTATUS status = STATUS_SUCCESS;
DEBUG("WRITE: writing/injecting a packet (context=%p, request=%p)",
context, request);
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ status = STATUS_INVALID_DEVICE_STATE;
+ goto windivert_write_exit;
+ }
+ layer = context->layer;
+ priority = context->priority;
+ flags = context->flags;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
- if (addr->Direction != WINDIVERT_DIRECTION_INBOUND &&
- addr->Direction != WINDIVERT_DIRECTION_OUTBOUND)
+ if ((flags & WINDIVERT_FLAG_RECV_ONLY) != 0)
{
status = STATUS_INVALID_PARAMETER;
- DEBUG_ERROR("failed to inject packet; invalid direction", status);
+ DEBUG_ERROR("failed to inject; recv-only flag is set", status);
+ goto windivert_write_exit;
+ }
+
+ if (layer == WINDIVERT_LAYER_FLOW)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ DEBUG_ERROR("failed to inject at FLOW layer", status);
goto windivert_write_exit;
}
@@ -1612,7 +1833,7 @@ windivert_write_bad_packet:
{
goto windivert_write_bad_packet;
}
- is_ipv4 = TRUE;
+ ipv4 = TRUE;
break;
case 6:
if (data_len < sizeof(WINDIVERT_IPV6HDR))
@@ -1625,7 +1846,7 @@ windivert_write_bad_packet:
{
goto windivert_write_bad_packet;
}
- is_ipv4 = FALSE;
+ ipv4 = FALSE;
break;
default:
goto windivert_write_bad_packet;
@@ -1636,7 +1857,7 @@ windivert_write_bad_packet:
(char *)data + sizeof(WINDIVERT_IPHDR),
data_len - sizeof(WINDIVERT_IPHDR));
}
- if (addr->Impostor && !windivert_decrement_ttl(data_copy, is_ipv4,
+ if (addr->Impostor && !windivert_decrement_ttl(data_copy, ipv4,
(addr->PseudoIPChecksum == 0)))
{
status = STATUS_HOPLIMIT_EXCEEDED;
@@ -1661,62 +1882,16 @@ windivert_write_bad_packet:
goto windivert_write_exit;
}
- KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
- {
- KeReleaseInStackQueuedSpinLock(&lock_handle);
- status = STATUS_INVALID_DEVICE_STATE;
- goto windivert_write_exit;
- }
- layer = context->layer;
- priority = context->priority;
- flags = context->flags;
- KeReleaseInStackQueuedSpinLock(&lock_handle);
-
- if (layer != WINDIVERT_LAYER_NETWORK_FORWARD)
- {
- checksums_info.Value = NET_BUFFER_LIST_INFO(buffers,
- TcpIpChecksumNetBufferListInfo);
- if (addr->Direction == WINDIVERT_DIRECTION_OUTBOUND)
- {
- checksums_info.Transmit.TcpChecksum =
- (addr->PseudoTCPChecksum == 0? 0: 1);
- checksums_info.Transmit.UdpChecksum =
- (addr->PseudoUDPChecksum == 0? 0: 1);
- checksums_info.Transmit.IpHeaderChecksum =
- (addr->PseudoIPChecksum == 0? 0: 1);
- }
- else
- {
- checksums_info.Receive.TcpChecksumSucceeded =
- (addr->PseudoTCPChecksum == 0? 0: 1);
- checksums_info.Receive.UdpChecksumSucceeded =
- (addr->PseudoUDPChecksum == 0? 0: 1);
- checksums_info.Receive.IpChecksumSucceeded =
- (addr->PseudoIPChecksum == 0? 0: 1);
- }
- NET_BUFFER_LIST_INFO(buffers, TcpIpChecksumNetBufferListInfo) =
- checksums_info.Value;
- }
- else
- {
- if (addr->PseudoTCPChecksum != 0 || addr->PseudoUDPChecksum != 0 ||
- addr->PseudoIPChecksum != 0)
- {
- status = STATUS_INVALID_PARAMETER;
- goto windivert_write_exit;
- }
- }
-
- handle = (is_ipv4? inject_handle: injectv6_handle);
+ handle = (ipv4? inject_handle: injectv6_handle);
compl_handle = ((flags & WINDIVERT_FLAG_DEBUG) != 0? (HANDLE)request: NULL);
if (layer == WINDIVERT_LAYER_NETWORK_FORWARD)
{
status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0,
- (is_ipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID,
- addr->IfIdx, buffers, windivert_inject_complete, compl_handle);
+ (ipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID,
+ addr->Network.IfIdx, buffers, windivert_inject_complete,
+ compl_handle);
}
- else if (addr->Direction == WINDIVERT_DIRECTION_OUTBOUND)
+ else if (addr->Outbound != 0)
{
status = FwpsInjectNetworkSendAsync0(handle, (HANDLE)priority, 0,
UNSPECIFIED_COMPARTMENT_ID, buffers, windivert_inject_complete,
@@ -1725,8 +1900,9 @@ windivert_write_bad_packet:
else
{
status = FwpsInjectNetworkReceiveAsync0(handle, (HANDLE)priority, 0,
- UNSPECIFIED_COMPARTMENT_ID, addr->IfIdx, addr->SubIfIdx, buffers,
- windivert_inject_complete, compl_handle);
+ UNSPECIFIED_COMPARTMENT_ID, addr->Network.IfIdx,
+ addr->Network.SubIfIdx, buffers, windivert_inject_complete,
+ compl_handle);
}
windivert_write_exit:
@@ -1740,7 +1916,7 @@ windivert_write_exit:
}
else
{
- DEBUG_ERROR("failed to inject packet", status);
+ // Request completed in windivert_ioctl()
if (buffers != NULL)
{
FwpsFreeNetBufferList0(buffers);
@@ -1788,6 +1964,26 @@ static void NTAPI windivert_inject_complete(VOID *context,
FwpsFreeNetBufferList0(buffers);
}
+/*
+ * WinDivert reinject complete routine.
+ */
+static void NTAPI windivert_reinject_complete(VOID *context,
+ NET_BUFFER_LIST *buffers, BOOLEAN dispatch_level)
+{
+ PMDL mdl;
+ PNET_BUFFER buffer;
+ size_t length;
+ packet_t packet;
+ UNREFERENCED_PARAMETER(dispatch_level);
+
+ buffer = NET_BUFFER_LIST_FIRST_NB(buffers);
+ packet = (packet_t)context;
+ mdl = NET_BUFFER_FIRST_MDL(buffer);
+ windivert_free_packet(packet);
+ IoFreeMdl(mdl);
+ FwpsFreeNetBufferList0(buffers);
+}
+
/*
* WinDivert caller context preprocessing.
*/
@@ -1983,7 +2179,19 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
case IOCTL_WINDIVERT_START_FILTER:
{
- BOOL is_inbound, is_outbound, is_ipv4, is_ipv6;
+ BOOL inbound, outbound, ipv4, ipv6;
+
+ filter = NULL;
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
+ {
+windivert_ioctl_bad_start_state:
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ windivert_free(filter);
+ status = STATUS_INVALID_DEVICE_STATE;
+ goto windivert_ioctl_exit;
+ }
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
filter0 = (windivert_ioctl_filter_t)outbuf;
filter0_len = outbuflen;
@@ -1996,37 +2204,52 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
}
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- if (context->state != WINDIVERT_CONTEXT_STATE_OPEN || context->on)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
{
- KeReleaseInStackQueuedSpinLock(&lock_handle);
- windivert_free(filter);
- status = STATUS_INVALID_DEVICE_STATE;
- goto windivert_ioctl_exit;
+ goto windivert_ioctl_bad_start_state;
}
- context->on = TRUE;
- context->filter = filter;
layer = context->layer;
+ flags = context->flags;
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_FLOW:
+ if ((flags & WINDIVERT_FLAG_SNIFF) == 0 ||
+ (flags & WINDIVERT_FLAG_RECV_ONLY) == 0)
+ {
+ goto windivert_ioctl_bad_start_state;
+ }
+ break;
+ default:
+ break;
+ }
+ context->state = WINDIVERT_CONTEXT_STATE_OPEN;
+ context->filter = filter;
KeReleaseInStackQueuedSpinLock(&lock_handle);
- windivert_filter_analyze(filter, &is_inbound, &is_outbound,
- &is_ipv4, &is_ipv6);
- status = windivert_install_callouts(context, layer, is_inbound,
- is_outbound, is_ipv4, is_ipv6);
+ windivert_filter_analyze(filter, flags, &inbound, &outbound,
+ &ipv4, &ipv6);
+ status = windivert_install_callouts(context, layer, inbound,
+ outbound, ipv4, ipv6);
break;
}
case IOCTL_WINDIVERT_SET_LAYER:
ioctl = (windivert_ioctl_t)inbuf;
- if (ioctl->arg > WINDIVERT_LAYER_MAX)
+ switch (ioctl->arg)
{
- status = STATUS_INVALID_PARAMETER;
- DEBUG_ERROR("failed to set layer; value too big", status);
- goto windivert_ioctl_exit;
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ case WINDIVERT_LAYER_FLOW:
+ break;
+ default:
+ status = STATUS_INVALID_PARAMETER;
+ DEBUG_ERROR("failed to set layer; invalid value", status);
+ goto windivert_ioctl_exit;
}
layer = (UINT8)ioctl->arg;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- if (context->state != WINDIVERT_CONTEXT_STATE_OPEN || context->on)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
status = STATUS_INVALID_DEVICE_STATE;
@@ -2048,7 +2271,7 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
}
priority = WINDIVERT_CONTEXT_PRIORITY((UINT32)ioctl->arg);
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- if (context->state != WINDIVERT_CONTEXT_STATE_OPEN || context->on)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
status = STATUS_INVALID_DEVICE_STATE;
@@ -2069,7 +2292,7 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
}
flags = ioctl->arg;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- if (context->state != WINDIVERT_CONTEXT_STATE_OPEN || context->on)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
status = STATUS_INVALID_DEVICE_STATE;
@@ -2192,9 +2415,9 @@ windivert_ioctl_exit:
}
/*
- * WinDivert notify callout.
+ * WinDivert notify function.
*/
-static NTSTATUS windivert_notify_callout(IN FWPS_CALLOUT_NOTIFY_TYPE type,
+static NTSTATUS windivert_notify(IN FWPS_CALLOUT_NOTIFY_TYPE type,
IN const GUID *filter_key, IN const FWPS_FILTER0 *filter)
{
UNREFERENCED_PARAMETER(type);
@@ -2204,154 +2427,212 @@ static NTSTATUS windivert_notify_callout(IN FWPS_CALLOUT_NOTIFY_TYPE type,
}
/*
- * WinDivert classify outbound IPv4 callout.
+ * WinDivert classify outbound IPv4 function.
*/
-static void windivert_classify_outbound_network_v4_callout(
+static void windivert_outbound_network_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_classify_callout((context_t)filter->context,
- WINDIVERT_DIRECTION_OUTBOUND,
- fixed_vals->incomingValue[
- FWPS_FIELD_OUTBOUND_IPPACKET_V4_INTERFACE_INDEX].value.uint32,
- fixed_vals->incomingValue[
- FWPS_FIELD_OUTBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX].value.uint32,
- TRUE,
- (fixed_vals->incomingValue[
- FWPS_FIELD_OUTBOUND_IPPACKET_V4_FLAGS].value.uint32 &
- FWP_CONDITION_FLAG_IS_LOOPBACK) != 0,
- 0, data, flow_context, result);
+ WINDIVERT_NETWORK_DATA network_data;
+ BOOL loopback;
+
+ if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
+ {
+ return;
+ }
+
+ network_data.IfIdx = fixed_vals->incomingValue[
+ FWPS_FIELD_OUTBOUND_IPPACKET_V4_INTERFACE_INDEX].value.uint32,
+ network_data.SubIfIdx = fixed_vals->incomingValue[
+ FWPS_FIELD_OUTBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX].value.uint32,
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_OUTBOUND_IPPACKET_V4_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+
+ windivert_network_classify((context_t)filter->context, &network_data,
+ /*ipv4=*/TRUE, /*outbound=*/TRUE, loopback, /*advance=*/0, data,
+ result);
}
/*
- * WinDivert classify outbound IPv6 callout.
+ * WinDivert classify outbound IPv6 function.
*/
-static void windivert_classify_outbound_network_v6_callout(
+static void windivert_outbound_network_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_classify_callout((context_t)filter->context,
- WINDIVERT_DIRECTION_OUTBOUND,
- fixed_vals->incomingValue[
- FWPS_FIELD_OUTBOUND_IPPACKET_V6_INTERFACE_INDEX].value.uint32,
- fixed_vals->incomingValue[
- FWPS_FIELD_OUTBOUND_IPPACKET_V6_SUB_INTERFACE_INDEX].value.uint32,
- FALSE,
- (fixed_vals->incomingValue[
- FWPS_FIELD_OUTBOUND_IPPACKET_V6_FLAGS].value.uint32 &
- FWP_CONDITION_FLAG_IS_LOOPBACK) != 0,
- 0, data, flow_context, result);
+ WINDIVERT_NETWORK_DATA network_data;
+ BOOL loopback;
+
+ if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
+ {
+ return;
+ }
+
+ network_data.IfIdx = fixed_vals->incomingValue[
+ FWPS_FIELD_OUTBOUND_IPPACKET_V6_INTERFACE_INDEX].value.uint32,
+ network_data.SubIfIdx = fixed_vals->incomingValue[
+ FWPS_FIELD_OUTBOUND_IPPACKET_V6_SUB_INTERFACE_INDEX].value.uint32,
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_OUTBOUND_IPPACKET_V6_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+
+ windivert_network_classify((context_t)filter->context, &network_data,
+ /*ipv4=*/FALSE, /*outbound=*/TRUE, loopback, /*advance=*/0,
+ data, result);
}
/*
- * WinDivert classify inbound IPv4 callout.
+ * WinDivert classify inbound IPv4 function.
*/
-static void windivert_classify_inbound_network_v4_callout(
+static void windivert_inbound_network_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)
{
- UINT advance = meta_vals->ipHeaderSize;
- windivert_classify_callout((context_t)filter->context,
- WINDIVERT_DIRECTION_INBOUND,
- fixed_vals->incomingValue[
- FWPS_FIELD_INBOUND_IPPACKET_V4_INTERFACE_INDEX].value.uint32,
- fixed_vals->incomingValue[
- FWPS_FIELD_INBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX].value.uint32,
- TRUE,
- (fixed_vals->incomingValue[
- FWPS_FIELD_INBOUND_IPPACKET_V4_FLAGS].value.uint32 &
- FWP_CONDITION_FLAG_IS_LOOPBACK) != 0,
- advance, data, flow_context, result);
+ WINDIVERT_NETWORK_DATA network_data;
+ UINT advance;
+ BOOL loopback;
+
+ if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
+ {
+ return;
+ }
+
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_INBOUND_IPPACKET_V4_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+ if (loopback)
+ {
+ result->actionType = FWP_ACTION_CONTINUE;
+ return;
+ }
+
+ network_data.IfIdx = fixed_vals->incomingValue[
+ FWPS_FIELD_INBOUND_IPPACKET_V4_INTERFACE_INDEX].value.uint32;
+ network_data.SubIfIdx = fixed_vals->incomingValue[
+ FWPS_FIELD_INBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX].value.uint32;
+ advance = meta_vals->ipHeaderSize;
+
+ windivert_network_classify((context_t)filter->context, &network_data,
+ /*ipv4=*/TRUE, /*outbound=*/FALSE, loopback, advance, data, result);
}
/*
- * WinDivert classify inbound IPv6 callout.
+ * WinDivert classify inbound IPv6 function.
*/
-static void windivert_classify_inbound_network_v6_callout(
+static void windivert_inbound_network_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)
{
- UINT advance = meta_vals->ipHeaderSize;
- windivert_classify_callout((context_t)filter->context,
- WINDIVERT_DIRECTION_INBOUND,
- fixed_vals->incomingValue[
- FWPS_FIELD_INBOUND_IPPACKET_V6_INTERFACE_INDEX].value.uint32,
- fixed_vals->incomingValue[
- FWPS_FIELD_INBOUND_IPPACKET_V6_SUB_INTERFACE_INDEX].value.uint32,
- FALSE,
- (fixed_vals->incomingValue[
- FWPS_FIELD_INBOUND_IPPACKET_V6_FLAGS].value.uint32 &
- FWP_CONDITION_FLAG_IS_LOOPBACK) != 0,
- advance, data, flow_context, result);
+ WINDIVERT_NETWORK_DATA network_data;
+ UINT advance;
+ BOOL loopback;
+
+ if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
+ {
+ return;
+ }
+
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_INBOUND_IPPACKET_V6_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+ if (loopback)
+ {
+ result->actionType = FWP_ACTION_CONTINUE;
+ return;
+ }
+
+ network_data.IfIdx = fixed_vals->incomingValue[
+ FWPS_FIELD_INBOUND_IPPACKET_V6_INTERFACE_INDEX].value.uint32;
+ network_data.SubIfIdx = fixed_vals->incomingValue[
+ FWPS_FIELD_INBOUND_IPPACKET_V6_SUB_INTERFACE_INDEX].value.uint32;
+ advance = meta_vals->ipHeaderSize;
+
+ windivert_network_classify((context_t)filter->context, &network_data,
+ /*ipv4=*/FALSE, /*outbound=*/FALSE, loopback, advance, data, result);
}
/*
- * WinDivert classify forward IPv4 callout.
+ * WinDivert classify forward IPv4 function.
*/
-static void windivert_classify_forward_network_v4_callout(
+static void windivert_forward_network_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_classify_callout((context_t)filter->context,
- WINDIVERT_DIRECTION_OUTBOUND,
- fixed_vals->incomingValue[
- FWPS_FIELD_IPFORWARD_V4_DESTINATION_INTERFACE_INDEX].value.uint32,
- 0, TRUE, FALSE, 0, data, flow_context, result);
+ WINDIVERT_NETWORK_DATA network_data;
+
+ if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
+ {
+ return;
+ }
+
+ network_data.IfIdx = fixed_vals->incomingValue[
+ FWPS_FIELD_IPFORWARD_V4_DESTINATION_INTERFACE_INDEX].value.uint32;
+ network_data.SubIfIdx = 0;
+
+ windivert_network_classify((context_t)filter->context, &network_data,
+ /*ipv4=*/TRUE, /*outbound=*/TRUE, /*loopback=*/FALSE, /*advance=*/0,
+ data, result);
}
/*
- * WinDivert classify forward IPv6 callout.
+ * WinDivert classify forward IPv6 function.
*/
-static void windivert_classify_forward_network_v6_callout(
+static void windivert_forward_network_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_classify_callout((context_t)filter->context,
- WINDIVERT_DIRECTION_OUTBOUND,
- fixed_vals->incomingValue[
- FWPS_FIELD_IPFORWARD_V6_DESTINATION_INTERFACE_INDEX].value.uint32,
- 0, FALSE, FALSE, 0, data, flow_context, result);
+ WINDIVERT_NETWORK_DATA network_data;
+
+ if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
+ {
+ return;
+ }
+
+ network_data.IfIdx = fixed_vals->incomingValue[
+ FWPS_FIELD_IPFORWARD_V6_DESTINATION_INTERFACE_INDEX].value.uint32;
+ network_data.SubIfIdx = 0;
+
+ windivert_network_classify((context_t)filter->context, &network_data,
+ /*ipv4=*/FALSE, /*outbound=*/TRUE, /*loopback=*/FALSE, /*advance=*/0,
+ data, result);
}
/*
- * WinDivert classify callout.
+ * WinDivert network classify function.
*/
-static void windivert_classify_callout(context_t context, IN UINT8 direction,
- IN UINT32 if_idx, IN UINT32 sub_if_idx, IN BOOL is_ipv4, IN BOOL loopback,
- IN UINT advance, IN OUT void *data, IN UINT64 flow_context,
+static void windivert_network_classify(context_t context,
+ IN PWINDIVERT_NETWORK_DATA network_data, IN BOOL ipv4, IN BOOL outbound,
+ IN BOOL loopback, IN UINT advance, IN OUT void *data,
OUT FWPS_CLASSIFY_OUT0 *result)
{
KLOCK_QUEUE_HANDLE lock_handle;
FWPS_PACKET_INJECTION_STATE packet_state;
HANDLE packet_context;
UINT32 priority, packet_priority;
+ UINT64 flags;
+ WINDIVERT_LAYER layer;
PNET_BUFFER_LIST buffers;
PNET_BUFFER buffer, buffer_fst, buffer_itr;
- BOOL outbound, impostor, sniff_mode, drop_mode, forward, ok;
+ BOOL impostor, sniff_mode, ok;
WDFOBJECT object;
PLIST_ENTRY old_entry;
filter_t filter;
LONGLONG timestamp;
NTSTATUS status;
- // Basic checks:
- if (!(result->rights & FWPS_RIGHT_ACTION_WRITE) || data == NULL)
- {
- return;
- }
-
result->actionType = FWP_ACTION_CONTINUE;
buffers = (PNET_BUFFER_LIST)data;
buffer = NET_BUFFER_LIST_FIRST_NB(buffers);
@@ -2361,7 +2642,7 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
// should have already been indicated.
return;
}
- if (is_ipv4)
+ if (ipv4)
{
packet_state = FwpsQueryPacketInjectionState0(inject_handle, buffers,
&packet_context);
@@ -2378,11 +2659,10 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
KeReleaseInStackQueuedSpinLock(&lock_handle);
return;
}
- sniff_mode = ((context->flags & WINDIVERT_FLAG_SNIFF) != 0);
- drop_mode = ((context->flags & WINDIVERT_FLAG_DROP) != 0);
- forward = (context->layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ flags = context->flags;
priority = context->priority;
filter = context->filter;
+ layer = context->layer;
object = (WDFOBJECT)context->object;
WdfObjectReference(object);
KeReleaseInStackQueuedSpinLock(&lock_handle);
@@ -2406,13 +2686,6 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
impostor = TRUE;
}
- // Loopback packets are considered outbound only.
- if (loopback && direction == WINDIVERT_DIRECTION_INBOUND)
- {
- WdfObjectDereference(object);
- return;
- }
-
// Get the timestamp.
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
@@ -2441,11 +2714,10 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
// Find the first NET_BUFFER we need to queue:
buffer_fst = buffer;
- outbound = (direction == WINDIVERT_DIRECTION_OUTBOUND);
do
{
- BOOL match = windivert_filter(buffer_fst, if_idx, sub_if_idx,
- outbound, is_ipv4, impostor, loopback, filter);
+ BOOL match = windivert_filter(buffer_fst, network_data,
+ /*flow_data=*/NULL, ipv4, outbound, loopback, impostor, filter);
if (match)
{
break;
@@ -2470,22 +2742,25 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
// STEP (1): Queue all non-matching packets up to buffer_fst.
buffer_itr = buffer;
+ sniff_mode = ((flags & WINDIVERT_FLAG_SNIFF) != 0);
while (!sniff_mode && buffer_itr != buffer_fst)
{
- ok = windivert_queue_work(context, sniff_mode, drop_mode, buffers,
- buffer_itr, direction, if_idx, sub_if_idx, is_ipv4, forward,
- impostor, loopback, FALSE, priority, timestamp);
+ ok = windivert_queue_work(context, buffer_itr, buffers, network_data,
+ /*flow_data=*/NULL, layer, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
+ flags, priority, ipv4, outbound, loopback, impostor,
+ /*match=*/FALSE, timestamp);
if (!ok)
{
- goto windivert_classify_callout_exit;
+ goto windivert_network_classify_exit;
}
buffer_itr = NET_BUFFER_NEXT_NB(buffer_itr);
}
// STEP (2): Queue the first matching packet buffer_fst:
- ok = windivert_queue_work(context, sniff_mode, drop_mode, buffers,
- buffer_fst, direction, if_idx, sub_if_idx, is_ipv4, forward, impostor,
- loopback, TRUE, priority, timestamp);
+ ok = windivert_queue_work(context, buffer_itr, buffers, network_data,
+ /*flow_data=*/NULL, layer, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
+ flags, priority, ipv4, outbound, loopback, impostor, /*match=*/TRUE,
+ timestamp);
if (advance != 0)
{
// Advance the NET_BUFFER to its original position. Note that we can
@@ -2496,26 +2771,27 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
}
if (!ok)
{
- goto windivert_classify_callout_exit;
+ goto windivert_network_classify_exit;
}
// STEP (3): Queue all remaining packets:
buffer_itr = NET_BUFFER_NEXT_NB(buffer_fst);
while (buffer_itr != NULL)
{
- BOOL match = windivert_filter(buffer_itr, if_idx, sub_if_idx,
- outbound, is_ipv4, impostor, loopback, filter);
- ok = windivert_queue_work(context, sniff_mode, drop_mode, buffers,
- buffer_itr, direction, if_idx, sub_if_idx, is_ipv4, forward,
- impostor, loopback, match, priority, timestamp);
+ BOOL match = windivert_filter(buffer_itr, network_data,
+ /*flow_data=*/NULL, ipv4, outbound, loopback, impostor, filter);
+ ok = windivert_queue_work(context, buffer_itr, buffers, network_data,
+ /*flow_data=*/NULL, layer, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
+ flags, priority, ipv4, outbound, loopback, impostor, match,
+ timestamp);
if (!ok)
{
- goto windivert_classify_callout_exit;
+ goto windivert_network_classify_exit;
}
buffer_itr = NET_BUFFER_NEXT_NB(buffer_itr);
}
-windivert_classify_callout_exit:
+windivert_network_classify_exit:
WdfObjectDereference(object);
if (!sniff_mode)
@@ -2526,6 +2802,276 @@ windivert_classify_callout_exit:
}
}
+/*
+ * WinDivert classify flow established IPv4 function.
+ */
+static void windivert_flow_established_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_FLOW_DATA flow_data;
+ BOOL outbound, loopback;
+ UINT64 flow_id;
+
+ flow_data.ProcessId = (UINT32)meta_vals->processId;
+ flow_data.LocalAddr[0] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS].value.uint32;
+ flow_data.LocalAddr[1] = 0x0000FFFF;
+ flow_data.LocalAddr[2] = 0;
+ flow_data.LocalAddr[3] = 0;
+ flow_data.RemoteAddr[0] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_ADDRESS].value.uint32;
+ flow_data.RemoteAddr[1] = 0x0000FFFF;
+ flow_data.RemoteAddr[2] = 0;
+ flow_data.RemoteAddr[3] = 0;
+ flow_data.LocalPort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_PORT].value.uint16;
+ flow_data.RemotePort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_PORT].value.uint16;
+ flow_data.Protocol = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8;
+
+ outbound = (fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.uint32 ==
+ FWP_DIRECTION_OUTBOUND);
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+ flow_id = meta_vals->flowHandle;
+
+ windivert_flow_established_classify((context_t)filter->context,
+ flow_id, &flow_data, /*ipv4=*/TRUE, outbound, loopback, result);
+}
+
+/*
+ * WinDivert classify flow established IPv6 function.
+ */
+static void windivert_flow_established_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_FLOW_DATA flow_data;
+ BOOL outbound, loopback;
+ UINT64 flow_id;
+ UINT8 *addr;
+ INT i;
+
+ // IPv6 assumes host byte order, so convert:
+ flow_data.ProcessId = (UINT32)meta_vals->processId;
+ addr = (UINT8 *)&flow_data.LocalAddr;
+ for (i = sizeof(flow_data.LocalAddr)-1; i >= 0; i--)
+ {
+ addr[sizeof(flow_data.LocalAddr)-i-1] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_ADDRESS]
+ .value.byteArray16->byteArray16[i];
+ }
+ for (i = sizeof(flow_data.RemoteAddr)-1; i >= 0; i--)
+ {
+ addr[sizeof(flow_data.RemoteAddr)-i-1] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_ADDRESS]
+ .value.byteArray16->byteArray16[i];
+ }
+ flow_data.LocalPort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_PORT].value.uint16;
+ flow_data.RemotePort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_PORT].value.uint16;
+ flow_data.Protocol = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL].value.uint8;
+
+ outbound = (fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_DIRECTION].value.uint32 ==
+ FWP_DIRECTION_OUTBOUND);
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+ flow_id = meta_vals->flowHandle;
+
+ windivert_flow_established_classify((context_t)filter->context,
+ flow_id, &flow_data, /*ipv4=*/FALSE, outbound, loopback, result);
+}
+
+/*
+ * WinDivert flow established classify function.
+ */
+static void windivert_flow_established_classify(context_t context,
+ IN UINT64 flow_id, IN PWINDIVERT_FLOW_DATA flow_data, IN BOOL ipv4,
+ IN BOOL outbound, IN BOOL loopback, OUT FWPS_CLASSIFY_OUT0 *result)
+{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ UINT64 flags;
+ UINT32 callout_id;
+ UINT16 layer_id;
+ BOOL match, ok;
+ WDFOBJECT object;
+ filter_t filter;
+ LONGLONG timestamp;
+ flow_t flow;
+ NTSTATUS status;
+
+ // Basic checks:
+ if (!(result->rights & FWPS_RIGHT_ACTION_WRITE))
+ {
+ return;
+ }
+
+ // Get the timestamp.
+ timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
+
+ result->actionType = FWP_ACTION_CONTINUE;
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ return;
+ }
+ filter = context->filter;
+ flags = context->flags;
+ callout_id = (ipv4? context->flow_v4_callout_id:
+ context->flow_v6_callout_id);
+ object = (WDFOBJECT)context->object;
+
+ // Reference only released once the flow has been deleted. This is to
+ // prevent the callout being unregistered while flow deletions are still
+ // pending, causing the operation to fail with STATUS_DEVICE_BUSY.
+ WdfObjectReference(object);
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ match = windivert_filter(/*buffer=*/NULL, /*network_data=*/NULL,
+ flow_data, ipv4, outbound, loopback, /*impostor=*/FALSE, filter);
+ if (match)
+ {
+ ok = windivert_queue_work(context, /*buffer=*/NULL, /*buffers=*/NULL,
+ /*network_data=*/NULL, flow_data, /*layer=*/WINDIVERT_LAYER_FLOW,
+ /*event=*/WINDIVERT_EVENT_FLOW_ESTABLISHED, flags, /*priority=*/0,
+ ipv4, outbound, loopback, /*impostor=*/FALSE, match, timestamp);
+ if (!ok)
+ {
+ WdfObjectDereference(object);
+ return;
+ }
+ }
+
+ // Associate a context with the flow. This is so we can detect when
+ // the flow is deleted.
+ flow = windivert_malloc(sizeof(struct flow_s), FALSE);
+ if (flow == NULL)
+ {
+ WdfObjectDereference(object);
+ return;
+ }
+ layer_id = (ipv4? FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4:
+ FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6);
+ flow->context = context;
+ flow->flow_id = flow_id;
+ flow->callout_id = callout_id;
+ flow->layer_id = layer_id;
+ flow->inserted = FALSE;
+ flow->deleted = FALSE;
+ flow->outbound = outbound;
+ flow->loopback = loopback;
+ flow->ipv6 = !ipv4;
+ RtlCopyMemory(&flow->data, flow_data, sizeof(flow->data));
+
+ status = FwpsFlowAssociateContext0(flow_id, layer_id, callout_id,
+ (UINT64)flow);
+ if (!NT_SUCCESS(status))
+ {
+ windivert_free(flow);
+ WdfObjectDereference(object);
+ return;
+ }
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ windivert_free(flow);
+ WdfObjectDereference(object);
+ return;
+ }
+ if (!flow->deleted)
+ {
+ InsertTailList(&context->flow_set, &flow->entry);
+ flow->inserted = TRUE;
+ }
+ else
+ {
+ // Flow was deleted before insertion; we are responsible for cleanup.
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ windivert_free(flow);
+ WdfObjectDereference(object);
+ return;
+ }
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+}
+
+/*
+ * WinDivert flow delete notify function.
+ */
+static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
+ UINT64 flow_context)
+{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ UINT64 flags;
+ BOOL match, cleanup;
+ WDFOBJECT object;
+ context_t context;
+ filter_t filter;
+ LONGLONG timestamp;
+ flow_t flow;
+
+ flow = (flow_t)flow_context;
+ if (flow == NULL)
+ {
+ return;
+ }
+
+ timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
+ context = flow->context;
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ object = (WDFOBJECT)context->object; // referenced in flow_established.
+ if (flow->inserted && !flow->deleted)
+ {
+ RemoveEntryList(&flow->entry);
+ }
+ flow->deleted = TRUE;
+ cleanup = flow->inserted;
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ goto windivert_flow_delete_notify_exit;
+ }
+ filter = context->filter;
+ flags = context->flags;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ match = windivert_filter(/*buffer=*/NULL, /*network_data=*/NULL,
+ &flow->data, !flow->ipv6, flow->outbound, flow->loopback,
+ /*impostor=*/FALSE, filter);
+ if (match)
+ {
+ (VOID)windivert_queue_work(context, /*buffer=*/NULL, /*buffers=*/NULL,
+ /*network_data=*/NULL, &flow->data, /*layer=*/WINDIVERT_LAYER_FLOW,
+ /*event=*/WINDIVERT_EVENT_FLOW_DELETED, flags, /*priority=*/0,
+ !flow->ipv6, flow->outbound, flow->loopback, /*impostor=*/FALSE,
+ match, timestamp);
+ }
+
+windivert_flow_delete_notify_exit:
+
+ if (cleanup)
+ {
+ windivert_free(flow);
+ WdfObjectDereference(object);
+ }
+}
+
/*
* WinDivert work item routine for out-of-band filtering.
*/
@@ -2563,63 +3109,113 @@ VOID windivert_worker(IN WDFWORKITEM item)
/*
* Queue work.
*/
-static BOOL windivert_queue_work(context_t context, BOOL sniff_mode,
- BOOL drop_mode, PNET_BUFFER_LIST buffers, PNET_BUFFER buffer,
- UINT8 direction, UINT32 if_idx, UINT32 sub_if_idx, BOOL is_ipv4,
- BOOL forward, BOOL impostor, BOOL loopback, BOOL match, UINT32 priority,
+static BOOL windivert_queue_work(context_t context, PNET_BUFFER buffer,
+ PNET_BUFFER_LIST buffers, PWINDIVERT_NETWORK_DATA network_data,
+ PWINDIVERT_FLOW_DATA flow_data, WINDIVERT_LAYER layer,
+ WINDIVERT_EVENT event, UINT64 flags, UINT32 priority, BOOL ipv4,
+ BOOL outbound, BOOL loopback, BOOL impostor, BOOL match,
LONGLONG timestamp)
{
KLOCK_QUEUE_HANDLE lock_handle;
packet_t work;
- UINT data_len;
- PVOID data;
+ ULONG packet_len;
+ PVOID packet_data;
+ UINT8 *data;
PLIST_ENTRY old_entry;
+ NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksums;
+ BOOL pseudo_ip_checksum, pseudo_tcp_checksum, pseudo_udp_checksum;
- if (!match && sniff_mode)
+ if (!match && (flags & WINDIVERT_FLAG_SNIFF) != 0)
{
return TRUE;
}
- if (match && drop_mode)
+ if (match && (flags & WINDIVERT_FLAG_DROP) != 0)
{
return TRUE;
}
- work = (packet_t)windivert_malloc(sizeof(struct packet_s), FALSE);
- if (work == NULL)
+ // Copy the packet & layer data.
+ switch (layer)
{
- return TRUE;
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ packet_len = NET_BUFFER_DATA_LENGTH(buffer);
+ if (packet_len > UINT16_MAX)
+ {
+ // Cannot handle oversized packet
+ return TRUE;
+ }
+ work = (packet_t)windivert_malloc(
+ WINDIVERT_PACKET_SIZE(WINDIVERT_NETWORK_DATA, packet_len),
+ FALSE);
+ if (work == NULL)
+ {
+ return TRUE;
+ }
+ work->packet_len = (UINT32)packet_len;
+ data = WINDIVERT_LAYER_DATA_PTR(work);
+ RtlCopyMemory(data, network_data, sizeof(WINDIVERT_NETWORK_DATA));
+ data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_NETWORK_DATA, work);
+ packet_data = NdisGetDataBuffer(buffer, packet_len, NULL, 1, 0);
+ if (packet_data == NULL)
+ {
+ NdisGetDataBuffer(buffer, packet_len, data, 1, 0);
+ }
+ else
+ {
+ RtlCopyMemory(data, packet_data, packet_len);
+ }
+ checksums.Value = NET_BUFFER_LIST_INFO(buffers,
+ TcpIpChecksumNetBufferListInfo);
+ if (outbound)
+ {
+ pseudo_ip_checksum = (checksums.Transmit.IpHeaderChecksum != 0);
+ pseudo_tcp_checksum = (checksums.Transmit.TcpChecksum != 0);
+ pseudo_udp_checksum = (checksums.Transmit.UdpChecksum != 0);
+ }
+ else
+ {
+ pseudo_ip_checksum =
+ (checksums.Receive.IpChecksumSucceeded != 0);
+ pseudo_tcp_checksum =
+ (checksums.Receive.TcpChecksumSucceeded != 0);
+ pseudo_udp_checksum =
+ (checksums.Receive.UdpChecksumSucceeded != 0);
+ }
+ break;
+
+ case WINDIVERT_LAYER_FLOW:
+ work = (packet_t)windivert_malloc(
+ WINDIVERT_PACKET_SIZE(WINDIVERT_FLOW_DATA, 0), FALSE);
+ if (work == NULL)
+ {
+ return TRUE;
+ }
+ work->packet_len = 0;
+ data = WINDIVERT_LAYER_DATA_PTR(work);
+ RtlCopyMemory(data, flow_data, sizeof(WINDIVERT_FLOW_DATA));
+ pseudo_ip_checksum = pseudo_tcp_checksum = pseudo_udp_checksum =
+ FALSE;
+ break;
+
+ default:
+ return TRUE;
}
- data_len = NET_BUFFER_DATA_LENGTH(buffer);
- work->data = windivert_malloc(data_len, FALSE);
- if (work->data == NULL)
- {
- windivert_free_packet(work);
- return TRUE;
- }
- work->data_len = data_len;
- data = NdisGetDataBuffer(buffer, data_len, NULL, 1, 0);
- if (data == NULL)
- {
- NdisGetDataBuffer(buffer, data_len, work->data, 1, 0);
- }
- else
- {
- RtlCopyMemory(work->data, data, data_len);
- }
- work->is_ipv4 = is_ipv4;
- work->forward = forward;
- work->impostor = impostor;
- work->loopback = loopback;
- work->match = match;
- work->direction = direction;
- work->if_idx = if_idx;
- work->sub_if_idx = sub_if_idx;
- work->priority = priority;
- work->timestamp = timestamp;
- work->checksums.Value = NET_BUFFER_LIST_INFO(buffers,
- TcpIpChecksumNetBufferListInfo);
+
+ work->layer = layer;
+ work->event = event;
+ work->outbound = (outbound? 1: 0);
+ work->loopback = (loopback? 1: 0);
+ work->impostor = (impostor? 1: 0);
+ work->ipv6 = (!ipv4? 1: 0);
+ work->pseudo_ip_checksum = (pseudo_ip_checksum? 1: 0);
+ work->pseudo_tcp_checksum = (pseudo_tcp_checksum? 1: 0);
+ work->pseudo_udp_checksum = (pseudo_udp_checksum? 1: 0);
+ work->match = match;
+ work->priority = priority;
+ work->timestamp = timestamp;
+
old_entry = NULL;
-
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
{
@@ -2667,10 +3263,10 @@ static void windivert_queue_packet(context_t context, packet_t packet)
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
- windivert_free_packet(packet);
+ windivert_reinject_packet(packet);
return;
}
- if (packet->data_len > context->packet_queue_maxsize)
+ if (packet->packet_len > context->packet_queue_maxsize)
{
// (Corner case) the packet is larger than the max queue size:
KeReleaseInStackQueuedSpinLock(&lock_handle);
@@ -2686,7 +3282,7 @@ static void windivert_queue_packet(context_t context, packet_t packet)
return;
}
- if (context->packet_queue_size + packet->data_len >
+ if (context->packet_queue_size + packet->packet_len >
context->packet_queue_maxsize ||
context->packet_queue_length + 1 > context->packet_queue_maxlength)
{
@@ -2694,7 +3290,7 @@ static void windivert_queue_packet(context_t context, packet_t packet)
old_entry = RemoveHeadList(&context->packet_queue);
old_packet = CONTAINING_RECORD(old_entry, struct packet_s, entry);
context->packet_queue_length--;
- context->packet_queue_size -= old_packet->data_len;
+ context->packet_queue_size -= old_packet->packet_len;
KeReleaseInStackQueuedSpinLock(&lock_handle);
DEBUG("DROP: packet queue is full, dropping packet");
windivert_free_packet(old_packet);
@@ -2707,7 +3303,7 @@ static void windivert_queue_packet(context_t context, packet_t packet)
// Queue the packet:
InsertTailList(&context->packet_queue, &packet->entry);
context->packet_queue_length++;
- context->packet_queue_size += packet->data_len;
+ context->packet_queue_size += packet->packet_len;
break;
}
}
@@ -2726,13 +3322,26 @@ static void windivert_queue_packet(context_t context, packet_t packet)
*/
static void windivert_reinject_packet(packet_t packet)
{
+ UINT8 *packet_data;
+ UINT32 packet_len;
+ PWINDIVERT_NETWORK_DATA network_data;
PMDL mdl;
PNET_BUFFER_LIST buffers;
HANDLE handle;
UINT32 priority;
NTSTATUS status;
- mdl = IoAllocateMdl(packet->data, packet->data_len, FALSE, FALSE, NULL);
+ if (packet->layer != WINDIVERT_LAYER_NETWORK &&
+ packet->layer != WINDIVERT_LAYER_NETWORK_FORWARD)
+ {
+ windivert_free_packet(packet);
+ return;
+ }
+
+ network_data = (PWINDIVERT_NETWORK_DATA)WINDIVERT_LAYER_DATA_PTR(packet);
+ packet_data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_NETWORK_DATA, packet);
+ packet_len = packet->packet_len;
+ mdl = IoAllocateMdl(packet_data, packet_len, FALSE, FALSE, NULL);
if (mdl == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
@@ -2742,7 +3351,7 @@ static void windivert_reinject_packet(packet_t packet)
}
MmBuildMdlForNonPagedPool(mdl);
status = FwpsAllocateNetBufferAndNetBufferList0(nbl_pool_handle, 0, 0,
- mdl, 0, packet->data_len, &buffers);
+ mdl, 0, packet_len, &buffers);
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to create NET_BUFFER_LIST for injected packet",
@@ -2752,39 +3361,35 @@ static void windivert_reinject_packet(packet_t packet)
return;
}
priority = packet->priority;
- NET_BUFFER_LIST_INFO(buffers, TcpIpChecksumNetBufferListInfo) =
- packet->checksums.Value;
- handle = (packet->is_ipv4? inject_handle: injectv6_handle);
- if (packet->forward)
+ handle = (packet->ipv6? injectv6_handle: inject_handle);
+ if (packet->layer == WINDIVERT_LAYER_NETWORK_FORWARD)
{
status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0,
- (packet->is_ipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID,
- packet->if_idx, buffers, windivert_inject_complete, NULL);
+ (packet->ipv6? AF_INET6: AF_INET), UNSPECIFIED_COMPARTMENT_ID,
+ network_data->IfIdx, buffers, windivert_reinject_complete,
+ (HANDLE)packet);
}
- else if (packet->direction == WINDIVERT_DIRECTION_OUTBOUND)
+ else if (packet->outbound)
{
- status = FwpsInjectNetworkSendAsync0(handle,
- (HANDLE)priority, 0, UNSPECIFIED_COMPARTMENT_ID, buffers,
- windivert_inject_complete, NULL);
+ status = FwpsInjectNetworkSendAsync0(handle, (HANDLE)priority, 0,
+ UNSPECIFIED_COMPARTMENT_ID, buffers, windivert_reinject_complete,
+ (HANDLE)packet);
}
else
{
- status = FwpsInjectNetworkReceiveAsync0(handle,
- (HANDLE)priority, 0, UNSPECIFIED_COMPARTMENT_ID, packet->if_idx,
- packet->sub_if_idx, buffers, windivert_inject_complete, NULL);
+ status = FwpsInjectNetworkReceiveAsync0(handle, (HANDLE)priority, 0,
+ UNSPECIFIED_COMPARTMENT_ID, network_data->IfIdx,
+ network_data->SubIfIdx, buffers, windivert_reinject_complete,
+ (HANDLE)packet);
}
- if (NT_SUCCESS(status))
- {
- packet->data = NULL; // Data is now owned by injected NET_BUFFER.
- }
- else
+ if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to re-inject (packet=%p)", status, packet);
FwpsFreeNetBufferList0(buffers);
IoFreeMdl(mdl);
+ windivert_free_packet(packet);
}
- windivert_free_packet(packet);
}
/*
@@ -2792,19 +3397,18 @@ static void windivert_reinject_packet(packet_t packet)
*/
static void windivert_free_packet(packet_t packet)
{
- windivert_free(packet->data);
windivert_free(packet);
}
/*
* Decrement the TTL of a packet.
*/
-static BOOL windivert_decrement_ttl(PVOID data, BOOL is_ipv4, BOOL checksum)
+static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4, BOOL checksum)
{
PWINDIVERT_IPHDR ip_header;
PWINDIVERT_IPV6HDR ipv6_header;
- if (is_ipv4)
+ if (ipv4)
{
ip_header = (PWINDIVERT_IPHDR)data;
if (ip_header->TTL <= 1)
@@ -2838,53 +3442,6 @@ static BOOL windivert_decrement_ttl(PVOID data, BOOL is_ipv4, BOOL checksum)
return TRUE;
}
-/*
- * Skip well-known IPv6 extension headers.
- */
-static UINT8 windivert_skip_headers(UINT8 proto, UINT8 **header, size_t *len)
-{
- size_t hdrlen;
-
- while (TRUE)
- {
- if (*len <= 2)
- {
- return IPPROTO_NONE;
- }
-
- hdrlen = (size_t)*(*header + 1);
- switch (proto)
- {
- case IPPROTO_FRAGMENT:
- hdrlen = 8;
- break;
- case IPPROTO_AH:
- hdrlen += 2;
- hdrlen *= 4;
- break;
- case IPPROTO_HOPOPTS:
- case IPPROTO_DSTOPTS:
- case IPPROTO_ROUTING:
- hdrlen++;
- hdrlen *= 8;
- break;
- case IPPROTO_NONE:
- return proto;
- default:
- return proto;
- }
-
- if (hdrlen >= *len)
- {
- return IPPROTO_NONE;
- }
-
- proto = **header;
- *header += hdrlen;
- *len -= hdrlen;
- }
-}
-
/*
* Big number comparison.
*/
@@ -2926,13 +3483,16 @@ static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b)
}
/*
- * Checks if the given packet is of interest.
+ * Parse packet headers.
*/
-static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
- UINT32 sub_if_idx, BOOL outbound, BOOL is_ipv4, BOOL impostor,
- BOOL loopback, filter_t filter)
+static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
+ PWINDIVERT_IPHDR *ip_header_ptr, PWINDIVERT_IPV6HDR *ipv6_header_ptr,
+ PWINDIVERT_ICMPHDR *icmp_header_ptr,
+ PWINDIVERT_ICMPV6HDR *icmpv6_header_ptr,
+ PWINDIVERT_TCPHDR *tcp_header_ptr, PWINDIVERT_UDPHDR *udp_header_ptr,
+ UINT *payload_len_ptr)
{
- size_t tot_len, ip_header_len;
+ UINT tot_len, ip_header_len;
PWINDIVERT_IPHDR ip_header = NULL;
PWINDIVERT_IPV6HDR ipv6_header = NULL;
PWINDIVERT_ICMPHDR icmp_header = NULL;
@@ -2940,7 +3500,8 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
PWINDIVERT_TCPHDR tcp_header = NULL;
PWINDIVERT_UDPHDR udp_header = NULL;
UINT16 ip, ttl;
- UINT8 proto;
+ UINT8 proto = 0;
+ UINT payload_len = 0;
NTSTATUS status;
// Parse the headers:
@@ -2952,7 +3513,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
}
// Get the IP header.
- if (is_ipv4)
+ if (ipv4)
{
// IPv4:
if (tot_len < sizeof(WINDIVERT_IPHDR))
@@ -3010,7 +3571,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
while (TRUE)
{
UINT8 *ext_header;
- size_t ext_header_len;
+ UINT ext_header_len;
BOOL isexthdr = TRUE;
ext_header = (UINT8 *)NdisGetDataBuffer(buffer, 2, NULL, 1, 0);
@@ -3019,7 +3580,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
break;
}
- ext_header_len = (size_t)ext_header[1];
+ ext_header_len = (UINT)ext_header[1];
switch (proto)
{
case IPPROTO_FRAGMENT:
@@ -3065,10 +3626,13 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
case IPPROTO_TCP:
tcp_header = (PWINDIVERT_TCPHDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_TCPHDR), NULL, 1, 0);
+ payload_len = tot_len - ip_header_len -
+ tcp_header->HdrLength*sizeof(UINT32);
break;
case IPPROTO_UDP:
udp_header = (PWINDIVERT_UDPHDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_UDPHDR), NULL, 1, 0);
+ payload_len = tot_len - ip_header_len - sizeof(WINDIVERT_UDPHDR);
break;
default:
break;
@@ -3082,12 +3646,56 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
return FALSE;
}
+ *ip_header_ptr = ip_header;
+ *ipv6_header_ptr = ipv6_header;
+ *icmp_header_ptr = icmp_header;
+ *icmpv6_header_ptr = icmpv6_header;
+ *tcp_header_ptr = tcp_header;
+ *udp_header_ptr = udp_header;
+ *payload_len_ptr = payload_len;
+
+ return TRUE;
+}
+
+/*
+ * Checks if the given network packet is of interest.
+ */
+static BOOL windivert_filter(PNET_BUFFER buffer,
+ PWINDIVERT_NETWORK_DATA network_data, PWINDIVERT_FLOW_DATA flow_data,
+ BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, filter_t filter)
+{
+ PWINDIVERT_IPHDR ip_header = NULL;
+ PWINDIVERT_IPV6HDR ipv6_header = NULL;
+ PWINDIVERT_ICMPHDR icmp_header = NULL;
+ PWINDIVERT_ICMPV6HDR icmpv6_header = NULL;
+ PWINDIVERT_TCPHDR tcp_header = NULL;
+ PWINDIVERT_UDPHDR udp_header = NULL;
+ UINT payload_len = 0;
+ UINT16 ip, ttl;
+ NTSTATUS status;
+
+ if (network_data != NULL)
+ {
+ if (!windivert_parse_headers(buffer, ipv4, &ip_header, &ipv6_header,
+ &icmp_header, &icmpv6_header, &tcp_header, &udp_header,
+ &payload_len))
+ {
+ return FALSE;
+ }
+ }
+ else if (flow_data == NULL)
+ {
+ DEBUG("FILTER: REJECT (invalid parameter)");
+ return FALSE;
+ }
+
// Execute the filter:
ip = 0;
ttl = WINDIVERT_FILTER_MAXLEN+1; // Additional safety
while (ttl-- != 0)
{
- BOOL result;
+ BOOL result = FALSE;
+ BOOL error = FALSE;
int cmp;
UINT32 field[4];
field[1] = 0;
@@ -3098,6 +3706,12 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
case WINDIVERT_FILTER_PROTOCOL_NONE:
result = TRUE;
break;
+ case WINDIVERT_FILTER_PROTOCOL_NETWORK:
+ result = (network_data != NULL);
+ break;
+ case WINDIVERT_FILTER_PROTOCOL_FLOW:
+ result = (flow_data != NULL);
+ break;
case WINDIVERT_FILTER_PROTOCOL_IP:
result = (ip_header != NULL);
break;
@@ -3117,6 +3731,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
result = (udp_header != NULL);
break;
default:
+ error = TRUE;
result = FALSE;
break;
}
@@ -3128,16 +3743,16 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
field[0] = 0;
break;
case WINDIVERT_FILTER_FIELD_INBOUND:
- field[0] = (UINT32)(!outbound);
+ field[0] = (UINT32)!outbound;
break;
case WINDIVERT_FILTER_FIELD_OUTBOUND:
field[0] = (UINT32)outbound;
break;
case WINDIVERT_FILTER_FIELD_IFIDX:
- field[0] = (UINT32)if_idx;
+ field[0] = network_data->IfIdx;
break;
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
- field[0] = (UINT32)sub_if_idx;
+ field[0] = network_data->SubIfIdx;
break;
case WINDIVERT_FILTER_FIELD_LOOPBACK:
field[0] = (UINT32)loopback;
@@ -3146,22 +3761,30 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
field[0] = (UINT32)impostor;
break;
case WINDIVERT_FILTER_FIELD_IP:
- field[0] = (UINT32)(ip_header != NULL);
+ field[0] = (UINT32)ipv4;
break;
case WINDIVERT_FILTER_FIELD_IPV6:
- field[0] = (UINT32)(ipv6_header != NULL);
+ field[0] = (UINT32)!ipv4;
break;
case WINDIVERT_FILTER_FIELD_ICMP:
- field[0] = (UINT32)(icmp_header != NULL);
+ field[0] = (UINT32)(flow_data != NULL?
+ flow_data->Protocol == IPPROTO_ICMP:
+ icmp_header != NULL);
break;
case WINDIVERT_FILTER_FIELD_ICMPV6:
- field[0] = (UINT32)(icmpv6_header != NULL);
+ field[0] = (UINT32)(flow_data != NULL?
+ flow_data->Protocol == IPPROTO_ICMPV6:
+ icmpv6_header != NULL);
break;
case WINDIVERT_FILTER_FIELD_TCP:
- field[0] = (UINT32)(tcp_header != NULL);
+ field[0] = (UINT32)(flow_data != NULL?
+ flow_data->Protocol == IPPROTO_TCP:
+ tcp_header != NULL);
break;
case WINDIVERT_FILTER_FIELD_UDP:
- field[0] = (UINT32)(udp_header != NULL);
+ field[0] = (UINT32)(flow_data != NULL?
+ flow_data->Protocol == IPPROTO_UDP:
+ udp_header != NULL);
break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
field[0] = (UINT32)ip_header->HdrLength;
@@ -3195,9 +3818,11 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
field[0] = (UINT32)RtlUshortByteSwap(ip_header->Checksum);
break;
case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
+ field[1] = 0x0000FFFF;
field[0] = (UINT32)RtlUlongByteSwap(ip_header->SrcAddr);
break;
case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
+ field[1] = 0x0000FFFF;
field[0] = (UINT32)RtlUlongByteSwap(ip_header->DstAddr);
break;
case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS:
@@ -3307,8 +3932,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
field[0] = (UINT32)RtlUshortByteSwap(tcp_header->UrgPtr);
break;
case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
- field[0] = (UINT32)(tot_len - ip_header_len -
- tcp_header->HdrLength*sizeof(UINT32));
+ field[0] = (UINT32)payload_len;
break;
case WINDIVERT_FILTER_FIELD_UDP_SRCPORT:
field[0] = (UINT32)RtlUshortByteSwap(udp_header->SrcPort);
@@ -3323,13 +3947,40 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
field[0] = (UINT32)RtlUshortByteSwap(udp_header->Checksum);
break;
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
- field[0] = (UINT32)(tot_len - ip_header_len -
- sizeof(WINDIVERT_UDPHDR));
+ field[0] = (UINT32)payload_len;
+ break;
+ case WINDIVERT_FILTER_FIELD_LOCALADDR:
+ field[0] = flow_data->LocalAddr[0];
+ field[1] = flow_data->LocalAddr[1];
+ field[2] = flow_data->LocalAddr[2];
+ field[3] = flow_data->LocalAddr[3];
+ break;
+ case WINDIVERT_FILTER_FIELD_REMOTEADDR:
+ field[0] = flow_data->RemoteAddr[0];
+ field[1] = flow_data->RemoteAddr[1];
+ field[2] = flow_data->RemoteAddr[2];
+ field[3] = flow_data->RemoteAddr[3];
+ break;
+ case WINDIVERT_FILTER_FIELD_LOCALPORT:
+ field[0] = (UINT32)flow_data->LocalPort;
+ break;
+ case WINDIVERT_FILTER_FIELD_REMOTEPORT:
+ field[0] = (UINT32)flow_data->RemotePort;
+ break;
+ case WINDIVERT_FILTER_FIELD_PROTOCOL:
+ field[0] = (UINT32)flow_data->Protocol;
+ break;
+ case WINDIVERT_FILTER_FIELD_PROCESSID:
+ field[0] = flow_data->ProcessId;
break;
default:
- field[0] = 0;
+ error = TRUE;
+ result = FALSE;
break;
}
+ }
+ if (result)
+ {
cmp = windivert_big_num_compare(field, filter[ip].arg);
switch (filter[ip].test)
{
@@ -3352,10 +4003,16 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
result = (cmp >= 0);
break;
default:
+ error = TRUE;
result = FALSE;
break;
}
}
+ if (error)
+ {
+ DEBUG("FILTER: REJECT (bad filter)");
+ return FALSE;
+ }
ip = (result? filter[ip].success: filter[ip].failure);
if (ip == WINDIVERT_FILTER_RESULT_ACCEPT)
{
@@ -3366,6 +4023,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
return FALSE;
}
}
+
DEBUG("FILTER: REJECT (filter TTL exceeded)");
return FALSE;
}
@@ -3373,21 +4031,28 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
/*
* Analyze the given filter.
*/
-static void windivert_filter_analyze(filter_t filter, BOOL *is_inbound,
- BOOL *is_outbound, BOOL *is_ipv4, BOOL *is_ipv6)
+static void windivert_filter_analyze(filter_t filter, UINT64 flags,
+ BOOL *inbound, BOOL *outbound, BOOL *ipv4, BOOL *ipv6)
{
BOOL result;
+ // Send-only?
+ if ((flags & WINDIVERT_FLAG_SEND_ONLY) != 0)
+ {
+windivert_filter_analyze_send_only:
+ *inbound = FALSE;
+ *outbound = FALSE;
+ *ipv4 = FALSE;
+ *ipv6 = FALSE;
+ return;
+ }
+
// False filter?
result = windivert_filter_test(filter, 0, WINDIVERT_FILTER_PROTOCOL_NONE,
WINDIVERT_FILTER_FIELD_ZERO, 0);
if (!result)
{
- *is_inbound = FALSE;
- *is_outbound = FALSE;
- *is_ipv4 = FALSE;
- *is_ipv6 = FALSE;
- return;
+ goto windivert_filter_analyze_send_only;
}
// Inbound?
@@ -3399,7 +4064,7 @@ static void windivert_filter_analyze(filter_t filter, BOOL *is_inbound,
WINDIVERT_FILTER_PROTOCOL_NONE, WINDIVERT_FILTER_FIELD_OUTBOUND,
0);
}
- *is_inbound = result;
+ *inbound = result;
// Outbound?
result = windivert_filter_test(filter, 0, WINDIVERT_FILTER_PROTOCOL_NONE,
@@ -3409,7 +4074,7 @@ static void windivert_filter_analyze(filter_t filter, BOOL *is_inbound,
result = windivert_filter_test(filter, 0,
WINDIVERT_FILTER_PROTOCOL_NONE, WINDIVERT_FILTER_FIELD_INBOUND, 0);
}
- *is_outbound = result;
+ *outbound = result;
// IPv4?
result = windivert_filter_test(filter, 0, WINDIVERT_FILTER_PROTOCOL_NONE,
@@ -3419,7 +4084,7 @@ static void windivert_filter_analyze(filter_t filter, BOOL *is_inbound,
result = windivert_filter_test(filter, 0,
WINDIVERT_FILTER_PROTOCOL_NONE, WINDIVERT_FILTER_FIELD_IPV6, 0);
}
- *is_ipv4 = result;
+ *ipv4 = result;
// Ipv6?
result = windivert_filter_test(filter, 0, WINDIVERT_FILTER_PROTOCOL_NONE,
@@ -3429,7 +4094,7 @@ static void windivert_filter_analyze(filter_t filter, BOOL *is_inbound,
result = windivert_filter_test(filter, 0,
WINDIVERT_FILTER_PROTOCOL_NONE, WINDIVERT_FILTER_FIELD_IP, 0);
}
- *is_ipv6 = result;
+ *ipv6 = result;
}
/*
@@ -3508,26 +4173,24 @@ static BOOL windivert_filter_test(filter_t filter, UINT16 ip, UINT8 protocol,
static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
size_t ioctl_filter_len)
{
- filter_t filter0 = NULL, result = NULL;
+ filter_t filter = NULL;
UINT16 i;
size_t length;
if (ioctl_filter_len % sizeof(struct windivert_ioctl_filter_s) != 0)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
length = ioctl_filter_len / sizeof(struct windivert_ioctl_filter_s);
- if (length >= WINDIVERT_FILTER_MAXLEN)
+ if (length >= WINDIVERT_FILTER_MAXLEN || length == 0)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
- // Do NOT use the stack (size = 12Kb on x86) for filter0.
- filter0 = (filter_t)windivert_malloc(
- WINDIVERT_FILTER_MAXLEN*sizeof(struct filter_s), TRUE);
- if (filter0 == NULL)
+ filter = (filter_t)windivert_malloc(length*sizeof(struct filter_s), FALSE);
+ if (filter == NULL)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
for (i = 0; i < length; i++)
@@ -3535,7 +4198,7 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
if (ioctl_filter[i].field > WINDIVERT_FILTER_FIELD_MAX ||
ioctl_filter[i].test > WINDIVERT_FILTER_TEST_MAX)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
switch (ioctl_filter[i].success)
{
@@ -3546,7 +4209,7 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
if (ioctl_filter[i].success <= i ||
ioctl_filter[i].success >= length)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
break;
}
@@ -3559,20 +4222,33 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
if (ioctl_filter[i].failure <= i ||
ioctl_filter[i].failure >= length)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
break;
}
// Enforce size limits:
if (ioctl_filter[i].field != WINDIVERT_FILTER_FIELD_IPV6_SRCADDR &&
- ioctl_filter[i].field != WINDIVERT_FILTER_FIELD_IPV6_DSTADDR)
+ ioctl_filter[i].field != WINDIVERT_FILTER_FIELD_IPV6_DSTADDR &&
+ ioctl_filter[i].field != WINDIVERT_FILTER_FIELD_LOCALADDR &&
+ ioctl_filter[i].field != WINDIVERT_FILTER_FIELD_REMOTEADDR)
{
- if (ioctl_filter[i].arg[1] != 0 ||
- ioctl_filter[i].arg[2] != 0 ||
+ if (ioctl_filter[i].arg[2] != 0 ||
ioctl_filter[i].arg[3] != 0)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
+ }
+ if ((ioctl_filter[i].field == WINDIVERT_FILTER_FIELD_IP_SRCADDR ||
+ ioctl_filter[i].field == WINDIVERT_FILTER_FIELD_IP_DSTADDR))
+ {
+ if (ioctl_filter[i].arg[1] != 0x0000FFFF)
+ {
+ goto windivert_filter_compile_error;
+ }
+ }
+ else if (ioctl_filter[i].arg[1] != 0)
+ {
+ goto windivert_filter_compile_error;
}
}
switch (ioctl_filter[i].field)
@@ -3596,14 +4272,14 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
case WINDIVERT_FILTER_FIELD_TCP_FIN:
if (ioctl_filter[i].arg[0] > 1)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH:
if (ioctl_filter[i].arg[0] > 0x0F)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
break;
case WINDIVERT_FILTER_FIELD_IP_TOS:
@@ -3616,15 +4292,16 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
case WINDIVERT_FILTER_FIELD_ICMP_CODE:
case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE:
case WINDIVERT_FILTER_FIELD_ICMPV6_CODE:
+ case WINDIVERT_FILTER_FIELD_PROTOCOL:
if (ioctl_filter[i].arg[0] > UINT8_MAX)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
break;
case WINDIVERT_FILTER_FIELD_IP_FRAGOFF:
if (ioctl_filter[i].arg[0] > 0x1FFF)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
break;
case WINDIVERT_FILTER_FIELD_IP_LENGTH:
@@ -3644,28 +4321,30 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
+ case WINDIVERT_FILTER_FIELD_LOCALPORT:
+ case WINDIVERT_FILTER_FIELD_REMOTEPORT:
if (ioctl_filter[i].arg[0] > UINT16_MAX)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
break;
case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL:
if (ioctl_filter[i].arg[0] > 0x000FFFFF)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
break;
default:
break;
}
- filter0[i].field = ioctl_filter[i].field;
- filter0[i].test = ioctl_filter[i].test;
- filter0[i].success = ioctl_filter[i].success;
- filter0[i].failure = ioctl_filter[i].failure;
- filter0[i].arg[0] = ioctl_filter[i].arg[0];
- filter0[i].arg[1] = ioctl_filter[i].arg[1];
- filter0[i].arg[2] = ioctl_filter[i].arg[2];
- filter0[i].arg[3] = ioctl_filter[i].arg[3];
+ filter[i].field = ioctl_filter[i].field;
+ filter[i].test = ioctl_filter[i].test;
+ filter[i].success = ioctl_filter[i].success;
+ filter[i].failure = ioctl_filter[i].failure;
+ filter[i].arg[0] = ioctl_filter[i].arg[0];
+ filter[i].arg[1] = ioctl_filter[i].arg[1];
+ filter[i].arg[2] = ioctl_filter[i].arg[2];
+ filter[i].arg[3] = ioctl_filter[i].arg[3];
// Protocol selection:
switch (ioctl_filter[i].field)
@@ -3673,8 +4352,6 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
case WINDIVERT_FILTER_FIELD_ZERO:
case WINDIVERT_FILTER_FIELD_INBOUND:
case WINDIVERT_FILTER_FIELD_OUTBOUND:
- case WINDIVERT_FILTER_FIELD_IFIDX:
- case WINDIVERT_FILTER_FIELD_SUBIFIDX:
case WINDIVERT_FILTER_FIELD_LOOPBACK:
case WINDIVERT_FILTER_FIELD_IMPOSTOR:
case WINDIVERT_FILTER_FIELD_IP:
@@ -3683,7 +4360,18 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
case WINDIVERT_FILTER_FIELD_ICMPV6:
case WINDIVERT_FILTER_FIELD_TCP:
case WINDIVERT_FILTER_FIELD_UDP:
- filter0[i].protocol = WINDIVERT_FILTER_PROTOCOL_NONE;
+ filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_NONE;
+ break;
+ case WINDIVERT_FILTER_FIELD_IFIDX:
+ case WINDIVERT_FILTER_FIELD_SUBIFIDX:
+ filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_NETWORK;
+ break;
+ case WINDIVERT_FILTER_FIELD_LOCALADDR:
+ case WINDIVERT_FILTER_FIELD_REMOTEADDR:
+ case WINDIVERT_FILTER_FIELD_LOCALPORT:
+ case WINDIVERT_FILTER_FIELD_REMOTEPORT:
+ case WINDIVERT_FILTER_FIELD_PROTOCOL:
+ filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_FLOW;
break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
case WINDIVERT_FILTER_FIELD_IP_TOS:
@@ -3697,7 +4385,7 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
case WINDIVERT_FILTER_FIELD_IP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
- filter0[i].protocol = WINDIVERT_FILTER_PROTOCOL_IP;
+ filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_IP;
break;
case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS:
case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL:
@@ -3706,19 +4394,19 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT:
case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
- filter0[i].protocol = WINDIVERT_FILTER_PROTOCOL_IPV6;
+ filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_IPV6;
break;
case WINDIVERT_FILTER_FIELD_ICMP_TYPE:
case WINDIVERT_FILTER_FIELD_ICMP_CODE:
case WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_ICMP_BODY:
- filter0[i].protocol = WINDIVERT_FILTER_PROTOCOL_ICMP;
+ filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_ICMP;
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE:
case WINDIVERT_FILTER_FIELD_ICMPV6_CODE:
case WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM:
case WINDIVERT_FILTER_FIELD_ICMPV6_BODY:
- filter0[i].protocol = WINDIVERT_FILTER_PROTOCOL_ICMPV6;
+ filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_ICMPV6;
break;
case WINDIVERT_FILTER_FIELD_TCP_SRCPORT:
case WINDIVERT_FILTER_FIELD_TCP_DSTPORT:
@@ -3735,29 +4423,25 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
- filter0[i].protocol = WINDIVERT_FILTER_PROTOCOL_TCP;
+ filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_TCP;
break;
case WINDIVERT_FILTER_FIELD_UDP_SRCPORT:
case WINDIVERT_FILTER_FIELD_UDP_DSTPORT:
case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
- filter0[i].protocol = WINDIVERT_FILTER_PROTOCOL_UDP;
+ filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_UDP;
break;
default:
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
}
- result = (filter_t)windivert_malloc(i*sizeof(struct filter_s), FALSE);
- if (result != NULL)
- {
- RtlMoveMemory(result, filter0, i*sizeof(struct filter_s));
- }
+ return filter;
-windivert_filter_compile_exit:
+windivert_filter_compile_error:
- windivert_free(filter0);
- return result;
+ windivert_free(filter);
+ return NULL;
}
From f0dd1224b1c94d751d1020eb6453fb9e27597d23 Mon Sep 17 00:00:00 2001
From: basil00
Date: Sun, 21 Oct 2018 10:12:19 +0800
Subject: [PATCH 02/23] Add a new REFLECT layer to WinDivert (see #156).
Adds a new REFLECT layer for monitoring WinDivert
handles. This includes:
- three new REFLECT events: ESTABLISHED, OPEN and
CLOSE;
- modifying the ADDRESS for REFLECT data:
open time, process-id, layer, flags, and
priority of the opened handle; and
- allowing WinDivertRecv() to read a
representation of the opened filter.
This change also includes a new "object"
representation for WinDivert filter strings.
The API has been updated as follows:
- WinDivertHelperCompileFilter (replaces
CheckFilter) compiles filter strings into the
object form; and
- WinDivertHelperFormatFilter can "decompile" an
object back into a human-readable filter
string.
Other:
- New NO_INSTALL flag.
- New windivertctl.exe sample program.
---
dll/windivert.c | 299 +----
dll/windivert.def | 3 +-
dll/windivert_helper.c | 1689 ++++++++++++++++++++++++--
examples/flowtrack/flowtrack.c | 74 +-
examples/netdump/netdump.c | 4 +-
examples/netfilter/netfilter.c | 4 +-
examples/windivertctl/windivertctl.c | 408 +++++++
include/windivert.h | 73 +-
include/windivert_device.h | 43 +-
mingw-build.sh | 6 +-
sys/sources | 2 +-
sys/windivert.c | 1106 +++++++++++------
test/test.c | 20 +-
13 files changed, 2854 insertions(+), 877 deletions(-)
create mode 100644 examples/windivertctl/windivertctl.c
diff --git a/dll/windivert.c b/dll/windivert.c
index e593e31..62208c2 100644
--- a/dll/windivert.c
+++ b/dll/windivert.c
@@ -119,13 +119,10 @@ static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code, UINT8 arg8,
UINT64 arg, PVOID buf, UINT len, UINT *iolen, LPOVERLAPPED overlapped);
static UINT8 WinDivertSkipExtHeaders(UINT8 proto, UINT8 **header, UINT *len);
-#ifdef WINDIVERT_DEBUG
-static void WinDivertFilterDump(windivert_ioctl_filter_t filter, UINT16 len);
-#endif
-
/*
* Include the helper API implementation.
*/
+#include "windivert_shared.c"
#include "windivert_helper.c"
/*
@@ -379,7 +376,7 @@ static BOOL WinDivertIoControl(HANDLE handle, DWORD code, UINT8 arg8,
static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code, UINT8 arg8,
UINT64 arg, PVOID buf, UINT len, UINT *iolen, LPOVERLAPPED overlapped)
{
- struct windivert_ioctl_s ioctl;
+ WINDIVERT_IOCTL ioctl;
BOOL result;
DWORD iolen0;
@@ -402,24 +399,21 @@ static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code, UINT8 arg8,
extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
INT16 priority, UINT64 flags)
{
- struct windivert_ioctl_filter_s object[WINDIVERT_FILTER_MAXLEN];
+ WINDIVERT_FILTER object[WINDIVERT_FILTER_MAXLEN];
UINT obj_len;
ERROR comp_err;
DWORD err;
HANDLE handle;
SC_HANDLE service;
- UINT32 priority32;
-
+ UINT64 priority64, filter_flags;
+
// Parameter checking.
- if (layer == 0)
- {
- layer = WINDIVERT_LAYER_NETWORK;
- }
switch (layer)
{
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
case WINDIVERT_LAYER_FLOW:
+ case WINDIVERT_LAYER_REFLECT:
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
@@ -431,25 +425,21 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
return INVALID_HANDLE_VALUE;
}
- priority32 = WINDIVERT_PRIORITY(priority);
- if (priority32 < WINDIVERT_PRIORITY_MIN ||
- priority32 > WINDIVERT_PRIORITY_MAX)
+ if (priority < WINDIVERT_PRIORITY_MIN ||
+ priority > WINDIVERT_PRIORITY_MAX)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
- // Compile the filter:
+ // Compile & analyze the filter:
comp_err = WinDivertCompileFilter(filter, layer, object, &obj_len);
if (IS_ERROR(comp_err))
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
-
-#ifdef WINDIVERT_DEBUG
- WinDivertFilterDump(object, obj_len);
-#endif
+ filter_flags = WinDivertAnalyzeFilter(object, obj_len);
// Attempt to open the WinDivert device:
handle = CreateFile(L"\\\\.\\" WINDIVERT_DEVICE_NAME,
@@ -464,6 +454,11 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
}
// Open failed because the device isn't installed; install it now.
+ if ((flags & WINDIVERT_FLAG_NO_INSTALL) != 0)
+ {
+ SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
+ return INVALID_HANDLE_VALUE;
+ }
SetLastError(0);
service = WinDivertDriverInstall();
if (service == NULL)
@@ -503,8 +498,8 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
// Set the flags:
if (flags != 0)
{
- if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_FLAGS, 0,
- (UINT64)flags, NULL, 0, NULL))
+ if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_FLAGS, 0, flags,
+ NULL, 0, NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
@@ -512,10 +507,12 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
}
// Set the priority:
- if (priority32 != WINDIVERT_PRIORITY_DEFAULT)
+ if (priority != WINDIVERT_PRIORITY_DEFAULT)
{
+ // Make positive:
+ priority64 = (UINT64)((INT64)priority + WINDIVERT_PRIORITY_MAX);
if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_PRIORITY, 0,
- (UINT64)priority32, NULL, 0, NULL))
+ priority64, NULL, 0, NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
@@ -523,8 +520,8 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
}
// Start the filter:
- if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_START_FILTER, 0, 0,
- object, obj_len*sizeof(struct windivert_ioctl_filter_s), NULL))
+ if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_START_FILTER, 0,
+ filter_flags, object, obj_len * sizeof(WINDIVERT_FILTER), NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
@@ -856,253 +853,3 @@ static BOOLEAN WinDivertAToX(const char *str, char **endptr, UINT32 *intptr)
return TRUE;
}
-/***************************************************************************/
-/* DEBUGGING */
-/***************************************************************************/
-
-#ifdef WINDIVERT_DEBUG
-/*
- * Print a filter (debugging).
- */
-static void WinDivertFilterDump(windivert_ioctl_filter_t filter, UINT16 len)
-{
- UINT16 i;
-
- for (i = 0; i < len; i++)
- {
- printf("label_%u:\n\tif (", i);
- switch (filter[i].field)
- {
- case WINDIVERT_FILTER_FIELD_ZERO:
- printf("zero ");
- break;
- case WINDIVERT_FILTER_FIELD_INBOUND:
- printf("inbound ");
- break;
- case WINDIVERT_FILTER_FIELD_OUTBOUND:
- printf("outbound ");
- break;
- case WINDIVERT_FILTER_FIELD_IFIDX:
- printf("ifIdx ");
- break;
- case WINDIVERT_FILTER_FIELD_SUBIFIDX:
- printf("subIfIdx ");
- break;
- case WINDIVERT_FILTER_FIELD_IP:
- printf("ip ");
- break;
- case WINDIVERT_FILTER_FIELD_IPV6:
- printf("ipv6 ");
- break;
- case WINDIVERT_FILTER_FIELD_ICMP:
- printf("icmp ");
- break;
- case WINDIVERT_FILTER_FIELD_ICMPV6:
- printf("icmpv6 ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP:
- printf("tcp ");
- break;
- case WINDIVERT_FILTER_FIELD_UDP:
- printf("udp ");
- break;
- case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
- printf("ip.HdrLength ");
- break;
- case WINDIVERT_FILTER_FIELD_IP_TOS:
- printf("ip.TOS ");
- break;
- case WINDIVERT_FILTER_FIELD_IP_LENGTH:
- printf("ip.Length ");
- break;
- case WINDIVERT_FILTER_FIELD_IP_ID:
- printf("ip.Id ");
- break;
- case WINDIVERT_FILTER_FIELD_IP_DF:
- printf("ip.DF ");
- break;
- case WINDIVERT_FILTER_FIELD_IP_MF:
- printf("ip.MF ");
- break;
- case WINDIVERT_FILTER_FIELD_IP_FRAGOFF:
- printf("ip.FragOff ");
- break;
- case WINDIVERT_FILTER_FIELD_IP_TTL:
- printf("ip.TTL ");
- break;
- case WINDIVERT_FILTER_FIELD_IP_PROTOCOL:
- printf("ip.Protocol ");
- break;
- case WINDIVERT_FILTER_FIELD_IP_CHECKSUM:
- printf("ip.Checksum ");
- break;
- case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
- printf("ip.SrcAddr ");
- break;
- case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
- printf("ip.DstAddr ");
- break;
- case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS:
- printf("ipv6.TrafficClass ");
- break;
- case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL:
- printf("ipv6.FlowLabel ");
- break;
- case WINDIVERT_FILTER_FIELD_IPV6_LENGTH:
- printf("ipv6.Length ");
- break;
- case WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR:
- printf("ipv6.NextHdr ");
- break;
- case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT:
- printf("ipv6.HopLimit ");
- break;
- case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
- printf("ipv6.SrcAddr ");
- break;
- case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
- printf("ipv6.DstAddr ");
- break;
- case WINDIVERT_FILTER_FIELD_ICMP_TYPE:
- printf("icmp.Type ");
- break;
- case WINDIVERT_FILTER_FIELD_ICMP_CODE:
- printf("icmp.Code ");
- break;
- case WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM:
- printf("icmp.Checksum ");
- break;
- case WINDIVERT_FILTER_FIELD_ICMP_BODY:
- printf("icmp.Body ");
- break;
- case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE:
- printf("icmpv6.Type ");
- break;
- case WINDIVERT_FILTER_FIELD_ICMPV6_CODE:
- printf("icmpv6.Code ");
- break;
- case WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM:
- printf("icmpv6.Checksum ");
- break;
- case WINDIVERT_FILTER_FIELD_ICMPV6_BODY:
- printf("icmpv6.Body ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_SRCPORT:
- printf("tcp.SrcPort ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_DSTPORT:
- printf("tcp.DstPort ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_SEQNUM:
- printf("tcp.SeqNum ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_ACKNUM:
- printf("tcp.AckNum ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH:
- printf("tcp.HdrLength ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_URG:
- printf("tcp.Urg ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_ACK:
- printf("tcp.Ack ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_PSH:
- printf("tcp.Psh ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_RST:
- printf("tcp.Rst ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_SYN:
- printf("tcp.Syn ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_FIN:
- printf("tcp.Fin ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_WINDOW:
- printf("tcp.Window ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
- printf("tcp.Checksum ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
- printf("tcp.UrgPtr ");
- break;
- case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
- printf("tcp.PayloadLength " );
- break;
- case WINDIVERT_FILTER_FIELD_UDP_SRCPORT:
- printf("udp.SrcPort ");
- break;
- case WINDIVERT_FILTER_FIELD_UDP_DSTPORT:
- printf("udp.DstPort ");
- break;
- case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
- printf("udp.Length ");
- break;
- case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
- printf("udp.Checksum ");
- break;
- case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
- printf("udp.PayloadLength ");
- break;
- default:
- printf("unknown.Field ");
- break;
- }
- switch (filter[i].test)
- {
- case WINDIVERT_FILTER_TEST_EQ:
- printf("== ");
- break;
- case WINDIVERT_FILTER_TEST_NEQ:
- printf("!= ");
- break;
- case WINDIVERT_FILTER_TEST_LT:
- printf("< ");
- break;
- case WINDIVERT_FILTER_TEST_LEQ:
- printf("<= ");
- break;
- case WINDIVERT_FILTER_TEST_GT:
- printf("> ");
- break;
- case WINDIVERT_FILTER_TEST_GEQ:
- printf(">= ");
- break;
- default:
- printf("?? ");
- break;
- }
- printf("%u)\n", filter[i].arg[0]);
- switch (filter[i].success)
- {
- case WINDIVERT_FILTER_RESULT_ACCEPT:
- printf("\t\treturn ACCEPT;\n");
- break;
- case WINDIVERT_FILTER_RESULT_REJECT:
- printf("\t\treturn REJECT;\n");
- break;
- default:
- printf("\t\tgoto label_%u;\n", filter[i].success);
- break;
- }
- printf("\telse\n");
- switch (filter[i].failure)
- {
- case WINDIVERT_FILTER_RESULT_ACCEPT:
- printf("\t\treturn ACCEPT;\n");
- break;
- case WINDIVERT_FILTER_RESULT_REJECT:
- printf("\t\treturn REJECT;\n");
- break;
- default:
- printf("\t\tgoto label_%u;\n", filter[i].failure);
- break;
- }
- }
-}
-
-#endif /* WINDIVERT_DEBUG */
-
diff --git a/dll/windivert.def b/dll/windivert.def
index 2c20d03..a36cd4a 100644
--- a/dll/windivert.def
+++ b/dll/windivert.def
@@ -13,5 +13,6 @@ EXPORTS
WinDivertHelperParsePacket
WinDivertHelperParseIPv4Address
WinDivertHelperParseIPv6Address
- WinDivertHelperCheckFilter
+ WinDivertHelperCompileFilter
WinDivertHelperEvalFilter
+ WinDivertHelperFormatFilter
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index 2b0c40a..86b39b6 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -108,6 +108,7 @@ typedef enum
TOKEN_UDP_LENGTH,
TOKEN_UDP_PAYLOAD_LENGTH,
TOKEN_UDP_SRC_PORT,
+ TOKEN_ZERO,
TOKEN_TRUE,
TOKEN_FALSE,
TOKEN_INBOUND,
@@ -122,6 +123,11 @@ typedef enum
TOKEN_LOCAL_PORT,
TOKEN_REMOTE_PORT,
TOKEN_PROTOCOL,
+ TOKEN_LAYER,
+ TOKEN_FLOW,
+ TOKEN_NETWORK,
+ TOKEN_NETWORK_FORWARD,
+ TOKEN_REFLECT,
TOKEN_OPEN,
TOKEN_CLOSE,
TOKEN_EQ,
@@ -166,6 +172,7 @@ struct EXPR
PEXPR arg[3];
};
UINT8 kind;
+ UINT8 count;
UINT16 succ;
UINT16 fail;
};
@@ -174,7 +181,7 @@ struct EXPR
* Error handling.
*/
#undef ERROR
-typedef UINT64 ERROR;
+typedef UINT64 ERROR, *PERROR;
#define WINDIVERT_ERROR_NONE 0
#define WINDIVERT_ERROR_NO_MEMORY 1
@@ -184,7 +191,8 @@ typedef UINT64 ERROR;
#define WINDIVERT_ERROR_BAD_TOKEN_FOR_LAYER 5
#define WINDIVERT_ERROR_UNEXPECTED_TOKEN 6
#define WINDIVERT_ERROR_OUTPUT_TOO_SHORT 7
-#define WINDIVERT_ERROR_ASSERTION_FAILED 8
+#define WINDIVERT_ERROR_BAD_OBJECT 8
+#define WINDIVERT_ERROR_ASSERTION_FAILED 9
#define MAKE_ERROR(code, pos) \
(((ERROR)(code) << 32) | (ERROR)(pos));
@@ -198,26 +206,22 @@ typedef UINT64 ERROR;
#define MAX(a, b) ((a) > (b)? (a): (b))
-/*
- * Compiler memory pool:
- */
-typedef struct POOL
-{
- unsigned offset;
- ERROR error;
- char memory[3 * 4096 - 32];
-} POOL, *PPOOL;
-
/*
* Prototypes.
*/
-static PEXPR WinDivertParseFilter(PPOOL pool, TOKEN *toks, UINT *i, INT depth,
- BOOL and);
+static PEXPR WinDivertParseFilter(HANDLE pool, TOKEN *toks, UINT *i,
+ INT depth, BOOL and, PERROR error);
+static BOOL WinDivertCondExecFilter(PWINDIVERT_FILTER filter, UINT length,
+ UINT8 field, UINT32 arg);
static UINT16 WinDivertInitPseudoHeader(PWINDIVERT_IPHDR ip_header,
PWINDIVERT_IPV6HDR ipv6_header, UINT8 protocol, UINT len,
void *pseudo_header);
static UINT16 WinDivertHelperCalcChecksum(PVOID pseudo_header,
UINT16 pseudo_header_len, PVOID data, UINT len);
+static BOOL WinDivertDeserializeFilter(PWINDIVERT_STREAM stream,
+ PWINDIVERT_FILTER filter, UINT *length);
+static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
+ BOOL top_level, BOOL and);
/*
* Skip well-known IPv6 extension headers.
@@ -810,6 +814,12 @@ static BOOL WinDivertCheckTokenKindForLayer(WINDIVERT_LAYER layer, KIND kind)
case TOKEN_REMOTE_ADDR:
case TOKEN_LOCAL_PORT:
case TOKEN_REMOTE_PORT:
+ case TOKEN_PROTOCOL:
+ case TOKEN_LAYER:
+ case TOKEN_FLOW:
+ case TOKEN_NETWORK:
+ case TOKEN_NETWORK_FORWARD:
+ case TOKEN_REFLECT:
return FALSE;
default:
return TRUE;
@@ -867,10 +877,110 @@ static BOOL WinDivertCheckTokenKindForLayer(WINDIVERT_LAYER layer, KIND kind)
case TOKEN_IF_IDX:
case TOKEN_SUB_IF_IDX:
case TOKEN_IMPOSTOR:
+ case TOKEN_LAYER:
+ case TOKEN_FLOW:
+ case TOKEN_NETWORK:
+ case TOKEN_NETWORK_FORWARD:
+ case TOKEN_REFLECT:
return FALSE;
default:
return TRUE;
}
+ case WINDIVERT_LAYER_REFLECT:
+ switch (kind)
+ {
+ case TOKEN_ICMP_BODY:
+ case TOKEN_ICMP_CHECKSUM:
+ case TOKEN_ICMP_CODE:
+ case TOKEN_ICMP_TYPE:
+ case TOKEN_ICMPV6_BODY:
+ case TOKEN_ICMPV6_CHECKSUM:
+ case TOKEN_ICMPV6_CODE:
+ case TOKEN_ICMPV6_TYPE:
+ case TOKEN_IP_CHECKSUM:
+ case TOKEN_IP_DF:
+ case TOKEN_IP_DST_ADDR:
+ case TOKEN_IP_FRAG_OFF:
+ case TOKEN_IP_HDR_LENGTH:
+ case TOKEN_IP_ID:
+ case TOKEN_IP_LENGTH:
+ case TOKEN_IP_MF:
+ case TOKEN_IP_PROTOCOL:
+ case TOKEN_IP_SRC_ADDR:
+ case TOKEN_IP_TOS:
+ case TOKEN_IP_TTL:
+ case TOKEN_IPV6_DST_ADDR:
+ case TOKEN_IPV6_FLOW_LABEL:
+ case TOKEN_IPV6_HOP_LIMIT:
+ case TOKEN_IPV6_LENGTH:
+ case TOKEN_IPV6_NEXT_HDR:
+ case TOKEN_IPV6_SRC_ADDR:
+ case TOKEN_IPV6_TRAFFIC_CLASS:
+ case TOKEN_TCP_ACK:
+ case TOKEN_TCP_ACK_NUM:
+ case TOKEN_TCP_CHECKSUM:
+ case TOKEN_TCP_DST_PORT:
+ case TOKEN_TCP_FIN:
+ case TOKEN_TCP_HDR_LENGTH:
+ case TOKEN_TCP_PAYLOAD_LENGTH:
+ case TOKEN_TCP_PSH:
+ case TOKEN_TCP_RST:
+ case TOKEN_TCP_SEQ_NUM:
+ case TOKEN_TCP_SRC_PORT:
+ case TOKEN_TCP_SYN:
+ case TOKEN_TCP_URG:
+ case TOKEN_TCP_URG_PTR:
+ case TOKEN_TCP_WINDOW:
+ case TOKEN_UDP_CHECKSUM:
+ case TOKEN_UDP_DST_PORT:
+ case TOKEN_UDP_LENGTH:
+ case TOKEN_UDP_PAYLOAD_LENGTH:
+ case TOKEN_UDP_SRC_PORT:
+ case TOKEN_IP:
+ case TOKEN_IPV6:
+ case TOKEN_ICMP:
+ case TOKEN_ICMPV6:
+ case TOKEN_TCP:
+ case TOKEN_UDP:
+ case TOKEN_LOOPBACK:
+ case TOKEN_IF_IDX:
+ case TOKEN_SUB_IF_IDX:
+ case TOKEN_IMPOSTOR:
+ case TOKEN_INBOUND:
+ case TOKEN_OUTBOUND:
+ case TOKEN_LOCAL_ADDR:
+ case TOKEN_REMOTE_ADDR:
+ case TOKEN_LOCAL_PORT:
+ case TOKEN_REMOTE_PORT:
+ case TOKEN_PROTOCOL:
+ return FALSE;
+ default:
+ return TRUE;
+ }
+ default:
+ return FALSE;
+ }
+}
+
+/*
+ * Expand a "macro" value.
+ */
+static BOOL WinDivertExpandMacro(KIND kind, UINT32 *val)
+{
+ switch (kind)
+ {
+ case TOKEN_NETWORK:
+ *val = WINDIVERT_LAYER_NETWORK;
+ return TRUE;
+ case TOKEN_NETWORK_FORWARD:
+ *val = WINDIVERT_LAYER_NETWORK_FORWARD;
+ return TRUE;
+ case TOKEN_FLOW:
+ *val = WINDIVERT_LAYER_FLOW;
+ return TRUE;
+ case TOKEN_REFLECT:
+ *val = WINDIVERT_LAYER_REFLECT;
+ return TRUE;
default:
return FALSE;
}
@@ -884,6 +994,10 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{
static const TOKEN_NAME token_names[] =
{
+ {"FLOW", TOKEN_FLOW},
+ {"NETWORK", TOKEN_NETWORK},
+ {"NETWORK_FORWARD", TOKEN_NETWORK_FORWARD},
+ {"REFLECT", TOKEN_REFLECT},
{"and", TOKEN_AND},
{"false", TOKEN_FALSE},
{"icmp", TOKEN_ICMP},
@@ -920,6 +1034,7 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{"ipv6.NextHdr", TOKEN_IPV6_NEXT_HDR},
{"ipv6.SrcAddr", TOKEN_IPV6_SRC_ADDR},
{"ipv6.TrafficClass", TOKEN_IPV6_TRAFFIC_CLASS},
+ {"layer", TOKEN_LAYER},
{"localAddr", TOKEN_LOCAL_ADDR},
{"localPort", TOKEN_LOCAL_PORT},
{"loopback", TOKEN_LOOPBACK},
@@ -954,6 +1069,7 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{"udp.Length", TOKEN_UDP_LENGTH},
{"udp.PayloadLength", TOKEN_UDP_PAYLOAD_LENGTH},
{"udp.SrcPort", TOKEN_UDP_SRC_PORT},
+ {"zero", TOKEN_ZERO},
};
TOKEN_NAME *result;
char c;
@@ -1053,12 +1169,13 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
break;
}
token[0] = c;
- if (WinDivertIsAlNum(c) || c == '.' || c == ':')
+ if (WinDivertIsAlNum(c) || c == '.' || c == ':' || c == '_')
{
UINT32 num;
char *end;
for (j = 1; j < TOKEN_MAXLEN && (WinDivertIsAlNum(filter[i]) ||
- filter[i] == '.' || filter[i] == ':'); j++, i++)
+ filter[i] == '.' || filter[i] == ':' || filter[i] == '_');
+ j++, i++)
{
token[j] = filter[i];
}
@@ -1087,7 +1204,15 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{
return MAKE_ERROR(WINDIVERT_ERROR_BAD_TOKEN_FOR_LAYER, i-j);
}
- tokens[tp++].kind = result->kind;
+ if (WinDivertExpandMacro(result->kind, &tokens[tp].val[0]))
+ {
+ tokens[tp].kind = TOKEN_NUMBER;
+ }
+ else
+ {
+ tokens[tp].kind = result->kind;
+ }
+ tp++;
continue;
}
@@ -1135,26 +1260,10 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
}
}
-/*
- * Pool allocation.
- */
-static void *WinDivertAlloc(PPOOL pool, UINT size)
-{
- void *ptr;
- if (pool->offset + size >= sizeof(pool->memory))
- {
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
- return NULL;
- }
- ptr = pool->memory + pool->offset;
- pool->offset += size;
- return ptr;
-};
-
/*
* Construct a variable/field.
*/
-static PEXPR WinDivertMakeVar(PPOOL pool, KIND kind)
+static PEXPR WinDivertMakeVar(KIND kind, PERROR error)
{
// NOTE: must be in order of kind.
static const EXPR vars[] =
@@ -1212,6 +1321,7 @@ static PEXPR WinDivertMakeVar(PPOOL pool, KIND kind)
{{{0}}, TOKEN_UDP_LENGTH},
{{{0}}, TOKEN_UDP_PAYLOAD_LENGTH},
{{{0}}, TOKEN_UDP_SRC_PORT},
+ {{{0}}, TOKEN_ZERO},
{{{0}}, TOKEN_TRUE},
{{{0}}, TOKEN_FALSE},
{{{0}}, TOKEN_INBOUND},
@@ -1226,6 +1336,7 @@ static PEXPR WinDivertMakeVar(PPOOL pool, KIND kind)
{{{0}}, TOKEN_LOCAL_PORT},
{{{0}}, TOKEN_REMOTE_PORT},
{{{0}}, TOKEN_PROTOCOL},
+ {{{0}}, TOKEN_LAYER},
};
// Binary search:
@@ -1245,14 +1356,14 @@ static PEXPR WinDivertMakeVar(PPOOL pool, KIND kind)
}
return (PEXPR)(vars + mid);
}
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_ASSERTION_FAILED, 0);
+ *error = MAKE_ERROR(WINDIVERT_ERROR_ASSERTION_FAILED, 0);
return NULL;
}
/*
* Construct zero.
*/
-static PEXPR WinDivertMakeZero(PPOOL pool)
+static PEXPR WinDivertMakeZero(void)
{
static const EXPR zero = {{{0, 0, 0, 0}}, TOKEN_NUMBER};
return (PEXPR)&zero;
@@ -1261,44 +1372,39 @@ static PEXPR WinDivertMakeZero(PPOOL pool)
/*
* Construct a number.
*/
-static PEXPR WinDivertMakeNumber(PPOOL pool, TOKEN *tok)
+static PEXPR WinDivertMakeNumber(HANDLE pool, UINT32 *val, PERROR error)
{
- PEXPR expr;
- if (tok->kind != TOKEN_NUMBER)
- {
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_ASSERTION_FAILED, 0);
- return NULL;
- }
- expr = (PEXPR)WinDivertAlloc(pool, sizeof(EXPR));
+ PEXPR expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
if (expr == NULL)
{
+ *error = MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
return NULL;
}
- memset(expr, 0, sizeof(EXPR));
expr->kind = TOKEN_NUMBER;
- expr->val[0] = tok->val[0];
- expr->val[1] = tok->val[1];
- expr->val[2] = tok->val[2];
- expr->val[3] = tok->val[3];
+ expr->val[0] = val[0];
+ expr->val[1] = val[1];
+ expr->val[2] = val[2];
+ expr->val[3] = val[3];
return expr;
}
/*
* Construct a binary operator.
*/
-static PEXPR WinDivertMakeBinOp(PPOOL pool, KIND kind, PEXPR arg0, PEXPR arg1)
+static PEXPR WinDivertMakeBinOp(HANDLE pool, KIND kind, PEXPR arg0, PEXPR arg1,
+ PERROR error)
{
PEXPR expr;
if (arg0 == NULL || arg1 == NULL)
{
return NULL;
}
- expr = (PEXPR)WinDivertAlloc(pool, sizeof(EXPR));
+ expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
if (expr == NULL)
{
+ *error = MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
return NULL;
}
- memset(expr, 0, sizeof(EXPR));
expr->kind = kind;
expr->arg[0] = arg0;
expr->arg[1] = arg1;
@@ -1308,15 +1414,15 @@ static PEXPR WinDivertMakeBinOp(PPOOL pool, KIND kind, PEXPR arg0, PEXPR arg1)
/*
* Construct an if-then-else.
*/
-static PEXPR WinDivertMakeIfThenElse(PPOOL pool, PEXPR cond, PEXPR th,
- PEXPR el)
+static PEXPR WinDivertMakeIfThenElse(HANDLE pool, PEXPR cond, PEXPR th,
+ PEXPR el, PERROR error)
{
- PEXPR expr = (PEXPR)WinDivertAlloc(pool, sizeof(EXPR));
+ PEXPR expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
if (expr == NULL)
{
+ *error = MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
return NULL;
}
- memset(expr, 0, sizeof(EXPR));
expr->kind = TOKEN_QUESTION;
expr->arg[0] = cond;
expr->arg[1] = th;
@@ -1327,7 +1433,7 @@ static PEXPR WinDivertMakeIfThenElse(PPOOL pool, PEXPR cond, PEXPR th,
/*
* Parse a filter test.
*/
-static PEXPR WinDivertParseTest(PPOOL pool, TOKEN *toks, UINT *i)
+static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error)
{
PEXPR var, val;
KIND kind;
@@ -1339,6 +1445,7 @@ static PEXPR WinDivertParseTest(PPOOL pool, TOKEN *toks, UINT *i)
}
switch (toks[*i].kind)
{
+ case TOKEN_ZERO:
case TOKEN_TRUE:
case TOKEN_FALSE:
case TOKEN_OUTBOUND:
@@ -1359,6 +1466,7 @@ static PEXPR WinDivertParseTest(PPOOL pool, TOKEN *toks, UINT *i)
case TOKEN_LOCAL_PORT:
case TOKEN_REMOTE_PORT:
case TOKEN_PROTOCOL:
+ case TOKEN_LAYER:
case TOKEN_IP_HDR_LENGTH:
case TOKEN_IP_TOS:
case TOKEN_IP_LENGTH:
@@ -1408,11 +1516,10 @@ static PEXPR WinDivertParseTest(PPOOL pool, TOKEN *toks, UINT *i)
case TOKEN_UDP_PAYLOAD_LENGTH:
break;
default:
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN,
- toks[*i].pos);
+ *error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, toks[*i].pos);
return NULL;
}
- var = WinDivertMakeVar(pool, toks[*i].kind);
+ var = WinDivertMakeVar(toks[*i].kind, error);
*i = *i + 1;
switch (toks[*i].kind)
{
@@ -1426,7 +1533,7 @@ static PEXPR WinDivertParseTest(PPOOL pool, TOKEN *toks, UINT *i)
break;
default:
return WinDivertMakeBinOp(pool, (not? TOKEN_EQ: TOKEN_NEQ), var,
- WinDivertMakeZero(pool));
+ WinDivertMakeZero(), error);
}
if (not)
{
@@ -1457,31 +1564,31 @@ static PEXPR WinDivertParseTest(PPOOL pool, TOKEN *toks, UINT *i)
*i = *i + 1;
if (toks[*i].kind != TOKEN_NUMBER)
{
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN,
- toks[*i].pos);
+ *error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, toks[*i].pos);
return NULL;
}
- val = WinDivertMakeNumber(pool, toks + *i);
+ val = WinDivertMakeNumber(pool, toks[*i].val, error);
*i = *i + 1;
- return WinDivertMakeBinOp(pool, kind, var, val);
+ return WinDivertMakeBinOp(pool, kind, var, val, error);
}
/*
* Parse a filter argument to an (and) (or) operator.
*/
-static PEXPR WinDivertParseArg(PPOOL pool, TOKEN *toks, UINT *i, INT depth)
+static PEXPR WinDivertParseArg(HANDLE pool, TOKEN *toks, UINT *i, INT depth,
+ PERROR error)
{
PEXPR arg, th, el;
if (depth-- < 0)
{
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_TOO_DEEP, toks[*i].pos);
+ *error = MAKE_ERROR(WINDIVERT_ERROR_TOO_DEEP, toks[*i].pos);
return NULL;
}
switch (toks[*i].kind)
{
case TOKEN_OPEN:
*i = *i + 1;
- arg = WinDivertParseFilter(pool, toks, i, depth, FALSE);
+ arg = WinDivertParseFilter(pool, toks, i, depth, FALSE, error);
if (toks[*i].kind == TOKEN_CLOSE)
{
*i = *i + 1;
@@ -1490,57 +1597,56 @@ static PEXPR WinDivertParseArg(PPOOL pool, TOKEN *toks, UINT *i, INT depth)
if (toks[*i].kind == TOKEN_QUESTION)
{
*i = *i + 1;
- th = WinDivertParseFilter(pool, toks, i, depth, FALSE);
+ th = WinDivertParseFilter(pool, toks, i, depth, FALSE, error);
if (th == NULL)
{
return NULL;
}
if (toks[*i].kind != TOKEN_COLON)
{
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN,
+ *error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN,
toks[*i].pos);
return NULL;
}
*i = *i + 1;
- el = WinDivertParseFilter(pool, toks, i, depth, FALSE);
+ el = WinDivertParseFilter(pool, toks, i, depth, FALSE, error);
if (el == NULL)
{
return NULL;
}
if (toks[*i].kind != TOKEN_CLOSE)
{
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN,
+ *error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN,
toks[*i].pos);
return NULL;
}
*i = *i + 1;
- arg = WinDivertMakeIfThenElse(pool, arg, th, el);
+ arg = WinDivertMakeIfThenElse(pool, arg, th, el, error);
return arg;
}
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN,
- toks[*i].pos);
+ *error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, toks[*i].pos);
return NULL;
default:
- return WinDivertParseTest(pool, toks, i);
+ return WinDivertParseTest(pool, toks, i, error);
}
}
/*
* Parse the filter into an expression object.
*/
-static PEXPR WinDivertParseFilter(PPOOL pool, TOKEN *toks, UINT *i, INT depth,
- BOOL and)
+static PEXPR WinDivertParseFilter(HANDLE pool, TOKEN *toks, UINT *i, INT depth,
+ BOOL and, PERROR error)
{
PEXPR expr, arg;
if (depth-- < 0)
{
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_TOO_DEEP, toks[*i].pos);
+ *error = MAKE_ERROR(WINDIVERT_ERROR_TOO_DEEP, toks[*i].pos);
return NULL;
}
if (and)
- expr = WinDivertParseArg(pool, toks, i, depth);
+ expr = WinDivertParseArg(pool, toks, i, depth, error);
else
- expr = WinDivertParseFilter(pool, toks, i, depth, TRUE);
+ expr = WinDivertParseFilter(pool, toks, i, depth, TRUE, error);
do
{
if (expr == NULL)
@@ -1551,13 +1657,13 @@ static PEXPR WinDivertParseFilter(PPOOL pool, TOKEN *toks, UINT *i, INT depth,
{
case TOKEN_AND:
*i = *i + 1;
- arg = WinDivertParseArg(pool, toks, i, depth);
- expr = WinDivertMakeBinOp(pool, TOKEN_AND, expr, arg);
+ arg = WinDivertParseArg(pool, toks, i, depth, error);
+ expr = WinDivertMakeBinOp(pool, TOKEN_AND, expr, arg, error);
continue;
case TOKEN_OR:
*i = *i + 1;
- arg = WinDivertParseFilter(pool, toks, i, depth, TRUE);
- expr = WinDivertMakeBinOp(pool, TOKEN_OR, expr, arg);
+ arg = WinDivertParseFilter(pool, toks, i, depth, TRUE, error);
+ expr = WinDivertMakeBinOp(pool, TOKEN_OR, expr, arg, error);
continue;
default:
return expr;
@@ -1578,12 +1684,18 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
UINT32 lb, ub;
switch (var->kind)
{
+ case TOKEN_ZERO:
+ lb = ub = 0;
+ break;
case TOKEN_TRUE:
lb = ub = 1;
break;
case TOKEN_FALSE:
lb = ub = 0;
break;
+ case TOKEN_LAYER:
+ lb = 0; ub = WINDIVERT_LAYER_MAX;
+ break;
case TOKEN_INBOUND:
case TOKEN_OUTBOUND:
case TOKEN_IP:
@@ -1615,7 +1727,7 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
case TOKEN_ICMP_CODE:
case TOKEN_ICMPV6_TYPE:
case TOKEN_ICMPV6_CODE:
- case TOKEN_PROCESS_ID:
+ case TOKEN_PROTOCOL:
lb = 0; ub = 0xFF;
break;
case TOKEN_IP_FRAG_OFF:
@@ -1787,7 +1899,7 @@ static INT16 WinDivertFlattenExpr(PEXPR expr, INT16 *label, INT16 succ,
* Emit a test.
*/
static void WinDivertEmitTest(PEXPR test, UINT16 offset,
- windivert_ioctl_filter_t object)
+ PWINDIVERT_FILTER object)
{
PEXPR var = test->arg[0], val = test->arg[1];
switch (test->kind)
@@ -1815,6 +1927,9 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
}
switch (var->kind)
{
+ case TOKEN_ZERO:
+ object->field = WINDIVERT_FILTER_FIELD_ZERO;
+ break;
case TOKEN_OUTBOUND:
object->field = WINDIVERT_FILTER_FIELD_OUTBOUND;
break;
@@ -1848,6 +1963,12 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
case TOKEN_REMOTE_PORT:
object->field = WINDIVERT_FILTER_FIELD_REMOTEPORT;
break;
+ case TOKEN_PROTOCOL:
+ object->field = WINDIVERT_FILTER_FIELD_PROTOCOL;
+ break;
+ case TOKEN_LAYER:
+ object->field = WINDIVERT_FILTER_FIELD_LAYER;
+ break;
case TOKEN_IP:
object->field = WINDIVERT_FILTER_FIELD_IP;
break;
@@ -2041,7 +2162,7 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
* Emit a filter object.
*/
static void WinDivertEmitFilter(PEXPR *stack, UINT len, UINT16 label,
- windivert_ioctl_filter_t object, UINT *obj_len)
+ PWINDIVERT_FILTER object, UINT *obj_len)
{
UINT i;
switch (label)
@@ -2049,12 +2170,11 @@ static void WinDivertEmitFilter(PEXPR *stack, UINT len, UINT16 label,
case WINDIVERT_FILTER_RESULT_ACCEPT:
case WINDIVERT_FILTER_RESULT_REJECT:
object[0].field = WINDIVERT_FILTER_FIELD_ZERO;
- object[0].test = (label == WINDIVERT_FILTER_RESULT_ACCEPT?
- WINDIVERT_FILTER_TEST_EQ: WINDIVERT_FILTER_TEST_NEQ);
+ object[0].test = WINDIVERT_FILTER_TEST_EQ;
object[0].arg[0] = object[0].arg[1] = object[0].arg[2] =
object[0].arg[3] = 0;
- object[0].success = WINDIVERT_FILTER_RESULT_ACCEPT;
- object[0].failure = WINDIVERT_FILTER_RESULT_REJECT;
+ object[0].success = label;
+ object[0].failure = label;
*obj_len = 1;
return;
default:
@@ -2067,50 +2187,225 @@ static void WinDivertEmitFilter(PEXPR *stack, UINT len, UINT16 label,
}
}
+/*
+ * Analyze a filter object.
+ */
+static UINT64 WinDivertAnalyzeFilter(PWINDIVERT_FILTER filter, UINT length)
+{
+ BOOL result;
+ UINT64 flags = 0;
+
+ // False filter?
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_ZERO, 0);
+ if (!result)
+ {
+ return 0;
+ }
+
+ // Inbound?
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_INBOUND, 1);
+ if (result)
+ {
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_OUTBOUND, 0);
+ }
+ flags |= (result? WINDIVERT_FILTER_FLAG_INBOUND: 0);
+
+ // Outbound?
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_OUTBOUND, 1);
+ if (result)
+ {
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_INBOUND, 0);
+ }
+ flags |= (result? WINDIVERT_FILTER_FLAG_OUTBOUND: 0);
+
+ // IPv4?
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_IP, 1);
+ if (result)
+ {
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_IPV6, 0);
+ }
+ flags |= (result? WINDIVERT_FILTER_FLAG_IP: 0);
+
+ // Ipv6?
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_IPV6, 1);
+ if (result)
+ {
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_IP, 0);
+ }
+ flags |= (result? WINDIVERT_FILTER_FLAG_IPV6: 0);
+
+ return flags;
+}
+
+/*
+ * Execute a filter object with respect to an assumption/condition.
+ * FALSE = definite reject; TRUE = maybe accept.
+ */
+static BOOL WinDivertCondExecFilter(PWINDIVERT_FILTER filter, UINT length,
+ UINT8 field, UINT32 arg)
+{
+ INT16 ip;
+ UINT8 succ, fail;
+ BOOL result[WINDIVERT_FILTER_MAXLEN];
+ BOOL result_succ, result_fail, result_test;
+
+ if (length == 0)
+ {
+ return TRUE;
+ }
+
+ for (ip = (INT16)(length-1); ip >= 0; ip--)
+ {
+ succ = filter[ip].success;
+ if (succ == WINDIVERT_FILTER_RESULT_ACCEPT || succ <= ip ||
+ succ >= length)
+ {
+ result_succ = TRUE;
+ }
+ else if (succ == WINDIVERT_FILTER_RESULT_REJECT)
+ {
+ result_succ = FALSE;
+ }
+ else
+ {
+ result_succ = result[succ];
+ }
+
+ fail = filter[ip].failure;
+ if (fail == WINDIVERT_FILTER_RESULT_ACCEPT || fail <= ip ||
+ fail >= length)
+ {
+ result_fail = TRUE;
+ }
+ else if (fail == WINDIVERT_FILTER_RESULT_REJECT)
+ {
+ result_fail = FALSE;
+ }
+ else
+ {
+ result_fail = result[fail];
+ }
+
+ if (result_succ && result_fail)
+ {
+ result[ip] = TRUE;
+ }
+ else if (!result_succ && !result_fail)
+ {
+ result[ip] = FALSE;
+ }
+ else if (filter[ip].field == field)
+ {
+ switch (filter[ip].test)
+ {
+ case WINDIVERT_FILTER_TEST_EQ:
+ result_test = (arg == filter[ip].arg[0]);
+ break;
+ case WINDIVERT_FILTER_TEST_NEQ:
+ result_test = (arg != filter[ip].arg[0]);
+ break;
+ case WINDIVERT_FILTER_TEST_LT:
+ result_test = (arg < filter[ip].arg[0]);
+ break;
+ case WINDIVERT_FILTER_TEST_LEQ:
+ result_test = (arg <= filter[ip].arg[0]);
+ break;
+ case WINDIVERT_FILTER_TEST_GT:
+ result_test = (arg > filter[ip].arg[0]);
+ break;
+ case WINDIVERT_FILTER_TEST_GEQ:
+ result_test = (arg >= filter[ip].arg[0]);
+ break;
+ default:
+ return TRUE; // abort.
+ }
+ result[ip] = (result_test? result_succ: result_fail);
+ }
+ else
+ {
+ result[ip] = TRUE;
+ }
+ }
+
+ return result[0];
+}
+
/*
* Compile a filter string into an executable filter object.
*/
static ERROR WinDivertCompileFilter(const char *filter,
- WINDIVERT_LAYER layer, windivert_ioctl_filter_t object, UINT *obj_len)
+ WINDIVERT_LAYER layer, PWINDIVERT_FILTER object, UINT *obj_len)
{
- TOKEN tokens[WINDIVERT_FILTER_MAXLEN*3];
- PEXPR stack[WINDIVERT_FILTER_MAXLEN];
- PPOOL pool;
+ TOKEN *tokens;
+ PEXPR *stack;
+ HANDLE pool;
PEXPR expr;
UINT i, max_depth;
INT16 label;
+ const SIZE_T min_pool_size = 8192;
+ const SIZE_T tokens_size = 5 * WINDIVERT_FILTER_MAXLEN;
ERROR error;
- // Tokenize the filter string:
- error = WinDivertTokenizeFilter(filter, layer, tokens,
- sizeof(tokens) / sizeof(tokens[0]) - 1);
- if (IS_ERROR(error))
+ // Check for pre-compiled filter object:
+ if (filter[0] == '@')
{
- return error;
+ WINDIVERT_STREAM stream;
+ stream.data = (char *)filter;
+ stream.pos = 0;
+ stream.max = UINT_MAX;
+ stream.overflow = FALSE;
+
+ if (!WinDivertDeserializeFilter(&stream, object, obj_len))
+ {
+ return MAKE_ERROR(WINDIVERT_ERROR_BAD_OBJECT, 0);
+ }
+ return MAKE_ERROR(WINDIVERT_ERROR_NONE, 0);
}
- // Allocate memory pool for the compiler:
- pool = (PPOOL)HeapAlloc(GetProcessHeap(), 0, sizeof(POOL));
+ // Allocate memory for the compiler:
+ pool = HeapCreate(HEAP_NO_SERIALIZE, min_pool_size, 16 * min_pool_size);
if (pool == NULL)
{
return MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
}
- pool->offset = 0;
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_NONE, 0);
+ tokens = (TOKEN *)HeapAlloc(pool, 0, tokens_size * sizeof(TOKEN));
+ stack = (PEXPR *)HeapAlloc(pool, 0,
+ WINDIVERT_FILTER_MAXLEN * sizeof(PEXPR));
+ if (tokens == NULL || stack == NULL)
+ {
+ HeapDestroy(pool);
+ return MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
+ }
+
+ // Tokenize the filter string:
+ error = WinDivertTokenizeFilter(filter, layer, tokens, tokens_size-1);
+ if (IS_ERROR(error))
+ {
+ HeapDestroy(pool);
+ return error;
+ }
// Parse the filter into an expression:
i = 0;
max_depth = 1024;
- expr = WinDivertParseFilter(pool, tokens, &i, max_depth, FALSE);
+ expr = WinDivertParseFilter(pool, tokens, &i, max_depth, FALSE, &error);
if (expr == NULL)
{
- error = pool->error;
- HeapFree(GetProcessHeap(), 0, pool);
+ HeapDestroy(pool);
return error;
}
if (tokens[i].kind != TOKEN_END)
{
- HeapFree(GetProcessHeap(), 0, pool);
+ HeapDestroy(pool);
return MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, tokens[i].pos);
}
@@ -2120,7 +2415,7 @@ static ERROR WinDivertCompileFilter(const char *filter,
WINDIVERT_FILTER_RESULT_REJECT, stack);
if (label < 0)
{
- HeapFree(GetProcessHeap(), 0, pool);
+ HeapDestroy(pool);
return MAKE_ERROR(WINDIVERT_ERROR_TOO_LONG, 0);
}
@@ -2129,7 +2424,7 @@ static ERROR WinDivertCompileFilter(const char *filter,
{
WinDivertEmitFilter(stack, label, label, object, obj_len);
}
- HeapFree(GetProcessHeap(), 0, pool);
+ HeapDestroy(pool);
return MAKE_ERROR(WINDIVERT_ERROR_NONE, 0);
}
@@ -2157,6 +2452,8 @@ static const char *WinDivertErrorString(UINT code)
return "Filter expression parse error";
case WINDIVERT_ERROR_OUTPUT_TOO_SHORT:
return "Filter object buffer is too short";
+ case WINDIVERT_ERROR_BAD_OBJECT:
+ return "Filter object is invalid";
case WINDIVERT_ERROR_ASSERTION_FAILED:
return "Internal assertion failed";
default:
@@ -2165,10 +2462,11 @@ static const char *WinDivertErrorString(UINT code)
}
/*
- * Check the given filter string.
+ * Compile the given filter string.
*/
-extern BOOL WinDivertHelperCheckFilter(const char *filter_str,
- WINDIVERT_LAYER layer, const char **error, UINT *error_pos)
+extern BOOL WinDivertHelperCompileFilter(const char *filter_str,
+ WINDIVERT_LAYER layer, char *object, UINT obj_len, const char **error,
+ UINT *error_pos)
{
ERROR err;
if (filter_str == NULL)
@@ -2176,7 +2474,33 @@ extern BOOL WinDivertHelperCheckFilter(const char *filter_str,
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- err = WinDivertCompileFilter(filter_str, layer, NULL, NULL);
+
+ SetLastError(ERROR_SUCCESS);
+ if (object == NULL)
+ {
+ err = WinDivertCompileFilter(filter_str, layer, NULL, NULL);
+ }
+ else
+ {
+ WINDIVERT_FILTER object0[WINDIVERT_FILTER_MAXLEN];
+ UINT obj0_len;
+ err = WinDivertCompileFilter(filter_str, layer, object0, &obj0_len);
+ if (!IS_ERROR(err))
+ {
+ WINDIVERT_STREAM stream;
+ stream.data = object;
+ stream.pos = 0;
+ stream.max = obj_len;
+ stream.overflow = FALSE;
+
+ WinDivertSerializeFilter(&stream, object0, obj0_len);
+ if (stream.overflow)
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ err = MAKE_ERROR(WINDIVERT_ERROR_OUTPUT_TOO_SHORT, 0);
+ }
+ }
+ }
if (error != NULL)
{
*error = WinDivertErrorString(GET_CODE(err));
@@ -2246,7 +2570,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
UINT32 val[4];
BOOL pass;
int cmp;
- struct windivert_ioctl_filter_s object[WINDIVERT_FILTER_MAXLEN];
+ WINDIVERT_FILTER object[WINDIVERT_FILTER_MAXLEN];
UINT obj_len;
if (filter == NULL || addr == NULL)
@@ -2279,6 +2603,8 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
return FALSE;
}
break;
+ case WINDIVERT_LAYER_REFLECT:
+ break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
@@ -2648,3 +2974,1134 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
}
}
+/*
+ * Get a char from a stream.
+ */
+static char WinDivertGetChar(PWINDIVERT_STREAM stream)
+{
+ char c;
+ if (stream->pos >= stream->max)
+ {
+ stream->overflow = TRUE;
+ return EOF;
+ }
+ c = stream->data[stream->pos];
+ stream->pos++;
+ return c;
+}
+
+/*
+ * Deserialize a number.
+ */
+static BOOL WinDivertDeserializeNumber(PWINDIVERT_STREAM stream, UINT max_len,
+ UINT32 *result)
+{
+ UINT32 i, val = 0;
+ char c;
+ for (i = 0; i < max_len; i++)
+ {
+ if ((val & 0xF8000000) != 0)
+ {
+ return FALSE; // Overflow
+ }
+ val <<= 5;
+ c = WinDivertGetChar(stream);
+ if (c >= '!' && c <= '!' + 31)
+ {
+ val += (UINT32)(c - '!');
+ }
+ else if (c >= '!' + 32 && c <= '!' + 64)
+ {
+ val += (UINT32)(c - '!' - 32);
+ *result = val;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Deserialize a test.
+ */
+static BOOL WinDivertDeserializeTest(PWINDIVERT_STREAM stream,
+ PWINDIVERT_FILTER filter)
+{
+ UINT32 val;
+ UINT i;
+
+ if (WinDivertGetChar(stream) != '_')
+ {
+ return FALSE;
+ }
+
+ if (!WinDivertDeserializeNumber(stream, 2, &val) ||
+ val > WINDIVERT_FILTER_FIELD_MAX)
+ {
+ return FALSE;
+ }
+ filter->field = (UINT8)val;
+
+ if (!WinDivertDeserializeNumber(stream, 2, &val) ||
+ val > WINDIVERT_FILTER_TEST_MAX)
+ {
+ return FALSE;
+ }
+ filter->test = (UINT8)val;
+
+ if (!WinDivertDeserializeNumber(stream, 7, &filter->arg[0]))
+ {
+ return FALSE;
+ }
+
+ switch (filter->field)
+ {
+ case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
+ case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
+ case WINDIVERT_FILTER_FIELD_LOCALADDR:
+ case WINDIVERT_FILTER_FIELD_REMOTEADDR:
+ for (i = 1; i < 4; i++)
+ {
+ if (!WinDivertDeserializeNumber(stream, 7, &filter->arg[i]))
+ {
+ return FALSE;
+ }
+ }
+ break;
+ case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
+ case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
+ filter->arg[1] = 0x0000FFFF;
+ filter->arg[2] = filter->arg[3] = 0;
+ break;
+ default:
+ filter->arg[1] = filter->arg[2] = filter->arg[3] = 0;
+ break;
+ }
+
+ if (!WinDivertDeserializeNumber(stream, 2, &val) || val > UINT8_MAX)
+ {
+ return FALSE;
+ }
+ filter->success = (UINT8)val - 2;
+
+ if (!WinDivertDeserializeNumber(stream, 2, &val) || val > UINT8_MAX)
+ {
+ return FALSE;
+ }
+ filter->failure = (UINT8)val - 2;
+
+ return TRUE;
+}
+
+/*
+ * Deserialize a filter header.
+ */
+static BOOL WinDivertDeserializeFilterHeader(PWINDIVERT_STREAM stream,
+ UINT *length)
+{
+ UINT32 version, length32;
+
+ if (WinDivertGetChar(stream) != '@' ||
+ WinDivertGetChar(stream) != 'W' ||
+ WinDivertGetChar(stream) != 'i' ||
+ WinDivertGetChar(stream) != 'n' ||
+ WinDivertGetChar(stream) != 'D' ||
+ WinDivertGetChar(stream) != 'i' ||
+ WinDivertGetChar(stream) != 'v' ||
+ WinDivertGetChar(stream) != '_')
+ {
+ return FALSE;
+ }
+
+ if (!WinDivertDeserializeNumber(stream, 4, &version) || (version != 0))
+ {
+ return FALSE;
+ }
+
+ if (!WinDivertDeserializeNumber(stream, 2, &length32) ||
+ length32 == 0 || length32 > WINDIVERT_FILTER_MAXLEN)
+ {
+ return FALSE;
+ }
+ *length = length32;
+
+ return TRUE;
+}
+
+/*
+ * Deserialize a filter.
+ */
+static BOOL WinDivertDeserializeFilter(PWINDIVERT_STREAM stream,
+ PWINDIVERT_FILTER filter, UINT *length)
+{
+ UINT i;
+
+ if (!WinDivertDeserializeFilterHeader(stream, length))
+ {
+ return FALSE;
+ }
+
+ for (i = 0; i < *length; i++)
+ {
+ if (!WinDivertDeserializeTest(stream, filter + i))
+ {
+ return FALSE;
+ }
+ }
+
+ if (WinDivertGetChar(stream) != '\0')
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Decompile a test into an expression.
+ */
+static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test)
+{
+ KIND kind;
+ PEXPR var, val, expr;
+ ERROR error;
+
+ switch (test->field)
+ {
+ case WINDIVERT_FILTER_FIELD_ZERO:
+ kind = TOKEN_ZERO; break;
+ case WINDIVERT_FILTER_FIELD_INBOUND:
+ kind = TOKEN_INBOUND; break;
+ case WINDIVERT_FILTER_FIELD_OUTBOUND:
+ kind = TOKEN_OUTBOUND; break;
+ case WINDIVERT_FILTER_FIELD_IFIDX:
+ kind = TOKEN_IF_IDX; break;
+ case WINDIVERT_FILTER_FIELD_SUBIFIDX:
+ kind = TOKEN_SUB_IF_IDX; break;
+ case WINDIVERT_FILTER_FIELD_IP:
+ kind = TOKEN_IP; break;
+ case WINDIVERT_FILTER_FIELD_IPV6:
+ kind = TOKEN_IPV6; break;
+ case WINDIVERT_FILTER_FIELD_ICMP:
+ kind = TOKEN_ICMP; break;
+ case WINDIVERT_FILTER_FIELD_TCP:
+ kind = TOKEN_TCP; break;
+ case WINDIVERT_FILTER_FIELD_UDP:
+ kind = TOKEN_UDP; break;
+ case WINDIVERT_FILTER_FIELD_ICMPV6:
+ kind = TOKEN_ICMPV6; break;
+ case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
+ kind = TOKEN_IP_HDR_LENGTH; break;
+ case WINDIVERT_FILTER_FIELD_IP_TOS:
+ kind = TOKEN_IP_TOS; break;
+ case WINDIVERT_FILTER_FIELD_IP_LENGTH:
+ kind = TOKEN_IP_LENGTH; break;
+ case WINDIVERT_FILTER_FIELD_IP_ID:
+ kind = TOKEN_IP_ID; break;
+ case WINDIVERT_FILTER_FIELD_IP_DF:
+ kind = TOKEN_IP_DF; break;
+ case WINDIVERT_FILTER_FIELD_IP_MF:
+ kind = TOKEN_IP_MF; break;
+ case WINDIVERT_FILTER_FIELD_IP_FRAGOFF:
+ kind = TOKEN_IP_FRAG_OFF; break;
+ case WINDIVERT_FILTER_FIELD_IP_TTL:
+ kind = TOKEN_IP_TTL; break;
+ case WINDIVERT_FILTER_FIELD_IP_PROTOCOL:
+ kind = TOKEN_IP_PROTOCOL; break;
+ case WINDIVERT_FILTER_FIELD_IP_CHECKSUM:
+ kind = TOKEN_IP_CHECKSUM; break;
+ case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
+ kind = TOKEN_IP_SRC_ADDR; break;
+ case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
+ kind = TOKEN_IP_DST_ADDR; break;
+ case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS:
+ kind = TOKEN_IPV6_TRAFFIC_CLASS; break;
+ case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL:
+ kind = TOKEN_IPV6_FLOW_LABEL; break;
+ case WINDIVERT_FILTER_FIELD_IPV6_LENGTH:
+ kind = TOKEN_IPV6_LENGTH; break;
+ case WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR:
+ kind = TOKEN_IPV6_NEXT_HDR; break;
+ case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT:
+ kind = TOKEN_IPV6_HOP_LIMIT; break;
+ case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
+ kind = TOKEN_IPV6_SRC_ADDR; break;
+ case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
+ kind = TOKEN_IPV6_DST_ADDR; break;
+ case WINDIVERT_FILTER_FIELD_ICMP_TYPE:
+ kind = TOKEN_ICMP_TYPE; break;
+ case WINDIVERT_FILTER_FIELD_ICMP_CODE:
+ kind = TOKEN_ICMP_CODE; break;
+ case WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM:
+ kind = TOKEN_ICMP_CHECKSUM; break;
+ case WINDIVERT_FILTER_FIELD_ICMP_BODY:
+ kind = TOKEN_ICMP_BODY; break;
+ case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE:
+ kind = TOKEN_ICMPV6_TYPE; break;
+ case WINDIVERT_FILTER_FIELD_ICMPV6_CODE:
+ kind = TOKEN_ICMPV6_CODE; break;
+ case WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM:
+ kind = TOKEN_ICMPV6_CHECKSUM; break;
+ case WINDIVERT_FILTER_FIELD_ICMPV6_BODY:
+ kind = TOKEN_ICMPV6_BODY; break;
+ case WINDIVERT_FILTER_FIELD_TCP_SRCPORT:
+ kind = TOKEN_TCP_SRC_PORT; break;
+ case WINDIVERT_FILTER_FIELD_TCP_DSTPORT:
+ kind = TOKEN_TCP_DST_PORT; break;
+ case WINDIVERT_FILTER_FIELD_TCP_SEQNUM:
+ kind = TOKEN_TCP_SEQ_NUM; break;
+ case WINDIVERT_FILTER_FIELD_TCP_ACKNUM:
+ kind = TOKEN_TCP_ACK_NUM; break;
+ case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH:
+ kind = TOKEN_TCP_HDR_LENGTH; break;
+ case WINDIVERT_FILTER_FIELD_TCP_URG:
+ kind = TOKEN_TCP_URG; break;
+ case WINDIVERT_FILTER_FIELD_TCP_ACK:
+ kind = TOKEN_TCP_ACK; break;
+ case WINDIVERT_FILTER_FIELD_TCP_PSH:
+ kind = TOKEN_TCP_PSH; break;
+ case WINDIVERT_FILTER_FIELD_TCP_RST:
+ kind = TOKEN_TCP_RST; break;
+ case WINDIVERT_FILTER_FIELD_TCP_SYN:
+ kind = TOKEN_TCP_SYN; break;
+ case WINDIVERT_FILTER_FIELD_TCP_FIN:
+ kind = TOKEN_TCP_FIN; break;
+ case WINDIVERT_FILTER_FIELD_TCP_WINDOW:
+ kind = TOKEN_TCP_WINDOW; break;
+ case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
+ kind = TOKEN_TCP_CHECKSUM; break;
+ case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
+ kind = TOKEN_TCP_URG_PTR; break;
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
+ kind = TOKEN_TCP_PAYLOAD_LENGTH; break;
+ case WINDIVERT_FILTER_FIELD_UDP_SRCPORT:
+ kind = TOKEN_UDP_SRC_PORT; break;
+ case WINDIVERT_FILTER_FIELD_UDP_DSTPORT:
+ kind = TOKEN_UDP_DST_PORT; break;
+ case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
+ kind = TOKEN_UDP_LENGTH; break;
+ case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
+ kind = TOKEN_UDP_CHECKSUM; break;
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
+ kind = TOKEN_UDP_PAYLOAD_LENGTH; break;
+ case WINDIVERT_FILTER_FIELD_LOOPBACK:
+ kind = TOKEN_LOOPBACK; break;
+ case WINDIVERT_FILTER_FIELD_IMPOSTOR:
+ kind = TOKEN_IMPOSTOR; break;
+ case WINDIVERT_FILTER_FIELD_PROCESSID:
+ kind = TOKEN_PROCESS_ID; break;
+ case WINDIVERT_FILTER_FIELD_LOCALADDR:
+ kind = TOKEN_LOCAL_ADDR; break;
+ case WINDIVERT_FILTER_FIELD_REMOTEADDR:
+ kind = TOKEN_REMOTE_ADDR; break;
+ case WINDIVERT_FILTER_FIELD_LOCALPORT:
+ kind = TOKEN_LOCAL_PORT; break;
+ case WINDIVERT_FILTER_FIELD_REMOTEPORT:
+ kind = TOKEN_REMOTE_PORT; break;
+ case WINDIVERT_FILTER_FIELD_PROTOCOL:
+ kind = TOKEN_PROTOCOL; break;
+ case WINDIVERT_FILTER_FIELD_LAYER:
+ kind = TOKEN_LAYER; break;
+ default:
+ return NULL;
+ }
+
+ var = WinDivertMakeVar(kind, &error);
+ if (var == NULL)
+ {
+ return NULL;
+ }
+ val = WinDivertMakeNumber(pool, test->arg, &error);
+ if (val == NULL)
+ {
+ return NULL;
+ }
+
+ switch (test->test)
+ {
+ case WINDIVERT_FILTER_TEST_EQ:
+ kind = TOKEN_EQ; break;
+ case WINDIVERT_FILTER_TEST_NEQ:
+ kind = TOKEN_NEQ; break;
+ case WINDIVERT_FILTER_TEST_LT:
+ kind = TOKEN_LT; break;
+ case WINDIVERT_FILTER_TEST_LEQ:
+ kind = TOKEN_LEQ; break;
+ case WINDIVERT_FILTER_TEST_GT:
+ kind = TOKEN_GT; break;
+ case WINDIVERT_FILTER_TEST_GEQ:
+ kind = TOKEN_GEQ; break;
+ default:
+ return NULL;
+ }
+
+ expr = WinDivertMakeBinOp(pool, kind, var, val, &error);
+ if (expr == NULL)
+ {
+ return NULL;
+ }
+ expr->succ = test->success;
+ expr->fail = test->failure;
+ return expr;
+}
+
+/*
+ * Dereference an expression.
+ */
+static void WinDivertDerefExpr(PEXPR *exprs, UINT8 i)
+{
+ switch (i)
+ {
+ case WINDIVERT_FILTER_RESULT_ACCEPT:
+ case WINDIVERT_FILTER_RESULT_REJECT:
+ return;
+ default:
+ exprs[i]->count--;
+ if (exprs[i]->count == 0)
+ {
+ exprs[i] = NULL;
+ }
+ return;
+ }
+}
+
+/*
+ * Apply an and/or simplification for WinDivertCoalesceAndOr().
+ */
+static PEXPR WinDivertSimplifyAndOr(HANDLE pool, PEXPR *exprs, PEXPR expr,
+ BOOL and, UINT8 next, UINT8 other)
+{
+ PEXPR next_expr = exprs[next], new_expr;
+ ERROR error;
+
+ new_expr = WinDivertMakeBinOp(pool, (and? TOKEN_AND: TOKEN_OR), expr,
+ next_expr, &error);
+ if (new_expr == NULL)
+ {
+ return NULL;
+ }
+ new_expr->succ = next_expr->succ;
+ new_expr->fail = next_expr->fail;
+ new_expr->count = expr->count;
+ WinDivertDerefExpr(exprs, next);
+ WinDivertDerefExpr(exprs, other);
+ return new_expr;
+}
+
+/*
+ * Detect and coalesce and/or (& (?:)) expression patterns.
+ */
+static PEXPR WinDivertCoalesceAndOr(HANDLE pool, PEXPR *exprs, UINT8 i,
+ ERROR *error)
+{
+ PEXPR expr, next_expr, new_expr;
+ BOOL singleton;
+ static const EXPR true_expr = {{{0}}, TOKEN_TRUE};
+
+ expr = exprs[i];
+ while (TRUE)
+ {
+ if (expr == NULL || expr->count == 0)
+ {
+ return NULL;
+ }
+
+ singleton = FALSE;
+ switch (expr->succ)
+ {
+ case WINDIVERT_FILTER_RESULT_ACCEPT:
+ case WINDIVERT_FILTER_RESULT_REJECT:
+ break;
+ default:
+ next_expr = exprs[expr->succ];
+ if (next_expr->count != 1)
+ {
+ break;
+ }
+ singleton = TRUE;
+ if (next_expr->fail == expr->fail)
+ {
+ expr = WinDivertSimplifyAndOr(pool, exprs, expr,
+ /*and=*/TRUE, expr->succ, expr->fail);
+ continue;
+ }
+ else if (next_expr->succ == expr->fail)
+ {
+ new_expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY,
+ sizeof(EXPR));
+ if (new_expr == NULL)
+ {
+ return NULL;
+ }
+ new_expr->kind = TOKEN_QUESTION;
+ new_expr->arg[0] = expr;
+ new_expr->arg[1] = next_expr;
+ new_expr->arg[2] = (PEXPR)&true_expr;
+ new_expr->succ = next_expr->succ;
+ new_expr->fail = next_expr->fail;
+ new_expr->count = expr->count;
+ WinDivertDerefExpr(exprs, expr->succ);
+ WinDivertDerefExpr(exprs, expr->fail);
+ expr = new_expr;
+ continue;
+ }
+ break;
+ }
+ switch (expr->fail)
+ {
+ case WINDIVERT_FILTER_RESULT_ACCEPT:
+ case WINDIVERT_FILTER_RESULT_REJECT:
+ singleton = FALSE;
+ break;
+ default:
+ next_expr = exprs[expr->fail];
+ if (next_expr->count != 1)
+ {
+ singleton = FALSE;
+ break;
+ }
+ if (next_expr->succ == expr->succ)
+ {
+ expr = WinDivertSimplifyAndOr(pool, exprs, expr,
+ /*and=*/FALSE, expr->fail, expr->succ);
+ continue;
+ }
+ else if (next_expr->fail == expr->succ)
+ {
+ expr = WinDivertSimplifyAndOr(pool, exprs, expr,
+ /*and=*/TRUE, expr->fail, expr->succ);
+ continue;
+ }
+ break;
+ }
+
+ if (singleton)
+ {
+ // Both branches have count==1; simplify into a (?:) expression:
+ PEXPR succ_expr, fail_expr;
+ succ_expr = exprs[expr->succ];
+ fail_expr = exprs[expr->fail];
+ if (succ_expr->succ != fail_expr->succ ||
+ succ_expr->fail != fail_expr->fail)
+ {
+ break;
+ }
+ new_expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
+ if (new_expr == NULL)
+ {
+ return NULL;
+ }
+ new_expr->kind = TOKEN_QUESTION;
+ new_expr->arg[0] = expr;
+ new_expr->arg[1] = succ_expr;
+ new_expr->arg[2] = fail_expr;
+ new_expr->succ = succ_expr->succ;
+ new_expr->fail = fail_expr->fail;
+ new_expr->count = expr->count;
+ WinDivertDerefExpr(exprs, expr->succ);
+ WinDivertDerefExpr(exprs, expr->fail);
+ WinDivertDerefExpr(exprs, new_expr->succ);
+ WinDivertDerefExpr(exprs, new_expr->fail);
+ expr = new_expr;
+ continue;
+ }
+
+ // No simplifications, so we are done.
+ break;
+ }
+
+ exprs[i] = expr;
+ return expr;
+}
+
+/*
+ * Coalesce all remaining expressions.
+ */
+static PEXPR WinDivertCoalesceExpr(HANDLE pool, PEXPR *exprs, UINT8 i)
+{
+ PEXPR expr, succ_expr, fail_expr, new_expr;
+ static const EXPR true_expr = {{{0}}, TOKEN_TRUE};
+ static const EXPR false_expr = {{{0}}, TOKEN_FALSE};
+
+ switch (i)
+ {
+ case WINDIVERT_FILTER_RESULT_ACCEPT:
+ return (PEXPR)&true_expr;
+ case WINDIVERT_FILTER_RESULT_REJECT:
+ return (PEXPR)&false_expr;
+ default:
+ break;
+ }
+
+ expr = exprs[i];
+ if (expr == NULL)
+ {
+ return NULL;
+ }
+
+ if (expr->succ == expr->fail)
+ {
+ return WinDivertCoalesceExpr(pool, exprs, expr->succ);
+ }
+
+ succ_expr = WinDivertCoalesceExpr(pool, exprs, expr->succ);
+ fail_expr = WinDivertCoalesceExpr(pool, exprs, expr->fail);
+ if (succ_expr == NULL || fail_expr == NULL)
+ {
+ return NULL;
+ }
+ if (succ_expr->kind == TOKEN_TRUE && fail_expr->kind == TOKEN_FALSE)
+ {
+ return expr;
+ }
+
+ new_expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
+ if (new_expr == NULL)
+ {
+ return NULL;
+ }
+
+ new_expr->kind = TOKEN_QUESTION;
+ new_expr->arg[0] = expr;
+ new_expr->arg[1] = succ_expr;
+ new_expr->arg[2] = fail_expr;
+ return new_expr;
+}
+
+/*
+ * Format a decimal number.
+ */
+static void WinDivertFormatNumber(PWINDIVERT_STREAM stream, UINT32 val)
+{
+ UINT64 r = 1000000000, dig;
+ BOOL zeroes = FALSE;
+
+ while (r != 0)
+ {
+ dig = val / r;
+ val = val % r;
+ r = r / 10;
+ if (dig == 0 && !zeroes && r != 0)
+ {
+ continue;
+ }
+ WinDivertPutChar(stream, '0' + dig);
+ zeroes = TRUE;
+ }
+}
+
+/*
+ * Format a hexidecimal number.
+ */
+static void WinDivertFormatHexNumber(PWINDIVERT_STREAM stream, UINT32 val)
+{
+ INT s = 28;
+ UINT32 dig;
+ BOOL zeroes = FALSE;
+
+ while (s >= 0)
+ {
+ dig = (val & ((UINT32)0xF << s)) >> s;
+ s -= 4;
+ if (dig == 0 && !zeroes && s >= 0)
+ {
+ continue;
+ }
+ WinDivertPutChar(stream, (dig <= 9? '0' + dig: 'a' + (dig - 10)));
+ zeroes = TRUE;
+ }
+}
+
+/*
+ * Format an IPv4 address.
+ */
+static void WinDivertFormatIPv4Addr(PWINDIVERT_STREAM stream, UINT32 addr)
+{
+ WinDivertFormatNumber(stream, (addr & 0xFF000000) >> 24);
+ WinDivertPutChar(stream, '.');
+ WinDivertFormatNumber(stream, (addr & 0x00FF0000) >> 16);
+ WinDivertPutChar(stream, '.');
+ WinDivertFormatNumber(stream, (addr & 0x0000FF00) >> 8);
+ WinDivertPutChar(stream, '.');
+ WinDivertFormatNumber(stream, (addr & 0x000000FF) >> 0);
+}
+
+/*
+ * Format an IPv6 address.
+ */
+static void WinDivertFormatIPv6Addr(PWINDIVERT_STREAM stream,
+ const UINT32 *addr32)
+{
+ INT i, z_curr, z_count, z_start, z_max;
+ UINT16 addr[8];
+
+ // IPv4 special case:
+ if (addr32[3] == 0 && addr32[2] == 0 && addr32[1] == 0x0000FFFF)
+ {
+ WinDivertFormatIPv4Addr(stream, addr32[0]);
+ return;
+ }
+
+ // Find zeroes:
+ memcpy(addr, addr32, sizeof(addr));
+ z_curr = 7;
+ z_count = 0;
+ z_start = z_max = -1;
+ for (i = 7; i >= 0; i--)
+ {
+ if (addr[i] == 0)
+ {
+ z_count++;
+ z_start = (z_count > z_max? z_curr: z_start);
+ z_max = (z_count > z_max? z_count: z_max);
+ }
+ else
+ {
+ z_curr = i-1;
+ z_count = 0;
+ }
+ }
+
+ // Format address:
+ for (i = 7; i >= 0; i--)
+ {
+ if (i == z_start)
+ {
+ WinDivertPutString(stream, (i == 7? "::": ":"));
+ i -= (z_max-1);
+ continue;
+ }
+ WinDivertFormatHexNumber(stream, addr[i]);
+ WinDivertPutString(stream, (i != 0? ":": ""));
+ }
+}
+
+/*
+ * Format a test expression.
+ */
+static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr)
+{
+ PEXPR field = expr->arg[0], val = expr->arg[1];
+ BOOL ipv4_addr = FALSE, ipv6_addr = FALSE, layer = FALSE;
+
+ switch (field->kind)
+ {
+ case TOKEN_ZERO:
+ case TOKEN_INBOUND:
+ case TOKEN_OUTBOUND:
+ case TOKEN_IP:
+ case TOKEN_IPV6:
+ case TOKEN_ICMP:
+ case TOKEN_TCP:
+ case TOKEN_UDP:
+ case TOKEN_ICMPV6:
+ case TOKEN_IP_DF:
+ case TOKEN_IP_MF:
+ case TOKEN_TCP_URG:
+ case TOKEN_TCP_ACK:
+ case TOKEN_TCP_PSH:
+ case TOKEN_TCP_RST:
+ case TOKEN_TCP_SYN:
+ case TOKEN_TCP_FIN:
+ case TOKEN_LOOPBACK:
+ case TOKEN_IMPOSTOR:
+ if (val->val[1] != 0 || val->val[2] != 0 || val->val[3] != 0 ||
+ val->val[0] > 1)
+ {
+ break;
+ }
+ switch (expr->kind)
+ {
+ case TOKEN_EQ:
+ WinDivertPutString(stream, (val->val[0] == 0? "not ": ""));
+ WinDivertFormatExpr(stream, field, /*top_level=*/FALSE,
+ /*and=*/FALSE);
+ return;
+ case TOKEN_NEQ:
+ WinDivertPutString(stream, (val->val[0] != 0? "not ": ""));
+ WinDivertFormatExpr(stream, field, /*top_level=*/FALSE,
+ /*and=*/FALSE);
+ return;
+ default:
+ break;
+ }
+ break;
+ case TOKEN_IP_SRC_ADDR:
+ case TOKEN_IP_DST_ADDR:
+ ipv4_addr = TRUE;
+ break;
+ case TOKEN_IPV6_SRC_ADDR:
+ case TOKEN_IPV6_DST_ADDR:
+ case TOKEN_LOCAL_ADDR:
+ case TOKEN_REMOTE_ADDR:
+ ipv6_addr = TRUE;
+ break;
+ case TOKEN_LAYER:
+ layer = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ WinDivertFormatExpr(stream, field, /*top_level=*/FALSE, /*and=*/FALSE);
+ switch (expr->kind)
+ {
+ case TOKEN_EQ:
+ WinDivertPutString(stream, " = "); break;
+ case TOKEN_NEQ:
+ WinDivertPutString(stream, " != "); break;
+ case TOKEN_LT:
+ WinDivertPutString(stream, " < "); break;
+ case TOKEN_LEQ:
+ WinDivertPutString(stream, " <= "); break;
+ case TOKEN_GT:
+ WinDivertPutString(stream, " > "); break;
+ case TOKEN_GEQ:
+ WinDivertPutString(stream, " >= "); break;
+ }
+ if (ipv4_addr)
+ {
+ WinDivertFormatIPv4Addr(stream, val->val[0]);
+ }
+ else if (ipv6_addr)
+ {
+ WinDivertFormatIPv6Addr(stream, val->val);
+ }
+ else if (layer)
+ {
+ switch (val->val[0])
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ WinDivertPutString(stream, "NETWORK"); break;
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ WinDivertPutString(stream, "NETWORK_FORWARD"); break;
+ case WINDIVERT_LAYER_FLOW:
+ WinDivertPutString(stream, "FLOW"); break;
+ case WINDIVERT_LAYER_REFLECT:
+ WinDivertPutString(stream, "REFLECT"); break;
+ default:
+ WinDivertFormatNumber(stream, val->val[0]); break;
+ }
+ }
+ else
+ {
+ WinDivertFormatNumber(stream, val->val[0]);
+ }
+}
+
+/*
+ * Format an expression.
+ */
+static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
+ BOOL top_level, BOOL and)
+{
+ if (stream->pos >= stream->max)
+ {
+ return;
+ }
+
+ switch (expr->kind)
+ {
+ case TOKEN_AND:
+ if (!top_level && !and)
+ {
+ WinDivertPutChar(stream, '(');
+ }
+ WinDivertFormatExpr(stream, expr->arg[0], /*top_level=*/FALSE,
+ /*and=*/TRUE);
+ WinDivertPutString(stream, " and ");
+ WinDivertFormatExpr(stream, expr->arg[1], /*top_level=*/FALSE,
+ /*and=*/TRUE);
+ if (!top_level && !and)
+ {
+ WinDivertPutChar(stream, ')');
+ }
+ return;
+ case TOKEN_OR:
+ if (!top_level && and)
+ {
+ WinDivertPutChar(stream, '(');
+ }
+ WinDivertFormatExpr(stream, expr->arg[0], /*top_level=*/FALSE,
+ /*and=*/FALSE);
+ WinDivertPutString(stream, " or ");
+ WinDivertFormatExpr(stream, expr->arg[1], /*top_level=*/FALSE,
+ /*and=*/FALSE);
+ if (!top_level && and)
+ {
+ WinDivertPutChar(stream, ')');
+ }
+ return;
+ case TOKEN_QUESTION:
+ WinDivertPutChar(stream, '(');
+ WinDivertFormatExpr(stream, expr->arg[0], /*top_level=*/TRUE,
+ /*and=*/FALSE);
+ WinDivertPutString(stream, "? ");
+ WinDivertFormatExpr(stream, expr->arg[1], /*top_level=*/TRUE,
+ /*and=*/FALSE);
+ WinDivertPutString(stream, ": ");
+ WinDivertFormatExpr(stream, expr->arg[2], /*top_level=*/TRUE,
+ /*and=*/FALSE);
+ WinDivertPutChar(stream, ')');
+ return;
+ case TOKEN_TRUE:
+ WinDivertPutString(stream, "true");
+ return;
+ case TOKEN_FALSE:
+ WinDivertPutString(stream, "false");
+ return;
+ case TOKEN_EQ:
+ case TOKEN_NEQ:
+ case TOKEN_LT:
+ case TOKEN_LEQ:
+ case TOKEN_GT:
+ case TOKEN_GEQ:
+ WinDivertFormatTestExpr(stream, expr);
+ return;
+ case TOKEN_ZERO:
+ WinDivertPutString(stream, "zero"); return;
+ case TOKEN_INBOUND:
+ WinDivertPutString(stream, "inbound"); return;
+ case TOKEN_OUTBOUND:
+ WinDivertPutString(stream, "outbound"); return;
+ case TOKEN_IF_IDX:
+ WinDivertPutString(stream, "ifIdx"); return;
+ case TOKEN_SUB_IF_IDX:
+ WinDivertPutString(stream, "subIfIdx"); return;
+ case TOKEN_IP:
+ WinDivertPutString(stream, "ip"); return;
+ case TOKEN_IPV6:
+ WinDivertPutString(stream, "ipv6"); return;
+ case TOKEN_ICMP:
+ WinDivertPutString(stream, "icmp"); return;
+ case TOKEN_TCP:
+ WinDivertPutString(stream, "tcp"); return;
+ case TOKEN_UDP:
+ WinDivertPutString(stream, "udp"); return;
+ case TOKEN_ICMPV6:
+ WinDivertPutString(stream, "icmpv6"); return;
+ case TOKEN_IP_HDR_LENGTH:
+ WinDivertPutString(stream, "ip.HdrLength"); return;
+ case TOKEN_IP_TOS:
+ WinDivertPutString(stream, "ip.TOS"); return;
+ case TOKEN_IP_LENGTH:
+ WinDivertPutString(stream, "ip.Length"); return;
+ case TOKEN_IP_ID:
+ WinDivertPutString(stream, "ip.Id"); return;
+ case TOKEN_IP_DF:
+ WinDivertPutString(stream, "ip.DF"); return;
+ case TOKEN_IP_MF:
+ WinDivertPutString(stream, "ip.MF"); return;
+ case TOKEN_IP_FRAG_OFF:
+ WinDivertPutString(stream, "ip.FragOff"); return;
+ case TOKEN_IP_TTL:
+ WinDivertPutString(stream, "ip.TTL"); return;
+ case TOKEN_IP_PROTOCOL:
+ WinDivertPutString(stream, "ip.Protocol"); return;
+ case TOKEN_IP_CHECKSUM:
+ WinDivertPutString(stream, "ip.Checksum"); return;
+ case TOKEN_IP_SRC_ADDR:
+ WinDivertPutString(stream, "ip.SrcAddr"); return;
+ case TOKEN_IP_DST_ADDR:
+ WinDivertPutString(stream, "ip.DstAddr"); return;
+ case TOKEN_IPV6_TRAFFIC_CLASS:
+ WinDivertPutString(stream, "ipv6.TrafficClass"); return;
+ case TOKEN_IPV6_FLOW_LABEL:
+ WinDivertPutString(stream, "ipv6.FlowLabel"); return;
+ case TOKEN_IPV6_LENGTH:
+ WinDivertPutString(stream, "ipv6.Length"); return;
+ case TOKEN_IPV6_NEXT_HDR:
+ WinDivertPutString(stream, "ipv6.NextHdr"); return;
+ case TOKEN_IPV6_HOP_LIMIT:
+ WinDivertPutString(stream, "ipv6.HopLimit"); return;
+ case TOKEN_IPV6_SRC_ADDR:
+ WinDivertPutString(stream, "ipv6.SrcAddr"); return;
+ case TOKEN_IPV6_DST_ADDR:
+ WinDivertPutString(stream, "ipv6.DstAddr"); return;
+ case TOKEN_ICMP_TYPE:
+ WinDivertPutString(stream, "icmp.Type"); return;
+ case TOKEN_ICMP_CODE:
+ WinDivertPutString(stream, "icmp.Code"); return;
+ case TOKEN_ICMP_CHECKSUM:
+ WinDivertPutString(stream, "icmp.Checksum"); return;
+ case TOKEN_ICMP_BODY:
+ WinDivertPutString(stream, "icmp.Body"); return;
+ case TOKEN_ICMPV6_TYPE:
+ WinDivertPutString(stream, "icmpv6.Type"); return;
+ case TOKEN_ICMPV6_CODE:
+ WinDivertPutString(stream, "icmpv6.Code"); return;
+ case TOKEN_ICMPV6_CHECKSUM:
+ WinDivertPutString(stream, "icmpv6.Checksum"); return;
+ case TOKEN_ICMPV6_BODY:
+ WinDivertPutString(stream, "icmpv6.Body"); return;
+ case TOKEN_TCP_SRC_PORT:
+ WinDivertPutString(stream, "tcp.SrcPort"); return;
+ case TOKEN_TCP_DST_PORT:
+ WinDivertPutString(stream, "tcp.DstPort"); return;
+ case TOKEN_TCP_SEQ_NUM:
+ WinDivertPutString(stream, "tcp.SeqNum"); return;
+ case TOKEN_TCP_ACK_NUM:
+ WinDivertPutString(stream, "tcp.AckNum"); return;
+ case TOKEN_TCP_HDR_LENGTH:
+ WinDivertPutString(stream, "tcp.HdrLength"); return;
+ case TOKEN_TCP_URG:
+ WinDivertPutString(stream, "tcp.Urg"); return;
+ case TOKEN_TCP_ACK:
+ WinDivertPutString(stream, "tcp.Ack"); return;
+ case TOKEN_TCP_PSH:
+ WinDivertPutString(stream, "tcp.Psh"); return;
+ case TOKEN_TCP_RST:
+ WinDivertPutString(stream, "tcp.Rst"); return;
+ case TOKEN_TCP_SYN:
+ WinDivertPutString(stream, "tcp.Syn"); return;
+ case TOKEN_TCP_FIN:
+ WinDivertPutString(stream, "tcp.Fin"); return;
+ case TOKEN_TCP_WINDOW:
+ WinDivertPutString(stream, "tcp.Window"); return;
+ case TOKEN_TCP_CHECKSUM:
+ WinDivertPutString(stream, "tcp.Checksum"); return;
+ case TOKEN_TCP_URG_PTR:
+ WinDivertPutString(stream, "tcp.UrgPtr"); return;
+ case TOKEN_TCP_PAYLOAD_LENGTH:
+ WinDivertPutString(stream, "tcp.PayloadLength"); return;
+ case TOKEN_UDP_SRC_PORT:
+ WinDivertPutString(stream, "udp.SrcPort"); return;
+ case TOKEN_UDP_DST_PORT:
+ WinDivertPutString(stream, "udp.DstPort"); return;
+ case TOKEN_UDP_LENGTH:
+ WinDivertPutString(stream, "udp.Length"); return;
+ case TOKEN_UDP_CHECKSUM:
+ WinDivertPutString(stream, "udp.Checksum"); return;
+ case TOKEN_UDP_PAYLOAD_LENGTH:
+ WinDivertPutString(stream, "udp.PayloadLength"); return;
+ case TOKEN_LOOPBACK:
+ WinDivertPutString(stream, "loopback"); return;
+ case TOKEN_IMPOSTOR:
+ WinDivertPutString(stream, "impostor"); return;
+ case TOKEN_PROCESS_ID:
+ WinDivertPutString(stream, "processId"); return;
+ case TOKEN_LOCAL_ADDR:
+ WinDivertPutString(stream, "localAddr"); return;
+ case TOKEN_REMOTE_ADDR:
+ WinDivertPutString(stream, "remoteAddr"); return;
+ case TOKEN_LOCAL_PORT:
+ WinDivertPutString(stream, "localPort"); return;
+ case TOKEN_REMOTE_PORT:
+ WinDivertPutString(stream, "remotePort"); return;
+ case TOKEN_PROTOCOL:
+ WinDivertPutString(stream, "protocol"); return;
+ case TOKEN_LAYER:
+ WinDivertPutString(stream, "layer"); return;
+ case TOKEN_NUMBER:
+ WinDivertFormatNumber(stream, expr->val[0]);
+ return;
+ }
+}
+
+/*
+ * Format a filter string.
+ */
+BOOL WinDivertHelperFormatFilter(const char *filter, WINDIVERT_LAYER layer,
+ char *buffer, UINT buflen)
+{
+ PEXPR exprs[WINDIVERT_FILTER_MAXLEN], expr;
+ ERROR err;
+ WINDIVERT_FILTER object[WINDIVERT_FILTER_MAXLEN];
+ UINT obj_len;
+ INT i;
+ HANDLE pool;
+ WINDIVERT_STREAM stream;
+ ERROR error;
+ const SIZE_T min_pool_size = 8192;
+
+ if (filter == NULL || buffer == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ err = WinDivertCompileFilter(filter, layer, object, &obj_len);
+ if (IS_ERROR(err))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ pool = HeapCreate(HEAP_NO_SERIALIZE, min_pool_size, 16 * min_pool_size);
+ if (pool == NULL)
+ {
+ return FALSE;
+ }
+
+ // Decompile all tests:
+ for (i = (INT)obj_len-1; i >= 0; i--)
+ {
+ expr = WinDivertDecompileTest(pool, object + i);
+ if (expr == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ exprs[i] = expr;
+ switch (expr->succ)
+ {
+ case WINDIVERT_FILTER_RESULT_ACCEPT:
+ case WINDIVERT_FILTER_RESULT_REJECT:
+ break;
+ default:
+ exprs[expr->succ]->count++;
+ break;
+ }
+ switch (expr->fail)
+ {
+ case WINDIVERT_FILTER_RESULT_ACCEPT:
+ case WINDIVERT_FILTER_RESULT_REJECT:
+ break;
+ default:
+ exprs[expr->fail]->count++;
+ break;
+ }
+ }
+ exprs[0]->count++;
+
+ // Coalesce (unflatten) tests into and/or expressions:
+ for (i = (INT)obj_len-1; i >= 0; i--)
+ {
+ error = MAKE_ERROR(WINDIVERT_ERROR_NONE, 0);
+ (PVOID)WinDivertCoalesceAndOr(pool, exprs, i, &error);
+ if (IS_ERROR(error))
+ {
+ HeapDestroy(pool);
+ return FALSE;
+ }
+ }
+
+ // Coalesce remaining expressions:
+ expr = WinDivertCoalesceExpr(pool, exprs, 0);
+ if (expr == NULL)
+ {
+ HeapDestroy(pool);
+ return FALSE;
+ }
+
+ // Format the final expression:
+ stream.data = buffer;
+ stream.pos = 0;
+ stream.max = buflen;
+ stream.overflow = FALSE;
+ WinDivertFormatExpr(&stream, expr, /*top_level=*/TRUE, /*and=*/FALSE);
+ WinDivertPutChar(&stream, '\0');
+
+ // Clean-up:
+ HeapDestroy(pool);
+ if (!stream.overflow)
+ {
+ return TRUE;
+ }
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+}
+
diff --git a/examples/flowtrack/flowtrack.c b/examples/flowtrack/flowtrack.c
index f705cae..83a1774 100644
--- a/examples/flowtrack/flowtrack.c
+++ b/examples/flowtrack/flowtrack.c
@@ -69,7 +69,7 @@ static void print_address(const UINT32 *addr)
if (addr[3] == 0 && addr[2] == 0 && addr[1] == 0x0000FFFF)
{
// IPv4 address:
- UINT32 a, b, c, d;
+ UINT32 a, b, c, d;
a = (addr[0] >> 24) & 0xFF;
b = (addr[0] >> 16) & 0xFF;
c = (addr[0] >> 8) & 0xFF;
@@ -82,9 +82,9 @@ static void print_address(const UINT32 *addr)
int i;
for (i = 3; i >= 0; i--)
{
- UINT32 a, b;
- a = (addr[i] >> 16) & 0xFFFF;
- b = (addr[i] >> 0) & 0xFFFF;
+ UINT32 a, b;
+ a = (addr[i] >> 16) & 0xFFFF;
+ b = (addr[i] >> 0) & 0xFFFF;
printf("%x:%x", a, b);
if (i != 0)
{
@@ -114,8 +114,8 @@ static DWORD draw(LPVOID arg)
while (TRUE)
{
- GetConsoleScreenBufferInfo(console, &screen);
- SetConsoleCursorPosition(console, top_left);
+ GetConsoleScreenBufferInfo(console, &screen);
+ SetConsoleCursorPosition(console, top_left);
rows = screen.srWindow.Bottom - screen.srWindow.Top + 1;
columns = screen.srWindow.Right - screen.srWindow.Left + 1;
@@ -132,7 +132,7 @@ static DWORD draw(LPVOID arg)
}
ReleaseMutex(lock);
- // Print the flows:
+ // Print the flows:
SetConsoleTextAttribute(console, BACKGROUND_RED | BACKGROUND_GREEN |
BACKGROUND_BLUE);
WriteConsole(console, header, sizeof(header)-1, &written, NULL);
@@ -142,21 +142,21 @@ static DWORD draw(LPVOID arg)
COORD pos = {sizeof(header)-1, 0};
FillConsoleOutputCharacterA(console, ' ', fill_len, pos,
&written);
- FillConsoleOutputAttribute(console,
+ FillConsoleOutputAttribute(console,
BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
- fill_len, pos, &written);
+ fill_len, pos, &written);
}
putchar('\n');
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
- for (i = 0; i < num_addrs && i < rows-1; i++)
+ for (i = 0; i < num_addrs && i < rows-1; i++)
{
COORD pos = {0, i+1};
addr = &addrs[i];
FillConsoleOutputCharacterA(console, ' ', columns, pos, &written);
- FillConsoleOutputAttribute(console,
- FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE,
- columns, pos, &written);
+ FillConsoleOutputAttribute(console,
+ FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE,
+ columns, pos, &written);
SetConsoleCursorPosition(console, pos);
if (i == rows-2 && (i+1) < num_addrs)
{
@@ -191,7 +191,7 @@ static DWORD draw(LPVOID arg)
}
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
- switch (addr->Flow.Protocol)
+ switch (addr->Flow.Protocol)
{
case IPPROTO_TCP:
SetConsoleTextAttribute(console, FOREGROUND_GREEN);
@@ -227,9 +227,9 @@ static DWORD draw(LPVOID arg)
{
COORD pos = {0, i+1};
FillConsoleOutputCharacterA(console, ' ', columns, pos, &written);
- FillConsoleOutputAttribute(console,
- FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE,
- columns, pos, &written);
+ FillConsoleOutputAttribute(console,
+ FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE,
+ columns, pos, &written);
}
Sleep(1000);
@@ -260,7 +260,24 @@ int __cdecl main(int argc, char **argv)
exit(EXIT_FAILURE);
}
- // Spawn the draw() thread.
+ // Open WinDivert FLOW handle:
+ handle = WinDivertOpen(filter, WINDIVERT_LAYER_FLOW, priority,
+ WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_RECV_ONLY);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ if (GetLastError() == ERROR_INVALID_PARAMETER &&
+ !WinDivertHelperCompileFilter(filter, WINDIVERT_LAYER_FLOW,
+ NULL, 0, &err_str, NULL))
+ {
+ fprintf(stderr, "error: invalid filter \"%s\"\n", err_str);
+ exit(EXIT_FAILURE);
+ }
+ fprintf(stderr, "error: failed to open the WinDivert device (%d)\n",
+ GetLastError());
+ return EXIT_FAILURE;
+ }
+
+ // Spawn the draw() thread.
lock = CreateMutex(NULL, FALSE, NULL);
thread = CreateThread(NULL, 1, (LPTHREAD_START_ROUTINE)draw, NULL, 0,
NULL);
@@ -272,23 +289,6 @@ int __cdecl main(int argc, char **argv)
}
CloseHandle(thread);
- // Open WinDivert FLOW handle:
- handle = WinDivertOpen(filter, WINDIVERT_LAYER_FLOW, priority,
- WINDIVERT_FLAGS_LAYER_FLOW);
- if (handle == INVALID_HANDLE_VALUE)
- {
- if (GetLastError() == ERROR_INVALID_PARAMETER &&
- !WinDivertHelperCheckFilter(filter, WINDIVERT_LAYER_FLOW,
- &err_str, NULL))
- {
- fprintf(stderr, "error: invalid filter \"%s\"\n", err_str);
- exit(EXIT_FAILURE);
- }
- fprintf(stderr, "error: failed to open the WinDivert device (%d)\n",
- GetLastError());
- return EXIT_FAILURE;
- }
-
// Main loop:
while (TRUE)
{
@@ -302,7 +302,7 @@ int __cdecl main(int argc, char **argv)
{
case WINDIVERT_EVENT_FLOW_ESTABLISHED:
- // Flow established:
+ // Flow established:
flow = (PFLOW)malloc(sizeof(FLOW));
if (flow == NULL)
{
@@ -318,7 +318,7 @@ int __cdecl main(int argc, char **argv)
case WINDIVERT_EVENT_FLOW_DELETED:
- // Flow deleted:
+ // Flow deleted:
prev = NULL;
WaitForSingleObject(lock, INFINITE);
flow = flows;
diff --git a/examples/netdump/netdump.c b/examples/netdump/netdump.c
index ee1f46d..1785c93 100644
--- a/examples/netdump/netdump.c
+++ b/examples/netdump/netdump.c
@@ -100,8 +100,8 @@ int __cdecl main(int argc, char **argv)
if (handle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_INVALID_PARAMETER &&
- !WinDivertHelperCheckFilter(argv[1], WINDIVERT_LAYER_NETWORK,
- &err_str, NULL))
+ !WinDivertHelperCompileFilter(argv[1], WINDIVERT_LAYER_NETWORK,
+ NULL, 0, &err_str, NULL))
{
fprintf(stderr, "error: invalid filter \"%s\"\n", err_str);
exit(EXIT_FAILURE);
diff --git a/examples/netfilter/netfilter.c b/examples/netfilter/netfilter.c
index b8e3fc1..f898191 100644
--- a/examples/netfilter/netfilter.c
+++ b/examples/netfilter/netfilter.c
@@ -170,8 +170,8 @@ int __cdecl main(int argc, char **argv)
if (handle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_INVALID_PARAMETER &&
- !WinDivertHelperCheckFilter(argv[1], WINDIVERT_LAYER_NETWORK,
- &err_str, NULL))
+ !WinDivertHelperCompileFilter(argv[1], WINDIVERT_LAYER_NETWORK,
+ NULL, 0, &err_str, NULL))
{
fprintf(stderr, "error: invalid filter \"%s\"\n", err_str);
exit(EXIT_FAILURE);
diff --git a/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c
new file mode 100644
index 0000000..f01111d
--- /dev/null
+++ b/examples/windivertctl/windivertctl.c
@@ -0,0 +1,408 @@
+/*
+ * streamdump.c
+ * (C) 2018, all rights reserved,
+ *
+ * This file is part of WinDivert.
+ *
+ * WinDivert is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * WinDivert is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * DESCRIPTION:
+ *
+ * usage: windivertctl.exe list
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "windivert.h"
+
+#define MAX_PACKET 0xFFFF
+#define MAX_FILTER_LEN 30000
+
+/*
+ * Process info.
+ */
+typedef struct INFO
+{
+ UINT32 process_id;
+ UINT32 ref_count;
+ HANDLE process;
+ struct INFO *next;
+} INFO, *PINFO;
+
+static INFO *open = NULL; // All open handles
+
+/*
+ * Modes.
+ */
+typedef enum
+{
+ LIST,
+ WATCH,
+ KILLALL
+} MODE;
+
+/*
+ * Months.
+ */
+static const char *months[12] =
+{
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
+ "Nov", "Dec"
+};
+
+/*
+ * Add a new process.
+ */
+static HANDLE add_process(UINT32 process_id)
+{
+ PINFO info = open;
+ HANDLE process;
+
+ while (info != NULL)
+ {
+ if (info->process_id == process_id)
+ {
+ info->ref_count++;
+ return info->process;
+ }
+ info = info->next;
+ }
+
+ process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE,
+ FALSE, process_id);
+ info = (INFO *)malloc(sizeof(INFO));
+ if (info == NULL)
+ {
+ fprintf(stderr, "error: failed to allocate memory (%d)\n",
+ GetLastError());
+ exit(EXIT_FAILURE);
+ }
+ info->process_id = process_id;
+ info->process = process;
+ info->ref_count = 1;
+ info->next = open;
+ open = info;
+ return process;
+}
+
+/*
+ * Lookup a process.
+ */
+static HANDLE lookup_process(UINT32 process_id)
+{
+ PINFO info = open;
+
+ while (info != NULL)
+ {
+ if (info->process_id == process_id)
+ {
+ return info->process;
+ }
+ info = info->next;
+ }
+}
+
+/*
+ * Remove an old process.
+ */
+static void remove_process(UINT32 process_id)
+{
+ PINFO info = open, prev = NULL;
+
+ while (info != NULL)
+ {
+ if (info->process_id == process_id)
+ {
+ info->ref_count--;
+ if (info->ref_count > 0)
+ {
+ return;
+ }
+ break;
+ }
+ prev = info;
+ info = info->next;
+ }
+
+ if (info->process != NULL)
+ {
+ CloseHandle(info->process);
+ }
+ if (prev != NULL)
+ {
+ prev->next = info->next;
+ }
+ else
+ {
+ open = info->next;
+ }
+ free(info);
+}
+
+/*
+ * Entry.
+ */
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE handle, process, console;
+ INT16 priority = -333; // Arbitrary.
+ UINT packet_len;
+ 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;
+ ULONGLONG freq, start_count;
+ LARGE_INTEGER li;
+ MODE mode;
+ const char *filter = "true";
+ const char *err_str = NULL;
+
+ if (argc != 2 && argc != 3)
+ {
+usage:
+ fprintf(stderr, "usage: %s (list|watch|killall) [filter]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (strcmp(argv[1], "list") == 0)
+ {
+ mode = LIST;
+ }
+ else if (strcmp(argv[1], "watch") == 0)
+ {
+ mode = WATCH;
+ }
+ else if (strcmp(argv[1], "killall") == 0)
+ {
+ mode = KILLALL;
+ }
+ else
+ {
+ goto usage;
+ }
+ if (argc == 3)
+ {
+ filter = argv[2];
+ }
+
+ // Time management
+ QueryPerformanceFrequency(&li);
+ freq = li.QuadPart;
+ QueryPerformanceCounter(&li);
+ start_count = li.QuadPart;
+
+ // Open WinDivert REFLECT handle:
+ handle = WinDivertOpen(filter, WINDIVERT_LAYER_REFLECT, priority,
+ WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_RECV_ONLY |
+ (mode == WATCH? 0: WINDIVERT_FLAG_NO_INSTALL));
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ if (mode != WATCH && GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
+ {
+ // WinDivert driver is not running, so no open handles.
+ return 0;
+ }
+ if (GetLastError() == ERROR_INVALID_PARAMETER &&
+ !WinDivertHelperCompileFilter(filter, WINDIVERT_LAYER_FLOW,
+ NULL, 0, &err_str, NULL))
+ {
+ fprintf(stderr, "error: invalid filter \"%s\"\n", err_str);
+ exit(EXIT_FAILURE);
+ }
+ fprintf(stderr, "error: failed to open the WinDivert device (%d)\n",
+ GetLastError());
+ return EXIT_FAILURE;
+ }
+
+ // Main loop:
+ console = GetStdHandle(STD_OUTPUT_HANDLE);
+ while (TRUE)
+ {
+ if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len))
+ {
+ fprintf(stderr, "failed to event (%d)\n", GetLastError());
+ continue;
+ }
+
+ switch (addr.Event)
+ {
+ case WINDIVERT_EVENT_REFLECT_ESTABLISHED:
+ case WINDIVERT_EVENT_REFLECT_OPEN:
+ // Open handle:
+ process = add_process(addr.Reflect.ProcessId);
+ if (mode == KILLALL)
+ {
+ SetConsoleTextAttribute(console, FOREGROUND_RED);
+ fputs("KILL", stdout);
+ TerminateProcess(process, 0);
+ }
+ else
+ {
+ SetConsoleTextAttribute(console, FOREGROUND_GREEN);
+ fputs("OPEN", stdout);
+ }
+ break;
+
+ case WINDIVERT_EVENT_REFLECT_CLOSE:
+ // Close handle:
+ if (mode != WATCH)
+ {
+ continue;
+ }
+ process = lookup_process(addr.Reflect.ProcessId);
+ SetConsoleTextAttribute(console, FOREGROUND_RED);
+ fputs("CLOSE", stdout);
+ break;
+ }
+ SetConsoleTextAttribute(console,
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ fputs(" time=", stdout);
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
+ printf("%.3fs", (double)(addr.Reflect.Timestamp - (INT64)start_count) /
+ (double)freq);
+ SetConsoleTextAttribute(console,
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ fputs(" pid=", stdout);
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
+ printf("%u", addr.Reflect.ProcessId);
+ SetConsoleTextAttribute(console,
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ fputs(" exe=", stdout);
+ path_len = 0;
+ if (process != NULL)
+ {
+ path_len = GetProcessImageFileName(process, path, sizeof(path));
+ }
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
+ printf("%s", (path_len != 0? path: "???"));
+ SetConsoleTextAttribute(console,
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ fputs(" layer=", stdout);
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
+ switch (addr.Reflect.Layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ fputs("NETWORK", stdout);
+ break;
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ fputs("NETWORK_FORWARD", stdout);
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ fputs("FLOW", stdout);
+ break;
+ case WINDIVERT_LAYER_REFLECT:
+ fputs("REFLECT", stdout);
+ break;
+ default:
+ fputs("???", stdout);
+ break;
+ }
+ SetConsoleTextAttribute(console,
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ fputs(" flags=", stdout);
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
+ if (addr.Reflect.Flags == 0)
+ {
+ fputs("0", stdout);
+ }
+ else
+ {
+ or = FALSE;
+ if ((addr.Reflect.Flags & WINDIVERT_FLAG_SNIFF) != 0)
+ {
+ fputs("SNIFF", stdout);
+ or = TRUE;
+ }
+ if ((addr.Reflect.Flags & WINDIVERT_FLAG_DROP) != 0)
+ {
+ printf("%sDROP", (or? "|": ""));
+ or = TRUE;
+ }
+ if ((addr.Reflect.Flags & WINDIVERT_FLAG_RECV_ONLY) != 0)
+ {
+ printf("%sRECV_ONLY", (or? "|": ""));
+ or = TRUE;
+ }
+ if ((addr.Reflect.Flags & WINDIVERT_FLAG_SEND_ONLY) != 0)
+ {
+ printf("%sSEND_ONLY", (or? "|": ""));
+ or = TRUE;
+ }
+ if ((addr.Reflect.Flags & WINDIVERT_FLAG_DEBUG) != 0)
+ {
+ printf("%sDEBUG", (or? "|": ""));
+ or = TRUE;
+ }
+ if ((addr.Reflect.Flags & WINDIVERT_FLAG_NO_INSTALL) != 0)
+ {
+ printf("%sNO_INSTALL", (or? "|": ""));
+ or = TRUE;
+ }
+ }
+ SetConsoleTextAttribute(console,
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ fputs(" priority=", stdout);
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
+ printf("%d", addr.Reflect.Priority);
+ SetConsoleTextAttribute(console,
+ 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, &object, NULL);
+ if (WinDivertHelperFormatFilter((char *)object, addr.Reflect.Layer,
+ filter_str, sizeof(filter_str)))
+ {
+ printf("\"%s\" \"%s\"", filter_str, (char *)object); // XXX
+ }
+ SetConsoleTextAttribute(console,
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ putchar('\n');
+
+ if (addr.Event == WINDIVERT_EVENT_REFLECT_CLOSE)
+ {
+ remove_process(addr.Reflect.ProcessId);
+ }
+ if (mode != WATCH && addr.Final)
+ {
+ break;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/include/windivert.h b/include/windivert.h
index 49029f2..68c2131 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -69,6 +69,17 @@ extern "C" {
/* WINDIVERT API */
/****************************************************************************/
+/*
+ * WinDivert layers.
+ */
+typedef enum
+{
+ WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */
+ WINDIVERT_LAYER_NETWORK_FORWARD = 1,/* Network layer (forwarded packets) */
+ WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */
+ WINDIVERT_LAYER_REFLECT = 3, /* Reflect layer. */
+} WINDIVERT_LAYER, *PWINDIVERT_LAYER;
+
/*
* WinDivert NETWORK and NETWORK_FORWARD layer data.
*/
@@ -91,6 +102,18 @@ typedef struct
UINT8 Protocol; /* Protocol. */
} WINDIVERT_FLOW_DATA, *PWINDIVERT_FLOW_DATA;
+/*
+ * WinDivert REFLECTION layer data.
+ */
+typedef struct
+{
+ INT64 Timestamp; /* Handle open time. */
+ UINT32 ProcessId; /* Handle process ID. */
+ WINDIVERT_LAYER Layer; /* Handle layer. */
+ UINT64 Flags; /* Handle flags. */
+ INT16 Priority; /* Handle priority. */
+} WINDIVERT_REFLECT_DATA, *PWINDIVERT_REFLECT_DATA;
+
/*
* WinDivert address.
*/
@@ -106,24 +129,16 @@ typedef struct
UINT32 PseudoIPChecksum:1; /* Packet has pseudo IPv4 checksum? */
UINT32 PseudoTCPChecksum:1; /* Packet has pseudo TCP checksum? */
UINT32 PseudoUDPChecksum:1; /* Packet has pseudo UDP checksum? */
- UINT32 Reserved:9;
+ UINT32 Final:1; /* Packet is final event? */
+ UINT32 Reserved:8;
union
{
WINDIVERT_NETWORK_DATA Network; /* Network layer data. */
WINDIVERT_FLOW_DATA Flow; /* Flow layer data. */
+ WINDIVERT_REFLECT_DATA Reflect; /* Reflect layer data. */
};
} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
-/*
- * WinDivert layers.
- */
-typedef enum
-{
- WINDIVERT_LAYER_NETWORK = 1, /* Network layer. */
- WINDIVERT_LAYER_NETWORK_FORWARD = 2,/* Network layer (forwarded packets) */
- WINDIVERT_LAYER_FLOW = 3 /* Flow layer. */
-} WINDIVERT_LAYER, *PWINDIVERT_LAYER;
-
/*
* WinDivert events.
*/
@@ -133,24 +148,23 @@ typedef enum
WINDIVERT_EVENT_FLOW_ESTABLISHED = 1,
/* Flow established. */
WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */
+ WINDIVERT_EVENT_REFLECT_ESTABLISHED = 3,
+ /* Previously open WinDivert handle. */
+ WINDIVERT_EVENT_REFLECT_OPEN = 4, /* Open new WinDivert handle. */
+ WINDIVERT_EVENT_REFLECT_CLOSE = 5, /* Close existing WinDivert handle. */
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
/*
* WinDivert flags.
*/
-#define WINDIVERT_FLAG_SNIFF 1
-#define WINDIVERT_FLAG_DROP 2
-#define WINDIVERT_FLAG_RECV_ONLY 4
+#define WINDIVERT_FLAG_SNIFF 0x01
+#define WINDIVERT_FLAG_DROP 0x02
+#define WINDIVERT_FLAG_RECV_ONLY 0x04
#define WINDIVERT_FLAG_READ_ONLY WINDIVERT_FLAG_RECV_ONLY
-#define WINDIVERT_FLAG_SEND_ONLY 8
+#define WINDIVERT_FLAG_SEND_ONLY 0x08
#define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY
-#define WINDIVERT_FLAG_DEBUG 16
-
-#define WINDIVERT_FLAGS_LAYER_NETWORK 0
-#define WINDIVERT_FLAGS_LAYER_NETWORK_FORWARD \
- 0
-#define WINDIVERT_FLAGS_LAYER_FLOW \
- (WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_RECV_ONLY)
+#define WINDIVERT_FLAG_DEBUG 0x10
+#define WINDIVERT_FLAG_NO_INSTALL 0x20
/*
* WinDivert parameters.
@@ -430,11 +444,13 @@ extern WINDIVERTEXPORT UINT WinDivertHelperCalcChecksums(
__in UINT64 flags);
/*
- * Check the given filter string.
+ * Compile the given filter string.
*/
-extern WINDIVERTEXPORT BOOL WinDivertHelperCheckFilter(
+extern WINDIVERTEXPORT BOOL WinDivertHelperCompileFilter(
__in const char *filter,
__in WINDIVERT_LAYER layer,
+ __out_opt char *object,
+ __in UINT objLen,
__out_opt const char **errorStr,
__out_opt UINT *errorPos);
@@ -447,6 +463,15 @@ extern WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter(
__in UINT packetLen,
__in PWINDIVERT_ADDRESS pAddr);
+/*
+ * Format the given filter string.
+ */
+extern BOOL WinDivertHelperFormatFilter(
+ __in const char *filter,
+ __in WINDIVERT_LAYER layer,
+ __out char *buffer,
+ __in UINT bufLen);
+
#endif /* WINDIVERT_KERNEL */
#ifdef __cplusplus
diff --git a/include/windivert_device.h b/include/windivert_device.h
index 73cc45f..2741402 100644
--- a/include/windivert_device.h
+++ b/include/windivert_device.h
@@ -128,8 +128,9 @@
#define WINDIVERT_FILTER_FIELD_LOCALPORT 63
#define WINDIVERT_FILTER_FIELD_REMOTEPORT 64
#define WINDIVERT_FILTER_FIELD_PROTOCOL 65
+#define WINDIVERT_FILTER_FIELD_LAYER 66
#define WINDIVERT_FILTER_FIELD_MAX \
- WINDIVERT_FILTER_FIELD_PROTOCOL
+ WINDIVERT_FILTER_FIELD_LAYER
#define WINDIVERT_FILTER_TEST_EQ 0
#define WINDIVERT_FILTER_TEST_NEQ 1
@@ -139,7 +140,7 @@
#define WINDIVERT_FILTER_TEST_GEQ 5
#define WINDIVERT_FILTER_TEST_MAX WINDIVERT_FILTER_TEST_GEQ
-#define WINDIVERT_FILTER_MAXLEN 128
+#define WINDIVERT_FILTER_MAXLEN (0xFF-2)
#define WINDIVERT_FILTER_RESULT_ACCEPT (WINDIVERT_FILTER_MAXLEN+1)
#define WINDIVERT_FILTER_RESULT_REJECT (WINDIVERT_FILTER_MAXLEN+2)
@@ -148,13 +149,15 @@
* WinDivert layers.
*/
#define WINDIVERT_LAYER_DEFAULT WINDIVERT_LAYER_NETWORK
+#define WINDIVERT_LAYER_MAX WINDIVERT_LAYER_REFLECT
/*
* WinDivert flags.
*/
#define WINDIVERT_FLAGS_ALL \
(WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP | WINDIVERT_FLAG_RECV_ONLY |\
- WINDIVERT_FLAG_SEND_ONLY | WINDIVERT_FLAG_DEBUG)
+ WINDIVERT_FLAG_SEND_ONLY | WINDIVERT_FLAG_DEBUG | \
+ WINDIVERT_FLAG_NO_INSTALL)
#define WINDIVERT_FLAGS_EXCLUDE(flags, flag1, flag2) \
(((flags) & ((flag1) | (flag2))) != ((flag1) | (flag2)))
#define WINDIVERT_FLAGS_VALID(flags) \
@@ -164,14 +167,24 @@
WINDIVERT_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_RECV_ONLY, \
WINDIVERT_FLAG_SEND_ONLY))
+/*
+ * WinDivert filter flags.
+ */
+#define WINDIVERT_FILTER_FLAG_INBOUND 0x0000000000000001ull
+#define WINDIVERT_FILTER_FLAG_OUTBOUND 0x0000000000000002ull
+#define WINDIVERT_FILTER_FLAG_IP 0x0000000000000004ull
+#define WINDIVERT_FILTER_FLAG_IPV6 0x0000000000000008ull
+
+#define WINDIVERT_FILTER_FLAGS_ALL \
+ (WINDIVERT_FILTER_FLAG_INBOUND | WINDIVERT_FILTER_FLAG_OUTBOUND | \
+ WINDIVERT_FILTER_FLAG_IP | WINDIVERT_FILTER_FLAG_IPV6)
+
/*
* WinDivert priorities.
*/
-#define WINDIVERT_PRIORITY(priority16) \
- ((UINT32)((INT32)(priority16) + 0x7FFF + 1))
-#define WINDIVERT_PRIORITY_DEFAULT WINDIVERT_PRIORITY(0)
-#define WINDIVERT_PRIORITY_MAX WINDIVERT_PRIORITY(1000)
-#define WINDIVERT_PRIORITY_MIN WINDIVERT_PRIORITY(-1000)
+#define WINDIVERT_PRIORITY_DEFAULT 0
+#define WINDIVERT_PRIORITY_MAX 30000
+#define WINDIVERT_PRIORITY_MIN -WINDIVERT_PRIORITY_MAX
/*
* WinDivert parameters.
@@ -190,27 +203,25 @@
* WinDivert message definitions.
*/
#pragma pack(push, 1)
-struct windivert_ioctl_s
+typedef struct
{
UINT16 magic; // WINDIVERT_IOCTL_MAGIC
UINT8 version; // WINDIVERT_IOCTL_VERSION
UINT8 arg8; // 8-bit argument
UINT64 arg; // 64-bit argument
-};
-typedef struct windivert_ioctl_s *windivert_ioctl_t;
+} WINDIVERT_IOCTL, *PWINDIVERT_IOCTL;
/*
* WinDivert IOCTL structures.
*/
-struct windivert_ioctl_filter_s
+typedef struct
{
UINT8 field; // WINDIVERT_FILTER_FIELD_*
UINT8 test; // WINDIVERT_FILTER_TEST_*
- UINT16 success; // Success continuation.
- UINT16 failure; // Fail continuation.
+ UINT8 success; // Success continuation.
+ UINT8 failure; // Fail continuation.
UINT32 arg[4]; // Argument.
-};
-typedef struct windivert_ioctl_filter_s *windivert_ioctl_filter_t;
+} WINDIVERT_FILTER, *PWINDIVERT_FILTER;
#pragma pack(pop)
/*
diff --git a/mingw-build.sh b/mingw-build.sh
index 74ca900..29a550e 100644
--- a/mingw-build.sh
+++ b/mingw-build.sh
@@ -59,7 +59,7 @@ do
fi
echo "BUILD MINGW-$CPU"
CC="$ENV-gcc"
- COPTS="-shared -Wall -Wno-pointer-to-int-cast -O2 -Iinclude/
+ COPTS="-shared -Wall -Wno-pointer-to-int-cast -Os -Iinclude/
-Wl,--enable-stdcall-fixup -Wl,--entry=${MANGLE}WinDivertDllEntry"
CLIBS="-lgcc -lkernel32 -ladvapi32"
STRIP="$ENV-strip"
@@ -101,6 +101,10 @@ do
$CC -s -O2 -Iinclude/ examples/flowtrack/flowtrack.c \
-o "install/MINGW/$CPU/flowtrack.exe" -lWinDivert -lws2_32 -lpsapi \
-lshlwapi -L"install/MINGW/$CPU/"
+ echo "\tcopy install/MINGW/$CPU/windivertctl.exe..."
+ $CC -s -O2 -Iinclude/ examples/windivertctl/windivertctl.c \
+ -o "install/MINGW/$CPU/windivertctl.exe" -lWinDivert -lws2_32 \
+ -lpsapi -lshlwapi -L"install/MINGW/$CPU/"
echo "\tcopy install/MINGW/$CPU/WinDivert$BITS.sys..."
cp install/WDDK/$CPU/WinDivert$BITS.sys install/MINGW/$CPU
else
diff --git a/sys/sources b/sys/sources
index 21685f8..1461d7a 100644
--- a/sys/sources
+++ b/sys/sources
@@ -19,6 +19,6 @@ NTTARGETFILES=
KMDF_VERSION_MAJOR=1
C_DEFINES=$(C_DEFINES) -DBINARY_COMPATIBLE=0 -DNT -DUNICODE -D_UNICODE \
-DNDIS60 -DNDIS_SUPPORT_NDIS60
-INCLUDES=$(DDK_INC_PATH);..\include
+INCLUDES=$(DDK_INC_PATH);..\include;..\dll
SOURCES=windivert.rc windivert.c
diff --git a/sys/windivert.c b/sys/windivert.c
index 9d4bcc2..08212d9 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -32,6 +32,7 @@
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include
#include
#include
#include
@@ -55,6 +56,7 @@ EVT_WDF_FILE_CLEANUP windivert_cleanup;
EVT_WDF_FILE_CLOSE windivert_close;
EVT_WDF_OBJECT_CONTEXT_DESTROY windivert_destroy;
EVT_WDF_WORKITEM windivert_worker;
+EVT_WDF_WORKITEM windivert_reflect_worker;
/*
* Debugging macros.
@@ -97,27 +99,15 @@ static void DEBUG_ERROR(PCCH format, NTSTATUS status, ...)
#define WINDIVERT_TAG 'viDW'
/*
- * WinDivert packet filter.
+ * WinDivert reflect context information.
*/
-struct filter_s
+struct reflect_context_s
{
- UINT8 protocol:4; // field's protocol
- UINT8 test:4; // Filter test
- UINT8 field; // Field of interest
- UINT16 success; // Success continuation
- UINT16 failure; // Fail continuation
- UINT32 arg[4]; // Comparison argument
+ LIST_ENTRY entry; // Open handle entry.
+ LONGLONG timestamp; // Open timestamp.
+ WINDIVERT_REFLECT_DATA data; // Reflect data.
+ BOOL inserted; // Entry inserted?
};
-typedef struct filter_s *filter_t;
-#define WINDIVERT_FILTER_PROTOCOL_NONE 0
-#define WINDIVERT_FILTER_PROTOCOL_IP 1
-#define WINDIVERT_FILTER_PROTOCOL_IPV6 2
-#define WINDIVERT_FILTER_PROTOCOL_ICMP 3
-#define WINDIVERT_FILTER_PROTOCOL_ICMPV6 4
-#define WINDIVERT_FILTER_PROTOCOL_TCP 5
-#define WINDIVERT_FILTER_PROTOCOL_UDP 6
-#define WINDIVERT_FILTER_PROTOCOL_NETWORK 7
-#define WINDIVERT_FILTER_PROTOCOL_FLOW 8
/*
* WinDivert context information.
@@ -157,22 +147,27 @@ struct context_s
UINT8 worker_curr; // Current read worker.
UINT8 layer; // Context's layer.
UINT64 flags; // Context's flags.
- UINT32 priority; // Context's priority.
+ UINT32 priority; // Context (internal) priority.
+ INT16 priority16; // Context (user) priority.
GUID callout_guid[WINDIVERT_CONTEXT_MAXLAYERS];
// Callout GUIDs.
GUID filter_guid[WINDIVERT_CONTEXT_MAXLAYERS];
// Filter GUIDs.
BOOL installed[WINDIVERT_CONTEXT_MAXLAYERS];// What is installed?
HANDLE engine_handle; // WFP engine handle.
- filter_t filter; // Packet filter.
+ PWINDIVERT_FILTER filter; // Packet filter.
+ UINT8 filter_len; // Length of filter.
+ struct reflect_context_s reflect; // Reflection info.
};
typedef struct context_s context_s;
typedef struct context_s *context_t;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(context_s, windivert_context_get);
#define WINDIVERT_TIMEOUT(context, t0, t1) \
- (((t1) >= (t0)? (t1) - (t0): (t0) - (t1)) > \
- (context)->packet_queue_maxcounts)
+ ((context)->layer == WINDIVERT_LAYER_NETWORK || \
+ (context)->layer == WINDIVERT_LAYER_NETWORK_FORWARD? \
+ ((t1) >= (t0)? (t1) - (t0): (t0) - (t1)) > \
+ (context)->packet_queue_maxcounts: FALSE)
/*
* WinDivert Layer information.
@@ -242,6 +237,7 @@ struct packet_s
UINT32 pseudo_ip_checksum:1; // Packet has pseudo IPv4 check?
UINT32 pseudo_tcp_checksum:1; // Packet has pseudo TCP check?
UINT32 pseudo_udp_checksum:1; // Packet has pseudo UDP check?
+ UINT32 final:1; // Packet is final event?
UINT32 match:1; // Packet matches filter?
UINT32 priority; // Packet priority.
UINT32 packet_len; // Length of the packet.
@@ -279,6 +275,18 @@ struct flow_s
};
typedef struct flow_s *flow_t;
+/*
+ * WinDivert reflect event.
+ */
+struct reflect_event_s
+{
+ LIST_ENTRY entry; // Entry for reflect_event_queue.
+ context_t context; // Context.
+ LONGLONG timestamp; // Event timestamp.
+ WINDIVERT_EVENT event; // Event.
+};
+typedef struct reflect_event_s *reflect_event_t;
+
/*
* IPv4/IPv6 pseudo headers.
*/
@@ -320,19 +328,20 @@ static LONGLONG counts_per_ms = 0;
static POOL_TYPE non_paged_pool = NonPagedPool;
/*
- * Priorities.
+ * Priorities & weights.
*/
-#define WINDIVERT_CONTEXT_PRIORITY(priority0) \
- windivert_context_priority(priority0)
-static UINT32 windivert_context_priority(UINT32 priority0)
+static UINT32 windivert_context_priority(INT64 priority64)
{
- UINT16 priority1 = (UINT16)InterlockedIncrement(&priority_counter);
- priority0 -= WINDIVERT_PRIORITY_MIN;
- return ((priority0 << 16) | ((UINT32)priority1 & 0x0000FFFF));
+ UINT32 priority, increment;
+ priority64 += WINDIVERT_PRIORITY_MAX; // Make positive
+ priority = (UINT32)(priority64 << 16);
+ increment = (UINT32)InterlockedIncrement(&priority_counter);
+ priority |= (increment & 0x0000FFFF);
+ return priority;
}
#define WINDIVERT_FILTER_WEIGHT(priority) \
- ((UINT64)(UINT32_MAX - (priority)))
+ ((UINT64)((UINT64)UINT32_MAX - (priority)))
/*
* Prototypes.
@@ -347,7 +356,7 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
IN WDFFILEOBJECT object);
static NTSTATUS windivert_install_sublayer(layer_t layer);
static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
- BOOL inbound, BOOL outbound, BOOL ipv4, BOOL ipv6);
+ UINT64 flags);
static NTSTATUS windivert_install_callout(context_t context, UINT idx,
layer_t layer, UINT32 *callout_id_ptr);
static void windivert_uninstall_callouts(context_t context,
@@ -412,26 +421,29 @@ static void windivert_network_classify(context_t context,
IN PWINDIVERT_NETWORK_DATA network_data, IN BOOL ipv4, IN BOOL outbound,
IN BOOL loopback, IN UINT advance, IN OUT void *data,
OUT FWPS_CLASSIFY_OUT0 *result);
-static BOOL windivert_queue_work(context_t context, PNET_BUFFER buffer,
- PNET_BUFFER_LIST buffers, PWINDIVERT_NETWORK_DATA network_data,
- PWINDIVERT_FLOW_DATA flow_data, WINDIVERT_LAYER layer,
- WINDIVERT_EVENT event, UINT64 flags, UINT32 priority, BOOL ipv4,
- BOOL outbound, BOOL loopback, BOOL impostor, BOOL match,
- LONGLONG timestamp);
+static BOOL windivert_queue_work(context_t context, PVOID packet,
+ ULONG packet_len, PNET_BUFFER_LIST buffers, WINDIVERT_LAYER layer,
+ PVOID layer_data, WINDIVERT_EVENT event, UINT64 flags, UINT32 priority,
+ BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, BOOL final,
+ BOOL match, LONGLONG timestamp);
static void windivert_queue_packet(context_t context, packet_t packet);
static void windivert_reinject_packet(packet_t packet);
static void windivert_free_packet(packet_t packet);
static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4, BOOL checksum);
static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b);
-static BOOL windivert_filter(PNET_BUFFER buffer,
- PWINDIVERT_NETWORK_DATA network_data, PWINDIVERT_FLOW_DATA flow_data,
- BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, filter_t filter);
-static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
- size_t ioctl_filter_len);
-static void windivert_filter_analyze(filter_t filter, UINT64 flags,
- BOOL *inbound, BOOL *outbound, BOOL *ipv4, BOOL *ipv6);
-static BOOL windivert_filter_test(filter_t filter, UINT16 ip, UINT8 protocol,
- UINT8 field, UINT32 arg);
+static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
+ PVOID layer_data, BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor,
+ PWINDIVERT_FILTER filter);
+static PWINDIVERT_FILTER windivert_filter_compile(
+ PWINDIVERT_FILTER ioctl_filter, size_t ioctl_filter_len);
+static NTSTATUS windivert_reflect_init(WDFOBJECT parent);
+static void windivert_reflect_close(void);
+static void windivert_reflect_event(context_t context, WINDIVERT_EVENT event);
+static void windivert_reflect_event_notify(context_t context,
+ LONGLONG timestamp, WINDIVERT_EVENT event);
+static void windivert_reflect_established_notify(context_t context,
+ LONGLONG timestamp);
+static void windivert_reflect_worker(IN WDFWORKITEM item);
/*
* WinDivert sublayer GUIDs
@@ -868,6 +880,12 @@ driver_entry_sublayer_error:
goto driver_entry_exit;
}
+ status = windivert_reflect_init((WDFOBJECT)device);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_exit;
+ }
+
driver_entry_exit:
if (!NT_SUCCESS(status))
@@ -998,7 +1016,7 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
context->packet_queue_maxtime = WINDIVERT_PARAM_QUEUE_TIME_DEFAULT;
context->layer = WINDIVERT_LAYER_DEFAULT;
context->flags = 0;
- context->priority = WINDIVERT_CONTEXT_PRIORITY(WINDIVERT_PRIORITY_DEFAULT);
+ context->priority = windivert_context_priority(WINDIVERT_PRIORITY_DEFAULT);
context->filter = NULL;
for (i = 0; i < WINDIVERT_CONTEXT_MAXWORKERS; i++)
{
@@ -1061,6 +1079,7 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
DEBUG_ERROR("failed to create WFP engine handle", status);
goto windivert_create_exit;
}
+ RtlZeroMemory(&context->reflect, sizeof(context->reflect));
windivert_create_exit:
@@ -1092,13 +1111,19 @@ windivert_create_exit:
* Register all WFP callouts.
*/
static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
- BOOL inbound, BOOL outbound, BOOL ipv4, BOOL ipv6)
+ UINT64 flags)
{
UINT8 i, j;
layer_t layers[WINDIVERT_CONTEXT_MAXLAYERS];
UINT32 *callout_ids[WINDIVERT_CONTEXT_MAXLAYERS] = {NULL};
+ BOOL inbound, outbound, ipv4, ipv6;
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);
+
i = 0;
switch (layer)
{
@@ -1145,6 +1170,9 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
}
break;
+ case WINDIVERT_LAYER_REFLECT:
+ break;
+
default:
return STATUS_INVALID_PARAMETER;
}
@@ -1408,7 +1436,6 @@ extern VOID windivert_cleanup(IN WDFFILEOBJECT object)
DEBUG("CLEANUP: cleaning up WinDivert context (context=%p)", context);
- timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPENING &&
context->state != WINDIVERT_CONTEXT_STATE_OPEN)
@@ -1423,6 +1450,10 @@ windivert_cleanup_error:
sniff_mode = ((context->flags & WINDIVERT_FLAG_SNIFF) != 0);
forward = (context->layer == WINDIVERT_LAYER_NETWORK_FORWARD);
priority = context->priority;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ windivert_reflect_event(context, WINDIVERT_EVENT_REFLECT_CLOSE);
+ timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
while (!IsListEmpty(&context->flow_set))
{
entry = RemoveHeadList(&context->flow_set);
@@ -1530,7 +1561,7 @@ extern VOID windivert_destroy(IN WDFOBJECT object)
{
KLOCK_QUEUE_HANDLE lock_handle;
context_t context = windivert_context_get((WDFFILEOBJECT)object);
- filter_t filter;
+ PWINDIVERT_FILTER filter;
NTSTATUS status;
DEBUG("DESTROY: destroying WinDivert context (context=%p)", context);
@@ -1609,6 +1640,7 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
{
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
+ case WINDIVERT_LAYER_REFLECT:
status = WdfRequestRetrieveOutputWdmMdl(request, &dst_mdl);
if (!NT_SUCCESS(status))
@@ -1624,7 +1656,14 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
goto windivert_read_service_request_exit;
}
- src = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_NETWORK_DATA, packet);
+ if (packet->layer != WINDIVERT_LAYER_REFLECT)
+ {
+ src = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_NETWORK_DATA, packet);
+ }
+ else
+ {
+ src = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_REFLECT_DATA, packet);
+ }
src_len = packet->packet_len;
dst_len = MmGetMdlByteCount(dst_mdl);
dst_len = (src_len < dst_len? src_len: dst_len);
@@ -1651,13 +1690,14 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
addr->Timestamp = (INT64)packet->timestamp;
addr->Layer = packet->layer;
addr->Event = packet->event;
- addr->Outbound = (packet->outbound? 1: 0);
- addr->Loopback = (packet->loopback? 1: 0);
- addr->Impostor = (packet->impostor? 1: 0);
- addr->IPv6 = (packet->ipv6? 1: 0);
- addr->PseudoIPChecksum = (packet->pseudo_ip_checksum? 1: 0);
- addr->PseudoTCPChecksum = (packet->pseudo_tcp_checksum? 1: 0);
- addr->PseudoUDPChecksum = (packet->pseudo_udp_checksum? 1: 0);
+ addr->Outbound = packet->outbound;
+ addr->Loopback = packet->loopback;
+ addr->Impostor = packet->impostor;
+ addr->IPv6 = packet->ipv6;
+ addr->PseudoIPChecksum = packet->pseudo_ip_checksum;
+ addr->PseudoTCPChecksum = packet->pseudo_tcp_checksum;
+ addr->PseudoUDPChecksum = packet->pseudo_udp_checksum;
+ addr->Final = packet->final;
addr->Reserved = 0;
switch (packet->layer)
{
@@ -1672,6 +1712,11 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
sizeof(WINDIVERT_FLOW_DATA));
break;
+ case WINDIVERT_LAYER_REFLECT:
+ RtlCopyMemory(&addr->Reflect, layer_data,
+ sizeof(WINDIVERT_REFLECT_DATA));
+ break;
+
default:
break;
}
@@ -1784,11 +1829,15 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
goto windivert_write_exit;
}
- if (layer == WINDIVERT_LAYER_FLOW)
+ switch (layer)
{
- status = STATUS_INVALID_PARAMETER;
- DEBUG_ERROR("failed to inject at FLOW layer", status);
- goto windivert_write_exit;
+ case WINDIVERT_LAYER_FLOW:
+ case WINDIVERT_LAYER_REFLECT:
+ status = STATUS_INVALID_PARAMETER;
+ DEBUG_ERROR("failed to inject at FLOW layer", status);
+ goto windivert_write_exit;
+ default:
+ break;
}
status = WdfRequestRetrieveOutputWdmMdl(request, &mdl);
@@ -1994,7 +2043,7 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
WDF_REQUEST_PARAMETERS params;
WDFMEMORY memobj;
PWINDIVERT_ADDRESS addr = NULL;
- windivert_ioctl_t ioctl;
+ PWINDIVERT_IOCTL ioctl;
WDF_OBJECT_ATTRIBUTES attributes;
req_context_t req_context = NULL;
NTSTATUS status;
@@ -2015,14 +2064,14 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
goto windivert_caller_context_error;
}
- if (inbuflen != sizeof(struct windivert_ioctl_s))
+ if (inbuflen != sizeof(WINDIVERT_IOCTL))
{
status = STATUS_INVALID_PARAMETER;
DEBUG_ERROR("input buffer not an ioctl message header", status);
goto windivert_caller_context_error;
}
- ioctl = (windivert_ioctl_t)inbuf;
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
if (ioctl->version != WINDIVERT_IOCTL_VERSION ||
ioctl->magic != WINDIVERT_IOCTL_MAGIC)
{
@@ -2115,11 +2164,13 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
KLOCK_QUEUE_HANDLE lock_handle;
PCHAR inbuf, outbuf;
size_t inbuflen, outbuflen, filter0_len;
- windivert_ioctl_t ioctl;
- windivert_ioctl_filter_t filter0;
- filter_t filter;
+ PWINDIVERT_IOCTL ioctl;
+ PWINDIVERT_FILTER filter0;
+ PWINDIVERT_FILTER filter;
UINT8 layer;
- UINT32 priority;
+ INT16 priority;
+ UINT32 priority32;
+ INT64 priority64;
UINT64 flags;
PWINDIVERT_ADDRESS addr;
req_context_t req_context;
@@ -2180,7 +2231,19 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
case IOCTL_WINDIVERT_START_FILTER:
{
BOOL inbound, outbound, ipv4, ipv6;
-
+ PIRP irp;
+ LONGLONG timestamp;
+ UINT32 process_id;
+ UINT8 filter_len;
+
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
+ if ((ioctl->arg & ~WINDIVERT_FILTER_FLAGS_ALL) != 0)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ DEBUG_ERROR("failed to start filter; invalid flags", status);
+ goto windivert_ioctl_exit;
+ }
+
filter = NULL;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
@@ -2191,9 +2254,10 @@ windivert_ioctl_bad_start_state:
status = STATUS_INVALID_DEVICE_STATE;
goto windivert_ioctl_exit;
}
+ context->state = WINDIVERT_CONTEXT_STATE_OPEN;
KeReleaseInStackQueuedSpinLock(&lock_handle);
- filter0 = (windivert_ioctl_filter_t)outbuf;
+ filter0 = (PWINDIVERT_FILTER)outbuf;
filter0_len = outbuflen;
filter = windivert_filter_compile(filter0, filter0_len);
if (filter == NULL)
@@ -2202,9 +2266,13 @@ windivert_ioctl_bad_start_state:
DEBUG_ERROR("failed to compile filter", status);
goto windivert_ioctl_exit;
}
+ filter_len = filter0_len / sizeof(WINDIVERT_FILTER);
+ irp = WdfRequestWdmGetIrp(request);
+ process_id = (UINT32)IoGetRequestorProcessId(irp);
+ timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
{
goto windivert_ioctl_bad_start_state;
}
@@ -2213,34 +2281,43 @@ windivert_ioctl_bad_start_state:
switch (layer)
{
case WINDIVERT_LAYER_FLOW:
+ case WINDIVERT_LAYER_REFLECT:
if ((flags & WINDIVERT_FLAG_SNIFF) == 0 ||
(flags & WINDIVERT_FLAG_RECV_ONLY) == 0)
{
goto windivert_ioctl_bad_start_state;
}
break;
+
default:
break;
}
- context->state = WINDIVERT_CONTEXT_STATE_OPEN;
- context->filter = filter;
+ context->filter = filter;
+ context->filter_len = filter_len;
+ context->reflect.data.Timestamp = timestamp;
+ context->reflect.data.ProcessId = process_id;
+ context->reflect.data.Layer = context->layer;
+ context->reflect.data.Flags = context->flags;
+ context->reflect.data.Priority = context->priority16;
+ context->reflect.inserted = FALSE;
KeReleaseInStackQueuedSpinLock(&lock_handle);
- windivert_filter_analyze(filter, flags, &inbound, &outbound,
- &ipv4, &ipv6);
- status = windivert_install_callouts(context, layer, inbound,
- outbound, ipv4, ipv6);
+ windivert_reflect_event(context, WINDIVERT_EVENT_REFLECT_OPEN);
+
+ flags = ioctl->arg;
+ status = windivert_install_callouts(context, layer, flags);
break;
}
case IOCTL_WINDIVERT_SET_LAYER:
- ioctl = (windivert_ioctl_t)inbuf;
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
switch (ioctl->arg)
{
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
case WINDIVERT_LAYER_FLOW:
+ case WINDIVERT_LAYER_REFLECT:
break;
default:
status = STATUS_INVALID_PARAMETER;
@@ -2260,16 +2337,17 @@ windivert_ioctl_bad_start_state:
break;
case IOCTL_WINDIVERT_SET_PRIORITY:
- ioctl = (windivert_ioctl_t)inbuf;
- if (ioctl->arg < WINDIVERT_PRIORITY_MIN ||
- ioctl->arg > WINDIVERT_PRIORITY_MAX)
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
+ priority64 = (INT64)ioctl->arg - WINDIVERT_PRIORITY_MAX;
+ if (priority64 < WINDIVERT_PRIORITY_MIN ||
+ priority64 > WINDIVERT_PRIORITY_MAX)
{
status = STATUS_INVALID_PARAMETER;
DEBUG_ERROR("failed to set priority; value out of range",
status);
goto windivert_ioctl_exit;
}
- priority = WINDIVERT_CONTEXT_PRIORITY((UINT32)ioctl->arg);
+ priority32 = windivert_context_priority(priority64);
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
{
@@ -2277,12 +2355,13 @@ windivert_ioctl_bad_start_state:
status = STATUS_INVALID_DEVICE_STATE;
goto windivert_ioctl_exit;
}
- context->priority = priority;
+ context->priority16 = (INT16)priority64;
+ context->priority = priority32;
KeReleaseInStackQueuedSpinLock(&lock_handle);
break;
case IOCTL_WINDIVERT_SET_FLAGS:
- ioctl = (windivert_ioctl_t)inbuf;
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
if (!WINDIVERT_FLAGS_VALID(ioctl->arg))
{
status = STATUS_INVALID_PARAMETER;
@@ -2303,7 +2382,7 @@ windivert_ioctl_bad_start_state:
break;
case IOCTL_WINDIVERT_SET_PARAM:
- ioctl = (windivert_ioctl_t)inbuf;
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
value = ioctl->arg;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
@@ -2366,7 +2445,7 @@ windivert_ioctl_bad_start_state:
break;
case IOCTL_WINDIVERT_GET_PARAM:
- ioctl = (windivert_ioctl_t)inbuf;
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
if (outbuflen != sizeof(UINT64))
{
status = STATUS_INVALID_PARAMETER;
@@ -2629,7 +2708,7 @@ static void windivert_network_classify(context_t context,
BOOL impostor, sniff_mode, ok;
WDFOBJECT object;
PLIST_ENTRY old_entry;
- filter_t filter;
+ PWINDIVERT_FILTER filter;
LONGLONG timestamp;
NTSTATUS status;
@@ -2716,8 +2795,8 @@ static void windivert_network_classify(context_t context,
buffer_fst = buffer;
do
{
- BOOL match = windivert_filter(buffer_fst, network_data,
- /*flow_data=*/NULL, ipv4, outbound, loopback, impostor, filter);
+ BOOL match = windivert_filter(buffer_fst, layer, (PVOID)network_data,
+ ipv4, outbound, loopback, impostor, filter);
if (match)
{
break;
@@ -2745,10 +2824,11 @@ static void windivert_network_classify(context_t context,
sniff_mode = ((flags & WINDIVERT_FLAG_SNIFF) != 0);
while (!sniff_mode && buffer_itr != buffer_fst)
{
- ok = windivert_queue_work(context, buffer_itr, buffers, network_data,
- /*flow_data=*/NULL, layer, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
+ ok = windivert_queue_work(context, (PVOID)buffer_itr,
+ NET_BUFFER_DATA_LENGTH(buffer_itr), buffers, layer,
+ (PVOID)network_data, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
flags, priority, ipv4, outbound, loopback, impostor,
- /*match=*/FALSE, timestamp);
+ /*final=*/FALSE, /*match=*/FALSE, timestamp);
if (!ok)
{
goto windivert_network_classify_exit;
@@ -2757,10 +2837,11 @@ static void windivert_network_classify(context_t context,
}
// STEP (2): Queue the first matching packet buffer_fst:
- ok = windivert_queue_work(context, buffer_itr, buffers, network_data,
- /*flow_data=*/NULL, layer, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
- flags, priority, ipv4, outbound, loopback, impostor, /*match=*/TRUE,
- timestamp);
+ ok = windivert_queue_work(context, (PVOID)buffer_itr,
+ NET_BUFFER_DATA_LENGTH(buffer_itr), buffers, layer,
+ (PVOID)network_data, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
+ flags, priority, ipv4, outbound, loopback, impostor, /*final=*/FALSE,
+ /*match=*/TRUE, timestamp);
if (advance != 0)
{
// Advance the NET_BUFFER to its original position. Note that we can
@@ -2778,12 +2859,13 @@ static void windivert_network_classify(context_t context,
buffer_itr = NET_BUFFER_NEXT_NB(buffer_fst);
while (buffer_itr != NULL)
{
- BOOL match = windivert_filter(buffer_itr, network_data,
- /*flow_data=*/NULL, ipv4, outbound, loopback, impostor, filter);
- ok = windivert_queue_work(context, buffer_itr, buffers, network_data,
- /*flow_data=*/NULL, layer, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
- flags, priority, ipv4, outbound, loopback, impostor, match,
- timestamp);
+ BOOL match = windivert_filter(buffer_itr, layer, (PVOID)network_data,
+ ipv4, outbound, loopback, impostor, filter);
+ ok = windivert_queue_work(context, (PVOID)buffer_itr,
+ NET_BUFFER_DATA_LENGTH(buffer_itr), buffers, layer,
+ (PVOID)network_data, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
+ flags, priority, ipv4, outbound, loopback, impostor,
+ /*FINAL=*/FALSE, match, timestamp);
if (!ok)
{
goto windivert_network_classify_exit;
@@ -2907,7 +2989,7 @@ static void windivert_flow_established_classify(context_t context,
UINT16 layer_id;
BOOL match, ok;
WDFOBJECT object;
- filter_t filter;
+ PWINDIVERT_FILTER filter;
LONGLONG timestamp;
flow_t flow;
NTSTATUS status;
@@ -2941,14 +3023,15 @@ static void windivert_flow_established_classify(context_t context,
WdfObjectReference(object);
KeReleaseInStackQueuedSpinLock(&lock_handle);
- match = windivert_filter(/*buffer=*/NULL, /*network_data=*/NULL,
- flow_data, ipv4, outbound, loopback, /*impostor=*/FALSE, filter);
+ match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW,
+ (PVOID)flow_data, ipv4, outbound, loopback, /*impostor=*/FALSE, filter);
if (match)
{
- ok = windivert_queue_work(context, /*buffer=*/NULL, /*buffers=*/NULL,
- /*network_data=*/NULL, flow_data, /*layer=*/WINDIVERT_LAYER_FLOW,
+ ok = windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0,
+ /*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW, (PVOID)flow_data,
/*event=*/WINDIVERT_EVENT_FLOW_ESTABLISHED, flags, /*priority=*/0,
- ipv4, outbound, loopback, /*impostor=*/FALSE, match, timestamp);
+ ipv4, outbound, loopback, /*impostor=*/FALSE, /*final=*/FALSE,
+ match, timestamp);
if (!ok)
{
WdfObjectDereference(object);
@@ -3021,7 +3104,7 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
BOOL match, cleanup;
WDFOBJECT object;
context_t context;
- filter_t filter;
+ PWINDIVERT_FILTER filter;
LONGLONG timestamp;
flow_t flow;
@@ -3051,16 +3134,16 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
flags = context->flags;
KeReleaseInStackQueuedSpinLock(&lock_handle);
- match = windivert_filter(/*buffer=*/NULL, /*network_data=*/NULL,
- &flow->data, !flow->ipv6, flow->outbound, flow->loopback,
+ match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW,
+ (PVOID)&flow->data, !flow->ipv6, flow->outbound, flow->loopback,
/*impostor=*/FALSE, filter);
if (match)
{
- (VOID)windivert_queue_work(context, /*buffer=*/NULL, /*buffers=*/NULL,
- /*network_data=*/NULL, &flow->data, /*layer=*/WINDIVERT_LAYER_FLOW,
- /*event=*/WINDIVERT_EVENT_FLOW_DELETED, flags, /*priority=*/0,
- !flow->ipv6, flow->outbound, flow->loopback, /*impostor=*/FALSE,
- match, timestamp);
+ (VOID)windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0,
+ /*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW,
+ (PVOID)&flow->data, /*event=*/WINDIVERT_EVENT_FLOW_DELETED, flags,
+ /*priority=*/0, !flow->ipv6, flow->outbound, flow->loopback,
+ /*impostor=*/FALSE, /*final=*/FALSE, match, timestamp);
}
windivert_flow_delete_notify_exit:
@@ -3109,20 +3192,22 @@ VOID windivert_worker(IN WDFWORKITEM item)
/*
* Queue work.
*/
-static BOOL windivert_queue_work(context_t context, PNET_BUFFER buffer,
- PNET_BUFFER_LIST buffers, PWINDIVERT_NETWORK_DATA network_data,
- PWINDIVERT_FLOW_DATA flow_data, WINDIVERT_LAYER layer,
- WINDIVERT_EVENT event, UINT64 flags, UINT32 priority, BOOL ipv4,
- BOOL outbound, BOOL loopback, BOOL impostor, BOOL match,
- LONGLONG timestamp)
+static BOOL windivert_queue_work(context_t context, PVOID packet,
+ ULONG packet_len, PNET_BUFFER_LIST buffers, WINDIVERT_LAYER layer,
+ PVOID layer_data, WINDIVERT_EVENT event, UINT64 flags, UINT32 priority,
+ BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, BOOL final,
+ BOOL match, LONGLONG timestamp)
{
KLOCK_QUEUE_HANDLE lock_handle;
+ PNET_BUFFER buffer;
packet_t work;
- ULONG packet_len;
PVOID packet_data;
UINT8 *data;
PLIST_ENTRY old_entry;
NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksums;
+ PWINDIVERT_NETWORK_DATA network_data;
+ PWINDIVERT_FLOW_DATA flow_data;
+ PWINDIVERT_REFLECT_DATA reflect_data;
BOOL pseudo_ip_checksum, pseudo_tcp_checksum, pseudo_udp_checksum;
if (!match && (flags & WINDIVERT_FLAG_SNIFF) != 0)
@@ -3139,7 +3224,8 @@ static BOOL windivert_queue_work(context_t context, PNET_BUFFER buffer,
{
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
- packet_len = NET_BUFFER_DATA_LENGTH(buffer);
+ buffer = (PNET_BUFFER)packet;
+ network_data = (PWINDIVERT_NETWORK_DATA)layer_data;
if (packet_len > UINT16_MAX)
{
// Cannot handle oversized packet
@@ -3185,6 +3271,7 @@ static BOOL windivert_queue_work(context_t context, PNET_BUFFER buffer,
break;
case WINDIVERT_LAYER_FLOW:
+ flow_data = (PWINDIVERT_FLOW_DATA)layer_data;
work = (packet_t)windivert_malloc(
WINDIVERT_PACKET_SIZE(WINDIVERT_FLOW_DATA, 0), FALSE);
if (work == NULL)
@@ -3198,6 +3285,24 @@ static BOOL windivert_queue_work(context_t context, PNET_BUFFER buffer,
FALSE;
break;
+ case WINDIVERT_LAYER_REFLECT:
+ reflect_data = (PWINDIVERT_REFLECT_DATA)layer_data;
+ work = (packet_t)windivert_malloc(
+ WINDIVERT_PACKET_SIZE(WINDIVERT_REFLECT_DATA, packet_len),
+ FALSE);
+ if (work == NULL)
+ {
+ return TRUE;
+ }
+ work->packet_len = packet_len;
+ data = WINDIVERT_LAYER_DATA_PTR(work);
+ RtlCopyMemory(data, reflect_data, sizeof(WINDIVERT_REFLECT_DATA));
+ data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_REFLECT_DATA, work);
+ RtlCopyMemory(data, packet, packet_len);
+ pseudo_ip_checksum = TRUE;
+ pseudo_tcp_checksum = pseudo_udp_checksum = FALSE;
+ break;
+
default:
return TRUE;
}
@@ -3211,6 +3316,7 @@ static BOOL windivert_queue_work(context_t context, PNET_BUFFER buffer,
work->pseudo_ip_checksum = (pseudo_ip_checksum? 1: 0);
work->pseudo_tcp_checksum = (pseudo_tcp_checksum? 1: 0);
work->pseudo_udp_checksum = (pseudo_udp_checksum? 1: 0);
+ work->final = (final? 1: 0);
work->match = match;
work->priority = priority;
work->timestamp = timestamp;
@@ -3235,7 +3341,7 @@ static BOOL windivert_queue_work(context_t context, PNET_BUFFER buffer,
context->worker_curr =
(context->worker_curr + 1) % WINDIVERT_CONTEXT_MAXWORKERS;
KeReleaseInStackQueuedSpinLock(&lock_handle);
-
+
if (old_entry != NULL)
{
work = CONTAINING_RECORD(old_entry, struct packet_s, entry);
@@ -3505,6 +3611,11 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
NTSTATUS status;
// Parse the headers:
+ if (buffer == NULL)
+ {
+ DEBUG("FILTER: REJECT (packet is NULL)");
+ return FALSE;
+ }
tot_len = NET_BUFFER_DATA_LENGTH(buffer);
if (tot_len < sizeof(WINDIVERT_IPHDR))
{
@@ -3660,9 +3771,9 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
/*
* Checks if the given network packet is of interest.
*/
-static BOOL windivert_filter(PNET_BUFFER buffer,
- PWINDIVERT_NETWORK_DATA network_data, PWINDIVERT_FLOW_DATA flow_data,
- BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, filter_t filter)
+static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
+ PVOID layer_data, BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor,
+ PWINDIVERT_FILTER filter)
{
PWINDIVERT_IPHDR ip_header = NULL;
PWINDIVERT_IPV6HDR ipv6_header = NULL;
@@ -3672,21 +3783,32 @@ static BOOL windivert_filter(PNET_BUFFER buffer,
PWINDIVERT_UDPHDR udp_header = NULL;
UINT payload_len = 0;
UINT16 ip, ttl;
+ PWINDIVERT_NETWORK_DATA network_data = NULL;
+ PWINDIVERT_FLOW_DATA flow_data = NULL;
+ PWINDIVERT_REFLECT_DATA reflect_data = NULL;
NTSTATUS status;
- if (network_data != NULL)
+ switch (layer)
{
- if (!windivert_parse_headers(buffer, ipv4, &ip_header, &ipv6_header,
- &icmp_header, &icmpv6_header, &tcp_header, &udp_header,
- &payload_len))
- {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ if (!windivert_parse_headers(buffer, ipv4, &ip_header, &ipv6_header,
+ &icmp_header, &icmpv6_header, &tcp_header, &udp_header,
+ &payload_len))
+ {
+ return FALSE;
+ }
+ network_data = (PWINDIVERT_NETWORK_DATA)layer_data;
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ flow_data = (PWINDIVERT_FLOW_DATA)layer_data;
+ break;
+ case WINDIVERT_LAYER_REFLECT:
+ reflect_data = (PWINDIVERT_REFLECT_DATA)layer_data;
+ break;
+ default:
+ DEBUG("FILTER: REJECT (invalid parameter)");
return FALSE;
- }
- }
- else if (flow_data == NULL)
- {
- DEBUG("FILTER: REJECT (invalid parameter)");
- return FALSE;
}
// Execute the filter:
@@ -3701,38 +3823,122 @@ static BOOL windivert_filter(PNET_BUFFER buffer,
field[1] = 0;
field[2] = 0;
field[3] = 0;
- switch (filter[ip].protocol)
+
+ switch (filter[ip].field)
{
- case WINDIVERT_FILTER_PROTOCOL_NONE:
+ case WINDIVERT_FILTER_FIELD_ZERO:
result = TRUE;
break;
- case WINDIVERT_FILTER_PROTOCOL_NETWORK:
- result = (network_data != NULL);
+ case WINDIVERT_FILTER_FIELD_INBOUND:
+ case WINDIVERT_FILTER_FIELD_OUTBOUND:
+ case WINDIVERT_FILTER_FIELD_LOOPBACK:
+ case WINDIVERT_FILTER_FIELD_IMPOSTOR:
+ case WINDIVERT_FILTER_FIELD_IP:
+ case WINDIVERT_FILTER_FIELD_IPV6:
+ case WINDIVERT_FILTER_FIELD_ICMP:
+ case WINDIVERT_FILTER_FIELD_ICMPV6:
+ case WINDIVERT_FILTER_FIELD_TCP:
+ case WINDIVERT_FILTER_FIELD_UDP:
+ result = (layer != WINDIVERT_LAYER_REFLECT);
break;
- case WINDIVERT_FILTER_PROTOCOL_FLOW:
- result = (flow_data != NULL);
+ case WINDIVERT_FILTER_FIELD_IFIDX:
+ case WINDIVERT_FILTER_FIELD_SUBIFIDX:
+ result = (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ result = result && (network_data != NULL);
break;
- case WINDIVERT_FILTER_PROTOCOL_IP:
- result = (ip_header != NULL);
+ case WINDIVERT_FILTER_FIELD_LOCALADDR:
+ case WINDIVERT_FILTER_FIELD_REMOTEADDR:
+ case WINDIVERT_FILTER_FIELD_LOCALPORT:
+ case WINDIVERT_FILTER_FIELD_REMOTEPORT:
+ case WINDIVERT_FILTER_FIELD_PROTOCOL:
+ result = (layer == WINDIVERT_LAYER_FLOW);
+ result = result && (flow_data != NULL);
break;
- case WINDIVERT_FILTER_PROTOCOL_IPV6:
- result = (ipv6_header != NULL);
+ case WINDIVERT_FILTER_FIELD_PROCESSID:
+ result = ((layer == WINDIVERT_LAYER_FLOW &&
+ flow_data != NULL) ||
+ (layer == WINDIVERT_LAYER_REFLECT &&
+ reflect_data != NULL));
break;
- case WINDIVERT_FILTER_PROTOCOL_ICMP:
- result = (icmp_header != NULL);
+ case WINDIVERT_FILTER_FIELD_LAYER:
+ result = (layer == WINDIVERT_LAYER_REFLECT);
+ result = result && (reflect_data != NULL);
break;
- case WINDIVERT_FILTER_PROTOCOL_ICMPV6:
- result = (icmpv6_header != NULL);
+ case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
+ case WINDIVERT_FILTER_FIELD_IP_TOS:
+ case WINDIVERT_FILTER_FIELD_IP_LENGTH:
+ case WINDIVERT_FILTER_FIELD_IP_ID:
+ case WINDIVERT_FILTER_FIELD_IP_DF:
+ case WINDIVERT_FILTER_FIELD_IP_MF:
+ case WINDIVERT_FILTER_FIELD_IP_FRAGOFF:
+ case WINDIVERT_FILTER_FIELD_IP_TTL:
+ case WINDIVERT_FILTER_FIELD_IP_PROTOCOL:
+ case WINDIVERT_FILTER_FIELD_IP_CHECKSUM:
+ case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
+ case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
+ result = (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ result = result && (ip_header != NULL);
break;
- case WINDIVERT_FILTER_PROTOCOL_TCP:
- result = (tcp_header != NULL);
+ case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS:
+ case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL:
+ case WINDIVERT_FILTER_FIELD_IPV6_LENGTH:
+ case WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR:
+ case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT:
+ case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
+ case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
+ result = (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ result = result && (ipv6_header != NULL);
break;
- case WINDIVERT_FILTER_PROTOCOL_UDP:
- result = (udp_header != NULL);
+ case WINDIVERT_FILTER_FIELD_ICMP_TYPE:
+ case WINDIVERT_FILTER_FIELD_ICMP_CODE:
+ case WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM:
+ case WINDIVERT_FILTER_FIELD_ICMP_BODY:
+ result = (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ result = result && (icmp_header != NULL);
+ break;
+ case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE:
+ case WINDIVERT_FILTER_FIELD_ICMPV6_CODE:
+ case WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM:
+ case WINDIVERT_FILTER_FIELD_ICMPV6_BODY:
+ result = (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ result = result && (icmpv6_header != NULL);
+ break;
+ case WINDIVERT_FILTER_FIELD_TCP_SRCPORT:
+ case WINDIVERT_FILTER_FIELD_TCP_DSTPORT:
+ case WINDIVERT_FILTER_FIELD_TCP_SEQNUM:
+ case WINDIVERT_FILTER_FIELD_TCP_ACKNUM:
+ case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH:
+ case WINDIVERT_FILTER_FIELD_TCP_URG:
+ case WINDIVERT_FILTER_FIELD_TCP_ACK:
+ case WINDIVERT_FILTER_FIELD_TCP_PSH:
+ case WINDIVERT_FILTER_FIELD_TCP_RST:
+ case WINDIVERT_FILTER_FIELD_TCP_SYN:
+ case WINDIVERT_FILTER_FIELD_TCP_FIN:
+ case WINDIVERT_FILTER_FIELD_TCP_WINDOW:
+ case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
+ case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
+ result = (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ result = result && (tcp_header != NULL);
+ break;
+ case WINDIVERT_FILTER_FIELD_UDP_SRCPORT:
+ case WINDIVERT_FILTER_FIELD_UDP_DSTPORT:
+ case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
+ case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
+ result = (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ result = result && (udp_header != NULL);
break;
default:
- error = TRUE;
result = FALSE;
+ error = TRUE;
break;
}
if (result)
@@ -3971,7 +4177,12 @@ static BOOL windivert_filter(PNET_BUFFER buffer,
field[0] = (UINT32)flow_data->Protocol;
break;
case WINDIVERT_FILTER_FIELD_PROCESSID:
- field[0] = flow_data->ProcessId;
+ field[0] = (flow_data != NULL?
+ flow_data->ProcessId:
+ reflect_data->ProcessId);
+ break;
+ case WINDIVERT_FILTER_FIELD_LAYER:
+ field[0] = reflect_data->Layer;
break;
default:
error = TRUE;
@@ -4028,166 +4239,28 @@ static BOOL windivert_filter(PNET_BUFFER buffer,
return FALSE;
}
-/*
- * Analyze the given filter.
- */
-static void windivert_filter_analyze(filter_t filter, UINT64 flags,
- BOOL *inbound, BOOL *outbound, BOOL *ipv4, BOOL *ipv6)
-{
- BOOL result;
-
- // Send-only?
- if ((flags & WINDIVERT_FLAG_SEND_ONLY) != 0)
- {
-windivert_filter_analyze_send_only:
- *inbound = FALSE;
- *outbound = FALSE;
- *ipv4 = FALSE;
- *ipv6 = FALSE;
- return;
- }
-
- // False filter?
- result = windivert_filter_test(filter, 0, WINDIVERT_FILTER_PROTOCOL_NONE,
- WINDIVERT_FILTER_FIELD_ZERO, 0);
- if (!result)
- {
- goto windivert_filter_analyze_send_only;
- }
-
- // Inbound?
- result = windivert_filter_test(filter, 0, WINDIVERT_FILTER_PROTOCOL_NONE,
- WINDIVERT_FILTER_FIELD_INBOUND, 1);
- if (result)
- {
- result = windivert_filter_test(filter, 0,
- WINDIVERT_FILTER_PROTOCOL_NONE, WINDIVERT_FILTER_FIELD_OUTBOUND,
- 0);
- }
- *inbound = result;
-
- // Outbound?
- result = windivert_filter_test(filter, 0, WINDIVERT_FILTER_PROTOCOL_NONE,
- WINDIVERT_FILTER_FIELD_OUTBOUND, 1);
- if (result)
- {
- result = windivert_filter_test(filter, 0,
- WINDIVERT_FILTER_PROTOCOL_NONE, WINDIVERT_FILTER_FIELD_INBOUND, 0);
- }
- *outbound = result;
-
- // IPv4?
- result = windivert_filter_test(filter, 0, WINDIVERT_FILTER_PROTOCOL_NONE,
- WINDIVERT_FILTER_FIELD_IP, 1);
- if (result)
- {
- result = windivert_filter_test(filter, 0,
- WINDIVERT_FILTER_PROTOCOL_NONE, WINDIVERT_FILTER_FIELD_IPV6, 0);
- }
- *ipv4 = result;
-
- // Ipv6?
- result = windivert_filter_test(filter, 0, WINDIVERT_FILTER_PROTOCOL_NONE,
- WINDIVERT_FILTER_FIELD_IPV6, 1);
- if (result)
- {
- result = windivert_filter_test(filter, 0,
- WINDIVERT_FILTER_PROTOCOL_NONE, WINDIVERT_FILTER_FIELD_IP, 0);
- }
- *ipv6 = result;
-}
-
-/*
- * Test a filter for any packet where field = arg.
- */
-static BOOL windivert_filter_test(filter_t filter, UINT16 ip, UINT8 protocol,
- UINT8 field, UINT32 arg)
-{
- BOOL known = FALSE;
- BOOL result = FALSE;
-
- if (ip == WINDIVERT_FILTER_RESULT_ACCEPT)
- {
- return TRUE;
- }
- if (ip == WINDIVERT_FILTER_RESULT_REJECT)
- {
- return FALSE;
- }
- if (ip > WINDIVERT_FILTER_MAXLEN)
- {
- return FALSE;
- }
-
- if (filter[ip].protocol == protocol &&
- filter[ip].field == field)
- {
- known = TRUE;
- switch (filter[ip].test)
- {
- case WINDIVERT_FILTER_TEST_EQ:
- result = (arg == filter[ip].arg[0]);
- break;
- case WINDIVERT_FILTER_TEST_NEQ:
- result = (arg != filter[ip].arg[0]);
- break;
- case WINDIVERT_FILTER_TEST_LT:
- result = (arg < filter[ip].arg[0]);
- break;
- case WINDIVERT_FILTER_TEST_LEQ:
- result = (arg <= filter[ip].arg[0]);
- break;
- case WINDIVERT_FILTER_TEST_GT:
- result = (arg > filter[ip].arg[0]);
- break;
- case WINDIVERT_FILTER_TEST_GEQ:
- result = (arg >= filter[ip].arg[0]);
- break;
- default:
- result = FALSE;
- break;
- }
- }
-
- if (!known)
- {
- result = windivert_filter_test(filter, filter[ip].success, protocol,
- field, arg);
- if (result)
- {
- return TRUE;
- }
- return windivert_filter_test(filter, filter[ip].failure, protocol,
- field, arg);
- }
- else
- {
- ip = (result? filter[ip].success: filter[ip].failure);
- return windivert_filter_test(filter, ip, protocol, field, arg);
- }
-}
-
/*
* Compile a WinDivert filter from an IOCTL.
*/
-static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
- size_t ioctl_filter_len)
+static PWINDIVERT_FILTER windivert_filter_compile(
+ PWINDIVERT_FILTER ioctl_filter, size_t ioctl_filter_len)
{
- filter_t filter = NULL;
+ PWINDIVERT_FILTER filter = NULL;
UINT16 i;
size_t length;
- if (ioctl_filter_len % sizeof(struct windivert_ioctl_filter_s) != 0)
+ if (ioctl_filter_len % sizeof(WINDIVERT_FILTER) != 0)
{
goto windivert_filter_compile_error;
}
- length = ioctl_filter_len / sizeof(struct windivert_ioctl_filter_s);
+ length = ioctl_filter_len / sizeof(WINDIVERT_FILTER);
if (length >= WINDIVERT_FILTER_MAXLEN || length == 0)
{
goto windivert_filter_compile_error;
}
- filter = (filter_t)windivert_malloc(length*sizeof(struct filter_s), FALSE);
+ filter = (PWINDIVERT_FILTER)windivert_malloc(
+ length * sizeof(WINDIVERT_FILTER), FALSE);
if (filter == NULL)
{
goto windivert_filter_compile_error;
@@ -4275,6 +4348,12 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
goto windivert_filter_compile_error;
}
break;
+ case WINDIVERT_FILTER_FIELD_LAYER:
+ if (ioctl_filter[i].arg[0] > WINDIVERT_LAYER_MAX)
+ {
+ goto windivert_filter_compile_error;
+ }
+ break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH:
if (ioctl_filter[i].arg[0] > 0x0F)
@@ -4345,96 +4424,6 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
filter[i].arg[1] = ioctl_filter[i].arg[1];
filter[i].arg[2] = ioctl_filter[i].arg[2];
filter[i].arg[3] = ioctl_filter[i].arg[3];
-
- // Protocol selection:
- switch (ioctl_filter[i].field)
- {
- case WINDIVERT_FILTER_FIELD_ZERO:
- case WINDIVERT_FILTER_FIELD_INBOUND:
- case WINDIVERT_FILTER_FIELD_OUTBOUND:
- case WINDIVERT_FILTER_FIELD_LOOPBACK:
- case WINDIVERT_FILTER_FIELD_IMPOSTOR:
- case WINDIVERT_FILTER_FIELD_IP:
- case WINDIVERT_FILTER_FIELD_IPV6:
- case WINDIVERT_FILTER_FIELD_ICMP:
- case WINDIVERT_FILTER_FIELD_ICMPV6:
- case WINDIVERT_FILTER_FIELD_TCP:
- case WINDIVERT_FILTER_FIELD_UDP:
- filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_NONE;
- break;
- case WINDIVERT_FILTER_FIELD_IFIDX:
- case WINDIVERT_FILTER_FIELD_SUBIFIDX:
- filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_NETWORK;
- break;
- case WINDIVERT_FILTER_FIELD_LOCALADDR:
- case WINDIVERT_FILTER_FIELD_REMOTEADDR:
- case WINDIVERT_FILTER_FIELD_LOCALPORT:
- case WINDIVERT_FILTER_FIELD_REMOTEPORT:
- case WINDIVERT_FILTER_FIELD_PROTOCOL:
- filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_FLOW;
- break;
- case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
- case WINDIVERT_FILTER_FIELD_IP_TOS:
- case WINDIVERT_FILTER_FIELD_IP_LENGTH:
- case WINDIVERT_FILTER_FIELD_IP_ID:
- case WINDIVERT_FILTER_FIELD_IP_DF:
- case WINDIVERT_FILTER_FIELD_IP_MF:
- case WINDIVERT_FILTER_FIELD_IP_FRAGOFF:
- case WINDIVERT_FILTER_FIELD_IP_TTL:
- case WINDIVERT_FILTER_FIELD_IP_PROTOCOL:
- case WINDIVERT_FILTER_FIELD_IP_CHECKSUM:
- case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
- case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
- filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_IP;
- break;
- case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS:
- case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL:
- case WINDIVERT_FILTER_FIELD_IPV6_LENGTH:
- case WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR:
- case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT:
- case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
- case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
- filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_IPV6;
- break;
- case WINDIVERT_FILTER_FIELD_ICMP_TYPE:
- case WINDIVERT_FILTER_FIELD_ICMP_CODE:
- case WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM:
- case WINDIVERT_FILTER_FIELD_ICMP_BODY:
- filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_ICMP;
- break;
- case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE:
- case WINDIVERT_FILTER_FIELD_ICMPV6_CODE:
- case WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM:
- case WINDIVERT_FILTER_FIELD_ICMPV6_BODY:
- filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_ICMPV6;
- break;
- case WINDIVERT_FILTER_FIELD_TCP_SRCPORT:
- case WINDIVERT_FILTER_FIELD_TCP_DSTPORT:
- case WINDIVERT_FILTER_FIELD_TCP_SEQNUM:
- case WINDIVERT_FILTER_FIELD_TCP_ACKNUM:
- case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH:
- case WINDIVERT_FILTER_FIELD_TCP_URG:
- case WINDIVERT_FILTER_FIELD_TCP_ACK:
- case WINDIVERT_FILTER_FIELD_TCP_PSH:
- case WINDIVERT_FILTER_FIELD_TCP_RST:
- case WINDIVERT_FILTER_FIELD_TCP_SYN:
- case WINDIVERT_FILTER_FIELD_TCP_FIN:
- case WINDIVERT_FILTER_FIELD_TCP_WINDOW:
- case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
- case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
- case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
- filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_TCP;
- break;
- case WINDIVERT_FILTER_FIELD_UDP_SRCPORT:
- case WINDIVERT_FILTER_FIELD_UDP_DSTPORT:
- case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
- case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
- case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
- filter[i].protocol = WINDIVERT_FILTER_PROTOCOL_UDP;
- break;
- default:
- goto windivert_filter_compile_error;
- }
}
return filter;
@@ -4445,3 +4434,330 @@ windivert_filter_compile_error:
return NULL;
}
+/****************************************************************************/
+/* WINDIVERT REFLECT MANAGER IMPLEMENTATION */
+/****************************************************************************/
+
+#include "windivert_shared.c"
+
+/*
+ * WinDivert reflect state.
+ */
+static BOOL reflect_inited = FALSE; // Reflection initialized?
+static KSPIN_LOCK reflect_lock; // Reflect lock.
+static LIST_ENTRY reflect_event_queue; // Reflect event queue.
+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.
+
+/*
+ * Initialize the reflection layer implementation.
+ */
+static NTSTATUS windivert_reflect_init(WDFOBJECT parent)
+{
+ WDF_WORKITEM_CONFIG item_config;
+ WDF_OBJECT_ATTRIBUTES obj_attrs;
+ NTSTATUS status;
+
+ KeInitializeSpinLock(&reflect_lock);
+ InitializeListHead(&reflect_event_queue);
+ InitializeListHead(&reflect_contexts);
+ InitializeListHead(&reflect_waiters);
+ WDF_WORKITEM_CONFIG_INIT(&item_config, windivert_reflect_worker);
+ item_config.AutomaticSerialization = TRUE;
+ WDF_OBJECT_ATTRIBUTES_INIT(&obj_attrs);
+ obj_attrs.ParentObject = parent;
+ status = WdfWorkItemCreate(&item_config, &obj_attrs, &reflect_worker);
+ if (!NT_SUCCESS(status))
+ {
+ DEBUG_ERROR("failed to create reflection work item", status);
+ return status;
+ }
+ reflect_inited = TRUE;
+ return STATUS_SUCCESS;
+}
+
+/*
+ * Cleanup the reflection layer implementation.
+ */
+static void windivert_reflect_close(void)
+{
+ if (!reflect_inited)
+ {
+ return;
+ }
+ WdfWorkItemFlush(reflect_worker);
+ WdfObjectDelete(reflect_worker);
+}
+
+/*
+ * WinDivert handle reflect event.
+ */
+static void windivert_reflect_event(context_t context, WINDIVERT_EVENT event)
+{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ WDFOBJECT object;
+ reflect_event_t reflect_event;
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ object = (WDFOBJECT)context->object;
+ if (event == WINDIVERT_EVENT_REFLECT_OPEN)
+ {
+ // To be released on WINDIVERT_EVENT_REFLECT_CLOSE. This ensures the
+ // context object remains valid until the close event has been handled.
+ WdfObjectReference(object);
+ }
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ // Queue the event:
+ reflect_event = (reflect_event_t)windivert_malloc(
+ sizeof(struct reflect_event_s), FALSE);
+ if (reflect_event == NULL)
+ {
+ WdfObjectDereference(object);
+ return;
+ }
+ reflect_event->context = context;
+ reflect_event->event = event;
+ KeAcquireInStackQueuedSpinLock(&reflect_lock, &lock_handle);
+ InsertTailList(&reflect_event_queue, &reflect_event->entry);
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ WdfWorkItemEnqueue(reflect_worker);
+}
+
+/*
+ * Create REFLECT layer "pseudo" packet to pass the filter.
+ */
+static PWINDIVERT_IPHDR windivert_reflect_pseudo_packet(context_t context,
+ ULONG *len_ptr)
+{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ UINT16 total_len;
+ UINT8 *packet;
+ char *object;
+ PWINDIVERT_FILTER filter;
+ UINT8 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.
+
+ total_len = sizeof(WINDIVERT_IPHDR) + WINDIVERT_OBJECT_MAXLEN;
+ packet = windivert_malloc(total_len, TRUE);
+ if (packet == NULL)
+ {
+ return NULL;
+ }
+
+ iphdr = (PWINDIVERT_IPHDR)packet;
+ object = (char *)(iphdr + 1);
+
+ stream.data = object;
+ stream.pos = 0;
+ stream.max = WINDIVERT_OBJECT_MAXLEN;
+ stream.overflow = FALSE;
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ filter = context->filter;
+ filter_len = context->filter_len;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ WinDivertSerializeFilter(&stream, filter, filter_len);
+
+ if (stream.overflow)
+ {
+ windivert_free(packet);
+ return NULL;
+ }
+
+ 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;
+}
+
+/*
+ * Notify all REFLECT layer contexts a new event.
+ */
+static void windivert_reflect_event_notify(context_t context,
+ LONGLONG timestamp, WINDIVERT_EVENT event)
+{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ PLIST_ENTRY entry;
+ context_t waiter;
+ PWINDIVERT_FILTER filter;
+ PWINDIVERT_IPHDR packet = NULL;
+ ULONG packet_len;
+ BOOL match;
+
+ entry = reflect_waiters.Flink;
+ while (entry != &reflect_waiters)
+ {
+ waiter = CONTAINING_RECORD(entry, struct context_s, reflect.entry);
+ entry = entry->Flink;
+ KeAcquireInStackQueuedSpinLock(&waiter->lock, &lock_handle);
+ filter = waiter->filter;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ match = windivert_filter(/*buffer=*/NULL,
+ /*layer=*/WINDIVERT_LAYER_REFLECT, (PVOID)&context->reflect.data,
+ /*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE,
+ /*impostor=*/FALSE, filter);
+ if (!match)
+ {
+ continue;
+ }
+ if (packet == NULL)
+ {
+ packet = windivert_reflect_pseudo_packet(context, &packet_len);
+ if (packet == NULL)
+ {
+ return;
+ }
+ }
+ (VOID)windivert_queue_work(waiter, (PVOID)packet, packet_len,
+ /*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT,
+ (PVOID)&context->reflect.data, event, /*flags=*/0, /*priority=*/0,
+ /*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE,
+ /*impostor=*/FALSE, /*final=*/FALSE, /*match=*/TRUE, timestamp);
+ }
+
+ windivert_free(packet);
+}
+
+/*
+ * Notify a new REFLECT layer context of all existing open handles.
+ */
+static void windivert_reflect_established_notify(context_t context,
+ LONGLONG timestamp)
+{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ PLIST_ENTRY entry;
+ BOOL match, ok, final;
+ context_t waiter;
+ PWINDIVERT_FILTER filter;
+ PWINDIVERT_IPHDR packet;
+ ULONG packet_len;
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ filter = context->filter;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ entry = reflect_contexts.Flink;
+ while (entry != &reflect_contexts)
+ {
+ waiter = CONTAINING_RECORD(entry, struct context_s, reflect.entry);
+ entry = entry->Flink;
+ match = windivert_filter(/*buffer=*/NULL,
+ /*layer=*/WINDIVERT_LAYER_REFLECT, (PVOID)&waiter->reflect.data,
+ /*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE,
+ /*impostor=*/FALSE, filter);
+ if (!match)
+ {
+ continue;
+ }
+ packet = windivert_reflect_pseudo_packet(waiter, &packet_len);
+ if (packet == NULL)
+ {
+ continue;
+ }
+ final = (entry == &reflect_contexts);
+ ok = windivert_queue_work(context, (PVOID)packet, packet_len,
+ /*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT,
+ (PVOID)&waiter->reflect.data,
+ /*event=*/WINDIVERT_EVENT_REFLECT_ESTABLISHED, /*flags=*/0,
+ /*priority=*/0, /*ipv4=*/TRUE, /*outbound=*/FALSE,
+ /*loopback=*/FALSE, /*impostor=*/FALSE, final, /*match=*/TRUE,
+ timestamp);
+ windivert_free(packet);
+ if (!ok)
+ {
+ break;
+ }
+ }
+}
+
+/*
+ * WinDivert REFLECT worker.
+ */
+static void windivert_reflect_worker(IN WDFWORKITEM item)
+{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ PLIST_ENTRY entry;
+ context_t context;
+ LONGLONG timestamp;
+ WINDIVERT_EVENT event;
+ reflect_event_t reflect_event;
+ WDFOBJECT object;
+ WINDIVERT_LAYER layer;
+
+ // All reflection events are serialized and handled by this worker.
+ // This ensures that we are always operating on a consistent "snapshot"
+ // of the WinDivert handle state. This worker also has exclusive control
+ // over reflect_contexts/reflect_waiters, so locking is not required.
+
+ KeAcquireInStackQueuedSpinLock(&reflect_lock, &lock_handle);
+ while (!IsListEmpty(&reflect_event_queue))
+ {
+ entry = RemoveHeadList(&reflect_event_queue);
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ reflect_event = CONTAINING_RECORD(entry, struct reflect_event_s, entry);
+ context = reflect_event->context;
+ event = reflect_event->event;
+ windivert_free(reflect_event);
+
+ DEBUG("REFLECT: %s event for WinDivert context (context=%p)",
+ (event == WINDIVERT_EVENT_REFLECT_OPEN? "open": "close"), context);
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ object = (WDFOBJECT)context->object;
+ layer = context->layer;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
+ switch (event)
+ {
+ case WINDIVERT_EVENT_REFLECT_OPEN:
+ context->reflect.inserted = TRUE;
+ if (layer != WINDIVERT_LAYER_REFLECT)
+ {
+ InsertTailList(&reflect_contexts, &context->reflect.entry);
+ }
+ else
+ {
+ InsertTailList(&reflect_waiters, &context->reflect.entry);
+ windivert_reflect_established_notify(context, timestamp);
+ }
+ break;
+
+ case WINDIVERT_EVENT_REFLECT_CLOSE:
+ if (context->reflect.inserted)
+ {
+ RemoveEntryList(&context->reflect.entry);
+ }
+ break;
+ }
+
+ if (layer != WINDIVERT_LAYER_REFLECT)
+ {
+ windivert_reflect_event_notify(context, timestamp, event);
+ }
+ if (event == WINDIVERT_EVENT_REFLECT_CLOSE)
+ {
+ WdfObjectDereference(object);
+ }
+
+ KeAcquireInStackQueuedSpinLock(&reflect_lock, &lock_handle);
+ }
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+}
+
diff --git a/test/test.c b/test/test.c
index edd7455..f2bd160 100644
--- a/test/test.c
+++ b/test/test.c
@@ -241,6 +241,9 @@ static struct test tests[] =
"false): false): false): false)", &pkt_http_request, TRUE},
{"(outbound? (ip? (tcp.DstPort == 80? (tcp.PayloadLength == 0? true: "
"false): false): false): false)", &pkt_http_request, FALSE},
+ {"(ipv6? tcp and tcp.DstPort = 1234 and (tcp.SrcPort = 999? !tcp.UrgPtr: "
+ "tcp.Syn) or udp: ip and tcp.DstPort == 80)",
+ &pkt_http_request, TRUE},
{"udp", &pkt_dns_request, TRUE},
{"udp && udp.SrcPort > 1 && ipv6", &pkt_dns_request, FALSE},
{"udp.DstPort == 53", &pkt_dns_request, TRUE},
@@ -388,21 +391,26 @@ static BOOL run_test(HANDLE inject_handle, const char *filter,
OVERLAPPED overlapped;
const char *err_str;
UINT err_pos;
+ PWINDIVERT_IPHDR iphdr = NULL;
HANDLE handle = INVALID_HANDLE_VALUE, handle0 = INVALID_HANDLE_VALUE,
event = NULL;
// (0) Verify the test data:
- if (!WinDivertHelperCheckFilter(filter, WINDIVERT_LAYER_NETWORK, &err_str,
- &err_pos))
+ if (!WinDivertHelperCompileFilter(filter, WINDIVERT_LAYER_NETWORK,
+ NULL, 0, &err_str, &err_pos))
{
fprintf(stderr, "error: filter string \"%s\" is invalid with error "
"\"%s\" (position=%u)\n", filter, err_str, err_pos);
goto failed;
}
+ WinDivertHelperParsePacket((PVOID)packet, packet_len, &iphdr, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL);
memset(&addr, 0, sizeof(addr));
- addr.Direction = WINDIVERT_DIRECTION_OUTBOUND;
- if (WinDivertHelperEvalFilter(filter, WINDIVERT_LAYER_NETWORK,
- (PVOID)packet, packet_len, &addr) != match)
+ addr.Outbound = TRUE;
+ addr.Layer = WINDIVERT_LAYER_NETWORK;
+ addr.IPv6 = (iphdr == NULL);
+ if (WinDivertHelperEvalFilter(filter, (PVOID)packet, packet_len, &addr)
+ != match)
{
fprintf(stderr, "error: filter \"%s\" does not match the given "
"packet\n", filter);
@@ -481,7 +489,7 @@ read_failed:
}
buf_len = (UINT)iolen;
}
- if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND)
+ if (addr.Outbound)
{
WinDivertHelperCalcChecksums(buf, buf_len, NULL, 0);
}
From 2ab1ddf1d2542be8753308c874c99e0a00e5945e Mon Sep 17 00:00:00 2001
From: basil00
Date: Mon, 22 Oct 2018 08:38:12 +0800
Subject: [PATCH 03/23] Make it possible to filter based on events.
E.g., "event == FLOW_ESTABLISHED".
---
dll/windivert_helper.c | 84 +++++++++++++++++++++++++++-
examples/windivertctl/windivertctl.c | 13 +----
include/windivert_device.h | 9 ++-
sys/windivert.c | 40 ++++++++-----
test/test.c | 1 +
5 files changed, 121 insertions(+), 26 deletions(-)
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index 86b39b6..24d7ac0 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -109,6 +109,7 @@ typedef enum
TOKEN_UDP_PAYLOAD_LENGTH,
TOKEN_UDP_SRC_PORT,
TOKEN_ZERO,
+ TOKEN_EVENT,
TOKEN_TRUE,
TOKEN_FALSE,
TOKEN_INBOUND,
@@ -128,6 +129,12 @@ typedef enum
TOKEN_NETWORK,
TOKEN_NETWORK_FORWARD,
TOKEN_REFLECT,
+ TOKEN_NETWORK_PACKET,
+ TOKEN_FLOW_ESTABLISHED,
+ TOKEN_FLOW_DELETED,
+ TOKEN_REFLECT_ESTABLISHED,
+ TOKEN_REFLECT_OPEN,
+ TOKEN_REFLECT_CLOSE,
TOKEN_OPEN,
TOKEN_CLOSE,
TOKEN_EQ,
@@ -820,6 +827,11 @@ static BOOL WinDivertCheckTokenKindForLayer(WINDIVERT_LAYER layer, KIND kind)
case TOKEN_NETWORK:
case TOKEN_NETWORK_FORWARD:
case TOKEN_REFLECT:
+ case TOKEN_FLOW_ESTABLISHED:
+ case TOKEN_FLOW_DELETED:
+ case TOKEN_REFLECT_ESTABLISHED:
+ case TOKEN_REFLECT_OPEN:
+ case TOKEN_REFLECT_CLOSE:
return FALSE;
default:
return TRUE;
@@ -882,6 +894,10 @@ static BOOL WinDivertCheckTokenKindForLayer(WINDIVERT_LAYER layer, KIND kind)
case TOKEN_NETWORK:
case TOKEN_NETWORK_FORWARD:
case TOKEN_REFLECT:
+ case TOKEN_NETWORK_PACKET:
+ case TOKEN_REFLECT_ESTABLISHED:
+ case TOKEN_REFLECT_OPEN:
+ case TOKEN_REFLECT_CLOSE:
return FALSE;
default:
return TRUE;
@@ -953,6 +969,9 @@ static BOOL WinDivertCheckTokenKindForLayer(WINDIVERT_LAYER layer, KIND kind)
case TOKEN_LOCAL_PORT:
case TOKEN_REMOTE_PORT:
case TOKEN_PROTOCOL:
+ case TOKEN_NETWORK_PACKET:
+ case TOKEN_FLOW_ESTABLISHED:
+ case TOKEN_FLOW_DELETED:
return FALSE;
default:
return TRUE;
@@ -981,6 +1000,24 @@ static BOOL WinDivertExpandMacro(KIND kind, UINT32 *val)
case TOKEN_REFLECT:
*val = WINDIVERT_LAYER_REFLECT;
return TRUE;
+ case TOKEN_NETWORK_PACKET:
+ *val = WINDIVERT_EVENT_NETWORK_PACKET;
+ return TRUE;
+ case TOKEN_FLOW_ESTABLISHED:
+ *val = WINDIVERT_EVENT_FLOW_ESTABLISHED;
+ return TRUE;
+ case TOKEN_FLOW_DELETED:
+ *val = WINDIVERT_EVENT_FLOW_DELETED;
+ return TRUE;
+ case TOKEN_REFLECT_ESTABLISHED:
+ *val = WINDIVERT_EVENT_REFLECT_ESTABLISHED;
+ return TRUE;
+ case TOKEN_REFLECT_OPEN:
+ *val = WINDIVERT_EVENT_REFLECT_OPEN;
+ return TRUE;
+ case TOKEN_REFLECT_CLOSE:
+ *val = WINDIVERT_EVENT_REFLECT_CLOSE;
+ return TRUE;
default:
return FALSE;
}
@@ -995,10 +1032,17 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
static const TOKEN_NAME token_names[] =
{
{"FLOW", TOKEN_FLOW},
+ {"FLOW_DELETED", TOKEN_FLOW_DELETED},
+ {"FLOW_ESTABLISHED", TOKEN_FLOW_ESTABLISHED},
{"NETWORK", TOKEN_NETWORK},
{"NETWORK_FORWARD", TOKEN_NETWORK_FORWARD},
+ {"NETWORK_PACKET", TOKEN_NETWORK_PACKET},
{"REFLECT", TOKEN_REFLECT},
+ {"REFLECT_CLOSE", TOKEN_REFLECT_CLOSE},
+ {"REFLECT_ESTABLISHED", TOKEN_REFLECT_ESTABLISHED},
+ {"REFLECT_OPEN", TOKEN_REFLECT_OPEN},
{"and", TOKEN_AND},
+ {"event", TOKEN_EVENT},
{"false", TOKEN_FALSE},
{"icmp", TOKEN_ICMP},
{"icmp.Body", TOKEN_ICMP_BODY},
@@ -1322,6 +1366,7 @@ static PEXPR WinDivertMakeVar(KIND kind, PERROR error)
{{{0}}, TOKEN_UDP_PAYLOAD_LENGTH},
{{{0}}, TOKEN_UDP_SRC_PORT},
{{{0}}, TOKEN_ZERO},
+ {{{0}}, TOKEN_EVENT},
{{{0}}, TOKEN_TRUE},
{{{0}}, TOKEN_FALSE},
{{{0}}, TOKEN_INBOUND},
@@ -1446,6 +1491,7 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error)
switch (toks[*i].kind)
{
case TOKEN_ZERO:
+ case TOKEN_EVENT:
case TOKEN_TRUE:
case TOKEN_FALSE:
case TOKEN_OUTBOUND:
@@ -1696,6 +1742,9 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
case TOKEN_LAYER:
lb = 0; ub = WINDIVERT_LAYER_MAX;
break;
+ case TOKEN_EVENT:
+ lb = 0; ub = WINDIVERT_EVENT_MAX;
+ break;
case TOKEN_INBOUND:
case TOKEN_OUTBOUND:
case TOKEN_IP:
@@ -1930,6 +1979,9 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
case TOKEN_ZERO:
object->field = WINDIVERT_FILTER_FIELD_ZERO;
break;
+ case TOKEN_EVENT:
+ object->field = WINDIVERT_FILTER_FIELD_EVENT;
+ break;
case TOKEN_OUTBOUND:
object->field = WINDIVERT_FILTER_FIELD_OUTBOUND;
break;
@@ -2728,6 +2780,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
case WINDIVERT_FILTER_FIELD_ZERO:
val[0] = 0;
break;
+ case WINDIVERT_FILTER_FIELD_EVENT:
+ val[0] = addr->Event;
+ break;
case WINDIVERT_FILTER_FIELD_INBOUND:
val[0] = !addr->Outbound;
break;
@@ -3173,6 +3228,8 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test)
{
case WINDIVERT_FILTER_FIELD_ZERO:
kind = TOKEN_ZERO; break;
+ case WINDIVERT_FILTER_FIELD_EVENT:
+ kind = TOKEN_EVENT; break;
case WINDIVERT_FILTER_FIELD_INBOUND:
kind = TOKEN_INBOUND; break;
case WINDIVERT_FILTER_FIELD_OUTBOUND:
@@ -3685,7 +3742,7 @@ static void WinDivertFormatIPv6Addr(PWINDIVERT_STREAM stream,
static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr)
{
PEXPR field = expr->arg[0], val = expr->arg[1];
- BOOL ipv4_addr = FALSE, ipv6_addr = FALSE, layer = FALSE;
+ BOOL ipv4_addr = FALSE, ipv6_addr = FALSE, layer = FALSE, event = FALSE;
switch (field->kind)
{
@@ -3742,6 +3799,9 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr)
case TOKEN_LAYER:
layer = TRUE;
break;
+ case TOKEN_EVENT:
+ event = TRUE;
+ break;
default:
break;
}
@@ -3786,6 +3846,26 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr)
WinDivertFormatNumber(stream, val->val[0]); break;
}
}
+ else if (event)
+ {
+ switch (val->val[0])
+ {
+ case WINDIVERT_EVENT_NETWORK_PACKET:
+ WinDivertPutString(stream, "NETWORK_PACKET"); break;
+ case WINDIVERT_EVENT_FLOW_ESTABLISHED:
+ WinDivertPutString(stream, "FLOW_ESTABLISHED"); break;
+ case WINDIVERT_EVENT_FLOW_DELETED:
+ WinDivertPutString(stream, "FLOW_DELETED"); break;
+ case WINDIVERT_EVENT_REFLECT_ESTABLISHED:
+ WinDivertPutString(stream, "REFLECT_ESTABLISHED"); break;
+ case WINDIVERT_EVENT_REFLECT_OPEN:
+ WinDivertPutString(stream, "REFLECT_OPEN"); break;
+ case WINDIVERT_EVENT_REFLECT_CLOSE:
+ WinDivertPutString(stream, "REFLECT_CLOSE"); break;
+ default:
+ WinDivertFormatNumber(stream, val->val[0]); break;
+ }
+ }
else
{
WinDivertFormatNumber(stream, val->val[0]);
@@ -3863,6 +3943,8 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
return;
case TOKEN_ZERO:
WinDivertPutString(stream, "zero"); return;
+ case TOKEN_EVENT:
+ WinDivertPutString(stream, "event"); return;
case TOKEN_INBOUND:
WinDivertPutString(stream, "inbound"); return;
case TOKEN_OUTBOUND:
diff --git a/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c
index f01111d..7be5d34 100644
--- a/examples/windivertctl/windivertctl.c
+++ b/examples/windivertctl/windivertctl.c
@@ -1,5 +1,5 @@
/*
- * streamdump.c
+ * windivertctl.c
* (C) 2018, all rights reserved,
*
* This file is part of WinDivert.
@@ -73,15 +73,6 @@ typedef enum
KILLALL
} MODE;
-/*
- * Months.
- */
-static const char *months[12] =
-{
- "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
- "Nov", "Dec"
-};
-
/*
* Add a new process.
*/
@@ -387,7 +378,7 @@ usage:
if (WinDivertHelperFormatFilter((char *)object, addr.Reflect.Layer,
filter_str, sizeof(filter_str)))
{
- printf("\"%s\" \"%s\"", filter_str, (char *)object); // XXX
+ printf("\"%s\"", filter_str);
}
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
diff --git a/include/windivert_device.h b/include/windivert_device.h
index 2741402..9ff6c7d 100644
--- a/include/windivert_device.h
+++ b/include/windivert_device.h
@@ -129,8 +129,9 @@
#define WINDIVERT_FILTER_FIELD_REMOTEPORT 64
#define WINDIVERT_FILTER_FIELD_PROTOCOL 65
#define WINDIVERT_FILTER_FIELD_LAYER 66
+#define WINDIVERT_FILTER_FIELD_EVENT 67
#define WINDIVERT_FILTER_FIELD_MAX \
- WINDIVERT_FILTER_FIELD_LAYER
+ WINDIVERT_FILTER_FIELD_EVENT
#define WINDIVERT_FILTER_TEST_EQ 0
#define WINDIVERT_FILTER_TEST_NEQ 1
@@ -151,6 +152,12 @@
#define WINDIVERT_LAYER_DEFAULT WINDIVERT_LAYER_NETWORK
#define WINDIVERT_LAYER_MAX WINDIVERT_LAYER_REFLECT
+/*
+ * WinDivert events.
+ */
+#define WINDIVERT_EVENT_MAX \
+ WINDIVERT_EVENT_REFLECT_CLOSE
+
/*
* WinDivert flags.
*/
diff --git a/sys/windivert.c b/sys/windivert.c
index 08212d9..d174986 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -432,8 +432,8 @@ static void windivert_free_packet(packet_t packet);
static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4, BOOL checksum);
static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b);
static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
- PVOID layer_data, BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor,
- PWINDIVERT_FILTER filter);
+ PVOID layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound,
+ BOOL loopback, BOOL impostor, PWINDIVERT_FILTER filter);
static PWINDIVERT_FILTER windivert_filter_compile(
PWINDIVERT_FILTER ioctl_filter, size_t ioctl_filter_len);
static NTSTATUS windivert_reflect_init(WDFOBJECT parent);
@@ -1834,7 +1834,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
case WINDIVERT_LAYER_FLOW:
case WINDIVERT_LAYER_REFLECT:
status = STATUS_INVALID_PARAMETER;
- DEBUG_ERROR("failed to inject at FLOW layer", status);
+ DEBUG_ERROR("failed to inject at layer", status);
goto windivert_write_exit;
default:
break;
@@ -2796,7 +2796,8 @@ static void windivert_network_classify(context_t context,
do
{
BOOL match = windivert_filter(buffer_fst, layer, (PVOID)network_data,
- ipv4, outbound, loopback, impostor, filter);
+ /*event=*/WINDIVERT_EVENT_NETWORK_PACKET, ipv4, outbound, loopback,
+ impostor, filter);
if (match)
{
break;
@@ -2860,7 +2861,8 @@ static void windivert_network_classify(context_t context,
while (buffer_itr != NULL)
{
BOOL match = windivert_filter(buffer_itr, layer, (PVOID)network_data,
- ipv4, outbound, loopback, impostor, filter);
+ /*event=*/WINDIVERT_EVENT_NETWORK_PACKET, ipv4, outbound,
+ loopback, impostor, filter);
ok = windivert_queue_work(context, (PVOID)buffer_itr,
NET_BUFFER_DATA_LENGTH(buffer_itr), buffers, layer,
(PVOID)network_data, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
@@ -3024,7 +3026,8 @@ static void windivert_flow_established_classify(context_t context,
KeReleaseInStackQueuedSpinLock(&lock_handle);
match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW,
- (PVOID)flow_data, ipv4, outbound, loopback, /*impostor=*/FALSE, filter);
+ (PVOID)flow_data, /*event=*/WINDIVERT_EVENT_FLOW_ESTABLISHED, ipv4,
+ outbound, loopback, /*impostor=*/FALSE, filter);
if (match)
{
ok = windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0,
@@ -3135,8 +3138,9 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
KeReleaseInStackQueuedSpinLock(&lock_handle);
match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW,
- (PVOID)&flow->data, !flow->ipv6, flow->outbound, flow->loopback,
- /*impostor=*/FALSE, filter);
+ (PVOID)&flow->data, /*event=*/WINDIVERT_EVENT_FLOW_DELETED,
+ !flow->ipv6, flow->outbound, flow->loopback, /*impostor=*/FALSE,
+ filter);
if (match)
{
(VOID)windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0,
@@ -3772,8 +3776,8 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
* Checks if the given network packet is of interest.
*/
static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
- PVOID layer_data, BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor,
- PWINDIVERT_FILTER filter)
+ PVOID layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound,
+ BOOL loopback, BOOL impostor, PWINDIVERT_FILTER filter)
{
PWINDIVERT_IPHDR ip_header = NULL;
PWINDIVERT_IPV6HDR ipv6_header = NULL;
@@ -3827,6 +3831,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
switch (filter[ip].field)
{
case WINDIVERT_FILTER_FIELD_ZERO:
+ case WINDIVERT_FILTER_FIELD_EVENT:
result = TRUE;
break;
case WINDIVERT_FILTER_FIELD_INBOUND:
@@ -3948,6 +3953,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
case WINDIVERT_FILTER_FIELD_ZERO:
field[0] = 0;
break;
+ case WINDIVERT_FILTER_FIELD_EVENT:
+ field[0] = (UINT32)event;
+ break;
case WINDIVERT_FILTER_FIELD_INBOUND:
field[0] = (UINT32)!outbound;
break;
@@ -4354,6 +4362,12 @@ static PWINDIVERT_FILTER windivert_filter_compile(
goto windivert_filter_compile_error;
}
break;
+ case WINDIVERT_FILTER_FIELD_EVENT:
+ if (ioctl_filter[i].arg[0] > WINDIVERT_EVENT_MAX)
+ {
+ goto windivert_filter_compile_error;
+ }
+ break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH:
if (ioctl_filter[i].arg[0] > 0x0F)
@@ -4609,7 +4623,7 @@ static void windivert_reflect_event_notify(context_t context,
KeReleaseInStackQueuedSpinLock(&lock_handle);
match = windivert_filter(/*buffer=*/NULL,
/*layer=*/WINDIVERT_LAYER_REFLECT, (PVOID)&context->reflect.data,
- /*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE,
+ event, /*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE,
/*impostor=*/FALSE, filter);
if (!match)
{
@@ -4658,8 +4672,8 @@ static void windivert_reflect_established_notify(context_t context,
entry = entry->Flink;
match = windivert_filter(/*buffer=*/NULL,
/*layer=*/WINDIVERT_LAYER_REFLECT, (PVOID)&waiter->reflect.data,
- /*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE,
- /*impostor=*/FALSE, filter);
+ /*event=*/WINDIVERT_EVENT_REFLECT_ESTABLISHED, /*ipv4=*/TRUE,
+ /*outbound=*/FALSE, /*loopback=*/FALSE, /*impostor=*/FALSE, filter);
if (!match)
{
continue;
diff --git a/test/test.c b/test/test.c
index f2bd160..f6511fc 100644
--- a/test/test.c
+++ b/test/test.c
@@ -113,6 +113,7 @@ static struct packet pkt_ipv6_exthdrs_udp =
};
static struct test tests[] =
{
+ {"event = NETWORK_PACKET", &pkt_echo_request, TRUE},
{"outbound and icmp", &pkt_echo_request, TRUE},
{"outbound", &pkt_echo_request, TRUE},
{"outbound and inbound", &pkt_echo_request, FALSE},
From fd75e6d42af895ebcb28a9676828098af0dd0b83 Mon Sep 17 00:00:00 2001
From: basil00
Date: Thu, 25 Oct 2018 10:20:46 +0800
Subject: [PATCH 04/23] Add a new SOCKET layer to WinDivert (see #156).
Adds a new SOCKET layer for monitoring socket
events, such as BIND, LISTEN, CONNECT,
and ACCEPT. These events occur before the
flow is established (and unlike the FLOW layer)
it is possible to block/drop SOCKET events.
Otherwise, this layer is very similar to the
FLOW layer, so the PID is available and injection
is not possible. This commit should be
considered to be a WIP.
Other changes:
- New socketdump.exe sample. Prints socket
events.
- Improve IPv6 address parsing.
- New helper functions:
* WinDivertHelperFormatIPv4Address
* WinDivertHelperFormatIPv6Address
- Fix REFLECT bugs.
- The network 5-tuple can now be accessed at
the NETWORK layer.
- Various cleanups.
---
dll/windivert.c | 1 +
dll/windivert.def | 2 +
dll/windivert_helper.c | 926 +++++++++++++--------
examples/flowtrack/flowtrack.c | 49 +-
examples/netdump/netdump.c | 15 +-
examples/socketdump/socketdump.c | 210 +++++
examples/windivertctl/windivertctl.c | 3 +
include/windivert.h | 43 +-
mingw-build.sh | 4 +
sys/windivert.c | 1120 ++++++++++++++++++++++++--
test/test.c | 10 +-
11 files changed, 1927 insertions(+), 456 deletions(-)
create mode 100644 examples/socketdump/socketdump.c
diff --git a/dll/windivert.c b/dll/windivert.c
index 62208c2..32a4da4 100644
--- a/dll/windivert.c
+++ b/dll/windivert.c
@@ -413,6 +413,7 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
case WINDIVERT_LAYER_FLOW:
+ case WINDIVERT_LAYER_SOCKET:
case WINDIVERT_LAYER_REFLECT:
break;
default:
diff --git a/dll/windivert.def b/dll/windivert.def
index a36cd4a..c9c072f 100644
--- a/dll/windivert.def
+++ b/dll/windivert.def
@@ -13,6 +13,8 @@ EXPORTS
WinDivertHelperParsePacket
WinDivertHelperParseIPv4Address
WinDivertHelperParseIPv6Address
+ WinDivertHelperFormatIPv4Address
+ WinDivertHelperFormatIPv6Address
WinDivertHelperCompileFilter
WinDivertHelperEvalFilter
WinDivertHelperFormatFilter
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index 24d7ac0..06976a6 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -126,12 +126,17 @@ typedef enum
TOKEN_PROTOCOL,
TOKEN_LAYER,
TOKEN_FLOW,
+ TOKEN_SOCKET,
TOKEN_NETWORK,
TOKEN_NETWORK_FORWARD,
TOKEN_REFLECT,
TOKEN_NETWORK_PACKET,
TOKEN_FLOW_ESTABLISHED,
TOKEN_FLOW_DELETED,
+ TOKEN_SOCKET_BIND,
+ TOKEN_SOCKET_CONNECT,
+ TOKEN_SOCKET_LISTEN,
+ TOKEN_SOCKET_ACCEPT,
TOKEN_REFLECT_ESTABLISHED,
TOKEN_REFLECT_OPEN,
TOKEN_REFLECT_CLOSE,
@@ -158,13 +163,49 @@ typedef struct
UINT pos;
UINT32 val[4];
} TOKEN;
-#define TOKEN_MAXLEN 32
+#define TOKEN_MAXLEN 32
typedef struct
{
char *name;
KIND kind;
-} TOKEN_NAME, *PTOKEN_NAME;
+ UINT8 flags;
+} TOKEN_INFO, *PTOKEN_INFO;
+
+#define WINDIVERT_LAYER_FLAG_NETWORK (1 << WINDIVERT_LAYER_NETWORK)
+#define WINDIVERT_LAYER_FLAG_NETWORK_FORWARD \
+ (1 << WINDIVERT_LAYER_NETWORK_FORWARD)
+#define WINDIVERT_LAYER_FLAG_FLOW (1 << WINDIVERT_LAYER_FLOW)
+#define WINDIVERT_LAYER_FLAG_SOCKET (1 << WINDIVERT_LAYER_SOCKET)
+#define WINDIVERT_LAYER_FLAG_REFLECT (1 << WINDIVERT_LAYER_REFLECT)
+
+/*
+ * Layer flags shorthand.
+ */
+#define LNMFSR (WINDIVERT_LAYER_FLAG_NETWORK | \
+ WINDIVERT_LAYER_FLAG_NETWORK_FORWARD | \
+ WINDIVERT_LAYER_FLAG_FLOW | \
+ WINDIVERT_LAYER_FLAG_SOCKET | \
+ WINDIVERT_LAYER_FLAG_REFLECT)
+#define LNMFS_ (WINDIVERT_LAYER_FLAG_NETWORK | \
+ WINDIVERT_LAYER_FLAG_NETWORK_FORWARD | \
+ WINDIVERT_LAYER_FLAG_FLOW | \
+ WINDIVERT_LAYER_FLAG_SOCKET)
+#define LN_F__ (WINDIVERT_LAYER_FLAG_NETWORK | \
+ WINDIVERT_LAYER_FLAG_FLOW)
+#define LN_FS_ (WINDIVERT_LAYER_FLAG_NETWORK | \
+ WINDIVERT_LAYER_FLAG_FLOW | \
+ WINDIVERT_LAYER_FLAG_SOCKET)
+#define L__FSR (WINDIVERT_LAYER_FLAG_FLOW | \
+ WINDIVERT_LAYER_FLAG_SOCKET | \
+ WINDIVERT_LAYER_FLAG_REFLECT)
+#define LNM___ (WINDIVERT_LAYER_FLAG_NETWORK | \
+ WINDIVERT_LAYER_FLAG_NETWORK_FORWARD)
+#define L__F__ WINDIVERT_LAYER_FLAG_FLOW
+#define L___S_ WINDIVERT_LAYER_FLAG_SOCKET
+#define L____R WINDIVERT_LAYER_FLAG_REFLECT
+
+
/*
* Filter expressions.
@@ -280,11 +321,11 @@ static UINT8 WinDivertSkipExtHeaders(UINT8 proto, UINT8 **header, UINT *len)
/*
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
*/
-extern BOOL WinDivertHelperParsePacket(PVOID pPacket, UINT packetLen,
+static BOOL WinDivertHelperParsePacket_2(PVOID pPacket, UINT packetLen,
PWINDIVERT_IPHDR *ppIpHdr, PWINDIVERT_IPV6HDR *ppIpv6Hdr,
PWINDIVERT_ICMPHDR *ppIcmpHdr, PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr,
- PWINDIVERT_TCPHDR *ppTcpHdr, PWINDIVERT_UDPHDR *ppUdpHdr, PVOID *ppData,
- UINT *pDataLen)
+ PWINDIVERT_TCPHDR *ppTcpHdr, PWINDIVERT_UDPHDR *ppUdpHdr, UINT8 *pProto,
+ PVOID *ppData, UINT *pDataLen)
{
PWINDIVERT_IPHDR ip_header = NULL;
PWINDIVERT_IPV6HDR ipv6_header = NULL;
@@ -293,7 +334,7 @@ extern BOOL WinDivertHelperParsePacket(PVOID pPacket, UINT packetLen,
PWINDIVERT_TCPHDR tcp_header = NULL;
PWINDIVERT_UDPHDR udp_header = NULL;
UINT16 header_len;
- UINT8 trans_proto;
+ UINT8 trans_proto = 0;
PVOID data = NULL;
UINT data_len = 0;
BOOL success;
@@ -431,6 +472,10 @@ WinDivertHelperParsePacketExit:
*ppUdpHdr = udp_header;
success = success && (udp_header != NULL);
}
+ if (pProto != NULL)
+ {
+ *pProto = trans_proto;
+ }
if (ppData != NULL)
{
*ppData = data;
@@ -443,6 +488,20 @@ WinDivertHelperParsePacketExit:
return success;
}
+/*
+ * Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
+ */
+extern BOOL WinDivertHelperParsePacket(PVOID pPacket, UINT packetLen,
+ PWINDIVERT_IPHDR *ppIpHdr, PWINDIVERT_IPV6HDR *ppIpv6Hdr,
+ PWINDIVERT_ICMPHDR *ppIcmpHdr, PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr,
+ PWINDIVERT_TCPHDR *ppTcpHdr, PWINDIVERT_UDPHDR *ppUdpHdr, PVOID *ppData,
+ UINT *pDataLen)
+{
+ return WinDivertHelperParsePacket_2(pPacket, packetLen, ppIpHdr,
+ ppIpv6Hdr, ppIcmpHdr, ppIcmpv6Hdr, ppTcpHdr, ppUdpHdr, NULL,
+ ppData, pDataLen);
+}
+
/*
* Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums.
*/
@@ -461,8 +520,8 @@ extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
UINT payload_len, checksum_len;
UINT count = 0;
- WinDivertHelperParsePacket(pPacket, packetLen, &ip_header, &ipv6_header,
- &icmp_header, &icmpv6_header, &tcp_header, &udp_header, NULL,
+ WinDivertHelperParsePacket_2(pPacket, packetLen, &ip_header, &ipv6_header,
+ &icmp_header, &icmpv6_header, &tcp_header, &udp_header, NULL, NULL,
&payload_len);
if (ip_header != NULL && !(flags & WINDIVERT_HELPER_NO_IP_CHECKSUM))
@@ -675,15 +734,15 @@ extern BOOL WinDivertHelperParseIPv4Address(const char *str, UINT32 *addr_ptr)
*/
extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr)
{
- UINT16 laddr[8];
- UINT16 raddr[8];
- BOOL left = TRUE;
+ UINT16 laddr[8] = {0};
+ UINT16 raddr[8] = {0};
+ UINT32 addr[4];
+ BOOL left = TRUE, ipv4 = FALSE;
+ UINT32 ipv4_addr;
UINT i, j, k, l, part;
char part_str[5];
- memset(laddr, 0, sizeof(laddr));
- memset(raddr, 0, sizeof(raddr));
-
+ j = 0;
if (*str == ':')
{
str++;
@@ -694,9 +753,13 @@ extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr)
}
left = FALSE;
str++;
+ if (*str == '\0')
+ {
+ goto WinDivertHelperParseIPv6AddressSuccess;
+ }
}
- for (i = 0, j = 0, k = 0; k < 8; k++)
+ for (i = 0, k = 0; k < 8; k++)
{
if (*str == ':')
{
@@ -707,6 +770,18 @@ extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr)
}
left = FALSE;
str++;
+ if (*str == '\0')
+ {
+ break;
+ }
+ }
+
+ if (i < 6 && WinDivertHelperParseIPv4Address(str, &ipv4_addr))
+ {
+ // Tail is IPv4 address:
+ ipv4 = TRUE;
+ j += 2;
+ goto WinDivertHelperParseIPv6AddressSuccess;
}
for (l = 0; l < 4 && WinDivertIsXDigit(*str); l++)
{
@@ -735,11 +810,7 @@ extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr)
}
if (*str == '\0')
{
- if (!left)
- {
- break;
- }
- if (k == 7)
+ if (!left || k == 7)
{
break;
}
@@ -748,44 +819,55 @@ extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr)
}
str++;
}
- if (*str != '\0')
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
-
- if (addr_ptr == NULL)
+
+WinDivertHelperParseIPv6AddressSuccess:
+
+ if (!ipv4 && addr_ptr == NULL)
{
return TRUE;
}
-
for (i = 0; i < 4; i++)
{
k = 2 * i + j;
l = k + 1;
k = (k >= 8? k - 8: k);
l = (l >= 8? l - 8: l);
- addr_ptr[3 - i] =
+ addr[3 - i] =
(UINT32)laddr[2 * i + 1] |
(UINT32)laddr[2 * i] << 16 |
(UINT32)raddr[l] |
(UINT32)raddr[k] << 16;
}
+ if (ipv4)
+ {
+ // Validate IPv4 address
+ if (addr[3] != 0 || addr[2] != 0 || addr[0] != 0 ||
+ (addr[1] != 0x0000FFFF && addr[1] != 0))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ addr[0] = ipv4_addr;
+ }
+ if (addr_ptr != NULL)
+ {
+ memcpy(addr_ptr, addr, sizeof(addr));
+ }
return TRUE;
}
/*
* Lookup a token.
*/
-static PTOKEN_NAME WinDivertTokenLookup(PTOKEN_NAME token_names,
- size_t token_names_len, const char *name)
+static PTOKEN_INFO WinDivertTokenLookup(PTOKEN_INFO token_info,
+ size_t token_info_len, const char *name)
{
- int lo = 0, hi = (int)token_names_len-1, mid;
+ int lo = 0, hi = (int)token_info_len-1, mid;
int cmp;
while (hi >= lo)
{
mid = (lo + hi) / 2;
- cmp = WinDivertStrCmp(token_names[mid].name, name);
+ cmp = WinDivertStrCmp(token_info[mid].name, name);
if (cmp < 0)
{
lo = mid+1;
@@ -796,191 +878,12 @@ static PTOKEN_NAME WinDivertTokenLookup(PTOKEN_NAME token_names,
}
else
{
- return &token_names[mid];
+ return &token_info[mid];
}
}
return NULL;
}
-/*
- * Validate token for layer.
- */
-static BOOL WinDivertCheckTokenKindForLayer(WINDIVERT_LAYER layer, KIND kind)
-{
- switch (layer)
- {
- case WINDIVERT_LAYER_NETWORK:
- case WINDIVERT_LAYER_NETWORK_FORWARD:
- switch (kind)
- {
- case TOKEN_INBOUND:
- case TOKEN_OUTBOUND:
- return (layer != WINDIVERT_LAYER_NETWORK_FORWARD);
- case TOKEN_PROCESS_ID:
- case TOKEN_LOCAL_ADDR:
- case TOKEN_REMOTE_ADDR:
- case TOKEN_LOCAL_PORT:
- case TOKEN_REMOTE_PORT:
- case TOKEN_PROTOCOL:
- case TOKEN_LAYER:
- case TOKEN_FLOW:
- case TOKEN_NETWORK:
- case TOKEN_NETWORK_FORWARD:
- case TOKEN_REFLECT:
- case TOKEN_FLOW_ESTABLISHED:
- case TOKEN_FLOW_DELETED:
- case TOKEN_REFLECT_ESTABLISHED:
- case TOKEN_REFLECT_OPEN:
- case TOKEN_REFLECT_CLOSE:
- return FALSE;
- default:
- return TRUE;
- }
- case WINDIVERT_LAYER_FLOW:
- switch (kind)
- {
- case TOKEN_ICMP_BODY:
- case TOKEN_ICMP_CHECKSUM:
- case TOKEN_ICMP_CODE:
- case TOKEN_ICMP_TYPE:
- case TOKEN_ICMPV6_BODY:
- case TOKEN_ICMPV6_CHECKSUM:
- case TOKEN_ICMPV6_CODE:
- case TOKEN_ICMPV6_TYPE:
- case TOKEN_IP_CHECKSUM:
- case TOKEN_IP_DF:
- case TOKEN_IP_DST_ADDR:
- case TOKEN_IP_FRAG_OFF:
- case TOKEN_IP_HDR_LENGTH:
- case TOKEN_IP_ID:
- case TOKEN_IP_LENGTH:
- case TOKEN_IP_MF:
- case TOKEN_IP_PROTOCOL:
- case TOKEN_IP_SRC_ADDR:
- case TOKEN_IP_TOS:
- case TOKEN_IP_TTL:
- case TOKEN_IPV6_DST_ADDR:
- case TOKEN_IPV6_FLOW_LABEL:
- case TOKEN_IPV6_HOP_LIMIT:
- case TOKEN_IPV6_LENGTH:
- case TOKEN_IPV6_NEXT_HDR:
- case TOKEN_IPV6_SRC_ADDR:
- case TOKEN_IPV6_TRAFFIC_CLASS:
- case TOKEN_TCP_ACK:
- case TOKEN_TCP_ACK_NUM:
- case TOKEN_TCP_CHECKSUM:
- case TOKEN_TCP_DST_PORT:
- case TOKEN_TCP_FIN:
- case TOKEN_TCP_HDR_LENGTH:
- case TOKEN_TCP_PAYLOAD_LENGTH:
- case TOKEN_TCP_PSH:
- case TOKEN_TCP_RST:
- case TOKEN_TCP_SEQ_NUM:
- case TOKEN_TCP_SRC_PORT:
- case TOKEN_TCP_SYN:
- case TOKEN_TCP_URG:
- case TOKEN_TCP_URG_PTR:
- case TOKEN_TCP_WINDOW:
- case TOKEN_UDP_CHECKSUM:
- case TOKEN_UDP_DST_PORT:
- case TOKEN_UDP_LENGTH:
- case TOKEN_UDP_PAYLOAD_LENGTH:
- case TOKEN_UDP_SRC_PORT:
- case TOKEN_IF_IDX:
- case TOKEN_SUB_IF_IDX:
- case TOKEN_IMPOSTOR:
- case TOKEN_LAYER:
- case TOKEN_FLOW:
- case TOKEN_NETWORK:
- case TOKEN_NETWORK_FORWARD:
- case TOKEN_REFLECT:
- case TOKEN_NETWORK_PACKET:
- case TOKEN_REFLECT_ESTABLISHED:
- case TOKEN_REFLECT_OPEN:
- case TOKEN_REFLECT_CLOSE:
- return FALSE;
- default:
- return TRUE;
- }
- case WINDIVERT_LAYER_REFLECT:
- switch (kind)
- {
- case TOKEN_ICMP_BODY:
- case TOKEN_ICMP_CHECKSUM:
- case TOKEN_ICMP_CODE:
- case TOKEN_ICMP_TYPE:
- case TOKEN_ICMPV6_BODY:
- case TOKEN_ICMPV6_CHECKSUM:
- case TOKEN_ICMPV6_CODE:
- case TOKEN_ICMPV6_TYPE:
- case TOKEN_IP_CHECKSUM:
- case TOKEN_IP_DF:
- case TOKEN_IP_DST_ADDR:
- case TOKEN_IP_FRAG_OFF:
- case TOKEN_IP_HDR_LENGTH:
- case TOKEN_IP_ID:
- case TOKEN_IP_LENGTH:
- case TOKEN_IP_MF:
- case TOKEN_IP_PROTOCOL:
- case TOKEN_IP_SRC_ADDR:
- case TOKEN_IP_TOS:
- case TOKEN_IP_TTL:
- case TOKEN_IPV6_DST_ADDR:
- case TOKEN_IPV6_FLOW_LABEL:
- case TOKEN_IPV6_HOP_LIMIT:
- case TOKEN_IPV6_LENGTH:
- case TOKEN_IPV6_NEXT_HDR:
- case TOKEN_IPV6_SRC_ADDR:
- case TOKEN_IPV6_TRAFFIC_CLASS:
- case TOKEN_TCP_ACK:
- case TOKEN_TCP_ACK_NUM:
- case TOKEN_TCP_CHECKSUM:
- case TOKEN_TCP_DST_PORT:
- case TOKEN_TCP_FIN:
- case TOKEN_TCP_HDR_LENGTH:
- case TOKEN_TCP_PAYLOAD_LENGTH:
- case TOKEN_TCP_PSH:
- case TOKEN_TCP_RST:
- case TOKEN_TCP_SEQ_NUM:
- case TOKEN_TCP_SRC_PORT:
- case TOKEN_TCP_SYN:
- case TOKEN_TCP_URG:
- case TOKEN_TCP_URG_PTR:
- case TOKEN_TCP_WINDOW:
- case TOKEN_UDP_CHECKSUM:
- case TOKEN_UDP_DST_PORT:
- case TOKEN_UDP_LENGTH:
- case TOKEN_UDP_PAYLOAD_LENGTH:
- case TOKEN_UDP_SRC_PORT:
- case TOKEN_IP:
- case TOKEN_IPV6:
- case TOKEN_ICMP:
- case TOKEN_ICMPV6:
- case TOKEN_TCP:
- case TOKEN_UDP:
- case TOKEN_LOOPBACK:
- case TOKEN_IF_IDX:
- case TOKEN_SUB_IF_IDX:
- case TOKEN_IMPOSTOR:
- case TOKEN_INBOUND:
- case TOKEN_OUTBOUND:
- case TOKEN_LOCAL_ADDR:
- case TOKEN_REMOTE_ADDR:
- case TOKEN_LOCAL_PORT:
- case TOKEN_REMOTE_PORT:
- case TOKEN_PROTOCOL:
- case TOKEN_NETWORK_PACKET:
- case TOKEN_FLOW_ESTABLISHED:
- case TOKEN_FLOW_DELETED:
- return FALSE;
- default:
- return TRUE;
- }
- default:
- return FALSE;
- }
-}
-
/*
* Expand a "macro" value.
*/
@@ -997,6 +900,9 @@ static BOOL WinDivertExpandMacro(KIND kind, UINT32 *val)
case TOKEN_FLOW:
*val = WINDIVERT_LAYER_FLOW;
return TRUE;
+ case TOKEN_SOCKET:
+ *val = WINDIVERT_LAYER_SOCKET;
+ return TRUE;
case TOKEN_REFLECT:
*val = WINDIVERT_LAYER_REFLECT;
return TRUE;
@@ -1009,6 +915,18 @@ static BOOL WinDivertExpandMacro(KIND kind, UINT32 *val)
case TOKEN_FLOW_DELETED:
*val = WINDIVERT_EVENT_FLOW_DELETED;
return TRUE;
+ case TOKEN_SOCKET_BIND:
+ *val = WINDIVERT_EVENT_SOCKET_BIND;
+ return TRUE;
+ case TOKEN_SOCKET_CONNECT:
+ *val = WINDIVERT_EVENT_SOCKET_CONNECT;
+ return TRUE;
+ case TOKEN_SOCKET_LISTEN:
+ *val = WINDIVERT_EVENT_SOCKET_LISTEN;
+ return TRUE;
+ case TOKEN_SOCKET_ACCEPT:
+ *val = WINDIVERT_EVENT_SOCKET_ACCEPT;
+ return TRUE;
case TOKEN_REFLECT_ESTABLISHED:
*val = WINDIVERT_EVENT_REFLECT_ESTABLISHED;
return TRUE;
@@ -1029,93 +947,98 @@ static BOOL WinDivertExpandMacro(KIND kind, UINT32 *val)
static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
TOKEN *tokens, UINT tokensmax)
{
- static const TOKEN_NAME token_names[] =
+ static const TOKEN_INFO token_info[] =
{
- {"FLOW", TOKEN_FLOW},
- {"FLOW_DELETED", TOKEN_FLOW_DELETED},
- {"FLOW_ESTABLISHED", TOKEN_FLOW_ESTABLISHED},
- {"NETWORK", TOKEN_NETWORK},
- {"NETWORK_FORWARD", TOKEN_NETWORK_FORWARD},
- {"NETWORK_PACKET", TOKEN_NETWORK_PACKET},
- {"REFLECT", TOKEN_REFLECT},
- {"REFLECT_CLOSE", TOKEN_REFLECT_CLOSE},
- {"REFLECT_ESTABLISHED", TOKEN_REFLECT_ESTABLISHED},
- {"REFLECT_OPEN", TOKEN_REFLECT_OPEN},
- {"and", TOKEN_AND},
- {"event", TOKEN_EVENT},
- {"false", TOKEN_FALSE},
- {"icmp", TOKEN_ICMP},
- {"icmp.Body", TOKEN_ICMP_BODY},
- {"icmp.Checksum", TOKEN_ICMP_CHECKSUM},
- {"icmp.Code", TOKEN_ICMP_CODE},
- {"icmp.Type", TOKEN_ICMP_TYPE},
- {"icmpv6", TOKEN_ICMPV6},
- {"icmpv6.Body", TOKEN_ICMPV6_BODY},
- {"icmpv6.Checksum", TOKEN_ICMPV6_CHECKSUM},
- {"icmpv6.Code", TOKEN_ICMPV6_CODE},
- {"icmpv6.Type", TOKEN_ICMPV6_TYPE},
- {"ifIdx", TOKEN_IF_IDX},
- {"impostor", TOKEN_IMPOSTOR},
- {"inbound", TOKEN_INBOUND},
- {"ip", TOKEN_IP},
- {"ip.Checksum", TOKEN_IP_CHECKSUM},
- {"ip.DF", TOKEN_IP_DF},
- {"ip.DstAddr", TOKEN_IP_DST_ADDR},
- {"ip.FragOff", TOKEN_IP_FRAG_OFF},
- {"ip.HdrLength", TOKEN_IP_HDR_LENGTH},
- {"ip.Id", TOKEN_IP_ID},
- {"ip.Length", TOKEN_IP_LENGTH},
- {"ip.MF", TOKEN_IP_MF},
- {"ip.Protocol", TOKEN_IP_PROTOCOL},
- {"ip.SrcAddr", TOKEN_IP_SRC_ADDR},
- {"ip.TOS", TOKEN_IP_TOS},
- {"ip.TTL", TOKEN_IP_TTL},
- {"ipv6", TOKEN_IPV6},
- {"ipv6.DstAddr", TOKEN_IPV6_DST_ADDR},
- {"ipv6.FlowLabel", TOKEN_IPV6_FLOW_LABEL},
- {"ipv6.HopLimit", TOKEN_IPV6_HOP_LIMIT},
- {"ipv6.Length", TOKEN_IPV6_LENGTH},
- {"ipv6.NextHdr", TOKEN_IPV6_NEXT_HDR},
- {"ipv6.SrcAddr", TOKEN_IPV6_SRC_ADDR},
- {"ipv6.TrafficClass", TOKEN_IPV6_TRAFFIC_CLASS},
- {"layer", TOKEN_LAYER},
- {"localAddr", TOKEN_LOCAL_ADDR},
- {"localPort", TOKEN_LOCAL_PORT},
- {"loopback", TOKEN_LOOPBACK},
- {"not", TOKEN_NOT},
- {"or", TOKEN_OR},
- {"outbound", TOKEN_OUTBOUND},
- {"processId", TOKEN_PROCESS_ID},
- {"protocol", TOKEN_PROTOCOL},
- {"remoteAddr", TOKEN_REMOTE_ADDR},
- {"remotePort", TOKEN_REMOTE_PORT},
- {"subIfIdx", TOKEN_SUB_IF_IDX},
- {"tcp", TOKEN_TCP},
- {"tcp.Ack", TOKEN_TCP_ACK},
- {"tcp.AckNum", TOKEN_TCP_ACK_NUM},
- {"tcp.Checksum", TOKEN_TCP_CHECKSUM},
- {"tcp.DstPort", TOKEN_TCP_DST_PORT},
- {"tcp.Fin", TOKEN_TCP_FIN},
- {"tcp.HdrLength", TOKEN_TCP_HDR_LENGTH},
- {"tcp.PayloadLength", TOKEN_TCP_PAYLOAD_LENGTH},
- {"tcp.Psh", TOKEN_TCP_PSH},
- {"tcp.Rst", TOKEN_TCP_RST},
- {"tcp.SeqNum", TOKEN_TCP_SEQ_NUM},
- {"tcp.SrcPort", TOKEN_TCP_SRC_PORT},
- {"tcp.Syn", TOKEN_TCP_SYN},
- {"tcp.Urg", TOKEN_TCP_URG},
- {"tcp.UrgPtr", TOKEN_TCP_URG_PTR},
- {"tcp.Window", TOKEN_TCP_WINDOW},
- {"true", TOKEN_TRUE},
- {"udp", TOKEN_UDP},
- {"udp.Checksum", TOKEN_UDP_CHECKSUM},
- {"udp.DstPort", TOKEN_UDP_DST_PORT},
- {"udp.Length", TOKEN_UDP_LENGTH},
- {"udp.PayloadLength", TOKEN_UDP_PAYLOAD_LENGTH},
- {"udp.SrcPort", TOKEN_UDP_SRC_PORT},
- {"zero", TOKEN_ZERO},
+ {"FLOW", TOKEN_FLOW, L____R},
+ {"FLOW_DELETED", TOKEN_FLOW_DELETED, L__F__},
+ {"FLOW_ESTABLISHED", TOKEN_FLOW_ESTABLISHED, L__F__},
+ {"NETWORK", TOKEN_NETWORK, L____R},
+ {"NETWORK_FORWARD", TOKEN_NETWORK_FORWARD, L____R},
+ {"NETWORK_PACKET", TOKEN_NETWORK_PACKET, LNM___},
+ {"REFLECT", TOKEN_REFLECT, L____R},
+ {"REFLECT_CLOSE", TOKEN_REFLECT_CLOSE, L____R},
+ {"REFLECT_ESTABLISHED", TOKEN_REFLECT_ESTABLISHED, L____R},
+ {"REFLECT_OPEN", TOKEN_REFLECT_OPEN, L____R},
+ {"SOCKET", TOKEN_SOCKET, L____R},
+ {"SOCKET_ACCEPT", TOKEN_SOCKET_ACCEPT, L___S_},
+ {"SOCKET_BIND", TOKEN_SOCKET_BIND, L___S_},
+ {"SOCKET_CONNECT", TOKEN_SOCKET_CONNECT, L___S_},
+ {"SOCKET_LISTEN", TOKEN_SOCKET_LISTEN, L___S_},
+ {"and", TOKEN_AND, LNMFSR},
+ {"event", TOKEN_EVENT, LNMFSR},
+ {"false", TOKEN_FALSE, LNMFSR},
+ {"icmp", TOKEN_ICMP, LNMFS_},
+ {"icmp.Body", TOKEN_ICMP_BODY, LNM___},
+ {"icmp.Checksum", TOKEN_ICMP_CHECKSUM, LNM___},
+ {"icmp.Code", TOKEN_ICMP_CODE, LNM___},
+ {"icmp.Type", TOKEN_ICMP_TYPE, LNM___},
+ {"icmpv6", TOKEN_ICMPV6, LNMFS_},
+ {"icmpv6.Body", TOKEN_ICMPV6_BODY, LNM___},
+ {"icmpv6.Checksum", TOKEN_ICMPV6_CHECKSUM, LNM___},
+ {"icmpv6.Code", TOKEN_ICMPV6_CODE, LNM___},
+ {"icmpv6.Type", TOKEN_ICMPV6_TYPE, LNM___},
+ {"ifIdx", TOKEN_IF_IDX, LNM___},
+ {"impostor", TOKEN_IMPOSTOR, LNM___},
+ {"inbound", TOKEN_INBOUND, LN_F__},
+ {"ip", TOKEN_IP, LNMFS_},
+ {"ip.Checksum", TOKEN_IP_CHECKSUM, LNM___},
+ {"ip.DF", TOKEN_IP_DF, LNM___},
+ {"ip.DstAddr", TOKEN_IP_DST_ADDR, LNM___},
+ {"ip.FragOff", TOKEN_IP_FRAG_OFF, LNM___},
+ {"ip.HdrLength", TOKEN_IP_HDR_LENGTH, LNM___},
+ {"ip.Id", TOKEN_IP_ID, LNM___},
+ {"ip.Length", TOKEN_IP_LENGTH, LNM___},
+ {"ip.MF", TOKEN_IP_MF, LNM___},
+ {"ip.Protocol", TOKEN_IP_PROTOCOL, LNM___},
+ {"ip.SrcAddr", TOKEN_IP_SRC_ADDR, LNM___},
+ {"ip.TOS", TOKEN_IP_TOS, LNM___},
+ {"ip.TTL", TOKEN_IP_TTL, LNM___},
+ {"ipv6", TOKEN_IPV6, LNMFS_},
+ {"ipv6.DstAddr", TOKEN_IPV6_DST_ADDR, LNM___},
+ {"ipv6.FlowLabel", TOKEN_IPV6_FLOW_LABEL, LNM___},
+ {"ipv6.HopLimit", TOKEN_IPV6_HOP_LIMIT, LNM___},
+ {"ipv6.Length", TOKEN_IPV6_LENGTH, LNM___},
+ {"ipv6.NextHdr", TOKEN_IPV6_NEXT_HDR, LNM___},
+ {"ipv6.SrcAddr", TOKEN_IPV6_SRC_ADDR, LNM___},
+ {"ipv6.TrafficClass", TOKEN_IPV6_TRAFFIC_CLASS, LNM___},
+ {"layer", TOKEN_LAYER, L____R},
+ {"localAddr", TOKEN_LOCAL_ADDR, LN_FS_},
+ {"localPort", TOKEN_LOCAL_PORT, LN_FS_},
+ {"loopback", TOKEN_LOOPBACK, LN_FS_},
+ {"not", TOKEN_NOT, LNMFSR},
+ {"or", TOKEN_OR, LNMFSR},
+ {"outbound", TOKEN_OUTBOUND, LN_F__},
+ {"processId", TOKEN_PROCESS_ID, L__FSR},
+ {"protocol", TOKEN_PROTOCOL, LN_FS_},
+ {"remoteAddr", TOKEN_REMOTE_ADDR, LN_FS_},
+ {"remotePort", TOKEN_REMOTE_PORT, LN_FS_},
+ {"subIfIdx", TOKEN_SUB_IF_IDX, LNM___},
+ {"tcp", TOKEN_TCP, LNMFS_},
+ {"tcp.Ack", TOKEN_TCP_ACK, LNM___},
+ {"tcp.AckNum", TOKEN_TCP_ACK_NUM, LNM___},
+ {"tcp.Checksum", TOKEN_TCP_CHECKSUM, LNM___},
+ {"tcp.DstPort", TOKEN_TCP_DST_PORT, LNM___},
+ {"tcp.Fin", TOKEN_TCP_FIN, LNM___},
+ {"tcp.HdrLength", TOKEN_TCP_HDR_LENGTH, LNM___},
+ {"tcp.PayloadLength", TOKEN_TCP_PAYLOAD_LENGTH, LNM___},
+ {"tcp.Psh", TOKEN_TCP_PSH, LNM___},
+ {"tcp.Rst", TOKEN_TCP_RST, LNM___},
+ {"tcp.SeqNum", TOKEN_TCP_SEQ_NUM, LNM___},
+ {"tcp.SrcPort", TOKEN_TCP_SRC_PORT, LNM___},
+ {"tcp.Syn", TOKEN_TCP_SYN, LNM___},
+ {"tcp.Urg", TOKEN_TCP_URG, LNM___},
+ {"tcp.UrgPtr", TOKEN_TCP_URG_PTR, LNM___},
+ {"tcp.Window", TOKEN_TCP_WINDOW, LNM___},
+ {"true", TOKEN_TRUE, LNMFSR},
+ {"udp", TOKEN_UDP, LNMFS_},
+ {"udp.Checksum", TOKEN_UDP_CHECKSUM, LNM___},
+ {"udp.DstPort", TOKEN_UDP_DST_PORT, LNM___},
+ {"udp.Length", TOKEN_UDP_LENGTH, LNM___},
+ {"udp.PayloadLength", TOKEN_UDP_PAYLOAD_LENGTH, LNM___},
+ {"udp.SrcPort", TOKEN_UDP_SRC_PORT, LNM___},
+ {"zero", TOKEN_ZERO, LNMFSR},
};
- TOKEN_NAME *result;
+ TOKEN_INFO *result;
char c;
char token[TOKEN_MAXLEN];
UINT i = 0, j;
@@ -1240,11 +1163,11 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
}
// Check for symbol:
- result = WinDivertTokenLookup((PTOKEN_NAME)token_names,
- sizeof(token_names) / sizeof(TOKEN_NAME), token);
+ result = WinDivertTokenLookup((PTOKEN_INFO)token_info,
+ sizeof(token_info) / sizeof(TOKEN_INFO), token);
if (result != NULL)
{
- if (!WinDivertCheckTokenKindForLayer(layer, result->kind))
+ if ((result->flags & (1 << layer)) == 0)
{
return MAKE_ERROR(WINDIVERT_ERROR_BAD_TOKEN_FOR_LAYER, i-j);
}
@@ -2618,6 +2541,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
PWINDIVERT_ICMPV6HDR icmpv6hdr = NULL;
PWINDIVERT_TCPHDR tcphdr = NULL;
PWINDIVERT_UDPHDR udphdr = NULL;
+ UINT8 protocol = 0;
UINT payload_len;
UINT32 val[4];
BOOL pass;
@@ -2639,8 +2563,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- WinDivertHelperParsePacket(packet, packet_len, &iphdr, &ipv6hdr,
- &icmphdr, &icmpv6hdr, &tcphdr, &udphdr, NULL, &payload_len);
+ WinDivertHelperParsePacket_2(packet, packet_len, &iphdr, &ipv6hdr,
+ &icmphdr, &icmpv6hdr, &tcphdr, &udphdr, &protocol, NULL,
+ &payload_len);
if ((addr->IPv6 && ipv6hdr == NULL) ||
(!addr->IPv6 && iphdr == NULL))
{
@@ -2649,6 +2574,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
}
break;
case WINDIVERT_LAYER_FLOW:
+ case WINDIVERT_LAYER_SOCKET:
if (packet != NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
@@ -2689,6 +2615,47 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
pass = TRUE;
switch (object[pc].field)
{
+ case WINDIVERT_FILTER_FIELD_ZERO:
+ case WINDIVERT_FILTER_FIELD_EVENT:
+ pass = TRUE;
+ break;
+ case WINDIVERT_FILTER_FIELD_INBOUND:
+ case WINDIVERT_FILTER_FIELD_OUTBOUND:
+ pass = (addr->Layer != WINDIVERT_LAYER_NETWORK_FORWARD &&
+ addr->Layer != WINDIVERT_LAYER_REFLECT);
+ break;
+ case WINDIVERT_FILTER_FIELD_LOOPBACK:
+ case WINDIVERT_FILTER_FIELD_IMPOSTOR:
+ case WINDIVERT_FILTER_FIELD_IP:
+ case WINDIVERT_FILTER_FIELD_IPV6:
+ case WINDIVERT_FILTER_FIELD_ICMP:
+ case WINDIVERT_FILTER_FIELD_ICMPV6:
+ case WINDIVERT_FILTER_FIELD_TCP:
+ case WINDIVERT_FILTER_FIELD_UDP:
+ pass = (addr->Layer != WINDIVERT_LAYER_REFLECT);
+ break;
+ case WINDIVERT_FILTER_FIELD_IFIDX:
+ case WINDIVERT_FILTER_FIELD_SUBIFIDX:
+ pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
+ addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ break;
+ case WINDIVERT_FILTER_FIELD_LOCALADDR:
+ case WINDIVERT_FILTER_FIELD_REMOTEADDR:
+ case WINDIVERT_FILTER_FIELD_LOCALPORT:
+ case WINDIVERT_FILTER_FIELD_REMOTEPORT:
+ case WINDIVERT_FILTER_FIELD_PROTOCOL:
+ pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
+ addr->Layer == WINDIVERT_LAYER_FLOW ||
+ addr->Layer == WINDIVERT_LAYER_SOCKET);
+ break;
+ case WINDIVERT_FILTER_FIELD_PROCESSID:
+ pass = (addr->Layer == WINDIVERT_LAYER_FLOW ||
+ addr->Layer == WINDIVERT_LAYER_SOCKET ||
+ addr->Layer == WINDIVERT_LAYER_REFLECT);
+ break;
+ case WINDIVERT_FILTER_FIELD_LAYER:
+ pass = (addr->Layer == WINDIVERT_LAYER_REFLECT);
+ break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
case WINDIVERT_FILTER_FIELD_IP_TOS:
case WINDIVERT_FILTER_FIELD_IP_LENGTH:
@@ -2701,7 +2668,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
case WINDIVERT_FILTER_FIELD_IP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
- pass = (iphdr != NULL);
+ pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
+ addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ pass = pass && (iphdr != NULL);
break;
case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS:
case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL:
@@ -2710,19 +2679,25 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT:
case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
- pass = (ipv6hdr != NULL);
+ pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
+ addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ pass = pass && (ipv6hdr != NULL);
break;
case WINDIVERT_FILTER_FIELD_ICMP_TYPE:
case WINDIVERT_FILTER_FIELD_ICMP_CODE:
case WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_ICMP_BODY:
- pass = (icmphdr != NULL);
+ pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
+ addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ pass = pass && (icmphdr != NULL);
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE:
case WINDIVERT_FILTER_FIELD_ICMPV6_CODE:
case WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM:
case WINDIVERT_FILTER_FIELD_ICMPV6_BODY:
- pass = (icmpv6hdr != NULL);
+ pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
+ addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ pass = pass && (icmpv6hdr != NULL);
break;
case WINDIVERT_FILTER_FIELD_TCP_SRCPORT:
case WINDIVERT_FILTER_FIELD_TCP_DSTPORT:
@@ -2739,35 +2714,22 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
- pass = (tcphdr != NULL);
+ pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
+ addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ pass = pass && (tcphdr != NULL);
break;
case WINDIVERT_FILTER_FIELD_UDP_SRCPORT:
case WINDIVERT_FILTER_FIELD_UDP_DSTPORT:
case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
- pass = (udphdr != NULL);
- break;
- case WINDIVERT_FILTER_FIELD_INBOUND:
- case WINDIVERT_FILTER_FIELD_OUTBOUND:
- pass = (addr->Layer != WINDIVERT_LAYER_NETWORK_FORWARD);
- break;
- case WINDIVERT_FILTER_FIELD_IFIDX:
- case WINDIVERT_FILTER_FIELD_SUBIFIDX:
pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
- break;
- case WINDIVERT_FILTER_FIELD_PROCESSID:
- case WINDIVERT_FILTER_FIELD_LOCALADDR:
- case WINDIVERT_FILTER_FIELD_REMOTEADDR:
- case WINDIVERT_FILTER_FIELD_LOCALPORT:
- case WINDIVERT_FILTER_FIELD_REMOTEPORT:
- case WINDIVERT_FILTER_FIELD_PROTOCOL:
- pass = (addr->Layer == WINDIVERT_LAYER_FLOW);
+ pass = pass && (udphdr != NULL);
break;
default:
- pass = TRUE;
- break;
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
}
if (!pass)
{
@@ -2808,20 +2770,80 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
val[0] = addr->IPv6;
break;
case WINDIVERT_FILTER_FIELD_ICMP:
- val[0] = (addr->Layer == WINDIVERT_LAYER_FLOW?
- addr->Flow.Protocol == IPPROTO_ICMP: icmphdr != NULL);
+ switch (addr->Layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ val[0] = (UINT32)(icmphdr != NULL);
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ val[0] = (UINT32)(!addr->IPv6 &&
+ addr->Socket.Protocol == IPPROTO_ICMP);
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ val[0] = (UINT32)(!addr->IPv6 &&
+ addr->Flow.Protocol == IPPROTO_ICMP);
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_ICMPV6:
- val[0] = (addr->Layer == WINDIVERT_LAYER_FLOW?
- addr->Flow.Protocol == IPPROTO_ICMPV6: icmpv6hdr != NULL);
+ switch (addr->Layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ val[0] = (UINT32)(icmpv6hdr != NULL);
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ val[0] = (UINT32)(addr->IPv6 &&
+ addr->Socket.Protocol == IPPROTO_ICMPV6);
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ val[0] = (UINT32)(addr->IPv6 &&
+ addr->Flow.Protocol == IPPROTO_ICMPV6);
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_TCP:
- val[0] = (addr->Layer == WINDIVERT_LAYER_FLOW?
- addr->Flow.Protocol == IPPROTO_TCP: tcphdr != NULL);
+ switch (addr->Layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ val[0] = (UINT32)(tcphdr != NULL);
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ val[0] = (UINT32)(addr->Socket.Protocol == IPPROTO_TCP);
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ val[0] = (UINT32)(addr->Flow.Protocol == IPPROTO_TCP);
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_UDP:
- val[0] = (addr->Layer == WINDIVERT_LAYER_FLOW?
- addr->Flow.Protocol == IPPROTO_UDP: udphdr != NULL);
+ switch (addr->Layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ val[0] = (UINT32)(udphdr != NULL);
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ val[0] = (UINT32)(addr->Socket.Protocol == IPPROTO_UDP);
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ val[0] = (UINT32)(addr->Flow.Protocol == IPPROTO_UDP);
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
val[0] = iphdr->HdrLength;
@@ -2972,29 +2994,183 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
val[0] = payload_len;
break;
- case WINDIVERT_FILTER_FIELD_PROCESSID:
- val[0] = addr->Flow.ProcessId;
- break;
case WINDIVERT_FILTER_FIELD_LOCALADDR:
- val[0] = addr->Flow.LocalAddr[0];
- val[1] = addr->Flow.LocalAddr[1];
- val[2] = addr->Flow.LocalAddr[2];
- val[3] = addr->Flow.LocalAddr[3];
+ switch (addr->Layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ if (!addr->IPv6)
+ {
+ val[1] = 0x0000FFFF;
+ val[0] = ntohl((addr->Outbound? iphdr->SrcAddr:
+ iphdr->DstAddr));
+ }
+ else if (addr->Outbound)
+ {
+ val[3] = ntohl(ipv6hdr->SrcAddr[0]);
+ val[2] = ntohl(ipv6hdr->SrcAddr[1]);
+ val[1] = ntohl(ipv6hdr->SrcAddr[2]);
+ val[0] = ntohl(ipv6hdr->SrcAddr[3]);
+ }
+ else
+ {
+ val[3] = ntohl(ipv6hdr->DstAddr[0]);
+ val[2] = ntohl(ipv6hdr->DstAddr[1]);
+ val[1] = ntohl(ipv6hdr->DstAddr[2]);
+ val[0] = ntohl(ipv6hdr->DstAddr[3]);
+ }
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ val[0] = addr->Flow.LocalAddr[0];
+ val[1] = addr->Flow.LocalAddr[1];
+ val[2] = addr->Flow.LocalAddr[2];
+ val[3] = addr->Flow.LocalAddr[3];
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ val[0] = addr->Socket.LocalAddr[0];
+ val[1] = addr->Socket.LocalAddr[1];
+ val[2] = addr->Socket.LocalAddr[2];
+ val[3] = addr->Socket.LocalAddr[3];
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_REMOTEADDR:
- val[0] = addr->Flow.RemoteAddr[0];
- val[1] = addr->Flow.RemoteAddr[1];
- val[2] = addr->Flow.RemoteAddr[2];
- val[3] = addr->Flow.RemoteAddr[3];
+ switch (addr->Layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ if (!addr->IPv6)
+ {
+ val[1] = 0x0000FFFF;
+ val[0] = ntohl((!addr->Outbound? iphdr->SrcAddr:
+ iphdr->DstAddr));
+ }
+ else if (!addr->Outbound)
+ {
+ val[3] = ntohl(ipv6hdr->SrcAddr[0]);
+ val[2] = ntohl(ipv6hdr->SrcAddr[1]);
+ val[1] = ntohl(ipv6hdr->SrcAddr[2]);
+ val[0] = ntohl(ipv6hdr->SrcAddr[3]);
+ }
+ else
+ {
+ val[3] = ntohl(ipv6hdr->DstAddr[0]);
+ val[2] = ntohl(ipv6hdr->DstAddr[1]);
+ val[1] = ntohl(ipv6hdr->DstAddr[2]);
+ val[0] = ntohl(ipv6hdr->DstAddr[3]);
+ }
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ val[0] = addr->Flow.RemoteAddr[0];
+ val[1] = addr->Flow.RemoteAddr[1];
+ val[2] = addr->Flow.RemoteAddr[2];
+ val[3] = addr->Flow.RemoteAddr[3];
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ val[0] = addr->Socket.RemoteAddr[0];
+ val[1] = addr->Socket.RemoteAddr[1];
+ val[2] = addr->Socket.RemoteAddr[2];
+ val[3] = addr->Socket.RemoteAddr[3];
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_LOCALPORT:
- val[0] = addr->Flow.LocalPort;
+ switch (addr->Layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ if (tcphdr != NULL)
+ {
+ val[0] = ntohs((addr->Outbound? tcphdr->SrcPort:
+ tcphdr->DstPort));
+ }
+ else if (udphdr != NULL)
+ {
+ val[0] = ntohs((addr->Outbound? udphdr->SrcPort:
+ udphdr->DstPort));
+ }
+ else
+ {
+ val[0] = 0;
+ }
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ val[0] = addr->Flow.LocalPort;
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ val[0] = addr->Socket.LocalPort;
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_REMOTEPORT:
- val[0] = addr->Flow.RemotePort;
+ switch (addr->Layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ if (tcphdr != NULL)
+ {
+ val[0] = ntohs((!addr->Outbound? tcphdr->SrcPort:
+ tcphdr->DstPort));
+ }
+ else if (udphdr != NULL)
+ {
+ val[0] = ntohs((!addr->Outbound? udphdr->SrcPort:
+ udphdr->DstPort));
+ }
+ else
+ {
+ val[0] = 0;
+ }
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ val[0] = addr->Flow.RemotePort;
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ val[0] = addr->Socket.RemotePort;
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_PROTOCOL:
- val[0] = addr->Flow.Protocol;
+ switch (addr->Layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ val[0] = protocol;
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ val[0] = addr->Flow.Protocol;
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ val[0] = addr->Socket.Protocol;
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ break;
+ case WINDIVERT_FILTER_FIELD_PROCESSID:
+ switch (addr->Layer)
+ {
+ case WINDIVERT_LAYER_FLOW:
+ val[0] = addr->Flow.ProcessId;
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ val[0] = addr->Socket.ProcessId;
+ break;
+ case WINDIVERT_LAYER_REFLECT:
+ val[0] = addr->Reflect.ProcessId;
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
@@ -3736,6 +3912,48 @@ static void WinDivertFormatIPv6Addr(PWINDIVERT_STREAM stream,
}
}
+/*
+ * Format an IPv4 address.
+ */
+extern BOOL WinDivertHelperFormatIPv4Address(UINT32 addr, char *buffer,
+ UINT bufLen)
+{
+ WINDIVERT_STREAM stream;
+ stream.data = buffer;
+ stream.pos = 0;
+ stream.max = bufLen;
+ stream.overflow = FALSE;
+ WinDivertFormatIPv4Addr(&stream, addr);
+ WinDivertPutNul(&stream);
+ if (stream.overflow)
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Format an IPv6 address.
+ */
+extern BOOL WinDivertHelperFormatIPv6Address(const UINT32 *addr, char *buffer,
+ UINT bufLen)
+{
+ WINDIVERT_STREAM stream;
+ stream.data = buffer;
+ stream.pos = 0;
+ stream.max = bufLen;
+ stream.overflow = FALSE;
+ WinDivertFormatIPv6Addr(&stream, addr);
+ WinDivertPutNul(&stream);
+ if (stream.overflow)
+ {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+ return TRUE;
+}
+
/*
* Format a test expression.
*/
@@ -3840,6 +4058,8 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr)
WinDivertPutString(stream, "NETWORK_FORWARD"); break;
case WINDIVERT_LAYER_FLOW:
WinDivertPutString(stream, "FLOW"); break;
+ case WINDIVERT_LAYER_SOCKET:
+ WinDivertPutString(stream, "SOCKET"); break;
case WINDIVERT_LAYER_REFLECT:
WinDivertPutString(stream, "REFLECT"); break;
default:
@@ -3856,6 +4076,14 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr)
WinDivertPutString(stream, "FLOW_ESTABLISHED"); break;
case WINDIVERT_EVENT_FLOW_DELETED:
WinDivertPutString(stream, "FLOW_DELETED"); break;
+ case WINDIVERT_EVENT_SOCKET_BIND:
+ WinDivertPutString(stream, "SOCKET_BIND"); break;
+ case WINDIVERT_EVENT_SOCKET_CONNECT:
+ WinDivertPutString(stream, "SOCKET_CONNECT"); break;
+ case WINDIVERT_EVENT_SOCKET_LISTEN:
+ WinDivertPutString(stream, "SOCKET_LISTEN"); break;
+ case WINDIVERT_EVENT_SOCKET_ACCEPT:
+ WinDivertPutString(stream, "SOCKET_ACCEPT"); break;
case WINDIVERT_EVENT_REFLECT_ESTABLISHED:
WinDivertPutString(stream, "REFLECT_ESTABLISHED"); break;
case WINDIVERT_EVENT_REFLECT_OPEN:
@@ -4175,7 +4403,7 @@ BOOL WinDivertHelperFormatFilter(const char *filter, WINDIVERT_LAYER layer,
stream.max = buflen;
stream.overflow = FALSE;
WinDivertFormatExpr(&stream, expr, /*top_level=*/TRUE, /*and=*/FALSE);
- WinDivertPutChar(&stream, '\0');
+ WinDivertPutNul(&stream);
// Clean-up:
HeapDestroy(pool);
diff --git a/examples/flowtrack/flowtrack.c b/examples/flowtrack/flowtrack.c
index 83a1774..c0e935e 100644
--- a/examples/flowtrack/flowtrack.c
+++ b/examples/flowtrack/flowtrack.c
@@ -1,5 +1,5 @@
/*
- * streamdump.c
+ * flowtrack.c
* (C) 2018, all rights reserved,
*
* This file is part of WinDivert.
@@ -47,7 +47,8 @@
#include "windivert.h"
-#define MAX_FLOWS 256
+#define MAX_FLOWS 256
+#define INET6_ADDRSTRLEN 45
/*
* Flow tracking.
@@ -61,39 +62,6 @@ typedef struct FLOW
static HANDLE lock;
static PFLOW flows = NULL;
-/*
- * Print an IP address.
- */
-static void print_address(const UINT32 *addr)
-{
- if (addr[3] == 0 && addr[2] == 0 && addr[1] == 0x0000FFFF)
- {
- // IPv4 address:
- UINT32 a, b, c, d;
- a = (addr[0] >> 24) & 0xFF;
- b = (addr[0] >> 16) & 0xFF;
- c = (addr[0] >> 8) & 0xFF;
- d = (addr[0] >> 0) & 0xFF;
- printf("%u.%u.%u.%u", a, b, c, d);
- }
- else
- {
- // IPv6 address:
- int i;
- for (i = 3; i >= 0; i--)
- {
- UINT32 a, b;
- a = (addr[i] >> 16) & 0xFFFF;
- b = (addr[i] >> 0) & 0xFFFF;
- printf("%x:%x", a, b);
- if (i != 0)
- {
- putchar(':');
- }
- }
- }
-}
-
/*
* Draw flows to console in a delayed loop.
*
@@ -105,6 +73,7 @@ static DWORD draw(LPVOID arg)
HANDLE process, console = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO screen;
char path[MAX_PATH+1];
+ char addr_str[INET6_ADDRSTRLEN+1];
char *filename;
const char header[] = "PID PROGRAM PROT FLOW";
DWORD rows, columns, written, fill_len, path_len, i;
@@ -216,11 +185,13 @@ static DWORD draw(LPVOID arg)
}
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
- print_address(addr->Flow.LocalAddr);
- printf(":%u %s ", addr->Flow.LocalPort,
+ WinDivertHelperFormatIPv6Address(addr->Flow.LocalAddr, addr_str,
+ sizeof(addr_str));
+ printf("%s:%u %s ", addr_str, addr->Flow.LocalPort,
(addr->Outbound? "---->": "<----"));
- print_address(addr->Flow.RemoteAddr);
- printf(":%u", addr->Flow.RemotePort);
+ WinDivertHelperFormatIPv6Address(addr->Flow.RemoteAddr, addr_str,
+ sizeof(addr_str));
+ printf("%s:%u", addr_str, addr->Flow.RemotePort);
fflush(stdout);
}
for (; i < rows-1; i++)
diff --git a/examples/netdump/netdump.c b/examples/netdump/netdump.c
index 1785c93..c07f2ef 100644
--- a/examples/netdump/netdump.c
+++ b/examples/netdump/netdump.c
@@ -49,7 +49,8 @@
#include "windivert.h"
-#define MAXBUF 0xFFFF
+#define MAXBUF 0xFFFF
+#define INET6_ADDRSTRLEN 45
/*
* Entry.
@@ -68,6 +69,7 @@ int __cdecl main(int argc, char **argv)
PWINDIVERT_ICMPV6HDR icmpv6_header;
PWINDIVERT_TCPHDR tcp_header;
PWINDIVERT_UDPHDR udp_header;
+ char src_str[INET6_ADDRSTRLEN+1], dst_str[INET6_ADDRSTRLEN+1];
const char *err_str;
LARGE_INTEGER base, freq;
double time_passed;
@@ -166,16 +168,19 @@ int __cdecl main(int argc, char **argv)
FOREGROUND_GREEN | FOREGROUND_RED);
printf("IPv4 [Version=%u HdrLength=%u TOS=%u Length=%u Id=0x%.4X "
"Reserved=%u DF=%u MF=%u FragOff=%u TTL=%u Protocol=%u "
- "Checksum=0x%.4X SrcAddr=%u.%u.%u.%u DstAddr=%u.%u.%u.%u]\n",
+ "Checksum=0x%.4X SrcAddr=%s DstAddr=%s]\n",
ip_header->Version, ip_header->HdrLength,
ntohs(ip_header->TOS), ntohs(ip_header->Length),
ntohs(ip_header->Id), WINDIVERT_IPHDR_GET_RESERVED(ip_header),
WINDIVERT_IPHDR_GET_DF(ip_header),
WINDIVERT_IPHDR_GET_MF(ip_header),
ntohs(WINDIVERT_IPHDR_GET_FRAGOFF(ip_header)), ip_header->TTL,
- ip_header->Protocol, ntohs(ip_header->Checksum),
- src_addr[0], src_addr[1], src_addr[2], src_addr[3],
- dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3]);
+ ip_header->Protocol, ntohs(ip_header->Checksum));
+ WinDivertHelperFormatIPv4Address(ntohl(ip_header->SrcAddr),
+ src_str, sizeof(src_str));
+ WinDivertHelperFormatIPv4Address(ntohl(ip_header->DstAddr),
+ dst_str, sizeof(dst_str));
+
}
if (ipv6_header != NULL)
{
diff --git a/examples/socketdump/socketdump.c b/examples/socketdump/socketdump.c
new file mode 100644
index 0000000..705b73a
--- /dev/null
+++ b/examples/socketdump/socketdump.c
@@ -0,0 +1,210 @@
+/*
+ * socketdump.c
+ * (C) 2018, all rights reserved,
+ *
+ * This file is part of WinDivert.
+ *
+ * WinDivert is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * WinDivert is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * DESCRIPTION:
+ *
+ * usage: socketdump.exe [filter]
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "windivert.h"
+
+#define INET6_ADDRSTRLEN 45
+
+/*
+ * Entry.
+ */
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE handle, process, console;
+ INT16 priority = 1121; // Arbitrary.
+ const char *filter = "true", *err_str;
+ char path[MAX_PATH+1];
+ char local_str[INET6_ADDRSTRLEN+1], remote_str[INET6_ADDRSTRLEN+1];
+ char *filename;
+ DWORD path_len;
+ UINT packet_len;
+ WINDIVERT_ADDRESS addr;
+
+ switch (argc)
+ {
+ case 1:
+ break;
+ case 2:
+ filter = argv[1];
+ break;
+ default:
+ fprintf(stderr, "usage: %s [filter]\n");
+ exit(EXIT_FAILURE);
+ }
+
+ // Open WinDivert SOCKET handle:
+ handle = WinDivertOpen(filter, WINDIVERT_LAYER_SOCKET, priority,
+ WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_RECV_ONLY);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ if (GetLastError() == ERROR_INVALID_PARAMETER &&
+ !WinDivertHelperCompileFilter(filter, WINDIVERT_LAYER_SOCKET,
+ NULL, 0, &err_str, NULL))
+ {
+ fprintf(stderr, "error: invalid filter \"%s\"\n", err_str);
+ exit(EXIT_FAILURE);
+ }
+ fprintf(stderr, "error: failed to open the WinDivert device (%d)\n",
+ GetLastError());
+ return EXIT_FAILURE;
+ }
+
+ // Main loop:
+ console = GetStdHandle(STD_OUTPUT_HANDLE);
+ while (TRUE)
+ {
+ if (!WinDivertRecv(handle, NULL, 0, &addr, &packet_len))
+ {
+ fprintf(stderr, "failed to read packet (%d)\n", GetLastError());
+ continue;
+ }
+
+ SetConsoleTextAttribute(console, FOREGROUND_GREEN);
+ switch (addr.Event)
+ {
+ case WINDIVERT_EVENT_SOCKET_BIND:
+ printf("BIND");
+ break;
+ case WINDIVERT_EVENT_SOCKET_LISTEN:
+ printf("LISTEN");
+ break;
+ case WINDIVERT_EVENT_SOCKET_CONNECT:
+ printf("CONNECT");
+ break;
+ case WINDIVERT_EVENT_SOCKET_ACCEPT:
+ printf("ACCEPT");
+ break;
+ default:
+ printf("???");
+ break;
+ }
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN |
+ FOREGROUND_BLUE);
+
+ printf(" pid=");
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
+ printf("%u", addr.Socket.ProcessId);
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN |
+ FOREGROUND_BLUE);
+
+ printf(" program=");
+ process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
+ addr.Socket.ProcessId);
+ path_len = 0;
+ if (process != NULL)
+ {
+ path_len = GetProcessImageFileName(process, path, sizeof(path));
+ CloseHandle(process);
+ }
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
+ if (path_len != 0)
+ {
+ filename = PathFindFileName(path);
+ printf("%s", filename);
+ }
+ else if (addr.Socket.ProcessId == 4)
+ {
+ printf("Windows");
+ }
+ else
+ {
+ printf("???");
+ }
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN |
+ FOREGROUND_BLUE);
+
+ printf(" protocol=");
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
+ switch (addr.Socket.Protocol)
+ {
+ case IPPROTO_TCP:
+ printf("TCP");
+ break;
+ case IPPROTO_UDP:
+ printf("UDP");
+ break;
+ case IPPROTO_ICMP:
+ printf("ICMP");
+ break;
+ case IPPROTO_ICMPV6:
+ printf("ICMPV6");
+ break;
+ default:
+ printf("%u", addr.Socket.Protocol);
+ break;
+ }
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN |
+ FOREGROUND_BLUE);
+
+ WinDivertHelperFormatIPv6Address(addr.Socket.LocalAddr, local_str,
+ sizeof(local_str));
+ if (addr.Socket.LocalPort != 0 || strcmp(local_str, "::") != 0)
+ {
+ printf(" local=");
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
+ printf("[%s]:%u", local_str, addr.Socket.LocalPort);
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN |
+ FOREGROUND_BLUE);
+ }
+
+ WinDivertHelperFormatIPv6Address(addr.Socket.RemoteAddr, remote_str,
+ sizeof(remote_str));
+ if (addr.Socket.RemotePort != 0 || strcmp(remote_str, "::") != 0)
+ {
+ printf(" remote=");
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
+ printf("[%s]:%u", remote_str, addr.Socket.RemotePort);
+ SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN |
+ FOREGROUND_BLUE);
+ }
+
+ putchar('\n');
+ }
+
+ return 0;
+}
+
diff --git a/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c
index 7be5d34..5e503dd 100644
--- a/examples/windivertctl/windivertctl.c
+++ b/examples/windivertctl/windivertctl.c
@@ -315,6 +315,9 @@ usage:
case WINDIVERT_LAYER_FLOW:
fputs("FLOW", stdout);
break;
+ case WINDIVERT_LAYER_SOCKET:
+ fputs("SOCKET", stdout);
+ break;
case WINDIVERT_LAYER_REFLECT:
fputs("REFLECT", stdout);
break;
diff --git a/include/windivert.h b/include/windivert.h
index 68c2131..aa35f40 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -77,7 +77,8 @@ typedef enum
WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */
WINDIVERT_LAYER_NETWORK_FORWARD = 1,/* Network layer (forwarded packets) */
WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */
- WINDIVERT_LAYER_REFLECT = 3, /* Reflect layer. */
+ WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */
+ WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */
} WINDIVERT_LAYER, *PWINDIVERT_LAYER;
/*
@@ -102,6 +103,19 @@ typedef struct
UINT8 Protocol; /* Protocol. */
} WINDIVERT_FLOW_DATA, *PWINDIVERT_FLOW_DATA;
+/*
+ * WinDivert SOCKET layer data.
+ */
+typedef struct
+{
+ UINT32 ProcessId; /* Process ID. */
+ UINT32 LocalAddr[4]; /* Local address. */
+ UINT32 RemoteAddr[4]; /* Remote address. */
+ UINT16 LocalPort; /* Local port. */
+ UINT16 RemotePort; /* Remote port. */
+ UINT8 Protocol; /* Protocol. */
+} WINDIVERT_SOCKET_DATA, *PWINDIVERT_SOCKET_DATA;
+
/*
* WinDivert REFLECTION layer data.
*/
@@ -135,6 +149,7 @@ typedef struct
{
WINDIVERT_NETWORK_DATA Network; /* Network layer data. */
WINDIVERT_FLOW_DATA Flow; /* Flow layer data. */
+ WINDIVERT_SOCKET_DATA Socket; /* Socket layer data. */
WINDIVERT_REFLECT_DATA Reflect; /* Reflect layer data. */
};
} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
@@ -148,10 +163,14 @@ typedef enum
WINDIVERT_EVENT_FLOW_ESTABLISHED = 1,
/* Flow established. */
WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */
- WINDIVERT_EVENT_REFLECT_ESTABLISHED = 3,
+ WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */
+ WINDIVERT_EVENT_SOCKET_CONNECT = 4, /* Socket connect. */
+ WINDIVERT_EVENT_SOCKET_LISTEN = 5, /* Socket listen. */
+ WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */
+ WINDIVERT_EVENT_REFLECT_ESTABLISHED = 7,
/* Previously open WinDivert handle. */
- WINDIVERT_EVENT_REFLECT_OPEN = 4, /* Open new WinDivert handle. */
- WINDIVERT_EVENT_REFLECT_CLOSE = 5, /* Close existing WinDivert handle. */
+ WINDIVERT_EVENT_REFLECT_OPEN = 8, /* Open new WinDivert handle. */
+ WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* Close existing WinDivert handle. */
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
/*
@@ -434,6 +453,22 @@ extern WINDIVERTEXPORT BOOL WinDivertHelperParseIPv6Address(
__in const char *addrStr,
__out_opt UINT32 *pAddr);
+/*
+ * Format an IPv4 address.
+ */
+extern WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv4Address(
+ __in UINT32 addr,
+ __out char *buffer,
+ __in UINT bufLen);
+
+/*
+ * Format an IPv6 address.
+ */
+extern WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv6Address(
+ __in const UINT32 *pAddr,
+ __out char *buffer,
+ __in UINT bufLen);
+
/*
* Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums.
*/
diff --git a/mingw-build.sh b/mingw-build.sh
index 29a550e..e0acd54 100644
--- a/mingw-build.sh
+++ b/mingw-build.sh
@@ -105,6 +105,10 @@ do
$CC -s -O2 -Iinclude/ examples/windivertctl/windivertctl.c \
-o "install/MINGW/$CPU/windivertctl.exe" -lWinDivert -lws2_32 \
-lpsapi -lshlwapi -L"install/MINGW/$CPU/"
+ echo "\tcopy install/MINGW/$CPU/socketdump.exe..."
+ $CC -s -O2 -Iinclude/ examples/socketdump/socketdump.c \
+ -o "install/MINGW/$CPU/socketdump.exe" -lWinDivert -lws2_32 \
+ -lpsapi -lshlwapi -L"install/MINGW/$CPU/"
echo "\tcopy install/MINGW/$CPU/WinDivert$BITS.sys..."
cp install/WDDK/$CPU/WinDivert$BITS.sys install/MINGW/$CPU
else
diff --git a/sys/windivert.c b/sys/windivert.c
index d174986..e6cb0f9 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -107,13 +107,14 @@ struct reflect_context_s
LONGLONG timestamp; // Open timestamp.
WINDIVERT_REFLECT_DATA data; // Reflect data.
BOOL inserted; // Entry inserted?
+ BOOL open; // Seen OPEN event?
};
/*
* WinDivert context information.
*/
#define WINDIVERT_CONTEXT_SIZE (sizeof(struct context_s))
-#define WINDIVERT_CONTEXT_MAXLAYERS 4
+#define WINDIVERT_CONTEXT_MAXLAYERS 8
#define WINDIVERT_CONTEXT_MAXWORKERS 1
typedef enum
{
@@ -412,11 +413,54 @@ static void windivert_flow_established_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_assignment_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_assignment_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,
+ const FWPS_FILTER0 *filter, IN UINT64 flow_context,
+ OUT FWPS_CLASSIFY_OUT0 *result);
+static void windivert_auth_connect_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,
+ const FWPS_FILTER0 *filter, IN UINT64 flow_context,
+ OUT FWPS_CLASSIFY_OUT0 *result);
+static void windivert_auth_listen_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_recv_accept_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_auth_recv_accept_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_flow_established_classify(context_t context,
IN UINT64 flow_id, IN PWINDIVERT_FLOW_DATA flow_data, IN BOOL ipv4,
IN BOOL outbound, IN BOOL loopback, OUT FWPS_CLASSIFY_OUT0 *result);
static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
UINT64 flow_context);
+static void windivert_socket_classify(context_t context,
+ PWINDIVERT_SOCKET_DATA socket_data, WINDIVERT_EVENT event, BOOL ipv4,
+ BOOL outbound, BOOL loopback, FWPS_CLASSIFY_OUT0 *result);
static void windivert_network_classify(context_t context,
IN PWINDIVERT_NETWORK_DATA network_data, IN BOOL ipv4, IN BOOL outbound,
IN BOOL loopback, IN UINT advance, IN OUT void *data,
@@ -431,6 +475,12 @@ static void windivert_reinject_packet(packet_t packet);
static void windivert_free_packet(packet_t packet);
static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4, BOOL checksum);
static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b);
+static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
+ PWINDIVERT_IPHDR *ip_header_ptr, PWINDIVERT_IPV6HDR *ipv6_header_ptr,
+ PWINDIVERT_ICMPHDR *icmp_header_ptr,
+ PWINDIVERT_ICMPV6HDR *icmpv6_header_ptr,
+ PWINDIVERT_TCPHDR *tcp_header_ptr, PWINDIVERT_UDPHDR *udp_header_ptr,
+ UINT8 *proto_ptr, UINT *payload_len_ptr);
static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
PVOID layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound,
BOOL loopback, BOOL impostor, PWINDIVERT_FILTER filter);
@@ -449,29 +499,53 @@ static void windivert_reflect_worker(IN WDFWORKITEM item);
* WinDivert sublayer GUIDs
*/
DEFINE_GUID(WINDIVERT_SUBLAYER_INBOUND_IPV4_GUID,
- 0x09C273C5, 0x0FB1, 0x4453,
- 0x95, 0xDF, 0x7E, 0x1C, 0x28, 0x78, 0xED, 0xDF);
+ 0x82A99281, 0x0389, 0x4DE2,
+ 0xAE, 0x2D, 0xA4, 0x51, 0x59, 0x16, 0x26, 0x06);
DEFINE_GUID(WINDIVERT_SUBLAYER_OUTBOUND_IPV4_GUID,
- 0x11C342F5, 0x4276, 0x494F,
- 0xBB, 0x30, 0x84, 0x55, 0x78, 0x6C, 0x67, 0x30);
+ 0xB0BB07C6, 0x3B3B, 0x41FE,
+ 0x83, 0x8B, 0xD8, 0x37, 0xDD, 0xB8, 0x75, 0x41);
DEFINE_GUID(WINDIVERT_SUBLAYER_INBOUND_IPV6_GUID,
- 0x2E5F6801, 0xE721, 0x4A0D,
- 0x8D, 0x48, 0xC8, 0x1D, 0x4F, 0x25, 0x45, 0x93);
+ 0xD7674846, 0x3AB5, 0x4E93,
+ 0x82, 0xD0, 0x2F, 0xCC, 0x03, 0xA2, 0x88, 0x7A);
DEFINE_GUID(WINDIVERT_SUBLAYER_OUTBOUND_IPV6_GUID,
- 0xB6511564, 0xD5E6, 0x44C8,
- 0x9C, 0x73, 0xBB, 0x22, 0x15, 0x39, 0xEB, 0x8A);
+ 0x6672F761, 0xA0F2, 0x4578,
+ 0x92, 0x50, 0x09, 0x03, 0x0D, 0x4E, 0x8C, 0x46);
DEFINE_GUID(WINDIVERT_SUBLAYER_FORWARD_IPV4_GUID,
- 0xEC5C40E3, 0xE508, 0x408B,
- 0xB9, 0x86, 0x58, 0xDE, 0xC7, 0x5F, 0x86, 0xE4);
+ 0x4622DCC6, 0xBD71, 0x48ED,
+ 0x9D, 0x1A, 0x72, 0xC9, 0x0D, 0xEB, 0xA1, 0x74);
DEFINE_GUID(WINDIVERT_SUBLAYER_FORWARD_IPV6_GUID,
- 0xE70D0973, 0x935F, 0x4790,
- 0x8E, 0x64, 0xF7, 0xF7, 0x36, 0x27, 0xA5, 0x8F);
+ 0x7E5B39EC, 0xB54C, 0x41B3,
+ 0xA7, 0x99, 0x47, 0x5E, 0x57, 0x41, 0xA4, 0x33);
DEFINE_GUID(WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV4_GUID,
- 0x168A6CF7, 0x6080, 0x4905,
- 0xAA, 0x72, 0x03, 0x74, 0x67, 0xCD, 0x4F, 0x19);
+ 0x53D6C270, 0xEB79, 0x44CD,
+ 0x83, 0xCD, 0x14, 0x34, 0xE6, 0x13, 0x91, 0x68);
DEFINE_GUID(WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV6_GUID,
- 0x9EAAEB28, 0xC1BB, 0x41F5,
- 0x9F, 0x27, 0x18, 0xD4, 0xDF, 0xE1, 0x31, 0xEE);
+ 0x44B0CDED, 0xAA11, 0x4704,
+ 0x92, 0xA7, 0x99, 0xD2, 0xB7, 0x59, 0x7A, 0x68);
+DEFINE_GUID(WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV4_GUID,
+ 0x736848B6, 0xBE0D, 0x4A8D,
+ 0xA0, 0xC2, 0xE2, 0x02, 0xDC, 0x29, 0x32, 0xBC);
+DEFINE_GUID(WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV6_GUID,
+ 0xF3458E58, 0xD123, 0x439B,
+ 0xB6, 0x40, 0x74, 0x3C, 0xC7, 0x53, 0x9E, 0x36);
+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_AUTH_LISTEN_IPV4_GUID,
+ 0x49F2A9AD, 0x805E, 0x4328,
+ 0xBB, 0xDA, 0x92, 0x57, 0xB5, 0x18, 0x3A, 0x40);
+DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV6_GUID,
+ 0xC1BB250E, 0xDE07, 0x41AB,
+ 0x82, 0xEE, 0xAD, 0x7B, 0xFF, 0x13, 0xCE, 0x35);
+DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV4_GUID,
+ 0x7A012579, 0xC75A, 0x4D29,
+ 0xB7, 0x47, 0x04, 0xAD, 0x3C, 0x7B, 0x32, 0x69);
+DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV6_GUID,
+ 0x1C51DD53, 0x6BA4, 0x4149,
+ 0x89, 0x97, 0x1C, 0xD4, 0x8B, 0x51, 0x1B, 0x7D);
/*
* WinDivert supported layers.
@@ -572,6 +646,136 @@ static struct layer_s layer_forward_network_ipv6_0 =
};
static layer_t layer_forward_network_ipv6 = &layer_forward_network_ipv6_0;
+static struct layer_s layer_resource_assignment_ipv4_0 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerResourceAssignmentIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutResourceAssignmentIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterResourceAssignmentIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)",
+ {0},
+ {0},
+ windivert_resource_assignment_v4_classify,
+ NULL,
+ 0
+};
+static layer_t layer_resource_assignment_ipv4 =
+ &layer_resource_assignment_ipv4_0;
+
+static struct layer_s layer_resource_assignment_ipv6_0 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerResourceAssignmentIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutResourceAssignmentIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterResourceAssignmentIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)",
+ {0},
+ {0},
+ windivert_resource_assignment_v6_classify,
+ NULL,
+ 0
+};
+static layer_t layer_resource_assignment_ipv6 =
+ &layer_resource_assignment_ipv6_0;
+
+static struct layer_s layer_auth_connect_ipv4_0 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthConnectIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthConnectIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterAuthConnectIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)",
+ {0},
+ {0},
+ windivert_auth_connect_v4_classify,
+ NULL,
+ 0
+};
+static layer_t layer_auth_connect_ipv4 = &layer_auth_connect_ipv4_0;
+
+static struct layer_s layer_auth_connect_ipv6_0 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthConnectIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthConnectIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterAuthConnectIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)",
+ {0},
+ {0},
+ windivert_auth_connect_v6_classify,
+ NULL,
+ 0
+};
+static layer_t layer_auth_connect_ipv6 = &layer_auth_connect_ipv6_0;
+
+static struct layer_s layer_auth_listen_ipv4_0 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthListenIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthListenIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterAuthListenIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)",
+ {0},
+ {0},
+ windivert_auth_listen_v4_classify,
+ NULL,
+ 0
+};
+static layer_t layer_auth_listen_ipv4 = &layer_auth_listen_ipv4_0;
+
+static struct layer_s layer_auth_listen_ipv6_0 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthListenIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthListenIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterAuthListenIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)",
+ {0},
+ {0},
+ windivert_auth_listen_v6_classify,
+ NULL,
+ 0
+};
+static layer_t layer_auth_listen_ipv6 = &layer_auth_listen_ipv6_0;
+
+static struct layer_s layer_auth_recv_accept_ipv4_0 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthRecvAcceptIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthRecvAcceptIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterAuthRecvAcceptIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)",
+ {0},
+ {0},
+ windivert_auth_recv_accept_v4_classify,
+ NULL,
+ 0
+};
+static layer_t layer_auth_recv_accept_ipv4 = &layer_auth_recv_accept_ipv4_0;
+
+static struct layer_s layer_auth_recv_accept_ipv6_0 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthRecvAcceptIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthRecvAcceptIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterAuthRecvAcceptIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)",
+ {0},
+ {0},
+ windivert_auth_recv_accept_v6_classify,
+ NULL,
+ 0
+};
+static layer_t layer_auth_recv_accept_ipv6 = &layer_auth_recv_accept_ipv6_0;
+
static struct layer_s layer_flow_established_ipv4_0 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerFlowEstablishedIPv4",
@@ -677,6 +881,18 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj,
FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
layer_flow_established_ipv6->layer_guid =
FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6;
+ layer_resource_assignment_ipv4->layer_guid =
+ FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4;
+ layer_resource_assignment_ipv6->layer_guid =
+ FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6;
+ layer_auth_connect_ipv4->layer_guid = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
+ layer_auth_connect_ipv6->layer_guid = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
+ layer_auth_listen_ipv4->layer_guid = FWPM_LAYER_ALE_AUTH_LISTEN_V4;
+ layer_auth_listen_ipv6->layer_guid = FWPM_LAYER_ALE_AUTH_LISTEN_V6;
+ layer_auth_recv_accept_ipv4->layer_guid =
+ FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
+ layer_auth_recv_accept_ipv6->layer_guid =
+ FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6;
layer_inbound_network_ipv4->sublayer_guid =
WINDIVERT_SUBLAYER_INBOUND_IPV4_GUID;
layer_outbound_network_ipv4->sublayer_guid =
@@ -693,6 +909,22 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj,
WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV4_GUID;
layer_flow_established_ipv6->sublayer_guid =
WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV6_GUID;
+ layer_resource_assignment_ipv4->sublayer_guid =
+ WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV4_GUID;
+ layer_resource_assignment_ipv6->sublayer_guid =
+ WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV6_GUID;
+ layer_auth_connect_ipv4->sublayer_guid =
+ WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV4_GUID;
+ layer_auth_connect_ipv6->sublayer_guid =
+ WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV6_GUID;
+ layer_auth_listen_ipv4->sublayer_guid =
+ WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV4_GUID;
+ layer_auth_listen_ipv6->sublayer_guid =
+ WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV6_GUID;
+ layer_auth_recv_accept_ipv4->sublayer_guid =
+ WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV4_GUID;
+ layer_auth_recv_accept_ipv6->sublayer_guid =
+ WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV6_GUID;
// Configure ourself as a non-PnP driver:
WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
@@ -873,6 +1105,46 @@ driver_entry_sublayer_error:
{
goto driver_entry_sublayer_error;
}
+ status = windivert_install_sublayer(layer_resource_assignment_ipv4);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(layer_resource_assignment_ipv6);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(layer_auth_connect_ipv4);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(layer_auth_connect_ipv6);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(layer_auth_listen_ipv4);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(layer_auth_listen_ipv6);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(layer_auth_recv_accept_ipv4);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(layer_auth_recv_accept_ipv6);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
status = FwpmTransactionCommit0(engine_handle);
if (!NT_SUCCESS(status))
{
@@ -954,6 +1226,22 @@ static void windivert_driver_unload(void)
&layer_flow_established_ipv4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
&layer_flow_established_ipv6->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ &layer_resource_assignment_ipv4->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ &layer_resource_assignment_ipv6->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ &layer_auth_connect_ipv4->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ &layer_auth_connect_ipv6->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ &layer_auth_listen_ipv4->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ &layer_auth_listen_ipv6->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ &layer_auth_recv_accept_ipv4->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ &layer_auth_recv_accept_ipv6->sublayer_guid);
status = FwpmTransactionCommit0(engine_handle);
if (!NT_SUCCESS(status))
{
@@ -1170,6 +1458,23 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
}
break;
+ case WINDIVERT_LAYER_SOCKET:
+ if (ipv4)
+ {
+ layers[i++] = layer_resource_assignment_ipv4;
+ layers[i++] = layer_auth_connect_ipv4;
+ layers[i++] = layer_auth_listen_ipv4;
+ layers[i++] = layer_auth_recv_accept_ipv4;
+ }
+ if (ipv6)
+ {
+ layers[i++] = layer_resource_assignment_ipv6;
+ layers[i++] = layer_auth_connect_ipv6;
+ layers[i++] = layer_auth_listen_ipv6;
+ layers[i++] = layer_auth_recv_accept_ipv6;
+ }
+ break;
+
case WINDIVERT_LAYER_REFLECT:
break;
@@ -1436,6 +1741,9 @@ extern VOID windivert_cleanup(IN WDFFILEOBJECT object)
DEBUG("CLEANUP: cleaning up WinDivert context (context=%p)", context);
+ windivert_reflect_event(context, WINDIVERT_EVENT_REFLECT_CLOSE);
+ timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
+
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPENING &&
context->state != WINDIVERT_CONTEXT_STATE_OPEN)
@@ -1450,10 +1758,6 @@ windivert_cleanup_error:
sniff_mode = ((context->flags & WINDIVERT_FLAG_SNIFF) != 0);
forward = (context->layer == WINDIVERT_LAYER_NETWORK_FORWARD);
priority = context->priority;
- KeReleaseInStackQueuedSpinLock(&lock_handle);
- windivert_reflect_event(context, WINDIVERT_EVENT_REFLECT_CLOSE);
- timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
- KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
while (!IsListEmpty(&context->flow_set))
{
entry = RemoveHeadList(&context->flow_set);
@@ -1671,6 +1975,7 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
break;
case WINDIVERT_LAYER_FLOW:
+ case WINDIVERT_LAYER_SOCKET:
status = STATUS_SUCCESS;
dst_len = 0;
@@ -1712,6 +2017,11 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
sizeof(WINDIVERT_FLOW_DATA));
break;
+ case WINDIVERT_LAYER_SOCKET:
+ RtlCopyMemory(&addr->Socket, layer_data,
+ sizeof(WINDIVERT_SOCKET_DATA));
+ break;
+
case WINDIVERT_LAYER_REFLECT:
RtlCopyMemory(&addr->Reflect, layer_data,
sizeof(WINDIVERT_REFLECT_DATA));
@@ -1832,6 +2142,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
switch (layer)
{
case WINDIVERT_LAYER_FLOW:
+ case WINDIVERT_LAYER_SOCKET:
case WINDIVERT_LAYER_REFLECT:
status = STATUS_INVALID_PARAMETER;
DEBUG_ERROR("failed to inject at layer", status);
@@ -2289,6 +2600,13 @@ windivert_ioctl_bad_start_state:
}
break;
+ case WINDIVERT_LAYER_SOCKET:
+ if ((flags & WINDIVERT_FLAG_RECV_ONLY) == 0)
+ {
+ goto windivert_ioctl_bad_start_state;
+ }
+ break;
+
default:
break;
}
@@ -2317,6 +2635,7 @@ windivert_ioctl_bad_start_state:
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
case WINDIVERT_LAYER_FLOW:
+ case WINDIVERT_LAYER_SOCKET:
case WINDIVERT_LAYER_REFLECT:
break;
default:
@@ -2953,6 +3272,7 @@ static void windivert_flow_established_v6_classify(
FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_ADDRESS]
.value.byteArray16->byteArray16[i];
}
+ addr = (UINT8 *)&flow_data.RemoteAddr;
for (i = sizeof(flow_data.RemoteAddr)-1; i >= 0; i--)
{
addr[sizeof(flow_data.RemoteAddr)-i-1] = fixed_vals->incomingValue[
@@ -3159,6 +3479,415 @@ windivert_flow_delete_notify_exit:
}
}
+/*
+ * WinDivert classify resource assignment IPv4 function.
+ */
+static void windivert_resource_assignment_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_SOCKET_DATA socket_data;
+ FWP_VALUE0 value;
+ BOOL loopback;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ value = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_ADDRESS].value;
+ if (value.type == FWP_UINT32)
+ {
+ socket_data.LocalAddr[0] = value.uint32;
+ socket_data.LocalAddr[1] = 0x0000FFFF;
+ }
+ else
+ {
+ socket_data.LocalAddr[0] = 0;
+ socket_data.LocalAddr[1] = 0;
+ }
+ socket_data.LocalAddr[2] = 0;
+ socket_data.LocalAddr[3] = 0;
+ socket_data.RemoteAddr[0] = 0;
+ socket_data.RemoteAddr[1] = 0;
+ socket_data.RemoteAddr[2] = 0;
+ socket_data.RemoteAddr[3] = 0;
+ value = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_PORT].value;
+ socket_data.LocalPort = (value.type == FWP_UINT16? value.uint16: 0);
+ socket_data.RemotePort = 0;
+ socket_data.Protocol = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_PROTOCOL].value.uint8;
+
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+
+ windivert_socket_classify((context_t)filter->context,
+ &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_BIND, /*ipv4=*/TRUE,
+ /*outbound=*/FALSE, loopback, result);
+}
+
+/*
+ * WinDivert classify resource assignment IPv6 function.
+ */
+static void windivert_resource_assignment_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_SOCKET_DATA socket_data;
+ FWP_VALUE0 value;
+ BOOL loopback;
+ UINT8 *addr;
+ INT i;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ addr = (UINT8 *)&socket_data.LocalAddr;
+ value = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_LOCAL_ADDRESS].value;
+ if (value.type == FWP_BYTE_ARRAY16_TYPE)
+ {
+ for (i = sizeof(socket_data.LocalAddr)-1; i >= 0; i--)
+ {
+ addr[sizeof(socket_data.LocalAddr)-i-1] =
+ value.byteArray16->byteArray16[i];
+ }
+ }
+ else
+ {
+ socket_data.LocalAddr[0] = 0;
+ socket_data.LocalAddr[1] = 0;
+ socket_data.LocalAddr[2] = 0;
+ socket_data.LocalAddr[3] = 0;
+ }
+ socket_data.RemoteAddr[0] = 0;
+ socket_data.RemoteAddr[1] = 0;
+ socket_data.RemoteAddr[2] = 0;
+ socket_data.RemoteAddr[3] = 0;
+ value = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_LOCAL_PORT].value;
+ socket_data.LocalPort = (value.type == FWP_UINT16? value.uint16: 0);
+ socket_data.RemotePort = 0;
+ socket_data.Protocol = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_PROTOCOL].value.uint8;
+
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+
+ windivert_socket_classify((context_t)filter->context,
+ &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_BIND, /*ipv4=*/FALSE,
+ /*outbound=*/FALSE, loopback, result);
+}
+
+/*
+ * WinDivert classify auth connect IPv4 function.
+ */
+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,
+ const FWPS_FILTER0 *filter, IN UINT64 flow_context,
+ OUT FWPS_CLASSIFY_OUT0 *result)
+{
+ WINDIVERT_SOCKET_DATA socket_data;
+ BOOL loopback;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ socket_data.LocalAddr[0] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS].value.uint32;
+ socket_data.LocalAddr[1] = 0x0000FFFF;
+ socket_data.LocalAddr[2] = 0;
+ socket_data.LocalAddr[3] = 0;
+ socket_data.RemoteAddr[0] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS].value.uint32;
+ socket_data.RemoteAddr[1] = 0x0000FFFF;
+ socket_data.RemoteAddr[2] = 0;
+ socket_data.RemoteAddr[3] = 0;
+ socket_data.LocalPort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16;
+ socket_data.RemotePort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16;
+ socket_data.Protocol = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8;
+
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+
+ windivert_socket_classify((context_t)filter->context,
+ &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_CONNECT, /*ipv4=*/TRUE,
+ /*outbound=*/TRUE, loopback, result);
+}
+
+/*
+ * WinDivert classify auth connect IPv6 function.
+ */
+static void windivert_auth_connect_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_SOCKET_DATA socket_data;
+ BOOL loopback;
+ UINT8 *addr;
+ INT i;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ addr = (UINT8 *)&socket_data.LocalAddr;
+ for (i = sizeof(socket_data.LocalAddr)-1; i >= 0; i--)
+ {
+ addr[sizeof(socket_data.LocalAddr)-i-1] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_ADDRESS]
+ .value.byteArray16->byteArray16[i];
+ }
+ addr = (UINT8 *)&socket_data.RemoteAddr;
+ for (i = sizeof(socket_data.RemoteAddr)-1; i >= 0; i--)
+ {
+ addr[sizeof(socket_data.RemoteAddr)-i-1] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_ADDRESS]
+ .value.byteArray16->byteArray16[i];
+ }
+ socket_data.LocalPort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16;
+ socket_data.RemotePort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16;
+ socket_data.Protocol = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8;
+
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS].value.uint32 &
+ 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 auth listen IPv4 function.
+ */
+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,
+ const FWPS_FILTER0 *filter, IN UINT64 flow_context,
+ OUT FWPS_CLASSIFY_OUT0 *result)
+{
+ WINDIVERT_SOCKET_DATA socket_data;
+ BOOL loopback;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ socket_data.LocalAddr[0] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_LISTEN_V4_IP_LOCAL_ADDRESS].value.uint32;
+ socket_data.LocalAddr[1] = 0x0000FFFF;
+ socket_data.LocalAddr[2] = 0;
+ socket_data.LocalAddr[3] = 0;
+ socket_data.RemoteAddr[0] = 0;
+ socket_data.RemoteAddr[1] = 0;
+ socket_data.RemoteAddr[2] = 0;
+ socket_data.RemoteAddr[3] = 0;
+ socket_data.LocalPort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_LISTEN_V4_IP_LOCAL_PORT].value.uint16;
+ socket_data.RemotePort = 0;
+ socket_data.Protocol = IPPROTO_TCP;
+
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_LISTEN_V4_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+
+ windivert_socket_classify((context_t)filter->context,
+ &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_LISTEN, /*ipv4=*/TRUE,
+ /*outbound=*/FALSE, loopback, result);
+}
+
+/*
+ * WinDivert classify auth listen IPv6 function.
+ */
+static void windivert_auth_listen_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_SOCKET_DATA socket_data;
+ BOOL loopback;
+ UINT8 *addr;
+ INT i;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ addr = (UINT8 *)&socket_data.LocalAddr;
+ for (i = sizeof(socket_data.LocalAddr)-1; i >= 0; i--)
+ {
+ addr[sizeof(socket_data.LocalAddr)-i-1] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_LISTEN_V6_IP_LOCAL_ADDRESS]
+ .value.byteArray16->byteArray16[i];
+ }
+ socket_data.RemoteAddr[0] = 0;
+ socket_data.RemoteAddr[1] = 0;
+ socket_data.RemoteAddr[2] = 0;
+ socket_data.RemoteAddr[3] = 0;
+ socket_data.LocalPort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_LISTEN_V6_IP_LOCAL_PORT].value.uint16;
+ socket_data.RemotePort = 0;
+ socket_data.Protocol = IPPROTO_TCP;
+
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_LISTEN_V6_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+
+ windivert_socket_classify((context_t)filter->context,
+ &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_LISTEN, /*ipv4=*/FALSE,
+ /*outbound=*/FALSE, loopback, result);
+}
+
+/*
+ * WinDivert classify auth recv accept IPv4 function.
+ */
+static void windivert_auth_recv_accept_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_SOCKET_DATA socket_data;
+ BOOL loopback;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ socket_data.LocalAddr[0] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS].value.uint32;
+ socket_data.LocalAddr[1] = 0x0000FFFF;
+ socket_data.LocalAddr[2] = 0;
+ socket_data.LocalAddr[3] = 0;
+ socket_data.RemoteAddr[0] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS].value.uint32;
+ socket_data.RemoteAddr[1] = 0x0000FFFF;
+ socket_data.RemoteAddr[2] = 0;
+ socket_data.RemoteAddr[3] = 0;
+ socket_data.LocalPort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT].value.uint16;
+ socket_data.RemotePort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT].value.uint16;
+ socket_data.Protocol = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8;
+
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+
+ windivert_socket_classify((context_t)filter->context,
+ &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_ACCEPT, /*ipv4=*/TRUE,
+ /*outbound=*/FALSE, loopback, result);
+}
+
+/*
+ * WinDivert classify auth recv accept IPv6 function.
+ */
+static void windivert_auth_recv_accept_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_SOCKET_DATA socket_data;
+ BOOL loopback;
+ UINT8 *addr;
+ INT i;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ addr = (UINT8 *)&socket_data.LocalAddr;
+ for (i = sizeof(socket_data.LocalAddr)-1; i >= 0; i--)
+ {
+ addr[sizeof(socket_data.LocalAddr)-i-1] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_ADDRESS]
+ .value.byteArray16->byteArray16[i];
+ }
+ addr = (UINT8 *)&socket_data.RemoteAddr;
+ for (i = sizeof(socket_data.RemoteAddr)-1; i >= 0; i--)
+ {
+ addr[sizeof(socket_data.RemoteAddr)-i-1] = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_ADDRESS]
+ .value.byteArray16->byteArray16[i];
+ }
+ socket_data.LocalPort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT].value.uint16;
+ socket_data.RemotePort = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT].value.uint16;
+ socket_data.Protocol = fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8;
+
+ loopback = ((fixed_vals->incomingValue[
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS].value.uint32 &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+
+ windivert_socket_classify((context_t)filter->context,
+ &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_ACCEPT, /*ipv4=*/FALSE,
+ /*outbound=*/FALSE, loopback, result);
+}
+
+/*
+ * WinDivert socket classify function.
+ */
+static void windivert_socket_classify(context_t context,
+ PWINDIVERT_SOCKET_DATA socket_data, WINDIVERT_EVENT event, BOOL ipv4,
+ BOOL outbound, BOOL loopback, FWPS_CLASSIFY_OUT0 *result)
+{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ UINT64 flags;
+ BOOL match, ok;
+ WDFOBJECT object;
+ PWINDIVERT_FILTER filter;
+ 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;
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ return;
+ }
+ filter = context->filter;
+ flags = context->flags;
+ object = (WDFOBJECT)context->object;
+ WdfObjectReference(object);
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_SOCKET,
+ (PVOID)socket_data, event, ipv4, outbound, loopback,
+ /*impostor=*/FALSE, filter);
+ if (match)
+ {
+ ok = windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0,
+ /*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_SOCKET,
+ (PVOID)socket_data, event, flags, /*priority=*/0, ipv4, outbound,
+ loopback, /*impostor=*/FALSE, /*final=*/FALSE, match, timestamp);
+ if (!ok)
+ {
+ WdfObjectDereference(object);
+ return;
+ }
+ }
+
+ WdfObjectDereference(object);
+ if ((flags & WINDIVERT_FLAG_SNIFF) == 0)
+ {
+ result->actionType = FWP_ACTION_BLOCK;
+ result->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
+ result->rights &= ~FWPS_RIGHT_ACTION_WRITE;
+ }
+}
+
/*
* WinDivert work item routine for out-of-band filtering.
*/
@@ -3211,6 +3940,7 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksums;
PWINDIVERT_NETWORK_DATA network_data;
PWINDIVERT_FLOW_DATA flow_data;
+ PWINDIVERT_SOCKET_DATA socket_data;
PWINDIVERT_REFLECT_DATA reflect_data;
BOOL pseudo_ip_checksum, pseudo_tcp_checksum, pseudo_udp_checksum;
@@ -3288,6 +4018,21 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
pseudo_ip_checksum = pseudo_tcp_checksum = pseudo_udp_checksum =
FALSE;
break;
+
+ case WINDIVERT_LAYER_SOCKET:
+ socket_data = (PWINDIVERT_SOCKET_DATA)layer_data;
+ work = (packet_t)windivert_malloc(
+ WINDIVERT_PACKET_SIZE(WINDIVERT_SOCKET_DATA, 0), FALSE);
+ if (work == NULL)
+ {
+ return TRUE;
+ }
+ work->packet_len = 0;
+ data = WINDIVERT_LAYER_DATA_PTR(work);
+ RtlCopyMemory(data, socket_data, sizeof(WINDIVERT_SOCKET_DATA));
+ pseudo_ip_checksum = pseudo_tcp_checksum = pseudo_udp_checksum =
+ FALSE;
+ break;
case WINDIVERT_LAYER_REFLECT:
reflect_data = (PWINDIVERT_REFLECT_DATA)layer_data;
@@ -3600,7 +4345,7 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
PWINDIVERT_ICMPHDR *icmp_header_ptr,
PWINDIVERT_ICMPV6HDR *icmpv6_header_ptr,
PWINDIVERT_TCPHDR *tcp_header_ptr, PWINDIVERT_UDPHDR *udp_header_ptr,
- UINT *payload_len_ptr)
+ UINT8 *proto_ptr, UINT *payload_len_ptr)
{
UINT tot_len, ip_header_len;
PWINDIVERT_IPHDR ip_header = NULL;
@@ -3767,6 +4512,7 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
*icmpv6_header_ptr = icmpv6_header;
*tcp_header_ptr = tcp_header;
*udp_header_ptr = udp_header;
+ *proto_ptr = proto;
*payload_len_ptr = payload_len;
return TRUE;
@@ -3785,10 +4531,12 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
PWINDIVERT_ICMPV6HDR icmpv6_header = NULL;
PWINDIVERT_TCPHDR tcp_header = NULL;
PWINDIVERT_UDPHDR udp_header = NULL;
+ UINT8 protocol = 0;
UINT payload_len = 0;
UINT16 ip, ttl;
PWINDIVERT_NETWORK_DATA network_data = NULL;
PWINDIVERT_FLOW_DATA flow_data = NULL;
+ PWINDIVERT_SOCKET_DATA socket_data = NULL;
PWINDIVERT_REFLECT_DATA reflect_data = NULL;
NTSTATUS status;
@@ -3798,7 +4546,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
case WINDIVERT_LAYER_NETWORK_FORWARD:
if (!windivert_parse_headers(buffer, ipv4, &ip_header, &ipv6_header,
&icmp_header, &icmpv6_header, &tcp_header, &udp_header,
- &payload_len))
+ &protocol, &payload_len))
{
return FALSE;
}
@@ -3807,6 +4555,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
case WINDIVERT_LAYER_FLOW:
flow_data = (PWINDIVERT_FLOW_DATA)layer_data;
break;
+ case WINDIVERT_LAYER_SOCKET:
+ socket_data = (PWINDIVERT_SOCKET_DATA)layer_data;
+ break;
case WINDIVERT_LAYER_REFLECT:
reflect_data = (PWINDIVERT_REFLECT_DATA)layer_data;
break;
@@ -3836,6 +4587,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
break;
case WINDIVERT_FILTER_FIELD_INBOUND:
case WINDIVERT_FILTER_FIELD_OUTBOUND:
+ result = (layer != WINDIVERT_LAYER_NETWORK_FORWARD &&
+ layer != WINDIVERT_LAYER_REFLECT);
+ break;
case WINDIVERT_FILTER_FIELD_LOOPBACK:
case WINDIVERT_FILTER_FIELD_IMPOSTOR:
case WINDIVERT_FILTER_FIELD_IP:
@@ -3850,25 +4604,23 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
result = (layer == WINDIVERT_LAYER_NETWORK ||
layer == WINDIVERT_LAYER_NETWORK_FORWARD);
- result = result && (network_data != NULL);
break;
case WINDIVERT_FILTER_FIELD_LOCALADDR:
case WINDIVERT_FILTER_FIELD_REMOTEADDR:
case WINDIVERT_FILTER_FIELD_LOCALPORT:
case WINDIVERT_FILTER_FIELD_REMOTEPORT:
case WINDIVERT_FILTER_FIELD_PROTOCOL:
- result = (layer == WINDIVERT_LAYER_FLOW);
- result = result && (flow_data != NULL);
+ result = (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_FLOW ||
+ layer == WINDIVERT_LAYER_SOCKET);
break;
case WINDIVERT_FILTER_FIELD_PROCESSID:
- result = ((layer == WINDIVERT_LAYER_FLOW &&
- flow_data != NULL) ||
- (layer == WINDIVERT_LAYER_REFLECT &&
- reflect_data != NULL));
+ result = (layer == WINDIVERT_LAYER_FLOW ||
+ layer == WINDIVERT_LAYER_SOCKET ||
+ layer == WINDIVERT_LAYER_REFLECT);
break;
case WINDIVERT_FILTER_FIELD_LAYER:
result = (layer == WINDIVERT_LAYER_REFLECT);
- result = result && (reflect_data != NULL);
break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
case WINDIVERT_FILTER_FIELD_IP_TOS:
@@ -3981,24 +4733,88 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
field[0] = (UINT32)!ipv4;
break;
case WINDIVERT_FILTER_FIELD_ICMP:
- field[0] = (UINT32)(flow_data != NULL?
- flow_data->Protocol == IPPROTO_ICMP:
- icmp_header != NULL);
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ field[0] = (UINT32)(icmp_header != NULL);
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ field[0] = (UINT32)(ipv4 &&
+ socket_data->Protocol == IPPROTO_ICMP);
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ field[0] = (UINT32)(ipv4 &&
+ flow_data->Protocol == IPPROTO_ICMP);
+ break;
+ default:
+ error = TRUE;
+ result = FALSE;
+ break;
+ }
break;
case WINDIVERT_FILTER_FIELD_ICMPV6:
- field[0] = (UINT32)(flow_data != NULL?
- flow_data->Protocol == IPPROTO_ICMPV6:
- icmpv6_header != NULL);
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ field[0] = (UINT32)(icmpv6_header != NULL);
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ field[0] = (UINT32)(!ipv4 &&
+ socket_data->Protocol == IPPROTO_ICMPV6);
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ field[0] = (UINT32)(!ipv4 &&
+ flow_data->Protocol == IPPROTO_ICMPV6);
+ break;
+ default:
+ error = TRUE;
+ result = FALSE;
+ break;
+ }
break;
case WINDIVERT_FILTER_FIELD_TCP:
- field[0] = (UINT32)(flow_data != NULL?
- flow_data->Protocol == IPPROTO_TCP:
- tcp_header != NULL);
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ field[0] = (UINT32)(tcp_header != NULL);
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ field[0] =
+ (UINT32)(socket_data->Protocol == IPPROTO_TCP);
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ field[0] =
+ (UINT32)(flow_data->Protocol == IPPROTO_TCP);
+ break;
+ default:
+ error = TRUE;
+ result = FALSE;
+ break;
+ }
break;
case WINDIVERT_FILTER_FIELD_UDP:
- field[0] = (UINT32)(flow_data != NULL?
- flow_data->Protocol == IPPROTO_UDP:
- udp_header != NULL);
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ field[0] = (UINT32)(udp_header != NULL);
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ field[0] =
+ (UINT32)(socket_data->Protocol == IPPROTO_UDP);
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ field[0] =
+ (UINT32)(flow_data->Protocol == IPPROTO_UDP);
+ break;
+ default:
+ error = TRUE;
+ result = FALSE;
+ break;
+ }
break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
field[0] = (UINT32)ip_header->HdrLength;
@@ -4164,30 +4980,209 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
field[0] = (UINT32)payload_len;
break;
case WINDIVERT_FILTER_FIELD_LOCALADDR:
- field[0] = flow_data->LocalAddr[0];
- field[1] = flow_data->LocalAddr[1];
- field[2] = flow_data->LocalAddr[2];
- field[3] = flow_data->LocalAddr[3];
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ if (ipv4)
+ {
+ field[1] = 0x0000FFFF;
+ field[0] = (UINT32)RtlUlongByteSwap(
+ (outbound? ip_header->SrcAddr:
+ ip_header->DstAddr));
+ }
+ else if (outbound)
+ {
+ field[3] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->SrcAddr[0]);
+ field[2] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->SrcAddr[1]);
+ field[1] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->SrcAddr[2]);
+ field[0] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->SrcAddr[3]);
+ }
+ else
+ {
+ field[3] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->DstAddr[0]);
+ field[2] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->DstAddr[1]);
+ field[1] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->DstAddr[2]);
+ field[0] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->DstAddr[3]);
+ }
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ field[0] = flow_data->LocalAddr[0];
+ field[1] = flow_data->LocalAddr[1];
+ field[2] = flow_data->LocalAddr[2];
+ field[3] = flow_data->LocalAddr[3];
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ field[0] = socket_data->LocalAddr[0];
+ field[1] = socket_data->LocalAddr[1];
+ field[2] = socket_data->LocalAddr[2];
+ field[3] = socket_data->LocalAddr[3];
+ break;
+ default:
+ error = TRUE;
+ result = FALSE;
+ break;
+ }
break;
case WINDIVERT_FILTER_FIELD_REMOTEADDR:
- field[0] = flow_data->RemoteAddr[0];
- field[1] = flow_data->RemoteAddr[1];
- field[2] = flow_data->RemoteAddr[2];
- field[3] = flow_data->RemoteAddr[3];
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ if (ipv4)
+ {
+ field[1] = 0x0000FFFF;
+ field[0] = (UINT32)RtlUlongByteSwap(
+ (!outbound? ip_header->SrcAddr:
+ ip_header->DstAddr));
+ }
+ else if (!outbound)
+ {
+ field[3] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->SrcAddr[0]);
+ field[2] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->SrcAddr[1]);
+ field[1] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->SrcAddr[2]);
+ field[0] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->SrcAddr[3]);
+ }
+ else
+ {
+ field[3] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->DstAddr[0]);
+ field[2] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->DstAddr[1]);
+ field[1] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->DstAddr[2]);
+ field[0] = (UINT32)RtlUlongByteSwap(
+ ipv6_header->DstAddr[3]);
+ }
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ field[0] = flow_data->RemoteAddr[0];
+ field[1] = flow_data->RemoteAddr[1];
+ field[2] = flow_data->RemoteAddr[2];
+ field[3] = flow_data->RemoteAddr[3];
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ field[0] = socket_data->RemoteAddr[0];
+ field[1] = socket_data->RemoteAddr[1];
+ field[2] = socket_data->RemoteAddr[2];
+ field[3] = socket_data->RemoteAddr[3];
+ break;
+ default:
+ error = TRUE;
+ result = FALSE;
+ break;
+ }
break;
case WINDIVERT_FILTER_FIELD_LOCALPORT:
- field[0] = (UINT32)flow_data->LocalPort;
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ if (tcp_header != NULL)
+ {
+ field[0] = (UINT32)RtlUshortByteSwap(
+ (outbound? tcp_header->SrcPort:
+ tcp_header->DstPort));
+ }
+ else if (udp_header != NULL)
+ {
+ field[0] = (UINT32)RtlUshortByteSwap(
+ (outbound? udp_header->SrcPort:
+ udp_header->DstPort));
+ }
+ else
+ {
+ field[0] = 0;
+ }
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ field[0] = (UINT32)flow_data->LocalPort;
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ field[0] = (UINT32)socket_data->LocalPort;
+ break;
+ default:
+ error = TRUE;
+ result = FALSE;
+ break;
+ }
break;
case WINDIVERT_FILTER_FIELD_REMOTEPORT:
- field[0] = (UINT32)flow_data->RemotePort;
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ if (tcp_header != NULL)
+ {
+ field[0] = (UINT32)RtlUshortByteSwap(
+ (!outbound? tcp_header->SrcPort:
+ tcp_header->DstPort));
+ }
+ else if (udp_header != NULL)
+ {
+ field[0] = (UINT32)RtlUshortByteSwap(
+ (!outbound? udp_header->SrcPort:
+ udp_header->DstPort));
+ }
+ else
+ {
+ field[0] = 0;
+ }
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ field[0] = (UINT32)flow_data->RemotePort;
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ field[0] = (UINT32)socket_data->RemotePort;
+ break;
+ default:
+ error = TRUE;
+ result = FALSE;
+ break;
+ }
break;
case WINDIVERT_FILTER_FIELD_PROTOCOL:
- field[0] = (UINT32)flow_data->Protocol;
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ field[0] = (UINT32)protocol;
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ field[0] = (UINT32)flow_data->Protocol;
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ field[0] = (UINT32)socket_data->Protocol;
+ break;
+ default:
+ error = TRUE;
+ result = FALSE;
+ break;
+ }
break;
case WINDIVERT_FILTER_FIELD_PROCESSID:
- field[0] = (flow_data != NULL?
- flow_data->ProcessId:
- reflect_data->ProcessId);
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_FLOW:
+ field[0] = flow_data->ProcessId;
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ field[0] = socket_data->ProcessId;
+ break;
+ case WINDIVERT_LAYER_REFLECT:
+ field[0] = reflect_data->ProcessId;
+ break;
+ default:
+ error = TRUE;
+ result = FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_LAYER:
field[0] = reflect_data->Layer;
@@ -4520,15 +5515,24 @@ static void windivert_reflect_event(context_t context, WINDIVERT_EVENT event)
// To be released on WINDIVERT_EVENT_REFLECT_CLOSE. This ensures the
// context object remains valid until the close event has been handled.
WdfObjectReference(object);
+ context->reflect.open = TRUE;
}
KeReleaseInStackQueuedSpinLock(&lock_handle);
+ if (!context->reflect.open)
+ {
+ // Ignore CLOSE with no matching OPEN:
+ return;
+ }
// Queue the event:
reflect_event = (reflect_event_t)windivert_malloc(
sizeof(struct reflect_event_s), FALSE);
if (reflect_event == NULL)
{
- WdfObjectDereference(object);
+ if (event == WINDIVERT_EVENT_REFLECT_CLOSE && context->reflect.open)
+ {
+ WdfObjectDereference(object);
+ }
return;
}
reflect_event->context = context;
diff --git a/test/test.c b/test/test.c
index f6511fc..fa30a02 100644
--- a/test/test.c
+++ b/test/test.c
@@ -257,6 +257,8 @@ static struct test tests[] =
&pkt_dns_request, TRUE},
{"ip.SrcAddr < 10.0.0.0 or ip.SrcAddr > 10.255.255.255",
&pkt_dns_request, FALSE},
+ {"ip.DstAddr == ::ffff:8.8.4.4", &pkt_dns_request, TRUE},
+ {"ip.DstAddr == ::0:ffff:8.8.4.4", &pkt_dns_request, TRUE},
{"udp.PayloadLength == 29", &pkt_dns_request, TRUE},
{"ipv6", &pkt_ipv6_tcp_syn, TRUE},
{"ip", &pkt_ipv6_tcp_syn, FALSE},
@@ -284,8 +286,10 @@ static struct test tests[] =
{"false", &pkt_ipv6_exthdrs_udp, FALSE},
{"udp", &pkt_ipv6_exthdrs_udp, TRUE},
{"tcp", &pkt_ipv6_exthdrs_udp, FALSE},
+ {"ipv6.SrcAddr == ::", &pkt_ipv6_exthdrs_udp, FALSE},
{"ipv6.SrcAddr == ::1", &pkt_ipv6_exthdrs_udp, TRUE},
{"ipv6.SrcAddr == ::2", &pkt_ipv6_exthdrs_udp, FALSE},
+ {"ipv6.SrcAddr == ::8.8.4.4", &pkt_ipv6_exthdrs_udp, FALSE},
{"ipv6.SrcAddr < abcd::1", &pkt_ipv6_exthdrs_udp, TRUE},
{"ipv6.SrcAddr <= abcd::1", &pkt_ipv6_exthdrs_udp, TRUE},
{"ipv6.SrcAddr != abcd::1", &pkt_ipv6_exthdrs_udp, TRUE},
@@ -332,7 +336,7 @@ int main(void)
Sleep(100);
// Run tests:
- size_t num_tests = sizeof(tests) / sizeof(struct test);
+ size_t num_tests = sizeof(tests) / sizeof(struct test), passed_tests = 0;
for (i = 0; i < num_tests; i++)
{
char *filter = tests[i].filter;
@@ -352,6 +356,7 @@ int main(void)
{
SetConsoleTextAttribute(console, FOREGROUND_GREEN);
printf("PASSED");
+ passed_tests++;
}
else
{
@@ -376,6 +381,9 @@ int main(void)
WinDivertClose(upper_handle);
WinDivertClose(lower_handle);
+ printf("\npassed = %.2f%%\n",
+ ((double)passed_tests / (double)num_tests) * 100.0);
+
return 0;
}
From 5aa4fc3c4622da87e1b70277d2fd4857845fbc3c Mon Sep 17 00:00:00 2001
From: basil00
Date: Fri, 26 Oct 2018 06:43:49 +0800
Subject: [PATCH 05/23] Enable NX flag for MmGetSystemAddressForMdlSafe.
See discussion in #128.
---
sys/windivert.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/sys/windivert.c b/sys/windivert.c
index e6cb0f9..191b3b3 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -327,6 +327,8 @@ static HANDLE engine_handle = NULL;
static LONG priority_counter = 0;
static LONGLONG counts_per_ms = 0;
static POOL_TYPE non_paged_pool = NonPagedPool;
+static MM_PAGE_PRIORITY no_write_flag = 0;
+static MM_PAGE_PRIORITY no_exec_flag = 0;
/*
* Priorities & weights.
@@ -862,6 +864,10 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj,
(version.dwMajorVersion == 6 && version.dwMinorVersion >= 2))
{
non_paged_pool = (POOL_TYPE)512; // NonPagedPoolNx (documented)
+ no_exec_flag = (MM_PAGE_PRIORITY)0x40000000;
+ // MdlMappingNoExecute
+ no_write_flag = (MM_PAGE_PRIORITY)0x80000000;
+ // MdlMappingNoWrite
}
}
@@ -1952,7 +1958,8 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
DEBUG_ERROR("failed to retrieve output MDL", status);
goto windivert_read_service_request_exit;
}
- dst = MmGetSystemAddressForMdlSafe(dst_mdl, NormalPagePriority);
+ dst = MmGetSystemAddressForMdlSafe(dst_mdl,
+ NormalPagePriority | no_exec_flag);
if (dst == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
@@ -2158,7 +2165,8 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
goto windivert_write_exit;
}
- data = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority);
+ data = MmGetSystemAddressForMdlSafe(mdl,
+ NormalPagePriority | no_write_flag | no_exec_flag);
if (data == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
@@ -2318,7 +2326,8 @@ static void NTAPI windivert_inject_complete(VOID *context,
WdfRequestCompleteWithInformation(request, status, length);
}
mdl = NET_BUFFER_FIRST_MDL(buffer);
- data = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority);
+ data = MmGetSystemAddressForMdlSafe(mdl,
+ NormalPagePriority | no_exec_flag);
windivert_free(data);
IoFreeMdl(mdl);
FwpsFreeNetBufferList0(buffers);
From 34e8f96910dfc6a35dbdbad08942e2e8e8f29dc5 Mon Sep 17 00:00:00 2001
From: basil00
Date: Fri, 26 Oct 2018 06:57:40 +0800
Subject: [PATCH 06/23] Consistent naming for DATA structs.
---
include/windivert.h | 16 +++---
sys/windivert.c | 118 ++++++++++++++++++++++----------------------
2 files changed, 67 insertions(+), 67 deletions(-)
diff --git a/include/windivert.h b/include/windivert.h
index aa35f40..dfe341d 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -88,7 +88,7 @@ typedef struct
{
UINT32 IfIdx; /* Packet's interface index. */
UINT32 SubIfIdx; /* Packet's sub-interface index. */
-} WINDIVERT_NETWORK_DATA, *PWINDIVERT_NETWORK_DATA;
+} WINDIVERT_DATA_NETWORK, *PWINDIVERT_DATA_NETWORK;
/*
* WinDivert FLOW layer data.
@@ -101,7 +101,7 @@ typedef struct
UINT16 LocalPort; /* Local port. */
UINT16 RemotePort; /* Remote port. */
UINT8 Protocol; /* Protocol. */
-} WINDIVERT_FLOW_DATA, *PWINDIVERT_FLOW_DATA;
+} WINDIVERT_DATA_FLOW, *PWINDIVERT_DATA_FLOW;
/*
* WinDivert SOCKET layer data.
@@ -114,7 +114,7 @@ typedef struct
UINT16 LocalPort; /* Local port. */
UINT16 RemotePort; /* Remote port. */
UINT8 Protocol; /* Protocol. */
-} WINDIVERT_SOCKET_DATA, *PWINDIVERT_SOCKET_DATA;
+} WINDIVERT_DATA_SOCKET, *PWINDIVERT_DATA_SOCKET;
/*
* WinDivert REFLECTION layer data.
@@ -126,7 +126,7 @@ typedef struct
WINDIVERT_LAYER Layer; /* Handle layer. */
UINT64 Flags; /* Handle flags. */
INT16 Priority; /* Handle priority. */
-} WINDIVERT_REFLECT_DATA, *PWINDIVERT_REFLECT_DATA;
+} WINDIVERT_DATA_REFLECT, *PWINDIVERT_DATA_REFLECT;
/*
* WinDivert address.
@@ -147,10 +147,10 @@ typedef struct
UINT32 Reserved:8;
union
{
- WINDIVERT_NETWORK_DATA Network; /* Network layer data. */
- WINDIVERT_FLOW_DATA Flow; /* Flow layer data. */
- WINDIVERT_SOCKET_DATA Socket; /* Socket layer data. */
- WINDIVERT_REFLECT_DATA Reflect; /* Reflect layer data. */
+ 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. */
};
} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
diff --git a/sys/windivert.c b/sys/windivert.c
index 191b3b3..47dacac 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -105,7 +105,7 @@ struct reflect_context_s
{
LIST_ENTRY entry; // Open handle entry.
LONGLONG timestamp; // Open timestamp.
- WINDIVERT_REFLECT_DATA data; // Reflect data.
+ WINDIVERT_DATA_REFLECT data; // Reflect data.
BOOL inserted; // Entry inserted?
BOOL open; // Seen OPEN event?
};
@@ -272,7 +272,7 @@ struct flow_s
BOOL outbound:1; // Flow is outound?
BOOL loopback:1; // Flow is loopback?
BOOL ipv6:1; // Flow is ipv6?
- WINDIVERT_FLOW_DATA data; // Flow data.
+ WINDIVERT_DATA_FLOW data; // Flow data.
};
typedef struct flow_s *flow_t;
@@ -456,15 +456,15 @@ static void windivert_auth_recv_accept_v6_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result);
static void windivert_flow_established_classify(context_t context,
- IN UINT64 flow_id, IN PWINDIVERT_FLOW_DATA flow_data, IN BOOL ipv4,
+ IN UINT64 flow_id, IN PWINDIVERT_DATA_FLOW flow_data, IN BOOL ipv4,
IN BOOL outbound, IN BOOL loopback, OUT FWPS_CLASSIFY_OUT0 *result);
static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
UINT64 flow_context);
static void windivert_socket_classify(context_t context,
- PWINDIVERT_SOCKET_DATA socket_data, WINDIVERT_EVENT event, BOOL ipv4,
+ PWINDIVERT_DATA_SOCKET socket_data, WINDIVERT_EVENT event, BOOL ipv4,
BOOL outbound, BOOL loopback, FWPS_CLASSIFY_OUT0 *result);
static void windivert_network_classify(context_t context,
- IN PWINDIVERT_NETWORK_DATA network_data, IN BOOL ipv4, IN BOOL outbound,
+ IN PWINDIVERT_DATA_NETWORK network_data, IN BOOL ipv4, IN BOOL outbound,
IN BOOL loopback, IN UINT advance, IN OUT void *data,
OUT FWPS_CLASSIFY_OUT0 *result);
static BOOL windivert_queue_work(context_t context, PVOID packet,
@@ -1969,11 +1969,11 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
if (packet->layer != WINDIVERT_LAYER_REFLECT)
{
- src = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_NETWORK_DATA, packet);
+ src = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_NETWORK, packet);
}
else
{
- src = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_REFLECT_DATA, packet);
+ src = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_REFLECT, packet);
}
src_len = packet->packet_len;
dst_len = MmGetMdlByteCount(dst_mdl);
@@ -2016,22 +2016,22 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
RtlCopyMemory(&addr->Network, layer_data,
- sizeof(WINDIVERT_NETWORK_DATA));
+ sizeof(WINDIVERT_DATA_NETWORK));
break;
case WINDIVERT_LAYER_FLOW:
RtlCopyMemory(&addr->Flow, layer_data,
- sizeof(WINDIVERT_FLOW_DATA));
+ sizeof(WINDIVERT_DATA_FLOW));
break;
case WINDIVERT_LAYER_SOCKET:
RtlCopyMemory(&addr->Socket, layer_data,
- sizeof(WINDIVERT_SOCKET_DATA));
+ sizeof(WINDIVERT_DATA_SOCKET));
break;
case WINDIVERT_LAYER_REFLECT:
RtlCopyMemory(&addr->Reflect, layer_data,
- sizeof(WINDIVERT_REFLECT_DATA));
+ sizeof(WINDIVERT_DATA_REFLECT));
break;
default:
@@ -2842,7 +2842,7 @@ static void windivert_outbound_network_v4_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_NETWORK_DATA network_data;
+ WINDIVERT_DATA_NETWORK network_data;
BOOL loopback;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
@@ -2872,7 +2872,7 @@ static void windivert_outbound_network_v6_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_NETWORK_DATA network_data;
+ WINDIVERT_DATA_NETWORK network_data;
BOOL loopback;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
@@ -2902,7 +2902,7 @@ static void windivert_inbound_network_v4_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_NETWORK_DATA network_data;
+ WINDIVERT_DATA_NETWORK network_data;
UINT advance;
BOOL loopback;
@@ -2939,7 +2939,7 @@ static void windivert_inbound_network_v6_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_NETWORK_DATA network_data;
+ WINDIVERT_DATA_NETWORK network_data;
UINT advance;
BOOL loopback;
@@ -2976,7 +2976,7 @@ static void windivert_forward_network_v4_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_NETWORK_DATA network_data;
+ WINDIVERT_DATA_NETWORK network_data;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
{
@@ -3001,7 +3001,7 @@ static void windivert_forward_network_v6_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_NETWORK_DATA network_data;
+ WINDIVERT_DATA_NETWORK network_data;
if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
{
@@ -3021,7 +3021,7 @@ static void windivert_forward_network_v6_classify(
* WinDivert network classify function.
*/
static void windivert_network_classify(context_t context,
- IN PWINDIVERT_NETWORK_DATA network_data, IN BOOL ipv4, IN BOOL outbound,
+ IN PWINDIVERT_DATA_NETWORK network_data, IN BOOL ipv4, IN BOOL outbound,
IN BOOL loopback, IN UINT advance, IN OUT void *data,
OUT FWPS_CLASSIFY_OUT0 *result)
{
@@ -3223,7 +3223,7 @@ static void windivert_flow_established_v4_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_FLOW_DATA flow_data;
+ WINDIVERT_DATA_FLOW flow_data;
BOOL outbound, loopback;
UINT64 flow_id;
@@ -3266,7 +3266,7 @@ static void windivert_flow_established_v6_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_FLOW_DATA flow_data;
+ WINDIVERT_DATA_FLOW flow_data;
BOOL outbound, loopback;
UINT64 flow_id;
UINT8 *addr;
@@ -3311,7 +3311,7 @@ static void windivert_flow_established_v6_classify(
* WinDivert flow established classify function.
*/
static void windivert_flow_established_classify(context_t context,
- IN UINT64 flow_id, IN PWINDIVERT_FLOW_DATA flow_data, IN BOOL ipv4,
+ IN UINT64 flow_id, IN PWINDIVERT_DATA_FLOW flow_data, IN BOOL ipv4,
IN BOOL outbound, IN BOOL loopback, OUT FWPS_CLASSIFY_OUT0 *result)
{
KLOCK_QUEUE_HANDLE lock_handle;
@@ -3497,7 +3497,7 @@ static void windivert_resource_assignment_v4_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_SOCKET_DATA socket_data;
+ WINDIVERT_DATA_SOCKET socket_data;
FWP_VALUE0 value;
BOOL loopback;
@@ -3545,7 +3545,7 @@ static void windivert_resource_assignment_v6_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_SOCKET_DATA socket_data;
+ WINDIVERT_DATA_SOCKET socket_data;
FWP_VALUE0 value;
BOOL loopback;
UINT8 *addr;
@@ -3599,7 +3599,7 @@ static void windivert_auth_connect_v4_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_SOCKET_DATA socket_data;
+ WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
socket_data.ProcessId = (UINT32)meta_vals->processId;
@@ -3638,7 +3638,7 @@ static void windivert_auth_connect_v6_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_SOCKET_DATA socket_data;
+ WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
UINT8 *addr;
INT i;
@@ -3683,7 +3683,7 @@ static void windivert_auth_listen_v4_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_SOCKET_DATA socket_data;
+ WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
socket_data.ProcessId = (UINT32)meta_vals->processId;
@@ -3719,7 +3719,7 @@ static void windivert_auth_listen_v6_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_SOCKET_DATA socket_data;
+ WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
UINT8 *addr;
INT i;
@@ -3759,7 +3759,7 @@ static void windivert_auth_recv_accept_v4_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_SOCKET_DATA socket_data;
+ WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
socket_data.ProcessId = (UINT32)meta_vals->processId;
@@ -3798,7 +3798,7 @@ static void windivert_auth_recv_accept_v6_classify(
const FWPS_FILTER0 *filter, IN UINT64 flow_context,
OUT FWPS_CLASSIFY_OUT0 *result)
{
- WINDIVERT_SOCKET_DATA socket_data;
+ WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
UINT8 *addr;
INT i;
@@ -3838,7 +3838,7 @@ static void windivert_auth_recv_accept_v6_classify(
* WinDivert socket classify function.
*/
static void windivert_socket_classify(context_t context,
- PWINDIVERT_SOCKET_DATA socket_data, WINDIVERT_EVENT event, BOOL ipv4,
+ PWINDIVERT_DATA_SOCKET socket_data, WINDIVERT_EVENT event, BOOL ipv4,
BOOL outbound, BOOL loopback, FWPS_CLASSIFY_OUT0 *result)
{
KLOCK_QUEUE_HANDLE lock_handle;
@@ -3947,10 +3947,10 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
UINT8 *data;
PLIST_ENTRY old_entry;
NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksums;
- PWINDIVERT_NETWORK_DATA network_data;
- PWINDIVERT_FLOW_DATA flow_data;
- PWINDIVERT_SOCKET_DATA socket_data;
- PWINDIVERT_REFLECT_DATA reflect_data;
+ PWINDIVERT_DATA_NETWORK network_data;
+ PWINDIVERT_DATA_FLOW flow_data;
+ PWINDIVERT_DATA_SOCKET socket_data;
+ PWINDIVERT_DATA_REFLECT reflect_data;
BOOL pseudo_ip_checksum, pseudo_tcp_checksum, pseudo_udp_checksum;
if (!match && (flags & WINDIVERT_FLAG_SNIFF) != 0)
@@ -3968,14 +3968,14 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
buffer = (PNET_BUFFER)packet;
- network_data = (PWINDIVERT_NETWORK_DATA)layer_data;
+ network_data = (PWINDIVERT_DATA_NETWORK)layer_data;
if (packet_len > UINT16_MAX)
{
// Cannot handle oversized packet
return TRUE;
}
work = (packet_t)windivert_malloc(
- WINDIVERT_PACKET_SIZE(WINDIVERT_NETWORK_DATA, packet_len),
+ WINDIVERT_PACKET_SIZE(WINDIVERT_DATA_NETWORK, packet_len),
FALSE);
if (work == NULL)
{
@@ -3983,8 +3983,8 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
}
work->packet_len = (UINT32)packet_len;
data = WINDIVERT_LAYER_DATA_PTR(work);
- RtlCopyMemory(data, network_data, sizeof(WINDIVERT_NETWORK_DATA));
- data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_NETWORK_DATA, work);
+ RtlCopyMemory(data, network_data, sizeof(WINDIVERT_DATA_NETWORK));
+ data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_NETWORK, work);
packet_data = NdisGetDataBuffer(buffer, packet_len, NULL, 1, 0);
if (packet_data == NULL)
{
@@ -4014,39 +4014,39 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
break;
case WINDIVERT_LAYER_FLOW:
- flow_data = (PWINDIVERT_FLOW_DATA)layer_data;
+ flow_data = (PWINDIVERT_DATA_FLOW)layer_data;
work = (packet_t)windivert_malloc(
- WINDIVERT_PACKET_SIZE(WINDIVERT_FLOW_DATA, 0), FALSE);
+ WINDIVERT_PACKET_SIZE(WINDIVERT_DATA_FLOW, 0), FALSE);
if (work == NULL)
{
return TRUE;
}
work->packet_len = 0;
data = WINDIVERT_LAYER_DATA_PTR(work);
- RtlCopyMemory(data, flow_data, sizeof(WINDIVERT_FLOW_DATA));
+ RtlCopyMemory(data, flow_data, sizeof(WINDIVERT_DATA_FLOW));
pseudo_ip_checksum = pseudo_tcp_checksum = pseudo_udp_checksum =
FALSE;
break;
case WINDIVERT_LAYER_SOCKET:
- socket_data = (PWINDIVERT_SOCKET_DATA)layer_data;
+ socket_data = (PWINDIVERT_DATA_SOCKET)layer_data;
work = (packet_t)windivert_malloc(
- WINDIVERT_PACKET_SIZE(WINDIVERT_SOCKET_DATA, 0), FALSE);
+ WINDIVERT_PACKET_SIZE(WINDIVERT_DATA_SOCKET, 0), FALSE);
if (work == NULL)
{
return TRUE;
}
work->packet_len = 0;
data = WINDIVERT_LAYER_DATA_PTR(work);
- RtlCopyMemory(data, socket_data, sizeof(WINDIVERT_SOCKET_DATA));
+ RtlCopyMemory(data, socket_data, sizeof(WINDIVERT_DATA_SOCKET));
pseudo_ip_checksum = pseudo_tcp_checksum = pseudo_udp_checksum =
FALSE;
break;
case WINDIVERT_LAYER_REFLECT:
- reflect_data = (PWINDIVERT_REFLECT_DATA)layer_data;
+ reflect_data = (PWINDIVERT_DATA_REFLECT)layer_data;
work = (packet_t)windivert_malloc(
- WINDIVERT_PACKET_SIZE(WINDIVERT_REFLECT_DATA, packet_len),
+ WINDIVERT_PACKET_SIZE(WINDIVERT_DATA_REFLECT, packet_len),
FALSE);
if (work == NULL)
{
@@ -4054,8 +4054,8 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
}
work->packet_len = packet_len;
data = WINDIVERT_LAYER_DATA_PTR(work);
- RtlCopyMemory(data, reflect_data, sizeof(WINDIVERT_REFLECT_DATA));
- data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_REFLECT_DATA, work);
+ RtlCopyMemory(data, reflect_data, sizeof(WINDIVERT_DATA_REFLECT));
+ data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_REFLECT, work);
RtlCopyMemory(data, packet, packet_len);
pseudo_ip_checksum = TRUE;
pseudo_tcp_checksum = pseudo_udp_checksum = FALSE;
@@ -4188,7 +4188,7 @@ static void windivert_reinject_packet(packet_t packet)
{
UINT8 *packet_data;
UINT32 packet_len;
- PWINDIVERT_NETWORK_DATA network_data;
+ PWINDIVERT_DATA_NETWORK network_data;
PMDL mdl;
PNET_BUFFER_LIST buffers;
HANDLE handle;
@@ -4202,8 +4202,8 @@ static void windivert_reinject_packet(packet_t packet)
return;
}
- network_data = (PWINDIVERT_NETWORK_DATA)WINDIVERT_LAYER_DATA_PTR(packet);
- packet_data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_NETWORK_DATA, packet);
+ network_data = (PWINDIVERT_DATA_NETWORK)WINDIVERT_LAYER_DATA_PTR(packet);
+ packet_data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_NETWORK, packet);
packet_len = packet->packet_len;
mdl = IoAllocateMdl(packet_data, packet_len, FALSE, FALSE, NULL);
if (mdl == NULL)
@@ -4543,10 +4543,10 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
UINT8 protocol = 0;
UINT payload_len = 0;
UINT16 ip, ttl;
- PWINDIVERT_NETWORK_DATA network_data = NULL;
- PWINDIVERT_FLOW_DATA flow_data = NULL;
- PWINDIVERT_SOCKET_DATA socket_data = NULL;
- PWINDIVERT_REFLECT_DATA reflect_data = NULL;
+ PWINDIVERT_DATA_NETWORK network_data = NULL;
+ PWINDIVERT_DATA_FLOW flow_data = NULL;
+ PWINDIVERT_DATA_SOCKET socket_data = NULL;
+ PWINDIVERT_DATA_REFLECT reflect_data = NULL;
NTSTATUS status;
switch (layer)
@@ -4559,16 +4559,16 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
{
return FALSE;
}
- network_data = (PWINDIVERT_NETWORK_DATA)layer_data;
+ network_data = (PWINDIVERT_DATA_NETWORK)layer_data;
break;
case WINDIVERT_LAYER_FLOW:
- flow_data = (PWINDIVERT_FLOW_DATA)layer_data;
+ flow_data = (PWINDIVERT_DATA_FLOW)layer_data;
break;
case WINDIVERT_LAYER_SOCKET:
- socket_data = (PWINDIVERT_SOCKET_DATA)layer_data;
+ socket_data = (PWINDIVERT_DATA_SOCKET)layer_data;
break;
case WINDIVERT_LAYER_REFLECT:
- reflect_data = (PWINDIVERT_REFLECT_DATA)layer_data;
+ reflect_data = (PWINDIVERT_DATA_REFLECT)layer_data;
break;
default:
DEBUG("FILTER: REJECT (invalid parameter)");
From 86db54b400206cb0961c8447faf10fa4f9527ef2 Mon Sep 17 00:00:00 2001
From: basil00
Date: Fri, 26 Oct 2018 10:38:35 +0800
Subject: [PATCH 07/23] Move pseduo checksum calculation inside driver.
This means WinDivertSend() no longer needs to
modify the packet and address buffers. See #134.
---
dll/windivert.c | 50 -----
dll/windivert_helper.c | 418 +----------------------------------------
include/windivert.h | 4 +-
sys/windivert.c | 47 +++--
4 files changed, 37 insertions(+), 482 deletions(-)
diff --git a/dll/windivert.c b/dll/windivert.c
index 32a4da4..eb4fd28 100644
--- a/dll/windivert.c
+++ b/dll/windivert.c
@@ -51,19 +51,6 @@
#define WINDIVERT_DRIVER32_SYS L"\\" WINDIVERT_DRIVER_NAME L"32.sys"
#define WINDIVERT_DRIVER64_SYS L"\\" WINDIVERT_DRIVER_NAME L"64.sys"
-/*
- * Definitions to remove (some) external dependencies:
- */
-#define BYTESWAP16(x) \
- ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00))
-#define BYTESWAP32(x) \
- ((((x) >> 24) & 0x000000FF) | (((x) >> 8) & 0x0000FF00) | \
- (((x) << 8) & 0x00FF0000) | (((x) << 24) & 0xFF000000))
-#define ntohs(x) BYTESWAP16(x)
-#define htons(x) BYTESWAP16(x)
-#define ntohl(x) BYTESWAP32(x)
-#define htonl(x) BYTESWAP32(x)
-
static BOOLEAN WinDivertIsXDigit(char c);
static BOOLEAN WinDivertIsSpace(char c);
static BOOLEAN WinDivertIsAlNum(char c);
@@ -532,41 +519,6 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
return handle;
}
-/*
- * Workaround for #134
- */
-static void WinDivertFixChecksums(PVOID pPacket, UINT packetLen,
- PWINDIVERT_ADDRESS addr)
-{
- UINT64 flags =
- WINDIVERT_HELPER_NO_IP_CHECKSUM |
- WINDIVERT_HELPER_NO_TCP_CHECKSUM |
- WINDIVERT_HELPER_NO_UDP_CHECKSUM;
- BOOL calc = FALSE;
- if (addr->PseudoIPChecksum != 0)
- {
- addr->PseudoIPChecksum = 0;
- flags &= ~WINDIVERT_HELPER_NO_IP_CHECKSUM;
- calc = TRUE;
- }
- if (addr->PseudoTCPChecksum != 0)
- {
- addr->PseudoTCPChecksum = 0;
- flags &= ~WINDIVERT_HELPER_NO_TCP_CHECKSUM;
- calc = TRUE;
- }
- if (addr->PseudoUDPChecksum != 0)
- {
- addr->PseudoUDPChecksum = 0;
- flags &= ~WINDIVERT_HELPER_NO_UDP_CHECKSUM;
- calc = TRUE;
- }
- if (calc)
- {
- WinDivertHelperCalcChecksums(pPacket, packetLen, addr, flags);
- }
-}
-
/*
* Receive a WinDivert packet.
*/
@@ -612,7 +564,6 @@ extern BOOL WinDivertSend(HANDLE handle, PVOID pPacket, UINT packetLen,
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- WinDivertFixChecksums(pPacket, packetLen, addr);
return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND, 0, (UINT64)addr,
pPacket, packetLen, writelen);
}
@@ -629,7 +580,6 @@ extern BOOL WinDivertSendEx(HANDLE handle, PVOID pPacket, UINT packetLen,
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- WinDivertFixChecksums(pPacket, packetLen, addr);
if (overlapped == NULL)
{
return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND, 0,
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index 06976a6..0ffc158 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -252,8 +252,6 @@ typedef UINT64 ERROR, *PERROR;
#define IS_ERROR(err) \
(GET_CODE(err) != WINDIVERT_ERROR_NONE)
-#define MAX(a, b) ((a) > (b)? (a): (b))
-
/*
* Prototypes.
*/
@@ -261,233 +259,11 @@ static PEXPR WinDivertParseFilter(HANDLE pool, TOKEN *toks, UINT *i,
INT depth, BOOL and, PERROR error);
static BOOL WinDivertCondExecFilter(PWINDIVERT_FILTER filter, UINT length,
UINT8 field, UINT32 arg);
-static UINT16 WinDivertInitPseudoHeader(PWINDIVERT_IPHDR ip_header,
- PWINDIVERT_IPV6HDR ipv6_header, UINT8 protocol, UINT len,
- void *pseudo_header);
-static UINT16 WinDivertHelperCalcChecksum(PVOID pseudo_header,
- UINT16 pseudo_header_len, PVOID data, UINT len);
static BOOL WinDivertDeserializeFilter(PWINDIVERT_STREAM stream,
PWINDIVERT_FILTER filter, UINT *length);
static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
BOOL top_level, BOOL and);
-/*
- * Skip well-known IPv6 extension headers.
- */
-static UINT8 WinDivertSkipExtHeaders(UINT8 proto, UINT8 **header, UINT *len)
-{
- UINT hdrlen;
-
- while (TRUE)
- {
- if (*len <= 2)
- {
- return IPPROTO_NONE;
- }
-
- hdrlen = (UINT)*(*header + 1);
- switch (proto)
- {
- case IPPROTO_FRAGMENT:
- hdrlen = 8;
- break;
- case IPPROTO_AH:
- hdrlen += 2;
- hdrlen *= 4;
- break;
- case IPPROTO_HOPOPTS:
- case IPPROTO_DSTOPTS:
- case IPPROTO_ROUTING:
- hdrlen++;
- hdrlen *= 8;
- break;
- case IPPROTO_NONE:
- return proto;
- default:
- return proto;
- }
-
- if (hdrlen >= *len)
- {
- return IPPROTO_NONE;
- }
-
- proto = **header;
- *header += hdrlen;
- *len -= hdrlen;
- }
-}
-
-/*
- * Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
- */
-static BOOL WinDivertHelperParsePacket_2(PVOID pPacket, UINT packetLen,
- PWINDIVERT_IPHDR *ppIpHdr, PWINDIVERT_IPV6HDR *ppIpv6Hdr,
- PWINDIVERT_ICMPHDR *ppIcmpHdr, PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr,
- PWINDIVERT_TCPHDR *ppTcpHdr, PWINDIVERT_UDPHDR *ppUdpHdr, UINT8 *pProto,
- PVOID *ppData, UINT *pDataLen)
-{
- PWINDIVERT_IPHDR ip_header = NULL;
- PWINDIVERT_IPV6HDR ipv6_header = NULL;
- PWINDIVERT_ICMPHDR icmp_header = NULL;
- PWINDIVERT_ICMPV6HDR icmpv6_header = NULL;
- PWINDIVERT_TCPHDR tcp_header = NULL;
- PWINDIVERT_UDPHDR udp_header = NULL;
- UINT16 header_len;
- UINT8 trans_proto = 0;
- PVOID data = NULL;
- UINT data_len = 0;
- BOOL success;
-
- if (pPacket == NULL || packetLen < sizeof(UINT8))
- {
- goto WinDivertHelperParsePacketExit;
- }
- data = pPacket;
- data_len = packetLen;
-
- ip_header = (PWINDIVERT_IPHDR)data;
- switch (ip_header->Version)
- {
- case 4:
- if (data_len < sizeof(WINDIVERT_IPHDR) ||
- ip_header->HdrLength < 5 ||
- data_len < ip_header->HdrLength*sizeof(UINT32) ||
- ntohs(ip_header->Length) != data_len)
- {
- ip_header = NULL;
- goto WinDivertHelperParsePacketExit;
- }
- trans_proto = ip_header->Protocol;
- header_len = ip_header->HdrLength*sizeof(UINT32);
- data = (PVOID)((UINT8 *)data + header_len);
- data_len -= header_len;
- break;
- case 6:
- ip_header = NULL;
- ipv6_header = (PWINDIVERT_IPV6HDR)data;
- if (data_len < sizeof(WINDIVERT_IPV6HDR) ||
- ntohs(ipv6_header->Length) !=
- data_len - sizeof(WINDIVERT_IPV6HDR))
- {
- ipv6_header = NULL;
- goto WinDivertHelperParsePacketExit;
- }
- trans_proto = ipv6_header->NextHdr;
- data = (PVOID)((UINT8 *)data + sizeof(WINDIVERT_IPV6HDR));
- data_len -= sizeof(WINDIVERT_IPV6HDR);
- trans_proto = WinDivertSkipExtHeaders(trans_proto, (UINT8 **)&data,
- &data_len);
- break;
- default:
- ip_header = NULL;
- goto WinDivertHelperParsePacketExit;
- }
- switch (trans_proto)
- {
- case IPPROTO_TCP:
- tcp_header = (PWINDIVERT_TCPHDR)data;
- if (data_len < sizeof(WINDIVERT_TCPHDR) ||
- tcp_header->HdrLength < 5 ||
- data_len < tcp_header->HdrLength*sizeof(UINT32))
- {
- tcp_header = NULL;
- goto WinDivertHelperParsePacketExit;
- }
- header_len = tcp_header->HdrLength*sizeof(UINT32);
- data = ((UINT8 *)data + header_len);
- data_len -= header_len;
- break;
- case IPPROTO_UDP:
- udp_header = (PWINDIVERT_UDPHDR)data;
- if (data_len < sizeof(WINDIVERT_UDPHDR) ||
- ntohs(udp_header->Length) != data_len)
- {
- udp_header = NULL;
- goto WinDivertHelperParsePacketExit;
- }
- data = ((UINT8 *)data + sizeof(WINDIVERT_UDPHDR));
- data_len -= sizeof(WINDIVERT_UDPHDR);
- break;
- case IPPROTO_ICMP:
- icmp_header = (PWINDIVERT_ICMPHDR)data;
- if (ip_header == NULL ||
- data_len < sizeof(WINDIVERT_ICMPHDR))
- {
- icmp_header = NULL;
- goto WinDivertHelperParsePacketExit;
- }
- data = ((UINT8 *)data + sizeof(WINDIVERT_ICMPHDR));
- data_len -= sizeof(WINDIVERT_ICMPHDR);
- break;
- case IPPROTO_ICMPV6:
- icmpv6_header = (PWINDIVERT_ICMPV6HDR)data;
- if (ipv6_header == NULL ||
- data_len < sizeof(WINDIVERT_ICMPV6HDR))
- {
- icmpv6_header = NULL;
- goto WinDivertHelperParsePacketExit;
- }
- data = ((UINT8 *)data + sizeof(WINDIVERT_ICMPV6HDR));
- data_len -= sizeof(WINDIVERT_ICMPV6HDR);
- break;
- default:
- break;
- }
-
- if (data_len == 0)
- {
- data = NULL;
- }
-
-WinDivertHelperParsePacketExit:
- success = TRUE;
- if (ppIpHdr != NULL)
- {
- *ppIpHdr = ip_header;
- success = success && (ip_header != NULL);
- }
- if (ppIpv6Hdr != NULL)
- {
- *ppIpv6Hdr = ipv6_header;
- success = success && (ipv6_header != NULL);
- }
- if (ppIcmpHdr != NULL)
- {
- *ppIcmpHdr = icmp_header;
- success = success && (icmp_header != NULL);
- }
- if (ppIcmpv6Hdr != NULL)
- {
- *ppIcmpv6Hdr = icmpv6_header;
- success = success && (icmpv6_header != NULL);
- }
- if (ppTcpHdr != NULL)
- {
- *ppTcpHdr = tcp_header;
- success = success && (tcp_header != NULL);
- }
- if (ppUdpHdr != NULL)
- {
- *ppUdpHdr = udp_header;
- success = success && (udp_header != NULL);
- }
- if (pProto != NULL)
- {
- *pProto = trans_proto;
- }
- if (ppData != NULL)
- {
- *ppData = data;
- success = success && (data != NULL);
- }
- if (pDataLen != NULL)
- {
- *pDataLen = data_len;
- }
- return success;
-}
-
/*
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
*/
@@ -497,196 +273,8 @@ extern BOOL WinDivertHelperParsePacket(PVOID pPacket, UINT packetLen,
PWINDIVERT_TCPHDR *ppTcpHdr, PWINDIVERT_UDPHDR *ppUdpHdr, PVOID *ppData,
UINT *pDataLen)
{
- return WinDivertHelperParsePacket_2(pPacket, packetLen, ppIpHdr,
- ppIpv6Hdr, ppIcmpHdr, ppIcmpv6Hdr, ppTcpHdr, ppUdpHdr, NULL,
- ppData, pDataLen);
-}
-
-/*
- * Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums.
- */
-extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
- PWINDIVERT_ADDRESS pAddr, UINT64 flags)
-{
- UINT8 pseudo_header[
- MAX(sizeof(WINDIVERT_PSEUDOHDR), sizeof(WINDIVERT_PSEUDOV6HDR))];
- UINT16 pseudo_header_len;
- PWINDIVERT_IPHDR ip_header;
- PWINDIVERT_IPV6HDR ipv6_header;
- PWINDIVERT_ICMPHDR icmp_header;
- PWINDIVERT_ICMPV6HDR icmpv6_header;
- PWINDIVERT_TCPHDR tcp_header;
- PWINDIVERT_UDPHDR udp_header;
- UINT payload_len, checksum_len;
- UINT count = 0;
-
- WinDivertHelperParsePacket_2(pPacket, packetLen, &ip_header, &ipv6_header,
- &icmp_header, &icmpv6_header, &tcp_header, &udp_header, NULL, NULL,
- &payload_len);
-
- if (ip_header != NULL && !(flags & WINDIVERT_HELPER_NO_IP_CHECKSUM))
- {
- ip_header->Checksum = 0;
- if (pAddr == NULL || pAddr->PseudoIPChecksum == 0)
- {
- ip_header->Checksum = WinDivertHelperCalcChecksum(NULL, 0,
- ip_header, ip_header->HdrLength*sizeof(UINT32));
- }
- count++;
- }
-
- if (icmp_header != NULL)
- {
- if ((flags & WINDIVERT_HELPER_NO_ICMP_CHECKSUM) != 0)
- {
- return count;
- }
- icmp_header->Checksum = 0;
- icmp_header->Checksum = WinDivertHelperCalcChecksum(NULL, 0,
- icmp_header, payload_len + sizeof(WINDIVERT_ICMPHDR));
- count++;
- return count;
- }
-
- if (icmpv6_header != NULL)
- {
- if ((flags & WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM) != 0)
- {
- return count;
- }
- checksum_len = payload_len + sizeof(WINDIVERT_ICMPV6HDR);
- pseudo_header_len = WinDivertInitPseudoHeader(NULL, ipv6_header,
- IPPROTO_ICMPV6, checksum_len, pseudo_header);
- icmpv6_header->Checksum = 0;
- icmpv6_header->Checksum = WinDivertHelperCalcChecksum(pseudo_header,
- pseudo_header_len, icmpv6_header, checksum_len);
- count++;
- return count;
- }
-
- if (tcp_header != NULL)
- {
- if ((flags & WINDIVERT_HELPER_NO_TCP_CHECKSUM) != 0)
- {
- return count;
- }
- if (pAddr == NULL || pAddr->PseudoTCPChecksum == 0)
- {
- // Full TCP checksum
- checksum_len = payload_len + tcp_header->HdrLength*sizeof(UINT32);
- pseudo_header_len = WinDivertInitPseudoHeader(ip_header,
- ipv6_header, IPPROTO_TCP, checksum_len, pseudo_header);
- tcp_header->Checksum = 0;
- tcp_header->Checksum = WinDivertHelperCalcChecksum(
- pseudo_header, pseudo_header_len, tcp_header, checksum_len);
- }
- else if (pAddr->Outbound)
- {
- // Pseudo TCP checksum
- tcp_header->Checksum = 0;
- }
- count++;
- return count;
- }
-
- if (udp_header != NULL)
- {
- if ((flags & WINDIVERT_HELPER_NO_UDP_CHECKSUM) != 0)
- {
- return count;
- }
- if (pAddr == NULL || pAddr->PseudoUDPChecksum == 0)
- {
- // Full UDP checksum
- checksum_len = payload_len + sizeof(WINDIVERT_UDPHDR);
- pseudo_header_len = WinDivertInitPseudoHeader(ip_header,
- ipv6_header, IPPROTO_UDP, checksum_len, pseudo_header);
- udp_header->Checksum = 0;
- udp_header->Checksum = WinDivertHelperCalcChecksum(
- pseudo_header, pseudo_header_len, udp_header, checksum_len);
- if (udp_header->Checksum == 0)
- {
- udp_header->Checksum = 0xFFFF;
- }
- }
- else if (pAddr->Outbound)
- {
- // Pseudo UDP checksum
- udp_header->Checksum = 0;
- }
- count++;
- }
- return count;
-}
-
-/*
- * Initialize the IP/IPv6 pseudo header.
- */
-static UINT16 WinDivertInitPseudoHeader(PWINDIVERT_IPHDR ip_header,
- PWINDIVERT_IPV6HDR ipv6_header, UINT8 protocol, UINT len,
- void *pseudo_header)
-{
- if (ip_header != NULL)
- {
- PWINDIVERT_PSEUDOHDR pseudo_header_v4 =
- (PWINDIVERT_PSEUDOHDR)pseudo_header;
- pseudo_header_v4->SrcAddr = ip_header->SrcAddr;
- pseudo_header_v4->DstAddr = ip_header->DstAddr;
- pseudo_header_v4->Zero = 0;
- pseudo_header_v4->Protocol = protocol;
- pseudo_header_v4->Length = htons((UINT16)len);
- return sizeof(WINDIVERT_PSEUDOHDR);
- }
- else
- {
- PWINDIVERT_PSEUDOV6HDR pseudo_header_v6 =
- (PWINDIVERT_PSEUDOV6HDR)pseudo_header;
- memcpy(pseudo_header_v6->SrcAddr, ipv6_header->SrcAddr,
- sizeof(pseudo_header_v6->SrcAddr));
- memcpy(pseudo_header_v6->DstAddr, ipv6_header->DstAddr,
- sizeof(pseudo_header_v6->DstAddr));
- pseudo_header_v6->Length = htonl((UINT32)len);
- pseudo_header_v6->NextHdr = protocol;
- pseudo_header_v6->Zero = 0;
- return sizeof(WINDIVERT_PSEUDOV6HDR);
- }
-}
-
-/*
- * Generic checksum computation.
- */
-static UINT16 WinDivertHelperCalcChecksum(PVOID pseudo_header,
- UINT16 pseudo_header_len, PVOID data, UINT len)
-{
- register const UINT16 *data16 = (const UINT16 *)pseudo_header;
- register size_t len16 = pseudo_header_len >> 1;
- register UINT32 sum = 0;
- size_t i;
-
- // Pseudo header:
- for (i = 0; i < len16; i++)
- {
- sum += (UINT32)data16[i];
- }
-
- // Main data:
- data16 = (const UINT16 *)data;
- len16 = len >> 1;
- for (i = 0; i < len16; i++)
- {
- sum += (UINT32)data16[i];
- }
-
- if (len & 0x1)
- {
- const UINT8 *data8 = (const UINT8 *)data;
- sum += (UINT16)data8[len-1];
- }
-
- sum = (sum & 0xFFFF) + (sum >> 16);
- sum += (sum >> 16);
- sum = ~sum;
- return (UINT16)sum;
+ return WinDivertParsePacket(pPacket, packetLen, ppIpHdr, ppIpv6Hdr,
+ ppIcmpHdr, ppIcmpv6Hdr, ppTcpHdr, ppUdpHdr, NULL, ppData, pDataLen);
}
/*
@@ -2563,7 +2151,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- WinDivertHelperParsePacket_2(packet, packet_len, &iphdr, &ipv6hdr,
+ WinDivertParsePacket(packet, packet_len, &iphdr, &ipv6hdr,
&icmphdr, &icmpv6hdr, &tcphdr, &udphdr, &protocol, NULL,
&payload_len);
if ((addr->IPv6 && ipv6hdr == NULL) ||
diff --git a/include/windivert.h b/include/windivert.h
index dfe341d..2c8249f 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -413,8 +413,6 @@ typedef struct
UINT16 Checksum;
} WINDIVERT_UDPHDR, *PWINDIVERT_UDPHDR;
-#ifndef WINDIVERT_KERNEL
-
/*
* Flags for WinDivertHelperCalcChecksums()
*/
@@ -424,6 +422,8 @@ typedef struct
#define WINDIVERT_HELPER_NO_TCP_CHECKSUM 8
#define WINDIVERT_HELPER_NO_UDP_CHECKSUM 16
+#ifndef WINDIVERT_KERNEL
+
/*
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
*/
diff --git a/sys/windivert.c b/sys/windivert.c
index 47dacac..2706043 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -663,7 +663,7 @@ static struct layer_s layer_resource_assignment_ipv4_0 =
0
};
static layer_t layer_resource_assignment_ipv4 =
- &layer_resource_assignment_ipv4_0;
+ &layer_resource_assignment_ipv4_0;
static struct layer_s layer_resource_assignment_ipv6_0 =
{
@@ -680,7 +680,7 @@ static struct layer_s layer_resource_assignment_ipv6_0 =
0
};
static layer_t layer_resource_assignment_ipv6 =
- &layer_resource_assignment_ipv6_0;
+ &layer_resource_assignment_ipv6_0;
static struct layer_s layer_auth_connect_ipv4_0 =
{
@@ -810,6 +810,11 @@ static struct layer_s layer_flow_established_ipv6_0 =
};
static layer_t layer_flow_established_ipv6 = &layer_flow_established_ipv6_0;
+/*
+ * Shared functions.
+ */
+#include "windivert_shared.c"
+
/*
* WinDivert malloc/free.
*/
@@ -887,18 +892,18 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj,
FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
layer_flow_established_ipv6->layer_guid =
FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6;
- layer_resource_assignment_ipv4->layer_guid =
+ layer_resource_assignment_ipv4->layer_guid =
FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4;
- layer_resource_assignment_ipv6->layer_guid =
+ layer_resource_assignment_ipv6->layer_guid =
FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6;
layer_auth_connect_ipv4->layer_guid = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
layer_auth_connect_ipv6->layer_guid = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
layer_auth_listen_ipv4->layer_guid = FWPM_LAYER_ALE_AUTH_LISTEN_V4;
layer_auth_listen_ipv6->layer_guid = FWPM_LAYER_ALE_AUTH_LISTEN_V6;
layer_auth_recv_accept_ipv4->layer_guid =
- FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
+ FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
layer_auth_recv_accept_ipv6->layer_guid =
- FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6;
+ FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6;
layer_inbound_network_ipv4->sublayer_guid =
WINDIVERT_SUBLAYER_INBOUND_IPV4_GUID;
layer_outbound_network_ipv4->sublayer_guid =
@@ -2119,7 +2124,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
BOOL ipv4;
UINT8 layer;
UINT32 priority;
- UINT64 flags;
+ UINT64 flags, checksums;
HANDLE handle, compl_handle;
PNET_BUFFER_LIST buffers = NULL;
NTSTATUS status = STATUS_SUCCESS;
@@ -2183,6 +2188,7 @@ windivert_write_bad_packet:
goto windivert_write_exit;
}
+ // Copy packet data:
data_copy = windivert_malloc(data_len, FALSE);
if (data_copy == NULL)
{
@@ -2191,7 +2197,6 @@ windivert_write_bad_packet:
status);
goto windivert_write_exit;
}
-
RtlCopyMemory(data_copy, data, sizeof(WINDIVERT_IPHDR));
ip_header = (PWINDIVERT_IPHDR)data_copy;
switch (ip_header->Version)
@@ -2225,6 +2230,19 @@ windivert_write_bad_packet:
(char *)data + sizeof(WINDIVERT_IPHDR),
data_len - sizeof(WINDIVERT_IPHDR));
}
+
+ // Fix checksums:
+ if (addr->PseudoIPChecksum != 0 || addr->PseudoTCPChecksum != 0 ||
+ addr->PseudoUDPChecksum != 0)
+ {
+ checksums =
+ (addr->PseudoIPChecksum? 0: WINDIVERT_HELPER_NO_IP_CHECKSUM) |
+ (addr->PseudoTCPChecksum? 0: WINDIVERT_HELPER_NO_TCP_CHECKSUM) |
+ (addr->PseudoUDPChecksum? 0: WINDIVERT_HELPER_NO_UDP_CHECKSUM);
+ WinDivertHelperCalcChecksums(data_copy, data_len, NULL, checksums);
+ }
+
+ // Decrement TTL for impostor packets:
if (addr->Impostor && !windivert_decrement_ttl(data_copy, ipv4,
(addr->PseudoIPChecksum == 0)))
{
@@ -2232,6 +2250,7 @@ windivert_write_bad_packet:
goto windivert_write_exit;
}
+ // Allocate packet:
mdl_copy = IoAllocateMdl(data_copy, data_len, FALSE, FALSE, NULL);
if (mdl_copy == NULL)
{
@@ -2239,7 +2258,6 @@ windivert_write_bad_packet:
DEBUG_ERROR("failed to allocate MDL for injected packet", status);
goto windivert_write_exit;
}
-
MmBuildMdlForNonPagedPool(mdl_copy);
status = FwpsAllocateNetBufferAndNetBufferList0(nbl_pool_handle, 0, 0,
mdl_copy, 0, data_len, &buffers);
@@ -2250,6 +2268,7 @@ windivert_write_bad_packet:
goto windivert_write_exit;
}
+ // Inject packet:
handle = (ipv4? inject_handle: injectv6_handle);
compl_handle = ((flags & WINDIVERT_FLAG_DEBUG) != 0? (HANDLE)request: NULL);
if (layer == WINDIVERT_LAYER_NETWORK_FORWARD)
@@ -3521,7 +3540,7 @@ static void windivert_resource_assignment_v4_classify(
socket_data.RemoteAddr[2] = 0;
socket_data.RemoteAddr[3] = 0;
value = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_PORT].value;
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_PORT].value;
socket_data.LocalPort = (value.type == FWP_UINT16? value.uint16: 0);
socket_data.RemotePort = 0;
socket_data.Protocol = fixed_vals->incomingValue[
@@ -3575,7 +3594,7 @@ static void windivert_resource_assignment_v6_classify(
socket_data.RemoteAddr[2] = 0;
socket_data.RemoteAddr[3] = 0;
value = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_LOCAL_PORT].value;
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_LOCAL_PORT].value;
socket_data.LocalPort = (value.type == FWP_UINT16? value.uint16: 0);
socket_data.RemotePort = 0;
socket_data.Protocol = fixed_vals->incomingValue[
@@ -3697,7 +3716,7 @@ static void windivert_auth_listen_v4_classify(
socket_data.RemoteAddr[2] = 0;
socket_data.RemoteAddr[3] = 0;
socket_data.LocalPort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_LISTEN_V4_IP_LOCAL_PORT].value.uint16;
+ FWPS_FIELD_ALE_AUTH_LISTEN_V4_IP_LOCAL_PORT].value.uint16;
socket_data.RemotePort = 0;
socket_data.Protocol = IPPROTO_TCP;
@@ -3737,7 +3756,7 @@ static void windivert_auth_listen_v6_classify(
socket_data.RemoteAddr[2] = 0;
socket_data.RemoteAddr[3] = 0;
socket_data.LocalPort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_LISTEN_V6_IP_LOCAL_PORT].value.uint16;
+ FWPS_FIELD_ALE_AUTH_LISTEN_V6_IP_LOCAL_PORT].value.uint16;
socket_data.RemotePort = 0;
socket_data.Protocol = IPPROTO_TCP;
@@ -5456,8 +5475,6 @@ windivert_filter_compile_error:
/* WINDIVERT REFLECT MANAGER IMPLEMENTATION */
/****************************************************************************/
-#include "windivert_shared.c"
-
/*
* WinDivert reflect state.
*/
From 316765aa929df04d3bec7d554be079d7b1ebf9a6 Mon Sep 17 00:00:00 2001
From: basil00
Date: Sat, 27 Oct 2018 06:52:14 +0800
Subject: [PATCH 08/23] Fix impostor packet checksums.
---
sys/windivert.c | 25 +++++++++++--------------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/sys/windivert.c b/sys/windivert.c
index 2706043..2315f22 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -475,7 +475,7 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
static void windivert_queue_packet(context_t context, packet_t packet);
static void windivert_reinject_packet(packet_t packet);
static void windivert_free_packet(packet_t packet);
-static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4, BOOL checksum);
+static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4);
static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b);
static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
PWINDIVERT_IPHDR *ip_header_ptr, PWINDIVERT_IPV6HDR *ipv6_header_ptr,
@@ -2243,8 +2243,7 @@ windivert_write_bad_packet:
}
// Decrement TTL for impostor packets:
- if (addr->Impostor && !windivert_decrement_ttl(data_copy, ipv4,
- (addr->PseudoIPChecksum == 0)))
+ if (addr->Impostor && !windivert_decrement_ttl(data_copy, ipv4))
{
status = STATUS_HOPLIMIT_EXCEEDED;
goto windivert_write_exit;
@@ -4286,7 +4285,7 @@ static void windivert_free_packet(packet_t packet)
/*
* Decrement the TTL of a packet.
*/
-static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4, BOOL checksum)
+static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4)
{
PWINDIVERT_IPHDR ip_header;
PWINDIVERT_IPV6HDR ipv6_header;
@@ -4299,17 +4298,15 @@ static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4, BOOL checksum)
return FALSE;
}
ip_header->TTL--;
- if (checksum)
+
+ // Incremental checksum update:
+ if (ip_header->Checksum >= 0xFFFE)
{
- // Incremental checksum update:
- if (ip_header->Checksum >= 0xFFFE)
- {
- ip_header->Checksum -= 0xFFFE;
- }
- else
- {
- ip_header->Checksum += 1;
- }
+ ip_header->Checksum -= 0xFFFE;
+ }
+ else
+ {
+ ip_header->Checksum += 1;
}
}
else
From de4245f95e30bb36f20e3197ddf52b09b125735a Mon Sep 17 00:00:00 2001
From: basil00
Date: Mon, 29 Oct 2018 05:40:03 +0800
Subject: [PATCH 09/23] Event & REFLECT layer fixes.
- Make event bitwise-OR-able.
- Simplify event names.
- Fix REFLECT serialization.
(setting AutomaticSerialization=TRUE does not
work.)
- Preallocate REFLECT memory.
---
dll/windivert_helper.c | 238 ++++++++++++++++-----------
examples/windivertctl/windivertctl.c | 4 +
include/windivert.h | 50 +++---
include/windivert_device.h | 3 +-
sys/windivert.c | 214 ++++++++++++++----------
test/test.c | 3 +-
6 files changed, 300 insertions(+), 212 deletions(-)
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index 0ffc158..5c3b224 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -130,16 +130,15 @@ typedef enum
TOKEN_NETWORK,
TOKEN_NETWORK_FORWARD,
TOKEN_REFLECT,
- TOKEN_NETWORK_PACKET,
- TOKEN_FLOW_ESTABLISHED,
- TOKEN_FLOW_DELETED,
- TOKEN_SOCKET_BIND,
- TOKEN_SOCKET_CONNECT,
- TOKEN_SOCKET_LISTEN,
- TOKEN_SOCKET_ACCEPT,
- TOKEN_REFLECT_ESTABLISHED,
- TOKEN_REFLECT_OPEN,
- TOKEN_REFLECT_CLOSE,
+ TOKEN_EVENT_PACKET,
+ TOKEN_EVENT_ESTABLISHED,
+ TOKEN_EVENT_DELETED,
+ TOKEN_EVENT_BIND,
+ TOKEN_EVENT_CONNECT,
+ TOKEN_EVENT_LISTEN,
+ TOKEN_EVENT_ACCEPT,
+ TOKEN_EVENT_OPEN,
+ TOKEN_EVENT_CLOSE,
TOKEN_OPEN,
TOKEN_CLOSE,
TOKEN_EQ,
@@ -193,6 +192,8 @@ typedef struct
WINDIVERT_LAYER_FLAG_SOCKET)
#define LN_F__ (WINDIVERT_LAYER_FLAG_NETWORK | \
WINDIVERT_LAYER_FLAG_FLOW)
+#define L__F_R (WINDIVERT_LAYER_FLAG_FLOW | \
+ WINDIVERT_LAYER_FLAG_REFLECT)
#define LN_FS_ (WINDIVERT_LAYER_FLAG_NETWORK | \
WINDIVERT_LAYER_FLAG_FLOW | \
WINDIVERT_LAYER_FLAG_SOCKET)
@@ -262,7 +263,7 @@ static BOOL WinDivertCondExecFilter(PWINDIVERT_FILTER filter, UINT length,
static BOOL WinDivertDeserializeFilter(PWINDIVERT_STREAM stream,
PWINDIVERT_FILTER filter, UINT *length);
static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
- BOOL top_level, BOOL and);
+ WINDIVERT_LAYER layer, BOOL top_level, BOOL and);
/*
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
@@ -475,7 +476,8 @@ static PTOKEN_INFO WinDivertTokenLookup(PTOKEN_INFO token_info,
/*
* Expand a "macro" value.
*/
-static BOOL WinDivertExpandMacro(KIND kind, UINT32 *val)
+static BOOL WinDivertExpandMacro(KIND kind, WINDIVERT_LAYER layer,
+ UINT32 *val)
{
switch (kind)
{
@@ -494,36 +496,42 @@ static BOOL WinDivertExpandMacro(KIND kind, UINT32 *val)
case TOKEN_REFLECT:
*val = WINDIVERT_LAYER_REFLECT;
return TRUE;
- case TOKEN_NETWORK_PACKET:
+ case TOKEN_EVENT_PACKET:
*val = WINDIVERT_EVENT_NETWORK_PACKET;
- return TRUE;
- case TOKEN_FLOW_ESTABLISHED:
- *val = WINDIVERT_EVENT_FLOW_ESTABLISHED;
- return TRUE;
- case TOKEN_FLOW_DELETED:
+ return (layer == WINDIVERT_LAYER_NETWORK);
+ case TOKEN_EVENT_ESTABLISHED:
+ if (layer == WINDIVERT_LAYER_FLOW)
+ {
+ *val = WINDIVERT_EVENT_FLOW_ESTABLISHED;
+ return TRUE;
+ }
+ else if (layer == WINDIVERT_LAYER_REFLECT)
+ {
+ *val = WINDIVERT_EVENT_REFLECT_ESTABLISHED;
+ return TRUE;
+ }
+ return FALSE;
+ case TOKEN_EVENT_DELETED:
*val = WINDIVERT_EVENT_FLOW_DELETED;
- return TRUE;
- case TOKEN_SOCKET_BIND:
+ return (layer == WINDIVERT_LAYER_FLOW);
+ case TOKEN_EVENT_BIND:
*val = WINDIVERT_EVENT_SOCKET_BIND;
- return TRUE;
- case TOKEN_SOCKET_CONNECT:
+ return (layer == WINDIVERT_LAYER_FLOW);
+ case TOKEN_EVENT_CONNECT:
*val = WINDIVERT_EVENT_SOCKET_CONNECT;
- return TRUE;
- case TOKEN_SOCKET_LISTEN:
+ return (layer == WINDIVERT_LAYER_SOCKET);
+ case TOKEN_EVENT_LISTEN:
*val = WINDIVERT_EVENT_SOCKET_LISTEN;
- return TRUE;
- case TOKEN_SOCKET_ACCEPT:
+ return (layer == WINDIVERT_LAYER_SOCKET);
+ case TOKEN_EVENT_ACCEPT:
*val = WINDIVERT_EVENT_SOCKET_ACCEPT;
- return TRUE;
- case TOKEN_REFLECT_ESTABLISHED:
- *val = WINDIVERT_EVENT_REFLECT_ESTABLISHED;
- return TRUE;
- case TOKEN_REFLECT_OPEN:
+ return (layer == WINDIVERT_LAYER_SOCKET);
+ case TOKEN_EVENT_OPEN:
*val = WINDIVERT_EVENT_REFLECT_OPEN;
- return TRUE;
- case TOKEN_REFLECT_CLOSE:
+ return (layer == WINDIVERT_LAYER_REFLECT);
+ case TOKEN_EVENT_CLOSE:
*val = WINDIVERT_EVENT_REFLECT_CLOSE;
- return TRUE;
+ return (layer == WINDIVERT_LAYER_REFLECT);
default:
return FALSE;
}
@@ -537,21 +545,20 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{
static const TOKEN_INFO token_info[] =
{
+ {"ACCEPT", TOKEN_EVENT_ACCEPT, L___S_},
+ {"BIND", TOKEN_EVENT_BIND, L___S_},
+ {"CLOSE", TOKEN_EVENT_CLOSE, L____R},
+ {"CONNECT", TOKEN_EVENT_CONNECT, L___S_},
+ {"DELETED", TOKEN_EVENT_DELETED, L__F__},
+ {"ESTABLISHED", TOKEN_EVENT_ESTABLISHED, L__F_R},
{"FLOW", TOKEN_FLOW, L____R},
- {"FLOW_DELETED", TOKEN_FLOW_DELETED, L__F__},
- {"FLOW_ESTABLISHED", TOKEN_FLOW_ESTABLISHED, L__F__},
+ {"LISTEN", TOKEN_EVENT_LISTEN, L___S_},
{"NETWORK", TOKEN_NETWORK, L____R},
{"NETWORK_FORWARD", TOKEN_NETWORK_FORWARD, L____R},
- {"NETWORK_PACKET", TOKEN_NETWORK_PACKET, LNM___},
+ {"OPEN", TOKEN_EVENT_OPEN, L____R},
+ {"PACKET", TOKEN_EVENT_PACKET, LNM___},
{"REFLECT", TOKEN_REFLECT, L____R},
- {"REFLECT_CLOSE", TOKEN_REFLECT_CLOSE, L____R},
- {"REFLECT_ESTABLISHED", TOKEN_REFLECT_ESTABLISHED, L____R},
- {"REFLECT_OPEN", TOKEN_REFLECT_OPEN, L____R},
{"SOCKET", TOKEN_SOCKET, L____R},
- {"SOCKET_ACCEPT", TOKEN_SOCKET_ACCEPT, L___S_},
- {"SOCKET_BIND", TOKEN_SOCKET_BIND, L___S_},
- {"SOCKET_CONNECT", TOKEN_SOCKET_CONNECT, L___S_},
- {"SOCKET_LISTEN", TOKEN_SOCKET_LISTEN, L___S_},
{"and", TOKEN_AND, LNMFSR},
{"event", TOKEN_EVENT, LNMFSR},
{"false", TOKEN_FALSE, LNMFSR},
@@ -759,7 +766,8 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{
return MAKE_ERROR(WINDIVERT_ERROR_BAD_TOKEN_FOR_LAYER, i-j);
}
- if (WinDivertExpandMacro(result->kind, &tokens[tp].val[0]))
+ if (WinDivertExpandMacro(result->kind, layer,
+ &tokens[tp].val[0]))
{
tokens[tp].kind = TOKEN_NUMBER;
}
@@ -3545,10 +3553,12 @@ extern BOOL WinDivertHelperFormatIPv6Address(const UINT32 *addr, char *buffer,
/*
* Format a test expression.
*/
-static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr)
+static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
+ WINDIVERT_LAYER layer)
{
PEXPR field = expr->arg[0], val = expr->arg[1];
- BOOL ipv4_addr = FALSE, ipv6_addr = FALSE, layer = FALSE, event = FALSE;
+ BOOL is_ipv4_addr = FALSE, is_ipv6_addr = FALSE, is_layer = FALSE,
+ is_event = FALSE;
switch (field->kind)
{
@@ -3580,13 +3590,13 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr)
{
case TOKEN_EQ:
WinDivertPutString(stream, (val->val[0] == 0? "not ": ""));
- WinDivertFormatExpr(stream, field, /*top_level=*/FALSE,
- /*and=*/FALSE);
+ WinDivertFormatExpr(stream, field, layer,
+ /*top_level=*/FALSE, /*and=*/FALSE);
return;
case TOKEN_NEQ:
WinDivertPutString(stream, (val->val[0] != 0? "not ": ""));
- WinDivertFormatExpr(stream, field, /*top_level=*/FALSE,
- /*and=*/FALSE);
+ WinDivertFormatExpr(stream, field, layer,
+ /*top_level=*/FALSE, /*and=*/FALSE);
return;
default:
break;
@@ -3594,25 +3604,26 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr)
break;
case TOKEN_IP_SRC_ADDR:
case TOKEN_IP_DST_ADDR:
- ipv4_addr = TRUE;
+ is_ipv4_addr = TRUE;
break;
case TOKEN_IPV6_SRC_ADDR:
case TOKEN_IPV6_DST_ADDR:
case TOKEN_LOCAL_ADDR:
case TOKEN_REMOTE_ADDR:
- ipv6_addr = TRUE;
+ is_ipv6_addr = TRUE;
break;
case TOKEN_LAYER:
- layer = TRUE;
+ is_layer = TRUE;
break;
case TOKEN_EVENT:
- event = TRUE;
+ is_event = TRUE;
break;
default:
break;
}
- WinDivertFormatExpr(stream, field, /*top_level=*/FALSE, /*and=*/FALSE);
+ WinDivertFormatExpr(stream, field, layer, /*top_level=*/FALSE,
+ /*and=*/FALSE);
switch (expr->kind)
{
case TOKEN_EQ:
@@ -3628,15 +3639,15 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr)
case TOKEN_GEQ:
WinDivertPutString(stream, " >= "); break;
}
- if (ipv4_addr)
+ if (is_ipv4_addr)
{
WinDivertFormatIPv4Addr(stream, val->val[0]);
}
- else if (ipv6_addr)
+ else if (is_ipv6_addr)
{
WinDivertFormatIPv6Addr(stream, val->val);
}
- else if (layer)
+ else if (is_layer)
{
switch (val->val[0])
{
@@ -3654,30 +3665,60 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr)
WinDivertFormatNumber(stream, val->val[0]); break;
}
}
- else if (event)
+ else if (is_event)
{
- switch (val->val[0])
+ switch (layer)
{
- case WINDIVERT_EVENT_NETWORK_PACKET:
- WinDivertPutString(stream, "NETWORK_PACKET"); break;
- case WINDIVERT_EVENT_FLOW_ESTABLISHED:
- WinDivertPutString(stream, "FLOW_ESTABLISHED"); break;
- case WINDIVERT_EVENT_FLOW_DELETED:
- WinDivertPutString(stream, "FLOW_DELETED"); break;
- case WINDIVERT_EVENT_SOCKET_BIND:
- WinDivertPutString(stream, "SOCKET_BIND"); break;
- case WINDIVERT_EVENT_SOCKET_CONNECT:
- WinDivertPutString(stream, "SOCKET_CONNECT"); break;
- case WINDIVERT_EVENT_SOCKET_LISTEN:
- WinDivertPutString(stream, "SOCKET_LISTEN"); break;
- case WINDIVERT_EVENT_SOCKET_ACCEPT:
- WinDivertPutString(stream, "SOCKET_ACCEPT"); break;
- case WINDIVERT_EVENT_REFLECT_ESTABLISHED:
- WinDivertPutString(stream, "REFLECT_ESTABLISHED"); break;
- case WINDIVERT_EVENT_REFLECT_OPEN:
- WinDivertPutString(stream, "REFLECT_OPEN"); break;
- case WINDIVERT_EVENT_REFLECT_CLOSE:
- WinDivertPutString(stream, "REFLECT_CLOSE"); break;
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ if (val->val[0] == WINDIVERT_EVENT_NETWORK_PACKET)
+ {
+ WinDivertPutString(stream, "PACKET");
+ }
+ else
+ {
+ WinDivertFormatNumber(stream, val->val[0]);
+ }
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ switch (val->val[0])
+ {
+ case WINDIVERT_EVENT_FLOW_ESTABLISHED:
+ WinDivertPutString(stream, "ESTABLISHED"); break;
+ case WINDIVERT_EVENT_FLOW_DELETED:
+ WinDivertPutString(stream, "DELETED"); break;
+ default:
+ WinDivertFormatNumber(stream, val->val[0]); break;
+ }
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ switch (val->val[0])
+ {
+ case WINDIVERT_EVENT_SOCKET_BIND:
+ WinDivertPutString(stream, "BIND"); break;
+ case WINDIVERT_EVENT_SOCKET_CONNECT:
+ WinDivertPutString(stream, "CONNECT"); break;
+ case WINDIVERT_EVENT_SOCKET_LISTEN:
+ WinDivertPutString(stream, "LISTEN"); break;
+ case WINDIVERT_EVENT_SOCKET_ACCEPT:
+ WinDivertPutString(stream, "ACCEPT"); break;
+ default:
+ WinDivertFormatNumber(stream, val->val[0]); break;
+ }
+ break;
+ case WINDIVERT_LAYER_REFLECT:
+ switch (val->val[0])
+ {
+ case WINDIVERT_EVENT_REFLECT_ESTABLISHED:
+ WinDivertPutString(stream, "ESTABLISHED"); break;
+ case WINDIVERT_EVENT_REFLECT_OPEN:
+ WinDivertPutString(stream, "OPEN"); break;
+ case WINDIVERT_EVENT_REFLECT_CLOSE:
+ WinDivertPutString(stream, "CLOSE"); break;
+ default:
+ WinDivertFormatNumber(stream, val->val[0]); break;
+ }
+ break;
default:
WinDivertFormatNumber(stream, val->val[0]); break;
}
@@ -3692,7 +3733,7 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr)
* Format an expression.
*/
static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
- BOOL top_level, BOOL and)
+ WINDIVERT_LAYER layer, BOOL top_level, BOOL and)
{
if (stream->pos >= stream->max)
{
@@ -3706,11 +3747,11 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
{
WinDivertPutChar(stream, '(');
}
- WinDivertFormatExpr(stream, expr->arg[0], /*top_level=*/FALSE,
- /*and=*/TRUE);
+ WinDivertFormatExpr(stream, expr->arg[0], layer,
+ /*top_level=*/FALSE, /*and=*/TRUE);
WinDivertPutString(stream, " and ");
- WinDivertFormatExpr(stream, expr->arg[1], /*top_level=*/FALSE,
- /*and=*/TRUE);
+ WinDivertFormatExpr(stream, expr->arg[1], layer,
+ /*top_level=*/FALSE, /*and=*/TRUE);
if (!top_level && !and)
{
WinDivertPutChar(stream, ')');
@@ -3721,11 +3762,11 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
{
WinDivertPutChar(stream, '(');
}
- WinDivertFormatExpr(stream, expr->arg[0], /*top_level=*/FALSE,
- /*and=*/FALSE);
+ WinDivertFormatExpr(stream, expr->arg[0], layer,
+ /*top_level=*/FALSE, /*and=*/FALSE);
WinDivertPutString(stream, " or ");
- WinDivertFormatExpr(stream, expr->arg[1], /*top_level=*/FALSE,
- /*and=*/FALSE);
+ WinDivertFormatExpr(stream, expr->arg[1], layer,
+ /*top_level=*/FALSE, /*and=*/FALSE);
if (!top_level && and)
{
WinDivertPutChar(stream, ')');
@@ -3733,14 +3774,14 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
return;
case TOKEN_QUESTION:
WinDivertPutChar(stream, '(');
- WinDivertFormatExpr(stream, expr->arg[0], /*top_level=*/TRUE,
- /*and=*/FALSE);
+ WinDivertFormatExpr(stream, expr->arg[0], layer,
+ /*top_level=*/TRUE, /*and=*/FALSE);
WinDivertPutString(stream, "? ");
- WinDivertFormatExpr(stream, expr->arg[1], /*top_level=*/TRUE,
- /*and=*/FALSE);
+ WinDivertFormatExpr(stream, expr->arg[1], layer,
+ /*top_level=*/TRUE, /*and=*/FALSE);
WinDivertPutString(stream, ": ");
- WinDivertFormatExpr(stream, expr->arg[2], /*top_level=*/TRUE,
- /*and=*/FALSE);
+ WinDivertFormatExpr(stream, expr->arg[2], layer,
+ /*top_level=*/TRUE, /*and=*/FALSE);
WinDivertPutChar(stream, ')');
return;
case TOKEN_TRUE:
@@ -3755,7 +3796,7 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
case TOKEN_LEQ:
case TOKEN_GT:
case TOKEN_GEQ:
- WinDivertFormatTestExpr(stream, expr);
+ WinDivertFormatTestExpr(stream, expr, layer);
return;
case TOKEN_ZERO:
WinDivertPutString(stream, "zero"); return;
@@ -3990,7 +4031,8 @@ BOOL WinDivertHelperFormatFilter(const char *filter, WINDIVERT_LAYER layer,
stream.pos = 0;
stream.max = buflen;
stream.overflow = FALSE;
- WinDivertFormatExpr(&stream, expr, /*top_level=*/TRUE, /*and=*/FALSE);
+ WinDivertFormatExpr(&stream, expr, layer, /*top_level=*/TRUE,
+ /*and=*/FALSE);
WinDivertPutNul(&stream);
// Clean-up:
diff --git a/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c
index 5e503dd..88e004d 100644
--- a/examples/windivertctl/windivertctl.c
+++ b/examples/windivertctl/windivertctl.c
@@ -278,6 +278,10 @@ usage:
SetConsoleTextAttribute(console, FOREGROUND_RED);
fputs("CLOSE", stdout);
break;
+
+ default:
+ fputs("???", stdout);
+ break;
}
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
diff --git a/include/windivert.h b/include/windivert.h
index 2c8249f..8b1afc4 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -134,17 +134,17 @@ typedef struct
typedef struct
{
INT64 Timestamp; /* Packet's timestamp. */
- UINT32 Layer:8; /* Packet's layer. */
- UINT32 Event:8; /* Packet event. */
- UINT32 Outbound:1; /* Packet is outound? */
- UINT32 Loopback:1; /* Packet is loopback? */
- UINT32 Impostor:1; /* Packet is impostor? */
- UINT32 IPv6:1; /* Packet is IPv6? */
- UINT32 PseudoIPChecksum:1; /* Packet has pseudo IPv4 checksum? */
- UINT32 PseudoTCPChecksum:1; /* Packet has pseudo TCP checksum? */
- UINT32 PseudoUDPChecksum:1; /* Packet has pseudo UDP checksum? */
- UINT32 Final:1; /* Packet is final event? */
- UINT32 Reserved:8;
+ UINT64 Layer:8; /* Packet's layer. */
+ UINT64 Event:24; /* Packet event. */
+ UINT64 Outbound:1; /* Packet is outound? */
+ UINT64 Loopback:1; /* Packet is loopback? */
+ UINT64 Impostor:1; /* Packet is impostor? */
+ UINT64 IPv6:1; /* Packet is IPv6? */
+ UINT64 PseudoIPChecksum:1; /* Packet has pseudo IPv4 checksum? */
+ UINT64 PseudoTCPChecksum:1; /* Packet has pseudo TCP checksum? */
+ UINT64 PseudoUDPChecksum:1; /* Packet has pseudo UDP checksum? */
+ UINT64 Final:1; /* Packet is final event? */
+ UINT64 Reserved:24;
union
{
WINDIVERT_DATA_NETWORK Network; /* Network layer data. */
@@ -159,18 +159,26 @@ typedef struct
*/
typedef enum
{
- WINDIVERT_EVENT_NETWORK_PACKET = 0, /* Network packet. */
- WINDIVERT_EVENT_FLOW_ESTABLISHED = 1,
+ WINDIVERT_EVENT_NETWORK_PACKET = 0x0001,
+ /* Network packet. */
+ WINDIVERT_EVENT_FLOW_ESTABLISHED = 0x0002,
/* Flow established. */
- WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */
- WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */
- WINDIVERT_EVENT_SOCKET_CONNECT = 4, /* Socket connect. */
- WINDIVERT_EVENT_SOCKET_LISTEN = 5, /* Socket listen. */
- WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */
- WINDIVERT_EVENT_REFLECT_ESTABLISHED = 7,
+ WINDIVERT_EVENT_FLOW_DELETED = 0x0004,
+ /* Flow deleted. */
+ WINDIVERT_EVENT_SOCKET_BIND = 0x0008,
+ /* Socket bind. */
+ WINDIVERT_EVENT_SOCKET_LISTEN = 0x0010,
+ /* Socket listen. */
+ WINDIVERT_EVENT_SOCKET_CONNECT = 0x0020,
+ /* Socket connect. */
+ WINDIVERT_EVENT_SOCKET_ACCEPT = 0x0040,
+ /* Socket accept. */
+ WINDIVERT_EVENT_REFLECT_ESTABLISHED = 0x0080,
/* Previously open WinDivert handle. */
- WINDIVERT_EVENT_REFLECT_OPEN = 8, /* Open new WinDivert handle. */
- WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* Close existing WinDivert handle. */
+ WINDIVERT_EVENT_REFLECT_OPEN = 0x0100,
+ /* Open new WinDivert handle. */
+ WINDIVERT_EVENT_REFLECT_CLOSE = 0x0200,
+ /* Close existing WinDivert handle. */
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
/*
diff --git a/include/windivert_device.h b/include/windivert_device.h
index 9ff6c7d..f945db2 100644
--- a/include/windivert_device.h
+++ b/include/windivert_device.h
@@ -155,8 +155,7 @@
/*
* WinDivert events.
*/
-#define WINDIVERT_EVENT_MAX \
- WINDIVERT_EVENT_REFLECT_CLOSE
+#define WINDIVERT_EVENT_MAX 0x8000
/*
* WinDivert flags.
diff --git a/sys/windivert.c b/sys/windivert.c
index 2315f22..a5d9b2a 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -98,6 +98,18 @@ static void DEBUG_ERROR(PCCH format, NTSTATUS status, ...)
#define WINDIVERT_TAG 'viDW'
+/*
+ * WinDivert reflect event.
+ */
+typedef struct context_s *context_t;
+struct reflect_event_s
+{
+ LIST_ENTRY entry; // Entry.
+ context_t context; // Context.
+ WINDIVERT_EVENT event; // Event.
+};
+typedef struct reflect_event_s *reflect_event_t;
+
/*
* WinDivert reflect context information.
*/
@@ -106,8 +118,9 @@ struct reflect_context_s
LIST_ENTRY entry; // Open handle entry.
LONGLONG timestamp; // Open timestamp.
WINDIVERT_DATA_REFLECT data; // Reflect data.
- BOOL inserted; // Entry inserted?
- BOOL open; // Seen OPEN event?
+ struct reflect_event_s open_event; // Open event.
+ struct reflect_event_s close_event; // Close event
+ BOOL open; // Seen open event?
};
/*
@@ -161,7 +174,6 @@ struct context_s
struct reflect_context_s reflect; // Reflection info.
};
typedef struct context_s context_s;
-typedef struct context_s *context_t;
WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(context_s, windivert_context_get);
#define WINDIVERT_TIMEOUT(context, t0, t1) \
@@ -229,17 +241,17 @@ struct packet_s
{
LIST_ENTRY entry; // Entry for queue.
LONGLONG timestamp; // Packet timestamp.
- UINT32 layer:8; // Layer.
- UINT32 event:8; // Event.
- UINT32 outbound:1; // Packet is outound?
- UINT32 loopback:1; // Packet is loopback?
- UINT32 impostor:1; // Packet is impostor?
- UINT32 ipv6:1; // Packet is IPv6?
- UINT32 pseudo_ip_checksum:1; // Packet has pseudo IPv4 check?
- UINT32 pseudo_tcp_checksum:1; // Packet has pseudo TCP check?
- UINT32 pseudo_udp_checksum:1; // Packet has pseudo UDP check?
- UINT32 final:1; // Packet is final event?
- UINT32 match:1; // Packet matches filter?
+ UINT64 layer:8; // Layer.
+ UINT64 event:24; // Event.
+ UINT64 outbound:1; // Packet is outound?
+ UINT64 loopback:1; // Packet is loopback?
+ UINT64 impostor:1; // Packet is impostor?
+ UINT64 ipv6:1; // Packet is IPv6?
+ UINT64 pseudo_ip_checksum:1; // Packet has pseudo IPv4 check?
+ UINT64 pseudo_tcp_checksum:1; // Packet has pseudo TCP check?
+ UINT64 pseudo_udp_checksum:1; // Packet has pseudo UDP check?
+ UINT64 final:1; // Packet is final event?
+ UINT64 match:1; // Packet matches filter?
UINT32 priority; // Packet priority.
UINT32 packet_len; // Length of the packet.
WINDIVERT_DATA_ALIGN UINT8 data[]; // Packet/layer data.
@@ -276,18 +288,6 @@ struct flow_s
};
typedef struct flow_s *flow_t;
-/*
- * WinDivert reflect event.
- */
-struct reflect_event_s
-{
- LIST_ENTRY entry; // Entry for reflect_event_queue.
- context_t context; // Context.
- LONGLONG timestamp; // Event timestamp.
- WINDIVERT_EVENT event; // Event.
-};
-typedef struct reflect_event_s *reflect_event_t;
-
/*
* IPv4/IPv6 pseudo headers.
*/
@@ -487,10 +487,12 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
PVOID layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound,
BOOL loopback, BOOL impostor, PWINDIVERT_FILTER filter);
static PWINDIVERT_FILTER windivert_filter_compile(
- PWINDIVERT_FILTER ioctl_filter, size_t ioctl_filter_len);
+ PWINDIVERT_FILTER ioctl_filter, size_t ioctl_filter_len,
+ WINDIVERT_LAYER layer);
static NTSTATUS windivert_reflect_init(WDFOBJECT parent);
static void windivert_reflect_close(void);
-static void windivert_reflect_event(context_t context, WINDIVERT_EVENT event);
+static void windivert_reflect_open_event(context_t context);
+static void windivert_reflect_close_event(context_t context);
static void windivert_reflect_event_notify(context_t context,
LONGLONG timestamp, WINDIVERT_EVENT event);
static void windivert_reflect_established_notify(context_t context,
@@ -1752,7 +1754,7 @@ extern VOID windivert_cleanup(IN WDFFILEOBJECT object)
DEBUG("CLEANUP: cleaning up WinDivert context (context=%p)", context);
- windivert_reflect_event(context, WINDIVERT_EVENT_REFLECT_CLOSE);
+ windivert_reflect_close_event(context);
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
@@ -2593,11 +2595,12 @@ windivert_ioctl_bad_start_state:
goto windivert_ioctl_exit;
}
context->state = WINDIVERT_CONTEXT_STATE_OPEN;
+ layer = context->layer;
KeReleaseInStackQueuedSpinLock(&lock_handle);
filter0 = (PWINDIVERT_FILTER)outbuf;
filter0_len = outbuflen;
- filter = windivert_filter_compile(filter0, filter0_len);
+ filter = windivert_filter_compile(filter0, filter0_len, layer);
if (filter == NULL)
{
status = STATUS_INVALID_PARAMETER;
@@ -2614,7 +2617,6 @@ windivert_ioctl_bad_start_state:
{
goto windivert_ioctl_bad_start_state;
}
- layer = context->layer;
flags = context->flags;
switch (layer)
{
@@ -2644,10 +2646,10 @@ windivert_ioctl_bad_start_state:
context->reflect.data.Layer = context->layer;
context->reflect.data.Flags = context->flags;
context->reflect.data.Priority = context->priority16;
- context->reflect.inserted = FALSE;
+ context->reflect.open = FALSE;
KeReleaseInStackQueuedSpinLock(&lock_handle);
- windivert_reflect_event(context, WINDIVERT_EVENT_REFLECT_OPEN);
+ windivert_reflect_open_event(context);
flags = ioctl->arg;
status = windivert_install_callouts(context, layer, flags);
@@ -5271,9 +5273,11 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
* Compile a WinDivert filter from an IOCTL.
*/
static PWINDIVERT_FILTER windivert_filter_compile(
- PWINDIVERT_FILTER ioctl_filter, size_t ioctl_filter_len)
+ PWINDIVERT_FILTER ioctl_filter, size_t ioctl_filter_len,
+ WINDIVERT_LAYER layer)
{
PWINDIVERT_FILTER filter = NULL;
+ WINDIVERT_EVENT event;
UINT16 i;
size_t length;
@@ -5328,7 +5332,7 @@ static PWINDIVERT_FILTER windivert_filter_compile(
break;
}
- // Enforce size limits:
+ // Enforce ranges:
if (ioctl_filter[i].field != WINDIVERT_FILTER_FIELD_IPV6_SRCADDR &&
ioctl_filter[i].field != WINDIVERT_FILTER_FIELD_IPV6_DSTADDR &&
ioctl_filter[i].field != WINDIVERT_FILTER_FIELD_LOCALADDR &&
@@ -5383,9 +5387,42 @@ static PWINDIVERT_FILTER windivert_filter_compile(
}
break;
case WINDIVERT_FILTER_FIELD_EVENT:
- if (ioctl_filter[i].arg[0] > WINDIVERT_EVENT_MAX)
+ event = (WINDIVERT_EVENT)ioctl_filter[i].arg[0];
+ switch (layer)
{
- goto windivert_filter_compile_error;
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ if (event != WINDIVERT_EVENT_NETWORK_PACKET)
+ {
+ goto windivert_filter_compile_error;
+ }
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ if (event != WINDIVERT_EVENT_FLOW_ESTABLISHED &&
+ event != WINDIVERT_EVENT_FLOW_DELETED)
+ {
+ goto windivert_filter_compile_error;
+ }
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ if (event != WINDIVERT_EVENT_SOCKET_BIND &&
+ event != WINDIVERT_EVENT_SOCKET_CONNECT &&
+ event != WINDIVERT_EVENT_SOCKET_LISTEN &&
+ event != WINDIVERT_EVENT_SOCKET_ACCEPT)
+ {
+ goto windivert_filter_compile_error;
+ }
+ break;
+ case WINDIVERT_LAYER_REFLECT:
+ if (event != WINDIVERT_EVENT_REFLECT_ESTABLISHED &&
+ event != WINDIVERT_EVENT_REFLECT_OPEN &&
+ event != WINDIVERT_EVENT_REFLECT_CLOSE)
+ {
+ goto windivert_filter_compile_error;
+ }
+ break;
+ default:
+ goto windivert_filter_compile_error;
}
break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
@@ -5472,15 +5509,21 @@ windivert_filter_compile_error:
/* WINDIVERT REFLECT MANAGER IMPLEMENTATION */
/****************************************************************************/
+#define WINDIVERT_REFLECT_PSEUDO_PACKET_MAX 12288
+
/*
* WinDivert reflect state.
*/
static BOOL reflect_inited = FALSE; // Reflection initialized?
+static BOOL reflect_worker_queued = FALSE; // Reflect worker queued?
static KSPIN_LOCK reflect_lock; // Reflect lock.
static LIST_ENTRY reflect_event_queue; // Reflect event queue.
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];
+#pragma data_seg(pop, stack)
/*
* Initialize the reflection layer implementation.
@@ -5496,7 +5539,7 @@ static NTSTATUS windivert_reflect_init(WDFOBJECT parent)
InitializeListHead(&reflect_contexts);
InitializeListHead(&reflect_waiters);
WDF_WORKITEM_CONFIG_INIT(&item_config, windivert_reflect_worker);
- item_config.AutomaticSerialization = TRUE;
+ item_config.AutomaticSerialization = FALSE;
WDF_OBJECT_ATTRIBUTES_INIT(&obj_attrs);
obj_attrs.ParentObject = parent;
status = WdfWorkItemCreate(&item_config, &obj_attrs, &reflect_worker);
@@ -5523,9 +5566,9 @@ static void windivert_reflect_close(void)
}
/*
- * WinDivert handle reflect event.
+ * WinDivert handle reflect open event.
*/
-static void windivert_reflect_event(context_t context, WINDIVERT_EVENT event)
+static void windivert_reflect_open_event(context_t context)
{
KLOCK_QUEUE_HANDLE lock_handle;
WDFOBJECT object;
@@ -5533,37 +5576,55 @@ static void windivert_reflect_event(context_t context, WINDIVERT_EVENT event)
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
object = (WDFOBJECT)context->object;
- if (event == WINDIVERT_EVENT_REFLECT_OPEN)
+ // To be released on the close event. This ensures the context object
+ // remains valid until the close event has been handled.
+ WdfObjectReference(object);
+ context->reflect.open = TRUE;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ // Queue the event:
+ reflect_event = &context->reflect.open_event;
+ reflect_event->context = context;
+ reflect_event->event = WINDIVERT_EVENT_REFLECT_OPEN;
+ KeAcquireInStackQueuedSpinLock(&reflect_lock, &lock_handle);
+ InsertTailList(&reflect_event_queue, &reflect_event->entry);
+ if (!reflect_worker_queued)
{
- // To be released on WINDIVERT_EVENT_REFLECT_CLOSE. This ensures the
- // context object remains valid until the close event has been handled.
- WdfObjectReference(object);
- context->reflect.open = TRUE;
+ WdfWorkItemEnqueue(reflect_worker);
+ reflect_worker_queued = TRUE;
}
KeReleaseInStackQueuedSpinLock(&lock_handle);
- if (!context->reflect.open)
+}
+
+/*
+ * WinDivert handle reflect close event.
+ */
+static void windivert_reflect_close_event(context_t context)
+{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ reflect_event_t reflect_event;
+ BOOL open;
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ open = context->reflect.open;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ if (!open)
{
- // Ignore CLOSE with no matching OPEN:
return;
}
// Queue the event:
- reflect_event = (reflect_event_t)windivert_malloc(
- sizeof(struct reflect_event_s), FALSE);
- if (reflect_event == NULL)
- {
- if (event == WINDIVERT_EVENT_REFLECT_CLOSE && context->reflect.open)
- {
- WdfObjectDereference(object);
- }
- return;
- }
+ reflect_event = &context->reflect.close_event;
reflect_event->context = context;
- reflect_event->event = event;
+ reflect_event->event = WINDIVERT_EVENT_REFLECT_CLOSE;
KeAcquireInStackQueuedSpinLock(&reflect_lock, &lock_handle);
InsertTailList(&reflect_event_queue, &reflect_event->entry);
+ if (!reflect_worker_queued)
+ {
+ WdfWorkItemEnqueue(reflect_worker);
+ reflect_worker_queued = TRUE;
+ }
KeReleaseInStackQueuedSpinLock(&lock_handle);
- WdfWorkItemEnqueue(reflect_worker);
}
/*
@@ -5584,20 +5645,14 @@ static PWINDIVERT_IPHDR windivert_reflect_pseudo_packet(context_t context,
// The filter is returned in a pseudo-IP packet. This is just to make
// the interface consistent, i.e., WinDivertRecv() always receives IP
// packets.
-
- total_len = sizeof(WINDIVERT_IPHDR) + WINDIVERT_OBJECT_MAXLEN;
- packet = windivert_malloc(total_len, TRUE);
- if (packet == NULL)
- {
- return NULL;
- }
+ packet = reflect_pseudo_packet;
iphdr = (PWINDIVERT_IPHDR)packet;
object = (char *)(iphdr + 1);
stream.data = object;
stream.pos = 0;
- stream.max = WINDIVERT_OBJECT_MAXLEN;
+ stream.max = sizeof(reflect_pseudo_packet) - sizeof(WINDIVERT_IPHDR);
stream.overflow = FALSE;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
@@ -5607,12 +5662,6 @@ static PWINDIVERT_IPHDR windivert_reflect_pseudo_packet(context_t context,
WinDivertSerializeFilter(&stream, filter, filter_len);
- if (stream.overflow)
- {
- windivert_free(packet);
- return NULL;
- }
-
total_len = sizeof(WINDIVERT_IPHDR) + (UINT16)stream.pos;
RtlZeroMemory(iphdr, sizeof(WINDIVERT_IPHDR));
iphdr->Version = 4;
@@ -5659,10 +5708,6 @@ static void windivert_reflect_event_notify(context_t context,
if (packet == NULL)
{
packet = windivert_reflect_pseudo_packet(context, &packet_len);
- if (packet == NULL)
- {
- return;
- }
}
(VOID)windivert_queue_work(waiter, (PVOID)packet, packet_len,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT,
@@ -5670,8 +5715,6 @@ static void windivert_reflect_event_notify(context_t context,
/*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE,
/*impostor=*/FALSE, /*final=*/FALSE, /*match=*/TRUE, timestamp);
}
-
- windivert_free(packet);
}
/*
@@ -5706,10 +5749,6 @@ static void windivert_reflect_established_notify(context_t context,
continue;
}
packet = windivert_reflect_pseudo_packet(waiter, &packet_len);
- if (packet == NULL)
- {
- continue;
- }
final = (entry == &reflect_contexts);
ok = windivert_queue_work(context, (PVOID)packet, packet_len,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT,
@@ -5718,7 +5757,6 @@ static void windivert_reflect_established_notify(context_t context,
/*priority=*/0, /*ipv4=*/TRUE, /*outbound=*/FALSE,
/*loopback=*/FALSE, /*impostor=*/FALSE, final, /*match=*/TRUE,
timestamp);
- windivert_free(packet);
if (!ok)
{
break;
@@ -5754,7 +5792,6 @@ static void windivert_reflect_worker(IN WDFWORKITEM item)
reflect_event = CONTAINING_RECORD(entry, struct reflect_event_s, entry);
context = reflect_event->context;
event = reflect_event->event;
- windivert_free(reflect_event);
DEBUG("REFLECT: %s event for WinDivert context (context=%p)",
(event == WINDIVERT_EVENT_REFLECT_OPEN? "open": "close"), context);
@@ -5768,7 +5805,6 @@ static void windivert_reflect_worker(IN WDFWORKITEM item)
switch (event)
{
case WINDIVERT_EVENT_REFLECT_OPEN:
- context->reflect.inserted = TRUE;
if (layer != WINDIVERT_LAYER_REFLECT)
{
InsertTailList(&reflect_contexts, &context->reflect.entry);
@@ -5781,10 +5817,7 @@ static void windivert_reflect_worker(IN WDFWORKITEM item)
break;
case WINDIVERT_EVENT_REFLECT_CLOSE:
- if (context->reflect.inserted)
- {
- RemoveEntryList(&context->reflect.entry);
- }
+ RemoveEntryList(&context->reflect.entry);
break;
}
@@ -5799,6 +5832,7 @@ static void windivert_reflect_worker(IN WDFWORKITEM item)
KeAcquireInStackQueuedSpinLock(&reflect_lock, &lock_handle);
}
+ reflect_worker_queued = FALSE;
KeReleaseInStackQueuedSpinLock(&lock_handle);
}
diff --git a/test/test.c b/test/test.c
index fa30a02..aab5ed0 100644
--- a/test/test.c
+++ b/test/test.c
@@ -113,7 +113,7 @@ static struct packet pkt_ipv6_exthdrs_udp =
};
static struct test tests[] =
{
- {"event = NETWORK_PACKET", &pkt_echo_request, TRUE},
+ {"event = PACKET", &pkt_echo_request, TRUE},
{"outbound and icmp", &pkt_echo_request, TRUE},
{"outbound", &pkt_echo_request, TRUE},
{"outbound and inbound", &pkt_echo_request, FALSE},
@@ -418,6 +418,7 @@ static BOOL run_test(HANDLE inject_handle, const char *filter,
addr.Outbound = TRUE;
addr.Layer = WINDIVERT_LAYER_NETWORK;
addr.IPv6 = (iphdr == NULL);
+ addr.Event = WINDIVERT_EVENT_NETWORK_PACKET;
if (WinDivertHelperEvalFilter(filter, (PVOID)packet, packet_len, &addr)
!= match)
{
From fc868feb3e108c7e3ed41173005db3da169b2094 Mon Sep 17 00:00:00 2001
From: basil00
Date: Tue, 30 Oct 2018 05:36:44 +0800
Subject: [PATCH 10/23] Add type-safe get-fixed-val routines.
This prevents possible bsods when values are
missing. Also add missing windivert_shared.c
file.
---
dll/windivert.c | 21 --
dll/windivert_shared.c | 614 +++++++++++++++++++++++++++++++++++++++++
sys/windivert.c | 473 ++++++++++++++-----------------
3 files changed, 819 insertions(+), 289 deletions(-)
create mode 100644 dll/windivert_shared.c
diff --git a/dll/windivert.c b/dll/windivert.c
index eb4fd28..cf4d399 100644
--- a/dll/windivert.c
+++ b/dll/windivert.c
@@ -63,27 +63,6 @@ static int WinDivertStrCmp(const char *s, const char *t);
static BOOLEAN WinDivertAToI(const char *str, char **endptr, UINT32 *intptr);
static BOOLEAN WinDivertAToX(const char *str, char **endptr, UINT32 *intptr);
-/*
- * IPv4/IPv6 pseudo headers.
- */
-typedef struct
-{
- UINT32 SrcAddr;
- UINT32 DstAddr;
- UINT8 Zero;
- UINT8 Protocol;
- UINT16 Length;
-} WINDIVERT_PSEUDOHDR, *PWINDIVERT_PSEUDOHDR;
-
-typedef struct
-{
- UINT32 SrcAddr[4];
- UINT32 DstAddr[4];
- UINT32 Length;
- UINT32 Zero:24;
- UINT32 NextHdr:8;
-} WINDIVERT_PSEUDOV6HDR, *PWINDIVERT_PSEUDOV6HDR;
-
/*
* Misc.
*/
diff --git a/dll/windivert_shared.c b/dll/windivert_shared.c
new file mode 100644
index 0000000..337064c
--- /dev/null
+++ b/dll/windivert_shared.c
@@ -0,0 +1,614 @@
+/*
+ * windivert_shared.c
+ * (C) 2018, all rights reserved,
+ *
+ * This file is part of WinDivert.
+ *
+ * WinDivert is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * WinDivert is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#define WINDIVERT_OBJECT_MAXLEN \
+ (8 + 4 + 2 + WINDIVERT_FILTER_MAXLEN * (1 + 2 + 2 + 4*7 + 2 + 2) + 1)
+
+#define MAX(a, b) ((a) > (b)? (a): (b))
+
+/*
+ * Definitions to remove (some) external dependencies:
+ */
+#define BYTESWAP16(x) \
+ ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00))
+#define BYTESWAP32(x) \
+ ((((x) >> 24) & 0x000000FF) | (((x) >> 8) & 0x0000FF00) | \
+ (((x) << 8) & 0x00FF0000) | (((x) << 24) & 0xFF000000))
+#define ntohs(x) BYTESWAP16(x)
+#define htons(x) BYTESWAP16(x)
+#define ntohl(x) BYTESWAP32(x)
+#define htonl(x) BYTESWAP32(x)
+
+/*
+ * IPv4/IPv6 pseudo headers.
+ */
+typedef struct
+{
+ UINT32 SrcAddr;
+ UINT32 DstAddr;
+ UINT8 Zero;
+ UINT8 Protocol;
+ UINT16 Length;
+} WINDIVERT_PSEUDOHDR, *PWINDIVERT_PSEUDOHDR;
+
+typedef struct
+{
+ UINT32 SrcAddr[4];
+ UINT32 DstAddr[4];
+ UINT32 Length;
+ UINT32 Zero:24;
+ UINT32 NextHdr:8;
+} WINDIVERT_PSEUDOV6HDR, *PWINDIVERT_PSEUDOV6HDR;
+
+/*
+ * Streams.
+ */
+typedef struct
+{
+ char *data;
+ UINT pos;
+ UINT max;
+ BOOL overflow;
+} WINDIVERT_STREAM, *PWINDIVERT_STREAM;
+
+/*
+ * Prototypes.
+ */
+static UINT16 WinDivertInitPseudoHeader(PWINDIVERT_IPHDR ip_header,
+ PWINDIVERT_IPV6HDR ipv6_header, UINT8 protocol, UINT len,
+ void *pseudo_header);
+static UINT16 WinDivertCalcChecksum(PVOID pseudo_header,
+ UINT16 pseudo_header_len, PVOID data, UINT len);
+
+/*
+ * Put a char into a stream.
+ */
+static void WinDivertPutChar(PWINDIVERT_STREAM stream, char c)
+{
+ if (stream->pos >= stream->max)
+ {
+ stream->overflow = TRUE;
+ return;
+ }
+ stream->data[stream->pos] = c;
+ stream->pos++;
+}
+
+/*
+ * Put a string into a stream.
+ */
+static void WinDivertPutString(PWINDIVERT_STREAM stream, const char *str)
+{
+ while (*str)
+ {
+ WinDivertPutChar(stream, *str);
+ str++;
+ }
+}
+
+/*
+ * Put a NUL character into a stream.
+ */
+static void WinDivertPutNul(PWINDIVERT_STREAM stream)
+{
+ if (stream->pos >= stream->max && stream->max > 0)
+ {
+ stream->data[stream->max-1] = '\0'; // Truncate
+ }
+ else
+ {
+ WinDivertPutChar(stream, '\0');
+ }
+}
+
+/*
+ * Serialize a number.
+ */
+static void WinDivertSerializeNumber(PWINDIVERT_STREAM stream, UINT32 val)
+{
+ UINT64 mask = 0x00000007C0000000ull;
+ UINT dig = 6;
+ UINT64 val64 = (UINT64)val;
+ BOOL final;
+
+ while ((mask & val64) == 0 && dig != 0)
+ {
+ mask >>= 5;
+ dig--;
+ }
+ while (TRUE)
+ {
+ final = (dig == 0);
+ WinDivertPutChar(stream, '!' + (char)((mask & val64) >> (5 * dig)) +
+ (final? 32: 0));
+ if (final)
+ {
+ break;
+ }
+ mask >>= 5;
+ dig--;
+ }
+}
+
+/*
+ * Serialize a test.
+ */
+static void WinDivertSerializeTest(PWINDIVERT_STREAM stream,
+ PWINDIVERT_FILTER filter)
+{
+ UINT i;
+
+ WinDivertPutChar(stream, '_');
+ WinDivertSerializeNumber(stream, filter->field);
+ WinDivertSerializeNumber(stream, filter->test);
+ WinDivertSerializeNumber(stream, filter->arg[0]);
+ switch (filter->field)
+ {
+ case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
+ case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
+ case WINDIVERT_FILTER_FIELD_LOCALADDR:
+ case WINDIVERT_FILTER_FIELD_REMOTEADDR:
+ for (i = 1; i < 4; i++)
+ {
+ WinDivertSerializeNumber(stream, filter->arg[i]);
+ }
+ break;
+ default:
+ break;
+ }
+ WinDivertSerializeNumber(stream, (UINT8)(filter->success + 2));
+ WinDivertSerializeNumber(stream, (UINT8)(filter->failure + 2));
+}
+
+/*
+ * Serialize a test.
+ */
+static void WinDivertSerializeFilter(PWINDIVERT_STREAM stream,
+ PWINDIVERT_FILTER filter, UINT8 length)
+{
+ UINT8 i;
+ WinDivertPutString(stream, "@WinDiv_"); // Magic
+ WinDivertSerializeNumber(stream, 0); // Version
+ WinDivertSerializeNumber(stream, length); // Length
+ for (i = 0; i < length; i++)
+ {
+ WinDivertSerializeTest(stream, filter + i);
+ }
+ WinDivertPutNul(stream);
+}
+
+/*
+ * Skip well-known IPv6 extension headers.
+ */
+static UINT8 WinDivertSkipExtHeaders(UINT8 proto, UINT8 **header, UINT *len)
+{
+ UINT hdrlen;
+
+ while (TRUE)
+ {
+ if (*len <= 2)
+ {
+ return IPPROTO_NONE;
+ }
+
+ hdrlen = (UINT)*(*header + 1);
+ switch (proto)
+ {
+ case IPPROTO_FRAGMENT:
+ hdrlen = 8;
+ break;
+ case IPPROTO_AH:
+ hdrlen += 2;
+ hdrlen *= 4;
+ break;
+ case IPPROTO_HOPOPTS:
+ case IPPROTO_DSTOPTS:
+ case IPPROTO_ROUTING:
+ hdrlen++;
+ hdrlen *= 8;
+ break;
+ case IPPROTO_NONE:
+ return proto;
+ default:
+ return proto;
+ }
+
+ if (hdrlen >= *len)
+ {
+ return IPPROTO_NONE;
+ }
+
+ proto = **header;
+ *header += hdrlen;
+ *len -= hdrlen;
+ }
+}
+
+/*
+ * Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
+ */
+static BOOL WinDivertParsePacket(PVOID pPacket, UINT packetLen,
+ PWINDIVERT_IPHDR *ppIpHdr, PWINDIVERT_IPV6HDR *ppIpv6Hdr,
+ PWINDIVERT_ICMPHDR *ppIcmpHdr, PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr,
+ PWINDIVERT_TCPHDR *ppTcpHdr, PWINDIVERT_UDPHDR *ppUdpHdr, UINT8 *pProto,
+ PVOID *ppData, UINT *pDataLen)
+{
+ PWINDIVERT_IPHDR ip_header = NULL;
+ PWINDIVERT_IPV6HDR ipv6_header = NULL;
+ PWINDIVERT_ICMPHDR icmp_header = NULL;
+ PWINDIVERT_ICMPV6HDR icmpv6_header = NULL;
+ PWINDIVERT_TCPHDR tcp_header = NULL;
+ PWINDIVERT_UDPHDR udp_header = NULL;
+ UINT16 header_len;
+ UINT8 trans_proto = 0;
+ PVOID data = NULL;
+ UINT data_len = 0;
+ BOOL success;
+
+ if (pPacket == NULL || packetLen < sizeof(UINT8))
+ {
+ goto WinDivertHelperParsePacketExit;
+ }
+ data = pPacket;
+ data_len = packetLen;
+
+ ip_header = (PWINDIVERT_IPHDR)data;
+ switch (ip_header->Version)
+ {
+ case 4:
+ if (data_len < sizeof(WINDIVERT_IPHDR) ||
+ ip_header->HdrLength < 5 ||
+ data_len < ip_header->HdrLength*sizeof(UINT32) ||
+ ntohs(ip_header->Length) != data_len)
+ {
+ ip_header = NULL;
+ goto WinDivertHelperParsePacketExit;
+ }
+ trans_proto = ip_header->Protocol;
+ header_len = ip_header->HdrLength*sizeof(UINT32);
+ data = (PVOID)((UINT8 *)data + header_len);
+ data_len -= header_len;
+ break;
+ case 6:
+ ip_header = NULL;
+ ipv6_header = (PWINDIVERT_IPV6HDR)data;
+ if (data_len < sizeof(WINDIVERT_IPV6HDR) ||
+ ntohs(ipv6_header->Length) !=
+ data_len - sizeof(WINDIVERT_IPV6HDR))
+ {
+ ipv6_header = NULL;
+ goto WinDivertHelperParsePacketExit;
+ }
+ trans_proto = ipv6_header->NextHdr;
+ data = (PVOID)((UINT8 *)data + sizeof(WINDIVERT_IPV6HDR));
+ data_len -= sizeof(WINDIVERT_IPV6HDR);
+ trans_proto = WinDivertSkipExtHeaders(trans_proto, (UINT8 **)&data,
+ &data_len);
+ break;
+ default:
+ ip_header = NULL;
+ goto WinDivertHelperParsePacketExit;
+ }
+ switch (trans_proto)
+ {
+ case IPPROTO_TCP:
+ tcp_header = (PWINDIVERT_TCPHDR)data;
+ if (data_len < sizeof(WINDIVERT_TCPHDR) ||
+ tcp_header->HdrLength < 5 ||
+ data_len < tcp_header->HdrLength*sizeof(UINT32))
+ {
+ tcp_header = NULL;
+ goto WinDivertHelperParsePacketExit;
+ }
+ header_len = tcp_header->HdrLength*sizeof(UINT32);
+ data = ((UINT8 *)data + header_len);
+ data_len -= header_len;
+ break;
+ case IPPROTO_UDP:
+ udp_header = (PWINDIVERT_UDPHDR)data;
+ if (data_len < sizeof(WINDIVERT_UDPHDR) ||
+ ntohs(udp_header->Length) != data_len)
+ {
+ udp_header = NULL;
+ goto WinDivertHelperParsePacketExit;
+ }
+ data = ((UINT8 *)data + sizeof(WINDIVERT_UDPHDR));
+ data_len -= sizeof(WINDIVERT_UDPHDR);
+ break;
+ case IPPROTO_ICMP:
+ icmp_header = (PWINDIVERT_ICMPHDR)data;
+ if (ip_header == NULL ||
+ data_len < sizeof(WINDIVERT_ICMPHDR))
+ {
+ icmp_header = NULL;
+ goto WinDivertHelperParsePacketExit;
+ }
+ data = ((UINT8 *)data + sizeof(WINDIVERT_ICMPHDR));
+ data_len -= sizeof(WINDIVERT_ICMPHDR);
+ break;
+ case IPPROTO_ICMPV6:
+ icmpv6_header = (PWINDIVERT_ICMPV6HDR)data;
+ if (ipv6_header == NULL ||
+ data_len < sizeof(WINDIVERT_ICMPV6HDR))
+ {
+ icmpv6_header = NULL;
+ goto WinDivertHelperParsePacketExit;
+ }
+ data = ((UINT8 *)data + sizeof(WINDIVERT_ICMPV6HDR));
+ data_len -= sizeof(WINDIVERT_ICMPV6HDR);
+ break;
+ default:
+ break;
+ }
+
+ if (data_len == 0)
+ {
+ data = NULL;
+ }
+
+WinDivertHelperParsePacketExit:
+ success = TRUE;
+ if (ppIpHdr != NULL)
+ {
+ *ppIpHdr = ip_header;
+ success = success && (ip_header != NULL);
+ }
+ if (ppIpv6Hdr != NULL)
+ {
+ *ppIpv6Hdr = ipv6_header;
+ success = success && (ipv6_header != NULL);
+ }
+ if (ppIcmpHdr != NULL)
+ {
+ *ppIcmpHdr = icmp_header;
+ success = success && (icmp_header != NULL);
+ }
+ if (ppIcmpv6Hdr != NULL)
+ {
+ *ppIcmpv6Hdr = icmpv6_header;
+ success = success && (icmpv6_header != NULL);
+ }
+ if (ppTcpHdr != NULL)
+ {
+ *ppTcpHdr = tcp_header;
+ success = success && (tcp_header != NULL);
+ }
+ if (ppUdpHdr != NULL)
+ {
+ *ppUdpHdr = udp_header;
+ success = success && (udp_header != NULL);
+ }
+ if (pProto != NULL)
+ {
+ *pProto = trans_proto;
+ }
+ if (ppData != NULL)
+ {
+ *ppData = data;
+ success = success && (data != NULL);
+ }
+ if (pDataLen != NULL)
+ {
+ *pDataLen = data_len;
+ }
+ return success;
+}
+
+/*
+ * Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums.
+ */
+extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
+ PWINDIVERT_ADDRESS pAddr, UINT64 flags)
+{
+ UINT8 pseudo_header[
+ MAX(sizeof(WINDIVERT_PSEUDOHDR), sizeof(WINDIVERT_PSEUDOV6HDR))];
+ UINT16 pseudo_header_len;
+ PWINDIVERT_IPHDR ip_header;
+ PWINDIVERT_IPV6HDR ipv6_header;
+ PWINDIVERT_ICMPHDR icmp_header;
+ PWINDIVERT_ICMPV6HDR icmpv6_header;
+ PWINDIVERT_TCPHDR tcp_header;
+ PWINDIVERT_UDPHDR udp_header;
+ UINT payload_len, checksum_len;
+ UINT count = 0;
+
+ WinDivertParsePacket(pPacket, packetLen, &ip_header, &ipv6_header,
+ &icmp_header, &icmpv6_header, &tcp_header, &udp_header, NULL, NULL,
+ &payload_len);
+
+ if (ip_header != NULL && !(flags & WINDIVERT_HELPER_NO_IP_CHECKSUM))
+ {
+ ip_header->Checksum = 0;
+ if (pAddr == NULL || pAddr->PseudoIPChecksum == 0)
+ {
+ ip_header->Checksum = WinDivertCalcChecksum(NULL, 0,
+ ip_header, ip_header->HdrLength*sizeof(UINT32));
+ }
+ count++;
+ }
+
+ if (icmp_header != NULL)
+ {
+ if ((flags & WINDIVERT_HELPER_NO_ICMP_CHECKSUM) != 0)
+ {
+ return count;
+ }
+ icmp_header->Checksum = 0;
+ icmp_header->Checksum = WinDivertCalcChecksum(NULL, 0,
+ icmp_header, payload_len + sizeof(WINDIVERT_ICMPHDR));
+ count++;
+ return count;
+ }
+
+ if (icmpv6_header != NULL)
+ {
+ if ((flags & WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM) != 0)
+ {
+ return count;
+ }
+ checksum_len = payload_len + sizeof(WINDIVERT_ICMPV6HDR);
+ pseudo_header_len = WinDivertInitPseudoHeader(NULL, ipv6_header,
+ IPPROTO_ICMPV6, checksum_len, pseudo_header);
+ icmpv6_header->Checksum = 0;
+ icmpv6_header->Checksum = WinDivertCalcChecksum(pseudo_header,
+ pseudo_header_len, icmpv6_header, checksum_len);
+ count++;
+ return count;
+ }
+
+ if (tcp_header != NULL)
+ {
+ if ((flags & WINDIVERT_HELPER_NO_TCP_CHECKSUM) != 0)
+ {
+ return count;
+ }
+ if (pAddr == NULL || pAddr->PseudoTCPChecksum == 0)
+ {
+ // Full TCP checksum
+ checksum_len = payload_len + tcp_header->HdrLength*sizeof(UINT32);
+ pseudo_header_len = WinDivertInitPseudoHeader(ip_header,
+ ipv6_header, IPPROTO_TCP, checksum_len, pseudo_header);
+ tcp_header->Checksum = 0;
+ tcp_header->Checksum = WinDivertCalcChecksum(
+ pseudo_header, pseudo_header_len, tcp_header, checksum_len);
+ }
+ else if (pAddr->Outbound)
+ {
+ // Pseudo TCP checksum
+ tcp_header->Checksum = 0;
+ }
+ count++;
+ return count;
+ }
+
+ if (udp_header != NULL)
+ {
+ if ((flags & WINDIVERT_HELPER_NO_UDP_CHECKSUM) != 0)
+ {
+ return count;
+ }
+ if (pAddr == NULL || pAddr->PseudoUDPChecksum == 0)
+ {
+ // Full UDP checksum
+ checksum_len = payload_len + sizeof(WINDIVERT_UDPHDR);
+ pseudo_header_len = WinDivertInitPseudoHeader(ip_header,
+ ipv6_header, IPPROTO_UDP, checksum_len, pseudo_header);
+ udp_header->Checksum = 0;
+ udp_header->Checksum = WinDivertCalcChecksum(
+ pseudo_header, pseudo_header_len, udp_header, checksum_len);
+ if (udp_header->Checksum == 0)
+ {
+ udp_header->Checksum = 0xFFFF;
+ }
+ }
+ else if (pAddr->Outbound)
+ {
+ // Pseudo UDP checksum
+ udp_header->Checksum = 0;
+ }
+ count++;
+ }
+ return count;
+}
+
+/*
+ * Initialize the IP/IPv6 pseudo header.
+ */
+static UINT16 WinDivertInitPseudoHeader(PWINDIVERT_IPHDR ip_header,
+ PWINDIVERT_IPV6HDR ipv6_header, UINT8 protocol, UINT len,
+ void *pseudo_header)
+{
+ if (ip_header != NULL)
+ {
+ PWINDIVERT_PSEUDOHDR pseudo_header_v4 =
+ (PWINDIVERT_PSEUDOHDR)pseudo_header;
+ pseudo_header_v4->SrcAddr = ip_header->SrcAddr;
+ pseudo_header_v4->DstAddr = ip_header->DstAddr;
+ pseudo_header_v4->Zero = 0;
+ pseudo_header_v4->Protocol = protocol;
+ pseudo_header_v4->Length = htons((UINT16)len);
+ return sizeof(WINDIVERT_PSEUDOHDR);
+ }
+ else
+ {
+ PWINDIVERT_PSEUDOV6HDR pseudo_header_v6 =
+ (PWINDIVERT_PSEUDOV6HDR)pseudo_header;
+ memcpy(pseudo_header_v6->SrcAddr, ipv6_header->SrcAddr,
+ sizeof(pseudo_header_v6->SrcAddr));
+ memcpy(pseudo_header_v6->DstAddr, ipv6_header->DstAddr,
+ sizeof(pseudo_header_v6->DstAddr));
+ pseudo_header_v6->Length = htonl((UINT32)len);
+ pseudo_header_v6->NextHdr = protocol;
+ pseudo_header_v6->Zero = 0;
+ return sizeof(WINDIVERT_PSEUDOV6HDR);
+ }
+}
+
+/*
+ * Generic checksum computation.
+ */
+static UINT16 WinDivertCalcChecksum(PVOID pseudo_header,
+ UINT16 pseudo_header_len, PVOID data, UINT len)
+{
+ register const UINT16 *data16 = (const UINT16 *)pseudo_header;
+ register size_t len16 = pseudo_header_len >> 1;
+ register UINT32 sum = 0;
+ size_t i;
+
+ // Pseudo header:
+ for (i = 0; i < len16; i++)
+ {
+ sum += (UINT32)data16[i];
+ }
+
+ // Main data:
+ data16 = (const UINT16 *)data;
+ len16 = len >> 1;
+ for (i = 0; i < len16; i++)
+ {
+ sum += (UINT32)data16[i];
+ }
+
+ if (len & 0x1)
+ {
+ const UINT8 *data8 = (const UINT8 *)data;
+ sum += (UINT16)data8[len-1];
+ }
+
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ sum += (sum >> 16);
+ sum = ~sum;
+ return (UINT16)sum;
+}
+
diff --git a/sys/windivert.c b/sys/windivert.c
index a5d9b2a..24f028b 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -288,27 +288,6 @@ struct flow_s
};
typedef struct flow_s *flow_t;
-/*
- * IPv4/IPv6 pseudo headers.
- */
-typedef struct
-{
- UINT32 SrcAddr;
- UINT32 DstAddr;
- UINT8 Zero;
- UINT8 Protocol;
- UINT16 Length;
-} WINDIVERT_PSEUDOHDR, *PWINDIVERT_PSEUDOHDR;
-
-typedef struct
-{
- UINT32 SrcAddr[4];
- UINT32 DstAddr[4];
- UINT32 Length;
- UINT32 Zero:24;
- UINT32 NextHdr:8;
-} WINDIVERT_PSEUDOV6HDR, *PWINDIVERT_PSEUDOV6HDR;
-
/*
* Misc.
*/
@@ -2853,6 +2832,59 @@ static NTSTATUS windivert_notify(IN FWPS_CALLOUT_NOTIFY_TYPE type,
return STATUS_SUCCESS;
}
+/*
+ * WinDivert get fixed values.
+ */
+static UINT8 windivert_get_val8(const FWPS_INCOMING_VALUES0 *fixed_vals,
+ int idx)
+{
+ FWP_VALUE0 value = fixed_vals->incomingValue[idx].value;
+ return (value.type != FWP_UINT8? 0: value.uint8);
+}
+static UINT16 windivert_get_val16(const FWPS_INCOMING_VALUES0 *fixed_vals,
+ int idx)
+{
+ FWP_VALUE0 value = fixed_vals->incomingValue[idx].value;
+ return (value.type != FWP_UINT16? 0: value.uint16);
+}
+static UINT32 windivert_get_val32(const FWPS_INCOMING_VALUES0 *fixed_vals,
+ int idx)
+{
+ FWP_VALUE0 value = fixed_vals->incomingValue[idx].value;
+ return (value.type != FWP_UINT32? 0: value.uint32);
+}
+static void windivert_get_ipv4_addr(const FWPS_INCOMING_VALUES0 *fixed_vals,
+ int idx, UINT32 *addr)
+{
+ FWP_VALUE0 value = fixed_vals->incomingValue[idx].value;
+ addr[2] = addr[3] = 0;
+ if (value.type != FWP_UINT32)
+ {
+ addr[0] = addr[1] = 0;
+ }
+ else
+ {
+ addr[0] = value.uint32;
+ addr[1] = 0x0000FFFF;
+ }
+}
+static void windivert_get_ipv6_addr(const FWPS_INCOMING_VALUES0 *fixed_vals,
+ int idx, UINT32 *addr)
+{
+ UINT8 *addr8 = (UINT8 *)addr;
+ INT i;
+ FWP_VALUE0 value = fixed_vals->incomingValue[idx].value;
+ if (value.type != FWP_BYTE_ARRAY16_TYPE)
+ {
+ RtlZeroMemory(&addr, 16);
+ return;
+ }
+ for (i = 16-1; i >= 0; i--)
+ {
+ addr8[16-i-1] = value.byteArray16->byteArray16[i];
+ }
+}
+
/*
* WinDivert classify outbound IPv4 function.
*/
@@ -2870,12 +2902,12 @@ static void windivert_outbound_network_v4_classify(
return;
}
- network_data.IfIdx = fixed_vals->incomingValue[
- FWPS_FIELD_OUTBOUND_IPPACKET_V4_INTERFACE_INDEX].value.uint32,
- network_data.SubIfIdx = fixed_vals->incomingValue[
- FWPS_FIELD_OUTBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX].value.uint32,
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_OUTBOUND_IPPACKET_V4_FLAGS].value.uint32 &
+ network_data.IfIdx = windivert_get_val32(fixed_vals,
+ FWPS_FIELD_OUTBOUND_IPPACKET_V4_INTERFACE_INDEX);
+ network_data.SubIfIdx = windivert_get_val32(fixed_vals,
+ FWPS_FIELD_OUTBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX);
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_OUTBOUND_IPPACKET_V4_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_network_classify((context_t)filter->context, &network_data,
@@ -2900,12 +2932,12 @@ static void windivert_outbound_network_v6_classify(
return;
}
- network_data.IfIdx = fixed_vals->incomingValue[
- FWPS_FIELD_OUTBOUND_IPPACKET_V6_INTERFACE_INDEX].value.uint32,
- network_data.SubIfIdx = fixed_vals->incomingValue[
- FWPS_FIELD_OUTBOUND_IPPACKET_V6_SUB_INTERFACE_INDEX].value.uint32,
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_OUTBOUND_IPPACKET_V6_FLAGS].value.uint32 &
+ network_data.IfIdx = windivert_get_val32(fixed_vals,
+ FWPS_FIELD_OUTBOUND_IPPACKET_V6_INTERFACE_INDEX);
+ network_data.SubIfIdx = windivert_get_val32(fixed_vals,
+ FWPS_FIELD_OUTBOUND_IPPACKET_V6_SUB_INTERFACE_INDEX);
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_OUTBOUND_IPPACKET_V6_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_network_classify((context_t)filter->context, &network_data,
@@ -2931,8 +2963,8 @@ static void windivert_inbound_network_v4_classify(
return;
}
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_INBOUND_IPPACKET_V4_FLAGS].value.uint32 &
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_INBOUND_IPPACKET_V4_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
if (loopback)
{
@@ -2940,10 +2972,10 @@ static void windivert_inbound_network_v4_classify(
return;
}
- network_data.IfIdx = fixed_vals->incomingValue[
- FWPS_FIELD_INBOUND_IPPACKET_V4_INTERFACE_INDEX].value.uint32;
- network_data.SubIfIdx = fixed_vals->incomingValue[
- FWPS_FIELD_INBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX].value.uint32;
+ network_data.IfIdx = windivert_get_val32(fixed_vals,
+ FWPS_FIELD_INBOUND_IPPACKET_V4_INTERFACE_INDEX);
+ network_data.SubIfIdx = windivert_get_val32(fixed_vals,
+ FWPS_FIELD_INBOUND_IPPACKET_V4_SUB_INTERFACE_INDEX);
advance = meta_vals->ipHeaderSize;
windivert_network_classify((context_t)filter->context, &network_data,
@@ -2968,8 +3000,8 @@ static void windivert_inbound_network_v6_classify(
return;
}
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_INBOUND_IPPACKET_V6_FLAGS].value.uint32 &
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_INBOUND_IPPACKET_V6_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
if (loopback)
{
@@ -2977,10 +3009,10 @@ static void windivert_inbound_network_v6_classify(
return;
}
- network_data.IfIdx = fixed_vals->incomingValue[
- FWPS_FIELD_INBOUND_IPPACKET_V6_INTERFACE_INDEX].value.uint32;
- network_data.SubIfIdx = fixed_vals->incomingValue[
- FWPS_FIELD_INBOUND_IPPACKET_V6_SUB_INTERFACE_INDEX].value.uint32;
+ network_data.IfIdx = windivert_get_val32(fixed_vals,
+ FWPS_FIELD_INBOUND_IPPACKET_V6_INTERFACE_INDEX);
+ network_data.SubIfIdx = windivert_get_val32(fixed_vals,
+ FWPS_FIELD_INBOUND_IPPACKET_V6_SUB_INTERFACE_INDEX);
advance = meta_vals->ipHeaderSize;
windivert_network_classify((context_t)filter->context, &network_data,
@@ -3003,8 +3035,8 @@ static void windivert_forward_network_v4_classify(
return;
}
- network_data.IfIdx = fixed_vals->incomingValue[
- FWPS_FIELD_IPFORWARD_V4_DESTINATION_INTERFACE_INDEX].value.uint32;
+ network_data.IfIdx = windivert_get_val32(fixed_vals,
+ FWPS_FIELD_IPFORWARD_V4_DESTINATION_INTERFACE_INDEX);
network_data.SubIfIdx = 0;
windivert_network_classify((context_t)filter->context, &network_data,
@@ -3028,8 +3060,8 @@ static void windivert_forward_network_v6_classify(
return;
}
- network_data.IfIdx = fixed_vals->incomingValue[
- FWPS_FIELD_IPFORWARD_V6_DESTINATION_INTERFACE_INDEX].value.uint32;
+ network_data.IfIdx = windivert_get_val32(fixed_vals,
+ FWPS_FIELD_IPFORWARD_V6_DESTINATION_INTERFACE_INDEX);
network_data.SubIfIdx = 0;
windivert_network_classify((context_t)filter->context, &network_data,
@@ -3248,28 +3280,24 @@ static void windivert_flow_established_v4_classify(
UINT64 flow_id;
flow_data.ProcessId = (UINT32)meta_vals->processId;
- flow_data.LocalAddr[0] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS].value.uint32;
- flow_data.LocalAddr[1] = 0x0000FFFF;
- flow_data.LocalAddr[2] = 0;
- flow_data.LocalAddr[3] = 0;
- flow_data.RemoteAddr[0] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_ADDRESS].value.uint32;
- flow_data.RemoteAddr[1] = 0x0000FFFF;
- flow_data.RemoteAddr[2] = 0;
- flow_data.RemoteAddr[3] = 0;
- flow_data.LocalPort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_PORT].value.uint16;
- flow_data.RemotePort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_PORT].value.uint16;
- flow_data.Protocol = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL].value.uint8;
+ windivert_get_ipv4_addr(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_ADDRESS,
+ flow_data.LocalAddr);
+ windivert_get_ipv4_addr(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_ADDRESS,
+ flow_data.RemoteAddr);
+ flow_data.LocalPort = windivert_get_val16(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_LOCAL_PORT);
+ flow_data.RemotePort = windivert_get_val16(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_REMOTE_PORT);
+ flow_data.Protocol = windivert_get_val8(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_IP_PROTOCOL);
- outbound = (fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION].value.uint32 ==
+ outbound = (windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION) ==
FWP_DIRECTION_OUTBOUND);
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_FLAGS].value.uint32 &
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
flow_id = meta_vals->flowHandle;
@@ -3289,37 +3317,26 @@ static void windivert_flow_established_v6_classify(
WINDIVERT_DATA_FLOW flow_data;
BOOL outbound, loopback;
UINT64 flow_id;
- UINT8 *addr;
- INT i;
- // IPv6 assumes host byte order, so convert:
flow_data.ProcessId = (UINT32)meta_vals->processId;
- addr = (UINT8 *)&flow_data.LocalAddr;
- for (i = sizeof(flow_data.LocalAddr)-1; i >= 0; i--)
- {
- addr[sizeof(flow_data.LocalAddr)-i-1] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_ADDRESS]
- .value.byteArray16->byteArray16[i];
- }
- addr = (UINT8 *)&flow_data.RemoteAddr;
- for (i = sizeof(flow_data.RemoteAddr)-1; i >= 0; i--)
- {
- addr[sizeof(flow_data.RemoteAddr)-i-1] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_ADDRESS]
- .value.byteArray16->byteArray16[i];
- }
- flow_data.LocalPort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_PORT].value.uint16;
- flow_data.RemotePort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_PORT].value.uint16;
- flow_data.Protocol = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL].value.uint8;
+ windivert_get_ipv6_addr(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_ADDRESS,
+ flow_data.LocalAddr);
+ windivert_get_ipv6_addr(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_ADDRESS,
+ flow_data.RemoteAddr);
+ flow_data.LocalPort = windivert_get_val16(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_PORT);
+ flow_data.RemotePort = windivert_get_val16(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_REMOTE_PORT);
+ flow_data.Protocol = windivert_get_val8(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_PROTOCOL);
- outbound = (fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_DIRECTION].value.uint32 ==
+ outbound = (windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_DIRECTION) ==
FWP_DIRECTION_OUTBOUND);
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_FLAGS].value.uint32 &
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
flow_id = meta_vals->flowHandle;
@@ -3518,37 +3535,21 @@ static void windivert_resource_assignment_v4_classify(
OUT FWPS_CLASSIFY_OUT0 *result)
{
WINDIVERT_DATA_SOCKET socket_data;
- FWP_VALUE0 value;
BOOL loopback;
socket_data.ProcessId = (UINT32)meta_vals->processId;
- value = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_ADDRESS].value;
- if (value.type == FWP_UINT32)
- {
- socket_data.LocalAddr[0] = value.uint32;
- socket_data.LocalAddr[1] = 0x0000FFFF;
- }
- else
- {
- socket_data.LocalAddr[0] = 0;
- socket_data.LocalAddr[1] = 0;
- }
- socket_data.LocalAddr[2] = 0;
- socket_data.LocalAddr[3] = 0;
- socket_data.RemoteAddr[0] = 0;
- socket_data.RemoteAddr[1] = 0;
- socket_data.RemoteAddr[2] = 0;
- socket_data.RemoteAddr[3] = 0;
- value = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_PORT].value;
- socket_data.LocalPort = (value.type == FWP_UINT16? value.uint16: 0);
+ windivert_get_ipv4_addr(fixed_vals,
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_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_ASSIGNMENT_V4_IP_LOCAL_PORT);
socket_data.RemotePort = 0;
- socket_data.Protocol = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_PROTOCOL].value.uint8;
+ socket_data.Protocol = windivert_get_val8(fixed_vals,
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_PROTOCOL);
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_FLAGS].value.uint32 &
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
@@ -3566,43 +3567,21 @@ static void windivert_resource_assignment_v6_classify(
OUT FWPS_CLASSIFY_OUT0 *result)
{
WINDIVERT_DATA_SOCKET socket_data;
- FWP_VALUE0 value;
BOOL loopback;
- UINT8 *addr;
- INT i;
socket_data.ProcessId = (UINT32)meta_vals->processId;
- addr = (UINT8 *)&socket_data.LocalAddr;
- value = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_LOCAL_ADDRESS].value;
- if (value.type == FWP_BYTE_ARRAY16_TYPE)
- {
- for (i = sizeof(socket_data.LocalAddr)-1; i >= 0; i--)
- {
- addr[sizeof(socket_data.LocalAddr)-i-1] =
- value.byteArray16->byteArray16[i];
- }
- }
- else
- {
- socket_data.LocalAddr[0] = 0;
- socket_data.LocalAddr[1] = 0;
- socket_data.LocalAddr[2] = 0;
- socket_data.LocalAddr[3] = 0;
- }
- socket_data.RemoteAddr[0] = 0;
- socket_data.RemoteAddr[1] = 0;
- socket_data.RemoteAddr[2] = 0;
- socket_data.RemoteAddr[3] = 0;
- value = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_LOCAL_PORT].value;
- socket_data.LocalPort = (value.type == FWP_UINT16? value.uint16: 0);
+ windivert_get_ipv6_addr(fixed_vals,
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_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_ASSIGNMENT_V6_IP_LOCAL_PORT);
socket_data.RemotePort = 0;
- socket_data.Protocol = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_PROTOCOL].value.uint8;
+ socket_data.Protocol = windivert_get_val8(fixed_vals,
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_PROTOCOL);
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_FLAGS].value.uint32 &
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
@@ -3623,25 +3602,21 @@ static void windivert_auth_connect_v4_classify(
BOOL loopback;
socket_data.ProcessId = (UINT32)meta_vals->processId;
- socket_data.LocalAddr[0] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS].value.uint32;
- socket_data.LocalAddr[1] = 0x0000FFFF;
- socket_data.LocalAddr[2] = 0;
- socket_data.LocalAddr[3] = 0;
- socket_data.RemoteAddr[0] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS].value.uint32;
- socket_data.RemoteAddr[1] = 0x0000FFFF;
- socket_data.RemoteAddr[2] = 0;
- socket_data.RemoteAddr[3] = 0;
- socket_data.LocalPort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16;
- socket_data.RemotePort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16;
- socket_data.Protocol = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8;
+ windivert_get_ipv4_addr(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS,
+ socket_data.LocalAddr);
+ windivert_get_ipv4_addr(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS,
+ socket_data.RemoteAddr);
+ socket_data.LocalPort = windivert_get_val16(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT);
+ socket_data.RemotePort = windivert_get_val16(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT);
+ socket_data.Protocol = windivert_get_val8(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL);
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS].value.uint32 &
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
@@ -3660,33 +3635,23 @@ static void windivert_auth_connect_v6_classify(
{
WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
- UINT8 *addr;
- INT i;
socket_data.ProcessId = (UINT32)meta_vals->processId;
- addr = (UINT8 *)&socket_data.LocalAddr;
- for (i = sizeof(socket_data.LocalAddr)-1; i >= 0; i--)
- {
- addr[sizeof(socket_data.LocalAddr)-i-1] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_ADDRESS]
- .value.byteArray16->byteArray16[i];
- }
- addr = (UINT8 *)&socket_data.RemoteAddr;
- for (i = sizeof(socket_data.RemoteAddr)-1; i >= 0; i--)
- {
- addr[sizeof(socket_data.RemoteAddr)-i-1] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_ADDRESS]
- .value.byteArray16->byteArray16[i];
- }
- socket_data.LocalPort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16;
- socket_data.RemotePort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16;
- socket_data.Protocol = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8;
+ windivert_get_ipv6_addr(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_ADDRESS,
+ socket_data.LocalAddr);
+ windivert_get_ipv6_addr(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_ADDRESS,
+ socket_data.RemoteAddr);
+ socket_data.LocalPort = windivert_get_val16(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_PORT);
+ socket_data.RemotePort = windivert_get_val16(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_PORT);
+ socket_data.Protocol = windivert_get_val8(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_PROTOCOL);
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS].value.uint32 &
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_CONNECT_V6_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
@@ -3707,22 +3672,17 @@ static void windivert_auth_listen_v4_classify(
BOOL loopback;
socket_data.ProcessId = (UINT32)meta_vals->processId;
- socket_data.LocalAddr[0] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_LISTEN_V4_IP_LOCAL_ADDRESS].value.uint32;
- socket_data.LocalAddr[1] = 0x0000FFFF;
- socket_data.LocalAddr[2] = 0;
- socket_data.LocalAddr[3] = 0;
- socket_data.RemoteAddr[0] = 0;
- socket_data.RemoteAddr[1] = 0;
- socket_data.RemoteAddr[2] = 0;
- socket_data.RemoteAddr[3] = 0;
- socket_data.LocalPort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_LISTEN_V4_IP_LOCAL_PORT].value.uint16;
+ windivert_get_ipv4_addr(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_LISTEN_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_AUTH_LISTEN_V4_IP_LOCAL_PORT);
socket_data.RemotePort = 0;
socket_data.Protocol = IPPROTO_TCP;
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_LISTEN_V4_FLAGS].value.uint32 &
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_LISTEN_V4_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
@@ -3741,28 +3701,19 @@ static void windivert_auth_listen_v6_classify(
{
WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
- UINT8 *addr;
- INT i;
socket_data.ProcessId = (UINT32)meta_vals->processId;
- addr = (UINT8 *)&socket_data.LocalAddr;
- for (i = sizeof(socket_data.LocalAddr)-1; i >= 0; i--)
- {
- addr[sizeof(socket_data.LocalAddr)-i-1] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_LISTEN_V6_IP_LOCAL_ADDRESS]
- .value.byteArray16->byteArray16[i];
- }
- socket_data.RemoteAddr[0] = 0;
- socket_data.RemoteAddr[1] = 0;
- socket_data.RemoteAddr[2] = 0;
- socket_data.RemoteAddr[3] = 0;
- socket_data.LocalPort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_LISTEN_V6_IP_LOCAL_PORT].value.uint16;
+ windivert_get_ipv6_addr(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_LISTEN_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_AUTH_LISTEN_V6_IP_LOCAL_PORT);
socket_data.RemotePort = 0;
socket_data.Protocol = IPPROTO_TCP;
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_LISTEN_V6_FLAGS].value.uint32 &
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_LISTEN_V6_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
@@ -3783,25 +3734,21 @@ static void windivert_auth_recv_accept_v4_classify(
BOOL loopback;
socket_data.ProcessId = (UINT32)meta_vals->processId;
- socket_data.LocalAddr[0] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS].value.uint32;
- socket_data.LocalAddr[1] = 0x0000FFFF;
- socket_data.LocalAddr[2] = 0;
- socket_data.LocalAddr[3] = 0;
- socket_data.RemoteAddr[0] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS].value.uint32;
- socket_data.RemoteAddr[1] = 0x0000FFFF;
- socket_data.RemoteAddr[2] = 0;
- socket_data.RemoteAddr[3] = 0;
- socket_data.LocalPort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT].value.uint16;
- socket_data.RemotePort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT].value.uint16;
- socket_data.Protocol = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8;
+ windivert_get_ipv4_addr(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS,
+ socket_data.LocalAddr);
+ windivert_get_ipv4_addr(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS,
+ socket_data.RemoteAddr);
+ socket_data.LocalPort = windivert_get_val16(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT);
+ socket_data.RemotePort = windivert_get_val16(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT);
+ socket_data.Protocol = windivert_get_val8(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL);
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS].value.uint32 &
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
@@ -3820,33 +3767,23 @@ static void windivert_auth_recv_accept_v6_classify(
{
WINDIVERT_DATA_SOCKET socket_data;
BOOL loopback;
- UINT8 *addr;
- INT i;
socket_data.ProcessId = (UINT32)meta_vals->processId;
- addr = (UINT8 *)&socket_data.LocalAddr;
- for (i = sizeof(socket_data.LocalAddr)-1; i >= 0; i--)
- {
- addr[sizeof(socket_data.LocalAddr)-i-1] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_ADDRESS]
- .value.byteArray16->byteArray16[i];
- }
- addr = (UINT8 *)&socket_data.RemoteAddr;
- for (i = sizeof(socket_data.RemoteAddr)-1; i >= 0; i--)
- {
- addr[sizeof(socket_data.RemoteAddr)-i-1] = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_ADDRESS]
- .value.byteArray16->byteArray16[i];
- }
- socket_data.LocalPort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT].value.uint16;
- socket_data.RemotePort = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT].value.uint16;
- socket_data.Protocol = fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8;
+ windivert_get_ipv6_addr(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_ADDRESS,
+ socket_data.LocalAddr);
+ windivert_get_ipv6_addr(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_ADDRESS,
+ socket_data.RemoteAddr);
+ socket_data.LocalPort = windivert_get_val16(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_PORT);
+ socket_data.RemotePort = windivert_get_val16(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_PORT);
+ socket_data.Protocol = windivert_get_val8(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_PROTOCOL);
- loopback = ((fixed_vals->incomingValue[
- FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS].value.uint32 &
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_FLAGS) &
FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
windivert_socket_classify((context_t)filter->context,
From 3966ec12872590be86588d5e6f0df65be0afdefd Mon Sep 17 00:00:00 2001
From: basil00
Date: Tue, 30 Oct 2018 08:56:43 +0800
Subject: [PATCH 11/23] Add a WINDIVERT_FLAG_PARTIAL flag.
This suppresses ERROR_INSUFFICIENT_BUFFER errors
if the passed buffer is too small. Applications
can set this flag if they want to do partial
reads.
---
examples/windivertctl/windivertctl.c | 5 +++++
include/windivert.h | 3 ++-
include/windivert_device.h | 4 +++-
sys/windivert.c | 20 ++++++++++----------
4 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c
index 88e004d..b2abceb 100644
--- a/examples/windivertctl/windivertctl.c
+++ b/examples/windivertctl/windivertctl.c
@@ -365,6 +365,11 @@ usage:
printf("%sDEBUG", (or? "|": ""));
or = TRUE;
}
+ if ((addr.Reflect.Flags & WINDIVERT_FLAG_PARTIAL) != 0)
+ {
+ printf("%sPARTIAL", (or? "|": ""));
+ or = TRUE;
+ }
if ((addr.Reflect.Flags & WINDIVERT_FLAG_NO_INSTALL) != 0)
{
printf("%sNO_INSTALL", (or? "|": ""));
diff --git a/include/windivert.h b/include/windivert.h
index 8b1afc4..b3baab0 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -191,7 +191,8 @@ typedef enum
#define WINDIVERT_FLAG_SEND_ONLY 0x08
#define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY
#define WINDIVERT_FLAG_DEBUG 0x10
-#define WINDIVERT_FLAG_NO_INSTALL 0x20
+#define WINDIVERT_FLAG_PARTIAL 0x20
+#define WINDIVERT_FLAG_NO_INSTALL 0x40
/*
* WinDivert parameters.
diff --git a/include/windivert_device.h b/include/windivert_device.h
index f945db2..1444da8 100644
--- a/include/windivert_device.h
+++ b/include/windivert_device.h
@@ -163,7 +163,7 @@
#define WINDIVERT_FLAGS_ALL \
(WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP | WINDIVERT_FLAG_RECV_ONLY |\
WINDIVERT_FLAG_SEND_ONLY | WINDIVERT_FLAG_DEBUG | \
- WINDIVERT_FLAG_NO_INSTALL)
+ WINDIVERT_FLAG_PARTIAL | WINDIVERT_FLAG_NO_INSTALL)
#define WINDIVERT_FLAGS_EXCLUDE(flags, flag1, flag2) \
(((flags) & ((flag1) | (flag2))) != ((flag1) | (flag2)))
#define WINDIVERT_FLAGS_VALID(flags) \
@@ -171,6 +171,8 @@
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_PARTIAL, \
WINDIVERT_FLAG_SEND_ONLY))
/*
diff --git a/sys/windivert.c b/sys/windivert.c
index 24f028b..3f52a18 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -1919,7 +1919,8 @@ static NTSTATUS windivert_read(context_t context, WDFREQUEST request)
/*
* WinDivert service a single read request.
*/
-static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
+static void windivert_read_service_request(packet_t packet, BOOL partial,
+ WDFREQUEST request)
{
PMDL dst_mdl;
UINT8 *layer_data, *src, *dst;
@@ -1963,6 +1964,10 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
}
src_len = packet->packet_len;
dst_len = MmGetMdlByteCount(dst_mdl);
+ if (!partial && src_len > dst_len)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ }
dst_len = (src_len < dst_len? src_len: dst_len);
RtlCopyMemory(dst, src, dst_len);
break;
@@ -2027,14 +2032,7 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request)
windivert_read_service_request_exit:
- if (NT_SUCCESS(status))
- {
- WdfRequestCompleteWithInformation(request, status, dst_len);
- }
- else
- {
- WdfRequestComplete(request, status);
- }
+ WdfRequestCompleteWithInformation(request, status, dst_len);
}
/*
@@ -2049,6 +2047,7 @@ static void windivert_read_service(context_t context)
PVOID dst, src;
ULONG dst_len, src_len;
LONGLONG timestamp;
+ BOOL partial;
BOOL timeout;
NTSTATUS status;
packet_t packet;
@@ -2057,6 +2056,7 @@ static void windivert_read_service(context_t context)
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ partial = ((context->flags & WINDIVERT_FLAG_PARTIAL) != 0);
while (context->state == WINDIVERT_CONTEXT_STATE_OPEN &&
!IsListEmpty(&context->packet_queue))
{
@@ -2080,7 +2080,7 @@ static void windivert_read_service(context_t context)
if (!timeout)
{
- windivert_read_service_request(packet, request);
+ windivert_read_service_request(packet, partial, request);
}
windivert_free_packet(packet);
From 4f7ff8866483ce624d3fb4e28e30edcc431e13a2 Mon Sep 17 00:00:00 2001
From: basil00
Date: Sat, 3 Nov 2018 08:40:34 +0800
Subject: [PATCH 12/23] Add batched recv/send to WinDivert (#156).
This change allows multiple packets to be
received/sent at once, reducing overheads. To
exploit this feature, applications need to use
the WinDivertRecvEx()/WinDivertSendEx()
functions with the new addrLen parameter. The
passthru example has been modified to use
batching.
The DEBUG flag has been retired since it
conflicts with batching, and was not very
useful anyway.
---
dll/windivert.c | 75 ++--
examples/passthru/passthru.c | 36 +-
examples/streamdump/streamdump.c | 8 +-
examples/windivertctl/windivertctl.c | 9 +-
include/windivert.h | 27 +-
include/windivert_device.h | 20 +-
sys/windivert.c | 630 ++++++++++++++++-----------
test/test.c | 4 +-
8 files changed, 478 insertions(+), 331 deletions(-)
diff --git a/dll/windivert.c b/dll/windivert.c
index cf4d399..0a7d63c 100644
--- a/dll/windivert.c
+++ b/dll/windivert.c
@@ -79,10 +79,10 @@ static BOOLEAN WinDivertAToX(const char *str, char **endptr, UINT32 *intptr);
static BOOLEAN WinDivertUse32Bit(void);
static BOOLEAN WinDivertGetDriverFileName(LPWSTR sys_str);
static SC_HANDLE WinDivertDriverInstall(VOID);
-static BOOL WinDivertIoControl(HANDLE handle, DWORD code, UINT8 arg8,
- UINT64 arg, PVOID buf, UINT len, UINT *iolen);
-static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code, UINT8 arg8,
- UINT64 arg, PVOID buf, UINT len, UINT *iolen, LPOVERLAPPED overlapped);
+static BOOL WinDivertIoControl(HANDLE handle, DWORD code, UINT64 arg1,
+ UINT64 arg2, PVOID buf, UINT len, UINT *iolen);
+static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code, UINT64 arg1,
+ UINT64 arg2, PVOID buf, UINT len, UINT *iolen, LPOVERLAPPED overlapped);
static UINT8 WinDivertSkipExtHeaders(UINT8 proto, UINT8 **header, UINT *len);
/*
@@ -300,8 +300,8 @@ WinDivertDriverInstallExit:
/*
* Perform a DeviceIoControl.
*/
-static BOOL WinDivertIoControl(HANDLE handle, DWORD code, UINT8 arg8,
- UINT64 arg, PVOID buf, UINT len, UINT *iolen)
+static BOOL WinDivertIoControl(HANDLE handle, DWORD code, UINT64 arg1,
+ UINT64 arg2, PVOID buf, UINT len, UINT *iolen)
{
OVERLAPPED overlapped;
DWORD iolen0;
@@ -320,7 +320,7 @@ static BOOL WinDivertIoControl(HANDLE handle, DWORD code, UINT8 arg8,
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = event;
- if (!WinDivertIoControlEx(handle, code, arg8, arg, buf, len, iolen,
+ if (!WinDivertIoControlEx(handle, code, arg1, arg2, buf, len, iolen,
&overlapped))
{
if (GetLastError() != ERROR_IO_PENDING ||
@@ -339,17 +339,15 @@ static BOOL WinDivertIoControl(HANDLE handle, DWORD code, UINT8 arg8,
/*
* Perform an (overlapped) DeviceIoControl.
*/
-static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code, UINT8 arg8,
- UINT64 arg, PVOID buf, UINT len, UINT *iolen, LPOVERLAPPED overlapped)
+static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code, UINT64 arg1,
+ UINT64 arg2, PVOID buf, UINT len, UINT *iolen, LPOVERLAPPED overlapped)
{
WINDIVERT_IOCTL ioctl;
BOOL result;
DWORD iolen0;
- ioctl.version = WINDIVERT_IOCTL_VERSION;
- ioctl.magic = WINDIVERT_IOCTL_MAGIC;
- ioctl.arg8 = arg8;
- ioctl.arg = arg;
+ ioctl.arg1 = arg1;
+ ioctl.arg2 = arg2;
result = DeviceIoControl(handle, code, &ioctl, sizeof(ioctl), buf,
(DWORD)len, &iolen0, overlapped);
if (result && iolen != NULL)
@@ -454,8 +452,8 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
// Set the layer:
if (layer != WINDIVERT_LAYER_DEFAULT)
{
- if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_LAYER, 0,
- (UINT64)layer, NULL, 0, NULL))
+ if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_LAYER,
+ (UINT64)layer, 0, NULL, 0, NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
@@ -465,7 +463,7 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
// Set the flags:
if (flags != 0)
{
- if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_FLAGS, 0, flags,
+ if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_FLAGS, flags, 0,
NULL, 0, NULL))
{
CloseHandle(handle);
@@ -478,8 +476,8 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
{
// Make positive:
priority64 = (UINT64)((INT64)priority + WINDIVERT_PRIORITY_MAX);
- if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_PRIORITY, 0,
- priority64, NULL, 0, NULL))
+ if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_PRIORITY,
+ priority64, 0, NULL, 0, NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
@@ -487,8 +485,8 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
}
// Start the filter:
- if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_START_FILTER, 0,
- filter_flags, object, obj_len * sizeof(WINDIVERT_FILTER), NULL))
+ if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_START_FILTER,
+ filter_flags, 0, object, obj_len * sizeof(WINDIVERT_FILTER), NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
@@ -504,15 +502,15 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
extern BOOL WinDivertRecv(HANDLE handle, PVOID pPacket, UINT packetLen,
PWINDIVERT_ADDRESS addr, UINT *readlen)
{
- return WinDivertIoControl(handle, IOCTL_WINDIVERT_RECV, 0, (UINT64)addr,
- pPacket, packetLen, readlen);
+ return WinDivertIoControl(handle, IOCTL_WINDIVERT_RECV, (UINT64)addr,
+ (UINT64)NULL, pPacket, packetLen, readlen);
}
/*
* Receive a WinDivert packet.
*/
extern BOOL WinDivertRecvEx(HANDLE handle, PVOID pPacket, UINT packetLen,
- UINT64 flags, PWINDIVERT_ADDRESS addr, UINT *readlen,
+ UINT *readLen, UINT64 flags, PWINDIVERT_ADDRESS addr, UINT *pAddrLen,
LPOVERLAPPED overlapped)
{
if (flags != 0)
@@ -522,13 +520,14 @@ extern BOOL WinDivertRecvEx(HANDLE handle, PVOID pPacket, UINT packetLen,
}
if (overlapped == NULL)
{
- return WinDivertIoControl(handle, IOCTL_WINDIVERT_RECV, 0,
- (UINT64)addr, pPacket, packetLen, readlen);
+ return WinDivertIoControl(handle, IOCTL_WINDIVERT_RECV,
+ (UINT64)addr, (UINT64)pAddrLen, pPacket, packetLen, readLen);
}
else
{
- return WinDivertIoControlEx(handle, IOCTL_WINDIVERT_RECV, 0,
- (UINT64)addr, pPacket, packetLen, readlen, overlapped);
+ return WinDivertIoControlEx(handle, IOCTL_WINDIVERT_RECV,
+ (UINT64)addr, (UINT64)pAddrLen, pPacket, packetLen, readLen,
+ overlapped);
}
}
@@ -538,36 +537,32 @@ extern BOOL WinDivertRecvEx(HANDLE handle, PVOID pPacket, UINT packetLen,
extern BOOL WinDivertSend(HANDLE handle, PVOID pPacket, UINT packetLen,
PWINDIVERT_ADDRESS addr, UINT *writelen)
{
- if (addr == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND, 0, (UINT64)addr,
- pPacket, packetLen, writelen);
+ return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND, (UINT64)addr,
+ sizeof(WINDIVERT_ADDRESS), pPacket, packetLen, writelen);
}
/*
* Send a WinDivert packet.
*/
extern BOOL WinDivertSendEx(HANDLE handle, PVOID pPacket, UINT packetLen,
- UINT64 flags, PWINDIVERT_ADDRESS addr, UINT *writelen,
+ UINT *writeLen, UINT64 flags, PWINDIVERT_ADDRESS addr, UINT addrLen,
LPOVERLAPPED overlapped)
{
- if (flags != 0 || addr == NULL)
+ if (flags != 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (overlapped == NULL)
{
- return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND, 0,
- (UINT64)addr, pPacket, packetLen, writelen);
+ return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND,
+ (UINT64)addr, (UINT64)addrLen, pPacket, packetLen, writeLen);
}
else
{
- return WinDivertIoControlEx(handle, IOCTL_WINDIVERT_SEND, 0,
- (UINT64)addr, pPacket, packetLen, writelen, overlapped);
+ return WinDivertIoControlEx(handle, IOCTL_WINDIVERT_SEND,
+ (UINT64)addr, (UINT64)addrLen, pPacket, packetLen, writeLen,
+ overlapped);
}
}
diff --git a/examples/passthru/passthru.c b/examples/passthru/passthru.c
index 3ffd053..6491635 100644
--- a/examples/passthru/passthru.c
+++ b/examples/passthru/passthru.c
@@ -47,7 +47,10 @@
#include "windivert.h"
-#define MAXBUF 0xFFFF
+#define MAXBUF 0xFFFF
+#define MAXBATCH 0xFF
+
+static int batch = 1;
static DWORD passthru(LPVOID arg);
@@ -59,9 +62,10 @@ int __cdecl main(int argc, char **argv)
int num_threads, priority = 0, i;
HANDLE handle, thread;
- if (argc != 3 && argc != 4)
+ if (argc < 3 || argc > 5)
{
- fprintf(stderr, "usage: %s filter num-threads [priority]\n", argv[0]);
+ fprintf(stderr, "usage: %s filter num-threads [batch] [priority]\n",
+ argv[0]);
exit(EXIT_FAILURE);
}
num_threads = atoi(argv[2]);
@@ -70,9 +74,18 @@ int __cdecl main(int argc, char **argv)
fprintf(stderr, "error: invalid number of threads\n");
exit(EXIT_FAILURE);
}
- if (argc == 4)
+ if (argc >= 4)
{
- priority = atoi(argv[3]);
+ batch = atoi(argv[3]);
+ }
+ if (batch <= 0 || batch > MAXBATCH)
+ {
+ fprintf(stderr, "error: invalid batch size\n");
+ exit(EXIT_FAILURE);
+ }
+ if (argc >= 5)
+ {
+ priority = atoi(argv[4]);
}
// Divert traffic matching the filter:
@@ -112,16 +125,18 @@ int __cdecl main(int argc, char **argv)
// Passthru thread.
static DWORD passthru(LPVOID arg)
{
- unsigned char packet[MAXBUF];
- UINT packet_len;
- WINDIVERT_ADDRESS addr;
+ UINT8 packet[MAXBUF];
+ UINT packet_len, addr_len;
+ WINDIVERT_ADDRESS addr[MAXBATCH];
HANDLE handle = (HANDLE)arg;
// Main loop:
while (TRUE)
{
// Read a matching packet.
- if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len))
+ addr_len = batch * sizeof(WINDIVERT_ADDRESS);
+ if (!WinDivertRecvEx(handle, packet, sizeof(packet), &packet_len, 0,
+ addr, &addr_len, NULL))
{
fprintf(stderr, "warning: failed to read packet (%d)\n",
GetLastError());
@@ -129,7 +144,8 @@ static DWORD passthru(LPVOID arg)
}
// Re-inject the matching packet.
- if (!WinDivertSend(handle, packet, packet_len, &addr, NULL))
+ if (!WinDivertSendEx(handle, packet, packet_len, NULL, 0, addr,
+ addr_len, NULL))
{
fprintf(stderr, "warning: failed to reinject packet (%d)\n",
GetLastError());
diff --git a/examples/streamdump/streamdump.c b/examples/streamdump/streamdump.c
index 48315fa..b1010c3 100644
--- a/examples/streamdump/streamdump.c
+++ b/examples/streamdump/streamdump.c
@@ -227,8 +227,8 @@ int __cdecl main(int argc, char **argv)
memset(&overlapped, 0, sizeof(overlapped));
ResetEvent(event);
overlapped.hEvent = event;
- if (!WinDivertRecvEx(handle, packet, sizeof(packet), 0, &addr,
- &packet_len, &overlapped))
+ if (!WinDivertRecvEx(handle, packet, sizeof(packet), &packet_len, 0,
+ &addr, NULL, &overlapped))
{
if (GetLastError() != ERROR_IO_PENDING)
{
@@ -299,8 +299,8 @@ read_failed:
error("failed to allocate memory");
}
memset(poverlapped, 0, sizeof(OVERLAPPED));
- if (WinDivertSendEx(handle, packet, packet_len, 0, &addr, NULL,
- poverlapped))
+ if (WinDivertSendEx(handle, packet, packet_len, NULL, 0, &addr,
+ sizeof(WINDIVERT_ADDRESS), poverlapped))
{
continue;
}
diff --git a/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c
index b2abceb..08705cb 100644
--- a/examples/windivertctl/windivertctl.c
+++ b/examples/windivertctl/windivertctl.c
@@ -360,14 +360,9 @@ usage:
printf("%sSEND_ONLY", (or? "|": ""));
or = TRUE;
}
- if ((addr.Reflect.Flags & WINDIVERT_FLAG_DEBUG) != 0)
+ if ((addr.Reflect.Flags & WINDIVERT_FLAG_RECV_PARTIAL) != 0)
{
- printf("%sDEBUG", (or? "|": ""));
- or = TRUE;
- }
- if ((addr.Reflect.Flags & WINDIVERT_FLAG_PARTIAL) != 0)
- {
- printf("%sPARTIAL", (or? "|": ""));
+ printf("%sRECV_PARTIAL", (or? "|": ""));
or = TRUE;
}
if ((addr.Reflect.Flags & WINDIVERT_FLAG_NO_INSTALL) != 0)
diff --git a/include/windivert.h b/include/windivert.h
index b3baab0..354b4e0 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -184,15 +184,14 @@ typedef enum
/*
* WinDivert flags.
*/
-#define WINDIVERT_FLAG_SNIFF 0x01
-#define WINDIVERT_FLAG_DROP 0x02
-#define WINDIVERT_FLAG_RECV_ONLY 0x04
+#define WINDIVERT_FLAG_SNIFF 0x0001
+#define WINDIVERT_FLAG_DROP 0x0002
+#define WINDIVERT_FLAG_RECV_ONLY 0x0004
#define WINDIVERT_FLAG_READ_ONLY WINDIVERT_FLAG_RECV_ONLY
-#define WINDIVERT_FLAG_SEND_ONLY 0x08
+#define WINDIVERT_FLAG_SEND_ONLY 0x0008
#define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY
-#define WINDIVERT_FLAG_DEBUG 0x10
-#define WINDIVERT_FLAG_PARTIAL 0x20
-#define WINDIVERT_FLAG_NO_INSTALL 0x40
+#define WINDIVERT_FLAG_RECV_PARTIAL 0x0010
+#define WINDIVERT_FLAG_NO_INSTALL 0x0020
/*
* WinDivert parameters.
@@ -201,7 +200,7 @@ typedef enum
{
WINDIVERT_PARAM_QUEUE_LEN = 0, /* Packet queue length. */
WINDIVERT_PARAM_QUEUE_TIME = 1, /* Packet queue time. */
- WINDIVERT_PARAM_QUEUE_SIZE = 2 /* Packet queue size. */
+ WINDIVERT_PARAM_QUEUE_SIZE = 2, /* Packet queue size. */
} WINDIVERT_PARAM, *PWINDIVERT_PARAM;
#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_QUEUE_SIZE
@@ -224,7 +223,7 @@ extern WINDIVERTEXPORT BOOL WinDivertRecv(
__out PVOID pPacket,
__in UINT packetLen,
__out_opt PWINDIVERT_ADDRESS pAddr,
- __out_opt UINT *readLen);
+ __out_opt UINT *pReadLen);
/*
* Receive (read) a packet from a WinDivert handle.
@@ -233,9 +232,10 @@ extern WINDIVERTEXPORT BOOL WinDivertRecvEx(
__in HANDLE handle,
__out PVOID pPacket,
__in UINT packetLen,
+ __out_opt UINT *pReadLen,
__in UINT64 flags,
- __out_opt PWINDIVERT_ADDRESS pAddr,
- __out_opt UINT *readLen,
+ __out PWINDIVERT_ADDRESS pAddr,
+ __inout_opt UINT *pAddrLen,
__inout_opt LPOVERLAPPED lpOverlapped);
/*
@@ -246,7 +246,7 @@ extern WINDIVERTEXPORT BOOL WinDivertSend(
__in PVOID pPacket,
__in UINT packetLen,
__in PWINDIVERT_ADDRESS pAddr,
- __out_opt UINT *writeLen);
+ __out_opt UINT *pWriteLen);
/*
* Send (write/inject) a packet to a WinDivert handle.
@@ -255,9 +255,10 @@ extern WINDIVERTEXPORT BOOL WinDivertSendEx(
__in HANDLE handle,
__in PVOID pPacket,
__in UINT packetLen,
+ __out_opt UINT *pWriteLen,
__in UINT64 flags,
__in PWINDIVERT_ADDRESS pAddr,
- __out_opt UINT *writeLen,
+ __in UINT addrLen,
__inout_opt LPOVERLAPPED lpOverlapped);
/*
diff --git a/include/windivert_device.h b/include/windivert_device.h
index 1444da8..65e194f 100644
--- a/include/windivert_device.h
+++ b/include/windivert_device.h
@@ -59,9 +59,6 @@
#define WINDIVERT_DEVICE_NAME \
L"WinDivert" WINDIVERT_VERSION_LSTR
-#define WINDIVERT_IOCTL_VERSION 7
-#define WINDIVERT_IOCTL_MAGIC 0xC7C9
-
#define WINDIVERT_FILTER_FIELD_ZERO 0
#define WINDIVERT_FILTER_FIELD_INBOUND 1
#define WINDIVERT_FILTER_FIELD_OUTBOUND 2
@@ -162,8 +159,8 @@
*/
#define WINDIVERT_FLAGS_ALL \
(WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP | WINDIVERT_FLAG_RECV_ONLY |\
- WINDIVERT_FLAG_SEND_ONLY | WINDIVERT_FLAG_DEBUG | \
- WINDIVERT_FLAG_PARTIAL | WINDIVERT_FLAG_NO_INSTALL)
+ WINDIVERT_FLAG_SEND_ONLY | WINDIVERT_FLAG_RECV_PARTIAL | \
+ WINDIVERT_FLAG_NO_INSTALL)
#define WINDIVERT_FLAGS_EXCLUDE(flags, flag1, flag2) \
(((flags) & ((flag1) | (flag2))) != ((flag1) | (flag2)))
#define WINDIVERT_FLAGS_VALID(flags) \
@@ -172,7 +169,7 @@
WINDIVERT_FLAG_DROP) && \
WINDIVERT_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_RECV_ONLY, \
WINDIVERT_FLAG_SEND_ONLY) && \
- WINDIVERT_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_PARTIAL, \
+ WINDIVERT_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_RECV_PARTIAL, \
WINDIVERT_FLAG_SEND_ONLY))
/*
@@ -207,16 +204,19 @@
#define WINDIVERT_PARAM_QUEUE_SIZE_MAX 33554432 // 32MB
#define WINDIVERT_PARAM_QUEUE_SIZE_DEFAULT 4194304 // 4MB
+/*
+ * WinDivert batch limits.
+ */
+#define WINDIVERT_BATCH_MAX 0xFF
+
/*
* WinDivert message definitions.
*/
#pragma pack(push, 1)
typedef struct
{
- UINT16 magic; // WINDIVERT_IOCTL_MAGIC
- UINT8 version; // WINDIVERT_IOCTL_VERSION
- UINT8 arg8; // 8-bit argument
- UINT64 arg; // 64-bit argument
+ UINT64 arg1; // argument #1
+ UINT64 arg2; // argument #2
} WINDIVERT_IOCTL, *PWINDIVERT_IOCTL;
/*
diff --git a/sys/windivert.c b/sys/windivert.c
index 3f52a18..0b092c0 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -159,7 +159,7 @@ struct context_s
WDFWORKITEM workers[WINDIVERT_CONTEXT_MAXWORKERS];
// Read workers.
UINT8 worker_curr; // Current read worker.
- UINT8 layer; // Context's layer.
+ WINDIVERT_LAYER layer; // Context's layer.
UINT64 flags; // Context's flags.
UINT32 priority; // Context (internal) priority.
INT16 priority16; // Context (user) priority.
@@ -215,6 +215,8 @@ typedef struct layer_s *layer_t;
struct req_context_s
{
PWINDIVERT_ADDRESS addr; // Pointer to address structure.
+ UINT *addr_len_ptr; // Pointer to address length.
+ UINT addr_len; // Address length (in bytes).
};
typedef struct req_context_s req_context_s;
typedef struct req_context_s *req_context_t;
@@ -347,7 +349,7 @@ extern VOID windivert_cleanup(IN WDFFILEOBJECT object);
extern VOID windivert_close(IN WDFFILEOBJECT object);
extern VOID windivert_destroy(IN WDFOBJECT object);
extern NTSTATUS windivert_write(context_t context, WDFREQUEST request,
- PWINDIVERT_ADDRESS addr);
+ req_context_t req_context);
extern void NTAPI windivert_inject_complete(VOID *context,
NET_BUFFER_LIST *packets, BOOLEAN dispatch_level);
extern void NTAPI windivert_reinject_complete(VOID *context,
@@ -1919,20 +1921,33 @@ static NTSTATUS windivert_read(context_t context, WDFREQUEST request)
/*
* WinDivert service a single read request.
*/
-static void windivert_read_service_request(packet_t packet, BOOL partial,
- WDFREQUEST request)
+static void windivert_read_service_request(context_t context, packet_t packet,
+ BOOL partial, LONGLONG timestamp, WDFREQUEST request)
{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ PLIST_ENTRY entry;
PMDL dst_mdl;
UINT8 *layer_data, *src, *dst;
- ULONG dst_len, src_len;
+ ULONG dst_len, src_len, read_len;
+ BOOL timeout;
+ packet_t new_packet;
req_context_t req_context;
PWINDIVERT_ADDRESS addr;
+ UINT i, addr_len, addr_len_max;
+ UINT *addr_len_ptr;
NTSTATUS status;
+ if (request == NULL)
+ {
+ // This occurs if the packet timed out.
+ windivert_free_packet(packet);
+ return;
+ }
+
DEBUG("SERVICE: servicing read request (request=%p, packet=%p)", request,
packet);
-
- layer_data = (PVOID)packet->data;
+
+ // Get the packet and address buffers:
switch (packet->layer)
{
case WINDIVERT_LAYER_NETWORK:
@@ -1953,29 +1968,14 @@ static void windivert_read_service_request(packet_t packet, BOOL partial,
DEBUG_ERROR("failed to get address of output MDL", status);
goto windivert_read_service_request_exit;
}
-
- if (packet->layer != WINDIVERT_LAYER_REFLECT)
- {
- src = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_NETWORK, packet);
- }
- else
- {
- src = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_REFLECT, packet);
- }
- src_len = packet->packet_len;
dst_len = MmGetMdlByteCount(dst_mdl);
- if (!partial && src_len > dst_len)
- {
- status = STATUS_BUFFER_TOO_SMALL;
- }
- dst_len = (src_len < dst_len? src_len: dst_len);
- RtlCopyMemory(dst, src, dst_len);
break;
case WINDIVERT_LAYER_FLOW:
case WINDIVERT_LAYER_SOCKET:
status = STATUS_SUCCESS;
+ dst = NULL;
dst_len = 0;
break;
@@ -1985,54 +1985,144 @@ static void windivert_read_service_request(packet_t packet, BOOL partial,
goto windivert_read_service_request_exit;
}
- // Write the address information.
- req_context = windivert_req_context_get(request);
- addr = req_context->addr;
- if (addr != NULL)
+ req_context = windivert_req_context_get(request);
+ addr = req_context->addr;
+ addr_len = 0;
+ addr_len_max = (UINT)req_context->addr_len;
+ addr_len_ptr = req_context->addr_len_ptr;
+ read_len = 0;
+ i = 0;
+ while (TRUE)
{
- addr->Timestamp = (INT64)packet->timestamp;
- addr->Layer = packet->layer;
- addr->Event = packet->event;
- addr->Outbound = packet->outbound;
- addr->Loopback = packet->loopback;
- addr->Impostor = packet->impostor;
- addr->IPv6 = packet->ipv6;
- addr->PseudoIPChecksum = packet->pseudo_ip_checksum;
- addr->PseudoTCPChecksum = packet->pseudo_tcp_checksum;
- addr->PseudoUDPChecksum = packet->pseudo_udp_checksum;
- addr->Final = packet->final;
- addr->Reserved = 0;
+ // Copy the packet data:
switch (packet->layer)
{
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
- RtlCopyMemory(&addr->Network, layer_data,
+ case WINDIVERT_LAYER_REFLECT:
+
+ if (packet->layer != WINDIVERT_LAYER_REFLECT)
+ {
+ src = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_NETWORK,
+ packet);
+ }
+ else
+ {
+ src = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_REFLECT,
+ packet);
+ }
+ src_len = packet->packet_len;
+ if (!partial && src_len > dst_len)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ }
+ src_len = (src_len < dst_len? src_len: dst_len);
+ RtlCopyMemory(dst, src, src_len);
+ dst += src_len;
+ dst_len -= src_len;
+ read_len += src_len;
+ break;
+
+ default:
+ break;
+ }
+
+ // Copy the address data:
+ addr[i].Timestamp = (INT64)packet->timestamp;
+ addr[i].Layer = packet->layer;
+ addr[i].Event = packet->event;
+ addr[i].Outbound = packet->outbound;
+ addr[i].Loopback = packet->loopback;
+ addr[i].Impostor = packet->impostor;
+ addr[i].IPv6 = packet->ipv6;
+ addr[i].PseudoIPChecksum = packet->pseudo_ip_checksum;
+ addr[i].PseudoTCPChecksum = packet->pseudo_tcp_checksum;
+ addr[i].PseudoUDPChecksum = packet->pseudo_udp_checksum;
+ addr[i].Final = packet->final;
+ addr[i].Reserved = 0;
+ layer_data = (PVOID)packet->data;
+ switch (packet->layer)
+ {
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ RtlCopyMemory(&addr[i].Network, layer_data,
sizeof(WINDIVERT_DATA_NETWORK));
break;
case WINDIVERT_LAYER_FLOW:
- RtlCopyMemory(&addr->Flow, layer_data,
+ RtlCopyMemory(&addr[i].Flow, layer_data,
sizeof(WINDIVERT_DATA_FLOW));
break;
case WINDIVERT_LAYER_SOCKET:
- RtlCopyMemory(&addr->Socket, layer_data,
+ RtlCopyMemory(&addr[i].Socket, layer_data,
sizeof(WINDIVERT_DATA_SOCKET));
break;
case WINDIVERT_LAYER_REFLECT:
- RtlCopyMemory(&addr->Reflect, layer_data,
+ RtlCopyMemory(&addr[i].Reflect, layer_data,
sizeof(WINDIVERT_DATA_REFLECT));
break;
default:
break;
}
+
+ i++;
+ addr_len += sizeof(WINDIVERT_ADDRESS);
+ if (addr_len >= addr_len_max || i >= WINDIVERT_BATCH_MAX)
+ {
+ // addr[] is full:
+ break;
+ }
+ if (dst_len < sizeof(WINDIVERT_IPHDR) + sizeof(WINDIVERT_TCPHDR))
+ {
+ // Remaining space too small:
+ break;
+ }
+
+ // Attempt to fill the buffer with more packets:
+ new_packet = NULL;
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ if (context->state == WINDIVERT_CONTEXT_STATE_OPEN &&
+ !IsListEmpty(&context->packet_queue))
+ {
+ entry = RemoveHeadList(&context->packet_queue);
+ new_packet = CONTAINING_RECORD(entry, struct packet_s, entry);
+ timeout = WINDIVERT_TIMEOUT(context, new_packet->timestamp,
+ timestamp);
+ if (new_packet->packet_len > dst_len || timeout)
+ {
+ // Note: timeouts to be handled elsewhere.
+ InsertHeadList(&context->packet_queue, entry);
+ new_packet = NULL;
+ }
+ else
+ {
+ context->packet_queue_length--;
+ context->packet_queue_size -= new_packet->packet_len;
+ }
+ }
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ if (new_packet == NULL)
+ {
+ // No suitable packet:
+ break;
+ }
+
+ windivert_free_packet(packet);
+ packet = new_packet;
+ }
+
+ if (addr_len_ptr != NULL)
+ {
+ *addr_len_ptr = addr_len;
}
windivert_read_service_request_exit:
- WdfRequestCompleteWithInformation(request, status, dst_len);
+ windivert_free_packet(packet);
+ WdfRequestCompleteWithInformation(request, status, read_len);
}
/*
@@ -2043,12 +2133,8 @@ static void windivert_read_service(context_t context)
KLOCK_QUEUE_HANDLE lock_handle;
WDFREQUEST request;
PLIST_ENTRY entry;
- PMDL dst_mdl;
- PVOID dst, src;
- ULONG dst_len, src_len;
LONGLONG timestamp;
- BOOL partial;
- BOOL timeout;
+ BOOL partial, timeout;
NTSTATUS status;
packet_t packet;
req_context_t req_context;
@@ -2056,7 +2142,7 @@ static void windivert_read_service(context_t context)
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- partial = ((context->flags & WINDIVERT_FLAG_PARTIAL) != 0);
+ partial = ((context->flags & WINDIVERT_FLAG_RECV_PARTIAL) != 0);
while (context->state == WINDIVERT_CONTEXT_STATE_OPEN &&
!IsListEmpty(&context->packet_queue))
{
@@ -2078,12 +2164,9 @@ static void windivert_read_service(context_t context)
context->packet_queue_size -= packet->packet_len;
KeReleaseInStackQueuedSpinLock(&lock_handle);
- if (!timeout)
- {
- windivert_read_service_request(packet, partial, request);
- }
+ windivert_read_service_request(context, packet, partial, timestamp,
+ request);
- windivert_free_packet(packet);
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
}
@@ -2094,12 +2177,12 @@ static void windivert_read_service(context_t context)
* WinDivert write routine.
*/
static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
- PWINDIVERT_ADDRESS addr)
+ req_context_t req_context)
{
KLOCK_QUEUE_HANDLE lock_handle;
PMDL mdl = NULL, mdl_copy = NULL;
PVOID data, data_copy = NULL;
- UINT data_len;
+ UINT data_len, packet_len, inject_len;
PWINDIVERT_IPHDR ip_header;
PWINDIVERT_IPV6HDR ipv6_header;
BOOL ipv4;
@@ -2108,7 +2191,9 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
UINT64 flags, checksums;
HANDLE handle, compl_handle;
PNET_BUFFER_LIST buffers = NULL;
- NTSTATUS status = STATUS_SUCCESS;
+ PWINDIVERT_ADDRESS addr;
+ UINT i, addr_len, addr_len_max;
+ NTSTATUS status = STATUS_SUCCESS, status_soft_error = STATUS_SUCCESS;
DEBUG("WRITE: writing/injecting a packet (context=%p, request=%p)",
context, request);
@@ -2118,7 +2203,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
status = STATUS_INVALID_DEVICE_STATE;
- goto windivert_write_exit;
+ goto windivert_write_hard_error;
}
layer = context->layer;
priority = context->priority;
@@ -2129,7 +2214,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
{
status = STATUS_INVALID_PARAMETER;
DEBUG_ERROR("failed to inject; recv-only flag is set", status);
- goto windivert_write_exit;
+ goto windivert_write_hard_error;
}
switch (layer)
@@ -2139,7 +2224,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
case WINDIVERT_LAYER_REFLECT:
status = STATUS_INVALID_PARAMETER;
DEBUG_ERROR("failed to inject at layer", status);
- goto windivert_write_exit;
+ goto windivert_write_hard_error;
default:
break;
}
@@ -2148,7 +2233,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
if (!NT_SUCCESS(status))
{
DEBUG_ERROR("failed to retrieve input MDL", status);
- goto windivert_write_exit;
+ goto windivert_write_hard_error;
}
data = MmGetSystemAddressForMdlSafe(mdl,
@@ -2157,176 +2242,181 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
{
status = STATUS_INSUFFICIENT_RESOURCES;
DEBUG_ERROR("failed to get MDL address", status);
- goto windivert_write_exit;
+ goto windivert_write_hard_error;
}
- data_len = MmGetMdlByteCount(mdl);
- if (data_len > UINT16_MAX || data_len < sizeof(WINDIVERT_IPHDR))
- {
-windivert_write_bad_packet:
- status = STATUS_INVALID_PARAMETER;
- DEBUG_ERROR("failed to inject a bad packet", status);
- goto windivert_write_exit;
- }
+ data_len = MmGetMdlByteCount(mdl);
+ inject_len = 0;
+ addr = req_context->addr;
+ addr_len_max = (ULONG)req_context->addr_len;
+ addr_len = 0;
- // Copy packet data:
- data_copy = windivert_malloc(data_len, FALSE);
- if (data_copy == NULL)
+ for (i = 0; addr_len < addr_len_max && i < WINDIVERT_BATCH_MAX; i++,
+ addr_len += sizeof(WINDIVERT_ADDRESS))
{
- status = STATUS_INSUFFICIENT_RESOURCES;
- DEBUG_ERROR("failed to allocate memory for injected packet data",
- status);
- goto windivert_write_exit;
- }
- RtlCopyMemory(data_copy, data, sizeof(WINDIVERT_IPHDR));
- ip_header = (PWINDIVERT_IPHDR)data_copy;
- switch (ip_header->Version)
- {
- case 4:
- if (data_len != RtlUshortByteSwap(ip_header->Length))
- {
- goto windivert_write_bad_packet;
- }
- ipv4 = TRUE;
- break;
- case 6:
- if (data_len < sizeof(WINDIVERT_IPV6HDR))
- {
- goto windivert_write_bad_packet;
- }
- ipv6_header = (PWINDIVERT_IPV6HDR)data_copy;
- if (data_len != RtlUshortByteSwap(ipv6_header->Length) +
- sizeof(WINDIVERT_IPV6HDR))
- {
- goto windivert_write_bad_packet;
- }
- ipv4 = FALSE;
- break;
- default:
- goto windivert_write_bad_packet;
- }
- if (data_len > sizeof(WINDIVERT_IPHDR))
- {
- RtlCopyMemory((char *)data_copy + sizeof(WINDIVERT_IPHDR),
- (char *)data + sizeof(WINDIVERT_IPHDR),
- data_len - sizeof(WINDIVERT_IPHDR));
- }
-
- // Fix checksums:
- if (addr->PseudoIPChecksum != 0 || addr->PseudoTCPChecksum != 0 ||
- addr->PseudoUDPChecksum != 0)
- {
- checksums =
- (addr->PseudoIPChecksum? 0: WINDIVERT_HELPER_NO_IP_CHECKSUM) |
- (addr->PseudoTCPChecksum? 0: WINDIVERT_HELPER_NO_TCP_CHECKSUM) |
- (addr->PseudoUDPChecksum? 0: WINDIVERT_HELPER_NO_UDP_CHECKSUM);
- WinDivertHelperCalcChecksums(data_copy, data_len, NULL, checksums);
- }
-
- // Decrement TTL for impostor packets:
- if (addr->Impostor && !windivert_decrement_ttl(data_copy, ipv4))
- {
- status = STATUS_HOPLIMIT_EXCEEDED;
- goto windivert_write_exit;
- }
-
- // Allocate packet:
- mdl_copy = IoAllocateMdl(data_copy, data_len, FALSE, FALSE, NULL);
- if (mdl_copy == NULL)
- {
- status = STATUS_INSUFFICIENT_RESOURCES;
- DEBUG_ERROR("failed to allocate MDL for injected packet", status);
- goto windivert_write_exit;
- }
- MmBuildMdlForNonPagedPool(mdl_copy);
- status = FwpsAllocateNetBufferAndNetBufferList0(nbl_pool_handle, 0, 0,
- mdl_copy, 0, data_len, &buffers);
- if (!NT_SUCCESS(status))
- {
- DEBUG_ERROR("failed to create NET_BUFFER_LIST for injected packet",
- status);
- goto windivert_write_exit;
- }
-
- // Inject packet:
- handle = (ipv4? inject_handle: injectv6_handle);
- compl_handle = ((flags & WINDIVERT_FLAG_DEBUG) != 0? (HANDLE)request: NULL);
- if (layer == WINDIVERT_LAYER_NETWORK_FORWARD)
- {
- status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0,
- (ipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID,
- addr->Network.IfIdx, buffers, windivert_inject_complete,
- compl_handle);
- }
- else if (addr->Outbound != 0)
- {
- status = FwpsInjectNetworkSendAsync0(handle, (HANDLE)priority, 0,
- UNSPECIFIED_COMPARTMENT_ID, buffers, windivert_inject_complete,
- compl_handle);
- }
- else
- {
- status = FwpsInjectNetworkReceiveAsync0(handle, (HANDLE)priority, 0,
- UNSPECIFIED_COMPARTMENT_ID, addr->Network.IfIdx,
- addr->Network.SubIfIdx, buffers, windivert_inject_complete,
- compl_handle);
- }
-
-windivert_write_exit:
-
- if (NT_SUCCESS(status))
- {
- if ((flags & WINDIVERT_FLAG_DEBUG) == 0)
+ buffers = NULL;
+ mdl_copy = NULL;
+ data_copy = NULL;
+
+ // Get the packet length:
+ if (data_len < sizeof(WINDIVERT_IPHDR))
{
- WdfRequestCompleteWithInformation(request, status, data_len);
+windivert_write_too_small_packet:
+ status = STATUS_BUFFER_TOO_SMALL;
+ DEBUG_ERROR("failed to inject partial packet", status);
+ goto windivert_write_hard_error;
}
- }
- else
- {
- // Request completed in windivert_ioctl()
- if (buffers != NULL)
+ ip_header = (PWINDIVERT_IPHDR)data;
+ switch (ip_header->Version)
{
+ case 4:
+ packet_len = RtlUshortByteSwap(ip_header->Length);
+ ipv4 = TRUE;
+ break;
+ case 6:
+ if (data_len < sizeof(WINDIVERT_IPV6HDR))
+ {
+ goto windivert_write_too_small_packet;
+ }
+ ipv6_header = (PWINDIVERT_IPV6HDR)data;
+ packet_len = RtlUshortByteSwap(ipv6_header->Length) +
+ sizeof(WINDIVERT_IPV6HDR);
+ ipv4 = FALSE;
+ break;
+ default:
+ status = STATUS_INVALID_PARAMETER;
+ DEBUG_ERROR("failed to inject non-IP packet", status);
+ goto windivert_write_hard_error;
+ }
+ if (data_len < packet_len)
+ {
+ goto windivert_write_too_small_packet;
+ }
+
+ // Copy packet data:
+ data_copy = windivert_malloc(packet_len, FALSE);
+ if (data_copy == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ DEBUG_ERROR("failed to allocate memory for injected packet data",
+ status);
+ goto windivert_write_hard_error;
+ }
+ RtlCopyMemory(data_copy, data, packet_len);
+
+ // Fix checksums:
+ if (addr[i].PseudoIPChecksum != 0 || addr[i].PseudoTCPChecksum != 0 ||
+ addr[i].PseudoUDPChecksum != 0)
+ {
+ checksums =
+ (addr[i].PseudoIPChecksum? 0:
+ WINDIVERT_HELPER_NO_IP_CHECKSUM) |
+ (addr[i].PseudoTCPChecksum? 0:
+ WINDIVERT_HELPER_NO_TCP_CHECKSUM) |
+ (addr[i].PseudoUDPChecksum? 0:
+ WINDIVERT_HELPER_NO_UDP_CHECKSUM);
+ WinDivertHelperCalcChecksums(data_copy, packet_len, NULL,
+ checksums);
+ }
+
+ // Decrement TTL for impostor packets:
+ if (addr[i].Impostor && !windivert_decrement_ttl(data_copy, ipv4))
+ {
+ status_soft_error = STATUS_HOPLIMIT_EXCEEDED;
+ windivert_free(data_copy);
+ goto windivert_write_loop;
+ }
+
+ // Allocate packet:
+ mdl_copy = IoAllocateMdl(data_copy, packet_len, FALSE, FALSE, NULL);
+ if (mdl_copy == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ DEBUG_ERROR("failed to allocate MDL for injected packet", status);
+ goto windivert_write_hard_error;
+ }
+ MmBuildMdlForNonPagedPool(mdl_copy);
+ status = FwpsAllocateNetBufferAndNetBufferList0(nbl_pool_handle, 0, 0,
+ mdl_copy, 0, packet_len, &buffers);
+ if (!NT_SUCCESS(status))
+ {
+ DEBUG_ERROR("failed to create NET_BUFFER_LIST for injected packet",
+ status);
+ goto windivert_write_hard_error;
+ }
+
+ // Inject packet:
+ handle = (ipv4? inject_handle: injectv6_handle);
+ if (layer == WINDIVERT_LAYER_NETWORK_FORWARD)
+ {
+ status = FwpsInjectForwardAsync0(handle, (HANDLE)priority, 0,
+ (ipv4? AF_INET: AF_INET6), UNSPECIFIED_COMPARTMENT_ID,
+ addr[i].Network.IfIdx, buffers, windivert_inject_complete,
+ data_copy);
+ }
+ else if (addr[i].Outbound != 0)
+ {
+ status = FwpsInjectNetworkSendAsync0(handle, (HANDLE)priority, 0,
+ UNSPECIFIED_COMPARTMENT_ID, buffers, windivert_inject_complete,
+ data_copy);
+ }
+ else
+ {
+ status = FwpsInjectNetworkReceiveAsync0(handle, (HANDLE)priority, 0,
+ UNSPECIFIED_COMPARTMENT_ID, addr[i].Network.IfIdx,
+ addr[i].Network.SubIfIdx, buffers, windivert_inject_complete,
+ data_copy);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ status_soft_error = status;
FwpsFreeNetBufferList0(buffers);
- }
- if (mdl_copy != NULL)
- {
IoFreeMdl(mdl_copy);
+ windivert_free(data_copy);
}
- windivert_free(data_copy);
+
+windivert_write_loop:
+
+ // Reset state:
+ inject_len += packet_len;
+ data = (PVOID)((UINT8 *)data + packet_len);
+ data_len -= packet_len;
}
+ // Note: status_soft_error is for "soft" errors that do not prevent other
+ // batched packets from being injected.
+ WdfRequestCompleteWithInformation(request, status_soft_error, inject_len);
+ return STATUS_SUCCESS;
+
+windivert_write_hard_error:
+
+ // Request to be completed in windivert_ioctl()
+ if (buffers != NULL)
+ {
+ FwpsFreeNetBufferList0(buffers);
+ }
+ if (mdl_copy != NULL)
+ {
+ IoFreeMdl(mdl_copy);
+ }
+ windivert_free(data_copy);
+
return status;
}
/*
* WinDivert inject complete routine.
*/
-static void NTAPI windivert_inject_complete(VOID *context,
+static void NTAPI windivert_inject_complete(VOID *data,
NET_BUFFER_LIST *buffers, BOOLEAN dispatch_level)
{
PMDL mdl;
- PVOID data;
PNET_BUFFER buffer;
- size_t length;
- WDFREQUEST request;
- NTSTATUS status;
UNREFERENCED_PARAMETER(dispatch_level);
buffer = NET_BUFFER_LIST_FIRST_NB(buffers);
- request = (WDFREQUEST)context;
- if (request != NULL)
- {
- status = NET_BUFFER_LIST_STATUS(buffers);
- length = 0;
- if (NT_SUCCESS(status))
- {
- length = NET_BUFFER_DATA_LENGTH(buffer);
- }
- WdfRequestCompleteWithInformation(request, status, length);
- }
mdl = NET_BUFFER_FIRST_MDL(buffer);
- data = MmGetSystemAddressForMdlSafe(mdl,
- NormalPagePriority | no_exec_flag);
windivert_free(data);
IoFreeMdl(mdl);
FwpsFreeNetBufferList0(buffers);
@@ -2340,7 +2430,6 @@ static void NTAPI windivert_reinject_complete(VOID *context,
{
PMDL mdl;
PNET_BUFFER buffer;
- size_t length;
packet_t packet;
UNREFERENCED_PARAMETER(dispatch_level);
@@ -2362,6 +2451,8 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
WDF_REQUEST_PARAMETERS params;
WDFMEMORY memobj;
PWINDIVERT_ADDRESS addr = NULL;
+ UINT *addr_len_ptr = NULL;
+ UINT64 addr_len = 0;
PWINDIVERT_IOCTL ioctl;
WDF_OBJECT_ATTRIBUTES attributes;
req_context_t req_context = NULL;
@@ -2390,16 +2481,6 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
goto windivert_caller_context_error;
}
- ioctl = (PWINDIVERT_IOCTL)inbuf;
- if (ioctl->version != WINDIVERT_IOCTL_VERSION ||
- ioctl->magic != WINDIVERT_IOCTL_MAGIC)
- {
- status = STATUS_INVALID_PARAMETER;
- DEBUG_ERROR("input buffer contained a bad ioctl message header",
- status);
- goto windivert_caller_context_error;
- }
-
// Probe and lock user buffers here (if required).
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, req_context_s);
status = WdfObjectAllocateContext(request, &attributes, &req_context);
@@ -2411,34 +2492,71 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
switch (params.Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_WINDIVERT_RECV:
- if ((PVOID)ioctl->arg == NULL)
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
+ addr = (PWINDIVERT_ADDRESS)ioctl->arg1;
+ addr_len_ptr = (UINT *)ioctl->arg2;
+ addr_len = sizeof(WINDIVERT_ADDRESS);
+ if (addr_len_ptr != NULL)
+ {
+ status = WdfRequestProbeAndLockUserBufferForWrite(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;
+ }
+ addr_len_ptr = (UINT *)WdfMemoryGetBuffer(memobj, NULL);
+ addr_len = *addr_len_ptr;
+ if (addr_len < sizeof(WINDIVERT_ADDRESS) ||
+ addr_len > WINDIVERT_BATCH_MAX * sizeof(WINDIVERT_ADDRESS))
+ {
+ status = STATUS_INVALID_PARAMETER;
+ DEBUG_ERROR("out-of-range address length for RECV ioctl",
+ status);
+ goto windivert_caller_context_error;
+ }
+ }
+ if (addr == NULL)
{
status = STATUS_INVALID_PARAMETER;
- DEBUG_ERROR("null arg pointer for RECV ioctl", status);
+ DEBUG_ERROR("null address for RECV ioctl", status);
goto windivert_caller_context_error;
}
- status = WdfRequestProbeAndLockUserBufferForWrite(request,
- (PVOID)ioctl->arg, sizeof(WINDIVERT_ADDRESS), &memobj);
+ status = WdfRequestProbeAndLockUserBufferForWrite(request, addr,
+ addr_len, &memobj);
if (!NT_SUCCESS(status))
{
- DEBUG_ERROR("invalid arg pointer for RECV ioctl", status);
+ DEBUG_ERROR("invalid address for RECV ioctl", status);
goto windivert_caller_context_error;
}
addr = (PWINDIVERT_ADDRESS)WdfMemoryGetBuffer(memobj, NULL);
break;
case IOCTL_WINDIVERT_SEND:
- if ((PVOID)ioctl->arg == NULL)
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
+ addr = (PWINDIVERT_ADDRESS)ioctl->arg1;
+ addr_len = ioctl->arg2;
+ if (addr_len < sizeof(WINDIVERT_ADDRESS) ||
+ addr_len > WINDIVERT_BATCH_MAX * sizeof(WINDIVERT_ADDRESS))
{
status = STATUS_INVALID_PARAMETER;
- DEBUG_ERROR("null arg pointer for SEND ioctl", status);
+ DEBUG_ERROR("out-of-range address length for RECV ioctl",
+ status);
goto windivert_caller_context_error;
}
- status = WdfRequestProbeAndLockUserBufferForRead(request,
- (PVOID)ioctl->arg, sizeof(WINDIVERT_ADDRESS), &memobj);
+ if (addr == NULL)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ DEBUG_ERROR("null address for SEND ioctl", status);
+ goto windivert_caller_context_error;
+ }
+ status = WdfRequestProbeAndLockUserBufferForRead(request, addr,
+ addr_len, &memobj);
if (!NT_SUCCESS(status))
{
- DEBUG_ERROR("invalid arg pointer for SEND ioctl", status);
+ DEBUG_ERROR("invalid address for SEND ioctl", status);
goto windivert_caller_context_error;
}
addr = (PWINDIVERT_ADDRESS)WdfMemoryGetBuffer(memobj, NULL);
@@ -2459,7 +2577,9 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
goto windivert_caller_context_error;
}
- req_context->addr = addr;
+ req_context->addr = addr;
+ req_context->addr_len = (UINT)addr_len;
+ req_context->addr_len_ptr = addr_len_ptr;
windivert_caller_context_exit:
@@ -2488,10 +2608,7 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
PWINDIVERT_FILTER filter;
UINT8 layer;
INT16 priority;
- UINT32 priority32;
- INT64 priority64;
UINT64 flags;
- PWINDIVERT_ADDRESS addr;
req_context_t req_context;
NTSTATUS status = STATUS_SUCCESS;
context_t context =
@@ -2539,8 +2656,7 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
case IOCTL_WINDIVERT_SEND:
req_context = windivert_req_context_get(request);
- addr = req_context->addr;
- status = windivert_write(context, request, addr);
+ status = windivert_write(context, request, req_context);
if (NT_SUCCESS(status))
{
return;
@@ -2552,11 +2668,13 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
BOOL inbound, outbound, ipv4, ipv6;
PIRP irp;
LONGLONG timestamp;
+ UINT64 filter_flags;
UINT32 process_id;
UINT8 filter_len;
ioctl = (PWINDIVERT_IOCTL)inbuf;
- if ((ioctl->arg & ~WINDIVERT_FILTER_FLAGS_ALL) != 0)
+ filter_flags = ioctl->arg1;
+ if ((filter_flags & ~WINDIVERT_FILTER_FLAGS_ALL) != 0)
{
status = STATUS_INVALID_PARAMETER;
DEBUG_ERROR("failed to start filter; invalid flags", status);
@@ -2630,15 +2748,18 @@ windivert_ioctl_bad_start_state:
windivert_reflect_open_event(context);
- flags = ioctl->arg;
- status = windivert_install_callouts(context, layer, flags);
+ status = windivert_install_callouts(context, layer, filter_flags);
break;
}
case IOCTL_WINDIVERT_SET_LAYER:
+ {
+ UINT64 layer;
+
ioctl = (PWINDIVERT_IOCTL)inbuf;
- switch (ioctl->arg)
+ layer = ioctl->arg1;
+ switch (layer)
{
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
@@ -2651,7 +2772,6 @@ windivert_ioctl_bad_start_state:
DEBUG_ERROR("failed to set layer; invalid value", status);
goto windivert_ioctl_exit;
}
- layer = (UINT8)ioctl->arg;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
{
@@ -2659,13 +2779,18 @@ windivert_ioctl_bad_start_state:
status = STATUS_INVALID_DEVICE_STATE;
goto windivert_ioctl_exit;
}
- context->layer = layer;
+ context->layer = (WINDIVERT_LAYER)layer;
KeReleaseInStackQueuedSpinLock(&lock_handle);
break;
+ }
case IOCTL_WINDIVERT_SET_PRIORITY:
+ {
+ UINT32 priority32;
+ INT64 priority64;
+
ioctl = (PWINDIVERT_IOCTL)inbuf;
- priority64 = (INT64)ioctl->arg - WINDIVERT_PRIORITY_MAX;
+ priority64 = (INT64)ioctl->arg1 - WINDIVERT_PRIORITY_MAX;
if (priority64 < WINDIVERT_PRIORITY_MIN ||
priority64 > WINDIVERT_PRIORITY_MAX)
{
@@ -2686,17 +2811,21 @@ windivert_ioctl_bad_start_state:
context->priority = priority32;
KeReleaseInStackQueuedSpinLock(&lock_handle);
break;
+ }
case IOCTL_WINDIVERT_SET_FLAGS:
+ {
+ UINT64 flags;
+
ioctl = (PWINDIVERT_IOCTL)inbuf;
- if (!WINDIVERT_FLAGS_VALID(ioctl->arg))
+ flags = ioctl->arg1;
+ if (!WINDIVERT_FLAGS_VALID(flags))
{
status = STATUS_INVALID_PARAMETER;
DEBUG_ERROR("failed to set flags; invalid flags value",
status);
goto windivert_ioctl_exit;
}
- flags = ioctl->arg;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
{
@@ -2707,10 +2836,15 @@ windivert_ioctl_bad_start_state:
context->flags = flags;
KeReleaseInStackQueuedSpinLock(&lock_handle);
break;
+ }
case IOCTL_WINDIVERT_SET_PARAM:
+ {
+ UINT64 param, value;
+
ioctl = (PWINDIVERT_IOCTL)inbuf;
- value = ioctl->arg;
+ param = ioctl->arg1;
+ value = ioctl->arg2;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
{
@@ -2718,7 +2852,7 @@ windivert_ioctl_bad_start_state:
status = STATUS_INVALID_DEVICE_STATE;
goto windivert_ioctl_exit;
}
- switch ((WINDIVERT_PARAM)ioctl->arg8)
+ switch (param)
{
case WINDIVERT_PARAM_QUEUE_LEN:
if (value < WINDIVERT_PARAM_QUEUE_LEN_MIN ||
@@ -2770,9 +2904,14 @@ windivert_ioctl_bad_start_state:
}
KeReleaseInStackQueuedSpinLock(&lock_handle);
break;
+ }
case IOCTL_WINDIVERT_GET_PARAM:
+ {
+ UINT64 param;
+
ioctl = (PWINDIVERT_IOCTL)inbuf;
+ param = ioctl->arg1;
if (outbuflen != sizeof(UINT64))
{
status = STATUS_INVALID_PARAMETER;
@@ -2788,7 +2927,7 @@ windivert_ioctl_bad_start_state:
status = STATUS_INVALID_DEVICE_STATE;
goto windivert_ioctl_exit;
}
- switch ((WINDIVERT_PARAM)ioctl->arg8)
+ switch (param)
{
case WINDIVERT_PARAM_QUEUE_LEN:
*valptr = context->packet_queue_maxlength;
@@ -2808,6 +2947,7 @@ windivert_ioctl_bad_start_state:
}
KeReleaseInStackQueuedSpinLock(&lock_handle);
break;
+ }
default:
status = STATUS_INVALID_DEVICE_REQUEST;
diff --git a/test/test.c b/test/test.c
index aab5ed0..ed8b590 100644
--- a/test/test.c
+++ b/test/test.c
@@ -319,7 +319,7 @@ int main(void)
// (1) stop normal traffic from interacting with the tests; and
// (2) stop test packets escaping to the Internet or TCP/IP stack.
upper_handle = WinDivertOpen("true", WINDIVERT_LAYER_NETWORK, -510,
- WINDIVERT_FLAG_DROP | WINDIVERT_FLAG_DEBUG);
+ WINDIVERT_FLAG_DROP);
lower_handle = WinDivertOpen("true", WINDIVERT_LAYER_NETWORK, 510,
WINDIVERT_FLAG_DROP);
if (upper_handle == INVALID_HANDLE_VALUE ||
@@ -468,7 +468,7 @@ static BOOL run_test(HANDLE inject_handle, const char *filter,
goto failed;
}
overlapped.hEvent = event;
- if (!WinDivertRecvEx(handle, buf, sizeof(buf), 0, &addr, &buf_len,
+ if (!WinDivertRecvEx(handle, buf, sizeof(buf), &buf_len, 0, &addr, NULL,
&overlapped))
{
if (GetLastError() != ERROR_IO_PENDING)
From 1ccf4861322bed3b18c2405ed9aab313bd9bdd0b Mon Sep 17 00:00:00 2001
From: basil00
Date: Sun, 4 Nov 2018 08:47:39 +0800
Subject: [PATCH 13/23] Calculate full checksums for reinjected packets.
---
examples/passthru/passthru.c | 2 +-
sys/windivert.c | 33 ++++++++++++++++++++++++++++++---
2 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/examples/passthru/passthru.c b/examples/passthru/passthru.c
index 6491635..dc56824 100644
--- a/examples/passthru/passthru.c
+++ b/examples/passthru/passthru.c
@@ -47,7 +47,7 @@
#include "windivert.h"
-#define MAXBUF 0xFFFF
+#define MAXBUF 400000
#define MAXBATCH 0xFF
static int batch = 1;
diff --git a/sys/windivert.c b/sys/windivert.c
index 0b092c0..4f2e817 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -4285,6 +4285,7 @@ static void windivert_reinject_packet(packet_t packet)
{
UINT8 *packet_data;
UINT32 packet_len;
+ UINT64 checksums;
PWINDIVERT_DATA_NETWORK network_data;
PMDL mdl;
PNET_BUFFER_LIST buffers;
@@ -4302,11 +4303,37 @@ static void windivert_reinject_packet(packet_t packet)
network_data = (PWINDIVERT_DATA_NETWORK)WINDIVERT_LAYER_DATA_PTR(packet);
packet_data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_NETWORK, packet);
packet_len = packet->packet_len;
+
+ // Fix checksums:
+ if (packet->pseudo_ip_checksum != 0 || packet->pseudo_tcp_checksum != 0 ||
+ packet->pseudo_udp_checksum != 0)
+ {
+ checksums =
+ (packet->pseudo_ip_checksum != 0? 0:
+ WINDIVERT_HELPER_NO_IP_CHECKSUM) |
+ (packet->pseudo_tcp_checksum != 0? 0:
+ WINDIVERT_HELPER_NO_TCP_CHECKSUM) |
+ (packet->pseudo_udp_checksum != 0? 0:
+ WINDIVERT_HELPER_NO_UDP_CHECKSUM);
+ WinDivertHelperCalcChecksums(packet_data, packet_len, NULL, checksums);
+ }
+
+ // Decrement TTL for impostor packets:
+ if (packet->impostor != 0 && !windivert_decrement_ttl(packet_data,
+ packet->ipv6 == 0))
+ {
+ status = STATUS_HOPLIMIT_EXCEEDED;
+ DEBUG_ERROR("failed to reinject ttl-exceeded impostor packet", status);
+ windivert_free_packet(packet);
+ return;
+ }
+
+ // Reinject packet:
mdl = IoAllocateMdl(packet_data, packet_len, FALSE, FALSE, NULL);
if (mdl == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
- DEBUG_ERROR("failed to allocate MDL for injected packet", status);
+ DEBUG_ERROR("failed to allocate MDL for reinjected packet", status);
windivert_free_packet(packet);
return;
}
@@ -4315,7 +4342,7 @@ static void windivert_reinject_packet(packet_t packet)
mdl, 0, packet_len, &buffers);
if (!NT_SUCCESS(status))
{
- DEBUG_ERROR("failed to create NET_BUFFER_LIST for injected packet",
+ DEBUG_ERROR("failed to create NET_BUFFER_LIST for reinjected packet",
status);
IoFreeMdl(mdl);
windivert_free_packet(packet);
@@ -4346,7 +4373,7 @@ static void windivert_reinject_packet(packet_t packet)
if (!NT_SUCCESS(status))
{
- DEBUG_ERROR("failed to re-inject (packet=%p)", status, packet);
+ DEBUG_ERROR("failed to reinject (packet=%p)", status, packet);
FwpsFreeNetBufferList0(buffers);
IoFreeMdl(mdl);
windivert_free_packet(packet);
From 3e40705178482c9f7a94e411e814b1ee3d89484a Mon Sep 17 00:00:00 2001
From: basil00
Date: Mon, 5 Nov 2018 09:44:25 +0800
Subject: [PATCH 14/23] Fix address formatting in sample programs.
---
examples/netdump/netdump.c | 52 ++++++++++++++++++----------------
examples/netfilter/netfilter.c | 46 +++++++++++++++++-------------
2 files changed, 54 insertions(+), 44 deletions(-)
diff --git a/examples/netdump/netdump.c b/examples/netdump/netdump.c
index c07f2ef..db7aaf5 100644
--- a/examples/netdump/netdump.c
+++ b/examples/netdump/netdump.c
@@ -52,6 +52,18 @@
#define MAXBUF 0xFFFF
#define INET6_ADDRSTRLEN 45
+/*
+ * IPv6 address byte swap.
+ */
+void byteswap128(UINT32 *dst_addr, const UINT32 *src_addr)
+{
+ int i;
+ for (i = 0; i < 4; i++)
+ {
+ dst_addr[i] = ntohl(src_addr[4-i-1]);
+ }
+}
+
/*
* Entry.
*/
@@ -69,6 +81,7 @@ int __cdecl main(int argc, char **argv)
PWINDIVERT_ICMPV6HDR icmpv6_header;
PWINDIVERT_TCPHDR tcp_header;
PWINDIVERT_UDPHDR udp_header;
+ UINT32 src_addr[4], dst_addr[4];
char src_str[INET6_ADDRSTRLEN+1], dst_str[INET6_ADDRSTRLEN+1];
const char *err_str;
LARGE_INTEGER base, freq;
@@ -162,8 +175,10 @@ int __cdecl main(int argc, char **argv)
addr.Network.IfIdx, addr.Network.SubIfIdx, addr.Loopback);
if (ip_header != NULL)
{
- UINT8 *src_addr = (UINT8 *)&ip_header->SrcAddr;
- UINT8 *dst_addr = (UINT8 *)&ip_header->DstAddr;
+ WinDivertHelperFormatIPv4Address(ntohl(ip_header->SrcAddr),
+ src_str, sizeof(src_str));
+ WinDivertHelperFormatIPv4Address(ntohl(ip_header->DstAddr),
+ dst_str, sizeof(dst_str));
SetConsoleTextAttribute(console,
FOREGROUND_GREEN | FOREGROUND_RED);
printf("IPv4 [Version=%u HdrLength=%u TOS=%u Length=%u Id=0x%.4X "
@@ -175,40 +190,27 @@ int __cdecl main(int argc, char **argv)
WINDIVERT_IPHDR_GET_DF(ip_header),
WINDIVERT_IPHDR_GET_MF(ip_header),
ntohs(WINDIVERT_IPHDR_GET_FRAGOFF(ip_header)), ip_header->TTL,
- ip_header->Protocol, ntohs(ip_header->Checksum));
- WinDivertHelperFormatIPv4Address(ntohl(ip_header->SrcAddr),
- src_str, sizeof(src_str));
- WinDivertHelperFormatIPv4Address(ntohl(ip_header->DstAddr),
- dst_str, sizeof(dst_str));
+ ip_header->Protocol, ntohs(ip_header->Checksum), src_str,
+ dst_str);
}
if (ipv6_header != NULL)
{
- UINT16 *src_addr = (UINT16 *)&ipv6_header->SrcAddr;
- UINT16 *dst_addr = (UINT16 *)&ipv6_header->DstAddr;
+ byteswap128(src_addr, ipv6_header->SrcAddr);
+ byteswap128(dst_addr, ipv6_header->DstAddr);
+ WinDivertHelperFormatIPv6Address(src_addr, src_str,
+ sizeof(src_str));
+ WinDivertHelperFormatIPv6Address(dst_addr, dst_str,
+ sizeof(dst_str));
SetConsoleTextAttribute(console,
FOREGROUND_GREEN | FOREGROUND_RED);
printf("IPv6 [Version=%u TrafficClass=%u FlowLabel=%u Length=%u "
- "NextHdr=%u HopLimit=%u SrcAddr=",
+ "NextHdr=%u HopLimit=%u SrcAddr=%s DstAddr=%s]\n",
ipv6_header->Version,
WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(ipv6_header),
ntohl(WINDIVERT_IPV6HDR_GET_FLOWLABEL(ipv6_header)),
ntohs(ipv6_header->Length), ipv6_header->NextHdr,
- ipv6_header->HopLimit);
- for (i = 0; i < 8; i++)
- {
- printf("%x%c", ntohs(src_addr[i]), (i == 7? ' ': ':'));
- }
- fputs("DstAddr=", stdout);
- for (i = 0; i < 8; i++)
- {
- printf("%x", ntohs(dst_addr[i]));
- if (i != 7)
- {
- putchar(':');
- }
- }
- fputs("]\n", stdout);
+ ipv6_header->HopLimit, src_str, dst_str);
}
if (icmp_header != NULL)
{
diff --git a/examples/netfilter/netfilter.c b/examples/netfilter/netfilter.c
index f898191..2377be6 100644
--- a/examples/netfilter/netfilter.c
+++ b/examples/netfilter/netfilter.c
@@ -55,7 +55,8 @@
#include "windivert.h"
-#define MAXBUF 0xFFFF
+#define MAXBUF 0xFFFF
+#define INET6_ADDRSTRLEN 45
/*
* Pre-fabricated packets.
@@ -96,6 +97,18 @@ static void PacketIpv6Init(PWINDIVERT_IPV6HDR packet);
static void PacketIpv6TcpInit(PTCPV6PACKET packet);
static void PacketIpv6Icmpv6Init(PICMPV6PACKET packet);
+/*
+ * IPv6 address byte swap.
+ */
+void byteswap128(UINT32 *dst_addr, const UINT32 *src_addr)
+{
+ int i;
+ for (i = 0; i < 4; i++)
+ {
+ dst_addr[i] = ntohl(src_addr[4-i-1]);
+ }
+}
+
/*
* Entry.
*/
@@ -113,6 +126,8 @@ int __cdecl main(int argc, char **argv)
PWINDIVERT_ICMPV6HDR icmpv6_header;
PWINDIVERT_TCPHDR tcp_header;
PWINDIVERT_UDPHDR udp_header;
+ UINT32 src_addr[4], dst_addr[4];
+ char src_str[INET6_ADDRSTRLEN+1], dst_str[INET6_ADDRSTRLEN+1];
UINT payload_len;
const char *err_str;
@@ -208,28 +223,21 @@ int __cdecl main(int argc, char **argv)
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
if (ip_header != NULL)
{
- UINT8 *src_addr = (UINT8 *)&ip_header->SrcAddr;
- UINT8 *dst_addr = (UINT8 *)&ip_header->DstAddr;
- printf("ip.SrcAddr=%u.%u.%u.%u ip.DstAddr=%u.%u.%u.%u ",
- src_addr[0], src_addr[1], src_addr[2], src_addr[3],
- dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3]);
+ WinDivertHelperFormatIPv4Address(ntohl(ip_header->SrcAddr),
+ src_str, sizeof(src_str));
+ WinDivertHelperFormatIPv4Address(ntohl(ip_header->DstAddr),
+ dst_str, sizeof(dst_str));
}
if (ipv6_header != NULL)
{
- UINT16 *src_addr = (UINT16 *)&ipv6_header->SrcAddr;
- UINT16 *dst_addr = (UINT16 *)&ipv6_header->DstAddr;
- fputs("ipv6.SrcAddr=", stdout);
- for (i = 0; i < 8; i++)
- {
- printf("%x%c", ntohs(src_addr[i]), (i == 7? ' ': ':'));
- }
- fputs(" ipv6.DstAddr=", stdout);
- for (i = 0; i < 8; i++)
- {
- printf("%x%c", ntohs(dst_addr[i]), (i == 7? ' ': ':'));
- }
- putchar(' ');
+ byteswap128(src_addr, ipv6_header->SrcAddr);
+ byteswap128(dst_addr, ipv6_header->DstAddr);
+ WinDivertHelperFormatIPv6Address(src_addr, src_str,
+ sizeof(src_str));
+ WinDivertHelperFormatIPv6Address(dst_addr, dst_str,
+ sizeof(dst_str));
}
+ printf("ip.SrcAddr=%s ip.DstAddr=%s ", src_str, dst_str);
if (icmp_header != NULL)
{
printf("icmp.Type=%u icmp.Code=%u ",
From 33a461eef66ca823f4eb134acda50f23f18d734d Mon Sep 17 00:00:00 2001
From: basil00
Date: Wed, 7 Nov 2018 07:54:32 +0800
Subject: [PATCH 15/23] Add packet/payload matching to WinDivert (#156).
Adds the follow terms to the filter language:
- packet[idx]: 8bit packet value at idx.
- packet16[idx]: 16bit packet value at idx.
- packet32[idx]: 32bit packet value at idx.
- PROTO.Payload[idx]: 8bit payload value at idx.
- PROTO.Payload16[idx]: 16bit payload value at
idx.
- PROTO.Payload32[idx]: 32bit payload value at
idx.
where PROTO is {tcp,udp}.
16 and 32bit values assume network byte ordering.
The index may be:
- An undecorated integer, in which case the
packet or payload is treated as a 8/16/32bit
value array, similar to C arrays.
- A 'b' decorated integer, (e.g, packet32[17b]),
in which case the integer is interpreted as a
byte offset.
- A negative (un)decorated integer, in which
case indexing begins at the *end* of the
packet or payload. E.g., packet32[-1] is the
last 32bits of the packet.
If the index is out-of-bounds, then the test
is deemed to be equivalent to "false".
---
dll/windivert_helper.c | 486 +++++++++++++++++++++++++++++++++----
dll/windivert_shared.c | 14 ++
include/windivert_device.h | 11 +-
sys/windivert.c | 268 +++++++++++++-------
test/test.c | 90 ++++++-
5 files changed, 724 insertions(+), 145 deletions(-)
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index 5c3b224..5057d08 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -93,6 +93,9 @@ typedef enum
TOKEN_TCP_DST_PORT,
TOKEN_TCP_FIN,
TOKEN_TCP_HDR_LENGTH,
+ TOKEN_TCP_PAYLOAD,
+ TOKEN_TCP_PAYLOAD16,
+ TOKEN_TCP_PAYLOAD32,
TOKEN_TCP_PAYLOAD_LENGTH,
TOKEN_TCP_PSH,
TOKEN_TCP_RST,
@@ -106,10 +109,16 @@ typedef enum
TOKEN_UDP_CHECKSUM,
TOKEN_UDP_DST_PORT,
TOKEN_UDP_LENGTH,
+ TOKEN_UDP_PAYLOAD,
+ TOKEN_UDP_PAYLOAD16,
+ TOKEN_UDP_PAYLOAD32,
TOKEN_UDP_PAYLOAD_LENGTH,
TOKEN_UDP_SRC_PORT,
TOKEN_ZERO,
TOKEN_EVENT,
+ TOKEN_PACKET,
+ TOKEN_PACKET16,
+ TOKEN_PACKET32,
TOKEN_TRUE,
TOKEN_FALSE,
TOKEN_INBOUND,
@@ -141,6 +150,10 @@ typedef enum
TOKEN_EVENT_CLOSE,
TOKEN_OPEN,
TOKEN_CLOSE,
+ TOKEN_SQUARE_OPEN,
+ TOKEN_SQUARE_CLOSE,
+ TOKEN_MINUS,
+ TOKEN_BYTES,
TOKEN_EQ,
TOKEN_NEQ,
TOKEN_LT,
@@ -239,9 +252,10 @@ typedef UINT64 ERROR, *PERROR;
#define WINDIVERT_ERROR_BAD_TOKEN 4
#define WINDIVERT_ERROR_BAD_TOKEN_FOR_LAYER 5
#define WINDIVERT_ERROR_UNEXPECTED_TOKEN 6
-#define WINDIVERT_ERROR_OUTPUT_TOO_SHORT 7
-#define WINDIVERT_ERROR_BAD_OBJECT 8
-#define WINDIVERT_ERROR_ASSERTION_FAILED 9
+#define WINDIVERT_ERROR_INDEX_OOB 7
+#define WINDIVERT_ERROR_OUTPUT_TOO_SHORT 8
+#define WINDIVERT_ERROR_BAD_OBJECT 9
+#define WINDIVERT_ERROR_ASSERTION_FAILED 10
#define MAKE_ERROR(code, pos) \
(((ERROR)(code) << 32) | (ERROR)(pos));
@@ -603,6 +617,9 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{"not", TOKEN_NOT, LNMFSR},
{"or", TOKEN_OR, LNMFSR},
{"outbound", TOKEN_OUTBOUND, LN_F__},
+ {"packet", TOKEN_PACKET, LNM___},
+ {"packet16", TOKEN_PACKET16, LNM___},
+ {"packet32", TOKEN_PACKET32, LNM___},
{"processId", TOKEN_PROCESS_ID, L__FSR},
{"protocol", TOKEN_PROTOCOL, LN_FS_},
{"remoteAddr", TOKEN_REMOTE_ADDR, LN_FS_},
@@ -615,6 +632,9 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{"tcp.DstPort", TOKEN_TCP_DST_PORT, LNM___},
{"tcp.Fin", TOKEN_TCP_FIN, LNM___},
{"tcp.HdrLength", TOKEN_TCP_HDR_LENGTH, LNM___},
+ {"tcp.Payload", TOKEN_TCP_PAYLOAD, LNM___},
+ {"tcp.Payload16", TOKEN_TCP_PAYLOAD16, LNM___},
+ {"tcp.Payload32", TOKEN_TCP_PAYLOAD32, LNM___},
{"tcp.PayloadLength", TOKEN_TCP_PAYLOAD_LENGTH, LNM___},
{"tcp.Psh", TOKEN_TCP_PSH, LNM___},
{"tcp.Rst", TOKEN_TCP_RST, LNM___},
@@ -629,6 +649,9 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{"udp.Checksum", TOKEN_UDP_CHECKSUM, LNM___},
{"udp.DstPort", TOKEN_UDP_DST_PORT, LNM___},
{"udp.Length", TOKEN_UDP_LENGTH, LNM___},
+ {"udp.Payload", TOKEN_UDP_PAYLOAD, LNM___},
+ {"udp.Payload16", TOKEN_UDP_PAYLOAD16, LNM___},
+ {"udp.Payload32", TOKEN_UDP_PAYLOAD32, LNM___},
{"udp.PayloadLength", TOKEN_UDP_PAYLOAD_LENGTH, LNM___},
{"udp.SrcPort", TOKEN_UDP_SRC_PORT, LNM___},
{"zero", TOKEN_ZERO, LNMFSR},
@@ -663,6 +686,15 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
case ')':
tokens[tp++].kind = TOKEN_CLOSE;
continue;
+ case '[':
+ tokens[tp++].kind = TOKEN_SQUARE_OPEN;
+ continue;
+ case ']':
+ tokens[tp++].kind = TOKEN_SQUARE_CLOSE;
+ continue;
+ case '-':
+ tokens[tp++].kind = TOKEN_MINUS;
+ continue;
case '!':
if (filter[i] == '=')
{
@@ -780,16 +812,26 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
}
// Check for base 10 number:
- if (WinDivertAToI(token, &end, &num) && *end == '\0')
+ if (WinDivertAToI(token, &end, &num))
{
- tokens[tp].kind = TOKEN_NUMBER;
- tokens[tp].val[0] = num;
- tp++;
- continue;
+ BOOL b = (*end == 'b' && *(end+1) == '\0');
+ if (*end == '\0' || b)
+ {
+ tokens[tp].kind = TOKEN_NUMBER;
+ tokens[tp].val[0] = num;
+ tp++;
+ if (b)
+ {
+ tokens[tp].kind = TOKEN_BYTES;
+ tp++;
+ }
+ continue;
+ }
}
// Check for base 16 number:
- if (WinDivertAToX(token, &end, &num) && *end == '\0')
+ if (token[0] == '0' && token[1] == 'x' &&
+ WinDivertAToX(token, &end, &num) && *end == '\0')
{
tokens[tp].kind = TOKEN_NUMBER;
tokens[tp].val[0] = num;
@@ -924,6 +966,23 @@ static PEXPR WinDivertMakeVar(KIND kind, PERROR error)
return NULL;
}
+/*
+ * Construct array varable.
+ */
+static PEXPR WinDivertMakeArrayVar(HANDLE pool, KIND kind, INT idx,
+ PERROR error)
+{
+ PEXPR var = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
+ if (var == NULL)
+ {
+ *error = MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
+ return NULL;
+ }
+ var->kind = kind;
+ var->val[0] = (UINT32)idx;
+ return var;
+}
+
/*
* Construct zero.
*/
@@ -938,6 +997,10 @@ static PEXPR WinDivertMakeZero(void)
*/
static PEXPR WinDivertMakeNumber(HANDLE pool, UINT32 *val, PERROR error)
{
+ if (val[0] == 0 && val[1] == 0 && val[2] == 0 && val[3] == 0)
+ {
+ return WinDivertMakeZero();
+ }
PEXPR expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
if (expr == NULL)
{
@@ -1001,7 +1064,8 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error)
{
PEXPR var, val;
KIND kind;
- BOOL not = FALSE;
+ BOOL not = FALSE, neg;
+ UINT idx, size;
while (toks[*i].kind == TOKEN_NOT)
{
not = !not;
@@ -1079,13 +1143,80 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error)
case TOKEN_UDP_LENGTH:
case TOKEN_UDP_CHECKSUM:
case TOKEN_UDP_PAYLOAD_LENGTH:
+ var = WinDivertMakeVar(toks[*i].kind, error);
+ *i = *i + 1;
+ break;
+ case TOKEN_PACKET:
+ case TOKEN_TCP_PAYLOAD:
+ case TOKEN_UDP_PAYLOAD:
+ size = sizeof(UINT8);
+ goto array;
+ case TOKEN_PACKET16:
+ case TOKEN_TCP_PAYLOAD16:
+ case TOKEN_UDP_PAYLOAD16:
+ size = sizeof(UINT16);
+ goto array;
+ case TOKEN_PACKET32:
+ case TOKEN_TCP_PAYLOAD32:
+ case TOKEN_UDP_PAYLOAD32:
+ size = sizeof(UINT32);
+ array:
+ kind = toks[*i].kind;
+ *i = *i + 1;
+ if (toks[*i].kind != TOKEN_SQUARE_OPEN)
+ {
+ goto unexpected_token;
+ }
+ *i = *i + 1;
+ neg = FALSE;
+ if (toks[*i].kind == TOKEN_MINUS)
+ {
+ neg = TRUE;
+ *i = *i + 1;
+ }
+ if (toks[*i].kind != TOKEN_NUMBER)
+ {
+ goto unexpected_token;
+ }
+ if (toks[*i].val[3] != 0 || toks[*i].val[2] != 0 ||
+ toks[*i].val[1] != 0 || toks[*i].val[0] > UINT16_MAX)
+ {
+ *error = MAKE_ERROR(WINDIVERT_ERROR_INDEX_OOB, toks[*i].pos);
+ return NULL;
+ }
+ idx = toks[*i].val[0];
+ *i = *i + 1;
+ if (toks[*i].kind == TOKEN_BYTES)
+ {
+ *i = *i + 1;
+ }
+ else
+ {
+ idx *= size;
+ }
+ if ((!neg && idx > UINT16_MAX - size) ||
+ (neg && idx > UINT16_MAX) || (neg && idx < size))
+ {
+ *error = MAKE_ERROR(WINDIVERT_ERROR_INDEX_OOB, toks[*i].pos);
+ return NULL;
+ }
+ var = WinDivertMakeArrayVar(pool, kind, (neg? -(INT)idx: (INT)idx),
+ error);
+ if (var == NULL)
+ {
+ return NULL;
+ }
+ if (toks[*i].kind != TOKEN_SQUARE_CLOSE)
+ {
+ goto unexpected_token;
+ }
+ *i = *i + 1;
break;
default:
+ unexpected_token:
*error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, toks[*i].pos);
return NULL;
}
- var = WinDivertMakeVar(toks[*i].kind, error);
- *i = *i + 1;
switch (toks[*i].kind)
{
case TOKEN_EQ:
@@ -1296,6 +1427,9 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
case TOKEN_ICMPV6_TYPE:
case TOKEN_ICMPV6_CODE:
case TOKEN_PROTOCOL:
+ case TOKEN_PACKET:
+ case TOKEN_TCP_PAYLOAD:
+ case TOKEN_UDP_PAYLOAD:
lb = 0; ub = 0xFF;
break;
case TOKEN_IP_FRAG_OFF:
@@ -1321,6 +1455,9 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
case TOKEN_UDP_PAYLOAD_LENGTH:
case TOKEN_LOCAL_PORT:
case TOKEN_REMOTE_PORT:
+ case TOKEN_PACKET16:
+ case TOKEN_TCP_PAYLOAD16:
+ case TOKEN_UDP_PAYLOAD16:
lb = 0; ub = 0xFFFF;
break;
case TOKEN_IPV6_FLOW_LABEL:
@@ -1469,6 +1606,7 @@ static INT16 WinDivertFlattenExpr(PEXPR expr, INT16 *label, INT16 succ,
static void WinDivertEmitTest(PEXPR test, UINT16 offset,
PWINDIVERT_FILTER object)
{
+ BOOL big;
PEXPR var = test->arg[0], val = test->arg[1];
switch (test->kind)
{
@@ -1493,6 +1631,8 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
default:
return;
}
+ big = FALSE;
+ object->arg[1] = object->arg[2] = object->arg[3] = 0;
switch (var->kind)
{
case TOKEN_ZERO:
@@ -1501,6 +1641,42 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
case TOKEN_EVENT:
object->field = WINDIVERT_FILTER_FIELD_EVENT;
break;
+ case TOKEN_PACKET:
+ object->field = WINDIVERT_FILTER_FIELD_PACKET;
+ object->arg[1] = var->val[0];
+ break;
+ case TOKEN_PACKET16:
+ object->field = WINDIVERT_FILTER_FIELD_PACKET16;
+ object->arg[1] = var->val[0];
+ break;
+ case TOKEN_PACKET32:
+ object->field = WINDIVERT_FILTER_FIELD_PACKET32;
+ object->arg[1] = var->val[0];
+ break;
+ case TOKEN_TCP_PAYLOAD:
+ object->field = WINDIVERT_FILTER_FIELD_TCP_PAYLOAD;
+ object->arg[1] = var->val[0];
+ break;
+ case TOKEN_TCP_PAYLOAD16:
+ object->field = WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16;
+ object->arg[1] = var->val[0];
+ break;
+ case TOKEN_TCP_PAYLOAD32:
+ object->field = WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32;
+ object->arg[1] = var->val[0];
+ break;
+ case TOKEN_UDP_PAYLOAD:
+ object->field = WINDIVERT_FILTER_FIELD_UDP_PAYLOAD;
+ object->arg[1] = var->val[0];
+ break;
+ case TOKEN_UDP_PAYLOAD16:
+ object->field = WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16;
+ object->arg[1] = var->val[0];
+ break;
+ case TOKEN_UDP_PAYLOAD32:
+ object->field = WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32;
+ object->arg[1] = var->val[0];
+ break;
case TOKEN_OUTBOUND:
object->field = WINDIVERT_FILTER_FIELD_OUTBOUND;
break;
@@ -1524,9 +1700,11 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
break;
case TOKEN_LOCAL_ADDR:
object->field = WINDIVERT_FILTER_FIELD_LOCALADDR;
+ big = TRUE;
break;
case TOKEN_REMOTE_ADDR:
object->field = WINDIVERT_FILTER_FIELD_REMOTEADDR;
+ big = TRUE;
break;
case TOKEN_LOCAL_PORT:
object->field = WINDIVERT_FILTER_FIELD_LOCALPORT;
@@ -1590,9 +1768,11 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
break;
case TOKEN_IP_SRC_ADDR:
object->field = WINDIVERT_FILTER_FIELD_IP_SRCADDR;
+ big = TRUE;
break;
case TOKEN_IP_DST_ADDR:
object->field = WINDIVERT_FILTER_FIELD_IP_DSTADDR;
+ big = TRUE;
break;
case TOKEN_IPV6_TRAFFIC_CLASS:
object->field = WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS;
@@ -1611,9 +1791,11 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
break;
case TOKEN_IPV6_SRC_ADDR:
object->field = WINDIVERT_FILTER_FIELD_IPV6_SRCADDR;
+ big = TRUE;
break;
case TOKEN_IPV6_DST_ADDR:
object->field = WINDIVERT_FILTER_FIELD_IPV6_DSTADDR;
+ big = TRUE;
break;
case TOKEN_ICMP_TYPE:
object->field = WINDIVERT_FILTER_FIELD_ICMP_TYPE;
@@ -1703,9 +1885,12 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
return;
}
object->arg[0] = val->val[0];
- object->arg[1] = val->val[1];
- object->arg[2] = val->val[2];
- object->arg[3] = val->val[3];
+ if (big)
+ {
+ object->arg[1] = val->val[1];
+ object->arg[2] = val->val[2];
+ object->arg[3] = val->val[3];
+ }
switch (test->succ)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
@@ -2021,6 +2206,8 @@ static const char *WinDivertErrorString(UINT code)
return "Filter expression contains a bad token for layer";
case WINDIVERT_ERROR_UNEXPECTED_TOKEN:
return "Filter expression parse error";
+ case WINDIVERT_ERROR_INDEX_OOB:
+ return "Filter expression array index is out-of-bounds";
case WINDIVERT_ERROR_OUTPUT_TOO_SHORT:
return "Filter object buffer is too short";
case WINDIVERT_ERROR_BAD_OBJECT:
@@ -2086,31 +2273,34 @@ extern BOOL WinDivertHelperCompileFilter(const char *filter_str,
/*
* Big number comparison.
*/
-static int WinDivertBigNumCompare(const UINT32 *a, const UINT32 *b)
+static int WinDivertBigNumCompare(const UINT32 *a, const UINT32 *b, BOOL big)
{
- if (a[3] < b[3])
+ if (big)
{
- return -1;
- }
- if (a[3] > b[3])
- {
- return 1;
- }
- if (a[2] < b[2])
- {
- return -1;
- }
- if (a[2] > b[2])
- {
- return 1;
- }
- if (a[1] < b[1])
- {
- return -1;
- }
- if (a[1] > b[1])
- {
- return 1;
+ if (a[3] < b[3])
+ {
+ return -1;
+ }
+ if (a[3] > b[3])
+ {
+ return 1;
+ }
+ if (a[2] < b[2])
+ {
+ return -1;
+ }
+ if (a[2] > b[2])
+ {
+ return 1;
+ }
+ if (a[1] < b[1])
+ {
+ return -1;
+ }
+ if (a[1] > b[1])
+ {
+ return 1;
+ }
}
if (a[0] < b[0])
{
@@ -2123,6 +2313,28 @@ static int WinDivertBigNumCompare(const UINT32 *a, const UINT32 *b)
return 0;
}
+/*
+ * Get packet/payload data.
+ */
+static BOOL WinDivertGetData(PVOID packet, UINT packet_len, UINT offset,
+ INT idx, UINT size, PVOID data)
+{
+ if (idx < 0)
+ {
+ idx += (INT)packet_len;
+ }
+ else
+ {
+ idx += (INT)offset;
+ }
+ if (idx < (INT)offset || idx > (INT)(packet_len - size))
+ {
+ return FALSE;
+ }
+ memcpy(data, (UINT8 *)packet + idx, size);
+ return TRUE;
+}
+
/*
* Evaluate the given filter with the given packet as input.
*/
@@ -2138,9 +2350,12 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
PWINDIVERT_TCPHDR tcphdr = NULL;
PWINDIVERT_UDPHDR udphdr = NULL;
UINT8 protocol = 0;
- UINT payload_len;
+ UINT header_len = 0, payload_len = 0;
UINT32 val[4];
- BOOL pass;
+ UINT8 data8;
+ UINT16 data16;
+ UINT32 data32;
+ BOOL pass, big;
int cmp;
WINDIVERT_FILTER object[WINDIVERT_FILTER_MAXLEN];
UINT obj_len;
@@ -2162,6 +2377,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
WinDivertParsePacket(packet, packet_len, &iphdr, &ipv6hdr,
&icmphdr, &icmpv6hdr, &tcphdr, &udphdr, &protocol, NULL,
&payload_len);
+ header_len = packet_len - payload_len;
if ((addr->IPv6 && ipv6hdr == NULL) ||
(!addr->IPv6 && iphdr == NULL))
{
@@ -2209,6 +2425,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
break;
}
pass = TRUE;
+ big = FALSE;
switch (object[pc].field)
{
case WINDIVERT_FILTER_FIELD_ZERO:
@@ -2232,6 +2449,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
break;
case WINDIVERT_FILTER_FIELD_IFIDX:
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
+ case WINDIVERT_FILTER_FIELD_PACKET:
+ case WINDIVERT_FILTER_FIELD_PACKET16:
+ case WINDIVERT_FILTER_FIELD_PACKET32:
pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
break;
@@ -2309,6 +2529,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
case WINDIVERT_FILTER_FIELD_TCP_WINDOW:
case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
@@ -2318,6 +2541,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
case WINDIVERT_FILTER_FIELD_UDP_DSTPORT:
case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
@@ -2332,7 +2558,6 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
pc = object[pc].failure;
continue;
}
- val[1] = val[2] = val[3] = 0;
switch (object[pc].field)
{
case WINDIVERT_FILTER_FIELD_ZERO:
@@ -2341,6 +2566,39 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
case WINDIVERT_FILTER_FIELD_EVENT:
val[0] = addr->Event;
break;
+ case WINDIVERT_FILTER_FIELD_PACKET:
+ pass = WinDivertGetData(packet, packet_len, /*offset=*/0,
+ object[pc].arg[1], sizeof(data8), &data8);
+ val[0] = data8;
+ break;
+ case WINDIVERT_FILTER_FIELD_PACKET16:
+ pass = WinDivertGetData(packet, packet_len, /*offset=*/0,
+ object[pc].arg[1], sizeof(data16), &data16);
+ val[0] = ntohs(data16);
+ break;
+ case WINDIVERT_FILTER_FIELD_PACKET32:
+ pass = WinDivertGetData(packet, packet_len, /*offset=*/0,
+ object[pc].arg[1], sizeof(data32), &data32);
+ val[0] = ntohl(data32);
+ break;
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
+ pass = WinDivertGetData(packet, packet_len, header_len,
+ object[pc].arg[1], sizeof(data8), &data8);
+ val[0] = data8;
+ break;
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
+ pass = WinDivertGetData(packet, packet_len, header_len,
+ object[pc].arg[1], sizeof(data16), &data16);
+ val[0] = ntohs(data16);
+ break;
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
+ pass = WinDivertGetData(packet, packet_len, header_len,
+ object[pc].arg[1], sizeof(data32), &data32);
+ val[0] = ntohl(data32);
+ break;
case WINDIVERT_FILTER_FIELD_INBOUND:
val[0] = !addr->Outbound;
break;
@@ -2495,12 +2753,14 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
val[0] = ipv6hdr->HopLimit;
break;
case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
+ big = TRUE;
val[3] = ntohl(ipv6hdr->SrcAddr[0]);
val[2] = ntohl(ipv6hdr->SrcAddr[1]);
val[1] = ntohl(ipv6hdr->SrcAddr[2]);
val[0] = ntohl(ipv6hdr->SrcAddr[3]);
break;
case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
+ big = TRUE;
val[3] = ntohl(ipv6hdr->DstAddr[0]);
val[2] = ntohl(ipv6hdr->DstAddr[1]);
val[1] = ntohl(ipv6hdr->DstAddr[2]);
@@ -2591,6 +2851,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
val[0] = payload_len;
break;
case WINDIVERT_FILTER_FIELD_LOCALADDR:
+ big = TRUE;
switch (addr->Layer)
{
case WINDIVERT_LAYER_NETWORK:
@@ -2633,6 +2894,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
}
break;
case WINDIVERT_FILTER_FIELD_REMOTEADDR:
+ big = TRUE;
switch (addr->Layer)
{
case WINDIVERT_LAYER_NETWORK:
@@ -2772,7 +3034,12 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- cmp = WinDivertBigNumCompare(val, object[pc].arg);
+ if (!pass)
+ {
+ pc = object[pc].failure;
+ continue;
+ }
+ cmp = WinDivertBigNumCompare(val, object[pc].arg, big);
switch (object[pc].test)
{
case WINDIVERT_FILTER_TEST_EQ:
@@ -2903,6 +3170,22 @@ static BOOL WinDivertDeserializeTest(PWINDIVERT_STREAM stream,
filter->arg[1] = 0x0000FFFF;
filter->arg[2] = filter->arg[3] = 0;
break;
+ case WINDIVERT_FILTER_FIELD_PACKET:
+ case WINDIVERT_FILTER_FIELD_PACKET16:
+ case WINDIVERT_FILTER_FIELD_PACKET32:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
+ if (!WinDivertDeserializeNumber(stream, 7, &val))
+ {
+ return FALSE;
+ }
+ filter->arg[1] = (UINT32)((INT)val - UINT16_MAX);
+ filter->arg[2] = filter->arg[3] = 0;
+ break;
default:
filter->arg[1] = filter->arg[2] = filter->arg[3] = 0;
break;
@@ -2994,6 +3277,7 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test)
{
KIND kind;
PEXPR var, val, expr;
+ UINT32 tmp[4];
ERROR error;
switch (test->field)
@@ -3002,6 +3286,24 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test)
kind = TOKEN_ZERO; break;
case WINDIVERT_FILTER_FIELD_EVENT:
kind = TOKEN_EVENT; break;
+ case WINDIVERT_FILTER_FIELD_PACKET:
+ kind = TOKEN_PACKET; break;
+ case WINDIVERT_FILTER_FIELD_PACKET16:
+ kind = TOKEN_PACKET16; break;
+ case WINDIVERT_FILTER_FIELD_PACKET32:
+ kind = TOKEN_PACKET32; break;
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
+ kind = TOKEN_TCP_PAYLOAD; break;
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
+ kind = TOKEN_TCP_PAYLOAD16; break;
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32:
+ kind = TOKEN_TCP_PAYLOAD32; break;
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
+ kind = TOKEN_UDP_PAYLOAD; break;
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
+ kind = TOKEN_UDP_PAYLOAD16; break;
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
+ kind = TOKEN_UDP_PAYLOAD32; break;
case WINDIVERT_FILTER_FIELD_INBOUND:
kind = TOKEN_INBOUND; break;
case WINDIVERT_FILTER_FIELD_OUTBOUND:
@@ -3138,15 +3440,42 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test)
return NULL;
}
- var = WinDivertMakeVar(kind, &error);
- if (var == NULL)
+ switch (kind)
{
- return NULL;
- }
- val = WinDivertMakeNumber(pool, test->arg, &error);
- if (val == NULL)
- {
- return NULL;
+ case TOKEN_PACKET:
+ case TOKEN_PACKET16:
+ case TOKEN_PACKET32:
+ case TOKEN_TCP_PAYLOAD:
+ case TOKEN_TCP_PAYLOAD16:
+ case TOKEN_TCP_PAYLOAD32:
+ case TOKEN_UDP_PAYLOAD:
+ case TOKEN_UDP_PAYLOAD16:
+ case TOKEN_UDP_PAYLOAD32:
+ var = WinDivertMakeArrayVar(pool, kind, test->arg[1], &error);
+ if (var == NULL)
+ {
+ return NULL;
+ }
+ tmp[0] = test->arg[0];
+ tmp[1] = tmp[2] = tmp[3] = 0;
+ val = WinDivertMakeNumber(pool, tmp, &error);
+ if (val == NULL)
+ {
+ return NULL;
+ }
+ break;
+ default:
+ var = WinDivertMakeVar(kind, &error);
+ if (var == NULL)
+ {
+ return NULL;
+ }
+ val = WinDivertMakeNumber(pool, test->arg, &error);
+ if (val == NULL)
+ {
+ return NULL;
+ }
+ break;
}
switch (test->test)
@@ -3558,7 +3887,7 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
{
PEXPR field = expr->arg[0], val = expr->arg[1];
BOOL is_ipv4_addr = FALSE, is_ipv6_addr = FALSE, is_layer = FALSE,
- is_event = FALSE;
+ is_event = FALSE, is_hex = FALSE;
switch (field->kind)
{
@@ -3618,6 +3947,23 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
case TOKEN_EVENT:
is_event = TRUE;
break;
+ case TOKEN_PACKET:
+ case TOKEN_PACKET16:
+ case TOKEN_PACKET32:
+ case TOKEN_IP_ID:
+ case TOKEN_IP_CHECKSUM:
+ case TOKEN_TCP_CHECKSUM:
+ case TOKEN_TCP_PAYLOAD:
+ case TOKEN_TCP_PAYLOAD16:
+ case TOKEN_TCP_PAYLOAD32:
+ case TOKEN_UDP_CHECKSUM:
+ case TOKEN_UDP_PAYLOAD:
+ case TOKEN_UDP_PAYLOAD16:
+ case TOKEN_UDP_PAYLOAD32:
+ case TOKEN_ICMP_CHECKSUM:
+ case TOKEN_ICMPV6_CHECKSUM:
+ is_hex = TRUE;
+ break;
default:
break;
}
@@ -3723,6 +4069,11 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
WinDivertFormatNumber(stream, val->val[0]); break;
}
}
+ else if (is_hex)
+ {
+ WinDivertPutString(stream, "0x");
+ WinDivertFormatHexNumber(stream, val->val[0]);
+ }
else
{
WinDivertFormatNumber(stream, val->val[0]);
@@ -3735,6 +4086,8 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
WINDIVERT_LAYER layer, BOOL top_level, BOOL and)
{
+ INT idx;
+
if (stream->pos >= stream->max)
{
return;
@@ -3802,6 +4155,24 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
WinDivertPutString(stream, "zero"); return;
case TOKEN_EVENT:
WinDivertPutString(stream, "event"); return;
+ case TOKEN_PACKET:
+ WinDivertPutString(stream, "packet"); break;
+ case TOKEN_PACKET16:
+ WinDivertPutString(stream, "packet16"); break;
+ case TOKEN_PACKET32:
+ WinDivertPutString(stream, "packet32"); break;
+ case TOKEN_TCP_PAYLOAD:
+ WinDivertPutString(stream, "tcp.Payload"); break;
+ case TOKEN_TCP_PAYLOAD16:
+ WinDivertPutString(stream, "tcp.Payload16"); break;
+ case TOKEN_TCP_PAYLOAD32:
+ WinDivertPutString(stream, "tcp.Payload32"); break;
+ case TOKEN_UDP_PAYLOAD:
+ WinDivertPutString(stream, "udp.Payload"); break;
+ case TOKEN_UDP_PAYLOAD16:
+ WinDivertPutString(stream, "udp.Payload16"); break;
+ case TOKEN_UDP_PAYLOAD32:
+ WinDivertPutString(stream, "udp.Payload32"); break;
case TOKEN_INBOUND:
WinDivertPutString(stream, "inbound"); return;
case TOKEN_OUTBOUND:
@@ -3935,9 +4306,18 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
case TOKEN_LAYER:
WinDivertPutString(stream, "layer"); return;
case TOKEN_NUMBER:
- WinDivertFormatNumber(stream, expr->val[0]);
- return;
+ WinDivertFormatNumber(stream, expr->val[0]); return;
}
+
+ WinDivertPutChar(stream, '[');
+ idx = (INT)expr->val[0];
+ if (idx < 0)
+ {
+ WinDivertPutChar(stream, '-');
+ idx = -idx;
+ }
+ WinDivertFormatNumber(stream, (UINT32)idx);
+ WinDivertPutString(stream, "b]");
}
/*
diff --git a/dll/windivert_shared.c b/dll/windivert_shared.c
index 337064c..bd6b9e0 100644
--- a/dll/windivert_shared.c
+++ b/dll/windivert_shared.c
@@ -167,6 +167,7 @@ static void WinDivertSerializeNumber(PWINDIVERT_STREAM stream, UINT32 val)
static void WinDivertSerializeTest(PWINDIVERT_STREAM stream,
PWINDIVERT_FILTER filter)
{
+ INT idx;
UINT i;
WinDivertPutChar(stream, '_');
@@ -184,6 +185,19 @@ static void WinDivertSerializeTest(PWINDIVERT_STREAM stream,
WinDivertSerializeNumber(stream, filter->arg[i]);
}
break;
+ case WINDIVERT_FILTER_FIELD_PACKET:
+ case WINDIVERT_FILTER_FIELD_PACKET16:
+ case WINDIVERT_FILTER_FIELD_PACKET32:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
+ idx = (INT)filter->arg[1];
+ idx += UINT16_MAX;
+ WinDivertSerializeNumber(stream, (UINT32)idx);
+ break;
default:
break;
}
diff --git a/include/windivert_device.h b/include/windivert_device.h
index 65e194f..3efd822 100644
--- a/include/windivert_device.h
+++ b/include/windivert_device.h
@@ -127,8 +127,17 @@
#define WINDIVERT_FILTER_FIELD_PROTOCOL 65
#define WINDIVERT_FILTER_FIELD_LAYER 66
#define WINDIVERT_FILTER_FIELD_EVENT 67
+#define WINDIVERT_FILTER_FIELD_PACKET 68
+#define WINDIVERT_FILTER_FIELD_PACKET16 69
+#define WINDIVERT_FILTER_FIELD_PACKET32 70
+#define WINDIVERT_FILTER_FIELD_TCP_PAYLOAD 71
+#define WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16 72
+#define WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32 73
+#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD 74
+#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16 75
+#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32 76
#define WINDIVERT_FILTER_FIELD_MAX \
- WINDIVERT_FILTER_FIELD_EVENT
+ WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32
#define WINDIVERT_FILTER_TEST_EQ 0
#define WINDIVERT_FILTER_TEST_NEQ 1
diff --git a/sys/windivert.c b/sys/windivert.c
index 4f2e817..175991c 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -457,13 +457,14 @@ static void windivert_queue_packet(context_t context, packet_t packet);
static void windivert_reinject_packet(packet_t packet);
static void windivert_free_packet(packet_t packet);
static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4);
-static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b);
+static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b,
+ BOOL big);
static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
PWINDIVERT_IPHDR *ip_header_ptr, PWINDIVERT_IPV6HDR *ipv6_header_ptr,
PWINDIVERT_ICMPHDR *icmp_header_ptr,
PWINDIVERT_ICMPV6HDR *icmpv6_header_ptr,
PWINDIVERT_TCPHDR *tcp_header_ptr, PWINDIVERT_UDPHDR *udp_header_ptr,
- UINT8 *proto_ptr, UINT *payload_len_ptr);
+ UINT8 *proto_ptr, UINT *header_len_ptr, UINT *payload_len_ptr);
static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
PVOID layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound,
BOOL loopback, BOOL impostor, PWINDIVERT_FILTER filter);
@@ -3014,7 +3015,7 @@ static void windivert_get_ipv6_addr(const FWPS_INCOMING_VALUES0 *fixed_vals,
UINT8 *addr8 = (UINT8 *)addr;
INT i;
FWP_VALUE0 value = fixed_vals->incomingValue[idx].value;
- if (value.type != FWP_BYTE_ARRAY16_TYPE)
+ if (value.type != FWP_BYTE_ARRAY16_TYPE)
{
RtlZeroMemory(&addr, 16);
return;
@@ -4431,31 +4432,34 @@ static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4)
/*
* Big number comparison.
*/
-static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b)
+static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b, BOOL big)
{
- if (a[3] < b[3])
+ if (big)
{
- return -1;
- }
- if (a[3] > b[3])
- {
- return 1;
- }
- if (a[2] < b[2])
- {
- return -1;
- }
- if (a[2] > b[2])
- {
- return 1;
- }
- if (a[1] < b[1])
- {
- return -1;
- }
- if (a[1] > b[1])
- {
- return 1;
+ if (a[3] < b[3])
+ {
+ return -1;
+ }
+ if (a[3] > b[3])
+ {
+ return 1;
+ }
+ if (a[2] < b[2])
+ {
+ return -1;
+ }
+ if (a[2] > b[2])
+ {
+ return 1;
+ }
+ if (a[1] < b[1])
+ {
+ return -1;
+ }
+ if (a[1] > b[1])
+ {
+ return 1;
+ }
}
if (a[0] < b[0])
{
@@ -4468,6 +4472,44 @@ static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b)
return 0;
}
+/*
+ * Get packet/payload data.
+ */
+static BOOL windivert_get_data(PNET_BUFFER buffer, UINT offset, INT idx,
+ UINT size, PVOID data)
+{
+ PVOID ptr;
+ UINT length = NET_BUFFER_DATA_LENGTH(buffer);
+
+ if (idx < 0)
+ {
+ idx += (INT)length;
+ }
+ else
+ {
+ idx += (INT)offset;
+ }
+ if (idx < (INT)offset || idx > (INT)(length - size))
+ {
+ return FALSE; // OOB
+ }
+
+ if (idx > 0)
+ {
+ NdisAdvanceNetBufferDataStart(buffer, idx, FALSE, NULL);
+ }
+ ptr = NdisGetDataBuffer(buffer, size, data, 1, 0);
+ if (ptr != NULL && ptr != data)
+ {
+ RtlCopyMemory(data, ptr, size); // Non-contiguous case
+ }
+ if (idx > 0)
+ {
+ (VOID)NdisRetreatNetBufferDataStart(buffer, idx, 0, NULL);
+ }
+ return TRUE;
+}
+
/*
* Parse packet headers.
*/
@@ -4476,7 +4518,7 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
PWINDIVERT_ICMPHDR *icmp_header_ptr,
PWINDIVERT_ICMPV6HDR *icmpv6_header_ptr,
PWINDIVERT_TCPHDR *tcp_header_ptr, PWINDIVERT_UDPHDR *udp_header_ptr,
- UINT8 *proto_ptr, UINT *payload_len_ptr)
+ UINT8 *proto_ptr, UINT *header_len_ptr, UINT *payload_len_ptr)
{
UINT tot_len, ip_header_len;
PWINDIVERT_IPHDR ip_header = NULL;
@@ -4487,7 +4529,7 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
PWINDIVERT_UDPHDR udp_header = NULL;
UINT16 ip, ttl;
UINT8 proto = 0;
- UINT payload_len = 0;
+ UINT header_len = 0, payload_len = 0;
NTSTATUS status;
// Parse the headers:
@@ -4609,23 +4651,25 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
case IPPROTO_ICMP:
icmp_header = (PWINDIVERT_ICMPHDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_ICMPHDR), NULL, 1, 0);
+ header_len = ip_header_len + sizeof(WINDIVERT_ICMPHDR);
break;
case IPPROTO_ICMPV6:
icmpv6_header = (PWINDIVERT_ICMPV6HDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_ICMPV6HDR), NULL, 1, 0);
+ header_len = ip_header_len + sizeof(WINDIVERT_ICMPV6HDR);
break;
case IPPROTO_TCP:
tcp_header = (PWINDIVERT_TCPHDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_TCPHDR), NULL, 1, 0);
- payload_len = tot_len - ip_header_len -
- tcp_header->HdrLength*sizeof(UINT32);
+ header_len = ip_header_len + tcp_header->HdrLength*sizeof(UINT32);
break;
case IPPROTO_UDP:
udp_header = (PWINDIVERT_UDPHDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_UDPHDR), NULL, 1, 0);
- payload_len = tot_len - ip_header_len - sizeof(WINDIVERT_UDPHDR);
+ header_len = ip_header_len + sizeof(WINDIVERT_UDPHDR);
break;
default:
+ header_len = ip_header_len;
break;
}
@@ -4644,7 +4688,8 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
*tcp_header_ptr = tcp_header;
*udp_header_ptr = udp_header;
*proto_ptr = proto;
- *payload_len_ptr = payload_len;
+ *header_len_ptr = header_len;
+ *payload_len_ptr = tot_len - header_len;
return TRUE;
}
@@ -4663,12 +4708,15 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
PWINDIVERT_TCPHDR tcp_header = NULL;
PWINDIVERT_UDPHDR udp_header = NULL;
UINT8 protocol = 0;
- UINT payload_len = 0;
+ UINT header_len = 0, payload_len = 0;
UINT16 ip, ttl;
PWINDIVERT_DATA_NETWORK network_data = NULL;
PWINDIVERT_DATA_FLOW flow_data = NULL;
PWINDIVERT_DATA_SOCKET socket_data = NULL;
PWINDIVERT_DATA_REFLECT reflect_data = NULL;
+ UINT8 data8;
+ UINT16 data16;
+ UINT32 data32;
NTSTATUS status;
switch (layer)
@@ -4677,7 +4725,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
case WINDIVERT_LAYER_NETWORK_FORWARD:
if (!windivert_parse_headers(buffer, ipv4, &ip_header, &ipv6_header,
&icmp_header, &icmpv6_header, &tcp_header, &udp_header,
- &protocol, &payload_len))
+ &protocol, &header_len, &payload_len))
{
return FALSE;
}
@@ -4703,12 +4751,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
while (ttl-- != 0)
{
BOOL result = FALSE;
- BOOL error = FALSE;
+ BOOL big = FALSE;
int cmp;
UINT32 field[4];
- field[1] = 0;
- field[2] = 0;
- field[3] = 0;
switch (filter[ip].field)
{
@@ -4733,6 +4778,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
break;
case WINDIVERT_FILTER_FIELD_IFIDX:
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
+ case WINDIVERT_FILTER_FIELD_PACKET:
+ case WINDIVERT_FILTER_FIELD_PACKET16:
+ case WINDIVERT_FILTER_FIELD_PACKET32:
result = (layer == WINDIVERT_LAYER_NETWORK ||
layer == WINDIVERT_LAYER_NETWORK_FORWARD);
break;
@@ -4810,6 +4858,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
case WINDIVERT_FILTER_FIELD_TCP_WINDOW:
case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
result = (layer == WINDIVERT_LAYER_NETWORK ||
layer == WINDIVERT_LAYER_NETWORK_FORWARD);
@@ -4819,15 +4870,16 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
case WINDIVERT_FILTER_FIELD_UDP_DSTPORT:
case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
result = (layer == WINDIVERT_LAYER_NETWORK ||
layer == WINDIVERT_LAYER_NETWORK_FORWARD);
result = result && (udp_header != NULL);
break;
default:
- result = FALSE;
- error = TRUE;
- break;
+ return FALSE;
}
if (result)
{
@@ -4839,6 +4891,39 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
case WINDIVERT_FILTER_FIELD_EVENT:
field[0] = (UINT32)event;
break;
+ case WINDIVERT_FILTER_FIELD_PACKET:
+ result = windivert_get_data(buffer, /*offset=*/0,
+ (INT)filter[ip].arg[1], sizeof(data8), &data8);
+ field[0] = (UINT32)data8;
+ break;
+ case WINDIVERT_FILTER_FIELD_PACKET16:
+ result = windivert_get_data(buffer, /*offset=*/0,
+ (INT)filter[ip].arg[1], sizeof(data16), &data16);
+ field[0] = (UINT32)RtlUshortByteSwap(data16);
+ break;
+ case WINDIVERT_FILTER_FIELD_PACKET32:
+ result = windivert_get_data(buffer, /*offset=*/0,
+ (INT)filter[ip].arg[1], sizeof(data32), &data32);
+ field[0] = (UINT32)RtlUlongByteSwap(data32);
+ break;
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
+ result = windivert_get_data(buffer, header_len,
+ (INT)filter[ip].arg[1], sizeof(data8), &data8);
+ field[0] = (UINT32)data8;
+ break;
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
+ result = windivert_get_data(buffer, header_len,
+ (INT)filter[ip].arg[1], sizeof(data16), &data16);
+ field[0] = (UINT32)RtlUshortByteSwap(data16);
+ break;
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
+ result = windivert_get_data(buffer, header_len,
+ (INT)filter[ip].arg[1], sizeof(data32), &data32);
+ field[0] = (UINT32)RtlUlongByteSwap(data32);
+ break;
case WINDIVERT_FILTER_FIELD_INBOUND:
field[0] = (UINT32)!outbound;
break;
@@ -4879,9 +4964,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
flow_data->Protocol == IPPROTO_ICMP);
break;
default:
- error = TRUE;
- result = FALSE;
- break;
+ return FALSE;
}
break;
case WINDIVERT_FILTER_FIELD_ICMPV6:
@@ -4900,9 +4983,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
flow_data->Protocol == IPPROTO_ICMPV6);
break;
default:
- error = TRUE;
- result = FALSE;
- break;
+ return FALSE;
}
break;
case WINDIVERT_FILTER_FIELD_TCP:
@@ -4921,9 +5002,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
(UINT32)(flow_data->Protocol == IPPROTO_TCP);
break;
default:
- error = TRUE;
- result = FALSE;
- break;
+ return FALSE;
}
break;
case WINDIVERT_FILTER_FIELD_UDP:
@@ -4942,9 +5021,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
(UINT32)(flow_data->Protocol == IPPROTO_UDP);
break;
default:
- error = TRUE;
- result = FALSE;
- break;
+ return FALSE;
}
break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
@@ -5004,6 +5081,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
field[0] = (UINT32)ipv6_header->HopLimit;
break;
case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
+ big = TRUE;
field[3] =
(UINT32)RtlUlongByteSwap(ipv6_header->SrcAddr[0]);
field[2] =
@@ -5014,6 +5092,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
(UINT32)RtlUlongByteSwap(ipv6_header->SrcAddr[3]);
break;
case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
+ big = TRUE;
field[3] =
(UINT32)RtlUlongByteSwap(ipv6_header->DstAddr[0]);
field[2] =
@@ -5111,6 +5190,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
field[0] = (UINT32)payload_len;
break;
case WINDIVERT_FILTER_FIELD_LOCALADDR:
+ big = TRUE;
switch (layer)
{
case WINDIVERT_LAYER_NETWORK:
@@ -5157,12 +5237,11 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
field[3] = socket_data->LocalAddr[3];
break;
default:
- error = TRUE;
- result = FALSE;
- break;
+ return FALSE;
}
break;
case WINDIVERT_FILTER_FIELD_REMOTEADDR:
+ big = TRUE;
switch (layer)
{
case WINDIVERT_LAYER_NETWORK:
@@ -5209,9 +5288,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
field[3] = socket_data->RemoteAddr[3];
break;
default:
- error = TRUE;
- result = FALSE;
- break;
+ return FALSE;
}
break;
case WINDIVERT_FILTER_FIELD_LOCALPORT:
@@ -5242,9 +5319,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
field[0] = (UINT32)socket_data->LocalPort;
break;
default:
- error = TRUE;
- result = FALSE;
- break;
+ return FALSE;
}
break;
case WINDIVERT_FILTER_FIELD_REMOTEPORT:
@@ -5275,9 +5350,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
field[0] = (UINT32)socket_data->RemotePort;
break;
default:
- error = TRUE;
- result = FALSE;
- break;
+ return FALSE;
}
break;
case WINDIVERT_FILTER_FIELD_PROTOCOL:
@@ -5293,9 +5366,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
field[0] = (UINT32)socket_data->Protocol;
break;
default:
- error = TRUE;
- result = FALSE;
- break;
+ return FALSE;
}
break;
case WINDIVERT_FILTER_FIELD_PROCESSID:
@@ -5311,22 +5382,19 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
field[0] = reflect_data->ProcessId;
break;
default:
- error = TRUE;
- result = FALSE;
+ return FALSE;
}
break;
case WINDIVERT_FILTER_FIELD_LAYER:
field[0] = reflect_data->Layer;
break;
default:
- error = TRUE;
- result = FALSE;
- break;
+ return FALSE;
}
}
if (result)
{
- cmp = windivert_big_num_compare(field, filter[ip].arg);
+ cmp = windivert_big_num_compare(field, filter[ip].arg, big);
switch (filter[ip].test)
{
case WINDIVERT_FILTER_TEST_EQ:
@@ -5348,16 +5416,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
result = (cmp >= 0);
break;
default:
- error = TRUE;
- result = FALSE;
- break;
+ return FALSE;
}
}
- if (error)
- {
- DEBUG("FILTER: REJECT (bad filter)");
- return FALSE;
- }
ip = (result? filter[ip].success: filter[ip].failure);
if (ip == WINDIVERT_FILTER_RESULT_ACCEPT)
{
@@ -5447,17 +5508,38 @@ static PWINDIVERT_FILTER windivert_filter_compile(
{
goto windivert_filter_compile_error;
}
- if ((ioctl_filter[i].field == WINDIVERT_FILTER_FIELD_IP_SRCADDR ||
- ioctl_filter[i].field == WINDIVERT_FILTER_FIELD_IP_DSTADDR))
+ switch (ioctl_filter[i].field)
{
- if (ioctl_filter[i].arg[1] != 0x0000FFFF)
+ case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
+ case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
+ if (ioctl_filter[i].arg[1] != 0x0000FFFF)
+ {
+ goto windivert_filter_compile_error;
+ }
+ break;
+ case WINDIVERT_FILTER_FIELD_PACKET:
+ case WINDIVERT_FILTER_FIELD_PACKET16:
+ case WINDIVERT_FILTER_FIELD_PACKET32:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
{
- goto windivert_filter_compile_error;
+ INT idx = (INT)ioctl_filter[i].arg[1];
+ if (idx > UINT16_MAX || idx < -UINT16_MAX)
+ {
+ goto windivert_filter_compile_error;
+ }
+ break;
}
- }
- else if (ioctl_filter[i].arg[1] != 0)
- {
- goto windivert_filter_compile_error;
+ default:
+ if (ioctl_filter[i].arg[1] != 0)
+ {
+ goto windivert_filter_compile_error;
+ }
+ break;
}
}
switch (ioctl_filter[i].field)
@@ -5547,6 +5629,9 @@ static PWINDIVERT_FILTER windivert_filter_compile(
case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE:
case WINDIVERT_FILTER_FIELD_ICMPV6_CODE:
case WINDIVERT_FILTER_FIELD_PROTOCOL:
+ case WINDIVERT_FILTER_FIELD_PACKET:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
if (ioctl_filter[i].arg[0] > UINT8_MAX)
{
goto windivert_filter_compile_error;
@@ -5577,6 +5662,9 @@ static PWINDIVERT_FILTER windivert_filter_compile(
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
case WINDIVERT_FILTER_FIELD_LOCALPORT:
case WINDIVERT_FILTER_FIELD_REMOTEPORT:
+ case WINDIVERT_FILTER_FIELD_PACKET16:
+ case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
if (ioctl_filter[i].arg[0] > UINT16_MAX)
{
goto windivert_filter_compile_error;
diff --git a/test/test.c b/test/test.c
index ed8b590..7dde63a 100644
--- a/test/test.c
+++ b/test/test.c
@@ -114,6 +114,22 @@ static struct packet pkt_ipv6_exthdrs_udp =
static struct test tests[] =
{
{"event = PACKET", &pkt_echo_request, TRUE},
+ {"packet[0] == 0x45", &pkt_echo_request, TRUE},
+ {"packet[0] == 0x33", &pkt_echo_request, FALSE},
+ {"packet[55] == 0x1b", &pkt_echo_request, TRUE},
+ {"packet[55b] == 0x1b", &pkt_echo_request, TRUE},
+ {"packet[1000] <= 0 || packet[-1000] = 7", &pkt_echo_request, FALSE},
+ {"packet[-1] == 0x37 && packet[-2] == 0x36 && packet[-3] == 0x35 && "
+ "packet[-4] == 0x34", &pkt_echo_request, TRUE},
+ {"packet16[0] == 0x4500", &pkt_echo_request, TRUE},
+ {"packet16[0] == 0x0045", &pkt_echo_request, FALSE},
+ {"packet16[2b] == 0x0054", &pkt_echo_request, TRUE},
+ {"packet16[1] == 0x0054", &pkt_echo_request, TRUE},
+ {"packet16[0] == 0x4500 && packet16[1] == 0x0054 && "
+ "packet16[-1] == 0x3637", &pkt_echo_request, TRUE},
+ {"packet32[0b] == 0x45000054 && packet32[3b] == 0x54123440 && "
+ "packet32[-4b] == 0x34353637 && packet32[-5b] == 0x33343536",
+ &pkt_echo_request, TRUE},
{"outbound and icmp", &pkt_echo_request, TRUE},
{"outbound", &pkt_echo_request, TRUE},
{"outbound and inbound", &pkt_echo_request, FALSE},
@@ -245,6 +261,74 @@ static struct test tests[] =
{"(ipv6? tcp and tcp.DstPort = 1234 and (tcp.SrcPort = 999? !tcp.UrgPtr: "
"tcp.Syn) or udp: ip and tcp.DstPort == 80)",
&pkt_http_request, TRUE},
+ {"packet32[0] = 0x45000209 && packet32[1] = 0x482d4000 && "
+ "packet16[8b] = 0x4006 && packet32[3] = 0x0a0a0a0a && "
+ "packet32[4] = 0x5db8d877 && packet32[5] = 0xa31a0050 && "
+ "packet32[6] = 0x5338ccc2 && packet32[7] = 0x5637b355 && "
+ "packet32[8] = 0x80180073 && packet16[38b] = 0x0000 && "
+ "packet32[10] = 0x0101080a && packet32[11] = 0x002c851b && "
+ "packet32[12] = 0x1b7f3a71 && packet32[13] = 0x47455420 && "
+ "packet32[14] = 0x2f204854 && packet32[15] = 0x54502f31 && "
+ "packet32[16] = 0x2e310d0a && packet32[17] = 0x486f7374 && "
+ "packet32[18] = 0x3a207777 && packet32[19] = 0x772e6578 && "
+ "packet32[20] = 0x616d706c && packet32[21] = 0x652e636f && "
+ "packet32[22] = 0x6d0d0a43 && packet32[23] = 0x6f6e6e65 && "
+ "packet32[24] = 0x6374696f && packet32[25] = 0x6e3a206b && "
+ "packet32[26] = 0x6565702d && packet32[27] = 0x616c6976 && "
+ "packet32[28] = 0x650d0a43 && packet32[29] = 0x61636865 && "
+ "packet32[30] = 0x2d436f6e && packet32[31] = 0x74726f6c && "
+ "packet32[32] = 0x3a206d61 && packet32[33] = 0x782d6167 && "
+ "packet32[34] = 0x653d300d && packet32[35] = 0x0a416363 && "
+ "packet32[36] = 0x6570743a && packet32[37] = 0x20746578 && "
+ "packet32[38] = 0x742f6874 && packet32[39] = 0x6d6c2c61 && "
+ "packet32[40] = 0x70706c69 && packet32[41] = 0x63617469 && "
+ "packet32[42] = 0x6f6e2f78 && packet32[43] = 0x68746d6c && "
+ "packet32[44] = 0x2b786d6c && packet32[45] = 0x2c617070 && "
+ "packet32[46] = 0x6c696361 && packet32[47] = 0x74696f6e && "
+ "packet32[48] = 0x2f786d6c && packet32[49] = 0x3b713d30 && "
+ "packet32[50] = 0x2e392c69 && packet32[51] = 0x6d616765 && "
+ "packet32[52] = 0x2f776562 && packet32[53] = 0x702c2a2f && "
+ "packet32[54] = 0x2a3b713d && packet32[55] = 0x302e380d && "
+ "packet32[56] = 0x0a557365 && packet32[57] = 0x722d4167 && "
+ "packet32[58] = 0x656e743a && packet32[59] = 0x20585858 && "
+ "packet32[60] = 0x58585858 && packet32[61] = 0x58585858 && "
+ "packet32[62] = 0x58585858 && packet32[63] = 0x58585858 && "
+ "packet32[64] = 0x58585858 && packet32[65] = 0x58585858 && "
+ "packet32[66] = 0x58585858 && packet32[67] = 0x58585858 && "
+ "packet32[68] = 0x58585858 && packet32[69] = 0x58585858 && "
+ "packet32[70] = 0x58585858 && packet32[71] = 0x58585858 && "
+ "packet32[72] = 0x58585858 && packet32[73] = 0x58585858 && "
+ "packet32[74] = 0x58585858 && packet32[75] = 0x58585858 && "
+ "packet32[76] = 0x58585858 && packet32[77] = 0x58585858 && "
+ "packet32[78] = 0x58585858 && packet32[79] = 0x58585858 && "
+ "packet32[80] = 0x58585858 && packet32[81] = 0x58585858 && "
+ "packet32[82] = 0x58585858 && packet32[83] = 0x58585858 && "
+ "packet32[84] = 0x58585858 && packet32[85] = 0x58585858 && "
+ "packet32[86] = 0x58585858 && packet32[87] = 0x58585858 && "
+ "packet32[88] = 0x58585858 && packet32[89] = 0x58585858 && "
+ "packet32[90] = 0x58585858 && packet32[91] = 0x58585858 && "
+ "packet32[92] = 0x58580d0a && packet32[93] = 0x41636365 && "
+ "packet32[94] = 0x70742d45 && packet32[95] = 0x6e636f64 && "
+ "packet32[96] = 0x696e673a && packet32[97] = 0x20677a69 && "
+ "packet32[98] = 0x702c6465 && packet32[99] = 0x666c6174 && "
+ "packet32[100] = 0x652c7364 && packet32[101] = 0x63680d0a && "
+ "packet32[102] = 0x41636365 && packet32[103] = 0x70742d4c && "
+ "packet32[104] = 0x616e6775 && packet32[105] = 0x6167653a && "
+ "packet32[106] = 0x20656e2d && packet32[107] = 0x55532c65 && "
+ "packet32[108] = 0x6e3b713d && packet32[109] = 0x302e380d && "
+ "packet32[110] = 0x0a49662d && packet32[111] = 0x4e6f6e65 && "
+ "packet32[112] = 0x2d4d6174 && packet32[113] = 0x63683a20 && "
+ "packet32[114] = 0x22333333 && packet32[115] = 0x33333333 && "
+ "packet32[116] = 0x3333220d && packet32[117] = 0x0a49662d && "
+ "packet32[118] = 0x4d6f6469 && packet32[119] = 0x66696564 && "
+ "packet32[120] = 0x2d53696e && packet32[121] = 0x63653a20 && "
+ "packet32[122] = 0x4672692c && packet32[123] = 0x20303320 && "
+ "packet32[124] = 0x41756720 && packet32[125] = 0x32303134 && "
+ "packet32[126] = 0x2031333a && packet32[127] = 0x33333a33 && "
+ "packet32[128] = 0x3320474d && packet32[129] = 0x540d0a0d && "
+ "packet[-1] = 0x0a", &pkt_http_request, TRUE},
+ {"tcp.Payload16[-1] == 0x0d0a", &pkt_http_request, TRUE},
+ {"tcp.Payload32[-2] == 0x20474d54", &pkt_http_request, TRUE},
{"udp", &pkt_dns_request, TRUE},
{"udp && udp.SrcPort > 1 && ipv6", &pkt_dns_request, FALSE},
{"udp.DstPort == 53", &pkt_dns_request, TRUE},
@@ -260,6 +344,10 @@ static struct test tests[] =
{"ip.DstAddr == ::ffff:8.8.4.4", &pkt_dns_request, TRUE},
{"ip.DstAddr == ::0:ffff:8.8.4.4", &pkt_dns_request, TRUE},
{"udp.PayloadLength == 29", &pkt_dns_request, TRUE},
+ {"udp.Payload16[-1] == 0x0001 && udp.Payload16[-2] == 0x0001",
+ &pkt_dns_request, TRUE},
+ {"packet16[-1] == 0x0001 && packet16[-2] == 0x0001",
+ &pkt_dns_request, TRUE},
{"ipv6", &pkt_ipv6_tcp_syn, TRUE},
{"ip", &pkt_ipv6_tcp_syn, FALSE},
{"tcp.Syn", &pkt_ipv6_tcp_syn, TRUE},
@@ -351,7 +439,7 @@ int main(void)
// Run the test:
BOOL res = run_test(upper_handle, filter, packet, packet_len, match);
- printf("%.2u ", i);
+ printf("%.3u ", i);
if (res)
{
SetConsoleTextAttribute(console, FOREGROUND_GREEN);
From 084c78e4afd0c2d838dc5f70292622bd219f2f6f Mon Sep 17 00:00:00 2001
From: basil00
Date: Fri, 9 Nov 2018 07:21:56 +0800
Subject: [PATCH 16/23] Code cleanup & improve const correctness in API.
---
dll/windivert.c | 15 +-
dll/windivert_helper.c | 12 +-
dll/windivert_shared.c | 6 +-
include/windivert.h | 24 +-
include/windivert_device.h | 22 +-
sys/windivert.c | 467 ++++++++++++++++---------------------
6 files changed, 247 insertions(+), 299 deletions(-)
diff --git a/dll/windivert.c b/dll/windivert.c
index 0a7d63c..fd30f66 100644
--- a/dll/windivert.c
+++ b/dll/windivert.c
@@ -534,18 +534,18 @@ extern BOOL WinDivertRecvEx(HANDLE handle, PVOID pPacket, UINT packetLen,
/*
* Send a WinDivert packet.
*/
-extern BOOL WinDivertSend(HANDLE handle, PVOID pPacket, UINT packetLen,
- PWINDIVERT_ADDRESS addr, UINT *writelen)
+extern BOOL WinDivertSend(HANDLE handle, const VOID *pPacket, UINT packetLen,
+ const WINDIVERT_ADDRESS *addr, UINT *writelen)
{
return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND, (UINT64)addr,
- sizeof(WINDIVERT_ADDRESS), pPacket, packetLen, writelen);
+ sizeof(WINDIVERT_ADDRESS), (PVOID)pPacket, packetLen, writelen);
}
/*
* Send a WinDivert packet.
*/
-extern BOOL WinDivertSendEx(HANDLE handle, PVOID pPacket, UINT packetLen,
- UINT *writeLen, UINT64 flags, PWINDIVERT_ADDRESS addr, UINT addrLen,
+extern BOOL WinDivertSendEx(HANDLE handle, const VOID *pPacket, UINT packetLen,
+ UINT *writeLen, UINT64 flags, const WINDIVERT_ADDRESS *addr, UINT addrLen,
LPOVERLAPPED overlapped)
{
if (flags != 0)
@@ -556,12 +556,13 @@ extern BOOL WinDivertSendEx(HANDLE handle, PVOID pPacket, UINT packetLen,
if (overlapped == NULL)
{
return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND,
- (UINT64)addr, (UINT64)addrLen, pPacket, packetLen, writeLen);
+ (UINT64)addr, (UINT64)addrLen, (PVOID)pPacket, packetLen,
+ writeLen);
}
else
{
return WinDivertIoControlEx(handle, IOCTL_WINDIVERT_SEND,
- (UINT64)addr, (UINT64)addrLen, pPacket, packetLen, writeLen,
+ (UINT64)addr, (UINT64)addrLen, (PVOID)pPacket, packetLen, writeLen,
overlapped);
}
}
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index 5057d08..3c200a9 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -282,13 +282,13 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
/*
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
*/
-extern BOOL WinDivertHelperParsePacket(PVOID pPacket, UINT packetLen,
+extern BOOL WinDivertHelperParsePacket(const VOID *pPacket, UINT packetLen,
PWINDIVERT_IPHDR *ppIpHdr, PWINDIVERT_IPV6HDR *ppIpv6Hdr,
PWINDIVERT_ICMPHDR *ppIcmpHdr, PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr,
PWINDIVERT_TCPHDR *ppTcpHdr, PWINDIVERT_UDPHDR *ppUdpHdr, PVOID *ppData,
UINT *pDataLen)
{
- return WinDivertParsePacket(pPacket, packetLen, ppIpHdr, ppIpv6Hdr,
+ return WinDivertParsePacket((PVOID)pPacket, packetLen, ppIpHdr, ppIpv6Hdr,
ppIcmpHdr, ppIcmpv6Hdr, ppTcpHdr, ppUdpHdr, NULL, ppData, pDataLen);
}
@@ -2316,7 +2316,7 @@ static int WinDivertBigNumCompare(const UINT32 *a, const UINT32 *b, BOOL big)
/*
* Get packet/payload data.
*/
-static BOOL WinDivertGetData(PVOID packet, UINT packet_len, UINT offset,
+static BOOL WinDivertGetData(const VOID *packet, UINT packet_len, UINT offset,
INT idx, UINT size, PVOID data)
{
if (idx < 0)
@@ -2338,8 +2338,8 @@ static BOOL WinDivertGetData(PVOID packet, UINT packet_len, UINT offset,
/*
* Evaluate the given filter with the given packet as input.
*/
-extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
- UINT packet_len, PWINDIVERT_ADDRESS addr)
+extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
+ UINT packet_len, const WINDIVERT_ADDRESS *addr)
{
UINT16 pc;
ERROR err;
@@ -2374,7 +2374,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet,
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- WinDivertParsePacket(packet, packet_len, &iphdr, &ipv6hdr,
+ WinDivertParsePacket((PVOID)packet, packet_len, &iphdr, &ipv6hdr,
&icmphdr, &icmpv6hdr, &tcphdr, &udphdr, &protocol, NULL,
&payload_len);
header_len = packet_len - payload_len;
diff --git a/dll/windivert_shared.c b/dll/windivert_shared.c
index bd6b9e0..ed15081 100644
--- a/dll/windivert_shared.c
+++ b/dll/windivert_shared.c
@@ -165,7 +165,7 @@ static void WinDivertSerializeNumber(PWINDIVERT_STREAM stream, UINT32 val)
* Serialize a test.
*/
static void WinDivertSerializeTest(PWINDIVERT_STREAM stream,
- PWINDIVERT_FILTER filter)
+ const WINDIVERT_FILTER *filter)
{
INT idx;
UINT i;
@@ -209,7 +209,7 @@ static void WinDivertSerializeTest(PWINDIVERT_STREAM stream,
* Serialize a test.
*/
static void WinDivertSerializeFilter(PWINDIVERT_STREAM stream,
- PWINDIVERT_FILTER filter, UINT8 length)
+ const WINDIVERT_FILTER *filter, UINT8 length)
{
UINT8 i;
WinDivertPutString(stream, "@WinDiv_"); // Magic
@@ -443,7 +443,7 @@ WinDivertHelperParsePacketExit:
* Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums.
*/
extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
- PWINDIVERT_ADDRESS pAddr, UINT64 flags)
+ const WINDIVERT_ADDRESS *pAddr, UINT64 flags)
{
UINT8 pseudo_header[
MAX(sizeof(WINDIVERT_PSEUDOHDR), sizeof(WINDIVERT_PSEUDOV6HDR))];
diff --git a/include/windivert.h b/include/windivert.h
index 354b4e0..a736f37 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -220,9 +220,9 @@ extern WINDIVERTEXPORT HANDLE WinDivertOpen(
*/
extern WINDIVERTEXPORT BOOL WinDivertRecv(
__in HANDLE handle,
- __out PVOID pPacket,
+ __out VOID *pPacket,
__in UINT packetLen,
- __out_opt PWINDIVERT_ADDRESS pAddr,
+ __out_opt WINDIVERT_ADDRESS *pAddr,
__out_opt UINT *pReadLen);
/*
@@ -234,7 +234,7 @@ extern WINDIVERTEXPORT BOOL WinDivertRecvEx(
__in UINT packetLen,
__out_opt UINT *pReadLen,
__in UINT64 flags,
- __out PWINDIVERT_ADDRESS pAddr,
+ __out WINDIVERT_ADDRESS *pAddr,
__inout_opt UINT *pAddrLen,
__inout_opt LPOVERLAPPED lpOverlapped);
@@ -243,9 +243,9 @@ extern WINDIVERTEXPORT BOOL WinDivertRecvEx(
*/
extern WINDIVERTEXPORT BOOL WinDivertSend(
__in HANDLE handle,
- __in PVOID pPacket,
+ __in const VOID *pPacket,
__in UINT packetLen,
- __in PWINDIVERT_ADDRESS pAddr,
+ __in const WINDIVERT_ADDRESS *pAddr,
__out_opt UINT *pWriteLen);
/*
@@ -253,11 +253,11 @@ extern WINDIVERTEXPORT BOOL WinDivertSend(
*/
extern WINDIVERTEXPORT BOOL WinDivertSendEx(
__in HANDLE handle,
- __in PVOID pPacket,
+ __in const VOID *pPacket,
__in UINT packetLen,
__out_opt UINT *pWriteLen,
__in UINT64 flags,
- __in PWINDIVERT_ADDRESS pAddr,
+ __in const WINDIVERT_ADDRESS *pAddr,
__in UINT addrLen,
__inout_opt LPOVERLAPPED lpOverlapped);
@@ -438,7 +438,7 @@ typedef struct
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
*/
extern WINDIVERTEXPORT BOOL WinDivertHelperParsePacket(
- __in PVOID pPacket,
+ __in const VOID *pPacket,
__in UINT packetLen,
__out_opt PWINDIVERT_IPHDR *ppIpHdr,
__out_opt PWINDIVERT_IPV6HDR *ppIpv6Hdr,
@@ -483,9 +483,9 @@ extern WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv6Address(
* Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums.
*/
extern WINDIVERTEXPORT UINT WinDivertHelperCalcChecksums(
- __inout PVOID pPacket,
+ __inout VOID *pPacket,
__in UINT packetLen,
- __in_opt PWINDIVERT_ADDRESS pAddr,
+ __in_opt const WINDIVERT_ADDRESS *pAddr,
__in UINT64 flags);
/*
@@ -504,9 +504,9 @@ extern WINDIVERTEXPORT BOOL WinDivertHelperCompileFilter(
*/
extern WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter(
__in const char *filter,
- __in PVOID pPacket,
+ __in const VOID *pPacket,
__in UINT packetLen,
- __in PWINDIVERT_ADDRESS pAddr);
+ __in const WINDIVERT_ADDRESS *pAddr);
/*
* Format the given filter string.
diff --git a/include/windivert_device.h b/include/windivert_device.h
index 3efd822..22bb898 100644
--- a/include/windivert_device.h
+++ b/include/windivert_device.h
@@ -245,20 +245,26 @@ typedef struct
* IOCTL codes.
*/
#define IOCTL_WINDIVERT_RECV \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x918, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x918, METHOD_OUT_DIRECT, FILE_READ_DATA)
#define IOCTL_WINDIVERT_SEND \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x919, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x919, METHOD_IN_DIRECT, FILE_READ_DATA | \
+ FILE_WRITE_DATA)
#define IOCTL_WINDIVERT_START_FILTER \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x91A, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x91A, METHOD_IN_DIRECT, FILE_READ_DATA | \
+ FILE_WRITE_DATA)
#define IOCTL_WINDIVERT_SET_LAYER \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x91B, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x91B, METHOD_IN_DIRECT, FILE_READ_DATA | \
+ FILE_WRITE_DATA)
#define IOCTL_WINDIVERT_SET_PRIORITY \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x91C, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x91C, METHOD_IN_DIRECT, FILE_READ_DATA | \
+ FILE_WRITE_DATA)
#define IOCTL_WINDIVERT_SET_FLAGS \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x91D, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x91D, METHOD_IN_DIRECT, FILE_READ_DATA | \
+ FILE_WRITE_DATA)
#define IOCTL_WINDIVERT_SET_PARAM \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x91E, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x91E, METHOD_IN_DIRECT, FILE_READ_DATA | \
+ FILE_WRITE_DATA)
#define IOCTL_WINDIVERT_GET_PARAM \
- CTL_CODE(FILE_DEVICE_NETWORK, 0x91F, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x91F, METHOD_OUT_DIRECT, FILE_READ_DATA)
#endif /* __WINDIVERT_DEVICE_H */
diff --git a/sys/windivert.c b/sys/windivert.c
index 175991c..8af6571 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -128,7 +128,6 @@ struct reflect_context_s
*/
#define WINDIVERT_CONTEXT_SIZE (sizeof(struct context_s))
#define WINDIVERT_CONTEXT_MAXLAYERS 8
-#define WINDIVERT_CONTEXT_MAXWORKERS 1
typedef enum
{
WINDIVERT_CONTEXT_STATE_OPENING = 0xA0, // Context is opening.
@@ -156,9 +155,7 @@ struct context_s
LONGLONG packet_queue_maxcounts; // Packet queue max counts.
ULONG packet_queue_maxtime; // Packet queue max time.
WDFQUEUE read_queue; // Read queue.
- WDFWORKITEM workers[WINDIVERT_CONTEXT_MAXWORKERS];
- // Read workers.
- UINT8 worker_curr; // Current read worker.
+ WDFWORKITEM worker; // Read worker.
WINDIVERT_LAYER layer; // Context's layer.
UINT64 flags; // Context's flags.
UINT32 priority; // Context (internal) priority.
@@ -169,7 +166,7 @@ struct context_s
// Filter GUIDs.
BOOL installed[WINDIVERT_CONTEXT_MAXLAYERS];// What is installed?
HANDLE engine_handle; // WFP engine handle.
- PWINDIVERT_FILTER filter; // Packet filter.
+ const WINDIVERT_FILTER *filter; // Packet filter.
UINT8 filter_len; // Length of filter.
struct reflect_context_s reflect; // Reflection info.
};
@@ -200,14 +197,14 @@ struct layer_s
wchar_t *callout_desc; // Call-out description.
wchar_t *filter_name; // Filter name.
wchar_t *filter_desc; // Filter description.
- GUID layer_guid; // WFP layer GUID.
- GUID sublayer_guid; // Sub-layer GUID.
+ const GUID *layer_guid; // WFP layer GUID.
+ const GUID *sublayer_guid; // Sub-layer GUID.
windivert_classify_t classify; // Classify function.
windivert_flow_delete_notify_t flow_delete;
// Flow delete function.
UINT16 sublayer_weight; // Sub-layer weight.
};
-typedef struct layer_s *layer_t;
+typedef const struct layer_s *layer_t;
/*
* WinDivert request context.
@@ -466,10 +463,10 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
PWINDIVERT_TCPHDR *tcp_header_ptr, PWINDIVERT_UDPHDR *udp_header_ptr,
UINT8 *proto_ptr, UINT *header_len_ptr, UINT *payload_len_ptr);
static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
- PVOID layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound,
- BOOL loopback, BOOL impostor, PWINDIVERT_FILTER filter);
-static PWINDIVERT_FILTER windivert_filter_compile(
- PWINDIVERT_FILTER ioctl_filter, size_t ioctl_filter_len,
+ const VOID *layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound,
+ BOOL loopback, BOOL impostor, const WINDIVERT_FILTER *filter);
+static const WINDIVERT_FILTER *windivert_filter_compile(
+ const WINDIVERT_FILTER *ioctl_filter, size_t ioctl_filter_len,
WINDIVERT_LAYER layer);
static NTSTATUS windivert_reflect_init(WDFOBJECT parent);
static void windivert_reflect_close(void);
@@ -536,7 +533,7 @@ DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV6_GUID,
/*
* WinDivert supported layers.
*/
-static struct layer_s layer_inbound_network_ipv4_0 =
+static const struct layer_s windivert_layer_inbound_network_ipv4 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerInboundNetworkIPv4",
L"" WINDIVERT_DEVICE_NAME L" sublayer network (inbound IPv4)",
@@ -544,15 +541,16 @@ static struct layer_s layer_inbound_network_ipv4_0 =
L"" WINDIVERT_DEVICE_NAME L" callout network (inbound IPv4)",
L"" WINDIVERT_DEVICE_NAME L"_FilterInboundNetworkIPv4",
L"" WINDIVERT_DEVICE_NAME L" filter network (inbound IPv4)",
- {0},
- {0},
+ &FWPM_LAYER_INBOUND_IPPACKET_V4,
+ &WINDIVERT_SUBLAYER_INBOUND_IPV4_GUID,
windivert_inbound_network_v4_classify,
NULL,
UINT16_MAX
};
-static layer_t layer_inbound_network_ipv4 = &layer_inbound_network_ipv4_0;
+#define WINDIVERT_LAYER_INBOUND_NETWORK_IPV4 \
+ (&windivert_layer_inbound_network_ipv4)
-static struct layer_s layer_outbound_network_ipv4_0 =
+static const struct layer_s windivert_layer_outbound_network_ipv4 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerOutboundNetworkIPv4",
L"" WINDIVERT_DEVICE_NAME L" sublayer network (outbound IPv4)",
@@ -560,15 +558,16 @@ static struct layer_s layer_outbound_network_ipv4_0 =
L"" WINDIVERT_DEVICE_NAME L" callout network (outbound IPv4)",
L"" WINDIVERT_DEVICE_NAME L"_FilterOutboundNetworkIPv4",
L"" WINDIVERT_DEVICE_NAME L" filter network (outbound IPv4)",
- {0},
- {0},
+ &FWPM_LAYER_OUTBOUND_IPPACKET_V4,
+ &WINDIVERT_SUBLAYER_OUTBOUND_IPV4_GUID,
windivert_outbound_network_v4_classify,
NULL,
UINT16_MAX
};
-static layer_t layer_outbound_network_ipv4 = &layer_outbound_network_ipv4_0;
+#define WINDIVERT_LAYER_OUTBOUND_NETWORK_IPV4 \
+ (&windivert_layer_outbound_network_ipv4)
-static struct layer_s layer_inbound_network_ipv6_0 =
+static const struct layer_s windivert_layer_inbound_network_ipv6 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerInboundNetworkIPv6",
L"" WINDIVERT_DEVICE_NAME L" sublayer network (inbound IPv6)",
@@ -576,15 +575,16 @@ static struct layer_s layer_inbound_network_ipv6_0 =
L"" WINDIVERT_DEVICE_NAME L" callout network (inbound IPv6)",
L"" WINDIVERT_DEVICE_NAME L"_FilterInboundNetworkIPv6",
L"" WINDIVERT_DEVICE_NAME L" filter network (inbound IPv6)",
- {0},
- {0},
+ &FWPM_LAYER_INBOUND_IPPACKET_V6,
+ &WINDIVERT_SUBLAYER_INBOUND_IPV6_GUID,
windivert_inbound_network_v6_classify,
NULL,
UINT16_MAX
};
-static layer_t layer_inbound_network_ipv6 = &layer_inbound_network_ipv6_0;
+#define WINDIVERT_LAYER_INBOUND_NETWORK_IPV6 \
+ (&windivert_layer_inbound_network_ipv6)
-static struct layer_s layer_outbound_network_ipv6_0 =
+static const struct layer_s windivert_layer_outbound_network_ipv6 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerOutboundNetworkIPv6",
L"" WINDIVERT_DEVICE_NAME L" sublayer network (outbound IPv6)",
@@ -592,15 +592,16 @@ static struct layer_s layer_outbound_network_ipv6_0 =
L"" WINDIVERT_DEVICE_NAME L" callout network (outbound IPv6)",
L"" WINDIVERT_DEVICE_NAME L"_FilterOutboundNetworkIPv6",
L"" WINDIVERT_DEVICE_NAME L" filter network (outbound IPv6)",
- {0},
- {0},
+ &FWPM_LAYER_OUTBOUND_IPPACKET_V6,
+ &WINDIVERT_SUBLAYER_OUTBOUND_IPV6_GUID,
windivert_outbound_network_v6_classify,
NULL,
UINT16_MAX
};
-static layer_t layer_outbound_network_ipv6 = &layer_outbound_network_ipv6_0;
+#define WINDIVERT_LAYER_OUTBOUND_NETWORK_IPV6 \
+ (&windivert_layer_outbound_network_ipv6)
-static struct layer_s layer_forward_network_ipv4_0 =
+static const struct layer_s windivert_layer_forward_network_ipv4 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerForwardNetworkIPv4",
L"" WINDIVERT_DEVICE_NAME L" sublayer network (forward IPv4)",
@@ -608,15 +609,16 @@ static struct layer_s layer_forward_network_ipv4_0 =
L"" WINDIVERT_DEVICE_NAME L" callout network (forward IPv4)",
L"" WINDIVERT_DEVICE_NAME L"_FilterForwardNetworkIPv4",
L"" WINDIVERT_DEVICE_NAME L" filter network (forward IPv4)",
- {0},
- {0},
+ &FWPM_LAYER_IPFORWARD_V4,
+ &WINDIVERT_SUBLAYER_FORWARD_IPV4_GUID,
windivert_forward_network_v4_classify,
NULL,
UINT16_MAX
};
-static layer_t layer_forward_network_ipv4 = &layer_forward_network_ipv4_0;
+#define WINDIVERT_LAYER_FORWARD_NETWORK_IPV4 \
+ (&windivert_layer_forward_network_ipv4)
-static struct layer_s layer_forward_network_ipv6_0 =
+static const struct layer_s windivert_layer_forward_network_ipv6 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerForwardNetworkIPv6",
L"" WINDIVERT_DEVICE_NAME L" sublayer network (forward IPv6)",
@@ -624,145 +626,152 @@ static struct layer_s layer_forward_network_ipv6_0 =
L"" WINDIVERT_DEVICE_NAME L" callout network (forward IPv6)",
L"" WINDIVERT_DEVICE_NAME L"_FilterForwardNetworkIPv6",
L"" WINDIVERT_DEVICE_NAME L" filter network (forward IPv6)",
- {0},
- {0},
+ &FWPM_LAYER_IPFORWARD_V6,
+ &WINDIVERT_SUBLAYER_FORWARD_IPV6_GUID,
windivert_forward_network_v6_classify,
NULL,
UINT16_MAX
};
-static layer_t layer_forward_network_ipv6 = &layer_forward_network_ipv6_0;
+#define WINDIVERT_LAYER_FORWARD_NETWORK_IPV6 \
+ (&windivert_layer_forward_network_ipv6)
-static struct layer_s layer_resource_assignment_ipv4_0 =
+static const struct layer_s windivert_layer_resource_assignment_ipv4 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerResourceAssignmentIPv4",
- L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer resource assignment (IPv4)",
L"" WINDIVERT_DEVICE_NAME L"_CalloutResourceAssignmentIPv4",
- L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L" callout resource assignment (IPv4)",
L"" WINDIVERT_DEVICE_NAME L"_FilterResourceAssignmentIPv4",
- L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)",
- {0},
- {0},
+ L"" WINDIVERT_DEVICE_NAME L" filter resource assignment (IPv4)",
+ &FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4,
+ &WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV4_GUID,
windivert_resource_assignment_v4_classify,
NULL,
0
};
-static layer_t layer_resource_assignment_ipv4 =
- &layer_resource_assignment_ipv4_0;
+#define WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4 \
+ (&windivert_layer_resource_assignment_ipv4)
-static struct layer_s layer_resource_assignment_ipv6_0 =
+static const struct layer_s windivert_layer_resource_assignment_ipv6 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerResourceAssignmentIPv6",
- L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer resource assignment (IPv6)",
L"" WINDIVERT_DEVICE_NAME L"_CalloutResourceAssignmentIPv6",
- L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L" callout resource assignment (IPv6)",
L"" WINDIVERT_DEVICE_NAME L"_FilterResourceAssignmentIPv6",
- L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)",
- {0},
- {0},
+ L"" WINDIVERT_DEVICE_NAME L" filter resource assignment (IPv6)",
+ &FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6,
+ &WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV6_GUID,
windivert_resource_assignment_v6_classify,
NULL,
0
};
-static layer_t layer_resource_assignment_ipv6 =
- &layer_resource_assignment_ipv6_0;
+#define WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6 \
+ (&windivert_layer_resource_assignment_ipv6)
-static struct layer_s layer_auth_connect_ipv4_0 =
+static const struct layer_s windivert_layer_auth_connect_ipv4 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthConnectIPv4",
- L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer auth connect (IPv4)",
L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthConnectIPv4",
- L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L" callout auth connect (IPv4)",
L"" WINDIVERT_DEVICE_NAME L"_FilterAuthConnectIPv4",
- L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)",
- {0},
- {0},
+ L"" WINDIVERT_DEVICE_NAME L" filter auth connect (IPv4)",
+ &FWPM_LAYER_ALE_AUTH_CONNECT_V4,
+ &WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV4_GUID,
windivert_auth_connect_v4_classify,
NULL,
0
};
-static layer_t layer_auth_connect_ipv4 = &layer_auth_connect_ipv4_0;
+#define WINDIVERT_LAYER_AUTH_CONNECT_IPV4 \
+ (&windivert_layer_auth_connect_ipv4)
-static struct layer_s layer_auth_connect_ipv6_0 =
+static const struct layer_s windivert_layer_auth_connect_ipv6 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthConnectIPv6",
- L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer auth connect (IPv6)",
L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthConnectIPv6",
- L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L" callout auth connect (IPv6)",
L"" WINDIVERT_DEVICE_NAME L"_FilterAuthConnectIPv6",
- L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)",
- {0},
- {0},
+ L"" WINDIVERT_DEVICE_NAME L" filter auth connect (IPv6)",
+ &FWPM_LAYER_ALE_AUTH_CONNECT_V6,
+ &WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV6_GUID,
windivert_auth_connect_v6_classify,
NULL,
0
};
-static layer_t layer_auth_connect_ipv6 = &layer_auth_connect_ipv6_0;
+#define WINDIVERT_LAYER_AUTH_CONNECT_IPV6 \
+ (&windivert_layer_auth_connect_ipv6)
-static struct layer_s layer_auth_listen_ipv4_0 =
+static const struct layer_s windivert_layer_auth_listen_ipv4 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthListenIPv4",
- L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer auth listen (IPv4)",
L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthListenIPv4",
- L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L" callout auth listen (IPv4)",
L"" WINDIVERT_DEVICE_NAME L"_FilterAuthListenIPv4",
- L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)",
- {0},
- {0},
+ L"" WINDIVERT_DEVICE_NAME L" filter auth listen (IPv4)",
+ &FWPM_LAYER_ALE_AUTH_LISTEN_V4,
+ &WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV4_GUID,
windivert_auth_listen_v4_classify,
NULL,
0
};
-static layer_t layer_auth_listen_ipv4 = &layer_auth_listen_ipv4_0;
+#define WINDIVERT_LAYER_AUTH_LISTEN_IPV4 \
+ (&windivert_layer_auth_listen_ipv4)
-static struct layer_s layer_auth_listen_ipv6_0 =
+static const struct layer_s windivert_layer_auth_listen_ipv6 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthListenIPv6",
- L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer auth listen (IPv6)",
L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthListenIPv6",
- L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L" callout auth listen (IPv6)",
L"" WINDIVERT_DEVICE_NAME L"_FilterAuthListenIPv6",
- L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)",
- {0},
- {0},
+ L"" WINDIVERT_DEVICE_NAME L" filter auth listen (IPv6)",
+ &FWPM_LAYER_ALE_AUTH_LISTEN_V6,
+ &WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV6_GUID,
windivert_auth_listen_v6_classify,
NULL,
0
};
-static layer_t layer_auth_listen_ipv6 = &layer_auth_listen_ipv6_0;
+#define WINDIVERT_LAYER_AUTH_LISTEN_IPV6 \
+ (&windivert_layer_auth_listen_ipv6)
-static struct layer_s layer_auth_recv_accept_ipv4_0 =
+static const struct layer_s windivert_layer_auth_recv_accept_ipv4 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthRecvAcceptIPv4",
- L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer auth recv accept (IPv4)",
L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthRecvAcceptIPv4",
- L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L" callout auth recv accept (IPv4)",
L"" WINDIVERT_DEVICE_NAME L"_FilterAuthRecvAcceptIPv4",
- L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)",
- {0},
- {0},
+ L"" WINDIVERT_DEVICE_NAME L" filter auth recv accept (IPv4)",
+ &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4,
+ &WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV4_GUID,
windivert_auth_recv_accept_v4_classify,
NULL,
0
};
-static layer_t layer_auth_recv_accept_ipv4 = &layer_auth_recv_accept_ipv4_0;
+#define WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4 \
+ (&windivert_layer_auth_recv_accept_ipv4)
-static struct layer_s layer_auth_recv_accept_ipv6_0 =
+static const struct layer_s windivert_layer_auth_recv_accept_ipv6 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthRecvAcceptIPv6",
- L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer auth recv accept (IPv6)",
L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthRecvAcceptIPv6",
- L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L" callout auth recv accept (IPv6)",
L"" WINDIVERT_DEVICE_NAME L"_FilterAuthRecvAcceptIPv6",
- L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)",
- {0},
- {0},
+ L"" WINDIVERT_DEVICE_NAME L" filter auth recv accept (IPv6)",
+ &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6,
+ &WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV6_GUID,
windivert_auth_recv_accept_v6_classify,
NULL,
0
};
-static layer_t layer_auth_recv_accept_ipv6 = &layer_auth_recv_accept_ipv6_0;
+#define WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6 \
+ (&windivert_layer_auth_recv_accept_ipv6)
-static struct layer_s layer_flow_established_ipv4_0 =
+static const struct layer_s windivert_layer_flow_established_ipv4 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerFlowEstablishedIPv4",
L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)",
@@ -770,15 +779,16 @@ static struct layer_s layer_flow_established_ipv4_0 =
L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)",
L"" WINDIVERT_DEVICE_NAME L"_FilterFlowEstablishedIPv4",
L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)",
- {0},
- {0},
+ &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4,
+ &WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV4_GUID,
windivert_flow_established_v4_classify,
windivert_flow_delete_notify,
0
};
-static layer_t layer_flow_established_ipv4 = &layer_flow_established_ipv4_0;
+#define WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV4 \
+ (&windivert_layer_flow_established_ipv4)
-static struct layer_s layer_flow_established_ipv6_0 =
+static const struct layer_s windivert_layer_flow_established_ipv6 =
{
L"" WINDIVERT_DEVICE_NAME L"_SubLayerFlowEstablishedIPv6",
L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)",
@@ -786,13 +796,14 @@ static struct layer_s layer_flow_established_ipv6_0 =
L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)",
L"" WINDIVERT_DEVICE_NAME L"_FilterFlowEstablishedIPv6",
L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)",
- {0},
- {0},
+ &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6,
+ &WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV6_GUID,
windivert_flow_established_v6_classify,
windivert_flow_delete_notify,
0
};
-static layer_t layer_flow_established_ipv6 = &layer_flow_established_ipv6_0;
+#define WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV6 \
+ (&windivert_layer_flow_established_ipv6)
/*
* Shared functions.
@@ -865,62 +876,6 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj,
counts_per_ms = freq.QuadPart / 1000;
counts_per_ms = (counts_per_ms == 0? 1: counts_per_ms);
- // Initialize the layers.
- layer_inbound_network_ipv4->layer_guid = FWPM_LAYER_INBOUND_IPPACKET_V4;
- layer_outbound_network_ipv4->layer_guid = FWPM_LAYER_OUTBOUND_IPPACKET_V4;
- layer_inbound_network_ipv6->layer_guid = FWPM_LAYER_INBOUND_IPPACKET_V6;
- layer_outbound_network_ipv6->layer_guid = FWPM_LAYER_OUTBOUND_IPPACKET_V6;
- layer_forward_network_ipv4->layer_guid = FWPM_LAYER_IPFORWARD_V4;
- layer_forward_network_ipv6->layer_guid = FWPM_LAYER_IPFORWARD_V6;
- layer_flow_established_ipv4->layer_guid =
- FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4;
- layer_flow_established_ipv6->layer_guid =
- FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6;
- layer_resource_assignment_ipv4->layer_guid =
- FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4;
- layer_resource_assignment_ipv6->layer_guid =
- FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6;
- layer_auth_connect_ipv4->layer_guid = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
- layer_auth_connect_ipv6->layer_guid = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
- layer_auth_listen_ipv4->layer_guid = FWPM_LAYER_ALE_AUTH_LISTEN_V4;
- layer_auth_listen_ipv6->layer_guid = FWPM_LAYER_ALE_AUTH_LISTEN_V6;
- layer_auth_recv_accept_ipv4->layer_guid =
- FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4;
- layer_auth_recv_accept_ipv6->layer_guid =
- FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6;
- layer_inbound_network_ipv4->sublayer_guid =
- WINDIVERT_SUBLAYER_INBOUND_IPV4_GUID;
- layer_outbound_network_ipv4->sublayer_guid =
- WINDIVERT_SUBLAYER_OUTBOUND_IPV4_GUID;
- layer_inbound_network_ipv6->sublayer_guid =
- WINDIVERT_SUBLAYER_INBOUND_IPV6_GUID;
- layer_outbound_network_ipv6->sublayer_guid =
- WINDIVERT_SUBLAYER_OUTBOUND_IPV6_GUID;
- layer_forward_network_ipv4->sublayer_guid =
- WINDIVERT_SUBLAYER_FORWARD_IPV4_GUID;
- layer_forward_network_ipv6->sublayer_guid =
- WINDIVERT_SUBLAYER_FORWARD_IPV6_GUID;
- layer_flow_established_ipv4->sublayer_guid =
- WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV4_GUID;
- layer_flow_established_ipv6->sublayer_guid =
- WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV6_GUID;
- layer_resource_assignment_ipv4->sublayer_guid =
- WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV4_GUID;
- layer_resource_assignment_ipv6->sublayer_guid =
- WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV6_GUID;
- layer_auth_connect_ipv4->sublayer_guid =
- WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV4_GUID;
- layer_auth_connect_ipv6->sublayer_guid =
- WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV6_GUID;
- layer_auth_listen_ipv4->sublayer_guid =
- WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV4_GUID;
- layer_auth_listen_ipv6->sublayer_guid =
- WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV6_GUID;
- layer_auth_recv_accept_ipv4->sublayer_guid =
- WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV4_GUID;
- layer_auth_recv_accept_ipv6->sublayer_guid =
- WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV6_GUID;
-
// Configure ourself as a non-PnP driver:
WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
config.DriverInitFlags |= WdfDriverInitNonPnpDriver;
@@ -1057,7 +1012,7 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj,
DEBUG_ERROR("failed to begin WFP transaction", status);
goto driver_entry_exit;
}
- status = windivert_install_sublayer(layer_inbound_network_ipv4);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_INBOUND_NETWORK_IPV4);
if (!NT_SUCCESS(status))
{
driver_entry_sublayer_error:
@@ -1065,77 +1020,79 @@ driver_entry_sublayer_error:
FwpmTransactionAbort0(engine_handle);
goto driver_entry_exit;
}
- status = windivert_install_sublayer(layer_outbound_network_ipv4);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_OUTBOUND_NETWORK_IPV4);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_inbound_network_ipv6);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_INBOUND_NETWORK_IPV6);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_outbound_network_ipv6);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_OUTBOUND_NETWORK_IPV6);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_forward_network_ipv4);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_FORWARD_NETWORK_IPV4);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_forward_network_ipv6);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_FORWARD_NETWORK_IPV6);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_flow_established_ipv4);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV4);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_flow_established_ipv6);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV6);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_resource_assignment_ipv4);
+ status = windivert_install_sublayer(
+ WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_resource_assignment_ipv6);
+ status = windivert_install_sublayer(
+ WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_auth_connect_ipv4);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_CONNECT_IPV4);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_auth_connect_ipv6);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_CONNECT_IPV6);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_auth_listen_ipv4);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_LISTEN_IPV4);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_auth_listen_ipv6);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_LISTEN_IPV6);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_auth_recv_accept_ipv4);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
}
- status = windivert_install_sublayer(layer_auth_recv_accept_ipv6);
+ status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
@@ -1206,37 +1163,37 @@ static void windivert_driver_unload(void)
return;
}
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_inbound_network_ipv4->sublayer_guid);
+ WINDIVERT_LAYER_INBOUND_NETWORK_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_outbound_network_ipv4->sublayer_guid);
+ WINDIVERT_LAYER_OUTBOUND_NETWORK_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_inbound_network_ipv6->sublayer_guid);
+ WINDIVERT_LAYER_INBOUND_NETWORK_IPV6->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_outbound_network_ipv6->sublayer_guid);
+ WINDIVERT_LAYER_OUTBOUND_NETWORK_IPV6->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_forward_network_ipv4->sublayer_guid);
+ WINDIVERT_LAYER_FORWARD_NETWORK_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_forward_network_ipv6->sublayer_guid);
+ WINDIVERT_LAYER_FORWARD_NETWORK_IPV6->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_flow_established_ipv4->sublayer_guid);
+ WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_flow_established_ipv6->sublayer_guid);
+ WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV6->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_resource_assignment_ipv4->sublayer_guid);
+ WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_resource_assignment_ipv6->sublayer_guid);
+ WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_auth_connect_ipv4->sublayer_guid);
+ WINDIVERT_LAYER_AUTH_CONNECT_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_auth_connect_ipv6->sublayer_guid);
+ WINDIVERT_LAYER_AUTH_CONNECT_IPV6->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_auth_listen_ipv4->sublayer_guid);
+ WINDIVERT_LAYER_AUTH_LISTEN_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_auth_listen_ipv6->sublayer_guid);
+ WINDIVERT_LAYER_AUTH_LISTEN_IPV6->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_auth_recv_accept_ipv4->sublayer_guid);
+ WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4->sublayer_guid);
FwpmSubLayerDeleteByKey0(engine_handle,
- &layer_auth_recv_accept_ipv6->sublayer_guid);
+ WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6->sublayer_guid);
status = FwpmTransactionCommit0(engine_handle);
if (!NT_SUCCESS(status))
{
@@ -1255,7 +1212,7 @@ static NTSTATUS windivert_install_sublayer(layer_t layer)
NTSTATUS status;
RtlZeroMemory(&sublayer, sizeof(sublayer));
- sublayer.subLayerKey = layer->sublayer_guid;
+ sublayer.subLayerKey = *(layer->sublayer_guid);
sublayer.displayData.name = layer->sublayer_name;
sublayer.displayData.description = layer->sublayer_desc;
sublayer.weight = layer->sublayer_weight;
@@ -1301,11 +1258,7 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
context->flags = 0;
context->priority = windivert_context_priority(WINDIVERT_PRIORITY_DEFAULT);
context->filter = NULL;
- for (i = 0; i < WINDIVERT_CONTEXT_MAXWORKERS; i++)
- {
- context->workers[i] = NULL;
- }
- context->worker_curr = 0;
+ context->worker = NULL;
for (i = 0; i < WINDIVERT_CONTEXT_MAXLAYERS; i++)
{
context->installed[i] = FALSE;
@@ -1343,15 +1296,11 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
item_config.AutomaticSerialization = FALSE;
WDF_OBJECT_ATTRIBUTES_INIT(&obj_attrs);
obj_attrs.ParentObject = (WDFOBJECT)object;
- for (i = 0; i < WINDIVERT_CONTEXT_MAXWORKERS; i++)
+ status = WdfWorkItemCreate(&item_config, &obj_attrs, &context->worker);
+ if (!NT_SUCCESS(status))
{
- status = WdfWorkItemCreate(&item_config, &obj_attrs,
- context->workers + i);
- if (!NT_SUCCESS(status))
- {
- DEBUG_ERROR("failed to create read service work item", status);
- goto windivert_create_exit;
- }
+ DEBUG_ERROR("failed to create read service work item", status);
+ goto windivert_create_exit;
}
RtlZeroMemory(&session, sizeof(session));
session.flags |= FWPM_SESSION_FLAG_DYNAMIC;
@@ -1374,12 +1323,9 @@ windivert_create_exit:
{
WdfObjectDelete(context->read_queue);
}
- for (i = 0; i < WINDIVERT_CONTEXT_MAXWORKERS; i++)
+ if (context->worker != NULL)
{
- if (context->workers[i] != NULL)
- {
- WdfObjectDelete(context->workers[i]);
- }
+ WdfObjectDelete(context->worker);
}
if (context->engine_handle != NULL)
{
@@ -1413,30 +1359,30 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
case WINDIVERT_LAYER_NETWORK:
if (inbound && ipv4)
{
- layers[i++] = layer_inbound_network_ipv4;
+ layers[i++] = WINDIVERT_LAYER_INBOUND_NETWORK_IPV4;
}
if (outbound && ipv4)
{
- layers[i++] = layer_outbound_network_ipv4;
+ layers[i++] = WINDIVERT_LAYER_OUTBOUND_NETWORK_IPV4;
}
if (inbound && ipv6)
{
- layers[i++] = layer_inbound_network_ipv6;
+ layers[i++] = WINDIVERT_LAYER_INBOUND_NETWORK_IPV6;
}
if (outbound && ipv6)
{
- layers[i++] = layer_outbound_network_ipv6;
+ layers[i++] = WINDIVERT_LAYER_OUTBOUND_NETWORK_IPV6;
}
break;
case WINDIVERT_LAYER_NETWORK_FORWARD:
if (ipv4)
{
- layers[i++] = layer_forward_network_ipv4;
+ layers[i++] = WINDIVERT_LAYER_FORWARD_NETWORK_IPV4;
}
if (ipv6)
{
- layers[i++] = layer_forward_network_ipv6;
+ layers[i++] = WINDIVERT_LAYER_FORWARD_NETWORK_IPV6;
}
break;
@@ -1444,29 +1390,29 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
if (ipv4)
{
callout_ids[i] = &context->flow_v4_callout_id;
- layers[i++] = layer_flow_established_ipv4;
+ layers[i++] = WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV4;
}
if (ipv6)
{
callout_ids[i] = &context->flow_v6_callout_id;
- layers[i++] = layer_flow_established_ipv6;
+ layers[i++] = WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV6;
}
break;
case WINDIVERT_LAYER_SOCKET:
if (ipv4)
{
- layers[i++] = layer_resource_assignment_ipv4;
- layers[i++] = layer_auth_connect_ipv4;
- layers[i++] = layer_auth_listen_ipv4;
- layers[i++] = layer_auth_recv_accept_ipv4;
+ layers[i++] = WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4;
+ layers[i++] = WINDIVERT_LAYER_AUTH_CONNECT_IPV4;
+ layers[i++] = WINDIVERT_LAYER_AUTH_LISTEN_IPV4;
+ layers[i++] = WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4;
}
if (ipv6)
{
- layers[i++] = layer_resource_assignment_ipv6;
- layers[i++] = layer_auth_connect_ipv6;
- layers[i++] = layer_auth_listen_ipv6;
- layers[i++] = layer_auth_recv_accept_ipv6;
+ layers[i++] = WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6;
+ layers[i++] = WINDIVERT_LAYER_AUTH_CONNECT_IPV6;
+ layers[i++] = WINDIVERT_LAYER_AUTH_LISTEN_IPV6;
+ layers[i++] = WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6;
}
break;
@@ -1540,15 +1486,15 @@ static NTSTATUS windivert_install_callout(context_t context, UINT idx,
mcallout.calloutKey = callout_guid;
mcallout.displayData.name = layer->callout_name;
mcallout.displayData.description = layer->callout_desc;
- mcallout.applicableLayer = layer->layer_guid;
+ mcallout.applicableLayer = *(layer->layer_guid);
RtlZeroMemory(&filter, sizeof(filter));
filter.filterKey = filter_guid;
- filter.layerKey = layer->layer_guid;
+ filter.layerKey = *(layer->layer_guid);
filter.displayData.name = layer->filter_name;
filter.displayData.description = layer->filter_desc;
filter.action.type = FWP_ACTION_CALLOUT_UNKNOWN;
filter.action.calloutKey = callout_guid;
- filter.subLayerKey = layer->sublayer_guid;
+ filter.subLayerKey = *(layer->sublayer_guid);
filter.weight.type = FWP_UINT64;
filter.weight.uint64 = &weight;
filter.rawContext = (UINT64)context;
@@ -1816,18 +1762,15 @@ windivert_cleanup_error:
KeReleaseInStackQueuedSpinLock(&lock_handle);
WdfIoQueuePurge(read_queue, NULL, NULL);
WdfObjectDelete(read_queue);
- for (i = 0; i < WINDIVERT_CONTEXT_MAXWORKERS; i++)
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ if (context->state != WINDIVERT_CONTEXT_STATE_CLOSING)
{
- KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- if (context->state != WINDIVERT_CONTEXT_STATE_CLOSING)
- {
- goto windivert_cleanup_error;
- }
- worker = context->workers[i];
- KeReleaseInStackQueuedSpinLock(&lock_handle);
- WdfWorkItemFlush(worker);
- WdfObjectDelete(worker);
+ goto windivert_cleanup_error;
}
+ worker = context->worker;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ WdfWorkItemFlush(worker);
+ WdfObjectDelete(worker);
}
/*
@@ -1860,7 +1803,7 @@ extern VOID windivert_destroy(IN WDFOBJECT object)
{
KLOCK_QUEUE_HANDLE lock_handle;
context_t context = windivert_context_get((WDFFILEOBJECT)object);
- PWINDIVERT_FILTER filter;
+ const WINDIVERT_FILTER *filter;
NTSTATUS status;
DEBUG("DESTROY: destroying WinDivert context (context=%p)", context);
@@ -1877,7 +1820,7 @@ extern VOID windivert_destroy(IN WDFOBJECT object)
KeReleaseInStackQueuedSpinLock(&lock_handle);
windivert_uninstall_callouts(context, WINDIVERT_CONTEXT_STATE_CLOSED);
FwpmEngineClose0(context->engine_handle);
- windivert_free(filter);
+ windivert_free((PVOID)filter);
}
/*
@@ -2603,10 +2546,9 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
{
KLOCK_QUEUE_HANDLE lock_handle;
PCHAR inbuf, outbuf;
- size_t inbuflen, outbuflen, filter0_len;
+ size_t inbuflen, outbuflen, ioctl_filter_len;
PWINDIVERT_IOCTL ioctl;
- PWINDIVERT_FILTER filter0;
- PWINDIVERT_FILTER filter;
+ const WINDIVERT_FILTER *ioctl_filter, *filter;
UINT8 layer;
INT16 priority;
UINT64 flags;
@@ -2688,7 +2630,7 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
{
windivert_ioctl_bad_start_state:
KeReleaseInStackQueuedSpinLock(&lock_handle);
- windivert_free(filter);
+ windivert_free((PVOID)filter);
status = STATUS_INVALID_DEVICE_STATE;
goto windivert_ioctl_exit;
}
@@ -2696,16 +2638,17 @@ windivert_ioctl_bad_start_state:
layer = context->layer;
KeReleaseInStackQueuedSpinLock(&lock_handle);
- filter0 = (PWINDIVERT_FILTER)outbuf;
- filter0_len = outbuflen;
- filter = windivert_filter_compile(filter0, filter0_len, layer);
+ ioctl_filter = (const WINDIVERT_FILTER *)outbuf;
+ ioctl_filter_len = outbuflen;
+ filter = windivert_filter_compile(ioctl_filter, ioctl_filter_len,
+ layer);
if (filter == NULL)
{
status = STATUS_INVALID_PARAMETER;
DEBUG_ERROR("failed to compile filter", status);
goto windivert_ioctl_exit;
}
- filter_len = filter0_len / sizeof(WINDIVERT_FILTER);
+ filter_len = ioctl_filter_len / sizeof(WINDIVERT_FILTER);
irp = WdfRequestWdmGetIrp(request);
process_id = (UINT32)IoGetRequestorProcessId(irp);
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
@@ -3229,7 +3172,7 @@ static void windivert_network_classify(context_t context,
BOOL impostor, sniff_mode, ok;
WDFOBJECT object;
PLIST_ENTRY old_entry;
- PWINDIVERT_FILTER filter;
+ const WINDIVERT_FILTER *filter;
LONGLONG timestamp;
NTSTATUS status;
@@ -3498,7 +3441,7 @@ static void windivert_flow_established_classify(context_t context,
UINT16 layer_id;
BOOL match, ok;
WDFOBJECT object;
- PWINDIVERT_FILTER filter;
+ const WINDIVERT_FILTER *filter;
LONGLONG timestamp;
flow_t flow;
NTSTATUS status;
@@ -3614,7 +3557,7 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
BOOL match, cleanup;
WDFOBJECT object;
context_t context;
- PWINDIVERT_FILTER filter;
+ const WINDIVERT_FILTER *filter;
LONGLONG timestamp;
flow_t flow;
@@ -3943,7 +3886,7 @@ static void windivert_socket_classify(context_t context,
UINT64 flags;
BOOL match, ok;
WDFOBJECT object;
- PWINDIVERT_FILTER filter;
+ const WINDIVERT_FILTER *filter;
LONGLONG timestamp;
NTSTATUS status;
@@ -4193,9 +4136,7 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
context->work_queue_length--;
}
InsertTailList(&context->work_queue, &work->entry);
- WdfWorkItemEnqueue(context->workers[context->worker_curr]);
- context->worker_curr =
- (context->worker_curr + 1) % WINDIVERT_CONTEXT_MAXWORKERS;
+ WdfWorkItemEnqueue(context->worker);
KeReleaseInStackQueuedSpinLock(&lock_handle);
if (old_entry != NULL)
@@ -4698,8 +4639,8 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
* Checks if the given network packet is of interest.
*/
static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
- PVOID layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound,
- BOOL loopback, BOOL impostor, PWINDIVERT_FILTER filter)
+ const VOID *layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound,
+ BOOL loopback, BOOL impostor, const WINDIVERT_FILTER *filter)
{
PWINDIVERT_IPHDR ip_header = NULL;
PWINDIVERT_IPV6HDR ipv6_header = NULL;
@@ -5437,8 +5378,8 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
/*
* Compile a WinDivert filter from an IOCTL.
*/
-static PWINDIVERT_FILTER windivert_filter_compile(
- PWINDIVERT_FILTER ioctl_filter, size_t ioctl_filter_len,
+static const WINDIVERT_FILTER *windivert_filter_compile(
+ const WINDIVERT_FILTER *ioctl_filter, size_t ioctl_filter_len,
WINDIVERT_LAYER layer)
{
PWINDIVERT_FILTER filter = NULL;
@@ -5693,7 +5634,7 @@ static PWINDIVERT_FILTER windivert_filter_compile(
windivert_filter_compile_error:
- windivert_free(filter);
+ windivert_free((PVOID)filter);
return NULL;
}
@@ -5829,7 +5770,7 @@ static PWINDIVERT_IPHDR windivert_reflect_pseudo_packet(context_t context,
UINT16 total_len;
UINT8 *packet;
char *object;
- PWINDIVERT_FILTER filter;
+ const WINDIVERT_FILTER *filter;
UINT8 filter_len;
PWINDIVERT_IPHDR iphdr;
WINDIVERT_STREAM stream;
@@ -5876,7 +5817,7 @@ static void windivert_reflect_event_notify(context_t context,
KLOCK_QUEUE_HANDLE lock_handle;
PLIST_ENTRY entry;
context_t waiter;
- PWINDIVERT_FILTER filter;
+ const WINDIVERT_FILTER *filter;
PWINDIVERT_IPHDR packet = NULL;
ULONG packet_len;
BOOL match;
@@ -5919,7 +5860,7 @@ static void windivert_reflect_established_notify(context_t context,
PLIST_ENTRY entry;
BOOL match, ok, final;
context_t waiter;
- PWINDIVERT_FILTER filter;
+ const WINDIVERT_FILTER *filter;
PWINDIVERT_IPHDR packet;
ULONG packet_len;
From 0a74b5528ca15b21fdae93effe6d21038b069739 Mon Sep 17 00:00:00 2001
From: basil00
Date: Fri, 9 Nov 2018 07:29:05 +0800
Subject: [PATCH 17/23] Update driver and inf version information.
---
inf/windivert32.inf | 2 +-
inf/windivert64.inf | 2 +-
sys/windivert.rc | 10 +++++-----
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/inf/windivert32.inf b/inf/windivert32.inf
index 2fdec6c..b87edf0 100644
--- a/inf/windivert32.inf
+++ b/inf/windivert32.inf
@@ -4,7 +4,7 @@ Class = WFPCALLOUTS
ClassGuid = {57465043-616C-6C6F-7574-5F636C617373}
Provider = %Basil%
CatalogFile = WinDivert32.Cat
-DriverVer = 10/22/2017,1.4.0
+DriverVer = 01/01/2019,2.0.0
[SourceDisksNames]
1 = %DiskName%
diff --git a/inf/windivert64.inf b/inf/windivert64.inf
index 3ab956d..ea6b19d 100644
--- a/inf/windivert64.inf
+++ b/inf/windivert64.inf
@@ -4,7 +4,7 @@ Class = WFPCALLOUTS
ClassGuid = {57465043-616C-6C6F-7574-5F636C617373}
Provider = %Basil%
CatalogFile = WinDivert64.Cat
-DriverVer = 10/22/2017,1.4.0
+DriverVer = 01/01/2019,2.0.0
[SourceDisksNames]
1 = %DiskName%
diff --git a/sys/windivert.rc b/sys/windivert.rc
index 563a3b7..cdd40a8 100644
--- a/sys/windivert.rc
+++ b/sys/windivert.rc
@@ -43,15 +43,15 @@
"[Bitcoin: 1C5vZVSbizPeZ8ydTYhUfm4LA2cNwBfcYh]"
#define VER_INTERNALNAME_STR "WinDivert.sys"
#define VER_ORIGINALFILENAME_STR "WinDivert.sys"
-#define VER_PRODUCTVERSION 1.4
-#define VER_PRODUCTVERSION_STR "1.4"
-#define VER_COMPANYNAME_STR "Basil's Projects"
-#define VER_LEGALCOPYRIGHT_YEARS "2011-2017"
+#define VER_PRODUCTVERSION 2.0
+#define VER_PRODUCTVERSION_STR "2.0"
+#define VER_COMPANYNAME_STR "Basil"
+#define VER_LEGALCOPYRIGHT_YEARS "2011-2019"
#define VER_LEGALCOPYRIGHT_STR \
"Copyright \251 " VER_COMPANYNAME_STR " " VER_LEGALCOPYRIGHT_YEARS
#define VER_FILEVERSION VER_PRODUCTVERSION
#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
-#define VER_PRODUCTNAME_STR "WinDivert 1.4 driver"
+#define VER_PRODUCTNAME_STR "WinDivert 2.0 driver"
#include "common.ver"
From 312050accb37bc0a74559cae574d13db41bd5eec Mon Sep 17 00:00:00 2001
From: basil00
Date: Sun, 11 Nov 2018 09:44:24 +0800
Subject: [PATCH 18/23] Add a new WinDivertShutdown() function (#156).
This function allows the user application to
"shutdown" a handle in anticipation of a
call to WinDivertClose(). When a handle has
been shutdown, new packets will no longer be
queued. However, existing queued packets can
still be read by WinDivertRecv(). When the
queue is emptied, WinDivertRecv() will fail
with ERROR_NO_DATA.
The WinDivertShutdown() function is analogous
to the shutdown() socket function.
This change also simplifies events.
---
dll/windivert.c | 9 ++
dll/windivert.def | 1 +
dll/windivert_helper.c | 17 +--
examples/windivertctl/windivertctl.c | 22 +++-
include/windivert.h | 51 +++++----
include/windivert_device.h | 6 +-
sys/windivert.c | 165 +++++++++++++++++++++------
7 files changed, 194 insertions(+), 77 deletions(-)
diff --git a/dll/windivert.c b/dll/windivert.c
index fd30f66..4527358 100644
--- a/dll/windivert.c
+++ b/dll/windivert.c
@@ -567,6 +567,15 @@ extern BOOL WinDivertSendEx(HANDLE handle, const VOID *pPacket, UINT packetLen,
}
}
+/*
+ * Shutdown a WinDivert handle.
+ */
+extern BOOL WinDivertShutdown(HANDLE handle, WINDIVERT_SHUTDOWN how)
+{
+ return WinDivertIoControl(handle, IOCTL_WINDIVERT_SHUTDOWN,
+ (UINT64)how, 0, NULL, 0, NULL);
+}
+
/*
* Close a WinDivert handle.
*/
diff --git a/dll/windivert.def b/dll/windivert.def
index c9c072f..7786f00 100644
--- a/dll/windivert.def
+++ b/dll/windivert.def
@@ -6,6 +6,7 @@ EXPORTS
WinDivertRecvEx
WinDivertSend
WinDivertSendEx
+ WinDivertShutdown
WinDivertClose
WinDivertSetParam
WinDivertGetParam
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index 3c200a9..bbb0d3c 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -514,23 +514,14 @@ static BOOL WinDivertExpandMacro(KIND kind, WINDIVERT_LAYER layer,
*val = WINDIVERT_EVENT_NETWORK_PACKET;
return (layer == WINDIVERT_LAYER_NETWORK);
case TOKEN_EVENT_ESTABLISHED:
- if (layer == WINDIVERT_LAYER_FLOW)
- {
- *val = WINDIVERT_EVENT_FLOW_ESTABLISHED;
- return TRUE;
- }
- else if (layer == WINDIVERT_LAYER_REFLECT)
- {
- *val = WINDIVERT_EVENT_REFLECT_ESTABLISHED;
- return TRUE;
- }
- return FALSE;
+ *val = WINDIVERT_EVENT_FLOW_ESTABLISHED;
+ return (layer == WINDIVERT_LAYER_FLOW);
case TOKEN_EVENT_DELETED:
*val = WINDIVERT_EVENT_FLOW_DELETED;
return (layer == WINDIVERT_LAYER_FLOW);
case TOKEN_EVENT_BIND:
*val = WINDIVERT_EVENT_SOCKET_BIND;
- return (layer == WINDIVERT_LAYER_FLOW);
+ return (layer == WINDIVERT_LAYER_SOCKET);
case TOKEN_EVENT_CONNECT:
*val = WINDIVERT_EVENT_SOCKET_CONNECT;
return (layer == WINDIVERT_LAYER_SOCKET);
@@ -4055,8 +4046,6 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
case WINDIVERT_LAYER_REFLECT:
switch (val->val[0])
{
- case WINDIVERT_EVENT_REFLECT_ESTABLISHED:
- WinDivertPutString(stream, "ESTABLISHED"); break;
case WINDIVERT_EVENT_REFLECT_OPEN:
WinDivertPutString(stream, "OPEN"); break;
case WINDIVERT_EVENT_REFLECT_CLOSE:
diff --git a/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c
index 08705cb..73bc827 100644
--- a/examples/windivertctl/windivertctl.c
+++ b/examples/windivertctl/windivertctl.c
@@ -238,6 +238,12 @@ usage:
GetLastError());
return EXIT_FAILURE;
}
+ if (mode != WATCH && !WinDivertShutdown(handle, WINDIVERT_SHUTDOWN_BOTH))
+ {
+ fprintf(stderr, "error: failed to shutdown WinDivert handle (%d)\n",
+ GetLastError());
+ return EXIT_FAILURE;
+ }
// Main loop:
console = GetStdHandle(STD_OUTPUT_HANDLE);
@@ -245,13 +251,16 @@ usage:
{
if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len))
{
+ if (mode != WATCH && GetLastError() == ERROR_NO_DATA)
+ {
+ break;
+ }
fprintf(stderr, "failed to event (%d)\n", GetLastError());
continue;
}
switch (addr.Event)
{
- case WINDIVERT_EVENT_REFLECT_ESTABLISHED:
case WINDIVERT_EVENT_REFLECT_OPEN:
// Open handle:
process = add_process(addr.Reflect.ProcessId);
@@ -395,10 +404,13 @@ usage:
{
remove_process(addr.Reflect.ProcessId);
}
- if (mode != WATCH && addr.Final)
- {
- break;
- }
+ }
+
+ if (!WinDivertClose(handle))
+ {
+ fprintf(stderr, "error: failed to close WinDivert handle (%d)\n",
+ GetLastError());
+ return EXIT_FAILURE;
}
return 0;
diff --git a/include/windivert.h b/include/windivert.h
index a736f37..c59d820 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -135,7 +135,7 @@ typedef struct
{
INT64 Timestamp; /* Packet's timestamp. */
UINT64 Layer:8; /* Packet's layer. */
- UINT64 Event:24; /* Packet event. */
+ UINT64 Event:8; /* Packet event. */
UINT64 Outbound:1; /* Packet is outound? */
UINT64 Loopback:1; /* Packet is loopback? */
UINT64 Impostor:1; /* Packet is impostor? */
@@ -143,8 +143,7 @@ typedef struct
UINT64 PseudoIPChecksum:1; /* Packet has pseudo IPv4 checksum? */
UINT64 PseudoTCPChecksum:1; /* Packet has pseudo TCP checksum? */
UINT64 PseudoUDPChecksum:1; /* Packet has pseudo UDP checksum? */
- UINT64 Final:1; /* Packet is final event? */
- UINT64 Reserved:24;
+ UINT64 Reserved:41;
union
{
WINDIVERT_DATA_NETWORK Network; /* Network layer data. */
@@ -159,26 +158,16 @@ typedef struct
*/
typedef enum
{
- WINDIVERT_EVENT_NETWORK_PACKET = 0x0001,
- /* Network packet. */
- WINDIVERT_EVENT_FLOW_ESTABLISHED = 0x0002,
+ WINDIVERT_EVENT_NETWORK_PACKET = 0, /* Network packet. */
+ WINDIVERT_EVENT_FLOW_ESTABLISHED = 1,
/* Flow established. */
- WINDIVERT_EVENT_FLOW_DELETED = 0x0004,
- /* Flow deleted. */
- WINDIVERT_EVENT_SOCKET_BIND = 0x0008,
- /* Socket bind. */
- WINDIVERT_EVENT_SOCKET_LISTEN = 0x0010,
- /* Socket listen. */
- WINDIVERT_EVENT_SOCKET_CONNECT = 0x0020,
- /* Socket connect. */
- WINDIVERT_EVENT_SOCKET_ACCEPT = 0x0040,
- /* Socket accept. */
- WINDIVERT_EVENT_REFLECT_ESTABLISHED = 0x0080,
- /* Previously open WinDivert handle. */
- WINDIVERT_EVENT_REFLECT_OPEN = 0x0100,
- /* Open new WinDivert handle. */
- WINDIVERT_EVENT_REFLECT_CLOSE = 0x0200,
- /* Close existing WinDivert handle. */
+ WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */
+ WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */
+ WINDIVERT_EVENT_SOCKET_LISTEN = 4, /* Socket listen. */
+ WINDIVERT_EVENT_SOCKET_CONNECT = 5, /* Socket connect. */
+ WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */
+ WINDIVERT_EVENT_REFLECT_OPEN = 7, /* Open new WinDivert handle. */
+ WINDIVERT_EVENT_REFLECT_CLOSE = 8, /* Close existing WinDivert handle. */
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
/*
@@ -204,6 +193,17 @@ typedef enum
} WINDIVERT_PARAM, *PWINDIVERT_PARAM;
#define WINDIVERT_PARAM_MAX WINDIVERT_PARAM_QUEUE_SIZE
+/*
+ * WinDivert shutdown parameter.
+ */
+typedef enum
+{
+ WINDIVERT_SHUTDOWN_RECV = 0x1, /* Shutdown recv. */
+ WINDIVERT_SHUTDOWN_SEND = 0x2, /* Shutdown send. */
+ WINDIVERT_SHUTDOWN_BOTH = 0x3, /* Shutdown recv and send. */
+} WINDIVERT_SHUTDOWN, *PWINDIVERT_SHUTDOWN;
+#define WINDIVERT_SHUTDOWN_MAX WINDIVERT_SHUTDOWN_BOTH
+
#ifndef WINDIVERT_KERNEL
/*
@@ -261,6 +261,13 @@ extern WINDIVERTEXPORT BOOL WinDivertSendEx(
__in UINT addrLen,
__inout_opt LPOVERLAPPED lpOverlapped);
+/*
+ * Shutdown a WinDivert handle.
+ */
+extern WINDIVERTEXPORT BOOL WinDivertShutdown(
+ __in HANDLE handle,
+ __in WINDIVERT_SHUTDOWN how);
+
/*
* Close a WinDivert handle.
*/
diff --git a/include/windivert_device.h b/include/windivert_device.h
index 22bb898..222d237 100644
--- a/include/windivert_device.h
+++ b/include/windivert_device.h
@@ -161,7 +161,8 @@
/*
* WinDivert events.
*/
-#define WINDIVERT_EVENT_MAX 0x8000
+#define WINDIVERT_EVENT_MAX \
+ WINDIVERT_EVENT_REFLECT_CLOSE
/*
* WinDivert flags.
@@ -244,6 +245,9 @@ typedef struct
/*
* IOCTL codes.
*/
+#define IOCTL_WINDIVERT_SHUTDOWN \
+ CTL_CODE(FILE_DEVICE_NETWORK, 0x917, METHOD_IN_DIRECT, FILE_READ_DATA | \
+ FILE_WRITE_DATA)
#define IOCTL_WINDIVERT_RECV \
CTL_CODE(FILE_DEVICE_NETWORK, 0x918, METHOD_OUT_DIRECT, FILE_READ_DATA)
#define IOCTL_WINDIVERT_SEND \
diff --git a/sys/windivert.c b/sys/windivert.c
index 8af6571..57d04bb 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -158,6 +158,9 @@ struct context_s
WDFWORKITEM worker; // Read worker.
WINDIVERT_LAYER layer; // Context's layer.
UINT64 flags; // Context's flags.
+ BOOL shutdown_recv; // Shutdown recv.
+ BOOL shutdown_send; // Shutdown send.
+ BOOL shutdown_recv_enabled; // Shutdown recv enabled?
UINT32 priority; // Context (internal) priority.
INT16 priority16; // Context (user) priority.
GUID callout_guid[WINDIVERT_CONTEXT_MAXLAYERS];
@@ -241,7 +244,7 @@ struct packet_s
LIST_ENTRY entry; // Entry for queue.
LONGLONG timestamp; // Packet timestamp.
UINT64 layer:8; // Layer.
- UINT64 event:24; // Event.
+ UINT64 event:8; // Event.
UINT64 outbound:1; // Packet is outound?
UINT64 loopback:1; // Packet is loopback?
UINT64 impostor:1; // Packet is impostor?
@@ -249,7 +252,6 @@ struct packet_s
UINT64 pseudo_ip_checksum:1; // Packet has pseudo IPv4 check?
UINT64 pseudo_tcp_checksum:1; // Packet has pseudo TCP check?
UINT64 pseudo_udp_checksum:1; // Packet has pseudo UDP check?
- UINT64 final:1; // Packet is final event?
UINT64 match:1; // Packet matches filter?
UINT32 priority; // Packet priority.
UINT32 packet_len; // Length of the packet.
@@ -448,8 +450,8 @@ static void windivert_network_classify(context_t context,
static BOOL windivert_queue_work(context_t context, PVOID packet,
ULONG packet_len, PNET_BUFFER_LIST buffers, WINDIVERT_LAYER layer,
PVOID layer_data, WINDIVERT_EVENT event, UINT64 flags, UINT32 priority,
- BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, BOOL final,
- BOOL match, LONGLONG timestamp);
+ BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, BOOL match,
+ LONGLONG timestamp);
static void windivert_queue_packet(context_t context, packet_t packet);
static void windivert_reinject_packet(packet_t packet);
static void windivert_free_packet(packet_t packet);
@@ -1256,6 +1258,9 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
context->packet_queue_maxtime = WINDIVERT_PARAM_QUEUE_TIME_DEFAULT;
context->layer = WINDIVERT_LAYER_DEFAULT;
context->flags = 0;
+ context->shutdown_recv = FALSE;
+ context->shutdown_recv_enabled = FALSE;
+ context->shutdown_send = FALSE;
context->priority = windivert_context_priority(WINDIVERT_PRIORITY_DEFAULT);
context->filter = NULL;
context->worker = NULL;
@@ -1982,7 +1987,6 @@ static void windivert_read_service_request(context_t context, packet_t packet,
addr[i].PseudoIPChecksum = packet->pseudo_ip_checksum;
addr[i].PseudoTCPChecksum = packet->pseudo_tcp_checksum;
addr[i].PseudoUDPChecksum = packet->pseudo_udp_checksum;
- addr[i].Final = packet->final;
addr[i].Reserved = 0;
layer_data = (PVOID)packet->data;
switch (packet->layer)
@@ -2114,6 +2118,26 @@ static void windivert_read_service(context_t context)
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
}
+
+ if (context->shutdown_recv && context->shutdown_recv_enabled &&
+ IsListEmpty(&context->packet_queue) &&
+ IsListEmpty(&context->work_queue))
+ {
+ // The handle has shutdown, the queue is empty, and no more packets
+ // will be queued. Notify any remaining requests.
+ while (context->state == WINDIVERT_CONTEXT_STATE_OPEN)
+ {
+ status = WdfIoQueueRetrieveNextRequest(context->read_queue,
+ &request);
+ if (!NT_SUCCESS(status))
+ {
+ break;
+ }
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ WdfRequestComplete(request, STATUS_PIPE_EMPTY);
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ }
+ }
KeReleaseInStackQueuedSpinLock(&lock_handle);
}
@@ -2149,6 +2173,12 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
status = STATUS_INVALID_DEVICE_STATE;
goto windivert_write_hard_error;
}
+ if (context->shutdown_send)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ status = STATUS_PIPE_EMPTY;
+ goto windivert_write_hard_error;
+ }
layer = context->layer;
priority = context->priority;
flags = context->flags;
@@ -2506,6 +2536,7 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
addr = (PWINDIVERT_ADDRESS)WdfMemoryGetBuffer(memobj, NULL);
break;
+ case IOCTL_WINDIVERT_SHUTDOWN:
case IOCTL_WINDIVERT_START_FILTER:
case IOCTL_WINDIVERT_SET_LAYER:
case IOCTL_WINDIVERT_SET_PRIORITY:
@@ -2605,7 +2636,43 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
return;
}
break;
-
+
+ case IOCTL_WINDIVERT_SHUTDOWN:
+ {
+ UINT64 how;
+
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
+ how = ioctl->arg1;
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ status = STATUS_INVALID_DEVICE_STATE;
+ goto windivert_ioctl_exit;
+ }
+ switch (how)
+ {
+ case WINDIVERT_SHUTDOWN_RECV:
+ context->shutdown_recv = TRUE;
+ break;
+ case WINDIVERT_SHUTDOWN_SEND:
+ context->shutdown_send = TRUE;
+ break;
+ case WINDIVERT_SHUTDOWN_BOTH:
+ context->shutdown_recv = context->shutdown_send = TRUE;
+ break;
+ default:
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ status = STATUS_INVALID_PARAMETER;
+ DEBUG_ERROR("failed to shutdown handle; invalid how",
+ status);
+ goto windivert_ioctl_exit;
+ }
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ windivert_read_service(context);
+ break;
+ }
+
case IOCTL_WINDIVERT_START_FILTER:
{
BOOL inbound, outbound, ipv4, ipv6;
@@ -2688,6 +2755,8 @@ windivert_ioctl_bad_start_state:
context->reflect.data.Flags = context->flags;
context->reflect.data.Priority = context->priority16;
context->reflect.open = FALSE;
+ context->shutdown_recv_enabled =
+ (layer != WINDIVERT_LAYER_REFLECT);
KeReleaseInStackQueuedSpinLock(&lock_handle);
windivert_reflect_open_event(context);
@@ -3197,7 +3266,8 @@ static void windivert_network_classify(context_t context,
}
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
+ context->shutdown_recv)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
return;
@@ -3293,7 +3363,7 @@ static void windivert_network_classify(context_t context,
NET_BUFFER_DATA_LENGTH(buffer_itr), buffers, layer,
(PVOID)network_data, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
flags, priority, ipv4, outbound, loopback, impostor,
- /*final=*/FALSE, /*match=*/FALSE, timestamp);
+ /*match=*/FALSE, timestamp);
if (!ok)
{
goto windivert_network_classify_exit;
@@ -3305,8 +3375,8 @@ static void windivert_network_classify(context_t context,
ok = windivert_queue_work(context, (PVOID)buffer_itr,
NET_BUFFER_DATA_LENGTH(buffer_itr), buffers, layer,
(PVOID)network_data, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
- flags, priority, ipv4, outbound, loopback, impostor, /*final=*/FALSE,
- /*match=*/TRUE, timestamp);
+ flags, priority, ipv4, outbound, loopback, impostor, /*match=*/TRUE,
+ timestamp);
if (advance != 0)
{
// Advance the NET_BUFFER to its original position. Note that we can
@@ -3330,8 +3400,8 @@ static void windivert_network_classify(context_t context,
ok = windivert_queue_work(context, (PVOID)buffer_itr,
NET_BUFFER_DATA_LENGTH(buffer_itr), buffers, layer,
(PVOID)network_data, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
- flags, priority, ipv4, outbound, loopback, impostor,
- /*FINAL=*/FALSE, match, timestamp);
+ flags, priority, ipv4, outbound, loopback, impostor, match,
+ timestamp);
if (!ok)
{
goto windivert_network_classify_exit;
@@ -3458,7 +3528,8 @@ static void windivert_flow_established_classify(context_t context,
result->actionType = FWP_ACTION_CONTINUE;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
+ context->shutdown_recv)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
return;
@@ -3483,8 +3554,7 @@ static void windivert_flow_established_classify(context_t context,
ok = windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW, (PVOID)flow_data,
/*event=*/WINDIVERT_EVENT_FLOW_ESTABLISHED, flags, /*priority=*/0,
- ipv4, outbound, loopback, /*impostor=*/FALSE, /*final=*/FALSE,
- match, timestamp);
+ ipv4, outbound, loopback, /*impostor=*/FALSE, match, timestamp);
if (!ok)
{
WdfObjectDereference(object);
@@ -3523,7 +3593,8 @@ static void windivert_flow_established_classify(context_t context,
}
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
+ context->shutdown_recv)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
windivert_free(flow);
@@ -3578,7 +3649,8 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
}
flow->deleted = TRUE;
cleanup = flow->inserted;
- if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
+ context->shutdown_recv)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
goto windivert_flow_delete_notify_exit;
@@ -3597,7 +3669,7 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW,
(PVOID)&flow->data, /*event=*/WINDIVERT_EVENT_FLOW_DELETED, flags,
/*priority=*/0, !flow->ipv6, flow->outbound, flow->loopback,
- /*impostor=*/FALSE, /*final=*/FALSE, match, timestamp);
+ /*impostor=*/FALSE, match, timestamp);
}
windivert_flow_delete_notify_exit:
@@ -3902,7 +3974,8 @@ static void windivert_socket_classify(context_t context,
result->actionType = FWP_ACTION_CONTINUE;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
- if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN ||
+ context->shutdown_recv)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
return;
@@ -3921,7 +3994,7 @@ static void windivert_socket_classify(context_t context,
ok = windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_SOCKET,
(PVOID)socket_data, event, flags, /*priority=*/0, ipv4, outbound,
- loopback, /*impostor=*/FALSE, /*final=*/FALSE, match, timestamp);
+ loopback, /*impostor=*/FALSE, match, timestamp);
if (!ok)
{
WdfObjectDereference(object);
@@ -3970,6 +4043,8 @@ VOID windivert_worker(IN WDFWORKITEM item)
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
}
KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ windivert_read_service(context);
}
/*
@@ -3978,8 +4053,8 @@ VOID windivert_worker(IN WDFWORKITEM item)
static BOOL windivert_queue_work(context_t context, PVOID packet,
ULONG packet_len, PNET_BUFFER_LIST buffers, WINDIVERT_LAYER layer,
PVOID layer_data, WINDIVERT_EVENT event, UINT64 flags, UINT32 priority,
- BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, BOOL final,
- BOOL match, LONGLONG timestamp)
+ BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, BOOL match,
+ LONGLONG timestamp)
{
KLOCK_QUEUE_HANDLE lock_handle;
PNET_BUFFER buffer;
@@ -4115,7 +4190,6 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
work->pseudo_ip_checksum = (pseudo_ip_checksum? 1: 0);
work->pseudo_tcp_checksum = (pseudo_tcp_checksum? 1: 0);
work->pseudo_udp_checksum = (pseudo_udp_checksum? 1: 0);
- work->final = (final? 1: 0);
work->match = match;
work->priority = priority;
work->timestamp = timestamp;
@@ -4128,6 +4202,16 @@ static BOOL windivert_queue_work(context_t context, PVOID packet,
windivert_free_packet(work);
return FALSE;
}
+ if (context->shutdown_recv && context->shutdown_recv_enabled)
+ {
+ if ((flags & WINDIVERT_FLAG_SNIFF) != 0)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ windivert_free_packet(work);
+ return FALSE;
+ }
+ work->match = FALSE;
+ }
context->work_queue_length++;
if (context->work_queue_length > WINDIVERT_WORK_QUEUE_LEN_MAX)
{
@@ -4214,9 +4298,6 @@ static void windivert_queue_packet(context_t context, packet_t packet)
DEBUG("PACKET: queued packet (packet=%p)", packet);
- // Service any pending I/O request.
- windivert_read_service(context);
-
return;
}
@@ -5541,8 +5622,7 @@ static const WINDIVERT_FILTER *windivert_filter_compile(
}
break;
case WINDIVERT_LAYER_REFLECT:
- if (event != WINDIVERT_EVENT_REFLECT_ESTABLISHED &&
- event != WINDIVERT_EVENT_REFLECT_OPEN &&
+ if (event != WINDIVERT_EVENT_REFLECT_OPEN &&
event != WINDIVERT_EVENT_REFLECT_CLOSE)
{
goto windivert_filter_compile_error;
@@ -5846,7 +5926,7 @@ static void windivert_reflect_event_notify(context_t context,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT,
(PVOID)&context->reflect.data, event, /*flags=*/0, /*priority=*/0,
/*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE,
- /*impostor=*/FALSE, /*final=*/FALSE, /*match=*/TRUE, timestamp);
+ /*impostor=*/FALSE, /*match=*/TRUE, timestamp);
}
}
@@ -5858,13 +5938,18 @@ static void windivert_reflect_established_notify(context_t context,
{
KLOCK_QUEUE_HANDLE lock_handle;
PLIST_ENTRY entry;
- BOOL match, ok, final;
+ BOOL match, ok;
context_t waiter;
const WINDIVERT_FILTER *filter;
PWINDIVERT_IPHDR packet;
ULONG packet_len;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ return;
+ }
filter = context->filter;
KeReleaseInStackQueuedSpinLock(&lock_handle);
@@ -5875,26 +5960,36 @@ static void windivert_reflect_established_notify(context_t context,
entry = entry->Flink;
match = windivert_filter(/*buffer=*/NULL,
/*layer=*/WINDIVERT_LAYER_REFLECT, (PVOID)&waiter->reflect.data,
- /*event=*/WINDIVERT_EVENT_REFLECT_ESTABLISHED, /*ipv4=*/TRUE,
+ /*event=*/WINDIVERT_EVENT_REFLECT_OPEN, /*ipv4=*/TRUE,
/*outbound=*/FALSE, /*loopback=*/FALSE, /*impostor=*/FALSE, filter);
if (!match)
{
continue;
}
packet = windivert_reflect_pseudo_packet(waiter, &packet_len);
- final = (entry == &reflect_contexts);
ok = windivert_queue_work(context, (PVOID)packet, packet_len,
/*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT,
(PVOID)&waiter->reflect.data,
- /*event=*/WINDIVERT_EVENT_REFLECT_ESTABLISHED, /*flags=*/0,
+ /*event=*/WINDIVERT_EVENT_REFLECT_OPEN, /*flags=*/0,
/*priority=*/0, /*ipv4=*/TRUE, /*outbound=*/FALSE,
- /*loopback=*/FALSE, /*impostor=*/FALSE, final, /*match=*/TRUE,
- timestamp);
+ /*loopback=*/FALSE, /*impostor=*/FALSE, /*match=*/TRUE, timestamp);
if (!ok)
{
break;
}
}
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ return;
+ }
+ // REFLECT layer shutdown is disabled until all previously open handles
+ // have been queued.
+ context->shutdown_recv_enabled = TRUE;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ windivert_read_service(context);
}
/*
From 67ad628a1f8c772201635324a22184819844684b Mon Sep 17 00:00:00 2001
From: basil00
Date: Wed, 14 Nov 2018 09:40:17 +0800
Subject: [PATCH 19/23] Add pseudo-random pkt matching to WinDivert (#156)
- Adds 3 new "pseudo-random" filter expressions:
* random8 (8bit)
* random16 (16bit)
* random32 (32bit)
Not really "random", but these values are based
on a hash of the packet headers & timestamp.
These are useful for traffic sampling, e.g.:
"random8 < 100" matches ~39% of all packets.
- Add new WinDivertHelperHashPacket() helper
function. The algorithm is an xxHash variant.
---
dll/windivert.def | 1 +
dll/windivert_hash.c | 201 +++++++++++++++++++++++++++++++++++++
dll/windivert_helper.c | 77 ++++++++++++++
dll/windivert_shared.c | 2 +
examples/netdump/netdump.c | 6 +-
include/windivert.h | 16 ++-
include/windivert_device.h | 5 +-
mingw-build.sh | 2 +-
sys/windivert.c | 58 ++++++++---
9 files changed, 347 insertions(+), 21 deletions(-)
create mode 100644 dll/windivert_hash.c
diff --git a/dll/windivert.def b/dll/windivert.def
index 7786f00..39d9efa 100644
--- a/dll/windivert.def
+++ b/dll/windivert.def
@@ -11,6 +11,7 @@ EXPORTS
WinDivertSetParam
WinDivertGetParam
WinDivertHelperCalcChecksums
+ WinDivertHelperHashPacket
WinDivertHelperParsePacket
WinDivertHelperParseIPv4Address
WinDivertHelperParseIPv6Address
diff --git a/dll/windivert_hash.c b/dll/windivert_hash.c
new file mode 100644
index 0000000..2dcbc94
--- /dev/null
+++ b/dll/windivert_hash.c
@@ -0,0 +1,201 @@
+/*
+ * windivert_hash.c
+ * (C) 2018, all rights reserved,
+ *
+ * This file is part of WinDivert.
+ *
+ * WinDivert is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ *
+ * WinDivert is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * xxHash - Fast Hash algorithm
+ * Copyright (C) 2012-2016, Yann Collet
+ *
+ * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This is a modified version of the 64bit xxHash algorithm:
+ * - The algorithm is seeded with packet data rather than the single 64bit
+ * "seed" value.
+ * - The input sized is fixed to 32bytes (excluding the seed), so there is
+ * only ever a single round. As such, the algorithm has been specialized.
+ */
+
+#define WINDIVERT_ROTL(x, r) (((x) << (r)) | ((x) >> (64 - (r))))
+
+static const UINT64 WINDIVERT_PRIME64_1 = 11400714785074694791ull;
+static const UINT64 WINDIVERT_PRIME64_2 = 14029467366897019727ull;
+static const UINT64 WINDIVERT_PRIME64_3 = 1609587929392839161ull;
+static const UINT64 WINDIVERT_PRIME64_4 = 9650029242287828579ull;
+
+static UINT64 WinDivertXXH64Round(UINT64 acc, UINT64 input)
+{
+ acc += input * WINDIVERT_PRIME64_2;
+ acc = WINDIVERT_ROTL(acc, 31);
+ acc *= WINDIVERT_PRIME64_1;
+ return acc;
+}
+
+static UINT64 WinDivertXXH64MergeRound(UINT64 acc, UINT64 val)
+{
+ val = WinDivertXXH64Round(0, val);
+ acc ^= val;
+ acc = acc * WINDIVERT_PRIME64_1 + WINDIVERT_PRIME64_4;
+ return acc;
+}
+
+static UINT64 WinDivertXXH64Avalanche(UINT64 h64)
+{
+ h64 ^= h64 >> 33;
+ h64 *= WINDIVERT_PRIME64_2;
+ h64 ^= h64 >> 29;
+ h64 *= WINDIVERT_PRIME64_3;
+ h64 ^= h64 >> 32;
+ return h64;
+}
+
+/*
+ * WinDivert packet hash function.
+ */
+static UINT64 WinDivertHashPacket(UINT64 seed, PWINDIVERT_IPHDR ip_header,
+ PWINDIVERT_IPV6HDR ipv6_header, PWINDIVERT_ICMPHDR icmp_header,
+ PWINDIVERT_ICMPV6HDR icmpv6_header, PWINDIVERT_TCPHDR tcp_header,
+ PWINDIVERT_UDPHDR udp_header)
+{
+ UINT64 h64, v1, v2, v3, v4, v[4], *data64;
+ UINT32 *data32;
+ UINT i;
+ static const UINT64 padding64[] = // SHA2 IV
+ {
+ 0x428A2F9871374491ull, 0xB5C0FBCFE9B5DBA5ull, 0x3956C25B59F111F1ull,
+ 0x923F82A4AB1C5ED5ull, 0xD807AA9812835B01ull, 0x243185BE550C7DC3ull,
+ 0x72BE5D7480DEB1FEull, 0x9BDC06A7C19BF174ull, 0xE49B69C1EFBE4786ull,
+ };
+
+ // Set-up seed & data
+ v1 = seed ^ padding64[0];
+ if (ip_header != NULL)
+ {
+ data64 = (UINT64 *)ip_header;
+ v2 = data64[0] ^ padding64[1];
+ v3 = data64[1] ^ padding64[2];
+ data32 = (UINT32 *)ip_header;
+ v4 = (UINT64)data32[4] ^ padding64[3];
+ i = 0;
+ }
+ else if (ipv6_header != NULL)
+ {
+ data64 = (UINT64 *)ipv6_header;
+ v2 = data64[0] ^ padding64[1];
+ v3 = data64[1] ^ padding64[2];
+ v4 = data64[2] ^ padding64[3];
+ v[0] = data64[3] ^ padding64[4];
+ v[1] = data64[4] ^ padding64[5];
+ i = 2;
+ }
+ else
+ return 0;
+
+ if (tcp_header != NULL)
+ {
+ data64 = (UINT64 *)tcp_header;
+ v[i] = data64[0] ^ padding64[i+4]; i++;
+ v[i] = data64[1] ^ padding64[i+4]; i++;
+ data32 = (UINT32 *)tcp_header;
+ if (i <= 3)
+ {
+ v[i] = (UINT64)data32[4] ^ padding64[i+4]; i++;
+ }
+ else
+ {
+ v2 ^= ((UINT64)data32[4] << 32);
+ }
+ }
+ else
+ {
+ if (udp_header != NULL)
+ {
+ data64 = (UINT64 *)udp_header;
+ v[i] = data64[0] ^ padding64[i+4]; i++;
+ }
+ else if (icmp_header != NULL)
+ {
+ data64 = (UINT64 *)icmp_header;
+ v[i] = data64[0] ^ padding64[i+4]; i++;
+ }
+ else if (icmpv6_header != NULL)
+ {
+ data64 = (UINT64 *)icmpv6_header;
+ v[i] = data64[0] ^ padding64[i+4]; i++;
+ }
+ }
+
+ while (i <= 3)
+ {
+ v[i] = seed ^ padding64[i+4]; i++;
+ }
+
+ // Hash
+ v1 = WinDivertXXH64Round(v[0], v1);
+ v2 = WinDivertXXH64Round(v[1], v2);
+ v3 = WinDivertXXH64Round(v[2], v3);
+ v4 = WinDivertXXH64Round(v[3], v4);
+ h64 = WINDIVERT_ROTL(v1, 1) + WINDIVERT_ROTL(v2, 7) +
+ WINDIVERT_ROTL(v3, 12) + WINDIVERT_ROTL(v4, 18);
+ h64 = WinDivertXXH64MergeRound(h64, v1);
+ h64 = WinDivertXXH64MergeRound(h64, v2);
+ h64 = WinDivertXXH64MergeRound(h64, v3);
+ h64 = WinDivertXXH64MergeRound(h64, v4);
+ h64 += 32; // "length"
+ h64 = WinDivertXXH64Avalanche(h64);
+
+ return h64;
+}
+
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index bbb0d3c..689e894 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -116,6 +116,9 @@ typedef enum
TOKEN_UDP_SRC_PORT,
TOKEN_ZERO,
TOKEN_EVENT,
+ TOKEN_RANDOM8,
+ TOKEN_RANDOM16,
+ TOKEN_RANDOM32,
TOKEN_PACKET,
TOKEN_PACKET16,
TOKEN_PACKET32,
@@ -613,6 +616,9 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
{"packet32", TOKEN_PACKET32, LNM___},
{"processId", TOKEN_PROCESS_ID, L__FSR},
{"protocol", TOKEN_PROTOCOL, LN_FS_},
+ {"random16", TOKEN_RANDOM16, LNM___},
+ {"random32", TOKEN_RANDOM32, LNM___},
+ {"random8", TOKEN_RANDOM8, LNM___},
{"remoteAddr", TOKEN_REMOTE_ADDR, LN_FS_},
{"remotePort", TOKEN_REMOTE_PORT, LN_FS_},
{"subIfIdx", TOKEN_SUB_IF_IDX, LNM___},
@@ -919,6 +925,9 @@ static PEXPR WinDivertMakeVar(KIND kind, PERROR error)
{{{0}}, TOKEN_UDP_SRC_PORT},
{{{0}}, TOKEN_ZERO},
{{{0}}, TOKEN_EVENT},
+ {{{0}}, TOKEN_RANDOM8},
+ {{{0}}, TOKEN_RANDOM16},
+ {{{0}}, TOKEN_RANDOM32},
{{{0}}, TOKEN_TRUE},
{{{0}}, TOKEN_FALSE},
{{{0}}, TOKEN_INBOUND},
@@ -1066,6 +1075,9 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error)
{
case TOKEN_ZERO:
case TOKEN_EVENT:
+ case TOKEN_RANDOM8:
+ case TOKEN_RANDOM16:
+ case TOKEN_RANDOM32:
case TOKEN_TRUE:
case TOKEN_FALSE:
case TOKEN_OUTBOUND:
@@ -1421,6 +1433,7 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
case TOKEN_PACKET:
case TOKEN_TCP_PAYLOAD:
case TOKEN_UDP_PAYLOAD:
+ case TOKEN_RANDOM8:
lb = 0; ub = 0xFF;
break;
case TOKEN_IP_FRAG_OFF:
@@ -1449,6 +1462,7 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
case TOKEN_PACKET16:
case TOKEN_TCP_PAYLOAD16:
case TOKEN_UDP_PAYLOAD16:
+ case TOKEN_RANDOM16:
lb = 0; ub = 0xFFFF;
break;
case TOKEN_IPV6_FLOW_LABEL:
@@ -1632,6 +1646,15 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset,
case TOKEN_EVENT:
object->field = WINDIVERT_FILTER_FIELD_EVENT;
break;
+ case TOKEN_RANDOM8:
+ object->field = WINDIVERT_FILTER_FIELD_RANDOM8;
+ break;
+ case TOKEN_RANDOM16:
+ object->field = WINDIVERT_FILTER_FIELD_RANDOM16;
+ break;
+ case TOKEN_RANDOM32:
+ object->field = WINDIVERT_FILTER_FIELD_RANDOM32;
+ break;
case TOKEN_PACKET:
object->field = WINDIVERT_FILTER_FIELD_PACKET;
object->arg[1] = var->val[0];
@@ -2342,6 +2365,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
PWINDIVERT_UDPHDR udphdr = NULL;
UINT8 protocol = 0;
UINT header_len = 0, payload_len = 0;
+ UINT64 random64 = 0;
UINT32 val[4];
UINT8 data8;
UINT16 data16;
@@ -2438,6 +2462,18 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
case WINDIVERT_FILTER_FIELD_UDP:
pass = (addr->Layer != WINDIVERT_LAYER_REFLECT);
break;
+ case WINDIVERT_FILTER_FIELD_RANDOM8:
+ case WINDIVERT_FILTER_FIELD_RANDOM16:
+ case WINDIVERT_FILTER_FIELD_RANDOM32:
+ pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
+ addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ if (pass && random64 == 0)
+ {
+ random64 = WinDivertHashPacket((UINT64)addr->Timestamp,
+ iphdr, ipv6hdr, icmphdr, icmpv6hdr, tcphdr, udphdr);
+ random64 |= 0xFF00000000000000ull;
+ }
+ break;
case WINDIVERT_FILTER_FIELD_IFIDX:
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
case WINDIVERT_FILTER_FIELD_PACKET:
@@ -2557,6 +2593,15 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
case WINDIVERT_FILTER_FIELD_EVENT:
val[0] = addr->Event;
break;
+ case WINDIVERT_FILTER_FIELD_RANDOM8:
+ val[0] = (random64 >> 48) & 0xFF;
+ break;
+ case WINDIVERT_FILTER_FIELD_RANDOM16:
+ val[0] = (random64 >> 32) & 0xFFFF;
+ break;
+ case WINDIVERT_FILTER_FIELD_RANDOM32:
+ val[0] = (UINT32)random64;
+ break;
case WINDIVERT_FILTER_FIELD_PACKET:
pass = WinDivertGetData(packet, packet_len, /*offset=*/0,
object[pc].arg[1], sizeof(data8), &data8);
@@ -3277,6 +3322,12 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test)
kind = TOKEN_ZERO; break;
case WINDIVERT_FILTER_FIELD_EVENT:
kind = TOKEN_EVENT; break;
+ case WINDIVERT_FILTER_FIELD_RANDOM8:
+ kind = TOKEN_RANDOM8; break;
+ case WINDIVERT_FILTER_FIELD_RANDOM16:
+ kind = TOKEN_RANDOM16; break;
+ case WINDIVERT_FILTER_FIELD_RANDOM32:
+ kind = TOKEN_RANDOM32; break;
case WINDIVERT_FILTER_FIELD_PACKET:
kind = TOKEN_PACKET; break;
case WINDIVERT_FILTER_FIELD_PACKET16:
@@ -4144,6 +4195,12 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
WinDivertPutString(stream, "zero"); return;
case TOKEN_EVENT:
WinDivertPutString(stream, "event"); return;
+ case TOKEN_RANDOM8:
+ WinDivertPutString(stream, "random8"); return;
+ case TOKEN_RANDOM16:
+ WinDivertPutString(stream, "random16"); return;
+ case TOKEN_RANDOM32:
+ WinDivertPutString(stream, "random32"); return;
case TOKEN_PACKET:
WinDivertPutString(stream, "packet"); break;
case TOKEN_PACKET16:
@@ -4414,3 +4471,23 @@ BOOL WinDivertHelperFormatFilter(const char *filter, WINDIVERT_LAYER layer,
return FALSE;
}
+/*
+ * WinDivert packet hash function.
+ */
+extern UINT64 WinDivertHelperHashPacket(const VOID *pPacket, UINT packetLen,
+ UINT64 seed)
+{
+ PWINDIVERT_IPHDR ip_header = NULL;
+ PWINDIVERT_IPV6HDR ipv6_header = NULL;
+ PWINDIVERT_ICMPHDR icmp_header = NULL;
+ PWINDIVERT_ICMPV6HDR icmpv6_header = NULL;
+ PWINDIVERT_TCPHDR tcp_header = NULL;
+ PWINDIVERT_UDPHDR udp_header = NULL;
+
+ WinDivertParsePacket((PVOID)pPacket, packetLen, &ip_header, &ipv6_header,
+ &icmp_header, &icmpv6_header, &tcp_header, &udp_header, NULL,
+ NULL, NULL);
+ return WinDivertHashPacket(seed, ip_header, ipv6_header, icmp_header,
+ icmpv6_header, tcp_header, udp_header);
+}
+
diff --git a/dll/windivert_shared.c b/dll/windivert_shared.c
index ed15081..7b32d3d 100644
--- a/dll/windivert_shared.c
+++ b/dll/windivert_shared.c
@@ -50,6 +50,8 @@
#define ntohl(x) BYTESWAP32(x)
#define htonl(x) BYTESWAP32(x)
+#include "windivert_hash.c"
+
/*
* IPv4/IPv6 pseudo headers.
*/
diff --git a/examples/netdump/netdump.c b/examples/netdump/netdump.c
index db7aaf5..68e70ae 100644
--- a/examples/netdump/netdump.c
+++ b/examples/netdump/netdump.c
@@ -82,6 +82,7 @@ int __cdecl main(int argc, char **argv)
PWINDIVERT_TCPHDR tcp_header;
PWINDIVERT_UDPHDR udp_header;
UINT32 src_addr[4], dst_addr[4];
+ UINT64 hash;
char src_str[INET6_ADDRSTRLEN+1], dst_str[INET6_ADDRSTRLEN+1];
const char *err_str;
LARGE_INTEGER base, freq;
@@ -169,10 +170,11 @@ int __cdecl main(int argc, char **argv)
SetConsoleTextAttribute(console, FOREGROUND_RED);
time_passed = (double)(addr.Timestamp - base.QuadPart) /
(double)freq.QuadPart;
+ hash = WinDivertHelperHashPacket(packet, packet_len, 0);
printf("Packet [Timestamp=%.8g, Direction=%s IfIdx=%u SubIfIdx=%u "
- "Loopback=%u]\n",
+ "Loopback=%u Hash=0x%.16llX]\n",
time_passed, (addr.Outbound? "outbound": "inbound"),
- addr.Network.IfIdx, addr.Network.SubIfIdx, addr.Loopback);
+ addr.Network.IfIdx, addr.Network.SubIfIdx, addr.Loopback, hash);
if (ip_header != NULL)
{
WinDivertHelperFormatIPv4Address(ntohl(ip_header->SrcAddr),
diff --git a/include/windivert.h b/include/windivert.h
index c59d820..6b08c9d 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -166,8 +166,8 @@ typedef enum
WINDIVERT_EVENT_SOCKET_LISTEN = 4, /* Socket listen. */
WINDIVERT_EVENT_SOCKET_CONNECT = 5, /* Socket connect. */
WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */
- WINDIVERT_EVENT_REFLECT_OPEN = 7, /* Open new WinDivert handle. */
- WINDIVERT_EVENT_REFLECT_CLOSE = 8, /* Close existing WinDivert handle. */
+ WINDIVERT_EVENT_REFLECT_OPEN = 7, /* WinDivert handle opened. */
+ WINDIVERT_EVENT_REFLECT_CLOSE = 8, /* WinDivert handle closed. */
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
/*
@@ -441,6 +441,18 @@ typedef struct
#ifndef WINDIVERT_KERNEL
+/*
+ * Hash a packet.
+ */
+extern WINDIVERTEXPORT UINT64 WinDivertHelperHashPacket(
+ __in const VOID *pPacket,
+ __in UINT packetLen,
+ __in UINT64 seed
+#ifdef __cplusplus
+ = 0
+#endif
+);
+
/*
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
*/
diff --git a/include/windivert_device.h b/include/windivert_device.h
index 222d237..fb09da7 100644
--- a/include/windivert_device.h
+++ b/include/windivert_device.h
@@ -136,8 +136,11 @@
#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD 74
#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16 75
#define WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32 76
+#define WINDIVERT_FILTER_FIELD_RANDOM8 77
+#define WINDIVERT_FILTER_FIELD_RANDOM16 78
+#define WINDIVERT_FILTER_FIELD_RANDOM32 79
#define WINDIVERT_FILTER_FIELD_MAX \
- WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32
+ WINDIVERT_FILTER_FIELD_RANDOM32
#define WINDIVERT_FILTER_TEST_EQ 0
#define WINDIVERT_FILTER_TEST_NEQ 1
diff --git a/mingw-build.sh b/mingw-build.sh
index e0acd54..2809dd7 100644
--- a/mingw-build.sh
+++ b/mingw-build.sh
@@ -59,7 +59,7 @@ do
fi
echo "BUILD MINGW-$CPU"
CC="$ENV-gcc"
- COPTS="-shared -Wall -Wno-pointer-to-int-cast -Os -Iinclude/
+ COPTS="-fno-ident -shared -Wall -Wno-pointer-to-int-cast -Os -Iinclude/
-Wl,--enable-stdcall-fixup -Wl,--entry=${MANGLE}WinDivertDllEntry"
CLIBS="-lgcc -lkernel32 -ladvapi32"
STRIP="$ENV-strip"
diff --git a/sys/windivert.c b/sys/windivert.c
index 57d04bb..78aaa0a 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -465,8 +465,9 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
PWINDIVERT_TCPHDR *tcp_header_ptr, PWINDIVERT_UDPHDR *udp_header_ptr,
UINT8 *proto_ptr, UINT *header_len_ptr, UINT *payload_len_ptr);
static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
- const VOID *layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound,
- BOOL loopback, BOOL impostor, const WINDIVERT_FILTER *filter);
+ const VOID *layer_data, LONGLONG timestamp, WINDIVERT_EVENT event,
+ BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor,
+ const WINDIVERT_FILTER *filter);
static const WINDIVERT_FILTER *windivert_filter_compile(
const WINDIVERT_FILTER *ioctl_filter, size_t ioctl_filter_len,
WINDIVERT_LAYER layer);
@@ -3330,8 +3331,8 @@ static void windivert_network_classify(context_t context,
do
{
BOOL match = windivert_filter(buffer_fst, layer, (PVOID)network_data,
- /*event=*/WINDIVERT_EVENT_NETWORK_PACKET, ipv4, outbound, loopback,
- impostor, filter);
+ timestamp, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET, ipv4,
+ outbound, loopback, impostor, filter);
if (match)
{
break;
@@ -3395,8 +3396,8 @@ static void windivert_network_classify(context_t context,
while (buffer_itr != NULL)
{
BOOL match = windivert_filter(buffer_itr, layer, (PVOID)network_data,
- /*event=*/WINDIVERT_EVENT_NETWORK_PACKET, ipv4, outbound,
- loopback, impostor, filter);
+ timestamp, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET, ipv4,
+ outbound, loopback, impostor, filter);
ok = windivert_queue_work(context, (PVOID)buffer_itr,
NET_BUFFER_DATA_LENGTH(buffer_itr), buffers, layer,
(PVOID)network_data, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET,
@@ -3547,8 +3548,9 @@ static void windivert_flow_established_classify(context_t context,
KeReleaseInStackQueuedSpinLock(&lock_handle);
match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW,
- (PVOID)flow_data, /*event=*/WINDIVERT_EVENT_FLOW_ESTABLISHED, ipv4,
- outbound, loopback, /*impostor=*/FALSE, filter);
+ (PVOID)flow_data, timestamp,
+ /*event=*/WINDIVERT_EVENT_FLOW_ESTABLISHED, ipv4, outbound, loopback,
+ /*impostor=*/FALSE, filter);
if (match)
{
ok = windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0,
@@ -3660,7 +3662,7 @@ static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id,
KeReleaseInStackQueuedSpinLock(&lock_handle);
match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW,
- (PVOID)&flow->data, /*event=*/WINDIVERT_EVENT_FLOW_DELETED,
+ (PVOID)&flow->data, timestamp, /*event=*/WINDIVERT_EVENT_FLOW_DELETED,
!flow->ipv6, flow->outbound, flow->loopback, /*impostor=*/FALSE,
filter);
if (match)
@@ -3987,7 +3989,7 @@ static void windivert_socket_classify(context_t context,
KeReleaseInStackQueuedSpinLock(&lock_handle);
match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_SOCKET,
- (PVOID)socket_data, event, ipv4, outbound, loopback,
+ (PVOID)socket_data, timestamp, event, ipv4, outbound, loopback,
/*impostor=*/FALSE, filter);
if (match)
{
@@ -4720,8 +4722,9 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
* Checks if the given network packet is of interest.
*/
static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
- const VOID *layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound,
- BOOL loopback, BOOL impostor, const WINDIVERT_FILTER *filter)
+ const VOID *layer_data, LONGLONG timestamp, WINDIVERT_EVENT event,
+ BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor,
+ const WINDIVERT_FILTER *filter)
{
PWINDIVERT_IPHDR ip_header = NULL;
PWINDIVERT_IPV6HDR ipv6_header = NULL;
@@ -4731,6 +4734,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
PWINDIVERT_UDPHDR udp_header = NULL;
UINT8 protocol = 0;
UINT header_len = 0, payload_len = 0;
+ UINT64 random64 = 0;
UINT16 ip, ttl;
PWINDIVERT_DATA_NETWORK network_data = NULL;
PWINDIVERT_DATA_FLOW flow_data = NULL;
@@ -4798,6 +4802,19 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
case WINDIVERT_FILTER_FIELD_UDP:
result = (layer != WINDIVERT_LAYER_REFLECT);
break;
+ case WINDIVERT_FILTER_FIELD_RANDOM8:
+ case WINDIVERT_FILTER_FIELD_RANDOM16:
+ case WINDIVERT_FILTER_FIELD_RANDOM32:
+ result = (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ if (result && random64 == 0)
+ {
+ random64 = WinDivertHashPacket((UINT64)timestamp,
+ ip_header, ipv6_header, icmp_header, icmpv6_header,
+ tcp_header, udp_header);
+ random64 |= 0xFF00000000000000ull; // Make non-zero.
+ }
+ break;
case WINDIVERT_FILTER_FIELD_IFIDX:
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
case WINDIVERT_FILTER_FIELD_PACKET:
@@ -4913,6 +4930,15 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
case WINDIVERT_FILTER_FIELD_EVENT:
field[0] = (UINT32)event;
break;
+ case WINDIVERT_FILTER_FIELD_RANDOM8:
+ field[0] = (UINT32)(random64 >> 48) & 0xFF;
+ break;
+ case WINDIVERT_FILTER_FIELD_RANDOM16:
+ field[0] = (UINT32)(random64 >> 32) & 0xFFFF;
+ break;
+ case WINDIVERT_FILTER_FIELD_RANDOM32:
+ field[0] = (UINT32)random64;
+ break;
case WINDIVERT_FILTER_FIELD_PACKET:
result = windivert_get_data(buffer, /*offset=*/0,
(INT)filter[ip].arg[1], sizeof(data8), &data8);
@@ -5653,6 +5679,7 @@ static const WINDIVERT_FILTER *windivert_filter_compile(
case WINDIVERT_FILTER_FIELD_PACKET:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_RANDOM8:
if (ioctl_filter[i].arg[0] > UINT8_MAX)
{
goto windivert_filter_compile_error;
@@ -5686,6 +5713,7 @@ static const WINDIVERT_FILTER *windivert_filter_compile(
case WINDIVERT_FILTER_FIELD_PACKET16:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_RANDOM16:
if (ioctl_filter[i].arg[0] > UINT16_MAX)
{
goto windivert_filter_compile_error;
@@ -5912,8 +5940,8 @@ static void windivert_reflect_event_notify(context_t context,
KeReleaseInStackQueuedSpinLock(&lock_handle);
match = windivert_filter(/*buffer=*/NULL,
/*layer=*/WINDIVERT_LAYER_REFLECT, (PVOID)&context->reflect.data,
- event, /*ipv4=*/TRUE, /*outbound=*/FALSE, /*loopback=*/FALSE,
- /*impostor=*/FALSE, filter);
+ timestamp, event, /*ipv4=*/TRUE, /*outbound=*/FALSE,
+ /*loopback=*/FALSE, /*impostor=*/FALSE, filter);
if (!match)
{
continue;
@@ -5960,7 +5988,7 @@ static void windivert_reflect_established_notify(context_t context,
entry = entry->Flink;
match = windivert_filter(/*buffer=*/NULL,
/*layer=*/WINDIVERT_LAYER_REFLECT, (PVOID)&waiter->reflect.data,
- /*event=*/WINDIVERT_EVENT_REFLECT_OPEN, /*ipv4=*/TRUE,
+ timestamp, /*event=*/WINDIVERT_EVENT_REFLECT_OPEN, /*ipv4=*/TRUE,
/*outbound=*/FALSE, /*loopback=*/FALSE, /*impostor=*/FALSE, filter);
if (!match)
{
From edbe5ea9426ef9614bd69ce07e34ac1601bb8b2d Mon Sep 17 00:00:00 2001
From: basil00
Date: Thu, 15 Nov 2018 07:58:44 +0800
Subject: [PATCH 20/23] Optimize based on event expressions.
E.g., if "event == CONNECT" then do not install
a callout for LISTEN, etc.
---
dll/windivert.c | 2 +-
dll/windivert_helper.c | 96 ++++++++++++++++++++++++++------------
include/windivert_device.h | 12 ++++-
sys/windivert.c | 51 ++++++++++++++++----
4 files changed, 120 insertions(+), 41 deletions(-)
diff --git a/dll/windivert.c b/dll/windivert.c
index 4527358..72e8bfa 100644
--- a/dll/windivert.c
+++ b/dll/windivert.c
@@ -404,7 +404,7 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
- filter_flags = WinDivertAnalyzeFilter(object, obj_len);
+ filter_flags = WinDivertAnalyzeFilter(layer, 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 689e894..08c3856 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -1960,7 +1960,8 @@ static void WinDivertEmitFilter(PEXPR *stack, UINT len, UINT16 label,
/*
* Analyze a filter object.
*/
-static UINT64 WinDivertAnalyzeFilter(PWINDIVERT_FILTER filter, UINT length)
+static UINT64 WinDivertAnalyzeFilter(WINDIVERT_LAYER layer,
+ PWINDIVERT_FILTER filter, UINT length)
{
BOOL result;
UINT64 flags = 0;
@@ -1973,45 +1974,80 @@ static UINT64 WinDivertAnalyzeFilter(PWINDIVERT_FILTER filter, UINT length)
return 0;
}
- // Inbound?
- result = WinDivertCondExecFilter(filter, length,
- WINDIVERT_FILTER_FIELD_INBOUND, 1);
- if (result)
+ if (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_NETWORK_FORWARD)
{
+ // Inbound?
result = WinDivertCondExecFilter(filter, length,
- WINDIVERT_FILTER_FIELD_OUTBOUND, 0);
- }
- flags |= (result? WINDIVERT_FILTER_FLAG_INBOUND: 0);
+ WINDIVERT_FILTER_FIELD_INBOUND, 1);
+ if (result)
+ {
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_OUTBOUND, 0);
+ }
+ flags |= (result? WINDIVERT_FILTER_FLAG_INBOUND: 0);
- // Outbound?
- result = WinDivertCondExecFilter(filter, length,
- WINDIVERT_FILTER_FIELD_OUTBOUND, 1);
- if (result)
+ // Outbound?
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_OUTBOUND, 1);
+ if (result)
+ {
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_INBOUND, 0);
+ }
+ flags |= (result? WINDIVERT_FILTER_FLAG_OUTBOUND: 0);
+ }
+
+ if (layer != WINDIVERT_LAYER_REFLECT)
{
+ // IPv4?
result = WinDivertCondExecFilter(filter, length,
- WINDIVERT_FILTER_FIELD_INBOUND, 0);
- }
- flags |= (result? WINDIVERT_FILTER_FLAG_OUTBOUND: 0);
+ WINDIVERT_FILTER_FIELD_IP, 1);
+ if (result)
+ {
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_IPV6, 0);
+ }
+ flags |= (result? WINDIVERT_FILTER_FLAG_IP: 0);
- // IPv4?
- result = WinDivertCondExecFilter(filter, length,
- WINDIVERT_FILTER_FIELD_IP, 1);
- if (result)
- {
+ // Ipv6?
result = WinDivertCondExecFilter(filter, length,
- WINDIVERT_FILTER_FIELD_IPV6, 0);
+ WINDIVERT_FILTER_FIELD_IPV6, 1);
+ if (result)
+ {
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_IP, 0);
+ }
+ flags |= (result? WINDIVERT_FILTER_FLAG_IPV6: 0);
}
- flags |= (result? WINDIVERT_FILTER_FLAG_IP: 0);
- // Ipv6?
- result = WinDivertCondExecFilter(filter, length,
- WINDIVERT_FILTER_FIELD_IPV6, 1);
- if (result)
- {
- result = WinDivertCondExecFilter(filter, length,
- WINDIVERT_FILTER_FIELD_IP, 0);
+ // Events:
+ switch (layer)
+ {
+ case WINDIVERT_LAYER_FLOW:
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_FLOW_DELETED);
+ flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_FLOW_DELETED: 0);
+ break;
+
+ case WINDIVERT_LAYER_SOCKET:
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_BIND);
+ flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND: 0);
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_CONNECT);
+ flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT: 0);
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_LISTEN);
+ flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN: 0);
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_ACCEPT);
+ flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT: 0);
+ break;
+
+ default:
+ break;
}
- flags |= (result? WINDIVERT_FILTER_FLAG_IPV6: 0);
return flags;
}
diff --git a/include/windivert_device.h b/include/windivert_device.h
index fb09da7..1384785 100644
--- a/include/windivert_device.h
+++ b/include/windivert_device.h
@@ -192,10 +192,20 @@
#define WINDIVERT_FILTER_FLAG_OUTBOUND 0x0000000000000002ull
#define WINDIVERT_FILTER_FLAG_IP 0x0000000000000004ull
#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_FLAGS_ALL \
(WINDIVERT_FILTER_FLAG_INBOUND | WINDIVERT_FILTER_FLAG_OUTBOUND | \
- WINDIVERT_FILTER_FLAG_IP | WINDIVERT_FILTER_FLAG_IPV6)
+ 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_CONNECT | \
+ WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN | \
+ WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT)
/*
* WinDivert priorities.
diff --git a/sys/windivert.c b/sys/windivert.c
index 78aaa0a..ab2b204 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -170,7 +170,8 @@ struct context_s
BOOL installed[WINDIVERT_CONTEXT_MAXLAYERS];// What is installed?
HANDLE engine_handle; // WFP engine handle.
const WINDIVERT_FILTER *filter; // Packet filter.
- UINT8 filter_len; // Length of filter.
+ UINT16 filter_len; // Length of filter.
+ UINT64 filter_flags; // Filter flags.
struct reflect_context_s reflect; // Reflection info.
};
typedef struct context_s context_s;
@@ -1264,6 +1265,8 @@ extern VOID windivert_create(IN WDFDEVICE device, IN WDFREQUEST request,
context->shutdown_send = FALSE;
context->priority = windivert_context_priority(WINDIVERT_PRIORITY_DEFAULT);
context->filter = NULL;
+ context->filter_len = 0;
+ context->filter_flags = 0;
context->worker = NULL;
for (i = 0; i < WINDIVERT_CONTEXT_MAXLAYERS; i++)
{
@@ -1351,13 +1354,17 @@ 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;
+ BOOL inbound, outbound, ipv4, ipv6, bind, connect, 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);
i = 0;
switch (layer)
@@ -1406,18 +1413,36 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer,
break;
case WINDIVERT_LAYER_SOCKET:
- if (ipv4)
+ if (ipv4 && bind)
{
layers[i++] = WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4;
+ }
+ if (ipv4 && connect)
+ {
layers[i++] = WINDIVERT_LAYER_AUTH_CONNECT_IPV4;
+ }
+ if (ipv4 && listen)
+ {
layers[i++] = WINDIVERT_LAYER_AUTH_LISTEN_IPV4;
+ }
+ if (ipv4 && accept)
+ {
layers[i++] = WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4;
}
- if (ipv6)
+ if (ipv6 && bind)
{
layers[i++] = WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6;
+ }
+ if (ipv6 && connect)
+ {
layers[i++] = WINDIVERT_LAYER_AUTH_CONNECT_IPV6;
+ }
+ if (ipv6 && listen)
+ {
layers[i++] = WINDIVERT_LAYER_AUTH_LISTEN_IPV6;
+ }
+ if (ipv6 && accept)
+ {
layers[i++] = WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6;
}
break;
@@ -2750,6 +2775,7 @@ windivert_ioctl_bad_start_state:
}
context->filter = filter;
context->filter_len = filter_len;
+ context->filter_flags = filter_flags;
context->reflect.data.Timestamp = timestamp;
context->reflect.data.ProcessId = process_id;
context->reflect.data.Layer = context->layer;
@@ -3507,7 +3533,7 @@ static void windivert_flow_established_classify(context_t context,
IN BOOL outbound, IN BOOL loopback, OUT FWPS_CLASSIFY_OUT0 *result)
{
KLOCK_QUEUE_HANDLE lock_handle;
- UINT64 flags;
+ UINT64 flags, filter_flags;
UINT32 callout_id;
UINT16 layer_id;
BOOL match, ok;
@@ -3537,6 +3563,7 @@ static void windivert_flow_established_classify(context_t context,
}
filter = context->filter;
flags = context->flags;
+ filter_flags = context->filter_flags;
callout_id = (ipv4? context->flow_v4_callout_id:
context->flow_v6_callout_id);
object = (WDFOBJECT)context->object;
@@ -3564,8 +3591,14 @@ static void windivert_flow_established_classify(context_t context,
}
}
- // Associate a context with the flow. This is so we can detect when
- // the flow is deleted.
+ // Associate a context with the flow. This is so we can detect the
+ // FLOW_DELETED event.
+ if ((filter_flags & WINDIVERT_FILTER_FLAG_EVENT_FLOW_DELETED) == 0)
+ {
+ // We don't care about FLOW_DELETED.
+ WdfObjectDereference(object);
+ return;
+ }
flow = windivert_malloc(sizeof(struct flow_s), FALSE);
if (flow == NULL)
{
@@ -5879,7 +5912,7 @@ static PWINDIVERT_IPHDR windivert_reflect_pseudo_packet(context_t context,
UINT8 *packet;
char *object;
const WINDIVERT_FILTER *filter;
- UINT8 filter_len;
+ UINT16 filter_len;
PWINDIVERT_IPHDR iphdr;
WINDIVERT_STREAM stream;
@@ -5901,7 +5934,7 @@ static PWINDIVERT_IPHDR windivert_reflect_pseudo_packet(context_t context,
filter_len = context->filter_len;
KeReleaseInStackQueuedSpinLock(&lock_handle);
- WinDivertSerializeFilter(&stream, filter, filter_len);
+ WinDivertSerializeFilter(&stream, filter, (UINT8)filter_len);
total_len = sizeof(WINDIVERT_IPHDR) + (UINT16)stream.pos;
RtlZeroMemory(iphdr, sizeof(WINDIVERT_IPHDR));
From 8ff3c86330a153bb0f86f354877921a6cfdcd0f3 Mon Sep 17 00:00:00 2001
From: basil00
Date: Thu, 15 Nov 2018 08:24:46 +0800
Subject: [PATCH 21/23] Version tweaks.
---
LICENSE | 6 +++---
README | 2 +-
doc/windivert.html | 8 ++++----
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/LICENSE b/LICENSE
index 5325b0b..8489a8e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
-WinDivert is dual-licensed, and is available under the GNU Lesser General
-Public License (LGPL) Version 3 or the GNU General Public License (GPL)
-Version 2. Copies of the LGPLv3, GPLv3 and GPLv2 are provided below.
+WinDivert is dual-licensed under your choice of the GNU Lesser General Public
+License (LGPL) Version 3 or the GNU General Public License (GPL) Version 2.
+Copies of the LGPLv3, GPLv3 and GPLv2 are provided below.
==============================================================================
diff --git a/README b/README
index 046ef7d..6798e09 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-WinDivert 1.4: Windows Packet Divert
+WinDivert 2.0: Windows Packet Divert
====================================
1. Introduction
diff --git a/doc/windivert.html b/doc/windivert.html
index 67d36d0..4f08cf2 100644
--- a/doc/windivert.html
+++ b/doc/windivert.html
@@ -1,10 +1,10 @@
- WinDivert 1.4 Documentation
+ WinDivert 2.0 Documentation
-WinDivert 1.4: Windows Packet Divert
+WinDivert 2.0: Windows Packet Divert
Table of Contents
- 1. Introduction
@@ -217,8 +217,8 @@ uninstalled during the next machine reboot.
The WinDivert driver can also be manually removed by issuing the following
commands at the command prompt
-sc stop WinDivert1.4
-sc delete WinDivert1.4
+sc stop WinDivert2.0
+sc delete WinDivert2.0
Note that this is not recommended as it will interfere with other
applications that depend on WinDivert.
From 54e627e82beacab6c754722fe704a842d0cf276e Mon Sep 17 00:00:00 2001
From: basil00
Date: Fri, 16 Nov 2018 07:50:04 +0800
Subject: [PATCH 22/23] Add byte ordering helper functions to WinDivert.
Some sample programs were linking to WinSock2
just for ntohl()/ntohs(). This dependency can
now be removed.
---
dll/windivert.def | 8 ++++++
dll/windivert_helper.c | 48 ++++++++++++++++++++++++++++++++++
dll/windivert_shared.c | 9 +++++++
examples/netdump/netdump.c | 20 ++++----------
examples/netfilter/netfilter.c | 23 ++++++----------
examples/webfilter/webfilter.c | 6 ++++-
include/windivert.h | 24 ++++++++++++++++-
mingw-build.sh | 14 +++++-----
8 files changed, 113 insertions(+), 39 deletions(-)
diff --git a/dll/windivert.def b/dll/windivert.def
index 39d9efa..aa30104 100644
--- a/dll/windivert.def
+++ b/dll/windivert.def
@@ -20,3 +20,11 @@ EXPORTS
WinDivertHelperCompileFilter
WinDivertHelperEvalFilter
WinDivertHelperFormatFilter
+ WinDivertHelperNtohs
+ WinDivertHelperHtons
+ WinDivertHelperNtohl
+ WinDivertHelperHtonl
+ WinDivertHelperNtohll
+ WinDivertHelperHtonll
+ WinDivertHelperNtohIpv6Address
+ WinDivertHelperHtonIpv6Address
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index 08c3856..de68059 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -4527,3 +4527,51 @@ extern UINT64 WinDivertHelperHashPacket(const VOID *pPacket, UINT packetLen,
icmpv6_header, tcp_header, udp_header);
}
+/*
+ * Byte ordering.
+ */
+extern UINT16 WinDivertHelperNtohs(UINT16 x)
+{
+ return BYTESWAP16(x);
+}
+extern UINT16 WinDivertHelperHtons(UINT16 x)
+{
+ return BYTESWAP16(x);
+}
+extern UINT32 WinDivertHelperNtohl(UINT32 x)
+{
+ return BYTESWAP32(x);
+}
+extern UINT32 WinDivertHelperHtonl(UINT32 x)
+{
+ return BYTESWAP32(x);
+}
+extern UINT64 WinDivertHelperNtohll(UINT64 x)
+{
+ return BYTESWAP64(x);
+}
+extern UINT64 WinDivertHelperHtonll(UINT64 x)
+{
+ return BYTESWAP64(x);
+}
+static void WinDivertByteSwap128(const UINT *inAddr, UINT *outAddr)
+{
+ UINT32 tmp[4], i; // tmp[] allows overlapping
+ for (i = 0; i < 4; i++)
+ {
+ tmp[3-i] = BYTESWAP32(inAddr[0]);
+ }
+ for (i = 0; i < 4; i++)
+ {
+ outAddr[i] = tmp[i];
+ }
+}
+extern void WinDivertHelperNtohIpv6Address(const UINT *inAddr, UINT *outAddr)
+{
+ WinDivertByteSwap128(inAddr, outAddr);
+}
+extern void WinDivertHelperHtonIpv6Address(const UINT *inAddr, UINT *outAddr)
+{
+ WinDivertByteSwap128(inAddr, outAddr);
+}
+
diff --git a/dll/windivert_shared.c b/dll/windivert_shared.c
index 7b32d3d..dfe2dd0 100644
--- a/dll/windivert_shared.c
+++ b/dll/windivert_shared.c
@@ -45,6 +45,15 @@
#define BYTESWAP32(x) \
((((x) >> 24) & 0x000000FF) | (((x) >> 8) & 0x0000FF00) | \
(((x) << 8) & 0x00FF0000) | (((x) << 24) & 0xFF000000))
+#define BYTESWAP64(x) \
+ ((((x) >> 56) & 0x00000000000000FFull) | \
+ (((x) >> 40) & 0x000000000000FF00ull) | \
+ (((x) >> 24) & 0x0000000000FF0000ull) | \
+ (((x) >> 8) & 0x00000000FF000000ull) | \
+ (((x) << 8) & 0x000000FF00000000ull) | \
+ (((x) << 24) & 0x0000FF0000000000ull) | \
+ (((x) << 40) & 0x00FF000000000000ull) | \
+ (((x) << 56) & 0xFF00000000000000ull))
#define ntohs(x) BYTESWAP16(x)
#define htons(x) BYTESWAP16(x)
#define ntohl(x) BYTESWAP32(x)
diff --git a/examples/netdump/netdump.c b/examples/netdump/netdump.c
index 68e70ae..4904b9e 100644
--- a/examples/netdump/netdump.c
+++ b/examples/netdump/netdump.c
@@ -41,7 +41,6 @@
*
*/
-#include
#include
#include
#include
@@ -49,21 +48,12 @@
#include "windivert.h"
+#define ntohs(x) WinDivertHelperNtohs(x)
+#define ntohl(x) WinDivertHelperNtohl(x)
+
#define MAXBUF 0xFFFF
#define INET6_ADDRSTRLEN 45
-/*
- * IPv6 address byte swap.
- */
-void byteswap128(UINT32 *dst_addr, const UINT32 *src_addr)
-{
- int i;
- for (i = 0; i < 4; i++)
- {
- dst_addr[i] = ntohl(src_addr[4-i-1]);
- }
-}
-
/*
* Entry.
*/
@@ -198,8 +188,8 @@ int __cdecl main(int argc, char **argv)
}
if (ipv6_header != NULL)
{
- byteswap128(src_addr, ipv6_header->SrcAddr);
- byteswap128(dst_addr, ipv6_header->DstAddr);
+ WinDivertHelperNtohIpv6Address(ipv6_header->SrcAddr, src_addr);
+ WinDivertHelperNtohIpv6Address(ipv6_header->DstAddr, dst_addr);
WinDivertHelperFormatIPv6Address(src_addr, src_str,
sizeof(src_str));
WinDivertHelperFormatIPv6Address(dst_addr, dst_str,
diff --git a/examples/netfilter/netfilter.c b/examples/netfilter/netfilter.c
index 2377be6..758a346 100644
--- a/examples/netfilter/netfilter.c
+++ b/examples/netfilter/netfilter.c
@@ -47,7 +47,6 @@
* This program is similar to Linux's iptables with the "-j REJECT" target.
*/
-#include
#include
#include
#include
@@ -55,8 +54,14 @@
#include "windivert.h"
+#define ntohs(x) WinDivertHelperNtohs(x)
+#define ntohl(x) WinDivertHelperNtohl(x)
+#define htons(x) WinDivertHelperHtons(x)
+#define htonl(x) WinDivertHelperHtonl(x)
+
#define MAXBUF 0xFFFF
#define INET6_ADDRSTRLEN 45
+#define IPPROTO_ICMPV6 58
/*
* Pre-fabricated packets.
@@ -97,18 +102,6 @@ static void PacketIpv6Init(PWINDIVERT_IPV6HDR packet);
static void PacketIpv6TcpInit(PTCPV6PACKET packet);
static void PacketIpv6Icmpv6Init(PICMPV6PACKET packet);
-/*
- * IPv6 address byte swap.
- */
-void byteswap128(UINT32 *dst_addr, const UINT32 *src_addr)
-{
- int i;
- for (i = 0; i < 4; i++)
- {
- dst_addr[i] = ntohl(src_addr[4-i-1]);
- }
-}
-
/*
* Entry.
*/
@@ -230,8 +223,8 @@ int __cdecl main(int argc, char **argv)
}
if (ipv6_header != NULL)
{
- byteswap128(src_addr, ipv6_header->SrcAddr);
- byteswap128(dst_addr, ipv6_header->DstAddr);
+ WinDivertHelperNtohIpv6Address(ipv6_header->SrcAddr, src_addr);
+ WinDivertHelperNtohIpv6Address(ipv6_header->DstAddr, dst_addr);
WinDivertHelperFormatIPv6Address(src_addr, src_str,
sizeof(src_str));
WinDivertHelperFormatIPv6Address(dst_addr, dst_str,
diff --git a/examples/webfilter/webfilter.c b/examples/webfilter/webfilter.c
index 860970b..cb1c1a5 100644
--- a/examples/webfilter/webfilter.c
+++ b/examples/webfilter/webfilter.c
@@ -42,13 +42,17 @@
* blockpage to the browser.
*/
-#include
#include
#include
#include
#include "windivert.h"
+#define ntohs(x) WinDivertHelperNtohs(x)
+#define ntohl(x) WinDivertHelperNtohl(x)
+#define htons(x) WinDivertHelperHtons(x)
+#define htonl(x) WinDivertHelperHtonl(x)
+
#define MAXBUF 0xFFFF
#define MAXURL 4096
diff --git a/include/windivert.h b/include/windivert.h
index 6b08c9d..cf63171 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -530,12 +530,34 @@ extern WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter(
/*
* Format the given filter string.
*/
-extern BOOL WinDivertHelperFormatFilter(
+extern WINDIVERTEXPORT BOOL WinDivertHelperFormatFilter(
__in const char *filter,
__in WINDIVERT_LAYER layer,
__out char *buffer,
__in UINT bufLen);
+/*
+ * Byte ordering.
+ */
+extern WINDIVERTEXPORT UINT16 WinDivertHelperNtohs(
+ __in UINT16 x);
+extern WINDIVERTEXPORT UINT16 WinDivertHelperHtons(
+ __in UINT16 x);
+extern WINDIVERTEXPORT UINT32 WinDivertHelperNtohl(
+ __in UINT32 x);
+extern WINDIVERTEXPORT UINT32 WinDivertHelperHtonl(
+ __in UINT32 x);
+extern WINDIVERTEXPORT UINT64 WinDivertHelperNtohll(
+ __in UINT64 x);
+extern WINDIVERTEXPORT UINT64 WinDivertHelperHtonll(
+ __in UINT64 x);
+extern WINDIVERTEXPORT void WinDivertHelperNtohIpv6Address(
+ __in const UINT *inAddr,
+ __out UINT *outAddr);
+extern WINDIVERTEXPORT void WinDivertHelperHtonIpv6Address(
+ __in const UINT *inAddr,
+ __out UINT *outAddr);
+
#endif /* WINDIVERT_KERNEL */
#ifdef __cplusplus
diff --git a/mingw-build.sh b/mingw-build.sh
index 2809dd7..9280310 100644
--- a/mingw-build.sh
+++ b/mingw-build.sh
@@ -79,19 +79,19 @@ do
--output-lib install/MINGW/$CPU/WinDivert.lib 2>/dev/null
echo "\tbuild install/MINGW/$CPU/netdump.exe..."
$CC -s -O2 -Iinclude/ examples/netdump/netdump.c \
- -o "install/MINGW/$CPU/netdump.exe" -lWinDivert -lws2_32 \
+ -o "install/MINGW/$CPU/netdump.exe" -lWinDivert \
-L"install/MINGW/$CPU/"
echo "\tbuild install/MINGW/$CPU/netfilter.exe..."
$CC -s -O2 -Iinclude/ examples/netfilter/netfilter.c \
- -o "install/MINGW/$CPU/netfilter.exe" -lWinDivert -lws2_32 \
+ -o "install/MINGW/$CPU/netfilter.exe" -lWinDivert \
-L"install/MINGW/$CPU/"
echo "\tbuild install/MINGW/$CPU/passthru.exe..."
$CC -s -O2 -Iinclude/ examples/passthru/passthru.c \
- -o "install/MINGW/$CPU/passthru.exe" -lWinDivert -lws2_32 \
+ -o "install/MINGW/$CPU/passthru.exe" -lWinDivert \
-L"install/MINGW/$CPU/"
echo "\tbuild install/MINGW/$CPU/webfilter.exe..."
$CC -s -O2 -Iinclude/ examples/webfilter/webfilter.c \
- -o "install/MINGW/$CPU/webfilter.exe" -lWinDivert -lws2_32 \
+ -o "install/MINGW/$CPU/webfilter.exe" -lWinDivert \
-L"install/MINGW/$CPU/"
echo "\tbuild install/MINGW/$CPU/streamdump.exe..."
$CC -s -O2 -Iinclude/ examples/streamdump/streamdump.c \
@@ -99,15 +99,15 @@ do
-L"install/MINGW/$CPU/"
echo "\tcopy install/MINGW/$CPU/flowtrack.exe..."
$CC -s -O2 -Iinclude/ examples/flowtrack/flowtrack.c \
- -o "install/MINGW/$CPU/flowtrack.exe" -lWinDivert -lws2_32 -lpsapi \
+ -o "install/MINGW/$CPU/flowtrack.exe" -lWinDivert -lpsapi \
-lshlwapi -L"install/MINGW/$CPU/"
echo "\tcopy install/MINGW/$CPU/windivertctl.exe..."
$CC -s -O2 -Iinclude/ examples/windivertctl/windivertctl.c \
- -o "install/MINGW/$CPU/windivertctl.exe" -lWinDivert -lws2_32 \
+ -o "install/MINGW/$CPU/windivertctl.exe" -lWinDivert \
-lpsapi -lshlwapi -L"install/MINGW/$CPU/"
echo "\tcopy install/MINGW/$CPU/socketdump.exe..."
$CC -s -O2 -Iinclude/ examples/socketdump/socketdump.c \
- -o "install/MINGW/$CPU/socketdump.exe" -lWinDivert -lws2_32 \
+ -o "install/MINGW/$CPU/socketdump.exe" -lWinDivert \
-lpsapi -lshlwapi -L"install/MINGW/$CPU/"
echo "\tcopy install/MINGW/$CPU/WinDivert$BITS.sys..."
cp install/WDDK/$CPU/WinDivert$BITS.sys install/MINGW/$CPU
From 29c6fda167db6d572c3b454be8420f6c9f2ebaeb Mon Sep 17 00:00:00 2001
From: basil00
Date: Mon, 19 Nov 2018 07:21:54 +0800
Subject: [PATCH 23/23] Improve & expand WinDivert test suite.
- Include tests for random*.
- Include latency timings in microseconds.
- More tests.
---
dll/windivert_helper.c | 4 +-
sys/windivert.c | 13 +-
test/build.sh | 2 +-
test/test.c | 320 ++++++++++++++++++++++++-----------------
test/test_data.c | 24 ++--
5 files changed, 215 insertions(+), 148 deletions(-)
diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c
index de68059..678a15d 100644
--- a/dll/windivert_helper.c
+++ b/dll/windivert_helper.c
@@ -2630,10 +2630,10 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
val[0] = addr->Event;
break;
case WINDIVERT_FILTER_FIELD_RANDOM8:
- val[0] = (random64 >> 48) & 0xFF;
+ val[0] = (UINT32)((random64 >> 48) & 0xFF);
break;
case WINDIVERT_FILTER_FIELD_RANDOM16:
- val[0] = (random64 >> 32) & 0xFFFF;
+ val[0] = (UINT32)((random64 >> 32) & 0xFFFF);
break;
case WINDIVERT_FILTER_FIELD_RANDOM32:
val[0] = (UINT32)random64;
diff --git a/sys/windivert.c b/sys/windivert.c
index ab2b204..81e024d 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -32,6 +32,7 @@
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+
#include
#include
#include
@@ -2314,7 +2315,9 @@ windivert_write_too_small_packet:
(addr[i].PseudoTCPChecksum? 0:
WINDIVERT_HELPER_NO_TCP_CHECKSUM) |
(addr[i].PseudoUDPChecksum? 0:
- WINDIVERT_HELPER_NO_UDP_CHECKSUM);
+ WINDIVERT_HELPER_NO_UDP_CHECKSUM) |
+ WINDIVERT_HELPER_NO_ICMP_CHECKSUM |
+ WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM;
WinDivertHelperCalcChecksums(data_copy, packet_len, NULL,
checksums);
}
@@ -4372,7 +4375,9 @@ static void windivert_reinject_packet(packet_t packet)
(packet->pseudo_tcp_checksum != 0? 0:
WINDIVERT_HELPER_NO_TCP_CHECKSUM) |
(packet->pseudo_udp_checksum != 0? 0:
- WINDIVERT_HELPER_NO_UDP_CHECKSUM);
+ WINDIVERT_HELPER_NO_UDP_CHECKSUM) |
+ WINDIVERT_HELPER_NO_ICMP_CHECKSUM |
+ WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM;
WinDivertHelperCalcChecksums(packet_data, packet_len, NULL, checksums);
}
@@ -4964,10 +4969,10 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
field[0] = (UINT32)event;
break;
case WINDIVERT_FILTER_FIELD_RANDOM8:
- field[0] = (UINT32)(random64 >> 48) & 0xFF;
+ field[0] = (UINT32)((random64 >> 48) & 0xFF);
break;
case WINDIVERT_FILTER_FIELD_RANDOM16:
- field[0] = (UINT32)(random64 >> 32) & 0xFFFF;
+ field[0] = (UINT32)((random64 >> 32) & 0xFFFF);
break;
case WINDIVERT_FILTER_FIELD_RANDOM32:
field[0] = (UINT32)random64;
diff --git a/test/build.sh b/test/build.sh
index bd22c25..d9cd37c 100755
--- a/test/build.sh
+++ b/test/build.sh
@@ -37,6 +37,6 @@
CC=x86_64-w64-mingw32-gcc
-$CC -s -O2 -I../include/ test.c -o test.exe -lWinDivert \
+$CC -fno-ident -s -O2 -I../include/ test.c -o test.exe -lWinDivert \
-L"../install/MINGW/amd64/"
diff --git a/test/test.c b/test/test.c
index 7dde63a..da25393 100644
--- a/test/test.c
+++ b/test/test.c
@@ -54,15 +54,15 @@
*/
struct packet
{
- char *packet;
+ const char *packet;
size_t packet_len;
char *name;
};
struct test
{
- char *filter;
- struct packet *packet;
+ const char *filter;
+ const struct packet *packet;
BOOL match;
};
@@ -70,48 +70,48 @@ struct test
* Prototypes.
*/
static BOOL run_test(HANDLE inject_handle, const char *filter,
- const char *packet, const size_t packet_len, BOOL match);
+ const char *packet, const size_t packet_len, BOOL match, INT64 *diff);
/*
* Test data.
*/
-static struct packet pkt_echo_request =
+static const struct packet pkt_echo_request =
{
echo_request,
sizeof(echo_request),
"ipv4_icmp_echo_req"
};
-static struct packet pkt_http_request =
+static const struct packet pkt_http_request =
{
http_request,
sizeof(http_request),
"ipv4_tcp_http_req"
};
-static struct packet pkt_dns_request =
+static const struct packet pkt_dns_request =
{
dns_request,
sizeof(dns_request),
"ipv4_udp_dns_req"
};
-static struct packet pkt_ipv6_tcp_syn =
+static const struct packet pkt_ipv6_tcp_syn =
{
ipv6_tcp_syn,
sizeof(ipv6_tcp_syn),
"ipv6_tcp_syn"
};
-static struct packet pkt_ipv6_echo_reply =
+static const struct packet pkt_ipv6_echo_reply =
{
ipv6_echo_reply,
sizeof(ipv6_echo_reply),
"ipv6_icmpv6_echo_rep"
};
-static struct packet pkt_ipv6_exthdrs_udp =
+static const struct packet pkt_ipv6_exthdrs_udp =
{
ipv6_exthdrs_udp,
sizeof(ipv6_exthdrs_udp),
"ipv6_exthdrs_udp"
};
-static struct test tests[] =
+static const struct test tests[] =
{
{"event = PACKET", &pkt_echo_request, TRUE},
{"packet[0] == 0x45", &pkt_echo_request, TRUE},
@@ -130,6 +130,18 @@ static struct test tests[] =
{"packet32[0b] == 0x45000054 && packet32[3b] == 0x54123440 && "
"packet32[-4b] == 0x34353637 && packet32[-5b] == 0x33343536",
&pkt_echo_request, TRUE},
+ {"random8 < 10", &pkt_echo_request, TRUE},
+ {"random16 >= 2222", &pkt_echo_request, TRUE},
+ {"random32 <= 0x80000000", &pkt_echo_request, TRUE},
+ {"(random8 < 128? icmp: udp)", &pkt_echo_request, TRUE},
+ {"(random8 <= 128? "
+ "(random16 <= 0x8000?"
+ "(random32 <= 0x80000000? ip: ipv6): "
+ "(random32 <= 0x80000000? icmpv6: icmp)): "
+ "(random16 <= 0x8000?"
+ "(random32 <= 0x80000000? tcp: icmp.Type >= 8): "
+ "(random32 <= 0x80000000? outbound: loopback)))",
+ &pkt_echo_request, TRUE},
{"outbound and icmp", &pkt_echo_request, TRUE},
{"outbound", &pkt_echo_request, TRUE},
{"outbound and inbound", &pkt_echo_request, FALSE},
@@ -329,6 +341,11 @@ static struct test tests[] =
"packet[-1] = 0x0a", &pkt_http_request, TRUE},
{"tcp.Payload16[-1] == 0x0d0a", &pkt_http_request, TRUE},
{"tcp.Payload32[-2] == 0x20474d54", &pkt_http_request, TRUE},
+ {"random8 < 128", &pkt_http_request, TRUE},
+ {"(random8 < 128? random16 < 0x8000: random32 < 0x80000000)",
+ &pkt_http_request, TRUE},
+ {"(random32 < 0x22223333? packet32[72] == 0x58585858: udp)",
+ &pkt_http_request, TRUE},
{"udp", &pkt_dns_request, TRUE},
{"udp && udp.SrcPort > 1 && ipv6", &pkt_dns_request, FALSE},
{"udp.DstPort == 53", &pkt_dns_request, TRUE},
@@ -348,6 +365,11 @@ static struct test tests[] =
&pkt_dns_request, TRUE},
{"packet16[-1] == 0x0001 && packet16[-2] == 0x0001",
&pkt_dns_request, TRUE},
+ {"tcp.Payload32[0] > 0", &pkt_dns_request, FALSE},
+ {"udp.Payload32[1] > 0", &pkt_dns_request, TRUE},
+ {"random8 < 128", &pkt_dns_request, TRUE},
+ {"(random8 < 128? random16 < 0x8000: random32 < 0x80000000)",
+ &pkt_dns_request, TRUE},
{"ipv6", &pkt_ipv6_tcp_syn, TRUE},
{"ip", &pkt_ipv6_tcp_syn, FALSE},
{"tcp.Syn", &pkt_ipv6_tcp_syn, TRUE},
@@ -361,6 +383,15 @@ static struct test tests[] =
{"ipv6.SrcAddr == aabb:5678:1::1234:ccdd", &pkt_ipv6_tcp_syn, FALSE},
{"tcp.SrcPort == 50046", &pkt_ipv6_tcp_syn, TRUE},
{"tcp.SrcPort == 0x0000C37E", &pkt_ipv6_tcp_syn, TRUE},
+ {"packet32[0b] == 0x60000000 && packet32[1b] == 0x00000000 && "
+ "packet32[2b] == 0x00000028 && packet32[3b] == 0x00002806 && "
+ "packet32[4b] == 0x00280640 && packet32[5b] == 0x28064012 && "
+ "packet32[-4b] == 0x01030307 && packet32[-5b] == 0x00010303",
+ &pkt_ipv6_tcp_syn, TRUE},
+ {"tcp.Payload32[0] > 0", &pkt_ipv6_tcp_syn, FALSE},
+ {"random8 < 128", &pkt_ipv6_tcp_syn, TRUE},
+ {"(random8 < 128? random16 < 0x8000: random32 < 0x80000000)",
+ &pkt_ipv6_tcp_syn, TRUE},
{"icmpv6", &pkt_ipv6_echo_reply, TRUE},
{"icmp", &pkt_ipv6_echo_reply, FALSE},
{"icmp or icmpv6", &pkt_ipv6_echo_reply, TRUE},
@@ -370,6 +401,9 @@ static struct test tests[] =
{"icmpv6.Body == 0x10720003", &pkt_ipv6_echo_reply, TRUE},
{"ipv6.DstAddr >= 1000", &pkt_ipv6_echo_reply, FALSE},
{"ipv6.DstAddr <= 1", &pkt_ipv6_echo_reply, TRUE},
+ {"random8 < 128", &pkt_ipv6_echo_reply, TRUE},
+ {"(random8 < 128? random16 < 0x8000: random32 < 0x80000000)",
+ &pkt_ipv6_echo_reply, TRUE},
{"true", &pkt_ipv6_exthdrs_udp, TRUE},
{"false", &pkt_ipv6_exthdrs_udp, FALSE},
{"udp", &pkt_ipv6_exthdrs_udp, TRUE},
@@ -392,6 +426,14 @@ static struct test tests[] =
"(inbound and tcp? tcp.SrcPort == 0xABAB: false) or "
"(inbound and udp? udp.SrcPort == 0xAAAA: false)",
&pkt_ipv6_exthdrs_udp, TRUE},
+ {"(tcp or udp) and (ip or ipv6) and (icmp or !icmpv6) and "
+ "(tcp.Payload16[-1] == 0x1234 or udp.Payload16[-1] == 0x2101)",
+ &pkt_ipv6_exthdrs_udp, TRUE},
+ {"(tcp or icmp or icmpv6 or ip or !udp or ipv6? udp.PayloadLength > 0: "
+ "udp.DstPort == 39482)", &pkt_ipv6_exthdrs_udp, TRUE},
+ {"random8 < 128", &pkt_ipv6_exthdrs_udp, TRUE},
+ {"(random8 < 128? random16 < 0x8000: random32 < 0x80000000)",
+ &pkt_ipv6_exthdrs_udp, TRUE},
};
/*
@@ -401,14 +443,16 @@ int main(void)
{
HANDLE upper_handle, lower_handle;
HANDLE console;
+ LARGE_INTEGER freq;
+ UINT64 diff;
size_t i;
// Open handles to:
// (1) stop normal traffic from interacting with the tests; and
// (2) stop test packets escaping to the Internet or TCP/IP stack.
- upper_handle = WinDivertOpen("true", WINDIVERT_LAYER_NETWORK, -510,
+ upper_handle = WinDivertOpen("true", WINDIVERT_LAYER_NETWORK, -999,
WINDIVERT_FLAG_DROP);
- lower_handle = WinDivertOpen("true", WINDIVERT_LAYER_NETWORK, 510,
+ lower_handle = WinDivertOpen("true", WINDIVERT_LAYER_NETWORK, 999,
WINDIVERT_FLAG_DROP);
if (upper_handle == INVALID_HANDLE_VALUE ||
lower_handle == INVALID_HANDLE_VALUE)
@@ -419,26 +463,25 @@ int main(void)
}
console = GetStdHandle(STD_OUTPUT_HANDLE);
+ QueryPerformanceFrequency(&freq);
// Wait for existing packets to flush:
- Sleep(100);
+ Sleep(150);
// Run tests:
size_t num_tests = sizeof(tests) / sizeof(struct test), passed_tests = 0;
for (i = 0; i < num_tests; i++)
{
- char *filter = tests[i].filter;
- char *packet = tests[i].packet->packet;
+ const char *filter = tests[i].filter;
+ const char *packet = tests[i].packet->packet;
size_t packet_len = tests[i].packet->packet_len;
char *name = tests[i].packet->name;
BOOL match = tests[i].match;
- // Ensure the correct checksum:
- WinDivertHelperCalcChecksums(packet, packet_len, NULL, 0);
-
// Run the test:
- BOOL res = run_test(upper_handle, filter, packet, packet_len, match);
-
+ BOOL res = run_test(upper_handle, filter, packet, packet_len, match,
+ &diff);
+ diff = 1000000 * diff / freq.QuadPart;
printf("%.3u ", i);
if (res)
{
@@ -453,7 +496,7 @@ int main(void)
}
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN |
FOREGROUND_BLUE);
- printf(" p=[");
+ printf(" %.5llu p=[", diff);
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
printf("%s", name);
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN |
@@ -479,66 +522,82 @@ int main(void)
* Run a test case.
*/
static BOOL run_test(HANDLE inject_handle, const char *filter,
- const char *packet, const size_t packet_len, BOOL match)
+ const char *packet, const size_t packet_len, BOOL match, INT64 *diff)
{
- char buf[MAX_PACKET];
- UINT buf_len, i;
+ static char object[8192];
+ char buf[2][MAX_PACKET];
+ UINT buf_len[2], i, idx;
DWORD iolen;
- WINDIVERT_ADDRESS addr;
- OVERLAPPED overlapped;
+ WINDIVERT_ADDRESS addr[2], addr_send;
+ OVERLAPPED overlapped[2];
const char *err_str;
UINT err_pos;
PWINDIVERT_IPHDR iphdr = NULL;
- HANDLE handle = INVALID_HANDLE_VALUE, handle0 = INVALID_HANDLE_VALUE,
- event = NULL;
+ HANDLE handle[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
+ HANDLE event[2] = {NULL, NULL};
+ BOOL random, result, ipv4;
+ LARGE_INTEGER end;
+
+ *diff = 0;
// (0) Verify the test data:
if (!WinDivertHelperCompileFilter(filter, WINDIVERT_LAYER_NETWORK,
- NULL, 0, &err_str, &err_pos))
+ object, sizeof(object), &err_str, &err_pos))
{
fprintf(stderr, "error: filter string \"%s\" is invalid with error "
"\"%s\" (position=%u)\n", filter, err_str, err_pos);
goto failed;
}
- WinDivertHelperParsePacket((PVOID)packet, packet_len, &iphdr, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL);
- memset(&addr, 0, sizeof(addr));
- addr.Outbound = TRUE;
- addr.Layer = WINDIVERT_LAYER_NETWORK;
- addr.IPv6 = (iphdr == NULL);
- addr.Event = WINDIVERT_EVENT_NETWORK_PACKET;
- if (WinDivertHelperEvalFilter(filter, (PVOID)packet, packet_len, &addr)
- != match)
- {
- fprintf(stderr, "error: filter \"%s\" does not match the given "
- "packet\n", filter);
- goto failed;
- }
- // (1) Open a WinDivert handle to the given filter:
- handle = WinDivertOpen(filter, WINDIVERT_LAYER_NETWORK, 0, 0);
- if (handle == INVALID_HANDLE_VALUE)
+ // (1) Open WinDivert handles:
+ handle[0] = WinDivertOpen(object, WINDIVERT_LAYER_NETWORK, 777, 0);
+ if (handle[0] == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "error: failed to open WinDivert handle for filter "
"\"%s\" (err = %d)\n", filter, GetLastError());
goto failed;
}
-
- if (!match)
+ handle[1] = WinDivertOpen("true", WINDIVERT_LAYER_NETWORK, 888, 0);
+ if (handle[1] == INVALID_HANDLE_VALUE)
{
- // Catch non-matching packets:
- handle0 = handle;
- handle = WinDivertOpen("true", WINDIVERT_LAYER_NETWORK, 33, 0);
- if (handle == INVALID_HANDLE_VALUE)
- {
- fprintf(stderr, "error: failed to open WinDivert handle "
- "(err = %d)\n", GetLastError());
- goto failed;
- }
+ fprintf(stderr, "error: failed to open WinDivert handle "
+ "(err = %d)\n", GetLastError());
+ goto failed;
+ }
+
+ // (2) Create pended recv requests:
+ event[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
+ event[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (event[0] == NULL || event[1] == NULL)
+ {
+ fprintf(stderr, "error: failed to create event (err = %d)\n",
+ GetLastError());
+ goto failed;
+ }
+ memset(&overlapped[0], 0, sizeof(overlapped[0]));
+ memset(&overlapped[1], 0, sizeof(overlapped[1]));
+ overlapped[0].hEvent = event[0];
+ overlapped[1].hEvent = event[1];
+ if (WinDivertRecvEx(handle[0], buf[0], sizeof(buf[0]), &buf_len[0], 0,
+ &addr[0], NULL, &overlapped[0]) ||
+ GetLastError() != ERROR_IO_PENDING ||
+ WinDivertRecvEx(handle[1], buf[1], sizeof(buf[1]), &buf_len[1], 0,
+ &addr[1], NULL, &overlapped[1]) ||
+ GetLastError() != ERROR_IO_PENDING)
+ {
+ fprintf(stderr, "error: failed to created pended recv from WinDivert "
+ "handle (err = %d)\n", GetLastError());
+ goto failed;
}
// (2) Inject the packet:
- if (!WinDivertSend(inject_handle, (PVOID)packet, packet_len, &addr, NULL))
+ memset(&addr_send, 0, sizeof(addr_send));
+ addr_send.Outbound = TRUE;
+ addr_send.PseudoIPChecksum = TRUE;
+ addr_send.PseudoTCPChecksum = TRUE;
+ addr_send.PseudoUDPChecksum = TRUE;
+ if (!WinDivertSend(inject_handle, (PVOID)packet, packet_len, &addr_send,
+ NULL))
{
fprintf(stderr, "error: failed to inject test packet (err = %d)\n",
GetLastError());
@@ -547,108 +606,111 @@ static BOOL run_test(HANDLE inject_handle, const char *filter,
// (3) Wait for the packet to arrive.
// NOTE: This may fail, so set a generous time-out of 250ms.
- memset(&overlapped, 0, sizeof(overlapped));
- event = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (event == NULL)
+ switch (WaitForMultipleObjects(2, event, FALSE, 250))
{
- fprintf(stderr, "error: failed to create event (err = %d)\n",
- GetLastError());
+ case WAIT_OBJECT_0:
+ QueryPerformanceCounter(&end);
+ result = TRUE;
+ idx = 0;
+ break;
+ case WAIT_OBJECT_0+1:
+ QueryPerformanceCounter(&end);
+ result = FALSE;
+ idx = 1;
+ break;
+ case WAIT_TIMEOUT:
+ fprintf(stderr, "error: failed to read packet from WinDivert "
+ "handle (timeout)\n", GetLastError());
+ goto failed;
+ default:
+ fprintf(stderr, "error: failed to wait for packet (err = %d)\n",
+ GetLastError());
+ goto failed;
+ }
+ if (!GetOverlappedResult(handle[idx], &overlapped[idx], &iolen, TRUE))
+ {
+ fprintf(stderr, "error: failed to get the overlapped result from "
+ "WinDivert handle (err = %d)\n", GetLastError());
goto failed;
}
- overlapped.hEvent = event;
- if (!WinDivertRecvEx(handle, buf, sizeof(buf), &buf_len, 0, &addr, NULL,
- &overlapped))
- {
- if (GetLastError() != ERROR_IO_PENDING)
- {
-read_failed:
- fprintf(stderr, "error: failed to read packet from WinDivert "
- "handle (err = %d)\n", GetLastError());
- goto failed;
- }
+ buf_len[idx] = (UINT)iolen;
+ *diff = end.QuadPart - addr[idx].Timestamp;
- switch (WaitForSingleObject(event, 250))
- {
- case WAIT_OBJECT_0:
- break;
- case WAIT_TIMEOUT:
- fprintf(stderr, "error: failed to read packet from WinDivert "
- "handle (timeout)\n", GetLastError());
- goto failed;
- default:
- goto read_failed;
- }
-
- if (!GetOverlappedResult(handle, &overlapped, &iolen, TRUE))
- {
- fprintf(stderr, "error: failed to get the overlapped result from "
- "WinDivert handle (err = %d)\n", GetLastError());
- goto failed;
- }
- buf_len = (UINT)iolen;
- }
- if (addr.Outbound)
- {
- WinDivertHelperCalcChecksums(buf, buf_len, NULL, 0);
- }
-
- // (4) Verify that the packet is the same.
- if (buf_len != packet_len)
+ // (4) Verify that the packet is the same & matches.
+ if (buf_len[idx] != packet_len)
{
fprintf(stderr, "error: packet length mis-match, expected (%u), got "
- "(%u)\n", packet_len, buf_len);
+ "(%u)\n", packet_len, buf_len[idx]);
goto failed;
}
+ iphdr = (PWINDIVERT_IPHDR)buf[idx];
+ ipv4 = (iphdr->Version == 4);
for (i = 0; i < packet_len; i++)
{
- if (packet[i] != buf[i])
+ if (ipv4 && i >= offsetof(WINDIVERT_IPHDR, Checksum) &&
+ i < offsetof(WINDIVERT_IPHDR, Checksum) + sizeof(UINT16))
+ {
+ // The IPv4 checksum can change, so ignore it.
+ continue;
+ }
+ if (packet[i] != buf[idx][i])
{
fprintf(stderr, "error: packet data mis-match, expected byte #%u "
"to be (0x%.2X), got (0x%.2X)\n", i, (unsigned char)packet[i],
- (unsigned char)buf[i]);
+ (unsigned char)buf[idx][i]);
for (i = 0; i < packet_len; i++)
{
- printf("%c", (packet[i] == buf[i]? '.': 'X'));
+ printf("%c", (packet[i] == buf[idx][i]? '.': 'X'));
}
putchar('\n');
goto failed;
}
}
+ random = (strstr(filter, "random") != 0);
+ // If (random && !result), then we cannot verify since the original
+ // non-matching random values have been lost:
+ if ((!random &&
+ WinDivertHelperEvalFilter(filter, buf[idx], buf_len[idx],
+ &addr[idx]) != result) ||
+ (random && result &&
+ !WinDivertHelperEvalFilter(filter, buf[idx], buf_len[idx],
+ &addr[idx])))
+ {
+ fprintf(stderr, "error: filter \"%s\" does not match the given "
+ "packet\n", filter);
+ goto failed;
+ }
+ if (!random && result != match)
+ {
+ fprintf(stderr, "error: filter \"%s\" does not match the expected "
+ "result\n", filter);
+ goto failed;
+ }
+
// (5) Clean-up:
- if (!WinDivertClose(handle))
+ if (!WinDivertClose(handle[0]) || !WinDivertClose(handle[1]))
{
- handle = INVALID_HANDLE_VALUE;
fprintf(stderr, "error: failed to close WinDivert handle (err = %d)\n",
GetLastError());
goto failed;
}
- if (handle0 != INVALID_HANDLE_VALUE)
- {
- if (!WinDivertClose(handle0))
- {
- handle0 = INVALID_HANDLE_VALUE;
- fprintf(stderr, "error: failed to close WinDivert handle "
- "(err = %d)\n", GetLastError());
- goto failed;
- }
- }
- CloseHandle(event);
+ CloseHandle(event[0]);
+ CloseHandle(event[1]);
return TRUE;
failed:
- if (handle0 != INVALID_HANDLE_VALUE)
+ for (i = 0; i < 2; i++)
{
- WinDivertClose(handle0);
- }
- if (handle != INVALID_HANDLE_VALUE)
- {
- WinDivertClose(handle);
- }
- if (event != NULL)
- {
- CloseHandle(event);
+ if (handle[i] != INVALID_HANDLE_VALUE)
+ {
+ WinDivertClose(handle[i]);
+ }
+ if (event[i] != NULL)
+ {
+ CloseHandle(event[i]);
+ }
}
return FALSE;
}
diff --git a/test/test_data.c b/test/test_data.c
index 94fa1f0..e1a33b7 100644
--- a/test/test_data.c
+++ b/test/test_data.c
@@ -33,11 +33,11 @@
*/
// IPV4 ICMP ECHO REQUEST
-static unsigned char echo_request[] =
+static const unsigned char echo_request[] =
{
0x45, 0x00, 0x00, 0x54, 0x12, 0x34, 0x40, 0x00,
0x40, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01,
- 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x3c, 0xd2,
0x0d, 0x56, 0x00, 0x01, 0x8b, 0xa6, 0x60, 0x54,
0x00, 0x00, 0x00, 0x00, 0xf9, 0x08, 0x0a, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13,
@@ -49,13 +49,13 @@ static unsigned char echo_request[] =
};
// IPV4 TCP HTTP GET REQUEST
-static unsigned char http_request[] =
+static const unsigned char http_request[] =
{
0x45, 0x00, 0x02, 0x09, 0x48, 0x2d, 0x40, 0x00,
0x40, 0x06, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a,
0x5d, 0xb8, 0xd8, 0x77, 0xa3, 0x1a, 0x00, 0x50,
0x53, 0x38, 0xcc, 0xc2, 0x56, 0x37, 0xb3, 0x55,
- 0x80, 0x18, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x18, 0x00, 0x73, 0x02, 0xa4, 0x00, 0x00,
0x01, 0x01, 0x08, 0x0a, 0x00, 0x2c, 0x85, 0x1b,
0x1b, 0x7f, 0x3a, 0x71, 0x47, 0x45, 0x54, 0x20,
0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31,
@@ -120,12 +120,12 @@ static unsigned char http_request[] =
};
// IPV4 DNS REQUEST
-static unsigned char dns_request[] =
+static const unsigned char dns_request[] =
{
0x45, 0x00, 0x00, 0x39, 0x20, 0x90, 0x00, 0x00,
0x49, 0x11, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01,
0x08, 0x08, 0x04, 0x04, 0xe0, 0x45, 0x00, 0x35,
- 0x00, 0x25, 0x00, 0x00, 0x17, 0x08, 0x01, 0x00,
+ 0x00, 0x25, 0x22, 0xa7, 0x17, 0x08, 0x01, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00,
@@ -133,7 +133,7 @@ static unsigned char dns_request[] =
};
// IPV6 TCP SYN
-static unsigned char ipv6_tcp_syn[] =
+static const unsigned char ipv6_tcp_syn[] =
{
0x60, 0x00, 0x00, 0x00, 0x00, 0x28, 0x06, 0x40,
0x12, 0x34, 0x56, 0x78, 0x00, 0x01, 0x00, 0x00,
@@ -142,20 +142,20 @@ static unsigned char ipv6_tcp_syn[] =
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0xc3, 0x7e, 0x00, 0x17, 0xe1, 0xd7, 0xc8, 0xaa,
0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xaa, 0xaa,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0xff, 0xc4,
+ 0xc3, 0x5e, 0x00, 0x00, 0x02, 0x04, 0xff, 0xc4,
0x04, 0x02, 0x08, 0x0a, 0xff, 0xff, 0x91, 0x86,
0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07
};
// IPV6 ICMPV6 ECHO REPLY
-static unsigned char ipv6_echo_reply[] =
+static const unsigned char ipv6_echo_reply[] =
{
0x60, 0x00, 0x00, 0x00, 0x00, 0x40, 0x3a, 0x1f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x81, 0x00, 0x00, 0x00, 0x10, 0x72, 0x00, 0x03,
+ 0x81, 0x00, 0x6e, 0xd6, 0x10, 0x72, 0x00, 0x03,
0xa4, 0xd5, 0x69, 0x54, 0x00, 0x00, 0x00, 0x00,
0xab, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
@@ -166,7 +166,7 @@ static unsigned char ipv6_echo_reply[] =
};
// IPV6 EXTENSION HEADERS UDP
-static unsigned char ipv6_exthdrs_udp[] =
+static const unsigned char ipv6_exthdrs_udp[] =
{
0x60, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x64,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -176,7 +176,7 @@ static unsigned char ipv6_exthdrs_udp[] =
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x12, 0x34, 0xaa, 0xaa, 0x00, 0x15, 0x00, 0x00,
+ 0x12, 0x34, 0xaa, 0xaa, 0x00, 0x15, 0xef, 0xf4,
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f,
0x72, 0x6c, 0x64, 0x21, 0x01
};