- 
                Notifications
    You must be signed in to change notification settings 
- Fork 562
WinDivert Documentation
- 1. Introduction
- 2. Building
- 3. Installing
- 4. Uninstalling
- 5. Programming API
- 
6. Helper Programming API
- 6.1 WINDIVERT_IPHDR
- 6.2 WINDIVERT_IPV6HDR
- 6.3 WINDIVERT_ICMPHDR
- 6.4 WINDIVERT_ICMPV6HDR
- 6.5 WINDIVERT_TCPHDR
- 6.6 WINDIVERT_UDPHDR
- 6.7 WinDivertHelperParsePacket
- 6.8 WinDivertHelperHashPacket
- 6.9 WinDivertHelperParseIPv4Address
- 6.10 WinDivertHelperParseIPv6Address
- 6.11 WinDivertHelperFormatIPv4Address
- 6.12 WinDivertHelperFormatIPv6Address
- 6.13 WinDivertHelperCalcChecksums
- 6.14 WinDivertHelperDecrementTTL
- 6.15 WinDivertHelperCompileFilter
- 6.16 WinDivertHelperEvalFilter
- 6.17 WinDivertHelperFormatFilter
- 6.18 WinDivertHelperNtoh*
- 6.19 WinDivertHelperHton*
 
- 7. Filter Language
- 8. Performance
- 9. Samples
- 10. Known Issues
- 11. License
WinDivert is a powerful user-mode capture/sniffing/modification/blocking/re-injection package for Windows 7, Windows 8 and Windows 10. 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.
The main features of the WinDivert are:
- User-mode packet capture, sniffing, dropping, filtering, modification, re-injection, etc.
- Simple, high-level, programming API.
- Fully documented with sample programs.
- Full IPv6 support.
- Full loopback (localhost) support.
- A modern WDF/WFP driver implementation.
- Open source; Licensed under GNU Lesser General Public License (LGPL) version 3. See the License for more information.
WinDivert provides similar functionality to
divert sockets from FreeBSD/MacOS, NETLINK sockets
from Linux.
Note that pre-built WinDivert binary distributions are available from the WinDivert website. Most users do not need to build their own version of WinDivert from source.
The source code for WinDivert is available for download at:
https://github.com/basil00/Divert
To build the WinDivert drivers from source:
- Download and install Windows Driver Kit 7.1.0.
- Open a x86 Free Build Environment console.
-  In the WinDivert package root directory, run the command:
wddk-build.bat This will build theinstall\WDDK\i386\WinDivert32.sysdriver.
- Next, open a x64 Free Build Environment console.
-  Re-run the wddk-build.batcommand to build theinstall\WDDK\amd64\WinDivert64.sysdriver.
To build the WinDivert user-mode library (WinDivert.dll) and sample
programs:
-  First, build the WinDivert drivers by running the
wddk-build.batcommand described above.
-  In Linux (with the MinGW cross-compilers installed) and in the
WinDivert package root directory, run the command:
sh mingw-build.sh This will the user-mode library and sample programs which will be placed in theinstall\MINGWsubdirectory.
The generated WinDivert.dll/WinDivert.lib files
should be compatible with all major compilers, including both MinGW and
Visual Studio.
If you built your own 
WinDivert32.sys/WinDivert64.sys drivers,
they must be digitally signed before they can be used.
See Driver Signing Requirements for Windows
for more information.
Note that the pre-built WinDivert32.sys/WinDivert64.sys
drivers from the official WinDivert distribution are already digitally signed.
WinDivert does not require any special installation. Depending on your target configuration, simply place the following files in your application's home directory:
| Application Type | Target Windows Type | Files Required | 
|---|---|---|
| 32-bit | 32-bit Windows only | WinDivert.dll(32-bit version) andWinDivert32.sys | 
| 64-bit | 64-bit Windows only | WinDivert.dll(64-bit version) andWinDivert64.sys | 
| 32-bit | Both 32-bit and 64-bit Windows | WinDivert.dll(32-bit version),WinDivert32.sys,
    andWinDivert64.sys | 
The WinDivert driver is automatically (and silently) installed on demand
whenever your application calls
WinDivertOpen().
The calling application must have Administrator privileges.
To uninstall, simply delete the WinDivert.dll,
WinDivert32.sys, and WinDivert64.sys 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 (1) terminating
all processes that are using WinDivert, and (2) issuing the following
commands at the command prompt
    sc stop WinDivert
    sc delete WinDivert
Alternatively, the WinDivert driver can be removed by using the
windivertctl.exe sample program by
issuing the following command:
windivertctl uninstall
To use the WinDivert package, a program/application must:
-  Include the windivert.hheader file#include "windivert.h" 
-  Link against or dynamically load the WinDivert.dlldynamic link library.
| typedef enum
{
    WINDIVERT_LAYER_NETWORK = 0,
    WINDIVERT_LAYER_NETWORK_FORWARD,
    WINDIVERT_LAYER_FLOW,
    WINDIVERT_LAYER_SOCKET,
    WINDIVERT_LAYER_REFLECT,
} WINDIVERT_LAYER, *PWINDIVERT_LAYER;
 | 
- 
Remarks
 WinDivert supports several layers for diverting or capturing network packets/events. Each layer has its own capabilities, such as the ability to block events or to inject new events, etc. The list of supported WinDivert layers is summarized below: Layer Capability Description Block? Inject? Data? PID? WINDIVERT_LAYER_NETWORKβ β β Network packets to/from the local machine. WINDIVERT_LAYER_NETWORK_FORWARDβ β β Network packets passing through the local machine. WINDIVERT_LAYER_FLOWβ Network flow established/deleted events. WINDIVERT_LAYER_SOCKETβ β Socket operation events. WINDIVERT_LAYER_REFLECTβ β WinDivert handle events. Here, the layer capabilities are: - (Block?) the layer can block events/packets;
- (Inject?) the layer can inject new events/packets;
- (Data?) whether the layer returns packets/data or not; and
- (PID?) whether the ID for the process associated with an event/packet is available at this layer, or not.
 The WINDIVERT_LAYER_NETWORKandWINDIVERT_LAYER_NETWORK_FORWARDlayers allow the user application to capture/block/inject network packets passing to/from (and through) the local machine. Due to technical limitations, process ID information is not available at these layers.The WINDIVERT_LAYER_FLOWlayer captures information about network flow establishment/deletion events. Here, a flow represents either (1) a TCP connection, or (2) an implicitflow created by the first sent/received packet for non-TCP traffic, e.g., UDP. Old flows are deleted when the corresponding connection is closed (for TCP), or based on an activity timeout (non-TCP). Flow-related events can be captured, but not blocked nor injected. Process ID information is also available at this layer. Due to technical limitations, theWINDIVERT_LAYER_FLOWlayer cannot capture flow events that occurred before the handle was opened.The WINDIVERT_LAYER_SOCKETlayer can capture or block events corresponding to socket operations, such asbind(),connect(),listen(), etc., or the termination of socket operations, such as a TCP socket disconnection. Unlike the flow layer, most socket-related events can be blocked. However, it is not possible to inject new or modified socket events. Process ID information (of the process responsible for the socket operation) is available at this layer. Due to technical limitations, this layer cannot capture events that occurred before the handle was opened.Finally, the WINDIVERT_LAYER_REFLECTlayer can capture events relating to WinDivert itself, such as when another process opens a new WinDivert handle, or closes an old WinDivert handle. WinDivert events can be captured but not injected nor blocked. Process ID information (of the process responsible for opening the WinDivert handle) is available at this layer. This layer also returns data in the form of anobject representation of the filter string used to open the handle. The object representation can be converted back into a human-readable filter string using theWinDivertHelperFormatFilter()function. This layer can also capture events that occurred before the handle was opened. This layer cannot capture events related to otherWINDIVERT_LAYER_REFLECT-layer handles.
| typedef enum
{
    WINDIVERT_EVENT_NETWORK_PACKET,
    WINDIVERT_EVENT_FLOW_ESTABLISHED,
    WINDIVERT_EVENT_FLOW_DELETED,
    WINDIVERT_EVENT_SOCKET_BIND,
    WINDIVERT_EVENT_SOCKET_CONNECT,
    WINDIVERT_EVENT_SOCKET_LISTEN,
    WINDIVERT_EVENT_SOCKET_ACCEPT,
    WINDIVERT_EVENT_SOCKET_CLOSE,
    WINDIVERT_EVENT_REFLECT_OPEN,
    WINDIVERT_EVENT_REFLECT_CLOSE,
} WINDIVERT_EVENT, *PWINDIVERT_EVENT;
 | 
- 
Remarks
 Each layer supports one or more events summarized below: - 
WINDIVERT_LAYER_NETWORKandWINDIVERT_LAYER_NETWORK_FORWARD: Only a single event is supported:Event Description WINDIVERT_EVENT_NETWORK_PACKETA new network packet. 
- 
WINDIVERT_LAYER_FLOW: Two events are supported:Event Description WINDIVERT_EVENT_FLOW_ESTABLISHEDA new flow is created. WINDIVERT_EVENT_FLOW_DELETEDAn old flow is deleted. 
- 
WINDIVERT_LAYER_SOCKET: The following events are supported:Event Description WINDIVERT_EVENT_SOCKET_BINDA bind()operation.WINDIVERT_EVENT_SOCKET_CONNECTA connect()operation.WINDIVERT_EVENT_SOCKET_LISTENA listen()operation.WINDIVERT_EVENT_SOCKET_ACCEPTAn accept()operation.WINDIVERT_EVENT_SOCKET_CLOSEA socket endpoint is closed. This corresponds to a previous binding being released, or an established connection being terminated. The event cannot be blocked. 
- 
WINDIVERT_LAYER_REFLECT: Two events are supported:Event Description WINDIVERT_EVENT_REFLECT_OPENA new WinDivert handle was opened. WINDIVERT_EVENT_REFLECT_CLOSEAn old WinDivert handle was closed. 
 
- 
| typedef struct
{
    UINT32 IfIdx;
    UINT32 SubIfIdx;
} WINDIVERT_DATA_NETWORK, *PWINDIVERT_DATA_NETWORK;
 | 
- 
Fields -  Timestamp: A timestamp indicating when event occurred.
-  Layer: The handle's layer (WINDIVERT_LAYER_*).
-  Event: The captured event (WINDIVERT_EVENT_*).
-  Sniffed: Set to1if the event wassniffed (i.e., not blocked),0otherwise..
-  Outbound: Set to1for outbound packets/event,0for inbound or otherwise.
-  Loopback: Set to1for loopback packets,0otherwise
-  Impostor: Set to1forimpostor packets,0otherwise.
-  IPv6: Set to1for IPv6 packets/events,0otherwise
-  IPChecksum: Set to1if the IPv4 checksum is valid,0otherwise.
-  TCPChecksum: Set to1if the TCP checksum is valid,0otherwise.
-  UDPChecksum: Set to1if the UDP checksum is valid,0otherwise.
-  Network.IfIdx: The interface index on which the packet arrived (for inbound packets), or is to be sent (for outbound packets).
-  Network.SubIfIdx: The sub-interface index forIfIdx.
-  Flow.EndpointId: The endpoint ID of the flow.
-  Flow.ParentEndpointId: The parent endpoint ID of the flow.
-  Flow.ProcessId: The ID of the process associated with the flow.
-  Flow.LocalAddr,Flow.RemoteAddr,Flow.LocalPort,Flow.RemotePort, andFlow.Protocol: The network 5-tuple associated with the flow.
-  Socket.EndpointId: The endpoint ID of the socket operation.
-  Socket.ParentEndpointId: The parent endpoint ID of the socket operation.
-  Socket.ProcessId: The ID of the process associated with the socket operation.
-  Socket.LocalAddr,Socket.RemoteAddr,Socket.LocalPort,Socket.RemotePort, andSocket.Protocol: The network 5-tuple associated with the socket operation.
-  Reflect.Timestamp: A timestamp indicating when the handle was opened.
-  Reflect.ProcessId: The ID of the process that opened the handle.
-  Reflect.Layer,Reflect.Flags, andReflect.Priority: TheWinDivertOpen()parameters of the opened handle.
 Remarks 
 TheWINDIVERT_ADDRESSstructure represents the "address" of a captured or injected packet. The address includes the packet's timestamp, layer, event, flags, and layer-specific data. All fields are set byWinDivertRecv()when the packet/event is captured. Only some fields are used byWinDivertSend()when a packet is injected.The Timestampindicates when the packet/event was first captured by WinDivert. It uses the same clock asQueryPerformanceCounter().The Layerindicates the layer parameter (WINDIVERT_LAYER_*) that was passed toWinDivertOpen(). It is included in the address to make the structure self-contained.The Eventindicates the layer-specific event (WINDIVERT_EVENT_*) that was captured.The Outboundflag is set for outbound packets/events, and is cleared for inbound or direction-less packets/events.The Loopbackflag is set for loopback 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 outbound only, and will not capture loopback packets on the inbound path.The Impostorflag is set for impostor 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 byWinDivertSend()is captured again byWinDivertRecv(). For more information, seeWinDivertSend().The IPv6flag is set for IPv6 packets/events, and cleared for IPv4 packets/events.The *Checksumflags indicate whether the packet has valid checksums or not. When IP/TCP/UDP checksum offloading is enabled, it is possible that captured packets do not have valid checksums. Invalid checksums may be arbitrary values.The Network.*fields are only valid at theWINDIVERT_LAYER_NETWORKandWINDIVERT_LAYER_NETWORK_FORWARDlayers. TheNetwork.IfIdx/Network.SubIfIdxindicate the packet's network adapter (a.k.a. interface) index. These values are ignored for outbound packets.The Flow.*fields are only valid at theWINDIVERT_LAYER_FLOWlayer. TheFlow.ProcessIdis the ID of the process that created the flow (for outbound), or receives the flow (for inbound). The (Flow.LocalAddr,Flow.LocalPort,Flow.RemoteAddr,Flow.RemotePort,Flow.Protocol) fields form the network 5-tuple associated with the flow. For IPv4, theFlow.LocalAddrandFlow.RemoteAddrfields will be IPv4-mapped IPv6 addresses, e.g. the IPv4 addressX.Y.Z.Wwill be represented by::ffff:X.Y.Z.W.The Socket.*fields are only valid at theWINDIVERT_LAYER_SOCKETlayer. TheSocket.ProcessIdis the ID of the process that executed the socket operation. The (Socket.LocalAddr,Socket.LocalPort,Socket.RemoteAddr,Socket.RemotePort,Socket.Protocol) fields form the network 5-tuple associated with the operation. For IPv4, theSocket.LocalAddrandSocket.RemoteAddrfields will be IPv4-mapped IPv6 addresses. TheWINDIVERT_EVENT_SOCKET_BINDandWINDIVERT_EVENT_SOCKET_LISTENevents can occur before a connection attempt has been made, meaning that theSocket.RemoteAddrandSocket.RemotePortfields for these events will be zero.The Reflect.*fields are only valid at theWINDIVERT_LAYER_REFLECTlayer. TheReflect.ProcessIdis the ID of the process that opened the WinDivert handle. TheReflect.Timestampfield is a timestamp indicating when the handle was opened, using the same clock asQueryPerformanceCounter(). TheReflect.Layer,Reflect.Flags, andReflect.Priorityfields correspond to theWinDivertOpen()parameters of the opened handle.Most address fields are ignored by WinDivertSend(). The exceptions areOutbound(forWINDIVERT_LAYER_NETWORKonly),Impostor,IPChecksum,TCPChecksum,UDPChecksum,Network.IfIdxandNetwork.SubIfIdx.
-  
| HANDLE WinDivertOpen(
    __in const char *filter,
    __in WINDIVERT_LAYER layer,
    __in INT16 priority,
    __in UINT64 flags
);
 | 
- 
Parameters -  filter: A packet filter string specified in the WinDivert filter language.
-  layer: The layer.
-  priority: The priority of the handle.
-  flags: Additional flags.
 Return Value 
 A valid WinDivert handle on success, orINVALID_HANDLE_VALUEif an error occurred. UseGetLastError()to get the reason for the error. Common errors include:Name Code Description ERROR_FILE_NOT_FOUND2 The driver files WinDivert32.sysorWinDivert64.syswere not found.ERROR_ACCESS_DENIED5 The calling application does not have Administrator privileges. ERROR_INVALID_PARAMETER87 This indicates an invalid packet filter string, layer, priority, or flags. ERROR_INVALID_IMAGE_HASH577 The WinDivert32.sysorWinDivert64.sysdriver does not have a valid digital signature (see the driver signing requirements above).ERROR_DRIVER_FAILED_PRIOR_UNLOAD654 An incompatible version of the WinDivert driver is currently loaded. ERROR_SERVICE_DOES_NOT_EXIST1060 The handle was opened with the WINDIVERT_FLAG_NO_INSTALLflag and the WinDivert driver is not already installed.ERROR_DRIVER_BLOCKED1275 This error occurs for various reasons, including: - the WinDivert driver is blocked by security software; or
- you are using a virtualization environment that does not support drivers.
 EPT_S_NOT_REGISTERED1753 This error occurs when the Base Filtering Engine service has been disabled. Remarks 
 Opens a WinDivert handle for the given filter. Unless otherwise specified byflags, any packet or event that matches the filter will be diverted to the handle. Diverted packets/events can be read by the application withWinDivertRecv().A typical application is only interested in a subset of all network traffic or events. In this case the filter should match as closely as possible to the subset of interest. This avoids unnecessary overheads introduced by diverting packets to the user-mode application. See the filter language section for more information. The layer of the WinDivert handle is determined by the layerparameter. SeeWINDIVERT_LAYERfor more information. Currently the following layers are supported:Layer Description WINDIVERT_LAYER_NETWORK = 0Network packets to/from the local machine. This is the default layer. WINDIVERT_LAYER_NETWORK_FORWARDNetwork packets passing through the local machine. WINDIVERT_LAYER_FLOWNetwork flow established/deleted events. WINDIVERT_LAYER_SOCKETSocket operation events. WINDIVERT_LAYER_REFLECTWinDivert handle events. Different WinDivert handles can be assigned different priorities by the priorityparameter. 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. Higherpriorityvalues represent higher priorities, withWINDIVERT_PRIORITY_HIGHESTbeing the highest priority,0the middle (and a good default) priority, andWINDIVERT_PRIORITY_LOWESTthe lowest priority.Different flags affect how the opened handle behaves. The following flags are supported: Flag Description WINDIVERT_FLAG_SNIFFThis flag opens the WinDivert handle in packet sniffing 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 Winpcap.WINDIVERT_FLAG_DROPThis flag indicates that the user application does not intend to read matching packets with WinDivertRecv(), instead the packets should be silently dropped. This is useful for implementing simple packet filters using the WinDivert filter language.WINDIVERT_FLAG_RECV_ONLYThis flags forces the handle into receive only mode which effectively disablesWinDivertSend(). This means that it is possible to block/capture packets or events but not inject them.WINDIVERT_FLAG_READ_ONLYAn alias for WINDIVERT_FLAG_RECV_ONLY.WINDIVERT_FLAG_SEND_ONLYThis flags forces the handle into send only mode which effectively disablesWinDivertRecv(). This means that it is possible to inject packets or events, but not block/capture them.WINDIVERT_FLAG_WRITE_ONLYAn alias for WINDIVERT_FLAG_SEND_ONLY.WINDIVERT_FLAG_NO_INSTALLThis flags causes WinDivertOpen()to fail withERROR_SERVICE_DOES_NOT_EXISTif the WinDivert driver is not already installed. This flag is useful for querying the WinDivert state using aWINDIVERT_LAYER_REFLECThandle.Note that any combination of (WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_DROP)or(WINDIVERT_FLAG_RECV_ONLY | WINDIVERT_FLAG_SEND_ONLY)are considered invalid.Some layers have mandatory flags, as listed below: Layer Required Flags WINDIVERT_LAYER_FLOWWINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_RECV_ONLYWINDIVERT_LAYER_SOCKETWINDIVERT_FLAG_RECV_ONLYWINDIVERT_LAYER_REFLECTWINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_RECV_ONLY
-  
| BOOL WinDivertRecv(
    __in HANDLE handle,
    __out_opt PVOID pPacket,
    __in UINT packetLen,
    __out_opt UINT *pRecvLen,
    __out_opt WINDIVERT_ADDRESS *pAddr
);
 | 
- 
Parameters -  handle: A valid WinDivert handle created byWinDivertOpen().
-  pPacket: An optional buffer for the captured packet.
-  packetLen: The length of thepPacketbuffer.
-  pRecvLen: The total number of bytes written topPacket. Can beNULLif this information is not required.
-  pAddr: An optional buffer for the address of the captured packet/event.
 Return Value 
 TRUEif a packet/event was successfully received, orFALSEif an error occurred. UseGetLastError()to get the reason for the error.Common errors include: Name Code Description ERROR_INSUFFICIENT_BUFFER122 The captured packet is larger than the pPacketbuffer.ERROR_NO_DATA232 The handlehas been shutdown usingWinDivertShutdown()and the packet queue is empty.Remarks 
 Receives a single captured packet/event matching the filter passed toWinDivertOpen(). The received packet/event is guaranteed to match the filter.Only some layers can capture packets/data, as summarized below: Layer Data? Description WINDIVERT_LAYER_NETWORKβ Network packet. WINDIVERT_LAYER_NETWORK_FORWARDβ Network packet. WINDIVERT_LAYER_FLOW- WINDIVERT_LAYER_SOCKET- WINDIVERT_LAYER_REFLECTβ Filter object. For layers that do support capturing, the captured packet/data will be written to the pPacketbuffer. If non-NULL, then the total number of bytes written topPacketwill be written topRecvLen. If thepPacketbuffer is too small, the packet will be truncated and the operation will fail with theERROR_INSUFFICIENT_BUFFERerror code. This error can be ignored if the application only intends to receive part of the packet, e.g., the IP headers only. For layers that do not capture packets/data, thepPacketparameter should beNULLandpacketLenshould be zero.If non- NULL, the address of the packet/event will be written to thepAddrbuffer.An application should call WinDivertRecv()as soon as possible after a successful call toWinDivertOpen(). When a WinDivert handle is open, any packet/event that matches the filter will be captured and queued until handled byWinDivertRecv(). Packets/events are not queued indefinitely, and if not handled in a timely manner, data may be lost. The amount of time a packet/event is queued can be controlled using theWinDivertSetParam()function.Captured packets are guaranteed to have correct checksums or have the corresponding *Checksumflag unset (seeWINDIVERT_ADDRESS).WinDivertRecv()should not be used on any WinDivert handle created with theWINDIVERT_FLAG_DROPset.
-  
| BOOL WinDivertRecvEx(
    __in HANDLE handle,
    __out VOID *pPacket,
    __in UINT packetLen,
    __out_opt UINT *pRecvLen,
    __in UINT64 flags,
    __out_opt WINDIVERT_ADDRESS *pAddr,
    __inout_opt UINT *pAddrLen,
    __inout_opt LPOVERLAPPED lpOverlapped
);
 | 
- 
Parameters -  handle: A valid WinDivert handle created byWinDivertOpen().
-  pPacket: A buffer for the captured packet(s).
-  packetLen: The length of thepPacketbuffer in bytes.
-  pRecvLen: The total number of bytes written topPacket. Can beNULLif this information is not required.
-  flags: Reserved, set to zero.
-  pAddr: TheWINDIVERT_ADDRESSof the captured packet(s).
-  pAddrLen: Initially, a pointer to the length of thepAddrbuffer in bytes. This value is updated to the total bytes written topAddr. IfNULL, a fixed length ofsizeof(WINDIVERT_ADDRESS)is assumed.
-  lpOverlapped: An optional pointer to aOVERLAPPEDstructure.
 Return Value 
 TRUEif a packet was successfully received, orFALSEotherwise. UseGetLastError()to get the reason. The error codeERROR_IO_PENDINGindicates that the overlapped operation has been successfully initiated and that completion will be indicated at a later time. All other codes indicate an error.Remarks 
 This function is equivalent toWinDivertRecv()except:-  Overlapped I/O is supported via the lpOverlappedparameter.
- Batched I/O (i.e., receiving multiple packets at once) is supported.
 Batched I/O makes it possible to receive up to WINDIVERT_BATCH_MAXpackets at once using a single operation, reducing the number of kernel/user-mode context switches and improving performance. To enable batched I/O:-  pass an array of more than one WINDIVERT_ADDRESStopAddr;
-  set pAddrLento be the total size (in bytes) of thepAddrbuffer; and
-  ensure that pPacketpoints to a sufficiently large buffer capable of receiving multiple packets.
 For example: UINT8 packets[10 * MTU]; // Space for up to 10 packets WINDIVERT_ADDRESS addr[10]; // Addresses for up to 10 packets UINT addr_len = sizeof(addr); BOOL result = WinDivertRecvEx(handle, packets, ..., addr, &addr_len, ...);upon successful completion, the value pointed to by pAddrLenis updated to the total number of address bytes actually received. For example, if a total of5packets were received, then the value pointed to bypAddrLenwill be set to(5*sizeof(WINDIVERT_ADDRESS)). The received packets are packed contiguously (i.e., no gaps) into thepPacketbuffer.
-  
| BOOL WinDivertSend(
    __in HANDLE handle,
    __in const VOID *pPacket,
    __in UINT packetLen,
    __out_opt UINT *pSendLen,
    __in const WINDIVERT_ADDRESS *pAddr
);
 | 
- 
Parameters -  handle: A valid WinDivert handle created byWinDivertOpen().
-  pPacket: A buffer containing a packet to be injected.
-  packetLen: The total length of thepPacketbuffer.
-  pSendLen: The total number of bytes injected. Can beNULLif this information is not required.
-  pAddr: The address of the injected packet.
 Return Value 
 TRUEif a packet was successfully injected, orFALSEif an error occurred. UseGetLastError()to get the reason for the error.Common errors include: Name Code Description ERROR_HOST_UNREACHABLE1232 This error occurs when an impostor packet (with pAddr->Impostorset to1) is injected and theip.TTLoripv6.HopLimitfield goes to zero. This is a defense oflast resort against infinite loops caused by impostor packets.Remarks 
 Injects a packet into the network stack. The injected packet may be one received fromWinDivertRecv(), or a modified version, or a completely new packet. Injected packets can be captured and diverted again by other WinDivert handles with lower priorities.Only the WINDIVERT_LAYER_NETWORKandWINDIVERT_LAYER_NETWORK_FORWARDlayers support packet injection, as summarized below:Layer Inject? WINDIVERT_LAYER_NETWORKβ WINDIVERT_LAYER_NETWORK_FORWARDβ WINDIVERT_LAYER_FLOWWINDIVERT_LAYER_SOCKETWINDIVERT_LAYER_REFLECTFor the WINDIVERT_LAYER_NETWORKlayer thepAddr->Outboundvalue determines which direction the packet is injected. If thepAddr->Outboundfield is1, the packet will be injected into the outbound path (i.e. a packet leaving the local machine). Else, ifpAddr->Outboundis0, the packet is injected into the inbound path (i.e. a packet arriving to the local machine). Note that only theOutboundfield, and not the IP addresses in the injected packet, determines the packet's direction.For packets injected into the inbound path, the pAddr->Network.IfIdxandpAddr->Network.SubIfIdxfields are assumed to contain valid interface numbers. These may be retrieved fromWinDivertRecv()(for packet modification), or from the IP Helper API.For outbound injected packets, the IfIdxandSubIfIdxfields are currently ignored and may be arbitrary values. Injecting an inbound packet on the outbound path may work (for some types of packets), however this should be considered "undocumented" behavior, and may be changed in the future.For impostor packets (where pAddr->Impostoris set to1) WinDivert will automatically decrement theip.TTLoripv6.HopLimitfields before reinjection. This is to mitigate infinite loops since WinDivert cannot prevent impostor packets from being captured again byWinDivertRecv().Injected packets must have the correct checksums or have the corresponding pAddr->*Checksumflag unset. A packet/address pair captured byWinDivertRecv()is guaranteed to satisfy this condition, so can be reinjected unmodified without recalculating checksums. Otherwise, if a modification is necessary, checksums can be recalculated using theWinDivertHelperCalcChecksums()function.
-  
| BOOL WinDivertSendEx(
    __in HANDLE handle,
    __in const VOID *pPacket,
    __in UINT packetLen,
    __out_opt UINT *pSendLen,
    __in UINT64 flags,
    __in const WINDIVERT_ADDRESS *pAddr,
    __in UINT addrLen,
    __inout_opt LPOVERLAPPED lpOverlapped
);
 | 
- 
Parameters -  handle: A valid WinDivert handle created byWinDivertOpen().
-  pPacket: A buffer containing the packet(s) to be injected.
-  packetLen: The total length of the bufferpPacket.
-  pSendLen: The total number of bytes injected. Can beNULLif this information is not required.
-  flags: Reserved, set to zero.
-  pAddr: Theaddress(es)of the injected packet(s).
-  addrLen: The total length (in bytes) of thepAddrbuffer.
-  lpOverlapped: An optional pointer to aOVERLAPPEDstructure.
 Return Value 
 TRUEif a packet was successfully injected, orFALSEotherwise. UseGetLastError()to get the reason. The error codeERROR_IO_PENDINGindicates that the overlapped operation has been successfully initiated and that completion will be indicated at a later time. All other codes indicate an error.Remarks 
 This function is equivalent toWinDivertSend()except:-  Overlapped I/O is supported via the lpOverlappedparameter.
- Batched I/O (i.e., sending multiple packets at once) is supported.
 Batched I/O makes it possible to send up to WINDIVERT_BATCH_MAXpackets at once using a single operation, reducing the number of kernel/user-mode context switches and improving performance. To use batched I/O:-  pack N packets into the pPacketbuffer (with no gaps between packets);
-  set packetLento be the total sum of the N packet lengths;
-  pack the corresponding N WINDIVERT_ADDRESSaddress structures into thepAddrbuffer; and
-  set addrLento be the total size (in bytes) of thepAddrbuffer.
 
-  
| BOOL WinDivertShutdown(
    __in HANDLE handle,
    __in WINDIVERT_SHUTDOWN how);
);
 | 
- 
Parameters -  handle: A valid WinDivert handle created byWinDivertOpen().
-  how: AWINDIVERT_SHUTDOWNvalue to indicate how the handle should be shutdown.
 Return Value 
 TRUEif successful,FALSEif an error occurred. UseGetLastError()to get the reason for the error.Remarks 
 This operation causes all or part of a WinDivert handle to be shut down. The possible values forhoware:How Description WINDIVERT_SHUTDOWN_RECVStop new packets being queued for WinDivertRecv().WINDIVERT_SHUTDOWN_SENDStop new packets being injected via WinDivertSend().WINDIVERT_SHUTDOWN_BOTHEquivalent to (WINDIVERT_SHUTDOWN_RECV | WINDIVERT_SHUTDOWN_SEND).Note that previously queued packets can still be received after WINDIVERT_SHUTDOWN_RECV. When the packet queue is empty,WinDivertRecv()will fail withERROR_NO_DATA.
-  
| BOOL WinDivertClose(
    __in HANDLE handle
);
 | 
- 
Parameters -  handle: A valid WinDivert handle created byWinDivertOpen().
 Return Value 
 TRUEif successful,FALSEif an error occurred. UseGetLastError()to get the reason for the error.Remarks 
 Closes a WinDivert handle created byWinDivertOpen().
-  
| BOOL WinDivertSetParam(
    __in HANDLE handle,
    __in WINDIVERT_PARAM param,
    __in UINT64 value);
 | 
- 
Parameters -  handle: A valid WinDivert handle created byWinDivertOpen().
-  param: A WinDivert parameter name.
-  value: The parameter's new value.
 Return Value 
 TRUEif successful,FALSEif an error occurred. UseGetLastError()to get the reason for the error.Remarks 
 Sets a WinDivert parameter. Currently, the following WinDivert parameters are defined.Parameter Description WINDIVERT_PARAM_QUEUE_LENGTHSets the maximum length of the packet queue for WinDivertRecv(). The default value isWINDIVERT_PARAM_QUEUE_LENGTH_DEFAULT, the minimum isWINDIVERT_PARAM_QUEUE_LENGTH_MIN, and the maximum isWINDIVERT_PARAM_QUEUE_LENGTH_MAX.WINDIVERT_PARAM_QUEUE_TIMESets 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 minimum time a packet can be queued before it can be dropped. The actual time may be exceed this value. Currently the default value is WINDIVERT_PARAM_QUEUE_TIME_DEFAULT, the minimum isWINDIVERT_PARAM_QUEUE_TIME_MIN, and the maximum isWINDIVERT_PARAM_QUEUE_TIME_MAX.WINDIVERT_PARAM_QUEUE_SIZESets the maximum number of bytes that can be stored in the packet queue for WinDivertRecv(). Currently the default value isWINDIVERT_PARAM_QUEUE_SIZE_DEFAULT, the minimum isWINDIVERT_PARAM_QUEUE_SIZE_MIN, and the maximum isWINDIVERT_PARAM_QUEUE_SIZE_MAX.
-  
| BOOL WinDivertGetParam(
    __in HANDLE handle,
    __in WINDIVERT_PARAM param,
    __out UINT64 *pValue);
 | 
- 
Parameters -  handle: A valid WinDivert handle created byWinDivertOpen().
-  param: A WinDivert parameter name.
-  value: The parameter's current value.
 Return Value 
 TRUEif successful,FALSEif an error occurred. UseGetLastError()to get the reason for the error.Remarks 
 Gets a WinDivert parameter. This function supports all the parameters fromWinDivertSetParam(), and the following additionalread-only parameters:Parameter Description WINDIVERT_PARAM_VERSION_MAJORReturns the major version of the driver. WINDIVERT_PARAM_VERSION_MINORReturns the minor version of the driver. 
-  
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 optional.
| typedef struct
{
    UINT8  HdrLength:4;
    UINT8  Version:4;
    UINT8  TOS;
    UINT16 Length;
    UINT16 Id;
    UINT16 ...;
    UINT8  TTL;
    UINT8  Protocol;
    UINT16 Checksum;
    UINT32 SrcAddr;
    UINT32 DstAddr;
} WINDIVERT_IPHDR, *PWINDIVERT_IPHDR;
 | 
- 
Fields 
 See here for more information.Remarks 
 IPv4 header definition.The following fields can only be get/set using the following macro definitions: - 
FragOff with WINDIVERT_IPHDR_GET_FRAGOFF(hdr)andWINDIVERT_IPHDR_SET_FRAGOFF(hdr, val)
- 
MF with WINDIVERT_IPHDR_GET_MF(hdr)andWINDIVERT_IPHDR_SET_MF(hdr, val)
- 
DF with WINDIVERT_IPHDR_GET_DF(hdr)andWINDIVERT_IPHDR_SET_DF(hdr, val)
- 
Reserved with WINDIVERT_IPHDR_GET_RESERVED(hdr)andWINDIVERT_IPHDR_SET_RESERVED(hdr, val)
 
- 
FragOff with 
| typedef struct
{
    UINT32 Version:4;
    UINT32 ...:28;
    UINT16 Length;
    UINT8  NextHdr;
    UINT8  HopLimit;
    UINT32 SrcAddr[4];
    UINT32 DstAddr[4];
} WINDIVERT_IPV6HDR, *PWINDIVERT_IPV6HDR;
 | 
- 
Fields 
 See here for more information.Remarks 
 IPv6 header definition.The following fields can only be get/set using the following macro definitions: - 
TrafficClass with
    WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(hdr)andWINDIVERT_IPV6HDR_SET_TRAFFICCLASS(hdr, val)
- 
FlowLabel with WINDIVERT_IPV6HDR_GET_FLOWLABEL(hdr)andWINDIVERT_IPV6HDR_SET_FLOWLABEL(hdr, val)
 
- 
TrafficClass with
    
| typedef struct
{
    UINT8  Type;
    UINT8  Code;
    UINT16 Checksum;
    UINT32 Body;
} WINDIVERT_ICMPHDR, *PWINDIVERT_ICMPHDR;
 | 
- 
Fields 
 See here for more information.Remarks 
 ICMP header definition.
| typedef struct
{
    UINT8  Type;
    UINT8  Code;
    UINT16 Checksum;
    UINT32 Body;
} WINDIVERT_ICMPV6HDR, *PWINDIVERT_ICMPV6HDR;
 | 
- 
Fields 
 See here for more information.Remarks 
 ICMPv6 header definition.
| 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;
} WINDIVERT_TCPHDR, *PWINDIVERT_TCPHDR;
 | 
- 
Fields 
 See here for more information.Remarks 
 TCP header definition.
| typedef struct
{
    UINT16 SrcPort;
    UINT16 DstPort;
    UINT16 Length;
    UINT16 Checksum;
} WINDIVERT_UDPHDR, *PWINDIVERT_UDPHDR;
 | 
- 
Fields 
 See here for more information.Remarks 
 UDP header definition.
| BOOL WinDivertHelperParsePacket(
    __in PVOID pPacket,
    __in UINT packetLen,
    __out_opt PWINDIVERT_IPHDR *ppIpHdr,
    __out_opt PWINDIVERT_IPV6HDR *ppIpv6Hdr,
    __out_opt UINT8 *pProtocol,
    __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,
    __out_opt PVOID *ppNext,
    __out_opt UINT *pNextLen
);
 | 
- 
Parameters -  pPacket: The packet(s) to be parsed.
-  packetLen: The total length of the packet(s)pPacket.
-  ppIpHdr: Output pointer to aWINDIVERT_IPHDR.
-  ppIpv6Hdr: Output pointer to aWINDIVERT_IPV6HDR.
-  pProtocol: Output transport protocol.
-  ppIcmpHdr: Output pointer to aWINDIVERT_ICMPHDR.
-  ppIcmpv6Hdr: Output pointer to aWINDIVERT_ICMPV6HDR.
-  ppTcpHdr: Output pointer to aWINDIVERT_TCPHDR.
-  ppUdpHdr: Output pointer to aWINDIVERT_UDPHDR.
-  ppData: Output pointer to the packet's data/payload.
-  pDataLen: Output data/payload length.
-  ppNext: Output pointer to the next packet (if present).
-  pNextLen: Output next packet length.
 Return Value 
 TRUEif successful,FALSEif an error occurred.Remarks 
 Parses a raw packet or batch of packets (e.g. fromWinDivertRecv()) into the various packet headers and/or payloads that may or may not be present.Each output parameter may be NULLor non-NULL. For non-NULLparameters, this function will write the pointer to the corresponding header/payload if it exists, or will writeNULLotherwise. Any non-NULLpointer that is returned:-  Is a pointer into the original pPacketpacket buffer; and
-  There is enough space in pPacketto fit the header.
 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. This function will always succeed provided the pPacketbuffer contains at least one IPv4 or IPv6 header and thepacketLenis correct.By default this function will parse a single packet. However, if either ppNextorpNextLenare non-NULL, then thepPacketparameter can point to a batch (>1) of packets (andpacketLencan be the total length of the batch). In this case, the function will parse the first packet, and a pointer to the remaining packet(s) will be written toppNext, and the remaining length will be written topNextLen. This makes it convenient to loop over every packet in the batch as follows:while (WinDivertHelperParsePacket(pPacket, packetLen, ..., &pPacket, &packetLen)) { ... }
-  
| UINT64 WinDivertHelperHashPacket(
    __in const VOID *pPacket,
    __in UINT packetLen,
    __in UINT64 seed = 0
);
 | 
- 
Parameters -  pPacket: The packet to be hashed.
-  packetLen: The total length of the packetpPacket.
-  seed: An optional seed value.
 Return Value 
 A 64bit hash value.Remarks 
 Calculates a 64bit hash value of the given packet. Note that the hash function depends on the packet's IP and transport headers only, and not the payload of the packet. That said, a weak dependency on the payload will exist if the TCP/UDP checksums are valid. The hash function itself is based on the xxHash algorithm and is not cryptographic.The optional seedvalue is also incorporated into the hash.
-  
| BOOL WinDivertHelperParseIPv4Address(
    __in const char *addrStr,
    __out_opt UINT32 *pAddr
);
 | 
- 
Parameters -  addrStr: The address string.
-  pAddr: Output address.
 Return Value 
 TRUEif successful,FALSEif an error occurred. UseGetLastError()to get the reason for the error.Remarks 
 Parses an IPv4 address stored inaddrStr. IfpAddris non-NULL, the result is be stored in host-byte-order. UseWinDivertHelperHtonl()to convert the result into network-byte-order.
-  
| BOOL WinDivertHelperParseIPv6Address(
    __in const char *addrStr,
    __out_opt UINT32 *pAddr
);
 | 
- 
Parameters -  addrStr: The address string.
-  pAddr: Output address.
 Return Value 
 TRUEif successful,FALSEif an error occurred. UseGetLastError()to get the reason for the error.Remarks 
 Parses an IPv6 address stored inaddrStr. IfpAddris non-NULL, the buffer assumed to be large enough to hold a 16-byte IPv6 address. The result is stored in host-byte-order. UseWinDivertHelperHtonIpv6Address()to convert the result into network-byte-order.
-  
| BOOL WinDivertHelperFormatIPv4Address(
    __in UINT32 addr,
    __out char *buffer,
    __in UINT bufLen
);
 | 
- 
Parameters -  addr: The IPv4 address in host-byte order.
-  buffer: The buffer to store the formatted string.
-  bufLen: The length ofbuffer.
 Return Value 
 TRUEif successful,FALSEif an error occurred. UseGetLastError()to get the reason for the error.Remarks 
 Convert an IPv4 address into a string.
-  
| BOOL WinDivertHelperFormatIPv6Address(
    __in const UINT32 *pAddr,
    __out char *buffer,
    __in UINT bufLen
);
 | 
- 
Parameters -  pAddr: The IPv6 address in host-byte order.
-  buffer: The buffer to store the formatted string.
-  bufLen: The length ofbuffer.
 Return Value 
 TRUEif successful,FALSEif an error occurred. UseGetLastError()to get the reason for the error.Remarks 
 Convert an IPv6 address into a string.
-  
| BOOL WinDivertHelperCalcChecksums(
    __inout VOID *pPacket,
    __in UINT packetLen,
    __out_opt WINDIVERT_ADDRESS *pAddr,
    __in UINT64 flags
);
 | 
- 
Parameters -  pPacket: The packet to be modified.
-  packetLen: The total length of the packetpPacket.
-  pAddr: Optional pointer to aWINDIVERT_ADDRESSstructure.
-  flags: One or more of the following flags:-  WINDIVERT_HELPER_NO_IP_CHECKSUM: Do not calculate the IPv4 checksum.
-  WINDIVERT_HELPER_NO_ICMP_CHECKSUM: Do not calculate the ICMP checksum.
-  WINDIVERT_HELPER_NO_ICMPV6_CHECKSUM: Do not calculate the ICMPv6 checksum.
-  WINDIVERT_HELPER_NO_TCP_CHECKSUM: Do not calculate the TCP checksum.
-  WINDIVERT_HELPER_NO_UDP_CHECKSUM: Do not calculate the UDP checksum.
 
-  
 Return Value 
 TRUEif successful,FALSEif an error occurred.Remarks 
 (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 withWinDivertSend().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). If pAddris non-NULL, this function sets the corresponding*Checksumflag (seeWINDIVERT_ADDRESS). Normally,pAddrshould point to the address passed toWinDivertSend()for packet injection.
-  
| BOOL WinDivertHelperDecrementTTL(
    __inout VOID *packet,
    __in packetLen
);
 | 
- 
Parameters -  pPacket: The packet to be modified.
-  packetLen: The total length of the packetpPacket.
 Return Value 
 TRUEif successful,FALSEif an error occurred. ReturnsFALSEif theip.TTLoripv6.HopHimitfields go to0.Remarks 
 Decrements theip.TTLoripv6.HopHimitfield by1, and returnsTRUEonly if the result is non-zero. This is useful for applications where packet loops may be a problem.For IPv4, this function will preserve the validity of the IPv4 checksum. That is, if the packet had a valid checksum before the operation, the resulting checksum will also be valid after the operation. This function updates the checksum field incrementally. 
-  
| BOOL WinDivertHelperCompileFilter(
    __in const char *filter,
    __in WINDIVERT_LAYER layer,
    __out_opt char *object,
    __in UINT objLen,
    __out_opt const char **errorStr,
    __out_opt UINT *errorPos
);
 | 
- 
Parameters -  filter: The packet filter string to be checked.
-  layer: The layer.
-  object: The compiled filter object.
-  objLen: The length of theobjectbuffer.
-  errorStr: The error description.
-  errorPos: The error position.
 Return Value 
 TRUEif the packet filter compilation is successful,FALSEotherwise.Remarks 
 Compiles the given packet filter string into a compactobject representation that is optionally stored inobjectif non-NULL. Theobject representation is a valid null terminated C string, but is otherwise opaque and not meant to be human readable. The object representation can be passed to all WinDivert functions, such asWinDivertOpen(), in place of the human-readable filter string equivalent.The compilation operation will succeed if the given filter string is valid with respect to the filter language. Otherwise, if the filter is invalid, then a human readable description of the error is returned by errorStr(if non-NULL), and the error's position is returned byerrorPos(if non-NULL).Note that all strings returned through errorStrare global static objects, and therefore do not need to be deallocated.
-  
| BOOL WinDivertHelperEvalFilter(
    __in const char *filter,
    __in const VOID *pPacket,
    __in UINT packetLen,
    __in const WINDIVERT_ADDRESS *pAddr
);
 | 
- 
Parameters -  filter: The packet filter string to be evaluated.
-  pPacket: The packet.
-  packetLen: The total length of the packetpPacket.
-  pAddr: TheWINDIVERT_ADDRESSof the packetpPacket.
 Return Value 
 TRUEif the packet matches the filter string,FALSEotherwise.Remarks 
 Evaluates the given packet against the given packet filter string. This function returnsTRUEif the packet matches, and returnsFALSEotherwise.This function also returns FALSEif an error occurs, in which caseGetLastError()can be used to get the reason for the error. Otherwise, if no error occurred,GetLastError()will return0.Note that this function is relatively slow since the packet filter string will be (re)compiled for each call. This overhead can be minimized by pre-compiling the filter string into the object representation using the WinDivertHelperCompileFilter()function.
-  
| BOOL WinDivertHelperEvalFilter(
    __in const char *filter,
    __in WINDIVERT_LAYER layer,
    __out char *buffer,
    __in UINT bufLen
);
 | 
- 
Parameters -  filter: The packet filter string to be evaluated.
-  layer: The layer.
-  buffer: A buffer for the formatted filter.
-  bufLen: The length ofbuffer.
 Return Value 
 TRUEif successful,FALSEif an error occurred. UseGetLastError()to get the reason for the error.Remarks 
 Formats the given filter string or object. This function is mainly useful fordecompiling the filter object representation back into a human-readable filter string representation. One application is theWINDIVERT_LAYER_REFLECTlayer, where the filter object associated with the reflection event is returned byWinDivertRecv().
-  
| UINT16 WinDivertHelperNtohs(
    __in UINT16 x
);
UINT32 WinDivertHelperNtohl(
    __in UINT32 x
);
UINT64 WinDivertHelperNtohll(
    __in UINT64 x
);
void WinDivertHelperNtohIpv6Address(
    __in const UINT *inAddr,
    __out UINT *outAddr
);
 | 
- 
Parameters -  x: The input value in network byte-order.
-  inAddr: The input IPv6 address in network byte-order.
-  outAddr: A buffer for the output IPv6 address in host byte-order.
 Return Value 
 The output value in host byte order.Remarks 
 Converts a value/IPv6-address from network to host byte-order.
-  
| UINT16 WinDivertHelperHtons(
    __in UINT16 x
);
UINT32 WinDivertHelperHtonl(
    __in UINT32 x
);
UINT64 WinDivertHelperHtonll(
    __in UINT64 x
);
void WinDivertHelperHtonIpv6Address(
    __in const UINT *inAddr,
    __out UINT *outAddr
);
 | 
- 
Parameters -  x: The input value in host byte-order.
-  inAddr: The input IPv6 address in host byte-order.
-  outAddr: A buffer for the output IPv6 address in network byte-order.
 Return Value 
 The output value in network byte order.Remarks 
 Converts a value/IPv6-address from host to network byte-order.
-  
The WinDivertOpen() function accepts a
string containing a filter.
Only packets/events that match the filter will be blocked and/or captured.
All other non-matching packets/events will be allowed to continue as normal.
The filter allows an application to select only a subset traffic that is of interest. For example, a HTTP blacklist filter is only interested in packets that might contain URLs. This could be achieved using the following filter.
HANDLE handle = WinDivertOpen(
    "outbound and "
    "tcp.PayloadLength > 0 and "
    "tcp.DstPort == 80", 0, 0, 0);
This filter selects only the subset of all traffic that is:
- outbound;
- contains a non-empty payload; and
- has TCP destination port 80 (i.e. HTTP web traffic).
A filter is a Boolean expression of the form:
FILTER := true | false | FILTER and FILTER | FILTER or FILTER | (FILTER) | (FILTER? FILTER: FILTER) | TEST
C-style syntax &&, ||, and ! may also
be used instead of and, or, and not, respectively.
C-style conditional operators are also supported,
where the expression (A? B: C) evaluates to:
-  BifAevaluates totrue; or
-  CifAevaluates tofalse.
A test is of the following form:
        TEST := TEST0 | not TEST0
        TEST0 := FIELD | FIELD op VAL
where op is one of the following:
| Operator | Description | 
|---|---|
| ==or= | Equal | 
| != | Not equal | 
| < | Less-than | 
| > | Greater-than | 
| <= | Less-than-or-equal | 
| >= | Greater-than-or-equal | 
and VAL is a decimal number, hexadecimal number, IPv4
address, IPv6 address or a layer-specific macro.
If the 
 is missing, the test is implicitly
op VAL
.
FIELD != 0
Finally, a field is some layer-specific property matching the packet or event. The possible fields are:
| Field | Layer | Description | ||||
|---|---|---|---|---|---|---|
| NETWORK | FORWARD | FLOWΒ Β Β  | SOCKETΒ  | REFLECT | ||
| zero | β | β | β | β | β | The value zero | 
| timestamp | β | β | β | β | β | The packet/event timestamp | 
| event | β | β | β | β | β | The event | 
| outbound | β | β | Is outbound? | |||
| inbound | β | β | Is inbound? | |||
| ifIdx | β | β | Interface index | |||
| subIfIdx | β | β | Sub-interface index | |||
| loopback | β | β | β | Is loopback packet? | ||
| impostor | β | β | Is impostor packet? | |||
| endpointId | β | β | Endpoint ID | |||
| parentEndpointId | β | β | Parent endpoint ID | |||
| processId | β | β | β | Process ID | ||
| random8 | β | β | 8-bit random number | |||
| random16 | β | β | 16-bit random number | |||
| random32 | β | β | 32-bit random number | |||
| layer | β | The handle's layer | ||||
| priority | β | The handle's priority | ||||
| packet[i] | β | β | The ith 8-bit word of the packet | |||
| packet16[i] | β | β | The ith 16-bit word of the packet | |||
| packet32[i] | β | β | The ith 32-bit word of the packet | |||
| length | β | β | The packet length | |||
| ip | β | β | β | β | Is IPv4? | |
| ipv6 | β | β | β | β | Is IPv6? | |
| icmp | β | β | β | β | Is ICMP? | |
| icmpv6 | β | β | β | β | Is ICMPv6? | |
| tcp | β | β | β | β | Is TCP? | |
| udp | β | β | β | β | Is UDP? | |
| protocol | β | β | β | The protocol | ||
| localAddr | β | β | β | The local address | ||
| localPort | β | β | β | The local port | ||
| remoteAddr | β | β | β | The remote address | ||
| remotePort | β | β | β | The remote port | ||
| ip.* | β | β | IPv4 fields (see WINDIVERT_IPHDR) | |||
| ipv6.* | β | β | IPv6 fields (see WINDIVERT_IPV6HDR) | |||
| icmp.* | β | β | ICMP fields (see WINDIVERT_ICMPHDR) | |||
| icmpv6.* | β | β | ICMPV6 fields (see WINDIVERT_ICMPV6HDR) | |||
| tcp.* | β | β | TCP fields (see WINDIVERT_TCPHDR) | |||
| tcp.PayloadLength | β | β | The TCP payload length | |||
| tcp.Payload[i] | β | β | The ith 8-bit word of the TCP payload | |||
| tcp.Payload16[i] | β | β | The ith 16-bit word of the TCP payload | |||
| tcp.Payload32[i] | β | β | The ith 32-bit word of the TCP payload | |||
| udp.* | β | β | UDP fields (see WINDIVERT_UDPHDR) | |||
| udp.PayloadLength | β | β | The UDP payload length | |||
| udp.Payload[i] | β | β | The ith 8-bit word of the UDP payload | |||
| udp.Payload16[i] | β | β | The ith 16-bit word of the UDP payload | |||
| udp.Payload32[i] | β | β | The ith 32-bit word of the UDP payload | |||
A test will also fails if the field is not relevant.
For example, the test 
 will fail if the
packet does not contain a TCP header.
tcp.DstPort == 80
The processId field matches the ID of the process associated
to an event.
Due to technical limitations, this field is not supported by the
WINDIVERT_LAYER_NETWORK* layers.
That said, it is usually possible to associate process IDs to network packets 
matching the same network 5-tuple.
Note that a fundamental race condition exists between the processId
and the termination of the corresponding process, see
the know issues listed below.
The packet*[i], tcp.Payload*[i] and
udp.Payload*[i] fields take an index parameter (i).
The following indexing schemes are supported:
-  Undecorated integer (e.g., packet32[10]): evaluates to theith word from the start of the packet/payload. This is essentially C-style array indexing;
-  Negative decorated integer (e.g., packet32[-10]): evaluates to theith word from the end of the packet/payload. Here the index (-1) is the first full word that fits; and
-  Byte decorated (negative) integer (e.g., packet32[10b]orpacket32[-10b]): evaluated to the word offset byibytes from the start (or end) of the packet/payload.
These fields can be used to match filters against the contents of packets/payloads in addition to address/header information. Words are assumed to be in network-byte ordering. If the index is out-of-bounds then the corresponding test is deemed to have failed.
The random* fields are not really random but use a
deterministic hash value calculated using the
WinDivertHelperHashPacket()
function.
Layer-specific macros make it possible to match events
and layers symbolically, e.g., 
 or
event == CONNECT
.
The possible macros are:
layer == SOCKET
| Macro | Layer | Value | ||||
|---|---|---|---|---|---|---|
| NETWORK | FORWARD | FLOWΒ Β Β  | SOCKETΒ  | REFLECT | ||
| TRUE | β | β | β | β | β | 1 | 
| FALSE | β | β | β | β | β | 0 | 
| TCP | β | β | β | β | β | IPPROTO_TCP(6) | 
| UDP | β | β | β | β | β | IPPROTO_UDP(17) | 
| ICMP | β | β | β | β | β | IPPROTO_ICMP(1) | 
| ICMPV6 | β | β | β | β | β | IPPROTO_ICMPV6(58) | 
| PACKET | β | β | WINDIVERT_EVENT_NETWORK_PACKET | |||
| ESTABLISHED | β | WINDIVERT_EVENT_FLOW_ESTABLISHED | ||||
| DELETED | β | WINDIVERT_EVENT_FLOW_DELETED | ||||
| BIND | β | WINDIVERT_EVENT_SOCKET_BIND | ||||
| CONNECT | β | WINDIVERT_EVENT_SOCKET_CONNECT | ||||
| ACCEPT | β | WINDIVERT_EVENT_SOCKET_ACCEPT | ||||
| LISTEN | β | WINDIVERT_EVENT_SOCKET_LISTEN | ||||
| OPEN | β | WINDIVERT_EVENT_REFLECT_OPEN | ||||
| CLOSE | β | β | WINDIVERT_EVENT_SOCKET_CLOSEfor theSOCKETlayer, orWINDIVERT_EVENT_REFLECT_CLOSEfor theREFLECTlayer. | |||
| NETWORK | β | WINDIVERT_LAYER_FLOW_NETWORK | ||||
| NETWORK_FORWARD | β | WINDIVERT_LAYER_FLOW_NETWORK_FORWARD | ||||
| FLOW | β | WINDIVERT_LAYER_FLOW_FLOW | ||||
| SOCKET | β | WINDIVERT_LAYER_FLOW_SOCKET | ||||
| REFLECT | β | WINDIVERT_LAYER_FLOW_REFLECT | ||||
- 
Divert all outbound (non-local) web traffic:
HANDLE handle = WinDivertOpen( "outbound and !loopback and " "(tcp.DstPort == 80 or udp.DstPort == 53)", 0, 0, 0 );
- 
Divert all inbound TCP SYNs:
HANDLE handle = WinDivertOpen( "inbound and " "tcp.Syn", 0, 0, 0 );
- 
Divert all traffic:
HANDLE handle = WinDivertOpen("true", 0, 0, 0);
- 
Divert no traffic:
HANDLE handle = WinDivertOpen("false", 0, 0, 0);This is useful for packet injection.
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
- As short as possible; and
- As selective as possible.
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.
Using WinDivert to redirect network traffic to/from a user application incurs performance overheads, such as copying packet data and user/kernel mode context switching. Under heavy load (≥1Gbps) these overheads can be significant. The following techniques can be used to reduce overheads (in order of importance):
- Selective Filter: Only select the subset of network traffic the user application is interested in. Non-matching traffic will continue to use the default path without incurring additional overheads.
- Batch Mode: The WinDivertRecvEx() and WinDivertSendEx() functions support batching that allows several packets to be received/sent at once. This can significantly reduce the overheads relating to user/kernel mode context switching.
- Multi-threading: It is possible to spread packet processing over multiple threads ensuring that the user application does not become a bottleneck. That said, sometimes spawning too many threads can degrade performance.
- Small Buffers: Large buffers generally incur more overhead compared to smaller buffers. In general, the buffer size should reflect the expected usage as closely as possible.
- Simple Filters: Currently WinDivert does not optimize the filter compilation, so it is up to the user application to ensure the filter is simple/optimized.
- 
Overlapped I/O: This allows the user application to do
    additional tasks at the same time as receive/send operations, which may
    improve performance for some applications.
    It is also possible for a single thread to initiate several
    receive/send operations at once.
    However, using overlapped I/O can be tricky, and it is important
    that all buffers passed to
    WinDivertRecvEx() or
    WinDivertSendEx() 
    (including the OVERLAPPEDstructure) are not modified by the user application until the operation completes.
- Queue length/size/time: If these values are too small then some packets may be dropped under heavy load. These values can be controlled using the WinDivertSetParam() function.
The passthru.exe sample program can
be used to experiment with different batch sizes and thread counts.
Some samples have been provided to demonstrate the WinDivert API. The sample programs are:
- 
webfilter.exe: 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.
- 
netdump.exe: 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 towinpcap. However, unlikewinpcap, WinDivert can see local (loopback) packets.
- 
netfilter.exe: 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 Linuxiptablescommand with the-j REJECToption.
- 
passthru.exe: A simple program that simply re-injects every packet it captures. This example has a configurable batch-size and thread count, and so is useful for performance testing or as a starting point for more interesting applications.
- 
streamdump.exe: 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.
- 
flowtrack.exe: A program that tracks all network flows to and from the local machine, including information such as the ID of the responsible process. Theflowtracksample demonstrates theWINDIVERT_LAYER_FLOWlayer.
- 
socketdump.exe: Dumps socket operations (bind(),connect(), etc.) and the ID of the responsible process. Thesocketdumpsample demonstrates theWINDIVERT_LAYER_SOCKETlayer.
- 
windivertctl.exeallows the user to query which processes are using WinDivert via thelistorwatchcommands, or to terminate all such processes using thekillcommand. Thewindivertctl.execan also forcibly remove the WinDivert driver using theuninstallcommand. Thewindivertctlsample demonstrates theWINDIVERT_LAYER_REFLECTlayer.
The samples are intended for educational purposes only, and are not fully-featured applications.
The following basic template for a WinDivert application using the
WINDIVERT_LAYER_NETWORK layer.
The basic idea is to open a WinDivert handle, then enter a
capture-modify-reinject loop:
    HANDLE handle;          // WinDivert handle
    WINDIVERT_ADDRESS addr; // Packet address
    char packet[MAXBUF];    // Packet buffer
    UINT packetLen;
// Open some filter
handle = WinDivertOpen("...", WINDIVERT_LAYER_NETWORK, 0, 0);
if (handle == INVALID_HANDLE_VALUE)
{
    // Handle error
    exit(1);
}
// Main capture-modify-inject loop:
while (TRUE)
{
    if (!WinDivertRecv(handle, packet, sizeof(packet), &packetLen, &addr))
    {
        // Handle recv error
        continue;
    }
    // Modify packet.
    WinDivertHelperCalcChecksums(packet, packetLen, &addr, 0);
    if (!WinDivertSend(handle, packet, packetLen, NULL, &addr))
    {
        // Handle send error
        continue;
    }
}
For applications that do not need to modify the packet, a better approach is
to open the WinDivert handle with the WINDIVERT_FLAG_SNIFF flag set,
and not re-inject the packet with
WinDivertSend().
See the netdump.exe sample program for an example of this usage.
WinDivert has some known limitations listed below:
- 
Injecting inbound ICMP/ICMPv6 messages:
    Calling WinDivertSend()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.
- The forward layer does not interact well with the Windows NAT: 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.
- 
Re-injecting unmodified packets can lead to infinite loops:
    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, 
    WinDivertSend()will eventually fail with errorERROR_HOST_UNREACHABLE. Unfortunately, such errors are not easy to fix. Some crude solutions include: (1) removing the incompatible driver, or (2) ignoring all packets withip.TTLoripv6.HopLimitless than the WindowsDefaultTTLregistry value. See GitHub issue #41 for more information.
- WinDivert can cause the MSVC x86_64 debugger to deadlock: 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 GitHub issue #26 for more information.
- 
WinDivert can cause packets to be out-of-order:
    Simply running the passthru.exesample 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.
- 
A race condition exists between 
 and process termination. By the time an event is received usingaddr.*.processIdWinDivertRecv(), it is possible that the process responsible for the event has already terminated. Furthermore, it is theoretically possible that theprocessIdhas been reassigned to an unrelated process. This problem can be partly mitigated by comparing the timestamp (addr.Timestamp) with the creation time of the process. If the process is newer, then the ID has been reassigned. This race condition does not affect theWINDIVERT_EVENT_REFLECT_OPENevent. In this special case, theaddr.Reflect.processIdis guaranteed to be valid until the correspondingWINDIVERT_EVENT_REFLECT_CLOSEevent is received by the user application or is dropped (filter mismatch or timeout).
WinDivert is dual-licensed under your choice of either the GNU Lesser General Public License (LGPL) Version 3 or the GNU General Public License (GPL) Version 2. Please see the notices below:
LGPL version 3:
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/>.
GPL version 2:
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.