Files
2018-11-15 08:24:46 +08:00

1794 lines
57 KiB
HTML

<!doctype html>
<html>
<head>
<title>WinDivert 2.0 Documentation</title>
</head>
<body>
<h1>WinDivert 2.0: Windows Packet Divert</h1>
<h2>Table of Contents</h2>
<ul>
<li><a href="#introduction">1. Introduction</a></li>
<li><a href="#building">2. Building</a></li>
<ul>
<li><a href="#driver_signing">2.1 Driver Signing</a></li>
</ul>
<li><a href="#installing">3. Installing</a></li>
<li><a href="#uninstalling">4. Uninstalling</a></li>
<li><a href="#programming_api">5. Programming API</a></li>
<ul>
<li><a href="#divert_address">5.1 WINDIVERT_ADDRESS</a></li>
<li><a href="#divert_open">5.2 WinDivertOpen</a></li>
<li><a href="#divert_recv">5.3 WinDivertRecv</a></li>
<li><a href="#divert_recv_ex">5.4 WinDivertRecvEx</a></li>
<li><a href="#divert_send">5.5 WinDivertSend</a></li>
<li><a href="#divert_send_ex">5.6 WinDivertSendEx</a></li>
<li><a href="#divert_close">5.7 WinDivertClose</a></li>
<li><a href="#divert_set_param">5.8 WinDivertSetParam</a></li>
<li><a href="#divert_get_param">5.9 WinDivertGetParam</a></li>
</ul>
<li><a href="#helper_programming_api">6. Helper Programming API</a></li>
<ul>
<li><a href="#divert_iphdr">6.1 WINDIVERT_IPHDR</a></li>
<li><a href="#divert_ipv6hdr">6.2 WINDIVERT_IPV6HDR</a></li>
<li><a href="#divert_icmphdr">6.3 WINDIVERT_ICMPHDR</a></li>
<li><a href="#divert_icmpv6hdr">6.4 WINDIVERT_ICMPV6HDR</a></li>
<li><a href="#divert_tcphdr">6.5 WINDIVERT_TCPHDR</a></li>
<li><a href="#divert_udphdr">6.6 WINDIVERT_UDPHDR</a></li>
<li><a href="#divert_helper_parse_packet">6.7 WinDivertHelperParsePacket</a></li>
<li><a href="#divert_help_parse_ipv4_address">6.8 WinDivertHelperParseIPv4Address</li>
<li><a href="#divert_help_parse_ipv6_address">6.9 WinDivertHelperParseIPv6Address</li>
<li><a href="#divert_helper_calc_checksums">6.10 WinDivertHelperCalcChecksums</a></li>
<li><a href="#divert_helper_check_filter">6.11 WinDivertHelperCheckFilter</a></li>
<li><a href="#divert_helper_eval_filter">6.12 WinDivertHelperEvalFilter</a></li>
</ul>
<li><a href="#filter_language">7. Filter Language</a></li>
<ul>
<li><a href="#filter_examples">7.1 Filter Examples</a></li>
<li><a href="#filter_usage">7.2 Filter Usage</a></li>
</ul>
<li><a href="#samples">8. Samples</a></li>
<li><a href="#known_issues">9. Known Issues</a></li>
<li><a href="#license">10. License</a></li>
</ul>
<hr>
<a name="introduction"><h2>1. Introduction</h2></a>
<p>
WinDivert is a user-mode
capture/sniffing/modification/blocking/re-injection package for
Windows Vista, Windows Server 2008, Windows 7, and Windows 8.
WinDivert can be used to implement user-mode packet filters, packet sniffers,
firewalls, NAT, VPNs, tunneling applications, etc., without the need to
write kernel-mode code.
</p>
<p>
The main features of the WinDivert are:
<ul>
<li> User-mode packet capture, sniffing, dropping, filtering, modification,
re-injection, etc.</li>
<li> Simple, high-level, programming API.</li>
<li> Fully documented with sample programs.</li>
<li> Full IPv6 support.</li>
<li> Full loopback (localhost) support.</li>
<li> A modern WDF/WFP driver implementation.</li>
<li> Open source; Licensed under GNU Lesser General Public License (LGPL)
version 3.
See the <a href="#license">License</a> for more information.</li>
</ul>
</p><p>
WinDivert provides similar functionality to
<tt>divert</tt> sockets from FreeBSD/MacOS, <tt>NETLINK</tt> sockets from
Linux, and some commercial packages such as <tt>WinPkFilter</tt> for Windows.
WinDivert also supports passive packet sniffing similar to <tt>Winpcap</tt>.
</p>
<hr>
<a name="building"><h2>2. Building</h2></a>
<p>
Note that pre-built WinDivert binary distributions are available from the
<a href="https://reqrypt.org/windivert.html">WinDivert website</a>.
Most users do not need to build their own version of WinDivert from source.
</p>
<p>
The source code for WinDivert is available for download at
<blockquote>
<a href="https://github.com/basil00/Divert">
https://github.com/basil00/Divert</a>
</blockquote>
To build the WinDivert drivers from source:
<ol>
<li> Download and install <a href="http://www.microsoft.com/whdc/devtools/wdk/default.mspx">
Windows Driver Kit 7.1.0</a>.</li>
<li> Open a <i>x86 Free Build Environment</i> console.</li>
<li> In the WinDivert package root directory, run the command:
<pre>
wddk-build.bat
</pre>
This will build the <tt>install\WDDK\i386\WinDivert32.sys</tt> driver.</li>
<li> Next, open a <i>x64 Free Build Environment</i> console.</li>
<li> Re-run the <tt>wddk-build.bat</tt> command to build the
<tt>install\WDDK\amd64\WinDivert64.sys</tt> driver.</li>
</ol>
</p>
<p>
To build the WinDivert user-mode library (<tt>WinDivert.dll</tt>) and sample
programs:
<ol>
<li> First, build the WinDivert drivers by running the
<tt>wddk-build.bat</tt> command described above.</li>
<li> In Linux (with the MinGW cross-compilers installed) and in the
WinDivert package root directory, run the command:
<pre>
sh mingw-build.sh
</pre>
This will the user-mode library and sample programs which will be placed
in the <tt>install\MINGW</tt> subdirectory.</li>
</ol>
</p>
<p>
The generated <tt>WinDivert.dll</tt>/<tt>WinDivert.lib</tt> files
should be compatible with all major compilers, including both MinGW and
Visual Studio.
</p>
<a name="driver_signing"><h3>2.1 Driver Signing</h3></a>
<p>
If you built your own
<tt>WinDivert32.sys</tt>/<tt>WinDivert64.sys</tt> drivers,
they must be digitally signed before they can be used.
See <a href="http://msdn.microsoft.com/en-us/windows/hardware/gg487317.aspx">Driver Signing Requirements for Windows</a>
for more information.
</p>
<p>
Note that the pre-built <tt>WinDivert32.sys</tt>/<tt>WinDivert64.sys</tt>
drivers from the official WinDivert distribution are already digitally signed.
</p>
<hr>
<a name="installing"><h2>3. Installing</h2></a>
<p>
WinDivert does not require any special installation.
Depending on your target configuration, simply place the following files in
your application's home directory:
</p>
<center>
<table border="1" cellpadding="5" width="75%">
<tr>
<th>
Application Type
</th>
<th>
Target Windows Type
</th>
<th>
Files Required
</th>
</tr>
<tr>
<td>
32-bit
</td>
<td>
32-bit Windows only
</td>
<td>
<tt>WinDivert.dll</tt> (32-bit version) and <tt>WinDivert32.sys</tt>
</td>
</tr>
<tr>
<td>
64-bit
</td>
<td>
64-bit Windows only
</td>
<td>
<tt>WinDivert.dll</tt> (64-bit version) and <tt>WinDivert64.sys</tt>
</td>
</tr>
<tr>
<td>
32-bit
</td>
<td>
Both 32-bit and 64-bit Windows
</td>
<td>
<tt>WinDivert.dll</tt> (32-bit version), <tt>WinDivert32.sys</tt>,
and <tt>WinDivert64.sys</tt>
</td>
</tr>
</table>
</center>
<p>
The WinDivert driver is automatically (and silently) installed on demand
whenever your application calls
<a href="#divert_open"><tt>WinDivertOpen()</tt></a>.
The calling application must have Administrator privileges.
</p>
<hr>
<a name="uninstalling"><h2>4. Uninstalling</h2></a>
<p>
To uninstall, simply delete the <tt>WinDivert.dll</tt>,
<tt>WinDivert32.sys</tt>, and <tt>WinDivert64.sys</tt> files.
If already running, the WinDivert driver will be automatically
uninstalled during the next machine reboot.
The WinDivert driver can also be manually removed by issuing the following
commands at the command prompt
<pre>
sc stop WinDivert2.0
sc delete WinDivert2.0
</pre>
Note that this is not recommended as it will interfere with other
applications that depend on WinDivert.
</p>
<hr>
<a name="programming_api"><h2>5. Programming API</h2></a>
<p>
To use the WinDivert package, a program/application must:
<ol>
<li> Include the <tt>windivert.h</tt> header file
<pre>
#include "windivert.h"
</pre></li>
<li> Link against or dynamically load the <tt>WinDivert.dll</tt> dynamic link
library.</li>
</ol>
<a name="divert_address"><h3>5.1 WINDIVERT_ADDRESS</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
typedef struct
{
INT64 Timestamp;
UINT32 IfIdx;
UINT32 SubIfIdx;
UINT8 Direction:1;
UINT8 Loopback:1;
UINT8 Impostor:1;
UINT8 PseudoIPChecksum:1;
UINT8 PseudoTCPChecksum:1;
UINT8 PseudoUDPChecksum:1;
} <b>WINDIVERT_ADDRESS</b>, *<b>PWINDIVERT_ADDRESS</b>;
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Fields</b>
<ul>
<li> <tt>Timestamp</tt>: A timestamp indicating when WinDivert first captured
the packet.</li>
<li> <tt>IfIdx</tt>: The interface index on which the packet arrived
(for inbound packets), or is to be sent (for outbound packets).</li>
<li> <tt>SubIfIdx</tt>: The sub-interface index for <tt>IfIdx</tt>.</li>
<li> <tt>Direction</tt>: The packet's direction.
The possible values are
<ul>
<li> <tt>WINDIVERT_DIRECTION_OUTBOUND</tt> with value 0 for <i>outbound</i>
packets.</li>
<li> <tt>WINDIVERT_DIRECTION_INBOUND</tt> with value 1 for <i>inbound</i>
packets.</li>
</ul></li>
<li> <tt>Loopback</tt>: Set to <tt>1</tt> for loopback packets, <tt>0</tt>
otherwise</li>
<li> <tt>Impostor</tt>: Set to <tt>1</tt> for <q>impostor</q> packets,
<tt>0</tt> otherwise.</li>
<li> <tt>PseudoIPChecksum</tt>: Set to <tt>1</tt> for packets with a
<i>pseudo</i> IPv4 checksum, <tt>0</tt> otherwise.</li>
<li> <tt>PseudoTCPChecksum</tt>: Set to <tt>1</tt> for packets with a
<i>pseudo</i> TCP checksum, <tt>0</tt> otherwise.</li>
<li> <tt>PseudoTCPChecksum</tt>: Set to <tt>1</tt> for packets with a
<i>pseudo</i> UDP checksum, <tt>0</tt> otherwise.</li>
</ul>
</p><p>
<b>Remarks</b><br>
The <a href="#divert_address"><tt>WINDIVERT_ADDRESS</tt></a> structure
represents the "address" of a captured or injected packet.
The address includes the packet's timestamp, network interfaces, direction
and other information.
</p><p>
The <tt>Timestamp</tt> indicates when the packet was first
captured by WinDivert.
It uses the same clock as
<a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx"><tt>QueryPerformanceCounter()</tt></a>.
The <tt>Timestamp</tt> value is ignored by
<a href="#divert_send"><tt>WinDivertSend()</tt></a>.
</p><p>
The <tt>IfIdx</tt>/<tt>SubIfIdx</tt> indicate the packet's network adapter
(a.k.a. interface) index.
These values are ignored for <i>outbound</i> packets.
</p><p>
The <tt>Direction</tt> field is set to <tt>WINDIVERT_DIRECTION_OUTBOUND</tt>
(<tt>0</tt>) for outbound packets, and
<tt>WINDIVERT_DIRECTION_INBOUND</tt> (<tt>1</tt>) for inbound packets.
This field is ignored for <i>forward</i> packets.
</p><p>
The <tt>Loopback</tt> flag is set for <i>loopback</i> packets.
Note that Windows considers any packet originating from, and destined to, the
current machine to be a loopback packet, so loopback packets are not
limited to localhost addresses.
Note that WinDivert considers loopback packets to be
<i>outbound only</i>, and will not capture loopback packets on the
inbound path.
</p><p>
The <tt>Impostor</tt> flag is set for <i>impostor</i> packets.
An impostor packet is any packet injected by another driver rather than
originating from the network or Windows TCP/IP stack.
Impostor packets are problematic since they can cause infinite loops,
where a packet injected by <a href="#divert_send"><tt>WinDivertSend()</tt></a>
is captured again by <a href="#divert_recv"><tt>WinDivertRecv()</tt></a>.
For more information, see <a href="#divert_send"><tt>WinDivertSend()</tt></a>.
</p><p>
The <tt>Pseudo*Checksum</tt> flags indicate whether the packet uses
<i>full</i> or <i>pseudo</i> checksums.
Pseudo checksums are used when
<i>IP/TCP/UDP checksum offloading</i> is enabled, meaning that the network
hardware calculates/validates checksums rather than the Windows TCP/IP stack.
Pseudo checksums may be arbitrary values.
Typically, modified packets should preserve the <tt>Pseudo*Checksum</tt> flags.
</p>
</dd></dl>
<a name="divert_open"><h3>5.2 WinDivertOpen</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
HANDLE <b>WinDivertOpen</b>(
__in const char *filter,
__in WINDIVERT_LAYER layer,
__in INT16 priority,
__in UINT64 flags
);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>filter</tt>: A packet filter string specified in the WinDivert
<a href="#filter_language">filter language</a>.</li>
<li> <tt>layer</tt>: The layer.</li>
<li> <tt>priority</tt>: The priority of the handle.</li>
<li> <tt>flags</tt>: Additional flags.</li>
</ul>
</p><p>
<b>Return Value</b><br>
A valid WinDivert handle on success, or
<tt>INVALID_HANDLE_VALUE</tt> if an error occurred.
Use <tt>GetLastError()</tt> to get the reason for the error.
Common errors include:
<center>
<table border="1" cellpadding="5" width="75%">
<tr>
<th>
Name
</th>
<th>
Code
</th>
<th>
Description
</th>
</tr>
<tr>
<td>
<tt>ERROR_FILE_NOT_FOUND</tt>
</td>
<td>
2
</td>
<td>
The driver files
<tt>WinDivert32.sys</tt> or <tt>WinDivert64.sys</tt>
were not found.
</td>
</tr>
<tr>
<td>
<tt>ERROR_ACCESS_DENIED</tt>
</td>
<td>
5
</td>
<td>
The calling application does not have Administrator privileges.
</td>
</tr>
<tr>
<td>
<tt>ERROR_INVALID_PARAMETER</tt>
</td>
<td>
87
</td>
<td>
This indicates an invalid packet filter string, layer, priority, or flags.
</td>
</tr>
<tr>
<td>
<tt>ERROR_INVALID_IMAGE_HASH</tt>
</td>
<td>
577
</td>
<td>
The <tt>WinDivert32.sys</tt> or <tt>WinDivert64.sys</tt> driver does not
have a valid digital signature
(see the <a href="#driver_signing">driver signing requirements</a> above).
</td>
</tr>
<tr>
<td>
<tt>ERROR_DRIVER_BLOCKED</tt>
</td>
<td>
1275
</td>
<td>
This error occurs for various reasons, including:
<ol>
<li> the WinDivert driver is blocked by security software; or</li>
<li> you are using a virtualization environment that does not support
drivers.</li>
</ol>
</td>
</tr>
<tr>
<td>
<tt>EPT_S_NOT_REGISTERED</tt>
</td>
<td>
1753
</td>
<td>
This error occurs when the <i>Base Filtering Engine</i> service has been
disabled.
</td>
</tr>
</table>
</center>
</p><p>
<b>Remarks</b><br>
Opens a WinDivert handle for the given filter.
Unless otherwise specified by <tt>flags</tt>, any packet that matches the
filter will be diverted to the handle.
Diverted packets can be read by the application with
<a href="#divert_recv"><tt>WinDivertRecv()</tt></a>.
</p>
<p>
A typical application is only interested in a subset of all network traffic.
In this case the filter should <i>match as closely as possible</i> to
the subset of interest.
This avoids unnecessary overheads introduced by diverting packets to the
user-mode application.
See the <a href="#filter_language">filter language</a> section for more
information.
</p>
<p>
The <i>layer</i> of the WinDivert handle is determined by the <tt>layer</tt>
parameter.
Currently the following layers are supported.
<center>
<table border="1" cellpadding="5" width="75%">
<tr>
<th>
Layer
</th>
<th>
Description
</th>
</tr>
<tr>
<td>
<tt>WINDIVERT_LAYER_NETWORK = 0</tt>
</td>
<td>
The network layer.
This is the default.
</td>
</tr>
<tr>
<td>
<tt>WINDIVERT_LAYER_NETWORK_FORWARD</tt>
</td>
<td>
The network layer (forwarded packets).
</td>
</tr>
</table>
</center>
</p>
<p>
Different WinDivert handles can be assigned different priorities by the
<tt>priority</tt> parameter.
Packets are diverted to higher priority handles before lower priority
handles.
Packets injected by a handle are then diverted to the next priority handle,
and so on, provided the packet matches the handle's filter.
A packet is only diverted once per priority level, so handles should not
share priority levels unless they use mutually exclusive filters.
Otherwise it is not defined which handle will receive the packet first.
Lower <tt>priority</tt> values represent higher priorities, with <tt>-1000</tt>
being the highest priority, <tt>0</tt> the middle (and a good default)
priority, and <tt>1000</tt> the lowest priority.
</p>
<p>
The following flags are supported.
<center>
<table border="1" cellpadding="5" width="75%">
<tr>
<th>
Flag
</th>
<th>
Description
</th>
</tr>
<tr>
<td>
<tt>WINDIVERT_FLAG_SNIFF</tt>
</td>
<td>
This flag opens the WinDivert handle in <i>packet sniffing</i> mode.
In packet sniffing mode the original packet is not dropped-and-diverted
(the default) but copied-and-diverted.
This mode is useful for implementing packet sniffing tools similar to those
applications that currently use <tt>Winpcap</tt>.
</td>
</tr>
<tr>
<td>
<tt>WINDIVERT_FLAG_DROP</tt>
</td>
<td>
This flag indicates that the user application does not intend to read matching
packets with <a href="#divert_recv"><tt>WinDivertRecv()</tt></a>, instead the
packets should be silently dropped.
This is useful for implementing simple packet filters using the
WinDivert <a href="#filter_language">filter language</a>.
</td>
</tr>
<tr>
<td>
<tt>WINDIVERT_FLAG_DEBUG</tt>
</td>
<td>
This flag causes <a href="#divert_send"><tt>WinDivertSend()</tt></a> to block
until the injected packet <i>exits</i> the Windows TCP/IP stack.
By default, <a href="#divert_send"><tt>WinDivertSend()</tt></a> does not
block and returns immediately after the packet <i>enters</i> the
TCP/IP stack.
The default mode is faster, but will not return an error code if the
packet is lost or rejected for any reason; making debugging difficult.
</td>
</tr>
</table>
</center>
Note that only one of <tt>WINDIVERT_FLAG_SNIFF</tt> or
<tt>WINDIVERT_FLAG_DROP</tt> may be set at the same time.
</p>
</dd></dl>
<a name="divert_recv"><h3>5.3 WinDivertRecv</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertRecv</b>(
__in HANDLE handle,
__out PVOID pPacket,
__in UINT packetLen,
__out_opt PWINDIVERT_ADDRESS pAddr,
__out_opt UINT *recvLen
);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>handle</tt>: A valid WinDivert handle created by
<a href="#divert_open"><tt>WinDivertOpen()</tt></a>.</li>
<li> <tt>pPacket</tt>: A buffer for the captured packet.</li>
<li> <tt>packetLen</tt>: The length of the buffer <tt>pPacket</tt>.</li>
<li> <tt>pAddr</tt>: The
<a href="#divert_address"><tt>WINDIVERT_ADDRESS</tt></a> of the captured
packet.</li>
<li> <tt>recvLen</tt>: The total number of bytes written to <tt>pPacket</tt>.
Can be <tt>NULL</tt> if this information is not required.</li>
</ul>
</p><p>
<b>Return Value</b><br>
<tt>TRUE</tt> if a packet was successfully received, or <tt>FALSE</tt> if
an error occurred.
Use <tt>GetLastError()</tt> to get the reason for the error.
</p><p>
<b>Remarks</b><br>
Receives a diverted packet that matched the filter passed to
<a href="#divert_open"><tt>WinDivertOpen()</tt></a>.
The received packet is guaranteed to match the filter.
</p><p>
The contents of the captured packet are written to <tt>pPacket</tt>.
If the captured packet is larger than the <tt>pPacket</tt> buffer length,
then the packet will be truncated.
If <tt>recvLen</tt> is non-<tt>NULL</tt>, then the total number of bytes
written to <tt>pPacket</tt> is placed there.
If non-<tt>NULL</tt>, the address of the captured packet is written to
<tt>pAddr</tt>.
</p><p>
An application should call <a href="#divert_recv"><tt>WinDivertRecv()</tt></a>
<i>as soon as possible</i>
after a successful call to <a href="#divert_open"><tt>WinDivertOpen()</tt></a>.
When a WinDivert handle is open, any packet that matches the filter will
be captured and queued until handled by
<a href="#divert_recv"><tt>WinDivertRecv()</tt></a>.
Packets are not queued indefinitely, and if not handled in a timely manner,
any captured packet may be dropped.
The amount of time a packet is queued can be controlled with the
<a href="#divert_set_param"><tt>WinDivertSetParam()</tt></a> function.
</p><p>
Captured packets are guaranteed to have correct checksums, or
pseudo checksums, as indicated by the <tt>Pseudo*Checksum</tt> flags
from the <a href="#divert_address"><tt>WINDIVERT_ADDRESS</tt></a>.
</p><p>
<a href="#divert_recv"><tt>WinDivertRecv()</tt></a> should not be used on any
WinDivert handle created with the <tt>WINDIVERT_FLAG_DROP</tt> set.
</p>
</dd></dl>
<a name="divert_recv_ex"><h3>5.4 WinDivertRecvEx</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertRecvEx</b>(
__in HANDLE handle,
__out PVOID pPacket,
__in UINT packetLen,
__in UINT64 flags,
__out_opt PWINDIVERT_ADDRESS pAddr,
__out_opt UINT *recvLen,
__inout_opt LPOVERLAPPED lpOverlapped
);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>handle</tt>: A valid WinDivert handle created by
<a href="#divert_open"><tt>WinDivertOpen()</tt></a>.</li>
<li> <tt>pPacket</tt>: A buffer for the captured packet.</li>
<li> <tt>packetLen</tt>: The length of the buffer <tt>pPacket</tt>.</li>
<li> <tt>flags</tt>: Reserved, set to zero.</li>
<li> <tt>pAddr</tt>: The
<a href="#divert_address"><tt>WINDIVERT_ADDRESS</tt></a> of the captured
packet.</li>
<li> <tt>recvLen</tt>: The total number of bytes written to <tt>pPacket</tt>.
Can be <tt>NULL</tt> if this information is not required.</li>
<li> <tt>lpOverlapped</tt>: An optional pointer to a <tt>OVERLAPPED</tt>
structure.</li>
</ul>
</p><p>
<b>Return Value</b><br>
<tt>TRUE</tt> if a packet was successfully received, or <tt>FALSE</tt>
otherwise.
Use <tt>GetLastError()</tt> to get the reason.
The error code <tt>ERROR_IO_PENDING</tt> indicates that the overlapped
operation has been successfully initiated and that completion will be
indicated at a later time.
All other codes indicate an error.
</p><p>
<b>Remarks</b><br>
This function is equivalent to
<a href="#divert_recv"><tt>WinDivertRecv()</tt></a> except that it
supports overlapped I/O via the <tt>lpOverlapped</tt> parameter.
</p>
</dd></dl>
<a name="divert_send"><h3>5.5 WinDivertSend</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertSend</b>(
__in HANDLE handle,
__in PVOID pPacket,
__in UINT packetLen,
__in PWINDIVERT_ADDRESS pAddr,
__out_opt UINT *sendLen
);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>handle</tt>: A valid WinDivert handle created by
<a href="#divert_open"><tt>WinDivertOpen()</tt></a>.</li>
<li> <tt>pPacket</tt>: A buffer containing the packet to be injected.</li>
<li> <tt>packetLen</tt>: The total length of the buffer <tt>pPacket</tt>.</li>
<li> <tt>pAddr</tt>: The
<a href="#divert_address"><tt>WINDIVERT_ADDRESS</tt></a> for the injected
packet.</li>
<li> <tt>sendLen</tt>: The total number of bytes injected.
Can be <tt>NULL</tt> if this information is not required.</li>
</ul>
</p><p>
<b>Return Value</b><br>
<tt>TRUE</tt> if a packet was successfully injected, or <tt>FALSE</tt> if
an error occurred.
Use <tt>GetLastError()</tt> to get the reason for the error.
</p><p>
Common errors include:
<center>
<table border="1" cellpadding="5" width="75%">
<tr>
<th>
Name
</th>
<th>
Code
</th>
<th>
Description
</th>
</tr>
<tr>
<td>
<tt>ERROR_HOST_UNREACHABLE</tt>
</td>
<td>
1232
</td>
<td>
This error occurs when an <i>impostor</i> packet (with
<tt>pAddr-&gt;Impostor</tt> set to <tt>1</tt>) is injected and the
<tt>ip.TTL</tt> or <tt>ipv6.HopLimit</tt> field goes to zero.
This is a defense of <q>last resort</q> against infinite loops caused by
impostor packets.
</td>
</tr>
</table>
</center>
</p><p>
Note that a return value of <tt>TRUE</tt> does not necessarily mean the
packet was accepted by the Windows TCP/IP stack.
For better error messages (at the cost of performance), pass the
<tt>WINDIVERT_FLAG_DEBUG</tt> flag to <a
href="#divert_open"><tt>WinDivertOpen()</tt></a>.
</p><p>
<b>Remarks</b><br>
Injects a packet into the network stack.
The injected packet may be one received from
<a href="#divert_recv"><tt>WinDivertRecv()</tt></a>, or a
modified version, or a completely new packet.
Injected packets can be captured and diverted again by other WinDivert
handles with lower priorities.
</p><p>
The <tt>pAddr</tt> parameter determines how the packet is injected.
If the <tt>Direction</tt> field is <tt>WINDIVERT_DIRECTION_OUTBOUND</tt>,
the packet is injected into the <i>outbound</i> path (i.e. a packet leaving
this computer).
Else, if <tt>Direction</tt> is <tt>WINDIVERT_DIRECTION_INBOUND</tt>,
the packet is injected into the <i>inbound</i> path (i.e. a packet arriving at
this computer).
Note that the <tt>Direction</tt> field, and <i>not</i> the IP addresses in
the injected packet, is used to determine the packet's direction.
</p><p>
For packets injected into the <i>inbound</i> path, the <tt>IfIdx</tt> and
<tt>SubIfIdx</tt> fields are assumed to contain valid interface numbers.
These may be retrieved from <a href="#divert_recv"><tt>WinDivertRecv()</tt></a>
(for packet modification),
or from the <a href="http://msdn.microsoft.com/en-us/library/aa366073%28v=VS.85%29.aspx">IP Helper API</a>.
</p><p>
For <i>outbound</i> injected packets, the <tt>IfIdx</tt> and <tt>SubIfIdx</tt>
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>
For <i>impostor</i> packets (where the <tt>Impostor</tt> field of
<tt>pAddr</tt> set to <tt>1</tt>) WinDivert will automatically decrement the
<tt>ip.TTL</tt> or <tt>ipv6.HopLimit</tt> fields for the injected packet.
This is to mitigate infinite loops since WinDivert cannot prevent
impostor packets from being captured again by
<a href="#divert_recv"><tt>WinDivertRecv()</tt></a>.
</p><p>
Injected packets must have the 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
guaranteed to have correct checksums.
</p>
<p>
When pseudo checksums are used,
the <a href="#divert_send"><tt>WinDivertSend()</tt></a> function may
modify the contents of the memory pointed to by the <tt>pPacket</tt> and
<tt>pAddr</tt> parameters.
Thus, it is important that this memory is not read-only.
</p>
</dd></dl>
<a name="divert_send_ex"><h3>5.6 WinDivertSendEx</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertSendEx</b>(
__in HANDLE handle,
__in PVOID pPacket,
__in UINT packetLen,
__in UINT64 flags,
__in PWINDIVERT_ADDRESS pAddr,
__out_opt UINT *sendLen,
__inout_opt LPOVERLAPPED lpOverlapped
);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>handle</tt>: A valid WinDivert handle created by
<a href="#divert_open"><tt>WinDivertOpen()</tt></a>.</li>
<li> <tt>pPacket</tt>: A buffer containing the packet to be injected.</li>
<li> <tt>packetLen</tt>: The total length of the buffer <tt>pPacket</tt>.</li>
<li> <tt>flags</tt>: Reserved, set to zero.</li>
<li> <tt>pAddr</tt>: The
<a href="#divert_address"><tt>WINDIVERT_ADDRESS</tt></a> for the injected
packet.</li>
<li> <tt>sendLen</tt>: The total number of bytes injected.
Can be <tt>NULL</tt> if this information is not required.</li>
<li> <tt>lpOverlapped</tt>: An optional pointer to a <tt>OVERLAPPED</tt>
structure.</li>
</ul>
</p><p>
<b>Return Value</b><br>
<tt>TRUE</tt> if a packet was successfully injected, or <tt>FALSE</tt>
otherwise.
Use <tt>GetLastError()</tt> to get the reason.
The error code <tt>ERROR_IO_PENDING</tt> indicates that the overlapped
operation has been successfully initiated and that completion will be
indicated at a later time.
All other codes indicate an error.
</p><p>
<b>Remarks</b><br>
This function is equivalent to
<a href="#divert_send"><tt>WinDivertSend()</tt></a> except that it
supports overlapped I/O via the <tt>lpOverlapped</tt> parameter.
</p>
</dd></dl>
<a name="divert_close"><h3>5.7 WinDivertClose</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertClose</b>(
__in HANDLE handle
);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>handle</tt>: A valid WinDivert handle created by
<a href="#divert_open"><tt>WinDivertOpen()</tt></a>.</li>
</ul>
</p><p>
<b>Return Value</b><br>
<tt>TRUE</tt> if successful, <tt>FALSE</tt> if an error occurred.
Use <tt>GetLastError()</tt> to get the reason for the error.
</p><p>
<b>Remarks</b><br>
Closes a WinDivert handle created by
<a href="#divert_open"><tt>WinDivertOpen()</tt></a>.
</p>
<dd></dl>
<a name="divert_set_param"><h3>5.8 WinDivertSetParam</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertSetParam</b>(
__in HANDLE handle,
__in WINDIVERT_PARAM param,
__in UINT64 value);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>handle</tt>: A valid WinDivert handle created by
<a href="#divert_open"><tt>WinDivertOpen()</tt></a>.</li>
<li> <tt>param</tt>: A WinDivert parameter name.</li>
<li> <tt>value</tt>: The parameter's new value.</li>
</ul>
</p><p>
<b>Return Value</b><br>
<tt>TRUE</tt> if successful, <tt>FALSE</tt> if an error occurred.
Use <tt>GetLastError()</tt> to get the reason for the error.
</p><p>
<b>Remarks</b><br>
Sets a WinDivert parameter.
Currently, the following WinDivert parameters are defined.
<center>
<table border="1" cellpadding="5" width="75%">
<tr>
<th>
Parameter
</th>
<th>
Description
</th>
</tr>
<tr>
<td>
<tt>WINDIVERT_PARAM_QUEUE_LEN</tt>
</td>
<td>
Sets the maximum length of the packet queue for
<a href="#divert_recv"><tt>WinDivertRecv()</tt></a>.
Currently the default value is 2048, the minimum is 16, and the maximum
is 16384.
</td>
</tr>
<tr>
<td>
<tt>WINDIVERT_PARAM_QUEUE_TIME</tt>
</td>
<td>
Sets the minimum time, in milliseconds, a packet can be queued before it is
automatically dropped.
Packets cannot be queued indefinitely, and ideally, packets should be
processed by the application as soon as is possible.
Note that this sets the <i>minimum</i> time a packet can be queued before
it can be dropped.
The actual time may be exceed this value.
Currently the default value is 1000 (1s), the minimum is 20 (20ms), and the
maximum is 8000 (8s).
</td>
</tr>
<tr>
<td>
<tt>WINDIVERT_PARAM_QUEUE_SIZE</tt>
</td>
<td>
Sets the maximum number of bytes that can be stored in the packet queue for
<a href="#divert_recv"><tt>WinDivertRecv()</tt></a>.
Currently the default value is 4194304 (4MB), the minimum is 65535 (64KB),
and the maximum is 33554432 (32MB).
</td>
</tr>
</table>
</center>
</p>
<dd></dl>
<a name="divert_get_param"><h3>5.9 WinDivertGetParam</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertGetParam</b>(
__in HANDLE handle,
__in WINDIVERT_PARAM param,
__out UINT64 *pValue);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>handle</tt>: A valid WinDivert handle created by
<a href="#divert_open"><tt>WinDivertOpen()</tt></a>.</li>
<li> <tt>param</tt>: A WinDivert parameter name.</li>
<li> <tt>value</tt>: The parameter's current value.</li>
</ul>
</p><p>
<b>Return Value</b><br>
<tt>TRUE</tt> if successful, <tt>FALSE</tt> if an error occurred.
Use <tt>GetLastError()</tt> to get the reason for the error.
</p><p>
<b>Remarks</b><br>
Gets a WinDivert parameter.
See <a href="#divert_set_param"><tt>WinDivertSetParam()</tt></a> for the list
of parameters.
</p>
<dd></dl>
<hr>
<a name="helper_programming_api"><h2>6. Helper Programming API</h2></a>
The WinDivert helper programming API is a collection of definitions
and functions designed to make writing WinDivert applications easier.
The use of the helper API is completely optional.
<a name="divert_iphdr"><h3>6.1 WINDIVERT_IPHDR</h3>
<table border="1" cellpadding="5"><tr><td>
<pre>
typedef struct
{
UINT8 HdrLength:4;
UINT8 Version:4;
UINT8 TOS;
UINT16 Length;
UINT16 Id;
UINT16 <i>...</i>;
UINT8 TTL;
UINT8 Protocol;
UINT16 Checksum;
UINT32 SrcAddr;
UINT32 DstAddr;
} <b>WINDIVERT_IPHDR</b>, *<b>PWINDIVERT_IPHDR</b>;
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Fields</b><br>
See <a href="http://en.wikipedia.org/wiki/IPv4#Packet_structure">here</a>
for more information.
</p><p>
<b>Remarks</b><br>
IPv4 header definition.
</p><p>
The following fields can only be get/set using the following macro
definitions:
<ul>
<li><i>FragOff</i> with <tt>WINDIVERT_IPHDR_GET_FRAGOFF(<i>hdr</i>)</tt> and
<tt>WINDIVERT_IPHDR_SET_FRAGOFF(<i>hdr</i>, <i>val</i>)</tt></li>
<li><i>MF</i> with <tt>WINDIVERT_IPHDR_GET_MF(<i>hdr</i>)</tt> and
<tt>WINDIVERT_IPHDR_SET_MF(<i>hdr</i>, <i>val</i>)</tt></li>
<li><i>DF</i> with <tt>WINDIVERT_IPHDR_GET_DF(<i>hdr</i>)</tt> and
<tt>WINDIVERT_IPHDR_SET_DF(<i>hdr</i>, <i>val</i>)</tt></li>
<li><i>Reserved</i> with <tt>WINDIVERT_IPHDR_GET_RESERVED(<i>hdr</i>)</tt> and
<tt>WINDIVERT_IPHDR_SET_RESERVED(<i>hdr</i>, <i>val</i>)</tt></li>
</ul>
</p>
</dl></dd>
<a name="divert_ipv6hdr"><h3>6.2 WINDIVERT_IPV6HDR</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
typedef struct
{
UINT32 Version:4;
UINT32 ...:28;
UINT16 Length;
UINT8 NextHdr;
UINT8 HopLimit;
UINT32 SrcAddr[4];
UINT32 DstAddr[4];
} <b>WINDIVERT_IPV6HDR</b>, *<b>PWINDIVERT_IPV6HDR</b>;
</pre>
</td></tr></table>
<dl><dd>
<b>Fields</b><br>
See <a href="http://en.wikipedia.org/wiki/IPv6_packet#Fixed_header">here</a>
for more information.
</p><p>
<b>Remarks</b><br>
IPv6 header definition.
</p><p>
The following fields can only be get/set using the following macro
definitions:
<ul>
<li><i>TrafficClass</i> with
<tt>WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(<i>hdr</i>)</tt> and
<tt>WINDIVERT_IPV6HDR_SET_TRAFFICCLASS(<i>hdr</i>, <i>val</i>)</tt></li>
<li><i>FlowLabel</i> with <tt>WINDIVERT_IPV6HDR_GET_FLOWLABEL(<i>hdr</i>)</tt> and
<tt>WINDIVERT_IPV6HDR_SET_FLOWLABEL(<i>hdr</i>, <i>val</i>)</tt></li>
</ul>
</p>
</dl></dd>
<a name="divert_icmphdr"><h3>6.3 WINDIVERT_ICMPHDR</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
typedef struct
{
UINT8 Type;
UINT8 Code;
UINT16 Checksum;
UINT32 Body;
} <b>WINDIVERT_ICMPHDR</b>, *<b>PWINDIVERT_ICMPHDR</b>;
</pre>
</td></tr></table>
<dl><dd>
<b>Fields</b><br>
See <a href="http://en.wikipedia.org/wiki/Internet_Control_Message_Protocol#ICMP_segment_structure">here</a>
for more information.
</p><p>
<b>Remarks</b><br>
ICMP header definition.
</p>
</dl></dd>
<a name="divert_icmpv6hdr"><h3>6.4 WINDIVERT_ICMPV6HDR</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
typedef struct
{
UINT8 Type;
UINT8 Code;
UINT16 Checksum;
UINT32 Body;
} <b>WINDIVERT_ICMPV6HDR</b>, *<b>PWINDIVERT_ICMPV6HDR</b>;
</pre>
</td></tr></table>
<dl><dd>
<b>Fields</b><br>
See <a href="http://en.wikipedia.org/wiki/ICMPv6#Packet_format">here</a> for
more information.
</p><p>
<b>Remarks</b><br>
ICMPv6 header definition.
</p>
</dl></dd>
<a name="divert_tcphdr"><h3>6.5 WINDIVERT_TCPHDR</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
typedef struct
{
UINT16 SrcPort;
UINT16 DstPort;
UINT32 SeqNum;
UINT32 AckNum;
UINT16 Reserved1:4;
UINT16 HdrLength:4;
UINT16 Fin:1;
UINT16 Syn:1;
UINT16 Rst:1;
UINT16 Psh:1;
UINT16 Ack:1;
UINT16 Urg:1;
UINT16 Reserved2:2;
UINT16 Window;
UINT16 Checksum;
UINT16 UrgPtr;
} <b>WINDIVERT_TCPHDR</b>, *<b>PWINDIVERT_TCPHDR</b>;
</pre>
</td></tr></table>
<dl><dd>
<b>Fields</b><br>
See <a href="http://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure">here</a>
for more information.
</p><p>
<b>Remarks</b><br>
TCP header definition.
</p>
</dl></dd>
<a name="divert_udphdr"><h3>6.6 WINDIVERT_UDPHDR</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
typedef struct
{
UINT16 SrcPort;
UINT16 DstPort;
UINT16 Length;
UINT16 Checksum;
} <b>WINDIVERT_UDPHDR</b>, *<b>PWINDIVERT_UDPHDR</b>;
</pre>
</td></tr></table>
<dl><dd>
<b>Fields</b><br>
See <a href="http://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure">here</a>
for more information.
</p><p>
<b>Remarks</b><br>
UDP header definition.
</p>
</dl></dd>
<a name="divert_helper_parse_packet"><h3>6.7 WinDivertHelperParsePacket</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertHelperParsePacket</b>(
__in PVOID pPacket,
__in UINT packetLen,
__out_opt PWINDIVERT_IPHDR *ppIpHdr,
__out_opt PWINDIVERT_IPV6HDR *ppIpv6Hdr,
__out_opt PWINDIVERT_ICMPHDR *ppIcmpHdr,
__out_opt PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr,
__out_opt PWINDIVERT_TCPHDR *ppTcpHdr,
__out_opt PWINDIVERT_UDPHDR *ppUdpHdr,
__out_opt PVOID *ppData,
__out_opt UINT *pDataLen
);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>pPacket</tt>: The packet to be parsed.</li>
<li> <tt>packetLen</tt>: The total length of the packet <tt>pPacket</tt>.</li>
<li> <tt>ppIpHdr</tt>: Output pointer to a <tt>WINDIVERT_IPHDR</tt>.</li>
<li> <tt>ppIpv6Hdr</tt>: Output pointer to a <tt>WINDIVERT_IPV6HDR</tt>.</li>
<li> <tt>ppIcmpHdr</tt>: Output pointer to a <tt>WINDIVERT_ICMPHDR</tt>.</li>
<li> <tt>ppIcmpv6Hdr</tt>: Output pointer to a <tt>WINDIVERT_ICMPV6HDR</tt>.</li>
<li> <tt>ppTcpHdr</tt>: Output pointer to a <tt>WINDIVERT_TCPHDR</tt>.</li>
<li> <tt>ppUdpHdr</tt>: Output pointer to a <tt>WINDIVERT_UDPHDR</tt>.</li>
<li> <tt>ppData</tt>: Output pointer to the packet's data/payload.</li>
<li> <tt>pDataLen</tt> Output data/payload length.</li>
</ul>
</p><p>
<b>Return Value</b><br>
<tt>TRUE</tt> if all expected (non-<tt>NULL</tt>) outputs were present,
<tt>FALSE</tt> otherwise.
Note that <tt>FALSE</tt> may sometimes be a legitimate return value, e.g.,
when both <tt>ppIpHdr</tt> and <tt>ppIpv6Hdr</tt> are non-<tt>NULL</tt>.
</p><p>
<b>Remarks</b><br>
Parses a raw packet (e.g. from <a
href="#divert_recv"><tt>WinDivertRecv()</tt></a>) into the
various packet headers and/or payloads that may or may not be present.
</p><p>
Each output parameter may be <tt>NULL</tt> or non-<tt>NULL</tt>.
For non-<tt>NULL</tt> parameters, this function will write the pointer to
the corresponding header/payload if it exists, or will write <tt>NULL</tt>
otherwise.
Any non-<tt>NULL</tt> pointer that is returned
<ol>
<li> Is a pointer into the original <tt>pPacket</tt> packet; and</li>
<li> There is enough space in <tt>pPacket</tt> to fit the header.</li>
</ol>
</p><p>
This function does not do any verification of the header/payload contents
beyond checking the header length and any other minimal information required
for parsing.
<p>
</dd></dl>
<a name="divert_help_parse_ipv4_address"><h3>6.8 WinDivertHelperParseIPv4Address</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertHelperParseIPv4Address</b>(
__in const char *addrStr,
__out_opt UINT32 *pAddr
);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>addrStr</tt>: The address string.</li>
<li> <tt>pAddr</tt>: Output address.</li>
</ul>
</p><p>
<b>Return Value</b><br>
<tt>TRUE</tt> if successful, <tt>FALSE</tt> if an error occurred.
Use <tt>GetLastError()</tt> to get the reason for the error.
</p><p>
<b>Remarks</b><br>
Parses an IPv4 address stored in <tt>addrStr</tt>.
If <tt>pAddr</tt> is non-<tt>NULL</tt>, the is be stored in
host-byte-order.
Use <tt>htonl()</tt> to convert the result into network-byte-order.
</p>
<dd></dl>
<a name="divert_help_parse_ipv6_address"><h3>6.9 WinDivertHelperParseIPv6Address</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertHelperParseIPv6Address</b>(
__in const char *addrStr,
__out_opt UINT32 *pAddr
);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>addrStr</tt>: The address string.</li>
<li> <tt>pAddr</tt>: Output address.</li>
</ul>
</p><p>
<b>Return Value</b><br>
<tt>TRUE</tt> if successful, <tt>FALSE</tt> if an error occurred.
Use <tt>GetLastError()</tt> to get the reason for the error.
</p><p>
<b>Remarks</b><br>
Parses an IPv6 address stored in <tt>addrStr</tt>.
If <tt>pAddr</tt> is non-<tt>NULL</tt>, 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
<tt>0011:2233:4455:6677:8899:aabb:ccdd:eeff</tt>, then
the result is ordered as follows:
<pre>
pAddr[0] = 0xccddeeff
pAddr[1] = 0x8899aabb
pAddr[2] = 0x44556677
pAddr[3] = 0x00112233
</pre>
where each <tt>pAddr[i]</tt> is in host-byte-order.
The result can be converted into network-byte-order by setting
<tt>pAddr[i] = htonl(pAddr[i])</tt> for each <tt>i</tt> and
swapping the array indexes.
</p>
<dd></dl>
<a name="divert_helper_calc_checksums"><h3>6.10 WinDivertHelperCalcChecksums</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
UINT <b>WinDivertHelperCalcChecksums</b>(
__inout PVOID pPacket,
__in UINT packetLen,
__in_opt PWINDIVERT_ADDRESS pAddr,
__in UINT64 flags
);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>pPacket</tt>: The packet to be modified.</li>
<li> <tt>packetLen</tt>: The total length of the packet <tt>pPacket</tt>.</li>
<li> <tt>pAddr</tt>: Optional pointer to a
<a href="#divert_address"><tt>WINDIVERT_ADDRESS</tt></a> structure.</li>
<li> <tt>flags</tt>: One or more of the following flags:
<ul>
<li> <tt>WINDIVERT_HELPER_NO_IP_CHECKSUM</tt>: Do not calculate the IPv4
checksum.</li>
<li> <tt>WINDIVERT_HELPER_NO_ICMP_CHECKSUM</tt>: Do not calculate the ICMP
checksum.</li>
<li> <tt>WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM</tt>: Do not calculate the ICMPv6
checksum.</li>
<li> <tt>WINDIVERT_HELPER_NO_TCP_CHECKSUM</tt>: Do not calculate the TCP
checksum.</li>
<li> <tt>WINDIVERT_HELPER_NO_UDP_CHECKSUM</tt>: Do not calculate the UDP
checksum.</li>
</ul></li>
</ul>
</p><p>
<b>Return Value</b><br>
The number of checksums calculated.
</p><p>
<b>Remarks</b><br>
(Re)calculates the checksum for any IPv4/ICMP/ICMPv6/TCP/UDP checksum present
in the given packet.
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>
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>
If <tt>pAddr</tt> is non-<tt>NULL</tt>, this function will avoid calculating
the full checksum if the <tt>Pseudo*Checksum</tt> flag is
set in the corresponding
<a href="#divert_address"><tt>WINDIVERT_ADDRESS</tt></a> structure.
The address structure should be the same as
the one passed to <a href="#divert_send"><tt>WinDivertSend()</tt></a> in
order to (re)inject the packet.
</p>
</dd></dl>
<a name="divert_helper_check_filter"><h3>6.11 WinDivertHelperCheckFilter</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertHelperCheckFilter</b>(
__in const char *filter,
__in WINDIVERT_LAYER layer,
__out_opt const char **errorStr,
__out_opt UINT *errorPos
);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>filter</tt>: The packet filter string to be checked.</li>
<li> <tt>layer</tt>: The layer.
<li> <tt>errorStr</tt>: The error description.</li>
<li> <tt>errorPos</tt>: The error position.</li>
</ul>
</p><p>
<b>Return Value</b><br>
<tt>TRUE</tt> if the packet filter string is valid, <tt>FALSE</tt> otherwise.
</p><p>
<b>Remarks</b><br>
Checks if the given packet filter string is valid with respect to the
<a href="#filter_language">filter language</a>.
If the filter is invalid, then a human readable description of the error is
returned by <tt>errorStr</tt> (if non-<tt>NULL</tt>), and the error's
position is returned by <tt>errorPos</tt> (if non-<tt>NULL</tt>).
</p><p>
Note that all strings returned through <tt>errorStr</tt> are global static
objects, and therefore do not need to be deallocated.
<p>
</dd></dl>
<a name="divert_helper_eval_filter"><h3>6.12 WinDivertHelperEvalFilter</h3></a>
<table border="1" cellpadding="5"><tr><td>
<pre>
BOOL <b>WinDivertHelperEvalFilter</b>(
__in const char *filter,
__in WINDIVERT_LAYER layer,
__in PVOID pPacket,
__in UINT packetLen,
__in PWINDIVERT_ADDRESS pAddr
);
</pre>
</td></tr></table>
<dl><dd>
<p>
<b>Parameters</b><br>
<ul>
<li> <tt>filter</tt>: The packet filter string to be evaluated.</li>
<li> <tt>layer</tt>: The layer.
<li> <tt>pPacket</tt>: The packet.</li>
<li> <tt>packetLen</tt>: The total length of the packet <tt>pPacket</tt>.</li>
<li> <tt>pAddr</tt>: The <tt>WINDIVERT_ADDRESS</tt> of the packet
<tt>pPacket</tt>.</li>
</ul>
</p><p>
<b>Return Value</b><br>
<tt>TRUE</tt> if the packet matches the filter string,
<tt>FALSE</tt> otherwise.
</p><p>
<b>Remarks</b><br>
Evaluates the given packet against the given packet filter string.
This function returns <tt>TRUE</tt> if the packet matches, and
returns <tt>FALSE</tt> otherwise.
</p><p>
This function also returns <tt>FALSE</tt> if an error occurs, in which
case <tt>GetLastError()</tt> can be used to get the reason for the error.
Otherwise, if no error occurred, <tt>GetLastError()</tt> will return
<tt>0</tt>.
</p><p>
Note that this function is relatively slow since the packet filter string
will be (re)compiled for each call.
This function is mainly intended for debugging or testing purposes.
<p>
</dd></dl>
<hr>
<a name="filter_language"><h2>7. Filter Language</h2></a>
<p>
The <a href="#divert_open"><tt>WinDivertOpen()</tt></a> function accepts a
string containing a <i>filter expression</i>.
Only packets that match the filter expression are diverted.
Any other packet is allowed to continue as per normal.
</p><p>
Filter allows an application to select only the subset of traffic that is of
interest.
For example, a URL blacklist filter would only be interested in packets that
contain URLs.
This could be achieved via the following filter.
<pre>
HANDLE handle = WinDivertOpen(
"outbound and "
"tcp.PayloadLength &gt; 0 and "
"tcp.DstPort == 80", 0, 0, 0);
</pre>
This filter specifies that we should only divert traffic that is
<ol>
<li>outbound;</li>
<li>contains a non-empty payload; and</li>
<li>has TCP destination port 80 (i.e. HTTP web traffic).
</ol>
</p><p>
A <i>filter</i> is a Boolean expression of the form:
<pre>
<i>FILTER</i> := true | false | <i>FILTER</i> and <i>FILTER</i> | <i>FILTER</i> or <i>FILTER</i> | (<i>FILTER</i>) | (<i>FILTER</i>? <i>FILTER</i>: <i>FILTER</i>) | <i>TEST</i>
</pre>
C-style syntax <tt>&amp;&amp;</tt>, <tt>||</tt>, and <tt>!</tt> may also
be used instead of <tt>and</tt>, <tt>or</tt>, and <tt>not</tt>, respectively.
C-style <i>conditional operators</i> are also supported,
where the expression <tt>(A? B: C)</tt> evaluates to:
<ul>
<li> <tt>B</tt> if <tt>A</tt> evaluates to <tt>true</tt>; or</li>
<li> <tt>C</tt> if <tt>A</tt> evaluates to <tt>false</tt>.
</ul>
A <i>test</i> is of the following form:
<pre>
<i>TEST</i> := <i>TEST0</i> | not <i>TEST0</i>
<i>TEST0</i> := <i>FIELD</i> | <i>FIELD</i> op <i>VAL</i>
</pre>
where <tt>op</tt> is one of the following:
</p><p>
<center>
<table border="1" cellpadding="5">
<tr><th>Operator</th><th>Description</th></tr>
<tr><td><tt>==</tt> or <tt>=</tt></td><td>Equal</td></tr>
<tr><td><tt>!=</tt></td><td>Not equal</td></tr>
<tr><td><tt>&lt;</tt></td><td>Less-than</td></tr>
<tr><td><tt>&gt;</tt></td><td>Greater-than</td></tr>
<tr><td><tt>&lt;=</tt></td><td>Less-than-or-equal</td></tr>
<tr><td><tt>&gt;=</tt></td><td>Greater-than-or-equal</td></tr>
</table>
</center>
</p><p>
and <tt><i>VAL</i></tt> is a decimal number, hexadecimal number, or IP
address.
If the "<tt>op <i>VAL</i></tt>" is missing, the test is implicitly
"<tt><i>FIELD</i> != 0</tt>".
</p><p>
Finally a <i>field</i> is some property about the packet.
The possible fields are:
</p><p>
<center>
<table border="1" cellpadding="5">
<tr><th>Field</th><th>Description</th></tr>
<tr><td><tt>outbound</tt></td><td>Is outbound? (only valid for <tt>WINDIVERT_LAYER_NETWORK</tt>)</td></tr>
<tr><td><tt>inbound</tt></td><td>Is inbound? (only valid for <tt>WINDIVERT_LAYER_NETWORK</tt>)</td></tr>
<tr><td><tt>ifIdx</tt></td><td>Interface index</td></tr>
<tr><td><tt>subIfIdx</tt></td><td>Sub-interface index</td></tr>
<tr><td><tt>loopback</tt></td><td>Is loopback packet?</td></tr>
<tr><td><tt>impostor</tt></td><td>Is impostor packet?</td></tr>
<tr><td><tt>ip</tt></td><td>Is IPv4?</td></tr>
<tr><td><tt>ipv6</tt></td><td>Is IPv6?</td></tr>
<tr><td><tt>icmp</tt></td><td>Is ICMP?</td></tr>
<tr><td><tt>icmpv6</tt></td><td>Is ICMPv6?</td></tr>
<tr><td><tt>tcp</tt></td><td>Is TCP?</td></tr>
<tr><td><tt>udp</tt></td><td>Is UDP?</td></tr>
<tr><td><tt>ip.*</tt></td><td>IPv4 fields (see <tt>WINDIVERT_IPHDR</tt>)</td></tr>
<tr><td><tt>ipv6.*</tt></td><td>IPv6 fields (see <tt>WINDIVERT_IPV6HDR</tt>)</td></tr>
<tr><td><tt>icmp.*</tt></td><td>ICMP fields (see <tt>WINDIVERT_ICMPHDR</tt>)</td></tr>
<tr><td><tt>icmpv6.*</tt></td><td>ICMPV6 fields (see <tt>WINDIVERT_ICMPV6HDR</tt>)</td></tr>
<tr><td><tt>tcp.*</tt></td><td>TCP fields (see <tt>WINDIVERT_TCPHDR</tt>)</td></tr>
<tr><td><tt>tcp.PayloadLength</tt></td><td>The TCP payload length</td></tr>
<tr><td><tt>udp.*</tt></td><td>UDP fields (see <tt>WINDIVERT_UDPHDR</tt>)</td></tr>
<tr><td><tt>udp.PayloadLength</tt></td><td>The UDP payload length</td></tr>
</table>
</center>
</p><p>
A <i>test</i> also fails if the field is missing.
E.g. the test "<tt>tcp.DstPort == 80</tt>" will fail if the packet does not
contain a TCP header.
</p>
<a name="filter_examples"><h3>7.1 Filter Examples</h3></a>
<p>
<ol>
<li>
Divert all outbound (non-local) web traffic:
<pre>
HANDLE handle = WinDivertOpen(
"outbound and !loopback and "
"(tcp.DstPort == 80 or udp.DstPort == 53)",
0, 0, 0
);
</pre>
</li>
<li>
Divert all inbound TCP SYNs:
<pre>
HANDLE handle = WinDivertOpen(
"inbound and "
"tcp.Syn",
0, 0, 0
);
</pre>
</li>
<li>
Divert all traffic:
<pre>
HANDLE handle = WinDivertOpen("true", 0, 0, 0);
</pre>
</li>
<li>
Divert no traffic:
<pre>
HANDLE handle = WinDivertOpen("false", 0, 0, 0);
</pre>
This is useful for packet injection.
</ol>
<a name="filter_usage"><h3>7.2 Filter Usage</h3></a>
<p>
The purpose of the filter is to help applications select the subset of
all network traffic that the application is interested in.
Ideally the filter should be
<ol>
<li> As short as possible; and</li>
<li> As selective as possible.</li>
</ol>
For some applications these two objectives can conflict.
That is, a selective filter is not short, and a short filter is not selective.
For such applications the developer should experiment with different
filter configurations and carefully measure the performance impact to
find the optimal solution.
</p>
<hr>
<a name="samples"><h2>8. Samples</h2></a>
<p>
Some samples have been provided to demonstrate the WinDivert API.
The sample programs are:
<ul>
<li><tt>webfilter.exe</tt>: A simple URL blacklist filter.
This program monitors outbound HTTP traffic.
If it finds a URL request that matches the blacklist, it hijacks the
TCP connection, reseting the connection at the server's end, and
sending a simple block-page to the browser.
The blacklist(s) are specified at the command-line.</li>
<li><tt>netdump.exe</tt>: A simple packet sniffer based on the
WinDivert filter language.
This program takes a filter specified at the command line, and prints
information about any packet that matches the filter.
This example uses WinDivert in "packet sniffing" mode, similar to
<tt>winpcap</tt>.
However, unlike <tt>winpcap</tt>, WinDivert can see local (loopback)
packets.
<li><tt>netfilter.exe</tt>: A simple firewall based on the WinDivert
filter language.
This program takes a filter specified at the command line, and blocks
any packet that matches the filter.
It blocks TCP by sending a TCP reset, UDP by an ICMP message, and all
other traffic it simply drops.
This is similar to the Linux <tt>iptables</tt> command with the
<tt>-j REJECT</tt> option.</li>
<li><tt>passthru.exe</tt>: A simple program that simply re-injects every
packet it captures.
This example is multi-threaded, where multiple threads are processing
packets from a single handle.
This example is useful for performance testing, and as a starting point
for more interesting applications.</li>
<li><tt>streamdump.exe</tt>: A simple program that demonstrates how to
handle streams using WinDivert.
The basic idea is to divert outbound TCP connections to a local proxy
server which can capture or manipulate the stream.
The <tt>streamdump</tt> sample program also demonstrates usage of the
<a href="#divert_recv_ex"><tt>WinDivertRecvEx()</tt></a> and
<a href="#divert_send_ex"><tt>WinDivertSendEx()</tt></a> functions.</li>
</ul>
</p><p>
The samples are intended for educational purposes only, and are not
fully-featured applications.
</p><p>
The following basic template for a WinDivert application.
The basic idea is to open a WinDivert handle, then enter a
capture-modify-reinject loop:
<pre>
HANDLE handle; // WinDivert handle
WINDIVERT_ADDRESS addr; // Packet address
char packet[MAXBUF]; // Packet buffer
UINT packetLen;
handle = WinDivertOpen("...", 0, 0, 0); // Open some filter
if (handle == INVALID_HANDLE_VALUE)
{
// Handle error
exit(1);
}
// Main capture-modify-inject loop:
while (TRUE)
{
if (!WinDivertRecv(handle, packet, sizeof(packet), &amp;addr, &amp;packetLen))
{
// Handle recv error
continue;
}
// Modify packet.
WinDivertHelperCalcChecksums(packet, packetLen, &amp;addr, 0);
if (!WinDivertSend(handle, packet, packetLen, &amp;addr, NULL))
{
// Handle send error
continue;
}
}
</pre>
For applications that do not need to modify the packet, a better approach is
to open the WinDivert handle with the <tt>WINDIVERT_FLAG_SNIFF</tt> flag set,
and not re-inject the packet with
<a href="#divert_send"><tt>WinDivertSend()</tt></a>.
See the <tt>netdump.exe</tt> sample program for an example of this usage.
</p>
<hr>
<a name="known_issues"><h2>9. Known Issues</h2></a>
<p>
There are some limitations to the WinDivert package.
They are
<ul>
<li><i>Injecting inbound ICMP/ICMPv6 messages</i>:
Calling <a href="#divert_send"><tt>WinDivertSend()</tt></a> will fail with
an error for certain types of inbound ICMP/ICMPv6 messages.
This is probably because the Windows TCP/IP stack does not handle
such messages.
Such errors are harmless and can be ignored.
</li>
<li><i>The forward layer does not interact well with the Windows NAT</i>:
It is not possible to block packets pre-NAT with WinDivert.
As a general principle, you should not try and mix WinDivert at the
forward layer with the Windows NAT implementation.
</li>
<li><i>Re-injecting unmodified packets can lead to infinite loops</i>:
If two or more Windows Filtering Platform (WFP) callout drivers
(including WinDivert applications) block and inject unmodified copies of
packets then this can lead to an infinite loop.
If such a loop occurs,
<a href="#divert_send"><tt>WinDivertSend()</tt></a> will eventually fail
with error <tt>ERROR_HOST_UNREACHABLE</tt>.
Unfortunately, such errors are not easy to fix.
Some crude solutions include: (1) removing the incompatible driver, or
(2) ignoring all packets with <tt>ip.TTL</tt> or
<tt>ipv6.HopLimit</tt> less than the Windows <tt>DefaultTTL</tt>
registry value.
See <a href="https://github.com/basil00/Divert/issues/41">
GitHub issue #41</a> for more information.
</li>
<li><i>WinDivert can cause the MSVC x86_64 debugger to deadlock</i>:
The deadlock occurs because the debugger uses local sockets.
Thus: the debugger pauses the WinDivert
application, which stops packets from being processed, which
causes the debugger wait forever on input from a socket.
The deadlock can be avoided by ignoring loopback traffic.
See <a href="https://github.com/basil00/Divert/issues/26">
GitHub issue #26</a> for more information.
</li>
<li><i>WinDivert can cause packets to be out-of-order</i>:
Simply running the <tt>passthru.exe</tt> sample program can cause
packets to become out-of-order.
This is not a bug, since there is no requirement for packets to
remain in-order.
However, this may affect other buggy software
(e.g. some buggy NAT implementations)
that incorrectly assume packets to be in-order.
</li>
</ul>
</p>
<hr>
<a name="license"><h2>10. License</h2></a>
<p>
WinDivert is dual-licensed, and is available under the
<a href="http://www.gnu.org/licenses/lgpl-3.0.txt">GNU Lesser General
Public License (LGPL) Version 3</a> or the
<a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">
GNU General Public License (GPL) Version 2</a>.
Please see the notices below:
</p>
<p>
<b>LGPL version 3</b>:
<pre>
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 &lt;http://www.gnu.org/licenses/&gt;.
</pre>
</p>
<p>
<b>GPL version 2</b>:
<pre>
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.
</pre>
</p>
</body>
</html>