1539 lines
46 KiB
HTML
1539 lines
46 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<title>WinDivert 1.1 Documentation</title>
|
|
</head>
|
|
<body>
|
|
<h1>WinDivert 1.1: 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>
|
|
<li><a href="#visual_studio_2012_support">2.2 Visual Studio 2012 Support</a></li>
|
|
<li><a href="#mingw_support">2.3 MinGW Support</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>
|
|
</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>
|
|
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 package 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>Free Build Environment</i> console (or
|
|
<i>Checked Build Environment</i> for debugging).</li>
|
|
<li> In the WinDivert package root directory, run the command:
|
|
<pre>
|
|
wddk-build.bat
|
|
</pre>
|
|
This will build the following files and place them in the
|
|
<tt>install\WDDK</tt> subdirectory:
|
|
<ul>
|
|
<li> <tt>WinDivert.dll</tt>: User-mode library.</li>
|
|
<li> <tt>WinDivert32.sys</tt> or <tt>WinDivert64.sys</tt>:
|
|
Kernel-mode WDF/WFP call-out driver.</li>
|
|
<li> <tt>*.exe</tt>: Sample applications from the <tt>divert\examples</tt>
|
|
directory.</li>
|
|
</ul></li>
|
|
</ol>
|
|
<i>NOTE:</i> The <tt>WinDivert.dll</tt> and <tt>WinDivert.lib</tt> files
|
|
are only compatible with programs compiled with the WDDK compiler.
|
|
See below for Visual Studio 2012 and MinGW support.
|
|
</p>
|
|
|
|
<a name="driver_signing"><h3>2.1 Driver Signing</h3></a>
|
|
<p>
|
|
Before the WinDivert package can be used, the
|
|
<tt>WinDivert32.sys</tt>/<tt>WinDivert64.sys</tt> driver
|
|
must be digitally signed.
|
|
See <a href="http://msdn.microsoft.com/en-us/windows/hardware/gg487317.aspx">Driver Signing Requirements for Windows</a>
|
|
for more information.
|
|
</p>
|
|
|
|
<a name="visual_studio_2012_support"><h3>2.2 Visual Studio 2012 Support</h3></a>
|
|
<p>
|
|
To build the WinDivert package for Visual Studio 2012:
|
|
<ol>
|
|
<li> First build the driver by running <tt>wddk-build.bat</tt> as per the
|
|
instructions above.</li>
|
|
<li> Open a <i>Visual Studio Command Prompt</i> environment.</li>
|
|
<li> In the WinDivert package root directory, run the command:
|
|
<pre>
|
|
msvc-build.bat
|
|
</pre>
|
|
This will build Visual Studio 2012 compatible files and place them in the
|
|
<tt>install\MSVC</tt> subdirectory.</li>
|
|
</ol>
|
|
</p>
|
|
|
|
<a name="mingw_support"><h3>2.3 MinGW Support</h3></a>
|
|
<p>
|
|
To build the WinDivert package for MinGW:
|
|
<ol>
|
|
<li> First build the driver by running <tt>wddk-build.bat</tt> as per
|
|
the instructions 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 build MinGW compatible files and place them in the
|
|
<tt>install\MINGW</tt> subdirectory.</li>
|
|
</ol>
|
|
|
|
</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>
|
|
<p>
|
|
The <tt>WinDivert.dll</tt> also depends on a C run-time library.
|
|
This is not distributed with the WinDivert binaries, and must be
|
|
installed/distributed separately if required.
|
|
</p>
|
|
<center>
|
|
<table border="1" cellpadding="5" width="75%">
|
|
<tr>
|
|
<th>
|
|
Build/Compiler
|
|
</th>
|
|
<th>
|
|
C-Runtime Dependency
|
|
</th>
|
|
<th>
|
|
Installed on Windows by Default?
|
|
</th>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
WDDK (Windows Driver Kit 7.1)
|
|
</td>
|
|
<td>
|
|
<tt>MSVCRT.dll</tt>
|
|
</td>
|
|
<td>
|
|
Yes
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
MSVC (Visual Studio 2012)
|
|
</td>
|
|
<td>
|
|
<tt>MSVCRT110.dll</tt>
|
|
</td>
|
|
<td>
|
|
No.
|
|
Must be installed separately or included with your application.
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
MINGW
|
|
</td>
|
|
<td>
|
|
<tt>MSVCRT.dll</tt>
|
|
</td>
|
|
<td>
|
|
Yes
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</center>
|
|
|
|
<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 WinDivert1.1
|
|
sc delete WinDivert1.1
|
|
</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
|
|
{
|
|
UINT32 IfIdx;
|
|
UINT32 SubIfIdx;
|
|
UINT8 Direction;
|
|
} <b>WINDIVERT_ADDRESS</b>, *<b>PWINDIVERT_ADDRESS</b>;
|
|
</pre>
|
|
</td></tr></table>
|
|
<dl><dd>
|
|
<p>
|
|
<b>Fields</b>
|
|
<ul>
|
|
<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>
|
|
</ul>
|
|
</p><p>
|
|
<b>Remarks</b><br>
|
|
The <tt>WINDIVERT_ADDRESS</tt> structure represents the "address" of a captured
|
|
or injected packet.
|
|
The address includes the packet's network interfaces and the packet direction.
|
|
</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>
|
|
</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_NO_CHECKSUM</tt>
|
|
</td>
|
|
<td>
|
|
By default WinDivert ensures that each diverted packet has a valid checksum.
|
|
If the checksum is missing (e.g. with TCP checksum offloading), WinDivert
|
|
will calculate it before passing the packet to the user application.
|
|
This flag disables this behavior.
|
|
</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 <tt>WINDIVERT_ADDRESS</tt> 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>
|
|
<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 <tt>WINDIVERT_ADDRESS</tt> 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 <tt>WINDIVERT_ADDRESS</tt> 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>
|
|
<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>
|
|
</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 <tt>WINDIVERT_ADDRESS</tt> 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 512, the minimum is 1, and the maximum
|
|
is 8192.
|
|
</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 512, the minimum is 128, and the maximum is
|
|
2048.
|
|
</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 non-<tt>NULL</tt>, the result is stored in <tt>pAddr</tt>.
|
|
</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 non-<tt>NULL</tt>, the result is stored in <tt>pAddr</tt>.
|
|
The <tt>pAddr</tt> parameter is assumed to point to a buffer large enough
|
|
to hold a 16-byte IPv6 address.
|
|
</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 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>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>
|
|
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>
|
|
</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>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.
|
|
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?</td></tr>
|
|
<tr><td><tt>inbound</tt></td><td>Is inbound?</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>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 web traffic:
|
|
<pre>
|
|
HANDLE handle = WinDivertOpen(
|
|
"outbound 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 only (inbound) local traffic:
|
|
<pre>
|
|
HANDLE handle = WinDivertOpen(
|
|
"inbound and ("
|
|
"(ip.DstAddr >= 127.0.0.1 and ip.DstAddr <= 127.255.255.255) or"
|
|
"ipv6.DstAddr == ::1)",
|
|
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>
|
|
</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.
|
|
|
|
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>:
|
|
For some ICMP/ICMPv6 messages, inbound injection does not work.
|
|
An error will be returned and the packet will be lost.
|
|
The work-around is to inject inbound ICMP messages as <tt>outbound</tt>.
|
|
</li>
|
|
<li><i>No IPv6 extension header support</i>:
|
|
Currently there is no filter support for IPv6 packets with extension
|
|
headers.
|
|
The work around is to capture all IPv6 traffic.</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.
|
|
</ul>
|
|
</p>
|
|
|
|
<hr>
|
|
<a name="license"><h2>10. License</h2></a>
|
|
<p>
|
|
This package is distributed <i>strictly</i> under the
|
|
<a href="http://www.gnu.org/licenses/lgpl-3.0.txt">GNU Lesser General
|
|
Public License (GPL) Version 3</a>.
|
|
Please note the following:
|
|
<pre>
|
|
This program 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>
|
|
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
|
|
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
|
|
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
|
|
</body>
|
|
</html>
|