1794 lines
57 KiB
HTML
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->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 > 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>&&</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><</tt></td><td>Less-than</td></tr>
|
|
<tr><td><tt>></tt></td><td>Greater-than</td></tr>
|
|
<tr><td><tt><=</tt></td><td>Less-than-or-equal</td></tr>
|
|
<tr><td><tt>>=</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), &addr, &packetLen))
|
|
{
|
|
// Handle recv error
|
|
continue;
|
|
}
|
|
|
|
// Modify packet.
|
|
|
|
WinDivertHelperCalcChecksums(packet, packetLen, &addr, 0);
|
|
if (!WinDivertSend(handle, packet, packetLen, &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 <http://www.gnu.org/licenses/>.
|
|
</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>
|