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/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..72e8bfa 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);
@@ -76,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.
*/
@@ -113,19 +79,16 @@ typedef struct
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);
-#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"
/*
@@ -337,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;
@@ -357,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 ||
@@ -376,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)
{
- struct windivert_ioctl_s ioctl;
+ 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)
@@ -402,39 +363,48 @@ 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 (!WINDIVERT_FLAGS_VALID(flags) || layer > WINDIVERT_LAYER_MAX)
+ switch (layer)
{
- SetLastError(ERROR_INVALID_PARAMETER);
- return INVALID_HANDLE_VALUE;
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ case WINDIVERT_LAYER_FLOW:
+ case WINDIVERT_LAYER_SOCKET:
+ case WINDIVERT_LAYER_REFLECT:
+ break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return INVALID_HANDLE_VALUE;
}
- priority32 = WINDIVERT_PRIORITY(priority);
- if (priority32 < WINDIVERT_PRIORITY_MIN ||
- priority32 > WINDIVERT_PRIORITY_MAX)
+ if (!WINDIVERT_FLAGS_VALID(flags))
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
- // Compile the filter:
+ if (priority < WINDIVERT_PRIORITY_MIN ||
+ priority > WINDIVERT_PRIORITY_MAX)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ // 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(layer, object, obj_len);
// Attempt to open the WinDivert device:
handle = CreateFile(L"\\\\.\\" WINDIVERT_DEVICE_NAME,
@@ -449,6 +419,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)
@@ -477,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;
@@ -488,8 +463,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, flags, 0,
+ NULL, 0, NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
@@ -497,10 +472,12 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
}
// Set the priority:
- if (priority32 != WINDIVERT_PRIORITY_DEFAULT)
+ if (priority != WINDIVERT_PRIORITY_DEFAULT)
{
- if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_PRIORITY, 0,
- (UINT64)priority32, NULL, 0, NULL))
+ // Make positive:
+ priority64 = (UINT64)((INT64)priority + WINDIVERT_PRIORITY_MAX);
+ if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_PRIORITY,
+ priority64, 0, NULL, 0, NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
@@ -508,8 +485,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,
+ filter_flags, 0, object, obj_len * sizeof(WINDIVERT_FILTER), NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
@@ -519,56 +496,21 @@ 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.
*/
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)
@@ -578,57 +520,62 @@ 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);
}
}
/*
* 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)
{
- if (addr == NULL)
- {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- WinDivertFixChecksums(pPacket, packetLen, addr);
- return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND, 0, (UINT64)addr,
- pPacket, packetLen, writelen);
+ return WinDivertIoControl(handle, IOCTL_WINDIVERT_SEND, (UINT64)addr,
+ sizeof(WINDIVERT_ADDRESS), (PVOID)pPacket, packetLen, writelen);
}
/*
* Send a WinDivert packet.
*/
-extern BOOL WinDivertSendEx(HANDLE handle, PVOID pPacket, UINT packetLen,
- UINT64 flags, PWINDIVERT_ADDRESS addr, UINT *writelen,
+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 || addr == NULL)
+ if (flags != 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
- WinDivertFixChecksums(pPacket, packetLen, addr);
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, (PVOID)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, (PVOID)pPacket, packetLen, writeLen,
+ overlapped);
}
}
+/*
+ * 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.
*/
@@ -841,253 +788,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..aa30104 100644
--- a/dll/windivert.def
+++ b/dll/windivert.def
@@ -6,12 +6,25 @@ EXPORTS
WinDivertRecvEx
WinDivertSend
WinDivertSendEx
+ WinDivertShutdown
WinDivertClose
WinDivertSetParam
WinDivertGetParam
WinDivertHelperCalcChecksums
+ WinDivertHelperHashPacket
WinDivertHelperParsePacket
WinDivertHelperParseIPv4Address
WinDivertHelperParseIPv6Address
- WinDivertHelperCheckFilter
+ WinDivertHelperFormatIPv4Address
+ WinDivertHelperFormatIPv6Address
+ WinDivertHelperCompileFilter
WinDivertHelperEvalFilter
+ WinDivertHelperFormatFilter
+ WinDivertHelperNtohs
+ WinDivertHelperHtons
+ WinDivertHelperNtohl
+ WinDivertHelperHtonl
+ WinDivertHelperNtohll
+ WinDivertHelperHtonll
+ WinDivertHelperNtohIpv6Address
+ WinDivertHelperHtonIpv6Address
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 917c803..678a15d 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,8 +109,19 @@ 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_RANDOM8,
+ TOKEN_RANDOM16,
+ TOKEN_RANDOM32,
+ TOKEN_PACKET,
+ TOKEN_PACKET16,
+ TOKEN_PACKET32,
TOKEN_TRUE,
TOKEN_FALSE,
TOKEN_INBOUND,
@@ -116,8 +130,33 @@ 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_LAYER,
+ TOKEN_FLOW,
+ TOKEN_SOCKET,
+ TOKEN_NETWORK,
+ TOKEN_NETWORK_FORWARD,
+ TOKEN_REFLECT,
+ 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_SQUARE_OPEN,
+ TOKEN_SQUARE_CLOSE,
+ TOKEN_MINUS,
+ TOKEN_BYTES,
TOKEN_EQ,
TOKEN_NEQ,
TOKEN_LT,
@@ -139,13 +178,51 @@ 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 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)
+#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.
@@ -160,6 +237,7 @@ struct EXPR
PEXPR arg[3];
};
UINT8 kind;
+ UINT8 count;
UINT16 succ;
UINT16 fail;
};
@@ -168,7 +246,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
@@ -177,8 +255,10 @@ typedef UINT64 ERROR;
#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_ASSERTION_FAILED 8
+#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));
@@ -190,427 +270,29 @@ typedef UINT64 ERROR;
#define IS_ERROR(err) \
(GET_CODE(err) != WINDIVERT_ERROR_NONE)
-#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 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);
-
-/*
- * 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;
- }
-}
+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 BOOL WinDivertDeserializeFilter(PWINDIVERT_STREAM stream,
+ PWINDIVERT_FILTER filter, UINT *length);
+static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
+ WINDIVERT_LAYER layer, BOOL top_level, BOOL and);
/*
* 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)
{
- 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;
- 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 (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;
-
- WinDivertHelperParsePacket(pPacket, packetLen, &ip_header, &ipv6_header,
- &icmp_header, &icmpv6_header, &tcp_header, &udp_header, 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->Direction == WINDIVERT_DIRECTION_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->Direction == WINDIVERT_DIRECTION_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((PVOID)pPacket, packetLen, ppIpHdr, ppIpv6Hdr,
+ ppIcmpHdr, ppIcmpv6Hdr, ppTcpHdr, ppUdpHdr, NULL, ppData, pDataLen);
}
/*
@@ -658,15 +340,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++;
@@ -677,9 +359,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 == ':')
{
@@ -690,6 +376,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++)
{
@@ -718,11 +416,7 @@ extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr)
}
if (*str == '\0')
{
- if (!left)
- {
- break;
- }
- if (k == 7)
+ if (!left || k == 7)
{
break;
}
@@ -731,44 +425,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[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;
@@ -779,86 +484,176 @@ static PTOKEN_NAME WinDivertTokenLookup(PTOKEN_NAME token_names,
}
else
{
- return &token_names[mid];
+ return &token_info[mid];
}
}
return NULL;
}
+/*
+ * Expand a "macro" value.
+ */
+static BOOL WinDivertExpandMacro(KIND kind, WINDIVERT_LAYER layer,
+ 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_SOCKET:
+ *val = WINDIVERT_LAYER_SOCKET;
+ return TRUE;
+ case TOKEN_REFLECT:
+ *val = WINDIVERT_LAYER_REFLECT;
+ return TRUE;
+ case TOKEN_EVENT_PACKET:
+ *val = WINDIVERT_EVENT_NETWORK_PACKET;
+ return (layer == WINDIVERT_LAYER_NETWORK);
+ case TOKEN_EVENT_ESTABLISHED:
+ *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_SOCKET);
+ case TOKEN_EVENT_CONNECT:
+ *val = WINDIVERT_EVENT_SOCKET_CONNECT;
+ return (layer == WINDIVERT_LAYER_SOCKET);
+ case TOKEN_EVENT_LISTEN:
+ *val = WINDIVERT_EVENT_SOCKET_LISTEN;
+ return (layer == WINDIVERT_LAYER_SOCKET);
+ case TOKEN_EVENT_ACCEPT:
+ *val = WINDIVERT_EVENT_SOCKET_ACCEPT;
+ return (layer == WINDIVERT_LAYER_SOCKET);
+ case TOKEN_EVENT_OPEN:
+ *val = WINDIVERT_EVENT_REFLECT_OPEN;
+ return (layer == WINDIVERT_LAYER_REFLECT);
+ case TOKEN_EVENT_CLOSE:
+ *val = WINDIVERT_EVENT_REFLECT_CLOSE;
+ return (layer == WINDIVERT_LAYER_REFLECT);
+ default:
+ return FALSE;
+ }
+}
+
/*
* Tokenize the given filter string.
*/
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[] =
{
- {"and", TOKEN_AND},
- {"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},
- {"loopback", TOKEN_LOOPBACK},
- {"not", TOKEN_NOT},
- {"or", TOKEN_OR},
- {"outbound", TOKEN_OUTBOUND},
- {"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},
+ {"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},
+ {"LISTEN", TOKEN_EVENT_LISTEN, L___S_},
+ {"NETWORK", TOKEN_NETWORK, L____R},
+ {"NETWORK_FORWARD", TOKEN_NETWORK_FORWARD, L____R},
+ {"OPEN", TOKEN_EVENT_OPEN, L____R},
+ {"PACKET", TOKEN_EVENT_PACKET, LNM___},
+ {"REFLECT", TOKEN_REFLECT, L____R},
+ {"SOCKET", TOKEN_SOCKET, L____R},
+ {"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__},
+ {"packet", TOKEN_PACKET, LNM___},
+ {"packet16", TOKEN_PACKET16, LNM___},
+ {"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___},
+ {"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.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___},
+ {"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.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},
};
- TOKEN_NAME *result;
+ TOKEN_INFO *result;
char c;
char token[TOKEN_MAXLEN];
UINT i = 0, j;
@@ -888,6 +683,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] == '=')
{
@@ -956,12 +760,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];
}
@@ -982,38 +787,48 @@ 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)
{
- switch (layer)
+ if ((result->flags & (1 << layer)) == 0)
{
- 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);
+ }
+ if (WinDivertExpandMacro(result->kind, layer,
+ &tokens[tp].val[0]))
+ {
+ tokens[tp].kind = TOKEN_NUMBER;
+ }
+ else
+ {
+ tokens[tp].kind = result->kind;
}
- tokens[tp++].kind = result->kind;
- continue;
- }
-
- // Check for base 10 number:
- if (WinDivertAToI(token, &end, &num) && *end == '\0')
- {
- tokens[tp].kind = TOKEN_NUMBER;
- tokens[tp].val[0] = num;
tp++;
continue;
}
+ // Check for base 10 number:
+ if (WinDivertAToI(token, &end, &num))
+ {
+ 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;
@@ -1023,6 +838,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 +848,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;
@@ -1056,26 +862,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[] =
@@ -1133,6 +923,11 @@ 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_EVENT},
+ {{{0}}, TOKEN_RANDOM8},
+ {{{0}}, TOKEN_RANDOM16},
+ {{{0}}, TOKEN_RANDOM32},
{{{0}}, TOKEN_TRUE},
{{{0}}, TOKEN_FALSE},
{{{0}}, TOKEN_INBOUND},
@@ -1140,7 +935,14 @@ 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},
+ {{{0}}, TOKEN_LAYER},
};
// Binary search:
@@ -1160,14 +962,31 @@ 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 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.
*/
-static PEXPR WinDivertMakeZero(PPOOL pool)
+static PEXPR WinDivertMakeZero(void)
{
static const EXPR zero = {{{0, 0, 0, 0}}, TOKEN_NUMBER};
return (PEXPR)&zero;
@@ -1176,44 +995,43 @@ 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)
+ if (val[0] == 0 && val[1] == 0 && val[2] == 0 && val[3] == 0)
{
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_ASSERTION_FAILED, 0);
- return NULL;
+ return WinDivertMakeZero();
}
- 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;
@@ -1223,15 +1041,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;
@@ -1242,11 +1060,12 @@ 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;
- BOOL not = FALSE;
+ BOOL not = FALSE, neg;
+ UINT idx, size;
while (toks[*i].kind == TOKEN_NOT)
{
not = !not;
@@ -1254,6 +1073,11 @@ static PEXPR WinDivertParseTest(PPOOL pool, TOKEN *toks, UINT *i)
}
switch (toks[*i].kind)
{
+ case TOKEN_ZERO:
+ case TOKEN_EVENT:
+ case TOKEN_RANDOM8:
+ case TOKEN_RANDOM16:
+ case TOKEN_RANDOM32:
case TOKEN_TRUE:
case TOKEN_FALSE:
case TOKEN_OUTBOUND:
@@ -1268,6 +1092,13 @@ 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_LAYER:
case TOKEN_IP_HDR_LENGTH:
case TOKEN_IP_TOS:
case TOKEN_IP_LENGTH:
@@ -1315,14 +1146,80 @@ static PEXPR WinDivertParseTest(PPOOL pool, TOKEN *toks, UINT *i)
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:
- pool->error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN,
- toks[*i].pos);
+ unexpected_token:
+ *error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, toks[*i].pos);
return NULL;
}
- var = WinDivertMakeVar(pool, toks[*i].kind);
- *i = *i + 1;
switch (toks[*i].kind)
{
case TOKEN_EQ:
@@ -1335,7 +1232,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)
{
@@ -1366,31 +1263,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;
@@ -1399,57 +1296,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)
@@ -1460,13 +1356,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;
@@ -1487,12 +1383,21 @@ 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_EVENT:
+ lb = 0; ub = WINDIVERT_EVENT_MAX;
+ break;
case TOKEN_INBOUND:
case TOKEN_OUTBOUND:
case TOKEN_IP:
@@ -1524,6 +1429,11 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
case TOKEN_ICMP_CODE:
case TOKEN_ICMPV6_TYPE:
case TOKEN_ICMPV6_CODE:
+ case TOKEN_PROTOCOL:
+ case TOKEN_PACKET:
+ case TOKEN_TCP_PAYLOAD:
+ case TOKEN_UDP_PAYLOAD:
+ case TOKEN_RANDOM8:
lb = 0; ub = 0xFF;
break;
case TOKEN_IP_FRAG_OFF:
@@ -1547,13 +1457,23 @@ 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:
+ case TOKEN_PACKET16:
+ case TOKEN_TCP_PAYLOAD16:
+ case TOKEN_UDP_PAYLOAD16:
+ case TOKEN_RANDOM16:
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;
@@ -1689,8 +1609,9 @@ 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)
{
+ BOOL big;
PEXPR var = test->arg[0], val = test->arg[1];
switch (test->kind)
{
@@ -1715,8 +1636,61 @@ 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:
+ object->field = WINDIVERT_FILTER_FIELD_ZERO;
+ break;
+ 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];
+ 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;
@@ -1735,6 +1709,29 @@ 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;
+ 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;
+ break;
+ 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;
@@ -1785,9 +1782,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;
@@ -1806,9 +1805,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;
@@ -1898,9 +1899,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:
@@ -1928,7 +1932,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)
@@ -1936,12 +1940,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:
@@ -1954,50 +1957,261 @@ static void WinDivertEmitFilter(PEXPR *stack, UINT len, UINT16 label,
}
}
+/*
+ * Analyze a filter object.
+ */
+static UINT64 WinDivertAnalyzeFilter(WINDIVERT_LAYER layer,
+ PWINDIVERT_FILTER filter, UINT length)
+{
+ BOOL result;
+ UINT64 flags = 0;
+
+ // False filter?
+ result = WinDivertCondExecFilter(filter, length,
+ WINDIVERT_FILTER_FIELD_ZERO, 0);
+ if (!result)
+ {
+ return 0;
+ }
+
+ if (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_NETWORK_FORWARD)
+ {
+ // 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);
+ }
+
+ if (layer != WINDIVERT_LAYER_REFLECT)
+ {
+ // 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);
+ }
+
+ // 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;
+ }
+
+ 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);
}
@@ -2007,7 +2221,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);
}
@@ -2016,7 +2230,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);
}
@@ -2042,8 +2256,12 @@ 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:
+ return "Filter object is invalid";
case WINDIVERT_ERROR_ASSERTION_FAILED:
return "Internal assertion failed";
default:
@@ -2052,10 +2270,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)
@@ -2063,7 +2282,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));
@@ -2078,31 +2323,34 @@ extern BOOL WinDivertHelperCheckFilter(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])
{
@@ -2115,44 +2363,101 @@ static int WinDivertBigNumCompare(const UINT32 *a, const UINT32 *b)
return 0;
}
+/*
+ * Get packet/payload data.
+ */
+static BOOL WinDivertGetData(const VOID *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.
*/
-extern BOOL WinDivertHelperEvalFilter(const char *filter,
- WINDIVERT_LAYER layer, 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;
- PWINDIVERT_IPHDR iphdr;
- PWINDIVERT_IPV6HDR ipv6hdr;
- PWINDIVERT_ICMPHDR icmphdr;
- PWINDIVERT_ICMPV6HDR icmpv6hdr;
- PWINDIVERT_TCPHDR tcphdr;
- PWINDIVERT_UDPHDR udphdr;
- UINT payload_len;
+ PWINDIVERT_IPHDR iphdr = NULL;
+ PWINDIVERT_IPV6HDR ipv6hdr = NULL;
+ PWINDIVERT_ICMPHDR icmphdr = NULL;
+ PWINDIVERT_ICMPV6HDR icmpv6hdr = NULL;
+ PWINDIVERT_TCPHDR tcphdr = NULL;
+ PWINDIVERT_UDPHDR udphdr = NULL;
+ UINT8 protocol = 0;
+ UINT header_len = 0, payload_len = 0;
+ UINT64 random64 = 0;
UINT32 val[4];
- BOOL pass;
+ UINT8 data8;
+ UINT16 data16;
+ UINT32 data32;
+ BOOL pass, big;
int cmp;
- struct windivert_ioctl_filter_s object[WINDIVERT_FILTER_MAXLEN];
+ WINDIVERT_FILTER 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;
+ }
+ WinDivertParsePacket((PVOID)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))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ case WINDIVERT_LAYER_SOCKET:
+ if (packet != NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ break;
+ case WINDIVERT_LAYER_REFLECT:
+ 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)
{
@@ -2171,8 +2476,65 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
break;
}
pass = TRUE;
+ big = FALSE;
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_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:
+ case WINDIVERT_FILTER_FIELD_PACKET16:
+ case WINDIVERT_FILTER_FIELD_PACKET32:
+ 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:
@@ -2185,7 +2547,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
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:
@@ -2194,19 +2558,25 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
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:
@@ -2222,42 +2592,96 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
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 = (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_PAYLOAD:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
+ case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
- pass = (udphdr != NULL);
+ pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
+ addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ pass = pass && (udphdr != NULL);
break;
default:
- pass = TRUE;
- break;
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
}
if (!pass)
{
pc = object[pc].failure;
continue;
}
- val[1] = val[2] = val[3] = 0;
switch (object[pc].field)
{
case WINDIVERT_FILTER_FIELD_ZERO:
val[0] = 0;
break;
+ case WINDIVERT_FILTER_FIELD_EVENT:
+ val[0] = addr->Event;
+ break;
+ case WINDIVERT_FILTER_FIELD_RANDOM8:
+ val[0] = (UINT32)((random64 >> 48) & 0xFF);
+ break;
+ case WINDIVERT_FILTER_FIELD_RANDOM16:
+ val[0] = (UINT32)((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);
+ 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->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 +2690,86 @@ 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);
+ 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] = (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] = (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] = (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;
@@ -2314,9 +2802,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:
@@ -2335,12 +2825,14 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
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]);
@@ -2430,11 +2922,196 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
val[0] = payload_len;
break;
+ case WINDIVERT_FILTER_FIELD_LOCALADDR:
+ big = TRUE;
+ 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:
+ big = TRUE;
+ 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:
+ 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:
+ 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:
+ 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);
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:
@@ -2463,3 +3140,1438 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter,
}
}
+/*
+ * 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;
+ 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;
+ }
+
+ 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;
+ UINT32 tmp[4];
+ ERROR error;
+
+ switch (test->field)
+ {
+ case WINDIVERT_FILTER_FIELD_ZERO:
+ 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:
+ 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:
+ 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;
+ }
+
+ switch (kind)
+ {
+ 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)
+ {
+ 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 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.
+ */
+static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr,
+ WINDIVERT_LAYER layer)
+{
+ 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_hex = 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, layer,
+ /*top_level=*/FALSE, /*and=*/FALSE);
+ return;
+ case TOKEN_NEQ:
+ WinDivertPutString(stream, (val->val[0] != 0? "not ": ""));
+ WinDivertFormatExpr(stream, field, layer,
+ /*top_level=*/FALSE, /*and=*/FALSE);
+ return;
+ default:
+ break;
+ }
+ break;
+ case TOKEN_IP_SRC_ADDR:
+ case TOKEN_IP_DST_ADDR:
+ is_ipv4_addr = TRUE;
+ break;
+ case TOKEN_IPV6_SRC_ADDR:
+ case TOKEN_IPV6_DST_ADDR:
+ case TOKEN_LOCAL_ADDR:
+ case TOKEN_REMOTE_ADDR:
+ is_ipv6_addr = TRUE;
+ break;
+ case TOKEN_LAYER:
+ is_layer = TRUE;
+ break;
+ 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;
+ }
+
+ WinDivertFormatExpr(stream, field, layer, /*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 (is_ipv4_addr)
+ {
+ WinDivertFormatIPv4Addr(stream, val->val[0]);
+ }
+ else if (is_ipv6_addr)
+ {
+ WinDivertFormatIPv6Addr(stream, val->val);
+ }
+ else if (is_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_SOCKET:
+ WinDivertPutString(stream, "SOCKET"); break;
+ case WINDIVERT_LAYER_REFLECT:
+ WinDivertPutString(stream, "REFLECT"); break;
+ default:
+ WinDivertFormatNumber(stream, val->val[0]); break;
+ }
+ }
+ else if (is_event)
+ {
+ switch (layer)
+ {
+ 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_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;
+ }
+ }
+ else if (is_hex)
+ {
+ WinDivertPutString(stream, "0x");
+ WinDivertFormatHexNumber(stream, val->val[0]);
+ }
+ else
+ {
+ WinDivertFormatNumber(stream, val->val[0]);
+ }
+}
+
+/*
+ * Format an expression.
+ */
+static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
+ WINDIVERT_LAYER layer, BOOL top_level, BOOL and)
+{
+ INT idx;
+
+ if (stream->pos >= stream->max)
+ {
+ return;
+ }
+
+ switch (expr->kind)
+ {
+ case TOKEN_AND:
+ if (!top_level && !and)
+ {
+ WinDivertPutChar(stream, '(');
+ }
+ WinDivertFormatExpr(stream, expr->arg[0], layer,
+ /*top_level=*/FALSE, /*and=*/TRUE);
+ WinDivertPutString(stream, " and ");
+ WinDivertFormatExpr(stream, expr->arg[1], layer,
+ /*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], layer,
+ /*top_level=*/FALSE, /*and=*/FALSE);
+ WinDivertPutString(stream, " or ");
+ WinDivertFormatExpr(stream, expr->arg[1], layer,
+ /*top_level=*/FALSE, /*and=*/FALSE);
+ if (!top_level && and)
+ {
+ WinDivertPutChar(stream, ')');
+ }
+ return;
+ case TOKEN_QUESTION:
+ WinDivertPutChar(stream, '(');
+ WinDivertFormatExpr(stream, expr->arg[0], layer,
+ /*top_level=*/TRUE, /*and=*/FALSE);
+ WinDivertPutString(stream, "? ");
+ WinDivertFormatExpr(stream, expr->arg[1], layer,
+ /*top_level=*/TRUE, /*and=*/FALSE);
+ WinDivertPutString(stream, ": ");
+ WinDivertFormatExpr(stream, expr->arg[2], layer,
+ /*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, layer);
+ return;
+ case TOKEN_ZERO:
+ 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:
+ 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:
+ 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;
+ }
+
+ WinDivertPutChar(stream, '[');
+ idx = (INT)expr->val[0];
+ if (idx < 0)
+ {
+ WinDivertPutChar(stream, '-');
+ idx = -idx;
+ }
+ WinDivertFormatNumber(stream, (UINT32)idx);
+ WinDivertPutString(stream, "b]");
+}
+
+/*
+ * 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, layer, /*top_level=*/TRUE,
+ /*and=*/FALSE);
+ WinDivertPutNul(&stream);
+
+ // Clean-up:
+ HeapDestroy(pool);
+ if (!stream.overflow)
+ {
+ return TRUE;
+ }
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ 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);
+}
+
+/*
+ * 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
new file mode 100644
index 0000000..dfe2dd0
--- /dev/null
+++ b/dll/windivert_shared.c
@@ -0,0 +1,639 @@
+/*
+ * 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 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)
+#define htonl(x) BYTESWAP32(x)
+
+#include "windivert_hash.c"
+
+/*
+ * 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,
+ const WINDIVERT_FILTER *filter)
+{
+ INT idx;
+ 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;
+ 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;
+ }
+ WinDivertSerializeNumber(stream, (UINT8)(filter->success + 2));
+ WinDivertSerializeNumber(stream, (UINT8)(filter->failure + 2));
+}
+
+/*
+ * Serialize a test.
+ */
+static void WinDivertSerializeFilter(PWINDIVERT_STREAM stream,
+ const WINDIVERT_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,
+ const WINDIVERT_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/doc/windivert.html b/doc/windivert.html
index 0f7b1e0..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.
@@ -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..c0e935e
--- /dev/null
+++ b/examples/flowtrack/flowtrack.c
@@ -0,0 +1,321 @@
+/*
+ * flowtrack.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
+#define INET6_ADDRSTRLEN 45
+
+/*
+ * Flow tracking.
+ */
+typedef struct FLOW
+{
+ WINDIVERT_ADDRESS addr;
+ struct FLOW *next;
+} FLOW, *PFLOW;
+
+static HANDLE lock;
+static PFLOW flows = NULL;
+
+/*
+ * 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 addr_str[INET6_ADDRSTRLEN+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);
+ WinDivertHelperFormatIPv6Address(addr->Flow.LocalAddr, addr_str,
+ sizeof(addr_str));
+ printf("%s:%u %s ", addr_str, addr->Flow.LocalPort,
+ (addr->Outbound? "---->": "<----"));
+ WinDivertHelperFormatIPv6Address(addr->Flow.RemoteAddr, addr_str,
+ sizeof(addr_str));
+ printf("%s:%u", addr_str, 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);
+ }
+
+ // 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);
+ if (thread == NULL)
+ {
+ fprintf(stderr, "error: failed to create thread (%d)\n",
+ GetLastError());
+ return EXIT_FAILURE;
+ }
+ CloseHandle(thread);
+
+ // 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..4904b9e 100644
--- a/examples/netdump/netdump.c
+++ b/examples/netdump/netdump.c
@@ -41,7 +41,6 @@
*
*/
-#include
#include
#include
#include
@@ -49,7 +48,11 @@
#include "windivert.h"
-#define MAXBUF 0xFFFF
+#define ntohs(x) WinDivertHelperNtohs(x)
+#define ntohl(x) WinDivertHelperNtohl(x)
+
+#define MAXBUF 0xFFFF
+#define INET6_ADDRSTRLEN 45
/*
* Entry.
@@ -68,6 +71,9 @@ 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];
+ UINT64 hash;
+ char src_str[INET6_ADDRSTRLEN+1], dst_str[INET6_ADDRSTRLEN+1];
const char *err_str;
LARGE_INTEGER base, freq;
double time_passed;
@@ -100,8 +106,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);
@@ -154,57 +160,49 @@ 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",
- time_passed, (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND?
- "outbound": "inbound"), addr.IfIdx, addr.SubIfIdx,
- addr.Loopback);
+ "Loopback=%u Hash=0x%.16llX]\n",
+ time_passed, (addr.Outbound? "outbound": "inbound"),
+ addr.Network.IfIdx, addr.Network.SubIfIdx, addr.Loopback, hash);
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 "
"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), src_str,
+ dst_str);
+
}
if (ipv6_header != NULL)
{
- UINT16 *src_addr = (UINT16 *)&ipv6_header->SrcAddr;
- UINT16 *dst_addr = (UINT16 *)&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,
+ 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 0e990ba..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,7 +54,14 @@
#include "windivert.h"
-#define MAXBUF 0xFFFF
+#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.
@@ -113,6 +119,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;
@@ -170,8 +178,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);
@@ -208,28 +216,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(' ');
+ 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,
+ 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 ",
@@ -287,7 +288,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 +315,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 +341,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 +364,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/passthru/passthru.c b/examples/passthru/passthru.c
index 3ffd053..dc56824 100644
--- a/examples/passthru/passthru.c
+++ b/examples/passthru/passthru.c
@@ -47,7 +47,10 @@
#include "windivert.h"
-#define MAXBUF 0xFFFF
+#define MAXBUF 400000
+#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/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/streamdump/streamdump.c b/examples/streamdump/streamdump.c
index c8c9164..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)
{
@@ -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);
@@ -301,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/webfilter/webfilter.c b/examples/webfilter/webfilter.c
index 2f04b00..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
@@ -238,7 +242,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/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c
new file mode 100644
index 0000000..73bc827
--- /dev/null
+++ b/examples/windivertctl/windivertctl.c
@@ -0,0 +1,418 @@
+/*
+ * windivertctl.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;
+
+/*
+ * 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;
+ }
+ 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);
+ while (TRUE)
+ {
+ 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_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;
+
+ default:
+ fputs("???", 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_SOCKET:
+ fputs("SOCKET", 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_RECV_PARTIAL) != 0)
+ {
+ printf("%sRECV_PARTIAL", (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\"", filter_str);
+ }
+ SetConsoleTextAttribute(console,
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ putchar('\n');
+
+ if (addr.Event == WINDIVERT_EVENT_REFLECT_CLOSE)
+ {
+ remove_process(addr.Reflect.ProcessId);
+ }
+ }
+
+ 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 6f344fa..cf63171 100644
--- a/include/windivert.h
+++ b/include/windivert.h
@@ -70,52 +70,140 @@ extern "C" {
/****************************************************************************/
/*
- * Divert 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;
-} 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_FORWARD = 1,/* Network layer (forwarded packets) */
+ WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */
+ WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */
+ WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */
} WINDIVERT_LAYER, *PWINDIVERT_LAYER;
/*
- * Divert flags.
+ * WinDivert NETWORK and NETWORK_FORWARD layer data.
*/
-#define WINDIVERT_FLAG_SNIFF 1
-#define WINDIVERT_FLAG_DROP 2
-#define WINDIVERT_FLAG_DEBUG 4
+typedef struct
+{
+ UINT32 IfIdx; /* Packet's interface index. */
+ UINT32 SubIfIdx; /* Packet's sub-interface index. */
+} WINDIVERT_DATA_NETWORK, *PWINDIVERT_DATA_NETWORK;
/*
- * Divert parameters.
+ * 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_DATA_FLOW, *PWINDIVERT_DATA_FLOW;
+
+/*
+ * 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_DATA_SOCKET, *PWINDIVERT_DATA_SOCKET;
+
+/*
+ * 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_DATA_REFLECT, *PWINDIVERT_DATA_REFLECT;
+
+/*
+ * WinDivert address.
+ */
+typedef struct
+{
+ INT64 Timestamp; /* Packet's timestamp. */
+ UINT64 Layer:8; /* Packet's layer. */
+ UINT64 Event:8; /* 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 Reserved:41;
+ union
+ {
+ WINDIVERT_DATA_NETWORK Network; /* Network layer data. */
+ WINDIVERT_DATA_FLOW Flow; /* Flow layer data. */
+ WINDIVERT_DATA_SOCKET Socket; /* Socket layer data. */
+ WINDIVERT_DATA_REFLECT Reflect; /* Reflect layer data. */
+ };
+} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
+
+/*
+ * 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_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, /* WinDivert handle opened. */
+ WINDIVERT_EVENT_REFLECT_CLOSE = 8, /* WinDivert handle closed. */
+} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
+
+/*
+ * WinDivert flags.
+ */
+#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 0x0008
+#define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY
+#define WINDIVERT_FLAG_RECV_PARTIAL 0x0010
+#define WINDIVERT_FLAG_NO_INSTALL 0x0020
+
+/*
+ * WinDivert parameters.
*/
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
+/*
+ * 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
/*
@@ -132,10 +220,10 @@ 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 UINT *readLen);
+ __out_opt WINDIVERT_ADDRESS *pAddr,
+ __out_opt UINT *pReadLen);
/*
* Receive (read) a packet from a WinDivert handle.
@@ -144,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 WINDIVERT_ADDRESS *pAddr,
+ __inout_opt UINT *pAddrLen,
__inout_opt LPOVERLAPPED lpOverlapped);
/*
@@ -154,23 +243,31 @@ 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,
- __out_opt UINT *writeLen);
+ __in const WINDIVERT_ADDRESS *pAddr,
+ __out_opt UINT *pWriteLen);
/*
* Send (write/inject) a packet to a WinDivert handle.
*/
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,
- __out_opt UINT *writeLen,
+ __in const WINDIVERT_ADDRESS *pAddr,
+ __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.
*/
@@ -333,8 +430,6 @@ typedef struct
UINT16 Checksum;
} WINDIVERT_UDPHDR, *PWINDIVERT_UDPHDR;
-#ifndef WINDIVERT_KERNEL
-
/*
* Flags for WinDivertHelperCalcChecksums()
*/
@@ -344,11 +439,25 @@ typedef struct
#define WINDIVERT_HELPER_NO_TCP_CHECKSUM 8
#define WINDIVERT_HELPER_NO_UDP_CHECKSUM 16
+#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.
*/
extern WINDIVERTEXPORT BOOL WinDivertHelperParsePacket(
- __in PVOID pPacket,
+ __in const VOID *pPacket,
__in UINT packetLen,
__out_opt PWINDIVERT_IPHDR *ppIpHdr,
__out_opt PWINDIVERT_IPV6HDR *ppIpv6Hdr,
@@ -373,21 +482,39 @@ 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.
*/
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);
/*
- * 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);
@@ -396,10 +523,40 @@ extern WINDIVERTEXPORT BOOL WinDivertHelperCheckFilter(
*/
extern WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter(
__in const char *filter,
- __in WINDIVERT_LAYER layer,
- __in PVOID pPacket,
+ __in const VOID *pPacket,
__in UINT packetLen,
- __in PWINDIVERT_ADDRESS pAddr);
+ __in const WINDIVERT_ADDRESS *pAddr);
+
+/*
+ * Format the given filter string.
+ */
+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 */
diff --git a/include/windivert_device.h b/include/windivert_device.h
index 0036461..1384785 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,9 +59,6 @@
#define WINDIVERT_DEVICE_NAME \
L"WinDivert" WINDIVERT_VERSION_LSTR
-#define WINDIVERT_IOCTL_VERSION 6
-#define WINDIVERT_IOCTL_MAGIC 0xA2BF
-
#define WINDIVERT_FILTER_FIELD_ZERO 0
#define WINDIVERT_FILTER_FIELD_INBOUND 1
#define WINDIVERT_FILTER_FIELD_OUTBOUND 2
@@ -122,8 +119,28 @@
#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_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_RANDOM8 77
+#define WINDIVERT_FILTER_FIELD_RANDOM16 78
+#define WINDIVERT_FILTER_FIELD_RANDOM32 79
#define WINDIVERT_FILTER_FIELD_MAX \
- WINDIVERT_FILTER_FIELD_IMPOSTOR
+ WINDIVERT_FILTER_FIELD_RANDOM32
#define WINDIVERT_FILTER_TEST_EQ 0
#define WINDIVERT_FILTER_TEST_NEQ 1
@@ -133,7 +150,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)
@@ -142,29 +159,60 @@
* WinDivert layers.
*/
#define WINDIVERT_LAYER_DEFAULT WINDIVERT_LAYER_NETWORK
-#define WINDIVERT_LAYER_MAX \
- WINDIVERT_LAYER_NETWORK_FORWARD
+#define WINDIVERT_LAYER_MAX WINDIVERT_LAYER_REFLECT
+
+/*
+ * WinDivert events.
+ */
+#define WINDIVERT_EVENT_MAX \
+ WINDIVERT_EVENT_REFLECT_CLOSE
/*
* 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_RECV_PARTIAL | \
+ WINDIVERT_FLAG_NO_INSTALL)
#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_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_RECV_PARTIAL, \
+ 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_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_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.
*/
-#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.
@@ -179,51 +227,61 @@
#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)
-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;
+ UINT64 arg1; // argument #1
+ UINT64 arg2; // argument #2
+} WINDIVERT_IOCTL, *PWINDIVERT_IOCTL;
/*
* WinDivert IOCTL structures.
*/
-struct windivert_ioctl_filter_s
+typedef struct
{
- UINT8 field; // WINDIVERT_FILTER_FIELD_IP_*
+ 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)
/*
* 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, 0x908, 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, 0x909, 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, 0x90A, 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, 0x90B, 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, 0x90C, 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, 0x90D, 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, 0x90E, 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, 0x90F, 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/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/mingw-build.sh b/mingw-build.sh
index 1fcbee4..9280310 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="-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"
@@ -79,24 +79,36 @@ 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 \
-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 -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 \
+ -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 \
+ -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/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 2ab6476..81e024d 100644
--- a/sys/windivert.c
+++ b/sys/windivert.c
@@ -32,6 +32,8 @@
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+
+#include
#include
#include
#include
@@ -55,11 +57,12 @@ 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.
*/
-// #define DEBUG_ON
+#define DEBUG_ON
#define DEBUG_BUFSIZE 256
#ifdef DEBUG_ON
@@ -97,36 +100,35 @@ static void DEBUG_ERROR(PCCH format, NTSTATUS status, ...)
#define WINDIVERT_TAG 'viDW'
/*
- * WinDivert packet filter.
+ * WinDivert reflect event.
*/
-struct filter_s
+typedef struct context_s *context_t;
+struct reflect_event_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; // Entry.
+ context_t context; // Context.
+ WINDIVERT_EVENT event; // Event.
+};
+typedef struct reflect_event_s *reflect_event_t;
+
+/*
+ * WinDivert reflect context information.
+ */
+struct reflect_context_s
+{
+ LIST_ENTRY entry; // Open handle entry.
+ LONGLONG timestamp; // Open timestamp.
+ WINDIVERT_DATA_REFLECT data; // Reflect data.
+ struct reflect_event_s open_event; // Open event.
+ struct reflect_event_s close_event; // Close event
+ BOOL open; // Seen open event?
};
-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
/*
* WinDivert context information.
*/
#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
+#define WINDIVERT_CONTEXT_MAXLAYERS 8
typedef enum
{
WINDIVERT_CONTEXT_STATE_OPENING = 0xA0, // Context is opening.
@@ -141,6 +143,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.
@@ -151,38 +156,44 @@ 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.
- UINT8 layer; // Context's layer.
+ WDFWORKITEM worker; // Read worker.
+ WINDIVERT_LAYER layer; // Context's layer.
UINT64 flags; // Context's flags.
- UINT32 priority; // Context's priority.
+ 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];
// 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.
+ const WINDIVERT_FILTER *filter; // Packet 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;
-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.
*/
-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.
@@ -191,11 +202,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.
- windivert_callout_t callout; // Call-out.
+ 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.
@@ -203,55 +217,79 @@ 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;
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.
+ UINT64 layer:8; // Layer.
+ UINT64 event:8; // 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 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;
-/*
- * IPv4/IPv6 pseudo headers.
- */
-typedef struct
-{
- UINT32 SrcAddr;
- UINT32 DstAddr;
- UINT8 Zero;
- UINT8 Protocol;
- UINT16 Length;
-} WINDIVERT_PSEUDOHDR, *PWINDIVERT_PSEUDOHDR;
+#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)))
-typedef struct
+/*
+ * WinDivert flow structure.
+ */
+struct flow_s
{
- UINT32 SrcAddr[4];
- UINT32 DstAddr[4];
- UINT32 Length;
- UINT32 Zero:24;
- UINT32 NextHdr:8;
-} WINDIVERT_PSEUDOV6HDR, *PWINDIVERT_PSEUDOV6HDR;
+ 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_DATA_FLOW data; // Flow data.
+};
+typedef struct flow_s *flow_t;
/*
* Misc.
@@ -271,21 +309,24 @@ 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.
+ * 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.
@@ -300,101 +341,204 @@ 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);
+ UINT64 flags);
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);
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);
-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_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_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_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_DATA_NETWORK 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, 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 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 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 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 BOOL windivert_filter_test(filter_t filter, UINT16 ip, UINT8 protocol,
- UINT8 field, UINT32 arg);
+static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4);
+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 *header_len_ptr, UINT *payload_len_ptr);
+static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
+ 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);
+static NTSTATUS windivert_reflect_init(WDFOBJECT parent);
+static void windivert_reflect_close(void);
+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,
+ LONGLONG timestamp);
+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,
+ 0x53D6C270, 0xEB79, 0x44CD,
+ 0x83, 0xCD, 0x14, 0x34, 0xE6, 0x13, 0x91, 0x68);
+DEFINE_GUID(WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV6_GUID,
+ 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.
*/
-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)",
@@ -402,13 +546,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},
- windivert_classify_inbound_network_v4_callout,
+ &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)",
@@ -416,13 +563,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},
- windivert_classify_outbound_network_v4_callout,
+ &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)",
@@ -430,13 +580,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},
- windivert_classify_inbound_network_v6_callout,
+ &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)",
@@ -444,13 +597,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},
- windivert_classify_outbound_network_v6_callout,
+ &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)",
@@ -458,13 +614,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},
- windivert_classify_forward_network_v4_callout,
+ &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)",
@@ -472,11 +631,189 @@ 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},
- windivert_classify_forward_network_v6_callout,
+ &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 const struct layer_s windivert_layer_resource_assignment_ipv4 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerResourceAssignmentIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer resource assignment (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutResourceAssignmentIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" callout resource assignment (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterResourceAssignmentIPv4",
+ 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
+};
+#define WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4 \
+ (&windivert_layer_resource_assignment_ipv4)
+
+static const struct layer_s windivert_layer_resource_assignment_ipv6 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerResourceAssignmentIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer resource assignment (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutResourceAssignmentIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" callout resource assignment (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterResourceAssignmentIPv6",
+ 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
+};
+#define WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6 \
+ (&windivert_layer_resource_assignment_ipv6)
+
+static const struct layer_s windivert_layer_auth_connect_ipv4 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthConnectIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer auth connect (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthConnectIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" callout auth connect (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterAuthConnectIPv4",
+ 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
+};
+#define WINDIVERT_LAYER_AUTH_CONNECT_IPV4 \
+ (&windivert_layer_auth_connect_ipv4)
+
+static const struct layer_s windivert_layer_auth_connect_ipv6 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthConnectIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer auth connect (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthConnectIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" callout auth connect (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterAuthConnectIPv6",
+ 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
+};
+#define WINDIVERT_LAYER_AUTH_CONNECT_IPV6 \
+ (&windivert_layer_auth_connect_ipv6)
+
+static const struct layer_s windivert_layer_auth_listen_ipv4 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthListenIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer auth listen (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthListenIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" callout auth listen (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterAuthListenIPv4",
+ 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
+};
+#define WINDIVERT_LAYER_AUTH_LISTEN_IPV4 \
+ (&windivert_layer_auth_listen_ipv4)
+
+static const struct layer_s windivert_layer_auth_listen_ipv6 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthListenIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer auth listen (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthListenIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" callout auth listen (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterAuthListenIPv6",
+ 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
+};
+#define WINDIVERT_LAYER_AUTH_LISTEN_IPV6 \
+ (&windivert_layer_auth_listen_ipv6)
+
+static const struct layer_s windivert_layer_auth_recv_accept_ipv4 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthRecvAcceptIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer auth recv accept (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthRecvAcceptIPv4",
+ L"" WINDIVERT_DEVICE_NAME L" callout auth recv accept (IPv4)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterAuthRecvAcceptIPv4",
+ 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
+};
+#define WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4 \
+ (&windivert_layer_auth_recv_accept_ipv4)
+
+static const struct layer_s windivert_layer_auth_recv_accept_ipv6 =
+{
+ L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthRecvAcceptIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" sublayer auth recv accept (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthRecvAcceptIPv6",
+ L"" WINDIVERT_DEVICE_NAME L" callout auth recv accept (IPv6)",
+ L"" WINDIVERT_DEVICE_NAME L"_FilterAuthRecvAcceptIPv6",
+ 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
+};
+#define WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6 \
+ (&windivert_layer_auth_recv_accept_ipv6)
+
+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)",
+ 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)",
+ &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4,
+ &WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV4_GUID,
+ windivert_flow_established_v4_classify,
+ windivert_flow_delete_notify,
+ 0
+};
+#define WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV4 \
+ (&windivert_layer_flow_established_ipv4)
+
+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)",
+ 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)",
+ &FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6,
+ &WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV6_GUID,
+ windivert_flow_established_v6_classify,
+ windivert_flow_delete_notify,
+ 0
+};
+#define WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV6 \
+ (&windivert_layer_flow_established_ipv6)
+
+/*
+ * Shared functions.
+ */
+#include "windivert_shared.c"
/*
* WinDivert malloc/free.
@@ -484,6 +821,10 @@ static layer_t layer_forward_network_ipv6 = &layer_forward_network_ipv6_0;
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)
@@ -528,6 +869,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
}
}
@@ -536,26 +881,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_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;
-
// Configure ourself as a non-PnP driver:
WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
config.DriverInitFlags |= WdfDriverInitNonPnpDriver;
@@ -692,7 +1017,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:
@@ -700,27 +1025,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(WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV4);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV6);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(
+ WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(
+ WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_CONNECT_IPV4);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_CONNECT_IPV6);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_LISTEN_IPV4);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_LISTEN_IPV6);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4);
+ if (!NT_SUCCESS(status))
+ {
+ goto driver_entry_sublayer_error;
+ }
+ status = windivert_install_sublayer(WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6);
if (!NT_SUCCESS(status))
{
goto driver_entry_sublayer_error;
@@ -732,6 +1109,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))
@@ -785,17 +1168,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,
+ WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV4->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV6->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV4->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ WINDIVERT_LAYER_RESOURCE_ASSIGNMENT_IPV6->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ WINDIVERT_LAYER_AUTH_CONNECT_IPV4->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ WINDIVERT_LAYER_AUTH_CONNECT_IPV6->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ WINDIVERT_LAYER_AUTH_LISTEN_IPV4->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ WINDIVERT_LAYER_AUTH_LISTEN_IPV6->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV4->sublayer_guid);
+ FwpmSubLayerDeleteByKey0(engine_handle,
+ WINDIVERT_LAYER_AUTH_RECV_ACCEPT_IPV6->sublayer_guid);
status = FwpmTransactionCommit0(engine_handle);
if (!NT_SUCCESS(status))
{
@@ -814,10 +1217,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))
@@ -858,19 +1261,22 @@ 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->shutdown_recv = FALSE;
+ context->shutdown_recv_enabled = FALSE;
+ context->shutdown_send = FALSE;
+ 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->filter_len = 0;
+ context->filter_flags = 0;
+ context->worker = NULL;
for (i = 0; i < WINDIVERT_CONTEXT_MAXLAYERS; i++)
{
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++)
@@ -900,15 +1306,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;
@@ -919,7 +1321,7 @@ 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;
+ RtlZeroMemory(&context->reflect, sizeof(context->reflect));
windivert_create_exit:
@@ -931,12 +1333,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)
{
@@ -951,44 +1350,106 @@ 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)
+ UINT64 flags)
{
UINT8 i, j;
layer_t layers[WINDIVERT_CONTEXT_MAXLAYERS];
+ UINT32 *callout_ids[WINDIVERT_CONTEXT_MAXLAYERS] = {NULL};
+ BOOL inbound, outbound, ipv4, ipv6, bind, connect, listen, accept;
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)
{
case WINDIVERT_LAYER_NETWORK:
- if (is_inbound && is_ipv4)
+ if (inbound && ipv4)
{
- layers[i++] = layer_inbound_network_ipv4;
+ layers[i++] = WINDIVERT_LAYER_INBOUND_NETWORK_IPV4;
}
- if (is_outbound && is_ipv4)
+ if (outbound && ipv4)
{
- layers[i++] = layer_outbound_network_ipv4;
+ layers[i++] = WINDIVERT_LAYER_OUTBOUND_NETWORK_IPV4;
}
- if (is_inbound && is_ipv6)
+ if (inbound && ipv6)
{
- layers[i++] = layer_inbound_network_ipv6;
+ layers[i++] = WINDIVERT_LAYER_INBOUND_NETWORK_IPV6;
}
- if (is_outbound && is_ipv6)
+ if (outbound && ipv6)
{
- layers[i++] = layer_outbound_network_ipv6;
+ layers[i++] = WINDIVERT_LAYER_OUTBOUND_NETWORK_IPV6;
}
break;
case WINDIVERT_LAYER_NETWORK_FORWARD:
- if (is_ipv4)
+ if (ipv4)
{
- layers[i++] = layer_forward_network_ipv4;
+ layers[i++] = WINDIVERT_LAYER_FORWARD_NETWORK_IPV4;
}
- if (is_ipv6)
+ if (ipv6)
{
- layers[i++] = layer_forward_network_ipv6;
+ layers[i++] = WINDIVERT_LAYER_FORWARD_NETWORK_IPV6;
}
break;
+
+ case WINDIVERT_LAYER_FLOW:
+ if (ipv4)
+ {
+ callout_ids[i] = &context->flow_v4_callout_id;
+ layers[i++] = WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV4;
+ }
+ if (ipv6)
+ {
+ callout_ids[i] = &context->flow_v6_callout_id;
+ layers[i++] = WINDIVERT_LAYER_FLOW_ESTABLISHED_IPV6;
+ }
+ break;
+
+ case WINDIVERT_LAYER_SOCKET:
+ 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 && 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;
+
+ case WINDIVERT_LAYER_REFLECT:
+ break;
default:
return STATUS_INVALID_PARAMETER;
@@ -996,7 +1457,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 +1479,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 +1488,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,32 +1511,38 @@ 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;
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;
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 +1622,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 +1640,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 +1660,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 +1685,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 +1703,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;
@@ -1238,9 +1714,12 @@ extern VOID windivert_cleanup(IN WDFFILEOBJECT object)
DEBUG("CLEANUP: cleaning up WinDivert context (context=%p)", context);
+ windivert_reflect_close_event(context);
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 +1731,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 +1775,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);
}
@@ -1301,20 +1794,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;
}
- windivert_uninstall_callouts(context, WINDIVERT_CONTEXT_STATE_CLOSING);
- FwpmEngineClose0(context->engine_handle);
+ worker = context->worker;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ WdfWorkItemFlush(worker);
+ WdfObjectDelete(worker);
}
/*
@@ -1347,7 +1835,7 @@ extern VOID windivert_destroy(IN WDFOBJECT object)
{
KLOCK_QUEUE_HANDLE lock_handle;
context_t context = windivert_context_get((WDFFILEOBJECT)object);
- filter_t filter;
+ const WINDIVERT_FILTER *filter;
NTSTATUS status;
DEBUG("DESTROY: destroying WinDivert context (context=%p)", context);
@@ -1362,7 +1850,9 @@ extern VOID windivert_destroy(IN WDFOBJECT object)
}
filter = context->filter;
KeReleaseInStackQueuedSpinLock(&lock_handle);
- windivert_free(filter);
+ windivert_uninstall_callouts(context, WINDIVERT_CONTEXT_STATE_CLOSED);
+ FwpmEngineClose0(context->engine_handle);
+ windivert_free((PVOID)filter);
}
/*
@@ -1383,6 +1873,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))
@@ -1400,89 +1897,207 @@ 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(context_t context, packet_t packet,
+ BOOL partial, LONGLONG timestamp, WDFREQUEST request)
{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ PLIST_ENTRY entry;
PMDL dst_mdl;
- PVOID dst, src;
- ULONG dst_len, src_len;
+ UINT8 *layer_data, *src, *dst;
+ 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);
-
- status = WdfRequestRetrieveOutputWdmMdl(request, &dst_mdl);
- if (!NT_SUCCESS(status))
+
+ // Get the packet and address buffers:
+ 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:
+ case WINDIVERT_LAYER_REFLECT:
+
+ 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 | no_exec_flag);
+ if (dst == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ DEBUG_ERROR("failed to get address of output MDL", status);
+ goto windivert_read_service_request_exit;
+ }
+ dst_len = MmGetMdlByteCount(dst_mdl);
+ break;
+
+ case WINDIVERT_LAYER_FLOW:
+ case WINDIVERT_LAYER_SOCKET:
+
+ status = STATUS_SUCCESS;
+ dst = NULL;
+ dst_len = 0;
+ break;
+
+ default:
+ status = STATUS_INVALID_DEVICE_STATE;
+ DEBUG_ERROR("invalid packet layer", status);
+ goto windivert_read_service_request_exit;
}
- 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);
-
- // 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->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)
+ // Copy the packet data:
+ switch (packet->layer)
{
- addr->PseudoIPChecksum = addr->PseudoTCPChecksum =
- addr->PseudoUDPChecksum = 1;
+ case WINDIVERT_LAYER_NETWORK:
+ case WINDIVERT_LAYER_NETWORK_FORWARD:
+ 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;
}
- else if (packet->forward)
+
+ // 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].Reserved = 0;
+ layer_data = (PVOID)packet->data;
+ switch (packet->layer)
{
- addr->PseudoIPChecksum = addr->PseudoTCPChecksum =
- addr->PseudoUDPChecksum = 0;
+ 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[i].Flow, layer_data,
+ sizeof(WINDIVERT_DATA_FLOW));
+ break;
+
+ case WINDIVERT_LAYER_SOCKET:
+ RtlCopyMemory(&addr[i].Socket, layer_data,
+ sizeof(WINDIVERT_DATA_SOCKET));
+ break;
+
+ case WINDIVERT_LAYER_REFLECT:
+ RtlCopyMemory(&addr[i].Reflect, layer_data,
+ sizeof(WINDIVERT_DATA_REFLECT));
+ break;
+
+ default:
+ break;
}
- else if (packet->direction == WINDIVERT_DIRECTION_OUTBOUND)
+
+ i++;
+ addr_len += sizeof(WINDIVERT_ADDRESS);
+ if (addr_len >= addr_len_max || i >= WINDIVERT_BATCH_MAX)
{
- addr->PseudoIPChecksum =
- (UINT8)packet->checksums.Transmit.IpHeaderChecksum;
- addr->PseudoTCPChecksum =
- (UINT8)packet->checksums.Transmit.TcpChecksum;
- addr->PseudoUDPChecksum =
- (UINT8)packet->checksums.Transmit.UdpChecksum;
+ // addr[] is full:
+ break;
}
- else
+ if (dst_len < sizeof(WINDIVERT_IPHDR) + sizeof(WINDIVERT_TCPHDR))
{
- addr->PseudoIPChecksum =
- (UINT8)packet->checksums.Receive.IpChecksumSucceeded;
- addr->PseudoTCPChecksum =
- (UINT8)packet->checksums.Receive.TcpChecksumSucceeded;
- addr->PseudoUDPChecksum =
- (UINT8)packet->checksums.Receive.UdpChecksumSucceeded;
+ // Remaining space too small:
+ break;
}
- addr->Reserved = 0;
+
+ // 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:
- if (NT_SUCCESS(status))
- {
- WdfRequestCompleteWithInformation(request, status, dst_len);
- }
- else
- {
- WdfRequestComplete(request, status);
- }
+
+ windivert_free_packet(packet);
+ WdfRequestCompleteWithInformation(request, status, read_len);
}
/*
@@ -1493,11 +2108,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 timeout;
+ BOOL partial, timeout;
NTSTATUS status;
packet_t packet;
req_context_t req_context;
@@ -1505,6 +2117,7 @@ static void windivert_read_service(context_t context)
timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ partial = ((context->flags & WINDIVERT_FLAG_RECV_PARTIAL) != 0);
while (context->state == WINDIVERT_CONTEXT_STATE_OPEN &&
!IsListEmpty(&context->packet_queue))
{
@@ -1523,18 +2136,35 @@ 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)
- {
- windivert_read_service_request(packet, request);
- }
+ windivert_read_service_request(context, packet, partial, timestamp,
+ request);
- windivert_free_packet(packet);
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);
}
@@ -1542,252 +2172,278 @@ 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 is_ipv4;
+ BOOL ipv4;
UINT8 layer;
UINT32 priority;
- UINT64 flags;
+ UINT64 flags, checksums;
HANDLE handle, compl_handle;
PNET_BUFFER_LIST buffers = NULL;
- NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksums_info;
- 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);
-
- if (addr->Direction != WINDIVERT_DIRECTION_INBOUND &&
- addr->Direction != WINDIVERT_DIRECTION_OUTBOUND)
- {
- status = STATUS_INVALID_PARAMETER;
- DEBUG_ERROR("failed to inject packet; invalid direction", status);
- goto windivert_write_exit;
- }
-
- status = WdfRequestRetrieveOutputWdmMdl(request, &mdl);
- if (!NT_SUCCESS(status))
- {
- DEBUG_ERROR("failed to retrieve input MDL", status);
- goto windivert_write_exit;
- }
-
- data = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority);
- if (data == NULL)
- {
- status = STATUS_INSUFFICIENT_RESOURCES;
- DEBUG_ERROR("failed to get MDL address", status);
- goto windivert_write_exit;
- }
- 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_copy = windivert_malloc(data_len, FALSE);
- if (data_copy == NULL)
- {
- 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;
- }
- is_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;
- }
- is_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));
- }
- if (addr->Impostor && !windivert_decrement_ttl(data_copy, is_ipv4,
- (addr->PseudoIPChecksum == 0)))
- {
- status = STATUS_HOPLIMIT_EXCEEDED;
- goto windivert_write_exit;
- }
-
- 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;
- }
-
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
status = STATUS_INVALID_DEVICE_STATE;
- goto windivert_write_exit;
+ 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;
KeReleaseInStackQueuedSpinLock(&lock_handle);
- if (layer != WINDIVERT_LAYER_NETWORK_FORWARD)
+ if ((flags & WINDIVERT_FLAG_RECV_ONLY) != 0)
{
- checksums_info.Value = NET_BUFFER_LIST_INFO(buffers,
- TcpIpChecksumNetBufferListInfo);
- if (addr->Direction == WINDIVERT_DIRECTION_OUTBOUND)
+ status = STATUS_INVALID_PARAMETER;
+ DEBUG_ERROR("failed to inject; recv-only flag is set", status);
+ goto windivert_write_hard_error;
+ }
+
+ 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);
+ goto windivert_write_hard_error;
+ default:
+ break;
+ }
+
+ status = WdfRequestRetrieveOutputWdmMdl(request, &mdl);
+ if (!NT_SUCCESS(status))
+ {
+ DEBUG_ERROR("failed to retrieve input MDL", status);
+ goto windivert_write_hard_error;
+ }
+
+ data = MmGetSystemAddressForMdlSafe(mdl,
+ NormalPagePriority | no_write_flag | no_exec_flag);
+ if (data == NULL)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ DEBUG_ERROR("failed to get MDL address", status);
+ goto windivert_write_hard_error;
+ }
+
+ data_len = MmGetMdlByteCount(mdl);
+ inject_len = 0;
+ addr = req_context->addr;
+ addr_len_max = (ULONG)req_context->addr_len;
+ addr_len = 0;
+
+ for (i = 0; addr_len < addr_len_max && i < WINDIVERT_BATCH_MAX; i++,
+ addr_len += sizeof(WINDIVERT_ADDRESS))
+ {
+ buffers = NULL;
+ mdl_copy = NULL;
+ data_copy = NULL;
+
+ // Get the packet length:
+ if (data_len < sizeof(WINDIVERT_IPHDR))
{
- 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);
+windivert_write_too_small_packet:
+ status = STATUS_BUFFER_TOO_SMALL;
+ DEBUG_ERROR("failed to inject partial packet", status);
+ goto windivert_write_hard_error;
+ }
+ 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) |
+ WINDIVERT_HELPER_NO_ICMP_CHECKSUM |
+ WINDIVERT_HELPER_NO_ICMPV6_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
{
- 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);
+ status = FwpsInjectNetworkReceiveAsync0(handle, (HANDLE)priority, 0,
+ UNSPECIFIED_COMPARTMENT_ID, addr[i].Network.IfIdx,
+ addr[i].Network.SubIfIdx, buffers, windivert_inject_complete,
+ data_copy);
}
- 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);
- 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);
- }
- else if (addr->Direction == WINDIVERT_DIRECTION_OUTBOUND)
- {
- 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->IfIdx, addr->SubIfIdx, buffers,
- windivert_inject_complete, compl_handle);
- }
-
-windivert_write_exit:
-
- if (NT_SUCCESS(status))
- {
- if ((flags & WINDIVERT_FLAG_DEBUG) == 0)
- {
- WdfRequestCompleteWithInformation(request, status, data_len);
- }
- }
- else
- {
- DEBUG_ERROR("failed to inject packet", status);
- if (buffers != NULL)
+ 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);
windivert_free(data);
IoFreeMdl(mdl);
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;
+ 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.
*/
@@ -1798,7 +2454,9 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
WDF_REQUEST_PARAMETERS params;
WDFMEMORY memobj;
PWINDIVERT_ADDRESS addr = NULL;
- windivert_ioctl_t ioctl;
+ UINT *addr_len_ptr = NULL;
+ UINT64 addr_len = 0;
+ PWINDIVERT_IOCTL ioctl;
WDF_OBJECT_ATTRIBUTES attributes;
req_context_t req_context = NULL;
NTSTATUS status;
@@ -1819,23 +2477,13 @@ 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;
- 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);
@@ -1847,39 +2495,77 @@ 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);
break;
+ case IOCTL_WINDIVERT_SHUTDOWN:
case IOCTL_WINDIVERT_START_FILTER:
case IOCTL_WINDIVERT_SET_LAYER:
case IOCTL_WINDIVERT_SET_PRIORITY:
@@ -1895,7 +2581,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:
@@ -1918,14 +2606,12 @@ 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;
+ size_t inbuflen, outbuflen, ioctl_filter_len;
+ PWINDIVERT_IOCTL ioctl;
+ const WINDIVERT_FILTER *ioctl_filter, *filter;
UINT8 layer;
- UINT32 priority;
+ INT16 priority;
UINT64 flags;
- PWINDIVERT_ADDRESS addr;
req_context_t req_context;
NTSTATUS status = STATUS_SUCCESS;
context_t context =
@@ -1973,103 +2659,218 @@ 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;
}
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 is_inbound, is_outbound, is_ipv4, is_ipv6;
+ BOOL inbound, outbound, ipv4, ipv6;
+ PIRP irp;
+ LONGLONG timestamp;
+ UINT64 filter_flags;
+ UINT32 process_id;
+ UINT8 filter_len;
- filter0 = (windivert_ioctl_filter_t)outbuf;
- filter0_len = outbuflen;
- filter = windivert_filter_compile(filter0, filter0_len);
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
+ 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);
+ goto windivert_ioctl_exit;
+ }
+
+ filter = NULL;
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
+ {
+windivert_ioctl_bad_start_state:
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ windivert_free((PVOID)filter);
+ status = STATUS_INVALID_DEVICE_STATE;
+ goto windivert_ioctl_exit;
+ }
+ context->state = WINDIVERT_CONTEXT_STATE_OPEN;
+ layer = context->layer;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ 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 = ioctl_filter_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_OPEN || context->on)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
{
- 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:
+ case WINDIVERT_LAYER_REFLECT:
+ if ((flags & WINDIVERT_FLAG_SNIFF) == 0 ||
+ (flags & WINDIVERT_FLAG_RECV_ONLY) == 0)
+ {
+ goto 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;
+ }
+ 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;
+ 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_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_reflect_open_event(context);
+
+ status = windivert_install_callouts(context, layer, filter_flags);
break;
}
case IOCTL_WINDIVERT_SET_LAYER:
- ioctl = (windivert_ioctl_t)inbuf;
- if (ioctl->arg > WINDIVERT_LAYER_MAX)
+ {
+ UINT64 layer;
+
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
+ layer = ioctl->arg1;
+ switch (layer)
{
- 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:
+ case WINDIVERT_LAYER_SOCKET:
+ case WINDIVERT_LAYER_REFLECT:
+ 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;
goto windivert_ioctl_exit;
}
- context->layer = layer;
+ context->layer = (WINDIVERT_LAYER)layer;
KeReleaseInStackQueuedSpinLock(&lock_handle);
break;
+ }
case IOCTL_WINDIVERT_SET_PRIORITY:
- ioctl = (windivert_ioctl_t)inbuf;
- if (ioctl->arg < WINDIVERT_PRIORITY_MIN ||
- ioctl->arg > WINDIVERT_PRIORITY_MAX)
+ {
+ UINT32 priority32;
+ INT64 priority64;
+
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
+ priority64 = (INT64)ioctl->arg1 - 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_OPEN || context->on)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
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;
- if (!WINDIVERT_FLAGS_VALID(ioctl->arg))
+ {
+ UINT64 flags;
+
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
+ 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_OPEN || context->on)
+ if (context->state != WINDIVERT_CONTEXT_STATE_OPENING)
{
KeReleaseInStackQueuedSpinLock(&lock_handle);
status = STATUS_INVALID_DEVICE_STATE;
@@ -2078,10 +2879,15 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
context->flags = flags;
KeReleaseInStackQueuedSpinLock(&lock_handle);
break;
+ }
case IOCTL_WINDIVERT_SET_PARAM:
- ioctl = (windivert_ioctl_t)inbuf;
- value = ioctl->arg;
+ {
+ UINT64 param, value;
+
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
+ param = ioctl->arg1;
+ value = ioctl->arg2;
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
if (context->state != WINDIVERT_CONTEXT_STATE_OPEN)
{
@@ -2089,7 +2895,7 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
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 ||
@@ -2141,9 +2947,14 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
}
KeReleaseInStackQueuedSpinLock(&lock_handle);
break;
+ }
case IOCTL_WINDIVERT_GET_PARAM:
- ioctl = (windivert_ioctl_t)inbuf;
+ {
+ UINT64 param;
+
+ ioctl = (PWINDIVERT_IOCTL)inbuf;
+ param = ioctl->arg1;
if (outbuflen != sizeof(UINT64))
{
status = STATUS_INVALID_PARAMETER;
@@ -2159,7 +2970,7 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
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;
@@ -2179,6 +2990,7 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
}
KeReleaseInStackQueuedSpinLock(&lock_handle);
break;
+ }
default:
status = STATUS_INVALID_DEVICE_REQUEST;
@@ -2192,9 +3004,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 +3016,265 @@ static NTSTATUS windivert_notify_callout(IN FWPS_CALLOUT_NOTIFY_TYPE type,
}
/*
- * WinDivert classify outbound IPv4 callout.
+ * WinDivert get fixed values.
*/
-static void windivert_classify_outbound_network_v4_callout(
+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.
+ */
+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_DATA_NETWORK network_data;
+ BOOL loopback;
+
+ if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
+ {
+ return;
+ }
+
+ 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,
+ /*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_DATA_NETWORK network_data;
+ BOOL loopback;
+
+ if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
+ {
+ return;
+ }
+
+ 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,
+ /*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_DATA_NETWORK network_data;
+ UINT advance;
+ BOOL loopback;
+
+ if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
+ {
+ return;
+ }
+
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_INBOUND_IPPACKET_V4_FLAGS) &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+ if (loopback)
+ {
+ result->actionType = FWP_ACTION_CONTINUE;
+ return;
+ }
+
+ 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,
+ /*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_DATA_NETWORK network_data;
+ UINT advance;
+ BOOL loopback;
+
+ if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
+ {
+ return;
+ }
+
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_INBOUND_IPPACKET_V6_FLAGS) &
+ FWP_CONDITION_FLAG_IS_LOOPBACK) != 0);
+ if (loopback)
+ {
+ result->actionType = FWP_ACTION_CONTINUE;
+ return;
+ }
+
+ 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,
+ /*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_DATA_NETWORK network_data;
+
+ if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
+ {
+ return;
+ }
+
+ 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,
+ /*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_DATA_NETWORK network_data;
+
+ if ((result->rights & FWPS_RIGHT_ACTION_WRITE) == 0 || data == NULL)
+ {
+ return;
+ }
+
+ 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,
+ /*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_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)
{
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;
+ const WINDIVERT_FILTER *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 +3284,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);
@@ -2373,16 +3296,16 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
}
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;
}
- 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 +3329,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 +3357,11 @@ 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, layer, (PVOID)network_data,
+ timestamp, /*event=*/WINDIVERT_EVENT_NETWORK_PACKET, ipv4,
+ outbound, loopback, impostor, filter);
if (match)
{
break;
@@ -2470,22 +3386,27 @@ 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, (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);
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, (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=*/TRUE,
+ timestamp);
if (advance != 0)
{
// Advance the NET_BUFFER to its original position. Note that we can
@@ -2496,26 +3417,29 @@ 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, layer, (PVOID)network_data,
+ 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,
+ 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 +3450,605 @@ 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_DATA_FLOW flow_data;
+ BOOL outbound, loopback;
+ UINT64 flow_id;
+
+ flow_data.ProcessId = (UINT32)meta_vals->processId;
+ 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 = (windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_DIRECTION) ==
+ FWP_DIRECTION_OUTBOUND);
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V4_FLAGS) &
+ 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_DATA_FLOW flow_data;
+ BOOL outbound, loopback;
+ UINT64 flow_id;
+
+ flow_data.ProcessId = (UINT32)meta_vals->processId;
+ 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 = (windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_DIRECTION) ==
+ FWP_DIRECTION_OUTBOUND);
+ loopback = ((windivert_get_val32(fixed_vals,
+ FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_FLAGS) &
+ 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_DATA_FLOW flow_data, IN BOOL ipv4,
+ IN BOOL outbound, IN BOOL loopback, OUT FWPS_CLASSIFY_OUT0 *result)
+{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ UINT64 flags, filter_flags;
+ UINT32 callout_id;
+ UINT16 layer_id;
+ BOOL match, ok;
+ WDFOBJECT object;
+ const WINDIVERT_FILTER *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 ||
+ context->shutdown_recv)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ return;
+ }
+ 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;
+
+ // 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, /*layer=*/WINDIVERT_LAYER_FLOW,
+ (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,
+ /*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW, (PVOID)flow_data,
+ /*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 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)
+ {
+ 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 ||
+ context->shutdown_recv)
+ {
+ 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;
+ const WINDIVERT_FILTER *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 ||
+ context->shutdown_recv)
+ {
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+ goto windivert_flow_delete_notify_exit;
+ }
+ filter = context->filter;
+ flags = context->flags;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_FLOW,
+ (PVOID)&flow->data, timestamp, /*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,
+ /*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, match, timestamp);
+ }
+
+windivert_flow_delete_notify_exit:
+
+ if (cleanup)
+ {
+ windivert_free(flow);
+ WdfObjectDereference(object);
+ }
+}
+
+/*
+ * 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_DATA_SOCKET socket_data;
+ BOOL loopback;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ 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 = windivert_get_val8(fixed_vals,
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_PROTOCOL);
+
+ 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,
+ &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_DATA_SOCKET socket_data;
+ BOOL loopback;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ 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 = windivert_get_val8(fixed_vals,
+ FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_PROTOCOL);
+
+ 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,
+ &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_DATA_SOCKET socket_data;
+ BOOL loopback;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ 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 = ((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,
+ &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_DATA_SOCKET socket_data;
+ BOOL loopback;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ 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 = ((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,
+ &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_DATA_SOCKET socket_data;
+ BOOL loopback;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ 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 = ((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,
+ &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_DATA_SOCKET socket_data;
+ BOOL loopback;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ 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 = ((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,
+ &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_DATA_SOCKET socket_data;
+ BOOL loopback;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ 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 = ((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,
+ &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_DATA_SOCKET socket_data;
+ BOOL loopback;
+
+ socket_data.ProcessId = (UINT32)meta_vals->processId;
+ 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 = ((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,
+ &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_DATA_SOCKET 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;
+ const WINDIVERT_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 ||
+ context->shutdown_recv)
+ {
+ 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, timestamp, 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, 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.
*/
@@ -2558,68 +4081,158 @@ VOID windivert_worker(IN WDFWORKITEM item)
KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
}
KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ windivert_read_service(context);
}
/*
* 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, 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 match,
LONGLONG timestamp)
{
KLOCK_QUEUE_HANDLE lock_handle;
+ PNET_BUFFER buffer;
packet_t work;
- UINT data_len;
- PVOID data;
+ PVOID packet_data;
+ UINT8 *data;
PLIST_ENTRY old_entry;
+ NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksums;
+ 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 && 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:
+ buffer = (PNET_BUFFER)packet;
+ 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_DATA_NETWORK, 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_DATA_NETWORK));
+ data = WINDIVERT_PACKET_DATA_PTR(WINDIVERT_DATA_NETWORK, 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:
+ flow_data = (PWINDIVERT_DATA_FLOW)layer_data;
+ work = (packet_t)windivert_malloc(
+ 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_DATA_FLOW));
+ pseudo_ip_checksum = pseudo_tcp_checksum = pseudo_udp_checksum =
+ FALSE;
+ break;
+
+ case WINDIVERT_LAYER_SOCKET:
+ socket_data = (PWINDIVERT_DATA_SOCKET)layer_data;
+ work = (packet_t)windivert_malloc(
+ 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_DATA_SOCKET));
+ pseudo_ip_checksum = pseudo_tcp_checksum = pseudo_udp_checksum =
+ FALSE;
+ break;
+
+ case WINDIVERT_LAYER_REFLECT:
+ reflect_data = (PWINDIVERT_DATA_REFLECT)layer_data;
+ work = (packet_t)windivert_malloc(
+ WINDIVERT_PACKET_SIZE(WINDIVERT_DATA_REFLECT, 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_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;
+ 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)
{
@@ -2627,6 +4240,16 @@ static BOOL windivert_queue_work(context_t context, BOOL sniff_mode,
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)
{
@@ -2635,11 +4258,9 @@ static BOOL windivert_queue_work(context_t context, BOOL sniff_mode,
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)
{
work = CONTAINING_RECORD(old_entry, struct packet_s, entry);
@@ -2667,10 +4288,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 +4307,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 +4315,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 +4328,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;
}
}
@@ -2715,9 +4336,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;
}
@@ -2726,65 +4344,103 @@ 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;
+ UINT64 checksums;
+ PWINDIVERT_DATA_NETWORK 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_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) |
+ WINDIVERT_HELPER_NO_ICMP_CHECKSUM |
+ WINDIVERT_HELPER_NO_ICMPV6_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;
}
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",
+ DEBUG_ERROR("failed to create NET_BUFFER_LIST for reinjected packet",
status);
IoFreeMdl(mdl);
windivert_free_packet(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))
+ if (!NT_SUCCESS(status))
{
- packet->data = NULL; // Data is now owned by injected NET_BUFFER.
- }
- else
- {
- 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);
}
- windivert_free_packet(packet);
}
/*
@@ -2792,19 +4448,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)
{
PWINDIVERT_IPHDR ip_header;
PWINDIVERT_IPV6HDR ipv6_header;
- if (is_ipv4)
+ if (ipv4)
{
ip_header = (PWINDIVERT_IPHDR)data;
if (ip_header->TTL <= 1)
@@ -2812,17 +4467,15 @@ static BOOL windivert_decrement_ttl(PVOID data, BOOL is_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
@@ -2838,81 +4491,37 @@ 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.
*/
-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])
{
@@ -2926,13 +4535,54 @@ static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b)
}
/*
- * Checks if the given packet is of interest.
+ * Get packet/payload data.
*/
-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_get_data(PNET_BUFFER buffer, UINT offset, INT idx,
+ UINT size, PVOID data)
{
- size_t tot_len, ip_header_len;
+ 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.
+ */
+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 *header_len_ptr, UINT *payload_len_ptr)
+{
+ UINT tot_len, ip_header_len;
PWINDIVERT_IPHDR ip_header = NULL;
PWINDIVERT_IPV6HDR ipv6_header = NULL;
PWINDIVERT_ICMPHDR icmp_header = NULL;
@@ -2940,10 +4590,16 @@ 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 header_len = 0, payload_len = 0;
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))
{
@@ -2952,7 +4608,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 +4666,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 +4675,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:
@@ -3057,20 +4713,25 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
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);
+ 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);
+ header_len = ip_header_len + sizeof(WINDIVERT_UDPHDR);
break;
default:
+ header_len = ip_header_len;
break;
}
@@ -3082,43 +4743,220 @@ 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;
+ *proto_ptr = proto;
+ *header_len_ptr = header_len;
+ *payload_len_ptr = tot_len - header_len;
+
+ return TRUE;
+}
+
+/*
+ * Checks if the given network packet is of interest.
+ */
+static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer,
+ 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;
+ PWINDIVERT_ICMPHDR icmp_header = NULL;
+ PWINDIVERT_ICMPV6HDR icmpv6_header = NULL;
+ PWINDIVERT_TCPHDR tcp_header = NULL;
+ 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;
+ PWINDIVERT_DATA_SOCKET socket_data = NULL;
+ PWINDIVERT_DATA_REFLECT reflect_data = NULL;
+ UINT8 data8;
+ UINT16 data16;
+ UINT32 data32;
+ NTSTATUS status;
+
+ switch (layer)
+ {
+ 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,
+ &protocol, &header_len, &payload_len))
+ {
+ return FALSE;
+ }
+ network_data = (PWINDIVERT_DATA_NETWORK)layer_data;
+ break;
+ case WINDIVERT_LAYER_FLOW:
+ flow_data = (PWINDIVERT_DATA_FLOW)layer_data;
+ break;
+ case WINDIVERT_LAYER_SOCKET:
+ socket_data = (PWINDIVERT_DATA_SOCKET)layer_data;
+ break;
+ case WINDIVERT_LAYER_REFLECT:
+ reflect_data = (PWINDIVERT_DATA_REFLECT)layer_data;
+ break;
+ default:
+ 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 big = FALSE;
int cmp;
UINT32 field[4];
- 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:
+ case WINDIVERT_FILTER_FIELD_EVENT:
result = TRUE;
break;
- case WINDIVERT_FILTER_PROTOCOL_IP:
- result = (ip_header != NULL);
+ case WINDIVERT_FILTER_FIELD_INBOUND:
+ case WINDIVERT_FILTER_FIELD_OUTBOUND:
+ result = (layer != WINDIVERT_LAYER_NETWORK_FORWARD &&
+ layer != WINDIVERT_LAYER_REFLECT);
break;
- case WINDIVERT_FILTER_PROTOCOL_IPV6:
- result = (ipv6_header != NULL);
+ 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_ICMP:
- result = (icmp_header != NULL);
+ 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_PROTOCOL_ICMPV6:
- result = (icmpv6_header != NULL);
+ 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;
- case WINDIVERT_FILTER_PROTOCOL_TCP:
- result = (tcp_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_NETWORK ||
+ layer == WINDIVERT_LAYER_FLOW ||
+ layer == WINDIVERT_LAYER_SOCKET);
break;
- case WINDIVERT_FILTER_PROTOCOL_UDP:
- result = (udp_header != NULL);
+ case WINDIVERT_FILTER_FIELD_PROCESSID:
+ result = (layer == WINDIVERT_LAYER_FLOW ||
+ layer == WINDIVERT_LAYER_SOCKET ||
+ layer == WINDIVERT_LAYER_REFLECT);
+ break;
+ case WINDIVERT_FILTER_FIELD_LAYER:
+ result = (layer == WINDIVERT_LAYER_REFLECT);
+ 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:
+ result = (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ result = result && (ip_header != NULL);
+ 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:
+ result = (layer == WINDIVERT_LAYER_NETWORK ||
+ layer == WINDIVERT_LAYER_NETWORK_FORWARD);
+ result = result && (ipv6_header != 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:
+ 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_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);
+ 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_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;
- break;
+ return FALSE;
}
if (result)
{
@@ -3127,17 +4965,62 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
case WINDIVERT_FILTER_FIELD_ZERO:
field[0] = 0;
break;
+ 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);
+ 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);
+ 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 +5029,86 @@ 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);
+ 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:
+ return FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_ICMPV6:
- field[0] = (UINT32)(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:
+ return FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_TCP:
- field[0] = (UINT32)(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:
+ return FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_UDP:
- field[0] = (UINT32)(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:
+ return FALSE;
+ }
break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
field[0] = (UINT32)ip_header->HdrLength;
@@ -3195,9 +5142,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:
@@ -3218,6 +5167,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
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] =
@@ -3228,6 +5178,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
(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] =
@@ -3307,8 +5258,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,14 +5273,214 @@ 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:
+ big = TRUE;
+ 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:
+ return FALSE;
+ }
+ break;
+ case WINDIVERT_FILTER_FIELD_REMOTEADDR:
+ big = TRUE;
+ 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:
+ return FALSE;
+ }
+ break;
+ case WINDIVERT_FILTER_FIELD_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:
+ return FALSE;
+ }
+ break;
+ case WINDIVERT_FILTER_FIELD_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:
+ return FALSE;
+ }
+ break;
+ case WINDIVERT_FILTER_FIELD_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:
+ return FALSE;
+ }
+ break;
+ case WINDIVERT_FILTER_FIELD_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:
+ return FALSE;
+ }
+ break;
+ case WINDIVERT_FILTER_FIELD_LAYER:
+ field[0] = reflect_data->Layer;
break;
default:
- field[0] = 0;
- break;
+ return FALSE;
}
- cmp = windivert_big_num_compare(field, filter[ip].arg);
+ }
+ if (result)
+ {
+ cmp = windivert_big_num_compare(field, filter[ip].arg, big);
switch (filter[ip].test)
{
case WINDIVERT_FILTER_TEST_EQ:
@@ -3352,8 +5502,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
result = (cmp >= 0);
break;
default:
- result = FALSE;
- break;
+ return FALSE;
}
}
ip = (result? filter[ip].success: filter[ip].failure);
@@ -3366,168 +5515,38 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
return FALSE;
}
}
+
DEBUG("FILTER: REJECT (filter TTL exceeded)");
return FALSE;
}
-/*
- * Analyze the given filter.
- */
-static void windivert_filter_analyze(filter_t filter, BOOL *is_inbound,
- BOOL *is_outbound, BOOL *is_ipv4, BOOL *is_ipv6)
-{
- BOOL result;
-
- // 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;
- }
-
- // 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);
- }
- *is_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);
- }
- *is_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);
- }
- *is_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);
- }
- *is_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 const WINDIVERT_FILTER *windivert_filter_compile(
+ const WINDIVERT_FILTER *ioctl_filter, size_t ioctl_filter_len,
+ WINDIVERT_LAYER layer)
{
- filter_t filter0 = NULL, result = NULL;
+ PWINDIVERT_FILTER filter = NULL;
+ WINDIVERT_EVENT event;
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_exit;
+ goto windivert_filter_compile_error;
}
- length = ioctl_filter_len / sizeof(struct windivert_ioctl_filter_s);
- if (length >= WINDIVERT_FILTER_MAXLEN)
+ length = ioctl_filter_len / sizeof(WINDIVERT_FILTER);
+ 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 = (PWINDIVERT_FILTER)windivert_malloc(
+ length * sizeof(WINDIVERT_FILTER), FALSE);
+ if (filter == NULL)
{
- goto windivert_filter_compile_exit;
+ goto windivert_filter_compile_error;
}
for (i = 0; i < length; i++)
@@ -3535,7 +5554,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 +5565,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 +5578,54 @@ 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:
+ // 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_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;
+ }
+ switch (ioctl_filter[i].field)
+ {
+ 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:
+ {
+ INT idx = (INT)ioctl_filter[i].arg[1];
+ if (idx > UINT16_MAX || idx < -UINT16_MAX)
+ {
+ goto windivert_filter_compile_error;
+ }
+ break;
+ }
+ default:
+ if (ioctl_filter[i].arg[1] != 0)
+ {
+ goto windivert_filter_compile_error;
+ }
+ break;
}
}
switch (ioctl_filter[i].field)
@@ -3596,14 +5649,58 @@ 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_LAYER:
+ if (ioctl_filter[i].arg[0] > WINDIVERT_LAYER_MAX)
+ {
+ goto windivert_filter_compile_error;
+ }
+ break;
+ case WINDIVERT_FILTER_FIELD_EVENT:
+ event = (WINDIVERT_EVENT)ioctl_filter[i].arg[0];
+ switch (layer)
+ {
+ 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_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:
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 +5713,20 @@ 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:
+ 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_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,120 +5746,387 @@ 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:
+ 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_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];
-
- // 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_IFIDX:
- case WINDIVERT_FILTER_FIELD_SUBIFIDX:
- 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:
- filter0[i].protocol = WINDIVERT_FILTER_PROTOCOL_NONE;
- 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:
- filter0[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:
- filter0[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;
- 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;
- 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:
- filter0[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;
- break;
- default:
- goto windivert_filter_compile_exit;
- }
+ 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];
}
- 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((PVOID)filter);
+ return NULL;
+}
+
+/****************************************************************************/
+/* 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.
+ */
+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 = FALSE;
+ 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 open event.
+ */
+static void windivert_reflect_open_event(context_t context)
+{
+ KLOCK_QUEUE_HANDLE lock_handle;
+ WDFOBJECT object;
+ reflect_event_t reflect_event;
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ object = (WDFOBJECT)context->object;
+ // 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)
+ {
+ WdfWorkItemEnqueue(reflect_worker);
+ reflect_worker_queued = TRUE;
+ }
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+}
+
+/*
+ * 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)
+ {
+ return;
+ }
+
+ // Queue the event:
+ reflect_event = &context->reflect.close_event;
+ reflect_event->context = context;
+ 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);
+}
+
+/*
+ * 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;
+ const WINDIVERT_FILTER *filter;
+ UINT16 filter_len;
+ PWINDIVERT_IPHDR iphdr;
+ WINDIVERT_STREAM stream;
+
+ // The filter is returned in a pseudo-IP packet. This is just to make
+ // the interface consistent, i.e., WinDivertRecv() always receives IP
+ // packets.
+
+ packet = reflect_pseudo_packet;
+ iphdr = (PWINDIVERT_IPHDR)packet;
+ object = (char *)(iphdr + 1);
+
+ stream.data = object;
+ stream.pos = 0;
+ stream.max = sizeof(reflect_pseudo_packet) - sizeof(WINDIVERT_IPHDR);
+ stream.overflow = FALSE;
+
+ KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
+ filter = context->filter;
+ filter_len = context->filter_len;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
+
+ WinDivertSerializeFilter(&stream, filter, (UINT8)filter_len);
+
+ total_len = sizeof(WINDIVERT_IPHDR) + (UINT16)stream.pos;
+ RtlZeroMemory(iphdr, sizeof(WINDIVERT_IPHDR));
+ iphdr->Version = 4;
+ iphdr->HdrLength = sizeof(WINDIVERT_IPHDR) / sizeof(UINT32);
+ iphdr->Length = RtlUshortByteSwap(total_len);
+ iphdr->TTL = 1;
+ iphdr->Protocol = 254; // "experimental"
+
+ *len_ptr = total_len;
+
+ return iphdr;
+}
+
+/*
+ * 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;
+ const WINDIVERT_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,
+ timestamp, event, /*ipv4=*/TRUE, /*outbound=*/FALSE,
+ /*loopback=*/FALSE, /*impostor=*/FALSE, filter);
+ if (!match)
+ {
+ continue;
+ }
+ if (packet == NULL)
+ {
+ packet = windivert_reflect_pseudo_packet(context, &packet_len);
+ }
+ (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, /*match=*/TRUE, timestamp);
+ }
+}
+
+/*
+ * 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;
+ 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);
+
+ 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,
+ timestamp, /*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);
+ ok = windivert_queue_work(context, (PVOID)packet, packet_len,
+ /*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_REFLECT,
+ (PVOID)&waiter->reflect.data,
+ /*event=*/WINDIVERT_EVENT_REFLECT_OPEN, /*flags=*/0,
+ /*priority=*/0, /*ipv4=*/TRUE, /*outbound=*/FALSE,
+ /*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);
+}
+
+/*
+ * 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;
+
+ 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:
+ 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:
+ 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);
+ }
+ reflect_worker_queued = FALSE;
+ KeReleaseInStackQueuedSpinLock(&lock_handle);
}
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"
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 edd7455..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,49 +70,78 @@ 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},
+ {"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},
+ {"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},
@@ -241,6 +270,82 @@ 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},
+ {"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},
+ {"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},
@@ -253,7 +358,18 @@ 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},
+ {"udp.Payload16[-1] == 0x0001 && udp.Payload16[-2] == 0x0001",
+ &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},
@@ -267,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},
@@ -276,12 +401,17 @@ 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},
{"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},
@@ -296,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},
};
/*
@@ -305,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,
- WINDIVERT_FLAG_DROP | WINDIVERT_FLAG_DEBUG);
- lower_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, 999,
WINDIVERT_FLAG_DROP);
if (upper_handle == INVALID_HANDLE_VALUE ||
lower_handle == INVALID_HANDLE_VALUE)
@@ -323,31 +463,31 @@ 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);
+ 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);
-
- printf("%.2u ", i);
+ BOOL res = run_test(upper_handle, filter, packet, packet_len, match,
+ &diff);
+ diff = 1000000 * diff / freq.QuadPart;
+ printf("%.3u ", i);
if (res)
{
SetConsoleTextAttribute(console, FOREGROUND_GREEN);
printf("PASSED");
+ passed_tests++;
}
else
{
@@ -356,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 |
@@ -372,6 +512,9 @@ int main(void)
WinDivertClose(upper_handle);
WinDivertClose(lower_handle);
+ printf("\npassed = %.2f%%\n",
+ ((double)passed_tests / (double)num_tests) * 100.0);
+
return 0;
}
@@ -379,60 +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;
- HANDLE handle = INVALID_HANDLE_VALUE, handle0 = INVALID_HANDLE_VALUE,
- event = NULL;
+ PWINDIVERT_IPHDR iphdr = 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 (!WinDivertHelperCheckFilter(filter, WINDIVERT_LAYER_NETWORK, &err_str,
- &err_pos))
+ if (!WinDivertHelperCompileFilter(filter, WINDIVERT_LAYER_NETWORK,
+ 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;
}
- memset(&addr, 0, sizeof(addr));
- addr.Direction = WINDIVERT_DIRECTION_OUTBOUND;
- if (WinDivertHelperEvalFilter(filter, WINDIVERT_LAYER_NETWORK,
- (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());
@@ -441,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), 0, &addr, &buf_len,
- &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.Direction == WINDIVERT_DIRECTION_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
};