Add a NO_REPLACE for WinDivertHelperCalcChecksums

The WINDIVERT_HELPER_NO_REPLACE flag tells WinDivertHelperCalcChecksums not to
recalculate and replace non-zero checksum fields.  This is useful for
reconstructing the checksums for packets returned by WinDivertRecv(), where
all non-zero checksum fields are already valid.  This allows WinDivert1.2
to achieve similar efficiency as WinDivert1.1, where checksums were calculated
by the driver.

Note that for modified packets, the WINDIVERT_HELPER_NO_REPLACE flag should
not be used, as all checksums need to be recalculated from scratch anyway.
This commit is contained in:
basil00
2015-07-25 13:24:28 +08:00
parent 82fb0e704c
commit 609ab63594
6 changed files with 53 additions and 23 deletions
+21 -6
View File
@@ -423,8 +423,14 @@ extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
PWINDIVERT_UDPHDR udp_header;
UINT payload_len, checksum_len;
UINT count = 0;
UINT64 flags_all =
(WINDIVERT_HELPER_NO_IP_CHECKSUM |
WINDIVERT_HELPER_NO_ICMP_CHECKSUM |
WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM |
WINDIVERT_HELPER_NO_TCP_CHECKSUM |
WINDIVERT_HELPER_NO_UDP_CHECKSUM);
if ((flags & 0x1F) == 0x1F)
if ((flags & flags_all) == flags_all)
{
return 0;
}
@@ -433,7 +439,8 @@ extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
&icmp_header, &icmpv6_header, &tcp_header, &udp_header, NULL,
&payload_len);
if (ip_header != NULL && !(flags & WINDIVERT_HELPER_NO_IP_CHECKSUM))
if (ip_header != NULL && !(flags & WINDIVERT_HELPER_NO_IP_CHECKSUM) &&
(!(flags & WINDIVERT_HELPER_NO_REPLACE) || ip_header->Checksum == 0))
{
ip_header->Checksum = 0;
ip_header->Checksum = WinDivertHelperCalcChecksum(NULL, 0,
@@ -443,7 +450,9 @@ extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
if (icmp_header != NULL)
{
if (flags & WINDIVERT_HELPER_NO_ICMP_CHECKSUM)
if ((flags & WINDIVERT_HELPER_NO_ICMP_CHECKSUM) ||
((flags & WINDIVERT_HELPER_NO_REPLACE) &&
icmp_header->Checksum != 0))
{
return count;
}
@@ -456,7 +465,9 @@ extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
if (icmpv6_header != NULL)
{
if (flags & WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM)
if ((flags & WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM) ||
((flags & WINDIVERT_HELPER_NO_REPLACE) &&
icmpv6_header->Checksum != 0))
{
return count;
}
@@ -472,7 +483,9 @@ extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
if (tcp_header != NULL)
{
if (flags & WINDIVERT_HELPER_NO_TCP_CHECKSUM)
if ((flags & WINDIVERT_HELPER_NO_TCP_CHECKSUM) ||
((flags & WINDIVERT_HELPER_NO_REPLACE) &&
tcp_header->Checksum != 0))
{
return count;
}
@@ -499,7 +512,9 @@ extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen,
if (udp_header != NULL)
{
if (flags & WINDIVERT_HELPER_NO_UDP_CHECKSUM)
if ((flags & WINDIVERT_HELPER_NO_UDP_CHECKSUM) ||
((flags & WINDIVERT_HELPER_NO_REPLACE) &&
udp_header->Checksum != 0))
{
return count;
}
+22 -4
View File
@@ -614,7 +614,7 @@ WinDivert sometimes captures outbound or loopback packets before the
IP/TCP/UDP checksum fields have been calculated.
For outbound packets, this occurs when <i>checksum offloading</i> is enabled,
which defers checksum calculation to a compatible NIC card.
If the checksum is absent the corresponding
If the checksum is absent then the corresponding
checksum field will be set to zero.
Correct checksums can be reconstructed using the
<a href="#divert_helper_calc_checksums"><tt>WinDivertHelperCalcChecksums()</tt></a>
@@ -730,6 +730,15 @@ fields are currently ignored and may be arbitrary values.
Injecting an inbound packet on the outbound path <i>may</i> work (for some
types of packets), however this should be considered "undocumented" behavior,
and may be changed in the future.
</p><p>
Injected packets should have correct checksums.
Correct checksums can be calculated using the
<a
href="#divert_helper_calc_checksums"><tt>WinDivertHelperCalcChecksums()</tt></a>
function.
Note that packets returned by
<a href="#divert_recv"><tt>WinDivertRecv()</tt></a> are not
guaranteed to have correct checksums.
</p>
</dd></dl>
@@ -1246,6 +1255,8 @@ UINT <b>WinDivertHelperCalcChecksums</b>(
checksum.</li>
<li> <tt>WINDIVERT_HELPER_NO_UDP_CHECKSUM</tt>: Do not calculate the UDP
checksum.</li>
<li> <tt>WINDIVERT_HELPER_NO_REPLACE</tt>: Do not replace non-zero
checksums.</li>
</ul></li>
</ul>
</p><p>
@@ -1259,12 +1270,19 @@ Individual checksum calculations may be disabled via the appropriate flag.
Typically this function should be invoked on a modified packet before it is
injected with <a href="#divert_send"><tt>WinDivertSend()</tt></a>.
</p><p>
This function will calculate each checksum from scratch, even if the existing
checksum is correct.
By default this function will calculate each checksum from scratch, even if
the existing checksum is correct.
This may be inefficient for some applications.
For better performance, incremental checksum calculations should be used
instead (not provided by this API).
<p>
</p><p>
If the <tt>WINDIVERT_HELPER_NO_REPLACE</tt> flag is used, this function will
assume that all non-zero checksum fields are already valid and will not
replace them.
This is useful for reconstructing checksums for packets returned by
<a href="#divert_recv"><tt>WinDivertRecv()</tt></a>, where
non-zero checksum fields do not need to be recalculated.
</p>
</dd></dl>
<a name="divert_helper_check_filter"><h3>6.11 WinDivertHelperCheckFilter</h3></a>
+3 -5
View File
@@ -118,11 +118,9 @@ int __cdecl main(int argc, char **argv)
continue;
}
// Calculate checksums for outbound packets.
if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND)
{
WinDivertHelperCalcChecksums(packet, packet_len, 0);
}
// Calculate checksums.
WinDivertHelperCalcChecksums(packet, packet_len,
WINDIVERT_HELPER_NO_REPLACE);
// Print info about the matching packet.
WinDivertHelperParsePacket(packet, packet_len, &ip_header,
+4 -7
View File
@@ -107,14 +107,11 @@ static DWORD passthru(LPVOID arg)
continue;
}
// NOTE: Since WinDivert1.2 outbound packets are not guaranteed
// to have correct checksums.
if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND)
{
WinDivertHelperCalcChecksums(packet, packet_len, 0);
}
// Re-inject the matching packet.
// NOTE: Only use the WINDIVERT_HELPER_NO_REPLACE flag if the packet
// was not modified.
WinDivertHelperCalcChecksums(packet, packet_len,
WINDIVERT_HELPER_NO_REPLACE);
if (!WinDivertSend(handle, packet, packet_len, &addr, NULL))
{
fprintf(stderr, "warning: failed to reinject packet (%d)\n",
+2 -1
View File
@@ -188,7 +188,8 @@ int __cdecl main(int argc, char **argv)
!BlackListPayloadMatch(blacklist, payload, (UINT16)payload_len))
{
// Packet does not match the blacklist; simply reinject it.
WinDivertHelperCalcChecksums(packet, packet_len, 0);
WinDivertHelperCalcChecksums(packet, packet_len,
WINDIVERT_HELPER_NO_REPLACE);
if (!WinDivertSend(handle, packet, packet_len, &addr, NULL))
{
fprintf(stderr, "warning: failed to reinject packet (%d)\n",
+1
View File
@@ -313,6 +313,7 @@ typedef struct
#define WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM 4
#define WINDIVERT_HELPER_NO_TCP_CHECKSUM 8
#define WINDIVERT_HELPER_NO_UDP_CHECKSUM 16
#define WINDIVERT_HELPER_NO_REPLACE 2048
/*
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.