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

Adds a new SOCKET layer for monitoring socket
events, such as BIND, LISTEN, CONNECT,
and ACCEPT.  These events occur before the
flow is established (and unlike the FLOW layer)
it is possible to block/drop SOCKET events.

Otherwise, this layer is very similar to the
FLOW layer, so the PID is available and injection
is not possible.  This commit should be
considered to be a WIP.

Other changes:
- New socketdump.exe sample.  Prints socket
  events.
- Improve IPv6 address parsing.
- New helper functions:
  * WinDivertHelperFormatIPv4Address
  * WinDivertHelperFormatIPv6Address
- Fix REFLECT bugs.
- The network 5-tuple can now be accessed at
  the NETWORK layer.
- Various cleanups.
This commit is contained in:
basil00
2018-10-25 10:25:41 +08:00
parent 2ab1ddf1d2
commit fd75e6d42a
11 changed files with 1927 additions and 456 deletions
+1
View File
@@ -413,6 +413,7 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer,
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
case WINDIVERT_LAYER_FLOW:
case WINDIVERT_LAYER_SOCKET:
case WINDIVERT_LAYER_REFLECT:
break;
default:
+2
View File
@@ -13,6 +13,8 @@ EXPORTS
WinDivertHelperParsePacket
WinDivertHelperParseIPv4Address
WinDivertHelperParseIPv6Address
WinDivertHelperFormatIPv4Address
WinDivertHelperFormatIPv6Address
WinDivertHelperCompileFilter
WinDivertHelperEvalFilter
WinDivertHelperFormatFilter
+577 -349
View File
File diff suppressed because it is too large Load Diff
+10 -39
View File
@@ -1,5 +1,5 @@
/*
* streamdump.c
* flowtrack.c
* (C) 2018, all rights reserved,
*
* This file is part of WinDivert.
@@ -47,7 +47,8 @@
#include "windivert.h"
#define MAX_FLOWS 256
#define MAX_FLOWS 256
#define INET6_ADDRSTRLEN 45
/*
* Flow tracking.
@@ -61,39 +62,6 @@ typedef struct FLOW
static HANDLE lock;
static PFLOW flows = NULL;
/*
* Print an IP address.
*/
static void print_address(const UINT32 *addr)
{
if (addr[3] == 0 && addr[2] == 0 && addr[1] == 0x0000FFFF)
{
// IPv4 address:
UINT32 a, b, c, d;
a = (addr[0] >> 24) & 0xFF;
b = (addr[0] >> 16) & 0xFF;
c = (addr[0] >> 8) & 0xFF;
d = (addr[0] >> 0) & 0xFF;
printf("%u.%u.%u.%u", a, b, c, d);
}
else
{
// IPv6 address:
int i;
for (i = 3; i >= 0; i--)
{
UINT32 a, b;
a = (addr[i] >> 16) & 0xFFFF;
b = (addr[i] >> 0) & 0xFFFF;
printf("%x:%x", a, b);
if (i != 0)
{
putchar(':');
}
}
}
}
/*
* Draw flows to console in a delayed loop.
*
@@ -105,6 +73,7 @@ static DWORD draw(LPVOID arg)
HANDLE process, console = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO screen;
char path[MAX_PATH+1];
char addr_str[INET6_ADDRSTRLEN+1];
char *filename;
const char header[] = "PID PROGRAM PROT FLOW";
DWORD rows, columns, written, fill_len, path_len, i;
@@ -216,11 +185,13 @@ static DWORD draw(LPVOID arg)
}
SetConsoleTextAttribute(console,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
print_address(addr->Flow.LocalAddr);
printf(":%u %s ", addr->Flow.LocalPort,
WinDivertHelperFormatIPv6Address(addr->Flow.LocalAddr, addr_str,
sizeof(addr_str));
printf("%s:%u %s ", addr_str, addr->Flow.LocalPort,
(addr->Outbound? "---->": "<----"));
print_address(addr->Flow.RemoteAddr);
printf(":%u", addr->Flow.RemotePort);
WinDivertHelperFormatIPv6Address(addr->Flow.RemoteAddr, addr_str,
sizeof(addr_str));
printf("%s:%u", addr_str, addr->Flow.RemotePort);
fflush(stdout);
}
for (; i < rows-1; i++)
+10 -5
View File
@@ -49,7 +49,8 @@
#include "windivert.h"
#define MAXBUF 0xFFFF
#define MAXBUF 0xFFFF
#define INET6_ADDRSTRLEN 45
/*
* Entry.
@@ -68,6 +69,7 @@ int __cdecl main(int argc, char **argv)
PWINDIVERT_ICMPV6HDR icmpv6_header;
PWINDIVERT_TCPHDR tcp_header;
PWINDIVERT_UDPHDR udp_header;
char src_str[INET6_ADDRSTRLEN+1], dst_str[INET6_ADDRSTRLEN+1];
const char *err_str;
LARGE_INTEGER base, freq;
double time_passed;
@@ -166,16 +168,19 @@ int __cdecl main(int argc, char **argv)
FOREGROUND_GREEN | FOREGROUND_RED);
printf("IPv4 [Version=%u HdrLength=%u TOS=%u Length=%u Id=0x%.4X "
"Reserved=%u DF=%u MF=%u FragOff=%u TTL=%u Protocol=%u "
"Checksum=0x%.4X SrcAddr=%u.%u.%u.%u DstAddr=%u.%u.%u.%u]\n",
"Checksum=0x%.4X SrcAddr=%s DstAddr=%s]\n",
ip_header->Version, ip_header->HdrLength,
ntohs(ip_header->TOS), ntohs(ip_header->Length),
ntohs(ip_header->Id), WINDIVERT_IPHDR_GET_RESERVED(ip_header),
WINDIVERT_IPHDR_GET_DF(ip_header),
WINDIVERT_IPHDR_GET_MF(ip_header),
ntohs(WINDIVERT_IPHDR_GET_FRAGOFF(ip_header)), ip_header->TTL,
ip_header->Protocol, ntohs(ip_header->Checksum),
src_addr[0], src_addr[1], src_addr[2], src_addr[3],
dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3]);
ip_header->Protocol, ntohs(ip_header->Checksum));
WinDivertHelperFormatIPv4Address(ntohl(ip_header->SrcAddr),
src_str, sizeof(src_str));
WinDivertHelperFormatIPv4Address(ntohl(ip_header->DstAddr),
dst_str, sizeof(dst_str));
}
if (ipv6_header != NULL)
{
+210
View File
@@ -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 <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: socketdump.exe [filter]
*/
#include <winsock2.h>
#include <windows.h>
#include <psapi.h>
#include <shlwapi.h>
#include <stdio.h>
#include <stdlib.h>
#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;
}
+3
View File
@@ -315,6 +315,9 @@ usage:
case WINDIVERT_LAYER_FLOW:
fputs("FLOW", stdout);
break;
case WINDIVERT_LAYER_SOCKET:
fputs("SOCKET", stdout);
break;
case WINDIVERT_LAYER_REFLECT:
fputs("REFLECT", stdout);
break;
+39 -4
View File
@@ -77,7 +77,8 @@ typedef enum
WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */
WINDIVERT_LAYER_NETWORK_FORWARD = 1,/* Network layer (forwarded packets) */
WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */
WINDIVERT_LAYER_REFLECT = 3, /* Reflect layer. */
WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */
WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */
} WINDIVERT_LAYER, *PWINDIVERT_LAYER;
/*
@@ -102,6 +103,19 @@ typedef struct
UINT8 Protocol; /* Protocol. */
} WINDIVERT_FLOW_DATA, *PWINDIVERT_FLOW_DATA;
/*
* WinDivert SOCKET layer data.
*/
typedef struct
{
UINT32 ProcessId; /* Process ID. */
UINT32 LocalAddr[4]; /* Local address. */
UINT32 RemoteAddr[4]; /* Remote address. */
UINT16 LocalPort; /* Local port. */
UINT16 RemotePort; /* Remote port. */
UINT8 Protocol; /* Protocol. */
} WINDIVERT_SOCKET_DATA, *PWINDIVERT_SOCKET_DATA;
/*
* WinDivert REFLECTION layer data.
*/
@@ -135,6 +149,7 @@ typedef struct
{
WINDIVERT_NETWORK_DATA Network; /* Network layer data. */
WINDIVERT_FLOW_DATA Flow; /* Flow layer data. */
WINDIVERT_SOCKET_DATA Socket; /* Socket layer data. */
WINDIVERT_REFLECT_DATA Reflect; /* Reflect layer data. */
};
} WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
@@ -148,10 +163,14 @@ typedef enum
WINDIVERT_EVENT_FLOW_ESTABLISHED = 1,
/* Flow established. */
WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */
WINDIVERT_EVENT_REFLECT_ESTABLISHED = 3,
WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */
WINDIVERT_EVENT_SOCKET_CONNECT = 4, /* Socket connect. */
WINDIVERT_EVENT_SOCKET_LISTEN = 5, /* Socket listen. */
WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */
WINDIVERT_EVENT_REFLECT_ESTABLISHED = 7,
/* Previously open WinDivert handle. */
WINDIVERT_EVENT_REFLECT_OPEN = 4, /* Open new WinDivert handle. */
WINDIVERT_EVENT_REFLECT_CLOSE = 5, /* Close existing WinDivert handle. */
WINDIVERT_EVENT_REFLECT_OPEN = 8, /* Open new WinDivert handle. */
WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* Close existing WinDivert handle. */
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
/*
@@ -434,6 +453,22 @@ extern WINDIVERTEXPORT BOOL WinDivertHelperParseIPv6Address(
__in const char *addrStr,
__out_opt UINT32 *pAddr);
/*
* Format an IPv4 address.
*/
extern WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv4Address(
__in UINT32 addr,
__out char *buffer,
__in UINT bufLen);
/*
* Format an IPv6 address.
*/
extern WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv6Address(
__in const UINT32 *pAddr,
__out char *buffer,
__in UINT bufLen);
/*
* Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums.
*/
+4
View File
@@ -105,6 +105,10 @@ do
$CC -s -O2 -Iinclude/ examples/windivertctl/windivertctl.c \
-o "install/MINGW/$CPU/windivertctl.exe" -lWinDivert -lws2_32 \
-lpsapi -lshlwapi -L"install/MINGW/$CPU/"
echo "\tcopy install/MINGW/$CPU/socketdump.exe..."
$CC -s -O2 -Iinclude/ examples/socketdump/socketdump.c \
-o "install/MINGW/$CPU/socketdump.exe" -lWinDivert -lws2_32 \
-lpsapi -lshlwapi -L"install/MINGW/$CPU/"
echo "\tcopy install/MINGW/$CPU/WinDivert$BITS.sys..."
cp install/WDDK/$CPU/WinDivert$BITS.sys install/MINGW/$CPU
else
+1062 -58
View File
File diff suppressed because it is too large Load Diff
+9 -1
View File
@@ -257,6 +257,8 @@ static struct test tests[] =
&pkt_dns_request, TRUE},
{"ip.SrcAddr < 10.0.0.0 or ip.SrcAddr > 10.255.255.255",
&pkt_dns_request, FALSE},
{"ip.DstAddr == ::ffff:8.8.4.4", &pkt_dns_request, TRUE},
{"ip.DstAddr == ::0:ffff:8.8.4.4", &pkt_dns_request, TRUE},
{"udp.PayloadLength == 29", &pkt_dns_request, TRUE},
{"ipv6", &pkt_ipv6_tcp_syn, TRUE},
{"ip", &pkt_ipv6_tcp_syn, FALSE},
@@ -284,8 +286,10 @@ static struct test tests[] =
{"false", &pkt_ipv6_exthdrs_udp, FALSE},
{"udp", &pkt_ipv6_exthdrs_udp, TRUE},
{"tcp", &pkt_ipv6_exthdrs_udp, FALSE},
{"ipv6.SrcAddr == ::", &pkt_ipv6_exthdrs_udp, FALSE},
{"ipv6.SrcAddr == ::1", &pkt_ipv6_exthdrs_udp, TRUE},
{"ipv6.SrcAddr == ::2", &pkt_ipv6_exthdrs_udp, FALSE},
{"ipv6.SrcAddr == ::8.8.4.4", &pkt_ipv6_exthdrs_udp, FALSE},
{"ipv6.SrcAddr < abcd::1", &pkt_ipv6_exthdrs_udp, TRUE},
{"ipv6.SrcAddr <= abcd::1", &pkt_ipv6_exthdrs_udp, TRUE},
{"ipv6.SrcAddr != abcd::1", &pkt_ipv6_exthdrs_udp, TRUE},
@@ -332,7 +336,7 @@ int main(void)
Sleep(100);
// Run tests:
size_t num_tests = sizeof(tests) / sizeof(struct test);
size_t num_tests = sizeof(tests) / sizeof(struct test), passed_tests = 0;
for (i = 0; i < num_tests; i++)
{
char *filter = tests[i].filter;
@@ -352,6 +356,7 @@ int main(void)
{
SetConsoleTextAttribute(console, FOREGROUND_GREEN);
printf("PASSED");
passed_tests++;
}
else
{
@@ -376,6 +381,9 @@ int main(void)
WinDivertClose(upper_handle);
WinDivertClose(lower_handle);
printf("\npassed = %.2f%%\n",
((double)passed_tests / (double)num_tests) * 100.0);
return 0;
}