Add a new REFLECT layer to WinDivert (see #156).

Adds a new REFLECT layer for monitoring WinDivert
handles.  This includes:
- three new REFLECT events: ESTABLISHED, OPEN and
  CLOSE;
- modifying the ADDRESS for REFLECT data:
  open time, process-id, layer, flags, and
  priority of the opened handle; and
- allowing WinDivertRecv() to read a
  representation of the opened filter.

This change also includes a new "object"
representation for WinDivert filter strings.
The API has been updated as follows:
- WinDivertHelperCompileFilter (replaces
  CheckFilter) compiles filter strings into the
  object form; and
- WinDivertHelperFormatFilter can "decompile" an
  object back into a human-readable filter
  string.

Other:
- New NO_INSTALL flag.
- New windivertctl.exe sample program.
This commit is contained in:
basil00
2018-10-21 10:12:19 +08:00
parent 6250568974
commit f0dd1224b1
13 changed files with 2854 additions and 877 deletions
+23 -276
View File
@@ -119,13 +119,10 @@ static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code, UINT8 arg8,
UINT64 arg, PVOID buf, UINT len, UINT *iolen, LPOVERLAPPED overlapped);
static UINT8 WinDivertSkipExtHeaders(UINT8 proto, UINT8 **header, UINT *len);
#ifdef WINDIVERT_DEBUG
static void WinDivertFilterDump(windivert_ioctl_filter_t filter, UINT16 len);
#endif
/*
* Include the helper API implementation.
*/
#include "windivert_shared.c"
#include "windivert_helper.c"
/*
@@ -379,7 +376,7 @@ static BOOL WinDivertIoControl(HANDLE handle, DWORD code, UINT8 arg8,
static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code, UINT8 arg8,
UINT64 arg, PVOID buf, UINT len, UINT *iolen, LPOVERLAPPED overlapped)
{
struct windivert_ioctl_s ioctl;
WINDIVERT_IOCTL ioctl;
BOOL result;
DWORD iolen0;
@@ -402,24 +399,21 @@ static BOOL WinDivertIoControlEx(HANDLE handle, DWORD code, UINT8 arg8,
extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
INT16 priority, UINT64 flags)
{
struct windivert_ioctl_filter_s object[WINDIVERT_FILTER_MAXLEN];
WINDIVERT_FILTER object[WINDIVERT_FILTER_MAXLEN];
UINT obj_len;
ERROR comp_err;
DWORD err;
HANDLE handle;
SC_HANDLE service;
UINT32 priority32;
UINT64 priority64, filter_flags;
// Parameter checking.
if (layer == 0)
{
layer = WINDIVERT_LAYER_NETWORK;
}
switch (layer)
{
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
case WINDIVERT_LAYER_FLOW:
case WINDIVERT_LAYER_REFLECT:
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
@@ -431,25 +425,21 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
return INVALID_HANDLE_VALUE;
}
priority32 = WINDIVERT_PRIORITY(priority);
if (priority32 < WINDIVERT_PRIORITY_MIN ||
priority32 > WINDIVERT_PRIORITY_MAX)
if (priority < WINDIVERT_PRIORITY_MIN ||
priority > WINDIVERT_PRIORITY_MAX)
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
// Compile the filter:
// Compile & analyze the filter:
comp_err = WinDivertCompileFilter(filter, layer, object, &obj_len);
if (IS_ERROR(comp_err))
{
SetLastError(ERROR_INVALID_PARAMETER);
return INVALID_HANDLE_VALUE;
}
#ifdef WINDIVERT_DEBUG
WinDivertFilterDump(object, obj_len);
#endif
filter_flags = WinDivertAnalyzeFilter(object, obj_len);
// Attempt to open the WinDivert device:
handle = CreateFile(L"\\\\.\\" WINDIVERT_DEVICE_NAME,
@@ -464,6 +454,11 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
}
// Open failed because the device isn't installed; install it now.
if ((flags & WINDIVERT_FLAG_NO_INSTALL) != 0)
{
SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
return INVALID_HANDLE_VALUE;
}
SetLastError(0);
service = WinDivertDriverInstall();
if (service == NULL)
@@ -503,8 +498,8 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
// Set the flags:
if (flags != 0)
{
if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_FLAGS, 0,
(UINT64)flags, NULL, 0, NULL))
if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_FLAGS, 0, flags,
NULL, 0, NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
@@ -512,10 +507,12 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
}
// Set the priority:
if (priority32 != WINDIVERT_PRIORITY_DEFAULT)
if (priority != WINDIVERT_PRIORITY_DEFAULT)
{
// Make positive:
priority64 = (UINT64)((INT64)priority + WINDIVERT_PRIORITY_MAX);
if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_SET_PRIORITY, 0,
(UINT64)priority32, NULL, 0, NULL))
priority64, NULL, 0, NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
@@ -523,8 +520,8 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
}
// Start the filter:
if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_START_FILTER, 0, 0,
object, obj_len*sizeof(struct windivert_ioctl_filter_s), NULL))
if (!WinDivertIoControl(handle, IOCTL_WINDIVERT_START_FILTER, 0,
filter_flags, object, obj_len * sizeof(WINDIVERT_FILTER), NULL))
{
CloseHandle(handle);
return INVALID_HANDLE_VALUE;
@@ -856,253 +853,3 @@ static BOOLEAN WinDivertAToX(const char *str, char **endptr, UINT32 *intptr)
return TRUE;
}
/***************************************************************************/
/* DEBUGGING */
/***************************************************************************/
#ifdef WINDIVERT_DEBUG
/*
* Print a filter (debugging).
*/
static void WinDivertFilterDump(windivert_ioctl_filter_t filter, UINT16 len)
{
UINT16 i;
for (i = 0; i < len; i++)
{
printf("label_%u:\n\tif (", i);
switch (filter[i].field)
{
case WINDIVERT_FILTER_FIELD_ZERO:
printf("zero ");
break;
case WINDIVERT_FILTER_FIELD_INBOUND:
printf("inbound ");
break;
case WINDIVERT_FILTER_FIELD_OUTBOUND:
printf("outbound ");
break;
case WINDIVERT_FILTER_FIELD_IFIDX:
printf("ifIdx ");
break;
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
printf("subIfIdx ");
break;
case WINDIVERT_FILTER_FIELD_IP:
printf("ip ");
break;
case WINDIVERT_FILTER_FIELD_IPV6:
printf("ipv6 ");
break;
case WINDIVERT_FILTER_FIELD_ICMP:
printf("icmp ");
break;
case WINDIVERT_FILTER_FIELD_ICMPV6:
printf("icmpv6 ");
break;
case WINDIVERT_FILTER_FIELD_TCP:
printf("tcp ");
break;
case WINDIVERT_FILTER_FIELD_UDP:
printf("udp ");
break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
printf("ip.HdrLength ");
break;
case WINDIVERT_FILTER_FIELD_IP_TOS:
printf("ip.TOS ");
break;
case WINDIVERT_FILTER_FIELD_IP_LENGTH:
printf("ip.Length ");
break;
case WINDIVERT_FILTER_FIELD_IP_ID:
printf("ip.Id ");
break;
case WINDIVERT_FILTER_FIELD_IP_DF:
printf("ip.DF ");
break;
case WINDIVERT_FILTER_FIELD_IP_MF:
printf("ip.MF ");
break;
case WINDIVERT_FILTER_FIELD_IP_FRAGOFF:
printf("ip.FragOff ");
break;
case WINDIVERT_FILTER_FIELD_IP_TTL:
printf("ip.TTL ");
break;
case WINDIVERT_FILTER_FIELD_IP_PROTOCOL:
printf("ip.Protocol ");
break;
case WINDIVERT_FILTER_FIELD_IP_CHECKSUM:
printf("ip.Checksum ");
break;
case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
printf("ip.SrcAddr ");
break;
case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
printf("ip.DstAddr ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS:
printf("ipv6.TrafficClass ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL:
printf("ipv6.FlowLabel ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_LENGTH:
printf("ipv6.Length ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR:
printf("ipv6.NextHdr ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT:
printf("ipv6.HopLimit ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
printf("ipv6.SrcAddr ");
break;
case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
printf("ipv6.DstAddr ");
break;
case WINDIVERT_FILTER_FIELD_ICMP_TYPE:
printf("icmp.Type ");
break;
case WINDIVERT_FILTER_FIELD_ICMP_CODE:
printf("icmp.Code ");
break;
case WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM:
printf("icmp.Checksum ");
break;
case WINDIVERT_FILTER_FIELD_ICMP_BODY:
printf("icmp.Body ");
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE:
printf("icmpv6.Type ");
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_CODE:
printf("icmpv6.Code ");
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM:
printf("icmpv6.Checksum ");
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_BODY:
printf("icmpv6.Body ");
break;
case WINDIVERT_FILTER_FIELD_TCP_SRCPORT:
printf("tcp.SrcPort ");
break;
case WINDIVERT_FILTER_FIELD_TCP_DSTPORT:
printf("tcp.DstPort ");
break;
case WINDIVERT_FILTER_FIELD_TCP_SEQNUM:
printf("tcp.SeqNum ");
break;
case WINDIVERT_FILTER_FIELD_TCP_ACKNUM:
printf("tcp.AckNum ");
break;
case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH:
printf("tcp.HdrLength ");
break;
case WINDIVERT_FILTER_FIELD_TCP_URG:
printf("tcp.Urg ");
break;
case WINDIVERT_FILTER_FIELD_TCP_ACK:
printf("tcp.Ack ");
break;
case WINDIVERT_FILTER_FIELD_TCP_PSH:
printf("tcp.Psh ");
break;
case WINDIVERT_FILTER_FIELD_TCP_RST:
printf("tcp.Rst ");
break;
case WINDIVERT_FILTER_FIELD_TCP_SYN:
printf("tcp.Syn ");
break;
case WINDIVERT_FILTER_FIELD_TCP_FIN:
printf("tcp.Fin ");
break;
case WINDIVERT_FILTER_FIELD_TCP_WINDOW:
printf("tcp.Window ");
break;
case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
printf("tcp.Checksum ");
break;
case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
printf("tcp.UrgPtr ");
break;
case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
printf("tcp.PayloadLength " );
break;
case WINDIVERT_FILTER_FIELD_UDP_SRCPORT:
printf("udp.SrcPort ");
break;
case WINDIVERT_FILTER_FIELD_UDP_DSTPORT:
printf("udp.DstPort ");
break;
case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
printf("udp.Length ");
break;
case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
printf("udp.Checksum ");
break;
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
printf("udp.PayloadLength ");
break;
default:
printf("unknown.Field ");
break;
}
switch (filter[i].test)
{
case WINDIVERT_FILTER_TEST_EQ:
printf("== ");
break;
case WINDIVERT_FILTER_TEST_NEQ:
printf("!= ");
break;
case WINDIVERT_FILTER_TEST_LT:
printf("< ");
break;
case WINDIVERT_FILTER_TEST_LEQ:
printf("<= ");
break;
case WINDIVERT_FILTER_TEST_GT:
printf("> ");
break;
case WINDIVERT_FILTER_TEST_GEQ:
printf(">= ");
break;
default:
printf("?? ");
break;
}
printf("%u)\n", filter[i].arg[0]);
switch (filter[i].success)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
printf("\t\treturn ACCEPT;\n");
break;
case WINDIVERT_FILTER_RESULT_REJECT:
printf("\t\treturn REJECT;\n");
break;
default:
printf("\t\tgoto label_%u;\n", filter[i].success);
break;
}
printf("\telse\n");
switch (filter[i].failure)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
printf("\t\treturn ACCEPT;\n");
break;
case WINDIVERT_FILTER_RESULT_REJECT:
printf("\t\treturn REJECT;\n");
break;
default:
printf("\t\tgoto label_%u;\n", filter[i].failure);
break;
}
}
}
#endif /* WINDIVERT_DEBUG */
+2 -1
View File
@@ -13,5 +13,6 @@ EXPORTS
WinDivertHelperParsePacket
WinDivertHelperParseIPv4Address
WinDivertHelperParseIPv6Address
WinDivertHelperCheckFilter
WinDivertHelperCompileFilter
WinDivertHelperEvalFilter
WinDivertHelperFormatFilter
+1573 -116
View File
File diff suppressed because it is too large Load Diff
+37 -37
View File
@@ -69,7 +69,7 @@ static void print_address(const UINT32 *addr)
if (addr[3] == 0 && addr[2] == 0 && addr[1] == 0x0000FFFF)
{
// IPv4 address:
UINT32 a, b, c, d;
UINT32 a, b, c, d;
a = (addr[0] >> 24) & 0xFF;
b = (addr[0] >> 16) & 0xFF;
c = (addr[0] >> 8) & 0xFF;
@@ -82,9 +82,9 @@ static void print_address(const UINT32 *addr)
int i;
for (i = 3; i >= 0; i--)
{
UINT32 a, b;
a = (addr[i] >> 16) & 0xFFFF;
b = (addr[i] >> 0) & 0xFFFF;
UINT32 a, b;
a = (addr[i] >> 16) & 0xFFFF;
b = (addr[i] >> 0) & 0xFFFF;
printf("%x:%x", a, b);
if (i != 0)
{
@@ -114,8 +114,8 @@ static DWORD draw(LPVOID arg)
while (TRUE)
{
GetConsoleScreenBufferInfo(console, &screen);
SetConsoleCursorPosition(console, top_left);
GetConsoleScreenBufferInfo(console, &screen);
SetConsoleCursorPosition(console, top_left);
rows = screen.srWindow.Bottom - screen.srWindow.Top + 1;
columns = screen.srWindow.Right - screen.srWindow.Left + 1;
@@ -132,7 +132,7 @@ static DWORD draw(LPVOID arg)
}
ReleaseMutex(lock);
// Print the flows:
// Print the flows:
SetConsoleTextAttribute(console, BACKGROUND_RED | BACKGROUND_GREEN |
BACKGROUND_BLUE);
WriteConsole(console, header, sizeof(header)-1, &written, NULL);
@@ -142,21 +142,21 @@ static DWORD draw(LPVOID arg)
COORD pos = {sizeof(header)-1, 0};
FillConsoleOutputCharacterA(console, ' ', fill_len, pos,
&written);
FillConsoleOutputAttribute(console,
FillConsoleOutputAttribute(console,
BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE,
fill_len, pos, &written);
fill_len, pos, &written);
}
putchar('\n');
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
for (i = 0; i < num_addrs && i < rows-1; i++)
for (i = 0; i < num_addrs && i < rows-1; i++)
{
COORD pos = {0, i+1};
addr = &addrs[i];
FillConsoleOutputCharacterA(console, ' ', columns, pos, &written);
FillConsoleOutputAttribute(console,
FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE,
columns, pos, &written);
FillConsoleOutputAttribute(console,
FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE,
columns, pos, &written);
SetConsoleCursorPosition(console, pos);
if (i == rows-2 && (i+1) < num_addrs)
{
@@ -191,7 +191,7 @@ static DWORD draw(LPVOID arg)
}
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
switch (addr->Flow.Protocol)
switch (addr->Flow.Protocol)
{
case IPPROTO_TCP:
SetConsoleTextAttribute(console, FOREGROUND_GREEN);
@@ -227,9 +227,9 @@ static DWORD draw(LPVOID arg)
{
COORD pos = {0, i+1};
FillConsoleOutputCharacterA(console, ' ', columns, pos, &written);
FillConsoleOutputAttribute(console,
FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE,
columns, pos, &written);
FillConsoleOutputAttribute(console,
FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE,
columns, pos, &written);
}
Sleep(1000);
@@ -260,7 +260,24 @@ int __cdecl main(int argc, char **argv)
exit(EXIT_FAILURE);
}
// Spawn the draw() thread.
// Open WinDivert FLOW handle:
handle = WinDivertOpen(filter, WINDIVERT_LAYER_FLOW, priority,
WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_RECV_ONLY);
if (handle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_INVALID_PARAMETER &&
!WinDivertHelperCompileFilter(filter, WINDIVERT_LAYER_FLOW,
NULL, 0, &err_str, NULL))
{
fprintf(stderr, "error: invalid filter \"%s\"\n", err_str);
exit(EXIT_FAILURE);
}
fprintf(stderr, "error: failed to open the WinDivert device (%d)\n",
GetLastError());
return EXIT_FAILURE;
}
// Spawn the draw() thread.
lock = CreateMutex(NULL, FALSE, NULL);
thread = CreateThread(NULL, 1, (LPTHREAD_START_ROUTINE)draw, NULL, 0,
NULL);
@@ -272,23 +289,6 @@ int __cdecl main(int argc, char **argv)
}
CloseHandle(thread);
// Open WinDivert FLOW handle:
handle = WinDivertOpen(filter, WINDIVERT_LAYER_FLOW, priority,
WINDIVERT_FLAGS_LAYER_FLOW);
if (handle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_INVALID_PARAMETER &&
!WinDivertHelperCheckFilter(filter, WINDIVERT_LAYER_FLOW,
&err_str, NULL))
{
fprintf(stderr, "error: invalid filter \"%s\"\n", err_str);
exit(EXIT_FAILURE);
}
fprintf(stderr, "error: failed to open the WinDivert device (%d)\n",
GetLastError());
return EXIT_FAILURE;
}
// Main loop:
while (TRUE)
{
@@ -302,7 +302,7 @@ int __cdecl main(int argc, char **argv)
{
case WINDIVERT_EVENT_FLOW_ESTABLISHED:
// Flow established:
// Flow established:
flow = (PFLOW)malloc(sizeof(FLOW));
if (flow == NULL)
{
@@ -318,7 +318,7 @@ int __cdecl main(int argc, char **argv)
case WINDIVERT_EVENT_FLOW_DELETED:
// Flow deleted:
// Flow deleted:
prev = NULL;
WaitForSingleObject(lock, INFINITE);
flow = flows;
+2 -2
View File
@@ -100,8 +100,8 @@ int __cdecl main(int argc, char **argv)
if (handle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_INVALID_PARAMETER &&
!WinDivertHelperCheckFilter(argv[1], WINDIVERT_LAYER_NETWORK,
&err_str, NULL))
!WinDivertHelperCompileFilter(argv[1], WINDIVERT_LAYER_NETWORK,
NULL, 0, &err_str, NULL))
{
fprintf(stderr, "error: invalid filter \"%s\"\n", err_str);
exit(EXIT_FAILURE);
+2 -2
View File
@@ -170,8 +170,8 @@ int __cdecl main(int argc, char **argv)
if (handle == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_INVALID_PARAMETER &&
!WinDivertHelperCheckFilter(argv[1], WINDIVERT_LAYER_NETWORK,
&err_str, NULL))
!WinDivertHelperCompileFilter(argv[1], WINDIVERT_LAYER_NETWORK,
NULL, 0, &err_str, NULL))
{
fprintf(stderr, "error: invalid filter \"%s\"\n", err_str);
exit(EXIT_FAILURE);
+408
View File
@@ -0,0 +1,408 @@
/*
* streamdump.c
* (C) 2018, all rights reserved,
*
* This file is part of WinDivert.
*
* WinDivert is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* 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 <winsock2.h>
#include <windows.h>
#include <psapi.h>
#include <shlwapi.h>
#include <stdio.h>
#include <stdlib.h>
#include "windivert.h"
#define MAX_PACKET 0xFFFF
#define MAX_FILTER_LEN 30000
/*
* Process info.
*/
typedef struct INFO
{
UINT32 process_id;
UINT32 ref_count;
HANDLE process;
struct INFO *next;
} INFO, *PINFO;
static INFO *open = NULL; // All open handles
/*
* Modes.
*/
typedef enum
{
LIST,
WATCH,
KILLALL
} MODE;
/*
* Months.
*/
static const char *months[12] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
"Nov", "Dec"
};
/*
* Add a new process.
*/
static HANDLE add_process(UINT32 process_id)
{
PINFO info = open;
HANDLE process;
while (info != NULL)
{
if (info->process_id == process_id)
{
info->ref_count++;
return info->process;
}
info = info->next;
}
process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE,
FALSE, process_id);
info = (INFO *)malloc(sizeof(INFO));
if (info == NULL)
{
fprintf(stderr, "error: failed to allocate memory (%d)\n",
GetLastError());
exit(EXIT_FAILURE);
}
info->process_id = process_id;
info->process = process;
info->ref_count = 1;
info->next = open;
open = info;
return process;
}
/*
* Lookup a process.
*/
static HANDLE lookup_process(UINT32 process_id)
{
PINFO info = open;
while (info != NULL)
{
if (info->process_id == process_id)
{
return info->process;
}
info = info->next;
}
}
/*
* Remove an old process.
*/
static void remove_process(UINT32 process_id)
{
PINFO info = open, prev = NULL;
while (info != NULL)
{
if (info->process_id == process_id)
{
info->ref_count--;
if (info->ref_count > 0)
{
return;
}
break;
}
prev = info;
info = info->next;
}
if (info->process != NULL)
{
CloseHandle(info->process);
}
if (prev != NULL)
{
prev->next = info->next;
}
else
{
open = info->next;
}
free(info);
}
/*
* Entry.
*/
int __cdecl main(int argc, char **argv)
{
HANDLE handle, process, console;
INT16 priority = -333; // Arbitrary.
UINT packet_len;
static UINT8 packet[MAX_PACKET];
static char path[MAX_PATH+1];
static char filter_str[MAX_FILTER_LEN];
PVOID object;
DWORD path_len;
BOOL or;
WINDIVERT_ADDRESS addr;
ULONGLONG freq, start_count;
LARGE_INTEGER li;
MODE mode;
const char *filter = "true";
const char *err_str = NULL;
if (argc != 2 && argc != 3)
{
usage:
fprintf(stderr, "usage: %s (list|watch|killall) [filter]\n", argv[0]);
exit(EXIT_FAILURE);
}
if (strcmp(argv[1], "list") == 0)
{
mode = LIST;
}
else if (strcmp(argv[1], "watch") == 0)
{
mode = WATCH;
}
else if (strcmp(argv[1], "killall") == 0)
{
mode = KILLALL;
}
else
{
goto usage;
}
if (argc == 3)
{
filter = argv[2];
}
// Time management
QueryPerformanceFrequency(&li);
freq = li.QuadPart;
QueryPerformanceCounter(&li);
start_count = li.QuadPart;
// Open WinDivert REFLECT handle:
handle = WinDivertOpen(filter, WINDIVERT_LAYER_REFLECT, priority,
WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_RECV_ONLY |
(mode == WATCH? 0: WINDIVERT_FLAG_NO_INSTALL));
if (handle == INVALID_HANDLE_VALUE)
{
if (mode != WATCH && GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
{
// WinDivert driver is not running, so no open handles.
return 0;
}
if (GetLastError() == ERROR_INVALID_PARAMETER &&
!WinDivertHelperCompileFilter(filter, WINDIVERT_LAYER_FLOW,
NULL, 0, &err_str, NULL))
{
fprintf(stderr, "error: invalid filter \"%s\"\n", err_str);
exit(EXIT_FAILURE);
}
fprintf(stderr, "error: failed to open the WinDivert device (%d)\n",
GetLastError());
return EXIT_FAILURE;
}
// Main loop:
console = GetStdHandle(STD_OUTPUT_HANDLE);
while (TRUE)
{
if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len))
{
fprintf(stderr, "failed to event (%d)\n", GetLastError());
continue;
}
switch (addr.Event)
{
case WINDIVERT_EVENT_REFLECT_ESTABLISHED:
case WINDIVERT_EVENT_REFLECT_OPEN:
// Open handle:
process = add_process(addr.Reflect.ProcessId);
if (mode == KILLALL)
{
SetConsoleTextAttribute(console, FOREGROUND_RED);
fputs("KILL", stdout);
TerminateProcess(process, 0);
}
else
{
SetConsoleTextAttribute(console, FOREGROUND_GREEN);
fputs("OPEN", stdout);
}
break;
case WINDIVERT_EVENT_REFLECT_CLOSE:
// Close handle:
if (mode != WATCH)
{
continue;
}
process = lookup_process(addr.Reflect.ProcessId);
SetConsoleTextAttribute(console, FOREGROUND_RED);
fputs("CLOSE", stdout);
break;
}
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
fputs(" time=", stdout);
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
printf("%.3fs", (double)(addr.Reflect.Timestamp - (INT64)start_count) /
(double)freq);
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
fputs(" pid=", stdout);
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
printf("%u", addr.Reflect.ProcessId);
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
fputs(" exe=", stdout);
path_len = 0;
if (process != NULL)
{
path_len = GetProcessImageFileName(process, path, sizeof(path));
}
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
printf("%s", (path_len != 0? path: "???"));
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
fputs(" layer=", stdout);
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
switch (addr.Reflect.Layer)
{
case WINDIVERT_LAYER_NETWORK:
fputs("NETWORK", stdout);
break;
case WINDIVERT_LAYER_NETWORK_FORWARD:
fputs("NETWORK_FORWARD", stdout);
break;
case WINDIVERT_LAYER_FLOW:
fputs("FLOW", stdout);
break;
case WINDIVERT_LAYER_REFLECT:
fputs("REFLECT", stdout);
break;
default:
fputs("???", stdout);
break;
}
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
fputs(" flags=", stdout);
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
if (addr.Reflect.Flags == 0)
{
fputs("0", stdout);
}
else
{
or = FALSE;
if ((addr.Reflect.Flags & WINDIVERT_FLAG_SNIFF) != 0)
{
fputs("SNIFF", stdout);
or = TRUE;
}
if ((addr.Reflect.Flags & WINDIVERT_FLAG_DROP) != 0)
{
printf("%sDROP", (or? "|": ""));
or = TRUE;
}
if ((addr.Reflect.Flags & WINDIVERT_FLAG_RECV_ONLY) != 0)
{
printf("%sRECV_ONLY", (or? "|": ""));
or = TRUE;
}
if ((addr.Reflect.Flags & WINDIVERT_FLAG_SEND_ONLY) != 0)
{
printf("%sSEND_ONLY", (or? "|": ""));
or = TRUE;
}
if ((addr.Reflect.Flags & WINDIVERT_FLAG_DEBUG) != 0)
{
printf("%sDEBUG", (or? "|": ""));
or = TRUE;
}
if ((addr.Reflect.Flags & WINDIVERT_FLAG_NO_INSTALL) != 0)
{
printf("%sNO_INSTALL", (or? "|": ""));
or = TRUE;
}
}
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
fputs(" priority=", stdout);
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
printf("%d", addr.Reflect.Priority);
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
fputs(" filter=", stdout);
SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN);
WinDivertHelperParsePacket(packet, packet_len, NULL, NULL, NULL, NULL,
NULL, NULL, &object, NULL);
if (WinDivertHelperFormatFilter((char *)object, addr.Reflect.Layer,
filter_str, sizeof(filter_str)))
{
printf("\"%s\" \"%s\"", filter_str, (char *)object); // XXX
}
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
putchar('\n');
if (addr.Event == WINDIVERT_EVENT_REFLECT_CLOSE)
{
remove_process(addr.Reflect.ProcessId);
}
if (mode != WATCH && addr.Final)
{
break;
}
}
return 0;
}
+49 -24
View File
@@ -69,6 +69,17 @@ extern "C" {
/* WINDIVERT API */
/****************************************************************************/
/*
* WinDivert layers.
*/
typedef enum
{
WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */
WINDIVERT_LAYER_NETWORK_FORWARD = 1,/* Network layer (forwarded packets) */
WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */
WINDIVERT_LAYER_REFLECT = 3, /* Reflect layer. */
} WINDIVERT_LAYER, *PWINDIVERT_LAYER;
/*
* WinDivert NETWORK and NETWORK_FORWARD layer data.
*/
@@ -91,6 +102,18 @@ typedef struct
UINT8 Protocol; /* Protocol. */
} WINDIVERT_FLOW_DATA, *PWINDIVERT_FLOW_DATA;
/*
* WinDivert REFLECTION layer data.
*/
typedef struct
{
INT64 Timestamp; /* Handle open time. */
UINT32 ProcessId; /* Handle process ID. */
WINDIVERT_LAYER Layer; /* Handle layer. */
UINT64 Flags; /* Handle flags. */
INT16 Priority; /* Handle priority. */
} WINDIVERT_REFLECT_DATA, *PWINDIVERT_REFLECT_DATA;
/*
* WinDivert address.
*/
@@ -106,24 +129,16 @@ typedef struct
UINT32 PseudoIPChecksum:1; /* Packet has pseudo IPv4 checksum? */
UINT32 PseudoTCPChecksum:1; /* Packet has pseudo TCP checksum? */
UINT32 PseudoUDPChecksum:1; /* Packet has pseudo UDP checksum? */
UINT32 Reserved:9;
UINT32 Final:1; /* Packet is final event? */
UINT32 Reserved:8;
union
{
WINDIVERT_NETWORK_DATA Network; /* Network layer data. */
WINDIVERT_FLOW_DATA Flow; /* Flow layer data. */
WINDIVERT_REFLECT_DATA Reflect; /* Reflect layer data. */
};
} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
/*
* WinDivert layers.
*/
typedef enum
{
WINDIVERT_LAYER_NETWORK = 1, /* Network layer. */
WINDIVERT_LAYER_NETWORK_FORWARD = 2,/* Network layer (forwarded packets) */
WINDIVERT_LAYER_FLOW = 3 /* Flow layer. */
} WINDIVERT_LAYER, *PWINDIVERT_LAYER;
/*
* WinDivert events.
*/
@@ -133,24 +148,23 @@ typedef enum
WINDIVERT_EVENT_FLOW_ESTABLISHED = 1,
/* Flow established. */
WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */
WINDIVERT_EVENT_REFLECT_ESTABLISHED = 3,
/* Previously open WinDivert handle. */
WINDIVERT_EVENT_REFLECT_OPEN = 4, /* Open new WinDivert handle. */
WINDIVERT_EVENT_REFLECT_CLOSE = 5, /* Close existing WinDivert handle. */
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
/*
* WinDivert flags.
*/
#define WINDIVERT_FLAG_SNIFF 1
#define WINDIVERT_FLAG_DROP 2
#define WINDIVERT_FLAG_RECV_ONLY 4
#define WINDIVERT_FLAG_SNIFF 0x01
#define WINDIVERT_FLAG_DROP 0x02
#define WINDIVERT_FLAG_RECV_ONLY 0x04
#define WINDIVERT_FLAG_READ_ONLY WINDIVERT_FLAG_RECV_ONLY
#define WINDIVERT_FLAG_SEND_ONLY 8
#define WINDIVERT_FLAG_SEND_ONLY 0x08
#define WINDIVERT_FLAG_WRITE_ONLY WINDIVERT_FLAG_SEND_ONLY
#define WINDIVERT_FLAG_DEBUG 16
#define WINDIVERT_FLAGS_LAYER_NETWORK 0
#define WINDIVERT_FLAGS_LAYER_NETWORK_FORWARD \
0
#define WINDIVERT_FLAGS_LAYER_FLOW \
(WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_RECV_ONLY)
#define WINDIVERT_FLAG_DEBUG 0x10
#define WINDIVERT_FLAG_NO_INSTALL 0x20
/*
* WinDivert parameters.
@@ -430,11 +444,13 @@ extern WINDIVERTEXPORT UINT WinDivertHelperCalcChecksums(
__in UINT64 flags);
/*
* Check the given filter string.
* Compile the given filter string.
*/
extern WINDIVERTEXPORT BOOL WinDivertHelperCheckFilter(
extern WINDIVERTEXPORT BOOL WinDivertHelperCompileFilter(
__in const char *filter,
__in WINDIVERT_LAYER layer,
__out_opt char *object,
__in UINT objLen,
__out_opt const char **errorStr,
__out_opt UINT *errorPos);
@@ -447,6 +463,15 @@ extern WINDIVERTEXPORT BOOL WinDivertHelperEvalFilter(
__in UINT packetLen,
__in PWINDIVERT_ADDRESS pAddr);
/*
* Format the given filter string.
*/
extern BOOL WinDivertHelperFormatFilter(
__in const char *filter,
__in WINDIVERT_LAYER layer,
__out char *buffer,
__in UINT bufLen);
#endif /* WINDIVERT_KERNEL */
#ifdef __cplusplus
+27 -16
View File
@@ -128,8 +128,9 @@
#define WINDIVERT_FILTER_FIELD_LOCALPORT 63
#define WINDIVERT_FILTER_FIELD_REMOTEPORT 64
#define WINDIVERT_FILTER_FIELD_PROTOCOL 65
#define WINDIVERT_FILTER_FIELD_LAYER 66
#define WINDIVERT_FILTER_FIELD_MAX \
WINDIVERT_FILTER_FIELD_PROTOCOL
WINDIVERT_FILTER_FIELD_LAYER
#define WINDIVERT_FILTER_TEST_EQ 0
#define WINDIVERT_FILTER_TEST_NEQ 1
@@ -139,7 +140,7 @@
#define WINDIVERT_FILTER_TEST_GEQ 5
#define WINDIVERT_FILTER_TEST_MAX WINDIVERT_FILTER_TEST_GEQ
#define WINDIVERT_FILTER_MAXLEN 128
#define WINDIVERT_FILTER_MAXLEN (0xFF-2)
#define WINDIVERT_FILTER_RESULT_ACCEPT (WINDIVERT_FILTER_MAXLEN+1)
#define WINDIVERT_FILTER_RESULT_REJECT (WINDIVERT_FILTER_MAXLEN+2)
@@ -148,13 +149,15 @@
* WinDivert layers.
*/
#define WINDIVERT_LAYER_DEFAULT WINDIVERT_LAYER_NETWORK
#define WINDIVERT_LAYER_MAX WINDIVERT_LAYER_REFLECT
/*
* WinDivert flags.
*/
#define WINDIVERT_FLAGS_ALL \
(WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP | WINDIVERT_FLAG_RECV_ONLY |\
WINDIVERT_FLAG_SEND_ONLY | WINDIVERT_FLAG_DEBUG)
WINDIVERT_FLAG_SEND_ONLY | WINDIVERT_FLAG_DEBUG | \
WINDIVERT_FLAG_NO_INSTALL)
#define WINDIVERT_FLAGS_EXCLUDE(flags, flag1, flag2) \
(((flags) & ((flag1) | (flag2))) != ((flag1) | (flag2)))
#define WINDIVERT_FLAGS_VALID(flags) \
@@ -164,14 +167,24 @@
WINDIVERT_FLAGS_EXCLUDE(flags, WINDIVERT_FLAG_RECV_ONLY, \
WINDIVERT_FLAG_SEND_ONLY))
/*
* WinDivert filter flags.
*/
#define WINDIVERT_FILTER_FLAG_INBOUND 0x0000000000000001ull
#define WINDIVERT_FILTER_FLAG_OUTBOUND 0x0000000000000002ull
#define WINDIVERT_FILTER_FLAG_IP 0x0000000000000004ull
#define WINDIVERT_FILTER_FLAG_IPV6 0x0000000000000008ull
#define WINDIVERT_FILTER_FLAGS_ALL \
(WINDIVERT_FILTER_FLAG_INBOUND | WINDIVERT_FILTER_FLAG_OUTBOUND | \
WINDIVERT_FILTER_FLAG_IP | WINDIVERT_FILTER_FLAG_IPV6)
/*
* WinDivert priorities.
*/
#define WINDIVERT_PRIORITY(priority16) \
((UINT32)((INT32)(priority16) + 0x7FFF + 1))
#define WINDIVERT_PRIORITY_DEFAULT WINDIVERT_PRIORITY(0)
#define WINDIVERT_PRIORITY_MAX WINDIVERT_PRIORITY(1000)
#define WINDIVERT_PRIORITY_MIN WINDIVERT_PRIORITY(-1000)
#define WINDIVERT_PRIORITY_DEFAULT 0
#define WINDIVERT_PRIORITY_MAX 30000
#define WINDIVERT_PRIORITY_MIN -WINDIVERT_PRIORITY_MAX
/*
* WinDivert parameters.
@@ -190,27 +203,25 @@
* WinDivert message definitions.
*/
#pragma pack(push, 1)
struct windivert_ioctl_s
typedef struct
{
UINT16 magic; // WINDIVERT_IOCTL_MAGIC
UINT8 version; // WINDIVERT_IOCTL_VERSION
UINT8 arg8; // 8-bit argument
UINT64 arg; // 64-bit argument
};
typedef struct windivert_ioctl_s *windivert_ioctl_t;
} WINDIVERT_IOCTL, *PWINDIVERT_IOCTL;
/*
* WinDivert IOCTL structures.
*/
struct windivert_ioctl_filter_s
typedef struct
{
UINT8 field; // WINDIVERT_FILTER_FIELD_*
UINT8 test; // WINDIVERT_FILTER_TEST_*
UINT16 success; // Success continuation.
UINT16 failure; // Fail continuation.
UINT8 success; // Success continuation.
UINT8 failure; // Fail continuation.
UINT32 arg[4]; // Argument.
};
typedef struct windivert_ioctl_filter_s *windivert_ioctl_filter_t;
} WINDIVERT_FILTER, *PWINDIVERT_FILTER;
#pragma pack(pop)
/*
+5 -1
View File
@@ -59,7 +59,7 @@ do
fi
echo "BUILD MINGW-$CPU"
CC="$ENV-gcc"
COPTS="-shared -Wall -Wno-pointer-to-int-cast -O2 -Iinclude/
COPTS="-shared -Wall -Wno-pointer-to-int-cast -Os -Iinclude/
-Wl,--enable-stdcall-fixup -Wl,--entry=${MANGLE}WinDivertDllEntry"
CLIBS="-lgcc -lkernel32 -ladvapi32"
STRIP="$ENV-strip"
@@ -101,6 +101,10 @@ do
$CC -s -O2 -Iinclude/ examples/flowtrack/flowtrack.c \
-o "install/MINGW/$CPU/flowtrack.exe" -lWinDivert -lws2_32 -lpsapi \
-lshlwapi -L"install/MINGW/$CPU/"
echo "\tcopy install/MINGW/$CPU/windivertctl.exe..."
$CC -s -O2 -Iinclude/ examples/windivertctl/windivertctl.c \
-o "install/MINGW/$CPU/windivertctl.exe" -lWinDivert -lws2_32 \
-lpsapi -lshlwapi -L"install/MINGW/$CPU/"
echo "\tcopy install/MINGW/$CPU/WinDivert$BITS.sys..."
cp install/WDDK/$CPU/WinDivert$BITS.sys install/MINGW/$CPU
else
+1 -1
View File
@@ -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
+711 -395
View File
File diff suppressed because it is too large Load Diff
+14 -6
View File
@@ -241,6 +241,9 @@ static struct test tests[] =
"false): false): false): false)", &pkt_http_request, TRUE},
{"(outbound? (ip? (tcp.DstPort == 80? (tcp.PayloadLength == 0? true: "
"false): false): false): false)", &pkt_http_request, FALSE},
{"(ipv6? tcp and tcp.DstPort = 1234 and (tcp.SrcPort = 999? !tcp.UrgPtr: "
"tcp.Syn) or udp: ip and tcp.DstPort == 80)",
&pkt_http_request, TRUE},
{"udp", &pkt_dns_request, TRUE},
{"udp && udp.SrcPort > 1 && ipv6", &pkt_dns_request, FALSE},
{"udp.DstPort == 53", &pkt_dns_request, TRUE},
@@ -388,21 +391,26 @@ static BOOL run_test(HANDLE inject_handle, const char *filter,
OVERLAPPED overlapped;
const char *err_str;
UINT err_pos;
PWINDIVERT_IPHDR iphdr = NULL;
HANDLE handle = INVALID_HANDLE_VALUE, handle0 = INVALID_HANDLE_VALUE,
event = NULL;
// (0) Verify the test data:
if (!WinDivertHelperCheckFilter(filter, WINDIVERT_LAYER_NETWORK, &err_str,
&err_pos))
if (!WinDivertHelperCompileFilter(filter, WINDIVERT_LAYER_NETWORK,
NULL, 0, &err_str, &err_pos))
{
fprintf(stderr, "error: filter string \"%s\" is invalid with error "
"\"%s\" (position=%u)\n", filter, err_str, err_pos);
goto failed;
}
WinDivertHelperParsePacket((PVOID)packet, packet_len, &iphdr, NULL,
NULL, NULL, NULL, NULL, NULL, NULL);
memset(&addr, 0, sizeof(addr));
addr.Direction = WINDIVERT_DIRECTION_OUTBOUND;
if (WinDivertHelperEvalFilter(filter, WINDIVERT_LAYER_NETWORK,
(PVOID)packet, packet_len, &addr) != match)
addr.Outbound = TRUE;
addr.Layer = WINDIVERT_LAYER_NETWORK;
addr.IPv6 = (iphdr == NULL);
if (WinDivertHelperEvalFilter(filter, (PVOID)packet, packet_len, &addr)
!= match)
{
fprintf(stderr, "error: filter \"%s\" does not match the given "
"packet\n", filter);
@@ -481,7 +489,7 @@ read_failed:
}
buf_len = (UINT)iolen;
}
if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND)
if (addr.Outbound)
{
WinDivertHelperCalcChecksums(buf, buf_len, NULL, 0);
}