adefe271a1
Commentary from Jason: Problem statement: We call IoCompleteRequest(Irp) immediately after NdisMIndicateReceiveNetBufferLists, which frees Irp->MdlAddress. Since we've just given the same memory to NdisMIndicateReceiveNetBufferLists (in a different MDL), we wind up freeing the memory before NDIS finishes processing them. Fix possibility 1: Move IoCompleteRequest(Irp) to TunReturnNetBufferLists. This requires reference counting how many NBLs are currently in flight that are using an IRP. When that drops to zero, we can call IoCompleteRequest (Irp). Problem: This means we have to block future wireguard-go Writes until *all* NBLs have completed processing in the networking stack. Is that safe to do? Will that introduce latency? Can userspace processes sabotage it by refusing to read from a TCP socket buffer? We don't know enough about how NdisMIndicateReceiveNetBufferLists works to assess its characteristics here. Fix possibility 2: Use NDIS_RECEIVE_FLAGS_RESOURCES, so that NdisMIndicateReceiveNetBufferLists makes a copy, and then we'll simply free everything immediately after. This is slow, and it could potentially lead to wireguard-go making the kernel allocate lots of memory in the case that NdisAllocateNetBufferAndNetBufferList doesn't ratelimit its creation in the same way Linux's skb_alloc does. However, it does make the lifetime of Irps shorter, which is easier to analyze, and it might lead to better latency, since we don't need to wait until userspace sends its next packets, so long as Ndis' ingestion queue doesn't become too large. This commit switches from (2) to (1). Signed-off-by: Simon Rozman <simon@rozman.si> |
||
---|---|---|
.editorconfig | ||
.gitignore | ||
COPYING | ||
README.md | ||
undocumented.h | ||
wintun.c | ||
wintun.inf | ||
wintun.proj | ||
wintun.props | ||
wintun.rc | ||
wintun.vcxproj | ||
wintun.vcxproj.filters | ||
wintun.wixproj | ||
wintun.wxs |
Wintun Network Adapter
TUN Device Driver for Windows
This is a layer 3 TUN driver for Windows 7, 8, 8.1, and 10. Originally created for WireGuard, it is intended to be useful to a wide variety of projects that require layer 3 tunneling devices with implementations primarily in userspace.
Build Requirements
Digital Signing
Digital signing is integral part of the build process. By default, the driver will be test-signed using a certificate that the WDK should automatically generate. To subsequently load the driver, you will need to put your computer into test mode by executing as Administrator bcdedit /set testsigning on
.
If you possess an EV certificate for kernel mode code signing you should switch TUN driver digital signing from test-signing to production-signing by authoring your wintun.vcxproj.user
file to look something like this:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SignMode>ProductionSign</SignMode>
<CrossCertificateFile>$(WDKContentRoot)CrossCertificates\DigiCert_High_Assurance_EV_Root_CA.crt</CrossCertificateFile>
<ProductionCertificate>DF98E075A012ED8C86FBCF14854B8F9555CB3D45</ProductionCertificate>
<TimestampServer>http://timestamp.digicert.com</TimestampServer>
</PropertyGroup>
</Project>
Modify the <CrossCertificateFile>
to contain the full path to the cross-signing certificate of CA that issued your certificate. You should be able to find its .crt
file in C:\Program Files (x86)\Windows Kits\10\CrossCertificates
. Note that the $(WDKContentRoot)
expands to C:\Program Files (x86)\Windows Kits\10\
.
If you already have wintun.vcxproj.user
file, just add the <PropertyGroup>
section.
Building from Command Line
Open Developer Command Prompt for VS 2019 and use the msbuild
command:
msbuild wintun.proj [/t:<target>]
Targets
-
Build
: Builds the driver release configurations of all supported platforms. This is the default target. -
Clean
: Deletes all intermediate and output files. -
Rebuild
: Alias forClean
followed byBuild
. -
SDV
: Runs Static Driver Verifier, which includes a clean driver build, only for AMD64 release configuration. -
DVL
: Runs theSDV
, and creates a Driver Verification Log, only for AMD64 release configurations. -
MSM
: Builds Microsoft Installer Merge Modules in<output folder>\wintun-<platform>-<version>.msm
. Requires WHQL signed driver.
The driver output folders are:
Platform and Configuration | Folder |
---|---|
x86 Debug | x86\Debug\wintun |
x86 Release | x86\Release\wintun |
AMD64 Debug | amd64\Debug\wintun |
AMD64 Release | amd64\Release\wintun |
ARM64 Debug | arm64\Debug\wintun |
ARM64 Release | arm64\Release\wintun |
Building Microsoft Installer Merge Modules
msbuild wintun.proj /t:DVL;Build
.- Perform Windows Hardware Lab Kit tests.
- Submit submission package to Microsoft.
- Copy WHQL-signed driver to
x86\Release\whql\
andamd64\Release\whql\
subfolders. msbuild wintun.proj /t:MSM
- MSM files are placed in
dist
subfolder.
Note: due to the use of SHA256 signatures throughout, Windows 7 users who would like a prompt-less installation generally need to have the KB2921916 hotfix installed, which can be obtained from these mirrors: amd64 and x86.
Usage
After loading the driver and creating a network interface the typical way using SetupAPI, open \\.\Device\WINTUN%d
as Local System, where %d
is the LUID index (NetLuidIndex
member) of the network device. You may then ReadFile
and WriteFile
bundles of packets of the following format:
+------------------------------+
| size_0 |
| 4 bytes, native endian |
+------------------------------+
| |
| padding |
| 12 bytes, all zero |
| |
+------------------------------+
| |
| packet_0 |
| size_0 bytes |
| |
~ ~
| |
+------------------------------+
| padding |
| 16-(size_0&15) bytes, |
| all zero |
+------------------------------+
| size_1 |
| 4 bytes, native endian |
+------------------------------+
| |
| padding |
| 12 bytes, all zero |
| |
+------------------------------+
| |
| packet_1 |
| size_1 bytes |
| |
~ ~
Each packet segment should contain a layer 3 IPv4 or IPv6 packet. Up to 256 packets may be read or written during each call to ReadFile
or WriteFile
.
It is advisable to use overlapped I/O for this. If using blocking I/O instead, it may be desirable to open separate handles for reading and writing.