Implement new packet parser(s) for WinDivert.

The new parser should better handle fragments
as well as be consistent with the kernel-mode
parser.  The new parser can also handle truncated
packets.
This commit is contained in:
basil00
2019-08-12 07:50:49 +08:00
parent 6501bec357
commit 317e6f1099
10 changed files with 525 additions and 260 deletions
+2
View File
@@ -308,3 +308,5 @@ WinDivert 2.1.0
- Fix BSOD caused by packets with missing or incomplete transport
headers (introduced in 2.0.0).
- Fix missing Flow.EndpointId and Flow.ParentEndpointId for IPv6 flows.
WinDivert 2.2.0
- Implement new packet parser that correctly handles IP fragments.
+1 -1
View File
@@ -1 +1 @@
2.1.0
2.2.0
+2
View File
@@ -85,6 +85,8 @@ static UINT32 WinDivertDivTen128(UINT32 *a);
#define UINT32_MAX 0xFFFFFFFF
#endif
#define IPPROTO_MH 135
#ifdef _MSC_VER
#pragma intrinsic(memcpy)
+70 -2
View File
@@ -496,11 +496,79 @@ static PTOKEN_INFO WinDivertTokenLookup(PTOKEN_INFO token_info,
return NULL;
}
/*
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
*/
extern BOOL WinDivertHelperParsePacket(const VOID *pPacket, UINT packetLen,
PWINDIVERT_IPHDR *ppIPHeader, PWINDIVERT_IPV6HDR *ppIPv6Header,
UINT8 *pProtocol, PWINDIVERT_ICMPHDR *ppICMPHeader,
PWINDIVERT_ICMPV6HDR *ppICMPv6Header, PWINDIVERT_TCPHDR *ppTCPHeader,
PWINDIVERT_UDPHDR *ppUDPHeader, PVOID *ppData, UINT *pDataLen,
PVOID *ppNext, UINT *pNextLen)
{
WINDIVERT_PACKET info;
if (!WinDivertHelperParsePacketEx(pPacket, packetLen, &info))
{
return FALSE;
}
if (info.Truncated)
{
return FALSE;
}
if (pProtocol != NULL)
{
*pProtocol = info.Protocol;
}
if (ppIPHeader != NULL)
{
*ppIPHeader = info.IPHeader;
}
if (ppIPv6Header != NULL)
{
*ppIPv6Header = info.IPv6Header;
}
if (ppICMPHeader != NULL)
{
*ppICMPHeader = info.ICMPHeader;
}
if (ppICMPv6Header != NULL)
{
*ppICMPv6Header = info.ICMPv6Header;
}
if (ppTCPHeader != NULL)
{
*ppTCPHeader = info.TCPHeader;
}
if (ppUDPHeader != NULL)
{
*ppUDPHeader = info.UDPHeader;
}
if (ppData != NULL)
{
*ppData = info.Payload;
}
if (pDataLen != NULL)
{
*pDataLen = info.PayloadLength;
}
if (ppNext != NULL)
{
*ppNext = (info.Extended? (PVOID)((UINT8 *)pPacket + packetLen): NULL);
}
if (pNextLen != NULL)
{
*pNextLen = (info.Extended?
packetLen - (info.HeaderLength + info.PayloadLength): 0);
}
return TRUE;
}
/*
* Expand a "macro" value.
*/
static BOOL WinDivertExpandMacro(KIND kind, WINDIVERT_LAYER layer,
UINT32 *val)
static BOOL WinDivertExpandMacro(KIND kind, WINDIVERT_LAYER layer, UINT32 *val)
{
switch (kind)
{
+192 -178
View File
@@ -73,6 +73,21 @@ static UINT64 WinDivertMul64(UINT64 a, UINT64 b)
#define WINDIVERT_MUL64(a, b) ((a) * (b))
#endif /* WIN32 */
/*
* IPv6 fragment header.
*/
typedef struct
{
UINT8 NextHdr;
UINT8 Reserved;
UINT16 FragOff0;
UINT32 Id;
} WINDIVERT_IPV6FRAGHDR, *PWINDIVERT_IPV6FRAGHDR;
#define WINDIVERT_IPV6FRAGHDR_GET_FRAGOFF(hdr) \
(((hdr)->FragOff0) & 0xF8FF)
#define WINDIVERT_IPV6FRAGHDR_GET_MF(hdr) \
((((hdr)->FragOff0) & 0x0100) != 0)
#include "windivert_hash.c"
/*
@@ -96,6 +111,29 @@ typedef struct
UINT32 NextHdr:8;
} WINDIVERT_PSEUDOV6HDR, *PWINDIVERT_PSEUDOV6HDR;
/*
* Packet info.
*/
typedef struct
{
UINT32 HeaderLength:17;
UINT32 FragOff:13;
UINT32 Fragment:1;
UINT32 MF:1;
UINT32 PayloadLength:16;
UINT32 Protocol:8;
UINT32 Truncated:1;
UINT32 Extended:1;
UINT32 Reserved1:6;
PWINDIVERT_IPHDR IPHeader;
PWINDIVERT_IPV6HDR IPv6Header;
PWINDIVERT_ICMPHDR ICMPHeader;
PWINDIVERT_ICMPV6HDR ICMPv6Header;
PWINDIVERT_TCPHDR TCPHeader;
PWINDIVERT_UDPHDR UDPHeader;
UINT8 *Payload;
} WINDIVERT_PACKET, *PWINDIVERT_PACKET;
/*
* Streams.
*/
@@ -283,61 +321,11 @@ static void WinDivertSerializeFilter(PWINDIVERT_STREAM stream,
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.
*/
extern BOOL WinDivertHelperParsePacket(const VOID *pPacket, UINT packetLen,
PWINDIVERT_IPHDR *ppIpHdr, PWINDIVERT_IPV6HDR *ppIpv6Hdr, UINT8 *pProtocol,
PWINDIVERT_ICMPHDR *ppIcmpHdr, PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr,
PWINDIVERT_TCPHDR *ppTcpHdr, PWINDIVERT_UDPHDR *ppUdpHdr, PVOID *ppData,
UINT *pDataLen, PVOID *ppNext, UINT *pNextLen)
static BOOL WinDivertHelperParsePacketEx(const VOID *pPacket, UINT packetLen,
PWINDIVERT_PACKET pInfo)
{
PWINDIVERT_IPHDR ip_header = NULL;
PWINDIVERT_IPV6HDR ipv6_header = NULL;
@@ -345,183 +333,181 @@ extern BOOL WinDivertHelperParsePacket(const VOID *pPacket, UINT packetLen,
PWINDIVERT_ICMPV6HDR icmpv6_header = NULL;
PWINDIVERT_TCPHDR tcp_header = NULL;
PWINDIVERT_UDPHDR udp_header = NULL;
UINT16 header_len;
PWINDIVERT_IPV6FRAGHDR frag_header;
UINT8 protocol = 0;
PVOID data = NULL, next = NULL;
UINT data_len = 0, next_len = 0, packet_len;
BOOL success = FALSE;
UINT8 *data = NULL;
UINT packet_len, total_len, header_len, data_len = 0, frag_off = 0;
BOOL MF = FALSE, fragment = FALSE, is_ext_header;
if (pPacket == NULL || packetLen < sizeof(WINDIVERT_IPHDR))
{
goto WinDivertHelperParsePacketExit;
return FALSE;
}
data = (PVOID)pPacket;
data = (UINT8 *)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)
if (packetLen < sizeof(WINDIVERT_IPHDR) ||
ip_header->HdrLength < 5)
{
ip_header = NULL;
goto WinDivertHelperParsePacketExit;
return FALSE;
}
packet_len = (UINT)ntohs(ip_header->Length);
header_len = ip_header->HdrLength*sizeof(UINT32);
protocol = ip_header->Protocol;
if (data_len < header_len || data_len < packet_len ||
packet_len < header_len)
total_len = (UINT)ntohs(ip_header->Length);
protocol = ip_header->Protocol;
header_len = ip_header->HdrLength * sizeof(UINT32);
if (total_len < header_len || packetLen < header_len)
{
ip_header = NULL;
goto WinDivertHelperParsePacketExit;
return FALSE;
}
else if (packet_len < data_len)
{
next = (PVOID)((UINT8 *)data + packet_len);
next_len = data_len - packet_len;
}
data = (PVOID)((UINT8 *)data + header_len);
data_len = packet_len - header_len;
frag_off = ntohs(WINDIVERT_IPHDR_GET_FRAGOFF(ip_header));
MF = (WINDIVERT_IPHDR_GET_MF(ip_header) != 0);
fragment = (MF || frag_off != 0);
packet_len = (total_len < packetLen? total_len: packetLen);
data += header_len;
data_len = packet_len - header_len;
break;
case 6:
ip_header = NULL;
ip_header = NULL;
ipv6_header = (PWINDIVERT_IPV6HDR)data;
if (data_len < sizeof(WINDIVERT_IPV6HDR) ||
data_len < ntohs(ipv6_header->Length) +
sizeof(WINDIVERT_IPV6HDR))
if (packetLen < sizeof(WINDIVERT_IPV6HDR))
{
ipv6_header = NULL;
goto WinDivertHelperParsePacketExit;
return FALSE;
}
protocol = ipv6_header->NextHdr;
packet_len = ntohs(ipv6_header->Length) + sizeof(WINDIVERT_IPV6HDR);
if (packet_len < data_len)
protocol = ipv6_header->NextHdr;
total_len = (UINT)ntohs(ipv6_header->Length) +
sizeof(WINDIVERT_IPV6HDR);
packet_len = (total_len < packetLen? total_len: packetLen);
data += sizeof(WINDIVERT_IPV6HDR);
data_len = packet_len - sizeof(WINDIVERT_IPV6HDR);
while (frag_off == 0 && data_len >= 2)
{
next = (PVOID)((UINT8 *)data + packet_len);
next_len = data_len - packet_len;
header_len = (UINT)data[1];
is_ext_header = TRUE;
switch (protocol)
{
case IPPROTO_FRAGMENT:
header_len = 8;
if (fragment || data_len < header_len)
{
is_ext_header = FALSE;
break;
}
frag_header = (PWINDIVERT_IPV6FRAGHDR)data;
frag_off = ntohs(
WINDIVERT_IPV6FRAGHDR_GET_FRAGOFF(frag_header));
MF = WINDIVERT_IPV6FRAGHDR_GET_MF(frag_header);
fragment = TRUE;
break;
case IPPROTO_AH:
header_len += 2;
header_len *= 4;
break;
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
case IPPROTO_MH:
header_len++;
header_len *= 8;
break;
default:
is_ext_header = FALSE;
break;
}
if (!is_ext_header || data_len < header_len)
{
break;
}
protocol = data[0];
data += header_len;
data_len -= header_len;
}
data = (PVOID)((UINT8 *)data + sizeof(WINDIVERT_IPV6HDR));
data_len = packet_len - sizeof(WINDIVERT_IPV6HDR);
protocol = WinDivertSkipExtHeaders(protocol, (UINT8 **)&data,
&data_len);
break;
default:
ip_header = NULL;
goto WinDivertHelperParsePacketExit;
return FALSE;
}
if (frag_off != 0)
{
goto WinDivertHelperParsePacketExit;
}
data = (data_len == 0? NULL: data);
success = TRUE;
switch (protocol)
{
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->HdrLength < 5)
{
tcp_header = NULL;
goto WinDivertHelperParsePacketExit;
}
header_len = tcp_header->HdrLength*sizeof(UINT32);
data = ((UINT8 *)data + header_len);
data_len -= header_len;
header_len = tcp_header->HdrLength * sizeof(UINT32);
header_len = (header_len > data_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)
if (data_len < sizeof(WINDIVERT_UDPHDR))
{
udp_header = NULL;
goto WinDivertHelperParsePacketExit;
}
data = ((UINT8 *)data + sizeof(WINDIVERT_UDPHDR));
data_len -= sizeof(WINDIVERT_UDPHDR);
udp_header = (PWINDIVERT_UDPHDR)data;
header_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);
icmp_header = (PWINDIVERT_ICMPHDR)data;
header_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);
icmpv6_header = (PWINDIVERT_ICMPV6HDR)data;
header_len = sizeof(WINDIVERT_ICMPV6HDR);
break;
default:
break;
}
if (data_len == 0)
{
data = NULL;
default:
goto WinDivertHelperParsePacketExit;
}
data += header_len;
data_len -= header_len;
WinDivertHelperParsePacketExit:
if (pProtocol != NULL)
if (pInfo == NULL)
{
*pProtocol = protocol;
return TRUE;
}
if (ppIpHdr != NULL)
{
*ppIpHdr = ip_header;
}
if (ppIpv6Hdr != NULL)
{
*ppIpv6Hdr = ipv6_header;
}
if (ppIcmpHdr != NULL)
{
*ppIcmpHdr = icmp_header;
}
if (ppIcmpv6Hdr != NULL)
{
*ppIcmpv6Hdr = icmpv6_header;
}
if (ppTcpHdr != NULL)
{
*ppTcpHdr = tcp_header;
}
if (ppUdpHdr != NULL)
{
*ppUdpHdr = udp_header;
}
if (ppData != NULL)
{
*ppData = data;
}
if (pDataLen != NULL)
{
*pDataLen = data_len;
}
if (ppNext != NULL)
{
*ppNext = next;
}
if (pNextLen != NULL)
{
*pNextLen = next_len;
}
if (ppNext == NULL && pNextLen == NULL && next != NULL)
{
success = FALSE;
}
return success;
data = (data_len == 0? NULL: data);
pInfo->Protocol = (UINT32)protocol;
pInfo->Fragment = (fragment? 1: 0);
pInfo->MF = (MF? 1: 0);
pInfo->FragOff = (UINT32)frag_off;
pInfo->Truncated = (total_len < packetLen? 1: 0);
pInfo->Extended = (total_len > packetLen? 1: 0);
pInfo->Reserved1 = 0;
pInfo->IPHeader = ip_header;
pInfo->IPv6Header = ipv6_header;
pInfo->ICMPHeader = icmp_header;
pInfo->ICMPv6Header = icmpv6_header;
pInfo->TCPHeader = tcp_header;
pInfo->UDPHeader = udp_header;
pInfo->Payload = data;
pInfo->HeaderLength = (UINT32)(packet_len - data_len);
pInfo->PayloadLength = (UINT32)data_len;
return TRUE;
}
/*
@@ -539,44 +525,59 @@ extern BOOL WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
PWINDIVERT_ICMPV6HDR icmpv6_header;
PWINDIVERT_TCPHDR tcp_header;
PWINDIVERT_UDPHDR udp_header;
WINDIVERT_PACKET info;
UINT payload_len, checksum_len;
BOOL truncated;
if (!WinDivertHelperParsePacket(pPacket, packetLen, &ip_header,
&ipv6_header, NULL, &icmp_header, &icmpv6_header, &tcp_header,
&udp_header, NULL, &payload_len, NULL, NULL))
if (!WinDivertHelperParsePacketEx(pPacket, packetLen, &info))
{
return FALSE;
}
ip_header = info.IPHeader;
if (ip_header != NULL && !(flags & WINDIVERT_HELPER_NO_IP_CHECKSUM))
{
ip_header->Checksum = 0;
ip_header->Checksum = WinDivertCalcChecksum(NULL, 0, ip_header,
ip_header->HdrLength*sizeof(UINT32));
ip_header->HdrLength * sizeof(UINT32));
if (pAddr != NULL)
{
pAddr->IPChecksum = 1;
}
}
payload_len = info.PayloadLength;
truncated = (info.Truncated || info.MF || info.FragOff != 0);
icmp_header = info.ICMPHeader;
if (icmp_header != NULL)
{
if ((flags & WINDIVERT_HELPER_NO_ICMP_CHECKSUM) != 0)
{
return TRUE;
}
if (truncated)
{
return FALSE;
}
icmp_header->Checksum = 0;
icmp_header->Checksum = WinDivertCalcChecksum(NULL, 0,
icmp_header, payload_len + sizeof(WINDIVERT_ICMPHDR));
return TRUE;
}
icmpv6_header = info.ICMPv6Header;
if (icmpv6_header != NULL)
{
if ((flags & WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM) != 0)
{
return TRUE;
}
if (truncated)
{
return FALSE;
}
ipv6_header = info.IPv6Header;
checksum_len = payload_len + sizeof(WINDIVERT_ICMPV6HDR);
pseudo_header_len = WinDivertInitPseudoHeader(NULL, ipv6_header,
IPPROTO_ICMPV6, checksum_len, pseudo_header);
@@ -585,14 +586,20 @@ extern BOOL WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
pseudo_header_len, icmpv6_header, checksum_len);
return TRUE;
}
tcp_header = info.TCPHeader;
if (tcp_header != NULL)
{
if ((flags & WINDIVERT_HELPER_NO_TCP_CHECKSUM) != 0)
{
return TRUE;
}
checksum_len = payload_len + tcp_header->HdrLength*sizeof(UINT32);
if (truncated)
{
return FALSE;
}
checksum_len = payload_len + tcp_header->HdrLength * sizeof(UINT32);
ipv6_header = info.IPv6Header;
pseudo_header_len = WinDivertInitPseudoHeader(ip_header,
ipv6_header, IPPROTO_TCP, checksum_len, pseudo_header);
tcp_header->Checksum = 0;
@@ -604,15 +611,21 @@ extern BOOL WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
}
return TRUE;
}
udp_header = info.UDPHeader;
if (udp_header != NULL)
{
if ((flags & WINDIVERT_HELPER_NO_UDP_CHECKSUM) != 0)
{
return TRUE;
}
if (truncated)
{
return FALSE;
}
// Full UDP checksum
checksum_len = payload_len + sizeof(WINDIVERT_UDPHDR);
ipv6_header = info.IPv6Header;
pseudo_header_len = WinDivertInitPseudoHeader(ip_header,
ipv6_header, IPPROTO_UDP, checksum_len, pseudo_header);
udp_header->Checksum = 0;
@@ -626,6 +639,7 @@ extern BOOL WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
{
pAddr->UDPChecksum = 1;
}
return TRUE;
}
return TRUE;
+1 -1
View File
@@ -45,7 +45,7 @@
#include "windivert.h"
#define WINDIVERT_VERSION_MAJOR 2
#define WINDIVERT_VERSION_MINOR 1
#define WINDIVERT_VERSION_MINOR 2
#define WINDIVERT_MAGIC_DLL 0x4C4C447669645724ull
#define WINDIVERT_MAGIC_SYS 0x5359537669645723ull
+111 -68
View File
@@ -289,6 +289,7 @@ typedef struct flow_s *flow_t;
#define UINT8_MAX 0xFF
#define UINT16_MAX 0xFFFF
#define UINT32_MAX 0xFFFFFFFF
#define IPPROTO_MH 135
/*
* Global state.
@@ -5284,8 +5285,8 @@ static BOOL windivert_lookup_data(PNET_BUFFER buffer, UINT offset, INT idx,
/*
* Parse packet headers.
*/
static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
BOOL frag_mode, PWINDIVERT_IPHDR *ip_header_ptr,
static __forceinline BOOL windivert_parse_headers(PNET_BUFFER buffer,
BOOL ipv4, BOOL frag_mode, 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,
@@ -5298,7 +5299,9 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
PWINDIVERT_ICMPV6HDR icmpv6_header = NULL;
PWINDIVERT_TCPHDR tcp_header = NULL;
PWINDIVERT_UDPHDR udp_header = NULL;
UINT8 proto = 0;
PWINDIVERT_IPV6FRAGHDR frag_header;
UINT8 protocol = 0;
UINT16 frag_off = 0;
UINT header_len = 0;
NTSTATUS status;
@@ -5340,14 +5343,14 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
DEBUG("FILTER: REJECT (bad IPv4 packet)");
return FALSE;
}
frag_off = RtlUshortByteSwap(WINDIVERT_IPHDR_GET_FRAGOFF(ip_header));
if (!frag_mode &&
(WINDIVERT_IPHDR_GET_MF(ip_header) != 0 ||
WINDIVERT_IPHDR_GET_FRAGOFF(ip_header) != 0))
(WINDIVERT_IPHDR_GET_MF(ip_header) != 0 || frag_off != 0))
{
DEBUG("FILTER: REJECT (fragment)");
return FALSE;
}
proto = ip_header->Protocol;
protocol = ip_header->Protocol;
NdisAdvanceNetBufferDataStart(buffer, ip_header_len, FALSE, NULL);
}
else
@@ -5374,26 +5377,32 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
DEBUG("FILTER: REJECT (bad IPv6 packet)");
return FALSE;
}
proto = ipv6_header->NextHdr;
protocol = ipv6_header->NextHdr;
NdisAdvanceNetBufferDataStart(buffer, ip_header_len, FALSE, NULL);
// Skip extension headers:
while (TRUE)
frag_header = NULL;
while (frag_off == 0)
{
UINT8 *ext_header;
UINT ext_header_len;
BOOL isexthdr = TRUE;
ext_header = (UINT8 *)NdisGetDataBuffer(buffer, 2, NULL, 1, 0);
if (ext_header == NULL)
{
break;
}
ext_header_len = (UINT)ext_header[1];
switch (proto)
UINT8 *ext_header = NULL;
UINT ext_header_len = 0;
BOOL is_ext_header;
switch (protocol)
{
case IPPROTO_FRAGMENT:
if (frag_header != NULL)
{
is_ext_header = FALSE;
break;
}
frag_header = (PWINDIVERT_IPV6FRAGHDR)
NdisGetDataBuffer(buffer, 8, NULL, 1, 0);
ext_header = (UINT8 *)frag_header;
if (frag_header == NULL)
{
is_ext_header = FALSE;
break;
}
if (!frag_mode)
{
DEBUG("FILTER: REJECT (fragment)");
@@ -5401,36 +5410,48 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
0, NULL);
return FALSE;
}
frag_off = RtlUshortByteSwap(
WINDIVERT_IPV6FRAGHDR_GET_FRAGOFF(frag_header));
ext_header_len = 8;
is_ext_header = TRUE;
break;
case IPPROTO_AH:
ext_header_len += 2;
ext_header_len *= 4;
break;
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
ext_header_len++;
ext_header_len *= 8;
case IPPROTO_MH:
ext_header = (UINT8 *)NdisGetDataBuffer(buffer, 2, NULL,
1, 0);
if (ext_header == NULL)
{
is_ext_header = FALSE;
break;
}
ext_header_len = (UINT)ext_header[1];
if (protocol == IPPROTO_AH)
{
ext_header_len += 2;
ext_header_len *= 4;
}
else
{
ext_header_len++;
ext_header_len *= 8;
}
is_ext_header = TRUE;
break;
default:
isexthdr = FALSE;
is_ext_header = FALSE;
break;
}
if (!isexthdr)
if (!is_ext_header || ip_header_len + ext_header_len > total_len)
{
break;
}
proto = ext_header[0];
if (ip_header_len + ext_header_len > total_len)
{
DEBUG("FILTER: REJECT (bad IPv6 extension header)");
NdisRetreatNetBufferDataStart(buffer, ip_header_len,
0, NULL);
return FALSE;
}
protocol = ext_header[0];
ip_header_len += ext_header_len;
NdisAdvanceNetBufferDataStart(buffer, ext_header_len, FALSE,
NULL);
@@ -5438,42 +5459,64 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
}
header_len = ip_header_len;
switch (proto)
if (frag_off == 0)
{
case IPPROTO_ICMP:
icmp_header = (PWINDIVERT_ICMPHDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_ICMPHDR), NULL, 1, 0);
header_len += (icmp_header == NULL? 0: sizeof(WINDIVERT_ICMPHDR));
break;
case IPPROTO_ICMPV6:
icmpv6_header = (PWINDIVERT_ICMPV6HDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_ICMPV6HDR), NULL, 1, 0);
header_len +=
(icmpv6_header == NULL? 0: sizeof(WINDIVERT_ICMPV6HDR));
break;
case IPPROTO_TCP:
tcp_header = (PWINDIVERT_TCPHDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_TCPHDR), NULL, 1, 0);
if (tcp_header != NULL)
{
UINT tcp_header_len = tcp_header->HdrLength * sizeof(UINT32);
if (header_len + tcp_header_len > total_len)
switch (protocol)
{
case IPPROTO_ICMP:
if (ip_header == NULL)
{
// Bad TCP options:
tcp_header = NULL;
break;
}
header_len += tcp_header_len;
}
break;
case IPPROTO_UDP:
udp_header = (PWINDIVERT_UDPHDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_UDPHDR), NULL, 1, 0);
header_len += (udp_header == NULL? 0: sizeof(WINDIVERT_UDPHDR));
break;
default:
break;
icmp_header = (PWINDIVERT_ICMPHDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_ICMPHDR), NULL, 1, 0);
header_len +=
(icmp_header == NULL? 0: sizeof(WINDIVERT_ICMPHDR));
break;
case IPPROTO_ICMPV6:
if (ipv6_header == NULL)
{
break;
}
icmpv6_header = (PWINDIVERT_ICMPV6HDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_ICMPV6HDR), NULL, 1, 0);
header_len +=
(icmpv6_header == NULL? 0: sizeof(WINDIVERT_ICMPV6HDR));
break;
case IPPROTO_TCP:
tcp_header = (PWINDIVERT_TCPHDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_TCPHDR), NULL, 1, 0);
if (tcp_header != NULL)
{
if (tcp_header->HdrLength < 5)
{
tcp_header = NULL;
}
else
{
UINT tcp_header_len =
tcp_header->HdrLength * sizeof(UINT32);
tcp_header_len =
(header_len + tcp_header_len > total_len?
total_len - header_len: tcp_header_len);
header_len += tcp_header_len;
}
}
break;
case IPPROTO_UDP:
udp_header = (PWINDIVERT_UDPHDR)NdisGetDataBuffer(buffer,
sizeof(WINDIVERT_UDPHDR), NULL, 1, 0);
header_len +=
(udp_header == NULL? 0: sizeof(WINDIVERT_UDPHDR));
break;
default:
break;
}
}
status = NdisRetreatNetBufferDataStart(buffer, ip_header_len, 0, NULL);
if (!NT_SUCCESS(status))
{
@@ -5488,7 +5531,7 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4,
*icmpv6_header_ptr = icmpv6_header;
*tcp_header_ptr = tcp_header;
*udp_header_ptr = udp_header;
*proto_ptr = proto;
*proto_ptr = protocol;
*header_len_ptr = header_len;
*payload_len_ptr = total_len - header_len;
+4 -4
View File
@@ -38,20 +38,20 @@
#define VER_FILETYPE VFT_DRV
#define VER_FILESUBTYPE VFT2_DRV_NETWORK
#define VER_FILEDESCRIPTION_STR \
"The WinDivert 2.0 driver " \
"The WinDivert 2.2 driver " \
"[URL: https://reqrypt.org/windivert.html] " \
"[Bitcoin: 1C5vZVSbizPeZ8ydTYhUfm4LA2cNwBfcYh]"
#define VER_INTERNALNAME_STR "WinDivert.sys"
#define VER_ORIGINALFILENAME_STR "WinDivert.sys"
#define VER_PRODUCTVERSION 2.1
#define VER_PRODUCTVERSION_STR "2.1"
#define VER_PRODUCTVERSION 2.2
#define VER_PRODUCTVERSION_STR "2.2"
#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 2.0 driver"
#define VER_PRODUCTNAME_STR "WinDivert 2.2 driver"
#include "common.ver"
+89 -6
View File
@@ -43,6 +43,7 @@
#include "windivert.h"
#define MAX_PACKET 2048
#define MIN(a, b) ((a) < (b)? (a): (b))
/*
* Packet data.
@@ -112,6 +113,30 @@ static const struct packet pkt_ipv6_exthdrs_udp =
sizeof(ipv6_exthdrs_udp),
"ipv6_exthdrs_udp"
};
static const struct packet pkt_ipv4_fragment_0 =
{
ipv4_fragment_0,
sizeof(ipv4_fragment_0),
"ipv4_fragemnt_0"
};
static const struct packet pkt_ipv4_fragment_1 =
{
ipv4_fragment_1,
sizeof(ipv4_fragment_1),
"ipv4_fragment_1"
};
static const struct packet pkt_ipv6_fragment_0 =
{
ipv6_fragment_0,
sizeof(ipv6_fragment_0),
"ipv6_fragment_0"
};
static const struct packet pkt_ipv6_fragment_1 =
{
ipv6_fragment_1,
sizeof(ipv6_fragment_1),
"ipv6_fragment_1"
};
static const struct test tests[] =
{
{"event = PACKET", &pkt_echo_request, TRUE},
@@ -309,6 +334,9 @@ static const struct test tests[] =
{"localAddr == 10.0.0.1 && remoteAddr == 8.8.8.8 && localPort == 8 && "
"remotePort == 0 && protocol == 1", &pkt_echo_request, TRUE},
{"packet[0] == 0x45", &pkt_echo_request, TRUE},
{"ip.MF or ip.FragOff != 0", &pkt_echo_request, FALSE},
{"icmp.Body != 123 || icmp.Body == 123", &pkt_echo_request, TRUE},
{"length == 84 && ip.Length == 84", &pkt_echo_request, TRUE},
{"tcp", &pkt_http_request, TRUE},
{"protocol == TCP", &pkt_http_request, TRUE},
{"outbound and tcp and tcp.DstPort == 80", &pkt_http_request, TRUE},
@@ -720,6 +748,7 @@ static const 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},
{"length == 104 && ipv6.Length == 64", &pkt_ipv6_echo_reply, TRUE},
{"ip and !loopback and (outbound? tcp.DstPort == 80 or"
" tcp.DstPort == 443 or udp.DstPort == 53 :"
" icmp.Type == 11 and icmp.Code == 0)", &pkt_ipv6_echo_reply, FALSE},
@@ -855,12 +884,47 @@ static const struct test tests[] =
&pkt_ipv6_exthdrs_udp, FALSE},
{"localAddr == ::1 and remoteAddr == 1 and localPort == 4660 and "
"remotePort == 43690 and protocol == 17", &pkt_ipv6_exthdrs_udp, TRUE},
{"ip.MF or ip.FragOff != 0", &pkt_ipv4_fragment_0, TRUE},
{"icmp", &pkt_ipv4_fragment_0, TRUE},
{"icmp.Body != 123 || icmp.Body == 123", &pkt_ipv4_fragment_0, TRUE},
{"length == 84 || ip.Length == 84", &pkt_ipv4_fragment_0, FALSE},
{"ip.HdrLength == 5 and ip.TOS == 0 and ip.Length == 28 and "
"ip.Id == 0x1234 and ip.FragOff == 0 and ip.MF == 1 and ip.DF == 0 and "
"ip.TTL == 64 and ip.Protocol == 1 and ip.SrcAddr == 0xFFFF0A000001 and "
"ip.DstAddr == 0xFFFF08080808 and icmp.Type == 8 and icmp.Code == 0 and "
"icmp.Body == 0x0D560001", &pkt_ipv4_fragment_0, TRUE},
{"ip.MF or ip.FragOff != 0", &pkt_ipv4_fragment_1, TRUE},
{"icmp", &pkt_ipv4_fragment_1, FALSE},
{"icmp.Body != 123 || icmp.Body == 123", &pkt_ipv4_fragment_1, FALSE},
{"length == 84 || ip.Length == 84", &pkt_ipv4_fragment_1, FALSE},
{"ip.HdrLength == 5 and ip.TOS == 0 and ip.Length == 76 and "
"ip.Id == 0x1234 and ip.FragOff == 1 and ip.MF == 0 and ip.DF == 0 and "
"ip.TTL == 64 and ip.Protocol == 1 and ip.SrcAddr == 0xFFFF0A000001 and "
"ip.DstAddr == 0xFFFF08080808", &pkt_ipv4_fragment_1, TRUE},
{"icmpv6", &pkt_ipv6_fragment_0, TRUE},
{"length == 104 || ipv6.Length == 64", &pkt_ipv6_fragment_0, FALSE},
{"ipv6.TrafficClass == 0x00000000 and ipv6.FlowLabel == 0x0000 and "
"ipv6.Length == 32 and ipv6.NextHdr == 44 and ipv6.HopLimit == 31 and "
"ipv6.SrcAddr == 0:0:0:0:0:0:0:1 and ipv6.DstAddr == 0:0:0:0:0:0:0:1 and "
"icmpv6.Type == 129 and icmpv6.Code == 0 and icmpv6.Body == 0x10720003",
&pkt_ipv6_fragment_0, TRUE},
{"icmpv6", &pkt_ipv6_fragment_1, FALSE},
{"length == 104 || ipv6.Length == 64", &pkt_ipv6_fragment_1, FALSE},
{"ipv6.TrafficClass == 0x00000000 and ipv6.FlowLabel == 0x0000 and "
"ipv6.Length == 48 and ipv6.NextHdr == 44 and ipv6.HopLimit == 31 and "
"ipv6.SrcAddr == 0:0:0:0:0:0:0:1 and ipv6.DstAddr == 0:0:0:0:0:0:0:1",
&pkt_ipv6_fragment_1, TRUE},
};
/*
* Test range.
*/
static size_t lo = 0, hi = UINT_MAX;
/*
* Main.
*/
int main(void)
int main(int argc, char **argv)
{
HANDLE upper_handle, lower_handle;
HANDLE console, monitor;
@@ -869,6 +933,25 @@ int main(void)
LARGE_INTEGER freq;
UINT64 diff;
size_t i;
size_t num_tests = sizeof(tests) / sizeof(struct test), passed_tests;
switch (argc)
{
case 1:
break;
case 3:
lo = atoi(argv[1]);
hi = atoi(argv[2]);
if (hi >= lo)
{
break;
}
// Fallthrough
default:
fprintf(stderr, "usage: %s [low high]\n", argv[0]);
exit(EXIT_FAILURE);
}
hi = MIN(num_tests, hi);
// Open handles to:
// (1) stop normal traffic from interacting with the tests; and
@@ -902,8 +985,8 @@ int main(void)
Sleep(150);
// Run tests:
size_t num_tests = sizeof(tests) / sizeof(struct test), passed_tests = 0;
for (i = 0; i < num_tests; i++)
passed_tests = 0;
for (i = lo; i < num_tests && i <= hi; i++)
{
const char *filter = tests[i].filter;
const char *packet = tests[i].packet->packet;
@@ -961,10 +1044,10 @@ int main(void)
}
printf("\npassed = %.2f%%\n",
((double)passed_tests / (double)num_tests) * 100.0);
((double)passed_tests / (double)(hi - lo)) * 100.0);
first = TRUE;
for (i = 0; i < num_tests; i++)
for (i = lo; i < num_tests && i <= hi; i++)
{
const char *filter = tests[i].filter;
char *name = tests[i].packet->name;
@@ -1274,7 +1357,7 @@ static DWORD monitor_worker(LPVOID arg)
}
size_t num_tests = sizeof(tests) / sizeof(struct test);
for (i = 0; i < num_tests; i++)
for (i = lo; i < num_tests && i <= hi; i++)
{
// (1) Read the reflected filter:
WinDivertHelperCompileFilter(tests[i].filter, WINDIVERT_LAYER_NETWORK,
+53
View File
@@ -181,3 +181,56 @@ static const unsigned char ipv6_exthdrs_udp[] =
0x72, 0x6c, 0x64, 0x21, 0x01
};
// IPV4 FRAGMENT #0
static const unsigned char ipv4_fragment_0[] =
{
0x45, 0x00, 0x00, 0x1C, 0x12, 0x34, 0x20, 0x00,
0x40, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01,
0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x3c, 0xd2,
0x0d, 0x56, 0x00, 0x01
};
// IPV4 FRAGMENT #1
static const unsigned char ipv4_fragment_1[] =
{
0x45, 0x00, 0x00, 0x4C, 0x12, 0x34, 0x00, 0x01,
0x40, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01,
0x08, 0x08, 0x08, 0x08, 0x8b, 0xa6, 0x60, 0x54,
0x00, 0x00, 0x00, 0x00, 0xf9, 0x08, 0x0a, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13,
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33,
0x34, 0x35, 0x36, 0x37
};
// IPV6 FRAGMENT #0
static const unsigned char ipv6_fragment_0[] =
{
0x60, 0x00, 0x00, 0x00, 0x00, 0x20, 0x2c, 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,
0x3a, 0x00, 0x00, 0x01, 0xc7, 0xf6, 0xce, 0x53,
0x81, 0x00, 0x6e, 0xd6, 0x10, 0x72, 0x00, 0x03,
0xa4, 0xd5, 0x69, 0x54, 0x00, 0x00, 0x00, 0x00,
0xab, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
// IPV6 FRAGMENT #1
static const unsigned char ipv6_fragment_1[] =
{
0x60, 0x00, 0x00, 0x00, 0x00, 0x30, 0x2c, 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,
0x3a, 0x00, 0x00, 0x18, 0xc7, 0xf6, 0xce, 0x53,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
};