aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-format65
-rw-r--r--.editorconfig4
-rw-r--r--.gitignore20
-rw-r--r--COPYING2
-rw-r--r--README.md393
-rw-r--r--api/adapter.c950
-rw-r--r--api/adapter.h137
-rw-r--r--api/adapter_win7.h351
-rw-r--r--api/api.vcxproj95
-rw-r--r--api/api.vcxproj.filters97
-rw-r--r--api/driver.c519
-rw-r--r--api/driver.h34
-rw-r--r--api/exports.def16
-rw-r--r--api/extract-driverver.js17
-rw-r--r--api/logger.c134
-rw-r--r--api/logger.h175
-rw-r--r--api/main.c134
-rw-r--r--api/main.h38
-rw-r--r--api/namespace.c154
-rw-r--r--api/namespace.h30
-rw-r--r--api/nci.def4
-rw-r--r--api/nci.h31
-rw-r--r--api/ntdll.h62
-rw-r--r--api/registry.c157
-rw-r--r--api/registry.h79
-rw-r--r--api/resource.c129
-rw-r--r--api/resource.h50
-rw-r--r--api/resources.rc65
-rw-r--r--api/rundll32.c398
-rw-r--r--api/rundll32.h26
-rw-r--r--api/session.c309
-rw-r--r--api/wintun.h274
-rw-r--r--atomic.h54
-rw-r--r--driver/driver.vcxproj52
-rw-r--r--driver/driver.vcxproj.filters (renamed from wintun.vcxproj.filters)3
-rw-r--r--driver/undocumented.h (renamed from undocumented.h)18
-rw-r--r--driver/wintun.c (renamed from wintun.c)389
-rw-r--r--driver/wintun.inf (renamed from wintun.inf)9
-rw-r--r--driver/wintun.rc (renamed from wintun.rc)16
-rw-r--r--example/example.c379
-rw-r--r--example/example.vcxproj41
-rw-r--r--example/example.vcxproj.filters14
-rw-r--r--installer/exports.def5
-rw-r--r--installer/installation.c660
-rw-r--r--installer/installation.h23
-rw-r--r--installer/installer.vcxproj234
-rw-r--r--installer/installer.vcxproj.filters49
-rw-r--r--installer/installer.wxs51
-rw-r--r--installer/msi.c266
-rw-r--r--installer/resources.rc48
-rw-r--r--installer/rundll32.c180
-rw-r--r--msi-example/README.md38
-rw-r--r--msi-example/build.bat60
-rw-r--r--msi-example/exampletun.wxs54
-rw-r--r--prebuilt-binaries-license.txt84
-rw-r--r--setupapihost/host.c184
-rw-r--r--setupapihost/host_win7.h102
-rw-r--r--setupapihost/setupapihost.vcxproj37
-rw-r--r--wintun.proj109
-rw-r--r--wintun.props140
-rw-r--r--wintun.sln80
-rw-r--r--wintun.vcxproj179
62 files changed, 6186 insertions, 2321 deletions
diff --git a/.clang-format b/.clang-format
index a77c201..46c2683 100644
--- a/.clang-format
+++ b/.clang-format
@@ -64,43 +64,60 @@ SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros: [
- 'EXTERN_C',
- 'PAGED',
- 'PAGEDX',
- 'NONPAGED',
- 'PNPCODE',
- 'INITCODE',
+ '__drv_allocatesMem',
+ '__drv_freesMem',
+ '__drv_preferredFunction',
+ '__drv_setsIRQL',
+ '_Acquires_exclusive_lock_',
+ '_Acquires_lock_',
+ '_Acquires_shared_lock_',
+ '_Acquires_rcu_',
'_At_',
- '_When_',
- '_Success_',
+ '_At_buffer_',
'_Check_return_',
- '_Must_inspect_result_',
+ '_Dispatch_type_',
+ '_Field_size_bytes_',
+ '_Function_class_',
+ '_Guarded_by_',
+ '_IRQL_lowers_',
+ '_IRQL_raises_',
'_IRQL_requires_',
'_IRQL_requires_max_',
'_IRQL_requires_min_',
'_IRQL_requires_same_',
- '_IRQL_saves_',
'_IRQL_restores_',
- '_IRQL_saves_global_',
'_IRQL_restores_global_',
- '_IRQL_raises_',
- '_IRQL_lowers_',
- '_Acquires_lock_',
- '_Releases_lock_',
- '_Acquires_exclusive_lock_',
+ '_IRQL_saves_',
+ '_IRQL_saves_global_',
+ '_Must_inspect_result_',
+ '_Out_writes_bytes_all_',
+ '_Post_equals_last_error_',
+ '_Post_maybenull_',
+ '_Post_notnull_',
+ '_Post_writable_byte_size_',
'_Releases_exclusive_lock_',
- '_Acquires_shared_lock_',
+ '_Releases_lock_',
'_Releases_shared_lock_',
+ '_Releases_rcu_',
+ '_Requires_shared_lock_held_',
+ '_Requires_exclusive_lock_held_',
'_Requires_lock_held_',
'_Requires_lock_not_held_',
+ '_Requires_rcu_held_',
+ '_Ret_bytecount_',
+ '_Ret_maybenull_',
+ '_Ret_range_',
+ '_Ret_writes_bytes_',
+ '_Return_type_success_',
+ '_Success_',
'_Use_decl_annotations_',
- '_Guarded_by_',
- '__drv_preferredFunction',
- '__drv_allocatesMem',
- '__drv_freesMem',
- '_Field_size_bytes_',
- '_Function_class_',
- '_Dispatch_type_'
+ '_When_',
+ 'EXTERN_C',
+ 'INITCODE',
+ 'NONPAGED',
+ 'PAGED',
+ 'PAGEDX',
+ 'PNPCODE'
]
TabWidth: '4'
UseTab: Never
diff --git a/.editorconfig b/.editorconfig
index 15595b4..d5f42f1 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,7 +1,7 @@
[*.{c,h,inf,rc}]
indent_style = space
-indent_style = 4
+indent_size = 4
-[*.{proj,props,vcxproj,wixproj,wxs}]
+[*.{proj,props,vcxproj,filters}]
indent_style = space
indent_size = 2
diff --git a/.gitignore b/.gitignore
index 7db1686..c4b6af9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,20 +4,20 @@
# Build Output
/dist
-/x86/Release
-/x86/Debug
-/amd64/Release
-/amd64/Debug
-/arm64/Release
-/arm64/Debug
+/Debug
+/Release
# Static Driver Verifier Output
-/sdv
-/smvbuild.log
-/smvstats.txt
+/driver/sdv
+/driver/smvbuild.log
+/driver/smvstats.txt
+
+# CodeQL Output
+/driver/driver.sarif
+/driver/vc140.pdb
# Driver Verification Log
-/wintun.DVL.XML
+/driver/wintun.DVL.XML
# Temporary files
*~
diff --git a/COPYING b/COPYING
index d05459a..9094713 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-This program is Copyright (C) 2018-2019 WireGuard LLC.
+This program is Copyright (C) 2018-2021 WireGuard LLC.
------------------------------------------------------------------------------
GNU GENERAL PUBLIC LICENSE
diff --git a/README.md b/README.md
index 98107d3..59b8f07 100644
--- a/README.md
+++ b/README.md
@@ -1,170 +1,339 @@
# [Wintun Network Adapter](https://www.wintun.net/)
### TUN Device Driver for Windows
-This is a layer 3 TUN driver for Windows 7, 8, 8.1, and 10. Originally created for [WireGuard](https://www.wireguard.com/), it is intended to be useful to a wide variety of projects that require layer 3 tunneling devices with implementations primarily in userspace.
+This is a layer 3 TUN driver for Windows 7, 8, 8.1, 10, and 11. Originally created for [WireGuard](https://www.wireguard.com/), it is intended to be useful to a wide variety of projects that require layer 3 tunneling devices with implementations primarily in userspace.
## Installation
-The following snippet may be used inside of a WiX `<Product>` element for including Wintun inside of a Windows Installer. Note that **MSI is the only supported method of installing Wintun**; if you're using a different install system (such as NSIS) and cannot bother to switch to MSI/WiX, then simply bundle an embedded MSI that you can execute with `msiexec.exe`.
+Wintun is deployed as a platform-specific `wintun.dll` file. Install the `wintun.dll` file side-by-side with your application. Download the dll from [wintun.net](https://www.wintun.net/), alongside the header file for your application described below.
-```xml
-<DirectoryRef Id="INSTALLFOLDER">
- <Merge Id="WintunMergeModule" Language="0" DiskId="1" SourceFile="path\to\wintun-x.y-amd64.msm" />
-</DirectoryRef>
-<Feature Id="WintunFeature" Title="Wintun" Level="1">
- <MergeRef Id="WintunMergeModule" />
-</Feature>
+## Usage
+
+Include the [`wintun.h` file](https://git.zx2c4.com/wintun/tree/api/wintun.h) in your project simply by copying it there and dynamically load the `wintun.dll` using [`LoadLibraryEx()`](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa) and [`GetProcAddress()`](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress) to resolve each function, using the typedefs provided in the header file. The [`InitializeWintun` function in the example.c code](https://git.zx2c4.com/wintun/tree/example/example.c) provides this in a function that you can simply copy and paste.
+
+With the library setup, Wintun can then be used by first creating an adapter, configuring it, and then setting its status to "up". Adapters have names (e.g. "OfficeNet") and types (e.g. "Wintun").
+
+```C
+WINTUN_ADAPTER_HANDLE Adapter1 = WintunCreateAdapter(L"OfficeNet", L"Wintun", &SomeFixedGUID1);
+WINTUN_ADAPTER_HANDLE Adapter2 = WintunCreateAdapter(L"HomeNet", L"Wintun", &SomeFixedGUID2);
+WINTUN_ADAPTER_HANDLE Adapter3 = WintunCreateAdapter(L"Data Center", L"Wintun", &SomeFixedGUID3);
```
-It is advisable to use the prebuilt and Microsoft-signed MSM files from [Wintun.net](https://www.wintun.net/).
+After creating an adapter, we can use it by starting a session:
-## Usage
+```C
+WINTUN_SESSION_HANDLE Session = WintunStartSession(Adapter2, 0x400000);
+```
-After loading the driver and creating a network interface the typical way using [SetupAPI](https://docs.microsoft.com/en-us/windows-hardware/drivers/install/setupapi), open the NDIS device object associated with the PnPInstanceId, enabling all forms of file sharing:
+Then, the `WintunAllocateSendPacket` and `WintunSendPacket` functions can be used for sending packets ([used by `SendPackets` in the example.c code](https://git.zx2c4.com/wintun/tree/example/example.c)):
```C
-TCHAR *InterfaceList = NULL;
-for (;;) {
- free(InterfaceList);
- DWORD RequiredBytes;
- if (CM_Get_Device_Interface_List_Size(&RequiredBytes, (LPGUID)&GUID_DEVINTERFACE_NET,
- InstanceId, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS)
- return FALSE;
- InterfaceList = calloc(sizeof(*InterfaceList), RequiredBytes);
- if (!InterfaceList)
- return FALSE;
- CONFIGRET Ret = CM_Get_Device_Interface_List((LPGUID)&GUID_DEVINTERFACE_NET, InstanceId,
- InterfaceList, RequiredBytes, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
- if (Ret == CR_SUCCESS)
+BYTE *OutgoingPacket = WintunAllocateSendPacket(Session, PacketDataSize);
+if (OutgoingPacket)
+{
+ memcpy(OutgoingPacket, PacketData, PacketDataSize);
+ WintunSendPacket(Session, OutgoingPacket);
+}
+else if (GetLastError() != ERROR_BUFFER_OVERFLOW) // Silently drop packets if the ring is full
+ Log(L"Packet write failed");
+```
+
+And the `WintunReceivePacket` and `WintunReleaseReceivePacket` functions can be used for receiving packets ([used by `ReceivePackets` in the example.c code](https://git.zx2c4.com/wintun/tree/example/example.c)):
+
+```C
+for (;;)
+{
+ DWORD IncomingPacketSize;
+ BYTE *IncomingPacket = WintunReceivePacket(Session, &IncomingPacketSize);
+ if (IncomingPacket)
+ {
+ DoSomethingWithPacket(IncomingPacket, IncomingPacketSize);
+ WintunReleaseReceivePacket(Session, IncomingPacket);
+ }
+ else if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ WaitForSingleObject(WintunGetReadWaitEvent(Session), INFINITE);
+ else
+ {
+ Log(L"Packet read failed");
break;
- if (Ret != CR_BUFFER_SMALL) {
- free(InterfaceList);
- return FALSE;
}
}
-HANDLE WintunHandle = CreateFile(InterfaceList, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING, 0, NULL);
-free(InterfaceList);
-...
```
-### Ring layout
+Some high performance use cases may want to spin on `WintunReceivePackets` for a number of cycles before falling back to waiting on the read-wait event.
-You must allocate two ring structs, one for receiving and one for sending:
+You are **highly encouraged** to read the [**example.c short example**](https://git.zx2c4.com/wintun/tree/example/example.c) to see how to put together a simple userspace network tunnel.
-```C
-typedef struct _TUN_RING {
- volatile ULONG Head;
- volatile ULONG Tail;
- volatile LONG Alertable;
- UCHAR Data[];
-} TUN_RING;
-```
+The various functions and definitions are [documented in the reference below](#Reference).
-- `Head`: Byte offset of the first packet in the ring. Its value must be a multiple of 4 and less than ring capacity.
+## Reference
-- `Tail`: Byte offset of the start of free space in the ring. Its value must be multiple of 4 and less than ring capacity.
+### Macro Definitions
-- `Alertable`: Zero when the consumer is processing packets, non-zero when the consumer has processed all packets and is waiting for `TailMoved` event.
+#### WINTUN\_MAX\_POOL
-- `Data`: The ring data.
+`#define WINTUN_MAX_POOL 256`
-In order to determine the size of the `Data` array:
+Maximum pool name length including zero terminator
-1. Pick a ring capacity ranging from 128kiB to 64MiB bytes. This capacity must be a power of two (e.g. 1MiB). The ring can hold up to this much data.
-2. Add 0x10000 trailing bytes to the capacity, in order to allow for always-contigious packet segments.
+#### WINTUN\_MIN\_RING\_CAPACITY
-The total ring size memory is then `sizeof(TUN_RING) + capacity + 0x10000`.
+`#define WINTUN_MIN_RING_CAPACITY 0x20000 /* 128kiB */`
-Each packet is stored in the ring aligned to `sizeof(ULONG)` as:
+Minimum ring capacity.
-```C
-typedef struct _TUN_PACKET {
- ULONG Size;
- UCHAR Data[];
-} TUN_PACKET;
-```
+#### WINTUN\_MAX\_RING\_CAPACITY
-- `Size`: Size of packet (max 0xFFFF).
+`#define WINTUN_MAX_RING_CAPACITY 0x4000000 /* 64MiB */`
-- `Data`: Layer 3 IPv4 or IPv6 packet.
+Maximum ring capacity.
-### Registering rings
+#### WINTUN\_MAX\_IP\_PACKET\_SIZE
-In order to register the two `TUN_RING`s, prepare a registration struct as:
+`#define WINTUN_MAX_IP_PACKET_SIZE 0xFFFF`
-```C
-typedef struct _TUN_REGISTER_RINGS {
- struct {
- ULONG RingSize;
- TUN_RING *Ring;
- HANDLE TailMoved;
- } Send, Receive;
-} TUN_REGISTER_RINGS;
-```
+Maximum IP packet size
-- `Send.RingSize`, `Receive.RingSize`: Sizes of the rings (`sizeof(TUN_RING) + capacity + 0x10000`, as above).
+### Typedefs
-- `Send.Ring`, `Receive.Ring`: Pointers to the rings.
+#### WINTUN\_ADAPTER\_HANDLE
-- `Send.TailMoved`: A handle to an [`auto-reset event`](https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createeventa) created by the client that Wintun signals after it moves the `Tail` member of the send ring.
+`typedef void* WINTUN_ADAPTER_HANDLE`
-- `Receive.TailMoved`: A handle to an [`auto-reset event`](https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createeventa) created by the client that the client will signal when it changes `Receive.Ring->Tail` and `Receive.Ring->Alertable` is non-zero.
+A handle representing Wintun adapter
-With events created, send and receive rings allocated, and registration struct populated, [`DeviceIoControl`](https://docs.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-deviceiocontrol)(`TUN_IOCTL_REGISTER_RINGS`: 0xca6ce5c0) with pointer and size of descriptor struct specified as `lpInBuffer` and `nInBufferSize` parameters. You may call `TUN_IOCTL_REGISTER_RINGS` on one handle only.
+#### WINTUN\_ENUM\_CALLBACK
+`typedef BOOL(* WINTUN_ENUM_CALLBACK) (WINTUN_ADAPTER_HANDLE Adapter, LPARAM Param)`
-### Writing to and from rings
+Called by WintunEnumAdapters for each adapter in the pool.
-Reading packets from the send ring may be done as:
+**Parameters**
-```C
-for (;;) {
- TUN_PACKET *Next = PopFromRing(Rings->Send.Ring);
- if (!Next) {
- Rings->Send.Ring->Alertable = TRUE;
- Next = PopFromRing(Rings->Send.Ring);
- if (!Next) {
- WaitForSingleObject(Rings->Send.TailMoved, INFINITE);
- Rings->Send.Ring->Alertable = FALSE;
- continue;
- }
- Rings->Send.Ring->Alertable = FALSE;
- ResetEvent(Rings->Send.TailMoved);
- }
- SendToClientProgram(Next);
-}
-```
+- *Adapter*: Adapter handle, which will be freed when this function returns.
+- *Param*: An application-defined value passed to the WintunEnumAdapters.
-It may be desirable to spin for some time under heavy use before waiting on the `TailMoved` event, in order to reduce latency.
+**Returns**
-When closing the handle, Wintun will set the `Tail` to 0xFFFFFFFF and set the `TailMoved` event to unblock the waiting user process.
+Non-zero to continue iterating adapters; zero to stop.
-Writing packets to the receive ring may be done as:
+#### WINTUN\_LOGGER\_CALLBACK
-```C
-for (;;) {
- TUN_PACKET *Next = ReceiveFromClientProgram();
- WriteToRing(Rings->Receive.Ring, Next);
- if (Rings->Receive.Ring->Alertable)
- SetEvent(Rings->Recieve.TailMoved);
-}
-```
+`typedef void(* WINTUN_LOGGER_CALLBACK) (WINTUN_LOGGER_LEVEL Level, DWORD64 Timestamp, const WCHAR *Message)`
+
+Called by internal logger to report diagnostic messages
+
+**Parameters**
+
+- *Level*: Message level.
+- *Timestamp*: Message timestamp in in 100ns intervals since 1601-01-01 UTC.
+- *Message*: Message text.
+
+#### WINTUN\_SESSION\_HANDLE
+
+`typedef void* WINTUN_SESSION_HANDLE`
+
+A handle representing Wintun session
+
+### Enumeration Types
+
+#### WINTUN\_LOGGER\_LEVEL
+
+`enum WINTUN_LOGGER_LEVEL`
+
+Determines the level of logging, passed to WINTUN\_LOGGER\_CALLBACK.
+
+- *WINTUN\_LOG\_INFO*: Informational
+- *WINTUN\_LOG\_WARN*: Warning
+- *WINTUN\_LOG\_ERR*: Error
+
+Enumerator
+
+### Functions
+
+#### WintunCreateAdapter()
+
+`WINTUN_ADAPTER_HANDLE WintunCreateAdapter (const WCHAR * Name, const WCHAR * TunnelType, const GUID * RequestedGUID)`
+
+Creates a new Wintun adapter.
+
+**Parameters**
+
+- *Name*: The requested name of the adapter. Zero-terminated string of up to MAX\_ADAPTER\_NAME-1 characters.
+- *Name*: Name of the adapter tunnel type. Zero-terminated string of up to MAX\_ADAPTER\_NAME-1 characters.
+- *RequestedGUID*: The GUID of the created network adapter, which then influences NLA generation deterministically. If it is set to NULL, the GUID is chosen by the system at random, and hence a new NLA entry is created for each new adapter. It is called "requested" GUID because the API it uses is completely undocumented, and so there could be minor interesting complications with its usage.
+
+**Returns**
+
+If the function succeeds, the return value is the adapter handle. Must be released with WintunCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call GetLastError.
+
+#### WintunOpenAdapter()
+
+`WINTUN_ADAPTER_HANDLE WintunOpenAdapter (const WCHAR * Name)`
+
+Opens an existing Wintun adapter.
+
+**Parameters**
+
+- *Name*: The requested name of the adapter. Zero-terminated string of up to MAX\_ADAPTER\_NAME-1 characters.
+
+**Returns**
+
+If the function succeeds, the return value is adapter handle. Must be released with WintunCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call GetLastError.
+
+#### WintunCloseAdapter()
+
+`void WintunCloseAdapter (WINTUN_ADAPTER_HANDLE Adapter)`
+
+Releases Wintun adapter resources and, if adapter was created with WintunCreateAdapter, removes adapter.
+
+**Parameters**
+
+- *Adapter*: Adapter handle obtained with WintunCreateAdapter or WintunOpenAdapter.
+
+#### WintunDeleteDriver()
+
+`BOOL WintunDeleteDriver ()`
+
+Deletes the Wintun driver if there are no more adapters in use.
+
+**Returns**
+
+If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError.
+
+#### WintunGetAdapterLuid()
+
+`void WintunGetAdapterLuid (WINTUN_ADAPTER_HANDLE Adapter, NET_LUID * Luid)`
+
+Returns the LUID of the adapter.
+
+**Parameters**
+
+- *Adapter*: Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
+- *Luid*: Pointer to LUID to receive adapter LUID.
+
+#### WintunGetRunningDriverVersion()
+
+`DWORD WintunGetRunningDriverVersion (void )`
+
+Determines the version of the Wintun driver currently loaded.
+
+**Returns**
+
+If the function succeeds, the return value is the version number. If the function fails, the return value is zero. To get extended error information, call GetLastError. Possible errors include the following: ERROR\_FILE\_NOT\_FOUND Wintun not loaded
+
+#### WintunSetLogger()
+
+`void WintunSetLogger (WINTUN_LOGGER_CALLBACK NewLogger)`
+
+Sets logger callback function.
+
+**Parameters**
+
+- *NewLogger*: Pointer to callback function to use as a new global logger. NewLogger may be called from various threads concurrently. Should the logging require serialization, you must handle serialization in NewLogger. Set to NULL to disable.
+
+#### WintunStartSession()
+
+`WINTUN_SESSION_HANDLE WintunStartSession (WINTUN_ADAPTER_HANDLE Adapter, DWORD Capacity)`
+
+Starts Wintun session.
+
+**Parameters**
+
+- *Adapter*: Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
+- *Capacity*: Rings capacity. Must be between WINTUN\_MIN\_RING\_CAPACITY and WINTUN\_MAX\_RING\_CAPACITY (incl.) Must be a power of two.
+
+**Returns**
+
+Wintun session handle. Must be released with WintunEndSession. If the function fails, the return value is NULL. To get extended error information, call GetLastError.
+
+#### WintunEndSession()
+
+`void WintunEndSession (WINTUN_SESSION_HANDLE Session)`
+
+Ends Wintun session.
+
+**Parameters**
+
+- *Session*: Wintun session handle obtained with WintunStartSession
+
+#### WintunGetReadWaitEvent()
+
+`HANDLE WintunGetReadWaitEvent (WINTUN_SESSION_HANDLE Session)`
+
+Gets Wintun session's read-wait event handle.
+
+**Parameters**
+
+- *Session*: Wintun session handle obtained with WintunStartSession
+
+**Returns**
+
+Pointer to receive event handle to wait for available data when reading. Should WintunReceivePackets return ERROR\_NO\_MORE\_ITEMS (after spinning on it for a while under heavy load), wait for this event to become signaled before retrying WintunReceivePackets. Do not call CloseHandle on this event - it is managed by the session.
+
+#### WintunReceivePacket()
+
+`BYTE* WintunReceivePacket (WINTUN_SESSION_HANDLE Session, DWORD * PacketSize)`
+
+Retrieves one or packet. After the packet content is consumed, call WintunReleaseReceivePacket with Packet returned from this function to release internal buffer. This function is thread-safe.
+
+**Parameters**
+
+- *Session*: Wintun session handle obtained with WintunStartSession
+- *PacketSize*: Pointer to receive packet size.
+
+**Returns**
+
+Pointer to layer 3 IPv4 or IPv6 packet. Client may modify its content at will. If the function fails, the return value is NULL. To get extended error information, call GetLastError. Possible errors include the following: ERROR\_HANDLE\_EOF Wintun adapter is terminating; ERROR\_NO\_MORE\_ITEMS Wintun buffer is exhausted; ERROR\_INVALID\_DATA Wintun buffer is corrupt
+
+#### WintunReleaseReceivePacket()
+
+`void WintunReleaseReceivePacket (WINTUN_SESSION_HANDLE Session, const BYTE * Packet)`
+
+Releases internal buffer after the received packet has been processed by the client. This function is thread-safe.
+
+**Parameters**
+
+- *Session*: Wintun session handle obtained with WintunStartSession
+- *Packet*: Packet obtained with WintunReceivePacket
+
+#### WintunAllocateSendPacket()
+
+`BYTE* WintunAllocateSendPacket (WINTUN_SESSION_HANDLE Session, DWORD PacketSize)`
+
+Allocates memory for a packet to send. After the memory is filled with packet data, call WintunSendPacket to send and release internal buffer. WintunAllocateSendPacket is thread-safe and the WintunAllocateSendPacket order of calls define the packet sending order.
+
+**Parameters**
+
+- *Session*: Wintun session handle obtained with WintunStartSession
+- *PacketSize*: Exact packet size. Must be less or equal to WINTUN\_MAX\_IP\_PACKET\_SIZE.
+
+**Returns**
+
+Returns pointer to memory where to prepare layer 3 IPv4 or IPv6 packet for sending. If the function fails, the return value is NULL. To get extended error information, call GetLastError. Possible errors include the following: ERROR\_HANDLE\_EOF Wintun adapter is terminating; ERROR\_BUFFER\_OVERFLOW Wintun buffer is full;
+
+#### WintunSendPacket()
+
+`void WintunSendPacket (WINTUN_SESSION_HANDLE Session, const BYTE * Packet)`
+
+Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket order of calls define the packet sending order. This means the packet is not guaranteed to be sent in the WintunSendPacket yet.
+
+**Parameters**
-Wintun will abort reading the receive ring on invalid `Head` or `Tail` or on a bogus packet. In this case, Wintun will set the `Head` to 0xFFFFFFFF. In order to restart it, reopen the handle and call `TUN_IOCTL_REGISTER_RINGS` again. However, it should be entirely possible to avoid feeding Wintun bogus packets and invalid offsets.
+- *Session*: Wintun session handle obtained with WintunStartSession
+- *Packet*: Packet obtained with WintunAllocateSendPacket
## Building
-**Do not distribute drivers named "Wintun", as they will most certainly clash with official deployments. Instead distribute [the signed MSMs from Wintun.net](https://www.wintun.net/).** If you are unable to use MSMs, [consult the MSI creation instructions](msi-example/README.md).
+**Do not distribute drivers or files named "Wintun", as they will most certainly clash with official deployments. Instead distribute [`wintun.dll` as downloaded from wintun.net](https://www.wintun.net).**
General requirements:
-- [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/)
-- [Windows Driver Kit for Windows 10, version 1903](https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk)
+- [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/) with Windows SDK
+- [Windows Driver Kit](https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk)
-`wintun.sln` may be opened in Visual Studio for development and building. Be sure to run `bcdedit /set testsigning on` before to enable unsigned driver loading. The default run sequence (F5) in Visual Studio will build and insert Wintun.
+`wintun.sln` may be opened in Visual Studio for development and building. Be sure to run `bcdedit /set testsigning on` and then reboot before to enable unsigned driver loading. The default run sequence (F5) in Visual Studio will build the example project and its dependencies.
## License
-The entire contents of this repository, including all documentation code, is "Copyright © 2018-2019 WireGuard LLC. All Rights Reserved." and is licensed under the [GPLv2](COPYING).
+The entire contents of [the repository](https://git.zx2c4.com/wintun/), including all documentation and example code, is "Copyright © 2018-2021 WireGuard LLC. All Rights Reserved." Source code is licensed under the [GPLv2](COPYING). Prebuilt binaries from [wintun.net](https://www.wintun.net/) are released under a more permissive license suitable for more forms of software contained inside of the .zip files distributed there.
diff --git a/api/adapter.c b/api/adapter.c
new file mode 100644
index 0000000..0dd8c42
--- /dev/null
+++ b/api/adapter.c
@@ -0,0 +1,950 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include <Windows.h>
+#include <winternl.h>
+#include <cfgmgr32.h>
+#include <devguid.h>
+#include <iphlpapi.h>
+#include <objbase.h>
+#include <ndisguid.h>
+#include <SetupAPI.h>
+#include <Shlwapi.h>
+#include <devioctl.h>
+#include <wchar.h>
+#include <initguid.h> /* Keep these two at bottom in this order, so that we only generate extra GUIDs for devpkey. The other keys we'll get from uuid.lib like usual. */
+#include <devpkey.h>
+
+/* We pretend we're Windows 8, and then hack around the limitation in Windows 7 below. */
+#if NTDDI_VERSION == NTDDI_WIN7
+# undef NTDDI_VERSION
+# define NTDDI_VERSION NTDDI_WIN8
+# include <devquery.h>
+# include <swdevice.h>
+# undef NTDDI_VERSION
+# define NTDDI_VERSION NTDDI_WIN7
+#else
+# include <devquery.h>
+# include <swdevice.h>
+#endif
+
+#include "adapter.h"
+#include "driver.h"
+#include "logger.h"
+#include "main.h"
+#include "namespace.h"
+#include "nci.h"
+#include "ntdll.h"
+#include "rundll32.h"
+#include "registry.h"
+#include "adapter_win7.h"
+
+#pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */
+
+const DEVPROPKEY DEVPKEY_Wintun_Name = {
+ { 0x3361c968, 0x2f2e, 0x4660, { 0xb4, 0x7e, 0x69, 0x9c, 0xdc, 0x4c, 0x32, 0xb9 } },
+ DEVPROPID_FIRST_USABLE + 1
+};
+
+_Must_inspect_result_
+static _Return_type_success_(return != FALSE)
+BOOL
+PopulateAdapterData(_Inout_ WINTUN_ADAPTER *Adapter)
+{
+ DWORD LastError = ERROR_SUCCESS;
+
+ /* Open HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\<class>\<id> registry key. */
+ HKEY Key =
+ SetupDiOpenDevRegKey(Adapter->DevInfo, &Adapter->DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
+ if (Key == INVALID_HANDLE_VALUE)
+ {
+ LOG_LAST_ERROR(L"Failed to open adapter device registry key");
+ return FALSE;
+ }
+
+ LPWSTR ValueStr = RegistryQueryString(Key, L"NetCfgInstanceId", TRUE);
+ if (!ValueStr)
+ {
+ WCHAR RegPath[MAX_REG_PATH];
+ LoggerGetRegistryKeyPath(Key, RegPath);
+ LastError = LOG(WINTUN_LOG_ERR, L"Failed to get %.*s\\NetCfgInstanceId", MAX_REG_PATH, RegPath);
+ goto cleanupKey;
+ }
+ if (FAILED(CLSIDFromString(ValueStr, &Adapter->CfgInstanceID)))
+ {
+ WCHAR RegPath[MAX_REG_PATH];
+ LoggerGetRegistryKeyPath(Key, RegPath);
+ LastError = LOG(WINTUN_LOG_ERR, L"%.*s\\NetCfgInstanceId is not a GUID: %s", MAX_REG_PATH, RegPath, ValueStr);
+ Free(ValueStr);
+ goto cleanupKey;
+ }
+ Free(ValueStr);
+
+ if (!RegistryQueryDWORD(Key, L"NetLuidIndex", &Adapter->LuidIndex, TRUE))
+ {
+ WCHAR RegPath[MAX_REG_PATH];
+ LoggerGetRegistryKeyPath(Key, RegPath);
+ LastError = LOG(WINTUN_LOG_ERR, L"Failed to get %.*s\\NetLuidIndex", MAX_REG_PATH, RegPath);
+ goto cleanupKey;
+ }
+
+ if (!RegistryQueryDWORD(Key, L"*IfType", &Adapter->IfType, TRUE))
+ {
+ WCHAR RegPath[MAX_REG_PATH];
+ LoggerGetRegistryKeyPath(Key, RegPath);
+ LastError = LOG(WINTUN_LOG_ERR, L"Failed to get %.*s\\*IfType", MAX_REG_PATH, RegPath);
+ goto cleanupKey;
+ }
+
+ Adapter->InterfaceFilename = AdapterGetDeviceObjectFileName(Adapter->DevInstanceID);
+ if (!Adapter->InterfaceFilename)
+ {
+ LastError = LOG_LAST_ERROR(L"Unable to determine device object file name");
+ goto cleanupKey;
+ }
+
+cleanupKey:
+ RegCloseKey(Key);
+ return RET_ERROR(TRUE, LastError);
+}
+
+static volatile LONG OrphanThreadIsWorking = FALSE;
+
+static DWORD
+DoOrphanedDeviceCleanup(_In_opt_ LPVOID Ctx)
+{
+ AdapterCleanupOrphanedDevices();
+ OrphanThreadIsWorking = FALSE;
+ return 0;
+}
+
+static VOID QueueUpOrphanedDeviceCleanupRoutine(VOID)
+{
+ if (InterlockedCompareExchange(&OrphanThreadIsWorking, TRUE, FALSE) == FALSE)
+ QueueUserWorkItem(DoOrphanedDeviceCleanup, NULL, 0);
+}
+
+VOID AdapterCleanupOrphanedDevices(VOID)
+{
+ HANDLE DeviceInstallationMutex = NamespaceTakeDeviceInstallationMutex();
+ if (!DeviceInstallationMutex)
+ {
+ LOG_LAST_ERROR(L"Failed to take device installation mutex");
+ return;
+ }
+
+ if (IsWindows7)
+ {
+ AdapterCleanupOrphanedDevicesWin7();
+ goto cleanupDeviceInstallationMutex;
+ }
+
+ HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WINTUN_ENUMERATOR, NULL, 0, NULL, NULL, NULL);
+ if (DevInfo == INVALID_HANDLE_VALUE)
+ {
+ LOG_LAST_ERROR(L"Failed to get adapters");
+ goto cleanupDeviceInstallationMutex;
+ }
+
+ SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
+ for (DWORD EnumIndex = 0;; ++EnumIndex)
+ {
+ if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ continue;
+ }
+ ULONG Status, Code;
+ if (CM_Get_DevNode_Status(&Status, &Code, DevInfoData.DevInst, 0) == CR_SUCCESS && !(Status & DN_HAS_PROBLEM))
+ continue;
+
+ DEVPROPTYPE PropType;
+ WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>";
+ SetupDiGetDevicePropertyW(
+ DevInfo,
+ &DevInfoData,
+ &DEVPKEY_Wintun_Name,
+ &PropType,
+ (PBYTE)Name,
+ MAX_ADAPTER_NAME * sizeof(Name[0]),
+ NULL,
+ 0);
+ if (!AdapterRemoveInstance(DevInfo, &DevInfoData))
+ {
+ LOG_LAST_ERROR(L"Failed to remove orphaned adapter \"%s\"", Name);
+ continue;
+ }
+ LOG(WINTUN_LOG_INFO, L"Removed orphaned adapter \"%s\"", Name);
+ }
+ SetupDiDestroyDeviceInfoList(DevInfo);
+cleanupDeviceInstallationMutex:
+ NamespaceReleaseMutex(DeviceInstallationMutex);
+}
+
+_Use_decl_annotations_
+VOID WINAPI
+WintunCloseAdapter(WINTUN_ADAPTER *Adapter)
+{
+ if (!Adapter)
+ return;
+ Free(Adapter->InterfaceFilename);
+ if (Adapter->SwDevice)
+ SwDeviceClose(Adapter->SwDevice);
+ if (Adapter->DevInfo)
+ {
+ if (!AdapterRemoveInstance(Adapter->DevInfo, &Adapter->DevInfoData))
+ LOG_LAST_ERROR(L"Failed to remove adapter when closing");
+ SetupDiDestroyDeviceInfoList(Adapter->DevInfo);
+ }
+ Free(Adapter);
+ QueueUpOrphanedDeviceCleanupRoutine();
+}
+
+static _Return_type_success_(return != FALSE)
+BOOL
+RenameByNetGUID(_In_ GUID *Guid, _In_reads_or_z_(MAX_ADAPTER_NAME) LPCWSTR Name)
+{
+ DWORD LastError = ERROR_NOT_FOUND;
+ HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WINTUN_ENUMERATOR, NULL, 0, NULL, NULL, NULL);
+ if (DevInfo == INVALID_HANDLE_VALUE)
+ {
+ LastError = GetLastError();
+ goto cleanup;
+ }
+
+ SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
+ for (DWORD EnumIndex = 0;; ++EnumIndex)
+ {
+ if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ continue;
+ }
+
+ HKEY Key = SetupDiOpenDevRegKey(DevInfo, &DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
+ if (Key == INVALID_HANDLE_VALUE)
+ continue;
+ LPWSTR ValueStr = RegistryQueryString(Key, L"NetCfgInstanceId", TRUE);
+ RegCloseKey(Key);
+ if (!ValueStr)
+ continue;
+ GUID Guid2;
+ HRESULT HRet = CLSIDFromString(ValueStr, &Guid2);
+ Free(ValueStr);
+ if (FAILED(HRet) || memcmp(Guid, &Guid2, sizeof(*Guid)))
+ continue;
+ LastError = SetupDiSetDevicePropertyW(
+ DevInfo,
+ &DevInfoData,
+ &DEVPKEY_Wintun_Name,
+ DEVPROP_TYPE_STRING,
+ (PBYTE)Name,
+ (DWORD)((wcslen(Name) + 1) * sizeof(Name[0])),
+ 0)
+ ? ERROR_SUCCESS
+ : GetLastError();
+ break;
+ }
+ SetupDiDestroyDeviceInfoList(DevInfo);
+cleanup:
+ return RET_ERROR(TRUE, LastError);
+}
+
+_Must_inspect_result_
+static _Return_type_success_(return != FALSE)
+BOOL
+ConvertInterfaceAliasToGuid(_In_z_ LPCWSTR Name, _Out_ GUID *Guid)
+{
+ NET_LUID Luid;
+ DWORD LastError = ConvertInterfaceAliasToLuid(Name, &Luid);
+ if (LastError != NO_ERROR)
+ {
+ SetLastError(LOG_ERROR(LastError, L"Failed convert interface %s name to the locally unique identifier", Name));
+ return FALSE;
+ }
+ LastError = ConvertInterfaceLuidToGuid(&Luid, Guid);
+ if (LastError != NO_ERROR)
+ {
+ SetLastError(LOG_ERROR(LastError, L"Failed to convert interface %s LUID (%I64u) to GUID", Name, Luid.Value));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static _Return_type_success_(return != FALSE)
+BOOL
+NciSetAdapterName(_In_ GUID *Guid, _In_reads_or_z_(MAX_ADAPTER_NAME) LPCWSTR Name)
+{
+ const int MaxSuffix = 1000;
+ WCHAR AvailableName[MAX_ADAPTER_NAME];
+ if (wcsncpy_s(AvailableName, _countof(AvailableName), Name, _TRUNCATE) == STRUNCATE)
+ {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return FALSE;
+ }
+ for (int i = 0;; ++i)
+ {
+ DWORD LastError = NciSetConnectionName(Guid, AvailableName);
+ if (LastError == ERROR_DUP_NAME)
+ {
+ GUID Guid2;
+ if (ConvertInterfaceAliasToGuid(AvailableName, &Guid2))
+ {
+ for (int j = 0; j < MaxSuffix; ++j)
+ {
+ WCHAR Proposal[MAX_ADAPTER_NAME];
+ if (_snwprintf_s(Proposal, _countof(Proposal), _TRUNCATE, L"%s %d", Name, j + 1) == -1)
+ {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return FALSE;
+ }
+ if (_wcsnicmp(Proposal, AvailableName, MAX_ADAPTER_NAME) == 0)
+ continue;
+ DWORD LastError2 = NciSetConnectionName(&Guid2, Proposal);
+ if (LastError2 == ERROR_DUP_NAME)
+ continue;
+ if (!RenameByNetGUID(&Guid2, Proposal))
+ LOG_LAST_ERROR(L"Failed to set foreign adapter name to \"%s\"", Proposal);
+ if (LastError2 == ERROR_SUCCESS)
+ {
+ LastError = NciSetConnectionName(Guid, AvailableName);
+ if (LastError == ERROR_SUCCESS)
+ break;
+ }
+ break;
+ }
+ }
+ }
+ if (LastError == ERROR_SUCCESS)
+ break;
+ if (i >= MaxSuffix || LastError != ERROR_DUP_NAME)
+ {
+ SetLastError(LastError);
+ return FALSE;
+ }
+ if (_snwprintf_s(AvailableName, _countof(AvailableName), _TRUNCATE, L"%s %d", Name, i + 1) == -1)
+ {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+_Use_decl_annotations_
+VOID WINAPI
+WintunGetAdapterLUID(WINTUN_ADAPTER *Adapter, NET_LUID *Luid)
+{
+ Luid->Info.Reserved = 0;
+ Luid->Info.NetLuidIndex = Adapter->LuidIndex;
+ Luid->Info.IfType = Adapter->IfType;
+}
+
+_Use_decl_annotations_
+HANDLE WINAPI
+AdapterOpenDeviceObject(const WINTUN_ADAPTER *Adapter)
+{
+ HANDLE Handle = CreateFileW(
+ Adapter->InterfaceFilename,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if (Handle == INVALID_HANDLE_VALUE)
+ LOG_LAST_ERROR(L"Failed to connect to adapter interface %s", Adapter->InterfaceFilename);
+ return Handle;
+}
+
+_Use_decl_annotations_
+LPWSTR
+AdapterGetDeviceObjectFileName(LPCWSTR InstanceId)
+{
+ ULONG InterfacesLen;
+ DWORD LastError = CM_MapCrToWin32Err(
+ CM_Get_Device_Interface_List_SizeW(
+ &InterfacesLen,
+ (GUID *)&GUID_DEVINTERFACE_NET,
+ (DEVINSTID_W)InstanceId,
+ CM_GET_DEVICE_INTERFACE_LIST_PRESENT),
+ ERROR_GEN_FAILURE);
+ if (LastError != ERROR_SUCCESS)
+ {
+ SetLastError(LOG_ERROR(LastError, L"Failed to query adapter %s associated instances size", InstanceId));
+ return NULL;
+ }
+ LPWSTR Interfaces = AllocArray(InterfacesLen, sizeof(*Interfaces));
+ if (!Interfaces)
+ return NULL;
+ LastError = CM_MapCrToWin32Err(
+ CM_Get_Device_Interface_ListW(
+ (GUID *)&GUID_DEVINTERFACE_NET,
+ (DEVINSTID_W)InstanceId,
+ Interfaces,
+ InterfacesLen,
+ CM_GET_DEVICE_INTERFACE_LIST_PRESENT),
+ ERROR_GEN_FAILURE);
+ if (LastError != ERROR_SUCCESS)
+ {
+ LOG_ERROR(LastError, L"Failed to get adapter %s associated instances", InstanceId);
+ Free(Interfaces);
+ SetLastError(LastError);
+ return NULL;
+ }
+ if (!Interfaces[0])
+ {
+ Free(Interfaces);
+ SetLastError(ERROR_DEVICE_NOT_AVAILABLE);
+ return NULL;
+ }
+ return Interfaces;
+}
+
+typedef struct _WAIT_FOR_INTERFACE_CTX
+{
+ HANDLE Event;
+ DWORD LastError;
+} WAIT_FOR_INTERFACE_CTX;
+
+static VOID WINAPI
+WaitForInterfaceCallback(
+ _In_ HDEVQUERY DevQuery,
+ _Inout_ PVOID Context,
+ _In_ const DEV_QUERY_RESULT_ACTION_DATA *ActionData)
+{
+ WAIT_FOR_INTERFACE_CTX *Ctx = Context;
+ DWORD Ret = ERROR_SUCCESS;
+ switch (ActionData->Action)
+ {
+ case DevQueryResultStateChange:
+ if (ActionData->Data.State != DevQueryStateAborted)
+ return;
+ Ret = ERROR_DEVICE_NOT_AVAILABLE;
+ case DevQueryResultAdd:
+ case DevQueryResultUpdate:
+ break;
+ default:
+ return;
+ }
+ Ctx->LastError = Ret;
+ SetEvent(Ctx->Event);
+}
+
+_Must_inspect_result_
+static _Return_type_success_(return != FALSE)
+BOOL
+WaitForInterface(_In_ WCHAR *InstanceId)
+{
+ if (IsWindows7)
+ return TRUE;
+
+ DWORD LastError = ERROR_SUCCESS;
+ static const DEVPROP_BOOLEAN DevPropTrue = DEVPROP_TRUE;
+ const DEVPROP_FILTER_EXPRESSION Filters[] = { { .Operator = DEVPROP_OPERATOR_EQUALS_IGNORE_CASE,
+ .Property.CompKey.Key = DEVPKEY_Device_InstanceId,
+ .Property.CompKey.Store = DEVPROP_STORE_SYSTEM,
+ .Property.Type = DEVPROP_TYPE_STRING,
+ .Property.Buffer = InstanceId,
+ .Property.BufferSize =
+ (ULONG)((wcslen(InstanceId) + 1) * sizeof(InstanceId[0])) },
+ { .Operator = DEVPROP_OPERATOR_EQUALS,
+ .Property.CompKey.Key = DEVPKEY_DeviceInterface_Enabled,
+ .Property.CompKey.Store = DEVPROP_STORE_SYSTEM,
+ .Property.Type = DEVPROP_TYPE_BOOLEAN,
+ .Property.Buffer = (PVOID)&DevPropTrue,
+ .Property.BufferSize = sizeof(DevPropTrue) },
+ { .Operator = DEVPROP_OPERATOR_EQUALS,
+ .Property.CompKey.Key = DEVPKEY_DeviceInterface_ClassGuid,
+ .Property.CompKey.Store = DEVPROP_STORE_SYSTEM,
+ .Property.Type = DEVPROP_TYPE_GUID,
+ .Property.Buffer = (PVOID)&GUID_DEVINTERFACE_NET,
+ .Property.BufferSize = sizeof(GUID_DEVINTERFACE_NET) } };
+ WAIT_FOR_INTERFACE_CTX Ctx = { .Event = CreateEventW(NULL, FALSE, FALSE, NULL) };
+ if (!Ctx.Event)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create event");
+ goto cleanup;
+ }
+ HDEVQUERY Query;
+ HRESULT HRet = DevCreateObjectQuery(
+ DevObjectTypeDeviceInterface,
+ DevQueryFlagUpdateResults,
+ 0,
+ NULL,
+ _countof(Filters),
+ Filters,
+ WaitForInterfaceCallback,
+ &Ctx,
+ &Query);
+ if (FAILED(HRet))
+ {
+ LastError = LOG_ERROR(HRet, L"Failed to create device query");
+ goto cleanupEvent;
+ }
+ LastError = WaitForSingleObject(Ctx.Event, 15000);
+ if (LastError != WAIT_OBJECT_0)
+ {
+ if (LastError == WAIT_FAILED)
+ LastError = LOG_LAST_ERROR(L"Failed to wait for device query");
+ else
+ LastError = LOG_ERROR(LastError, L"Timed out waiting for device query");
+ goto cleanupQuery;
+ }
+ LastError = Ctx.LastError;
+ if (LastError != ERROR_SUCCESS)
+ LastError = LOG_ERROR(LastError, L"Failed to get enabled device");
+cleanupQuery:
+ DevCloseObjectQuery(Query);
+cleanupEvent:
+ CloseHandle(Ctx.Event);
+cleanup:
+ return RET_ERROR(TRUE, LastError);
+}
+
+typedef struct _SW_DEVICE_CREATE_CTX
+{
+ HRESULT CreateResult;
+ WCHAR *DeviceInstanceId;
+ HANDLE Triggered;
+} SW_DEVICE_CREATE_CTX;
+
+static VOID
+DeviceCreateCallback(
+ _In_ HSWDEVICE SwDevice,
+ _In_ HRESULT CreateResult,
+ _In_ VOID *Context,
+ _In_opt_ PCWSTR DeviceInstanceId)
+{
+ SW_DEVICE_CREATE_CTX *Ctx = Context;
+ Ctx->CreateResult = CreateResult;
+ if (DeviceInstanceId)
+ wcsncpy_s(Ctx->DeviceInstanceId, MAX_DEVICE_ID_LEN, DeviceInstanceId, _TRUNCATE);
+ SetEvent(Ctx->Triggered);
+}
+
+_Use_decl_annotations_
+WINTUN_ADAPTER_HANDLE WINAPI
+WintunCreateAdapter(LPCWSTR Name, LPCWSTR TunnelType, const GUID *RequestedGUID)
+{
+ DWORD LastError = ERROR_SUCCESS;
+ WINTUN_ADAPTER *Adapter = NULL;
+
+ HANDLE DeviceInstallationMutex = NamespaceTakeDeviceInstallationMutex();
+ if (!DeviceInstallationMutex)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to take device installation mutex");
+ goto cleanup;
+ }
+
+ HDEVINFO DevInfoExistingAdapters;
+ SP_DEVINFO_DATA_LIST *ExistingAdapters;
+ if (!DriverInstall(&DevInfoExistingAdapters, &ExistingAdapters))
+ {
+ LastError = GetLastError();
+ goto cleanupDeviceInstallationMutex;
+ }
+
+ LOG(WINTUN_LOG_INFO, L"Creating adapter");
+
+ Adapter = Zalloc(sizeof(*Adapter));
+ if (!Adapter)
+ goto cleanupDriverInstall;
+
+ WCHAR TunnelTypeName[MAX_ADAPTER_NAME + 8];
+ if (_snwprintf_s(TunnelTypeName, _countof(TunnelTypeName), _TRUNCATE, L"%s Tunnel", TunnelType) == -1)
+ {
+ LastError = ERROR_BUFFER_OVERFLOW;
+ goto cleanupAdapter;
+ }
+
+ DEVINST RootNode;
+ WCHAR RootNodeName[200 /* rasmans.dll uses 200 hard coded instead of calling CM_Get_Device_ID_Size. */];
+ CONFIGRET ConfigRet;
+ if ((ConfigRet = CM_Locate_DevNodeW(&RootNode, NULL, CM_LOCATE_DEVNODE_NORMAL)) != CR_SUCCESS ||
+ (ConfigRet = CM_Get_Device_IDW(RootNode, RootNodeName, _countof(RootNodeName), 0)) != CR_SUCCESS)
+ {
+ LastError = LOG_ERROR(CM_MapCrToWin32Err(ConfigRet, ERROR_GEN_FAILURE), L"Failed to get root node name");
+ goto cleanupAdapter;
+ }
+
+ GUID InstanceId;
+ HRESULT HRet = S_OK;
+ if (RequestedGUID)
+ memcpy(&InstanceId, RequestedGUID, sizeof(InstanceId));
+ else
+ HRet = CoCreateGuid(&InstanceId);
+ WCHAR InstanceIdStr[MAX_GUID_STRING_LEN];
+ if (FAILED(HRet) || !StringFromGUID2(&InstanceId, InstanceIdStr, _countof(InstanceIdStr)))
+ {
+ LastError = LOG_ERROR(HRet, L"Failed to convert GUID");
+ goto cleanupAdapter;
+ }
+ SW_DEVICE_CREATE_CTX CreateContext = { .DeviceInstanceId = Adapter->DevInstanceID,
+ .Triggered = CreateEventW(NULL, FALSE, FALSE, NULL) };
+ if (!CreateContext.Triggered)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create event trigger");
+ goto cleanupAdapter;
+ }
+
+ if (IsWindows7)
+ {
+ if (!CreateAdapterWin7(Adapter, Name, TunnelTypeName))
+ {
+ LastError = GetLastError();
+ goto cleanupCreateContext;
+ }
+ goto skipSwDevice;
+ }
+ if (!IsWindows10)
+ goto skipStub;
+
+ SW_DEVICE_CREATE_INFO StubCreateInfo = { .cbSize = sizeof(StubCreateInfo),
+ .pszInstanceId = InstanceIdStr,
+ .pszzHardwareIds = L"",
+ .CapabilityFlags =
+ SWDeviceCapabilitiesSilentInstall | SWDeviceCapabilitiesDriverRequired,
+ .pszDeviceDescription = TunnelTypeName };
+ DEVPROPERTY StubDeviceProperties[] = { { .CompKey = { .Key = DEVPKEY_Device_ClassGuid,
+ .Store = DEVPROP_STORE_SYSTEM },
+ .Type = DEVPROP_TYPE_GUID,
+ .Buffer = (PVOID)&GUID_DEVCLASS_NET,
+ .BufferSize = sizeof(GUID_DEVCLASS_NET) } };
+ HRet = SwDeviceCreate(
+ WINTUN_HWID,
+ RootNodeName,
+ &StubCreateInfo,
+ _countof(StubDeviceProperties),
+ StubDeviceProperties,
+ DeviceCreateCallback,
+ &CreateContext,
+ &Adapter->SwDevice);
+ if (FAILED(HRet))
+ {
+ LastError = LOG_ERROR(HRet, L"Failed to initiate stub device creation");
+ goto cleanupCreateContext;
+ }
+ if (WaitForSingleObject(CreateContext.Triggered, INFINITE) != WAIT_OBJECT_0)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to wait for stub device creation trigger");
+ goto cleanupCreateContext;
+ }
+ if (FAILED(CreateContext.CreateResult))
+ {
+ LastError = LOG_ERROR(CreateContext.CreateResult, L"Failed to create stub device");
+ goto cleanupCreateContext;
+ }
+ DEVINST DevInst;
+ CONFIGRET CRet = CM_Locate_DevNodeW(&DevInst, Adapter->DevInstanceID, CM_LOCATE_DEVNODE_PHANTOM);
+ if (CRet != CR_SUCCESS)
+ {
+ LastError =
+ LOG_ERROR(CM_MapCrToWin32Err(CRet, ERROR_DEVICE_ENUMERATION_ERROR), L"Failed to make stub device list");
+ goto cleanupCreateContext;
+ }
+ HKEY DriverKey;
+ CRet = CM_Open_DevNode_Key(DevInst, KEY_SET_VALUE, 0, RegDisposition_OpenAlways, &DriverKey, CM_REGISTRY_SOFTWARE);
+ if (CRet != CR_SUCCESS)
+ {
+ LastError =
+ LOG_ERROR(CM_MapCrToWin32Err(CRet, ERROR_PNP_REGISTRY_ERROR), L"Failed to create software registry key");
+ goto cleanupCreateContext;
+ }
+ LastError =
+ RegSetValueExW(DriverKey, L"SuggestedInstanceId", 0, REG_BINARY, (const BYTE *)&InstanceId, sizeof(InstanceId));
+ RegCloseKey(DriverKey);
+ if (LastError != ERROR_SUCCESS)
+ {
+ LastError = LOG_ERROR(LastError, L"Failed to set SuggestedInstanceId to %s", InstanceIdStr);
+ goto cleanupCreateContext;
+ }
+ SwDeviceClose(Adapter->SwDevice);
+ Adapter->SwDevice = NULL;
+
+skipStub:;
+ static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID;
+ SW_DEVICE_CREATE_INFO CreateInfo = { .cbSize = sizeof(CreateInfo),
+ .pszInstanceId = InstanceIdStr,
+ .pszzHardwareIds = Hwids,
+ .CapabilityFlags =
+ SWDeviceCapabilitiesSilentInstall | SWDeviceCapabilitiesDriverRequired,
+ .pszDeviceDescription = TunnelTypeName };
+ DEVPROPERTY DeviceProperties[] = {
+ { .CompKey = { .Key = DEVPKEY_Wintun_Name, .Store = DEVPROP_STORE_SYSTEM },
+ .Type = DEVPROP_TYPE_STRING,
+ .Buffer = (WCHAR *)Name,
+ .BufferSize = (ULONG)((wcslen(Name) + 1) * sizeof(*Name)) },
+ { .CompKey = { .Key = DEVPKEY_Device_FriendlyName, .Store = DEVPROP_STORE_SYSTEM },
+ .Type = DEVPROP_TYPE_STRING,
+ .Buffer = TunnelTypeName,
+ .BufferSize = (ULONG)((wcslen(TunnelTypeName) + 1) * sizeof(*TunnelTypeName)) },
+ { .CompKey = { .Key = DEVPKEY_Device_DeviceDesc, .Store = DEVPROP_STORE_SYSTEM },
+ .Type = DEVPROP_TYPE_STRING,
+ .Buffer = TunnelTypeName,
+ .BufferSize = (ULONG)((wcslen(TunnelTypeName) + 1) * sizeof(*TunnelTypeName)) }
+ };
+
+ HRet = SwDeviceCreate(
+ WINTUN_HWID,
+ RootNodeName,
+ &CreateInfo,
+ _countof(DeviceProperties),
+ DeviceProperties,
+ DeviceCreateCallback,
+ &CreateContext,
+ &Adapter->SwDevice);
+ if (FAILED(HRet))
+ {
+ LastError = LOG_ERROR(HRet, L"Failed to initiate device creation");
+ goto cleanupCreateContext;
+ }
+ if (WaitForSingleObject(CreateContext.Triggered, INFINITE) != WAIT_OBJECT_0)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to wait for device creation trigger");
+ goto cleanupCreateContext;
+ }
+ if (FAILED(CreateContext.CreateResult))
+ {
+ LastError = LOG_ERROR(CreateContext.CreateResult, L"Failed to create device");
+ goto cleanupCreateContext;
+ }
+
+ if (!WaitForInterface(Adapter->DevInstanceID))
+ {
+ LastError = GetLastError();
+ DEVPROPTYPE PropertyType = 0;
+ NTSTATUS NtStatus = 0;
+ INT32 ProblemCode = 0;
+ Adapter->DevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
+ if (Adapter->DevInfo == INVALID_HANDLE_VALUE)
+ {
+ Adapter->DevInfo = NULL;
+ goto cleanupCreateContext;
+ }
+ Adapter->DevInfoData.cbSize = sizeof(Adapter->DevInfoData);
+ if (!SetupDiOpenDeviceInfoW(
+ Adapter->DevInfo, Adapter->DevInstanceID, NULL, DIOD_INHERIT_CLASSDRVS, &Adapter->DevInfoData))
+ {
+ SetupDiDestroyDeviceInfoList(Adapter->DevInfo);
+ Adapter->DevInfo = NULL;
+ goto cleanupCreateContext;
+ }
+ if (!SetupDiGetDevicePropertyW(
+ Adapter->DevInfo,
+ &Adapter->DevInfoData,
+ &DEVPKEY_Device_ProblemStatus,
+ &PropertyType,
+ (PBYTE)&NtStatus,
+ sizeof(NtStatus),
+ NULL,
+ 0) ||
+ PropertyType != DEVPROP_TYPE_NTSTATUS)
+ NtStatus = 0;
+ if (!SetupDiGetDevicePropertyW(
+ Adapter->DevInfo,
+ &Adapter->DevInfoData,
+ &DEVPKEY_Device_ProblemCode,
+ &PropertyType,
+ (PBYTE)&ProblemCode,
+ sizeof(ProblemCode),
+ NULL,
+ 0) ||
+ (PropertyType != DEVPROP_TYPE_INT32 && PropertyType != DEVPROP_TYPE_UINT32))
+ ProblemCode = 0;
+ LastError = RtlNtStatusToDosError(NtStatus);
+ if (LastError == ERROR_SUCCESS)
+ LastError = ERROR_DEVICE_NOT_AVAILABLE;
+ LOG_ERROR(LastError, L"Failed to setup adapter (problem code: 0x%X, ntstatus: 0x%X)", ProblemCode, NtStatus);
+ goto cleanupCreateContext;
+ }
+
+skipSwDevice:
+ Adapter->DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
+ if (Adapter->DevInfo == INVALID_HANDLE_VALUE)
+ {
+ Adapter->DevInfo = NULL;
+ LastError = LOG_LAST_ERROR(L"Failed to make device list");
+ goto cleanupCreateContext;
+ }
+ Adapter->DevInfoData.cbSize = sizeof(Adapter->DevInfoData);
+ if (!SetupDiOpenDeviceInfoW(
+ Adapter->DevInfo, Adapter->DevInstanceID, NULL, DIOD_INHERIT_CLASSDRVS, &Adapter->DevInfoData))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to open device instance ID %s", Adapter->DevInstanceID);
+ SetupDiDestroyDeviceInfoList(Adapter->DevInfo);
+ Adapter->DevInfo = NULL;
+ goto cleanupCreateContext;
+ }
+
+ if (!PopulateAdapterData(Adapter))
+ {
+ LastError = LOG(WINTUN_LOG_ERR, L"Failed to populate adapter data");
+ goto cleanupCreateContext;
+ }
+
+ if (!NciSetAdapterName(&Adapter->CfgInstanceID, Name))
+ {
+ LastError = LOG(WINTUN_LOG_ERR, L"Failed to set adapter name \"%s\"", Name);
+ goto cleanupCreateContext;
+ }
+
+ if (IsWindows7)
+ CreateAdapterPostWin7(Adapter, TunnelTypeName);
+
+cleanupCreateContext:
+ CloseHandle(CreateContext.Triggered);
+cleanupAdapter:
+ if (LastError != ERROR_SUCCESS)
+ {
+ WintunCloseAdapter(Adapter);
+ Adapter = NULL;
+ }
+cleanupDriverInstall:
+ DriverInstallDeferredCleanup(DevInfoExistingAdapters, ExistingAdapters);
+cleanupDeviceInstallationMutex:
+ NamespaceReleaseMutex(DeviceInstallationMutex);
+cleanup:
+ QueueUpOrphanedDeviceCleanupRoutine();
+ return RET_ERROR(Adapter, LastError);
+}
+
+_Use_decl_annotations_
+WINTUN_ADAPTER_HANDLE WINAPI
+WintunOpenAdapter(LPCWSTR Name)
+{
+ DWORD LastError = ERROR_SUCCESS;
+ WINTUN_ADAPTER *Adapter = NULL;
+
+ HANDLE DeviceInstallationMutex = NamespaceTakeDeviceInstallationMutex();
+ if (!DeviceInstallationMutex)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to take device installation mutex");
+ goto cleanup;
+ }
+
+ Adapter = Zalloc(sizeof(*Adapter));
+ if (!Adapter)
+ goto cleanupDeviceInstallationMutex;
+
+ HDEVINFO DevInfo =
+ SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WINTUN_ENUMERATOR, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
+ if (DevInfo == INVALID_HANDLE_VALUE)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to get present adapters");
+ goto cleanupAdapter;
+ }
+
+ SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
+ BOOL Found = FALSE;
+ for (DWORD EnumIndex = 0; !Found; ++EnumIndex)
+ {
+ if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ continue;
+ }
+
+ DEVPROPTYPE PropType;
+ WCHAR OtherName[MAX_ADAPTER_NAME];
+ Found = SetupDiGetDevicePropertyW(
+ DevInfo,
+ &DevInfoData,
+ &DEVPKEY_Wintun_Name,
+ &PropType,
+ (PBYTE)OtherName,
+ MAX_ADAPTER_NAME * sizeof(OtherName[0]),
+ NULL,
+ 0) &&
+ PropType == DEVPROP_TYPE_STRING && !_wcsicmp(Name, OtherName);
+ }
+ if (!Found)
+ {
+ LastError = LOG_ERROR(ERROR_NOT_FOUND, L"Failed to find matching adapter name");
+ goto cleanupDevInfo;
+ }
+ DWORD RequiredChars = _countof(Adapter->DevInstanceID);
+ if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, Adapter->DevInstanceID, RequiredChars, &RequiredChars))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to get adapter instance ID");
+ goto cleanupDevInfo;
+ }
+ Adapter->DevInfo = DevInfo;
+ Adapter->DevInfoData = DevInfoData;
+ BOOL Ret = WaitForInterface(Adapter->DevInstanceID) && PopulateAdapterData(Adapter);
+ Adapter->DevInfo = NULL;
+ if (!Ret)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to populate adapter");
+ goto cleanupDevInfo;
+ }
+
+cleanupDevInfo:
+ SetupDiDestroyDeviceInfoList(DevInfo);
+cleanupAdapter:
+ if (LastError != ERROR_SUCCESS)
+ {
+ WintunCloseAdapter(Adapter);
+ Adapter = NULL;
+ }
+cleanupDeviceInstallationMutex:
+ NamespaceReleaseMutex(DeviceInstallationMutex);
+cleanup:
+ QueueUpOrphanedDeviceCleanupRoutine();
+ return RET_ERROR(Adapter, LastError);
+}
+
+_Use_decl_annotations_
+BOOL
+AdapterRemoveInstance(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData)
+{
+#ifdef MAYBE_WOW64
+ if (NativeMachine != IMAGE_FILE_PROCESS)
+ return RemoveInstanceViaRundll32(DevInfo, DevInfoData);
+#endif
+
+ SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
+ .InstallFunction = DIF_REMOVE },
+ .Scope = DI_REMOVEDEVICE_GLOBAL };
+ return SetupDiSetClassInstallParamsW(
+ DevInfo, DevInfoData, &RemoveDeviceParams.ClassInstallHeader, sizeof(RemoveDeviceParams)) &&
+ SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, DevInfoData);
+}
+
+_Use_decl_annotations_
+BOOL
+AdapterEnableInstance(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData)
+{
+#ifdef MAYBE_WOW64
+ if (NativeMachine != IMAGE_FILE_PROCESS)
+ return EnableInstanceViaRundll32(DevInfo, DevInfoData);
+#endif
+
+ SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
+ .InstallFunction = DIF_PROPERTYCHANGE },
+ .StateChange = DICS_ENABLE,
+ .Scope = DICS_FLAG_GLOBAL };
+ return SetupDiSetClassInstallParamsW(DevInfo, DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) &&
+ SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, DevInfoData);
+}
+
+_Use_decl_annotations_
+BOOL
+AdapterDisableInstance(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData)
+{
+#ifdef MAYBE_WOW64
+ if (NativeMachine != IMAGE_FILE_PROCESS)
+ return DisableInstanceViaRundll32(DevInfo, DevInfoData);
+#endif
+ SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
+ .InstallFunction = DIF_PROPERTYCHANGE },
+ .StateChange = DICS_DISABLE,
+ .Scope = DICS_FLAG_GLOBAL };
+ return SetupDiSetClassInstallParamsW(DevInfo, DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) &&
+ SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, DevInfoData);
+}
diff --git a/api/adapter.h b/api/adapter.h
new file mode 100644
index 0000000..cfa22fd
--- /dev/null
+++ b/api/adapter.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+#include "wintun.h"
+#include <IPExport.h>
+#include <SetupAPI.h>
+#include <cfgmgr32.h>
+#include <Windows.h>
+
+#define WINTUN_HWID L"Wintun"
+#define WINTUN_ENUMERATOR (IsWindows7 ? L"ROOT\\" WINTUN_HWID : L"SWD\\" WINTUN_HWID)
+
+extern const DEVPROPKEY DEVPKEY_Wintun_Name;
+
+typedef struct HSWDEVICE__ *HSWDEVICE;
+
+/**
+ * Wintun adapter descriptor.
+ */
+typedef struct _WINTUN_ADAPTER
+{
+ HSWDEVICE SwDevice;
+ HDEVINFO DevInfo;
+ SP_DEVINFO_DATA DevInfoData;
+ WCHAR *InterfaceFilename;
+ GUID CfgInstanceID;
+ WCHAR DevInstanceID[MAX_DEVICE_ID_LEN];
+ DWORD LuidIndex;
+ DWORD IfType;
+ DWORD IfIndex;
+} WINTUN_ADAPTER;
+/**
+ * @copydoc WINTUN_CREATE_ADAPTER_FUNC
+ */
+WINTUN_CREATE_ADAPTER_FUNC WintunCreateAdapter;
+
+/**
+ * @copydoc WINTUN_OPEN_ADAPTER_FUNC
+ */
+WINTUN_OPEN_ADAPTER_FUNC WintunOpenAdapter;
+
+/**
+ * @copydoc WINTUN_CLOSE_ADAPTER_FUNC
+ */
+WINTUN_CLOSE_ADAPTER_FUNC WintunCloseAdapter;
+
+/**
+ * @copydoc WINTUN_GET_ADAPTER_LUID_FUNC
+ */
+WINTUN_GET_ADAPTER_LUID_FUNC WintunGetAdapterLUID;
+
+/**
+ * Returns a handle to the adapter device object.
+ *
+ * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter.
+ *
+ * @return If the function succeeds, the return value is adapter device object handle.
+ * If the function fails, the return value is INVALID_HANDLE_VALUE. To get extended error
+ * information, call GetLastError.
+ */
+_Return_type_success_(return != INVALID_HANDLE_VALUE)
+HANDLE WINAPI
+AdapterOpenDeviceObject(_In_ const WINTUN_ADAPTER *Adapter);
+
+/**
+ * Returns the device object file name for an adapter instance ID.
+ *
+ * @param InstanceID The device instance ID of the adapter.
+ *
+ * @return If the function succeeds, the return value is the filename of the device object, which
+ * must be freed with Free(). If the function fails, the return value is INVALID_HANDLE_VALUE.
+ * To get extended error information, call GetLastError.
+ */
+_Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+LPWSTR
+AdapterGetDeviceObjectFileName(_In_z_ LPCWSTR InstanceId);
+
+/**
+ * Cleans up adapters with no attached process.
+ */
+VOID AdapterCleanupOrphanedDevices(VOID);
+
+/**
+ * Cleans up adapters that use the old enumerator.
+ */
+VOID AdapterCleanupLegacyDevices(VOID);
+
+/**
+ * Removes the specified device instance.
+ *
+ * @param DevInfo Device info handle from SetupAPI.
+ * @param DevInfoData Device info data specifying which device.
+ *
+ * @return If the function succeeds, the return value is TRUE. If the
+ * function fails, the return value is FALSE. To get extended
+ * error information, call GetLastError.
+ */
+
+_Return_type_success_(return != FALSE)
+BOOL
+AdapterRemoveInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
+
+/**
+ * Enables the specified device instance.
+ *
+ * @param DevInfo Device info handle from SetupAPI.
+ * @param DevInfoData Device info data specifying which device.
+ *
+ * @return If the function succeeds, the return value is TRUE. If the
+ * function fails, the return value is FALSE. To get extended
+ * error information, call GetLastError.
+ */
+
+_Return_type_success_(return != FALSE)
+BOOL
+AdapterEnableInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
+
+/**
+ * Disables the specified device instance.
+ *
+ * @param DevInfo Device info handle from SetupAPI.
+ * @param DevInfoData Device info data specifying which device.
+ *
+ * @return If the function succeeds, the return value is TRUE. If the
+ * function fails, the return value is FALSE. To get extended
+ * error information, call GetLastError.
+ */
+
+_Return_type_success_(return != FALSE)
+BOOL
+AdapterDisableInstance(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
diff --git a/api/adapter_win7.h b/api/adapter_win7.h
new file mode 100644
index 0000000..affbd09
--- /dev/null
+++ b/api/adapter_win7.h
@@ -0,0 +1,351 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+static const DEVPROPKEY DEVPKEY_Wintun_OwningProcess = {
+ { 0x3361c968, 0x2f2e, 0x4660, { 0xb4, 0x7e, 0x69, 0x9c, 0xdc, 0x4c, 0x32, 0xb9 } },
+ DEVPROPID_FIRST_USABLE + 3
+};
+
+typedef struct _OWNING_PROCESS
+{
+ DWORD ProcessId;
+ FILETIME CreationTime;
+} OWNING_PROCESS;
+
+_Must_inspect_result_
+static _Return_type_success_(return != FALSE)
+BOOL
+WaitForInterfaceWin7(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData, _In_ LPCWSTR DevInstanceId)
+{
+ ULONG Status, Number;
+ DWORD ValType, Zero;
+ WCHAR *FileName = NULL;
+ HKEY Key = INVALID_HANDLE_VALUE;
+ HANDLE FileHandle = INVALID_HANDLE_VALUE;
+ BOOLEAN Ret = FALSE;
+ for (DWORD Tries = 0; Tries < 1500; ++Tries)
+ {
+ if (Tries)
+ Sleep(10);
+ if (Key == INVALID_HANDLE_VALUE)
+ Key = SetupDiOpenDevRegKey(DevInfo, DevInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_QUERY_VALUE);
+ if (!FileName)
+ FileName = AdapterGetDeviceObjectFileName(DevInstanceId);
+ if (FileName && FileHandle == INVALID_HANDLE_VALUE)
+ FileHandle = CreateFileW(
+ FileName,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ Zero = 0;
+ if (FileName && FileHandle != INVALID_HANDLE_VALUE && Key != INVALID_HANDLE_VALUE && Key &&
+ RegQueryValueExW(Key, L"NetCfgInstanceId", NULL, &ValType, NULL, &Zero) != ERROR_MORE_DATA &&
+ CM_Get_DevNode_Status(&Status, &Number, DevInfoData->DevInst, 0) == CR_SUCCESS &&
+ !(Status & DN_HAS_PROBLEM) && !Number)
+ {
+ Ret = TRUE;
+ break;
+ }
+ }
+ if (Key != INVALID_HANDLE_VALUE && Key)
+ RegCloseKey(Key);
+ if (FileHandle != INVALID_HANDLE_VALUE)
+ CloseHandle(FileHandle);
+ Free(FileName);
+ return Ret;
+}
+
+_Must_inspect_result_
+static _Return_type_success_(return != FALSE)
+BOOL
+CreateAdapterWin7(_Inout_ WINTUN_ADAPTER *Adapter, _In_z_ LPCWSTR Name, _In_z_ LPCWSTR TunnelTypeName)
+{
+ DWORD LastError = ERROR_SUCCESS;
+
+ HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
+ if (DevInfo == INVALID_HANDLE_VALUE)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create empty device information set");
+ goto cleanup;
+ }
+ SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
+
+#ifdef MAYBE_WOW64
+ if (NativeMachine != IMAGE_FILE_PROCESS)
+ {
+ if (!CreateInstanceWin7ViaRundll32(Adapter->DevInstanceID))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create device instance");
+ goto cleanup;
+ }
+ if (!SetupDiOpenDeviceInfoW(DevInfo, Adapter->DevInstanceID, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+ goto resumeAfterInstance;
+ }
+#endif
+
+ if (!SetupDiCreateDeviceInfoW(
+ DevInfo, WINTUN_HWID, &GUID_DEVCLASS_NET, TunnelTypeName, NULL, DICD_GENERATE_ID, &DevInfoData))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create new device information element");
+ goto cleanupDevInfo;
+ }
+ SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) };
+ if (!SetupDiGetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to retrieve adapter device installation parameters");
+ goto cleanupDevInfo;
+ }
+ DevInstallParams.Flags |= DI_QUIETINSTALL;
+ if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to set adapter device installation parameters");
+ goto cleanupDevInfo;
+ }
+ if (!SetupDiSetSelectedDevice(DevInfo, &DevInfoData))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to select adapter device");
+ goto cleanupDevInfo;
+ }
+ static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID;
+ if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids)))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to set adapter hardware ID");
+ goto cleanupDevInfo;
+ }
+ if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed building adapter driver info list");
+ goto cleanupDevInfo;
+ }
+ SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) };
+ if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, 0, &DrvInfoData) ||
+ !SetupDiSetSelectedDriverW(DevInfo, &DevInfoData, &DrvInfoData))
+ {
+ LastError = LOG_ERROR(ERROR_DRIVER_INSTALL_BLOCKED, L"Failed to select a driver");
+ goto cleanupDriverInfo;
+ }
+
+ if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DevInfo, &DevInfoData))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to register adapter device");
+ goto cleanupDevInfo;
+ }
+ if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, DevInfo, &DevInfoData))
+ LOG_LAST_ERROR(L"Failed to register adapter coinstallers");
+ if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, DevInfo, &DevInfoData))
+ LOG_LAST_ERROR(L"Failed to install adapter interfaces");
+ if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, DevInfo, &DevInfoData))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to install adapter device");
+ goto cleanupDevice;
+ }
+
+#ifdef MAYBE_WOW64
+resumeAfterInstance:;
+#endif
+
+ OWNING_PROCESS OwningProcess = { .ProcessId = GetCurrentProcessId() };
+ FILETIME Unused;
+ if (!GetProcessTimes(GetCurrentProcess(), &OwningProcess.CreationTime, &Unused, &Unused, &Unused))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to get process creation time");
+ goto cleanupDevice;
+ }
+
+ if (!SetupDiSetDeviceRegistryPropertyW(
+ DevInfo,
+ &DevInfoData,
+ SPDRP_FRIENDLYNAME,
+ (PBYTE)TunnelTypeName,
+ (DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0]))) ||
+ !SetupDiSetDeviceRegistryPropertyW(
+ DevInfo,
+ &DevInfoData,
+ SPDRP_DEVICEDESC,
+ (PBYTE)TunnelTypeName,
+ (DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0]))) ||
+ !SetupDiSetDevicePropertyW(
+ DevInfo,
+ &DevInfoData,
+ &DEVPKEY_Wintun_Name,
+ DEVPROP_TYPE_STRING,
+ (PBYTE)Name,
+ (DWORD)((wcslen(Name) + 1) * sizeof(Name[0])),
+ 0) ||
+ !SetupDiSetDevicePropertyW(
+ DevInfo,
+ &DevInfoData,
+ &DEVPKEY_Wintun_OwningProcess,
+ DEVPROP_TYPE_BINARY,
+ (PBYTE)&OwningProcess,
+ sizeof(OwningProcess),
+ 0))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to set device properties");
+ goto cleanupDevice;
+ }
+
+ DWORD RequiredChars = _countof(Adapter->DevInstanceID);
+ if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, Adapter->DevInstanceID, RequiredChars, &RequiredChars))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to get adapter instance ID");
+ goto cleanupDevice;
+ }
+
+ if (!WaitForInterfaceWin7(DevInfo, &DevInfoData, Adapter->DevInstanceID))
+ {
+ DEVPROPTYPE PropertyType = 0;
+ INT32 ProblemCode = 0;
+ if (!SetupDiGetDevicePropertyW(
+ DevInfo,
+ &DevInfoData,
+ &DEVPKEY_Device_ProblemCode,
+ &PropertyType,
+ (PBYTE)&ProblemCode,
+ sizeof(ProblemCode),
+ NULL,
+ 0) ||
+ (PropertyType != DEVPROP_TYPE_INT32 && PropertyType != DEVPROP_TYPE_UINT32))
+ ProblemCode = 0;
+ LastError = LOG_ERROR(
+ ERROR_DEVICE_REINITIALIZATION_NEEDED, L"Failed to setup adapter (problem code: 0x%x)", ProblemCode);
+ goto cleanupDevice;
+ }
+
+cleanupDevice:
+ if (LastError != ERROR_SUCCESS)
+ AdapterRemoveInstance(DevInfo, &DevInfoData);
+cleanupDriverInfo:
+ SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
+cleanupDevInfo:
+ SetupDiDestroyDeviceInfoList(DevInfo);
+cleanup:
+ return RET_ERROR(TRUE, LastError);
+}
+
+static VOID
+CreateAdapterPostWin7(_Inout_ WINTUN_ADAPTER *Adapter, _In_z_ LPCWSTR TunnelTypeName)
+{
+ SetupDiSetDeviceRegistryPropertyW(
+ Adapter->DevInfo,
+ &Adapter->DevInfoData,
+ SPDRP_FRIENDLYNAME,
+ (PBYTE)TunnelTypeName,
+ (DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0])));
+ SetupDiSetDeviceRegistryPropertyW(
+ Adapter->DevInfo,
+ &Adapter->DevInfoData,
+ SPDRP_DEVICEDESC,
+ (PBYTE)TunnelTypeName,
+ (DWORD)((wcslen(TunnelTypeName) + 1) * sizeof(TunnelTypeName[0])));
+}
+
+static BOOL
+ProcessIsStale(_In_ OWNING_PROCESS *OwningProcess)
+{
+ HANDLE Process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, OwningProcess->ProcessId);
+ if (!Process)
+ return TRUE;
+ FILETIME CreationTime, Unused;
+ BOOL Ret = GetProcessTimes(Process, &CreationTime, &Unused, &Unused, &Unused);
+ CloseHandle(Process);
+ if (!Ret)
+ return FALSE;
+ return !!memcmp(&CreationTime, &OwningProcess->CreationTime, sizeof(CreationTime));
+}
+
+VOID AdapterCleanupOrphanedDevicesWin7(VOID)
+{
+ HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, WINTUN_ENUMERATOR, NULL, 0, NULL, NULL, NULL);
+ if (DevInfo == INVALID_HANDLE_VALUE)
+ {
+ if (GetLastError() != ERROR_INVALID_DATA)
+ LOG_LAST_ERROR(L"Failed to get adapters");
+ return;
+ }
+
+ SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
+ for (DWORD EnumIndex = 0;; ++EnumIndex)
+ {
+ if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ continue;
+ }
+
+ OWNING_PROCESS OwningProcess;
+ DEVPROPTYPE PropType;
+ if (SetupDiGetDevicePropertyW(
+ DevInfo,
+ &DevInfoData,
+ &DEVPKEY_Wintun_OwningProcess,
+ &PropType,
+ (PBYTE)&OwningProcess,
+ sizeof(OwningProcess),
+ NULL,
+ 0) &&
+ PropType == DEVPROP_TYPE_BINARY && !ProcessIsStale(&OwningProcess))
+ continue;
+
+ WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>";
+ SetupDiGetDevicePropertyW(
+ DevInfo,
+ &DevInfoData,
+ &DEVPKEY_Wintun_Name,
+ &PropType,
+ (PBYTE)Name,
+ MAX_ADAPTER_NAME * sizeof(Name[0]),
+ NULL,
+ 0);
+ if (!AdapterRemoveInstance(DevInfo, &DevInfoData))
+ {
+ LOG_LAST_ERROR(L"Failed to remove orphaned adapter \"%s\"", Name);
+ continue;
+ }
+ LOG(WINTUN_LOG_INFO, L"Removed orphaned adapter \"%s\"", Name);
+ }
+ SetupDiDestroyDeviceInfoList(DevInfo);
+}
+
+VOID AdapterCleanupLegacyDevices(VOID)
+{
+ HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, L"ROOT\\NET", NULL, 0, NULL, NULL, NULL);
+ if (DevInfo == INVALID_HANDLE_VALUE)
+ return;
+ SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
+ for (DWORD EnumIndex = 0;; ++EnumIndex)
+ {
+ if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DevInfoData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ continue;
+ }
+ WCHAR HardwareIDs[0x400] = { 0 };
+ DWORD ValueType, Size = sizeof(HardwareIDs) - sizeof(HardwareIDs[0]);
+ if (!SetupDiGetDeviceRegistryPropertyW(
+ DevInfo, &DevInfoData, SPDRP_HARDWAREID, &ValueType, (PBYTE)HardwareIDs, Size, &Size) ||
+ Size > sizeof(HardwareIDs) - sizeof(HardwareIDs[0]))
+ continue;
+ Size /= sizeof(HardwareIDs[0]);
+ for (WCHAR *P = HardwareIDs; P < HardwareIDs + Size; P += wcslen(P) + 1)
+ {
+ if (!_wcsicmp(P, WINTUN_HWID))
+ {
+ AdapterRemoveInstance(DevInfo, &DevInfoData);
+ break;
+ }
+ }
+ }
+ SetupDiDestroyDeviceInfoList(DevInfo);
+} \ No newline at end of file
diff --git a/api/api.vcxproj b/api/api.vcxproj
new file mode 100644
index 0000000..d0d0dcb
--- /dev/null
+++ b/api/api.vcxproj
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}</ProjectGuid>
+ <RootNamespace>api</RootNamespace>
+ <ProjectName>api</ProjectName>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="..\wintun.props" />
+ <PropertyGroup>
+ <TargetName>wintun</TargetName>
+ <IgnoreImportLibrary>true</IgnoreImportLibrary>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <PreprocessorDefinitions>_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Platform)'=='Win32'">MAYBE_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Platform)'=='x64'">MAYBE_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Platform)'=='ARM'">MAYBE_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Platform)'=='ARM64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalOptions>/volatile:iso %(AdditionalOptions)</AdditionalOptions>
+ <DisableSpecificWarnings>4100;4201;$(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>..\$(Configuration)\$(WintunPlatform);..\$(Configuration);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions Condition="Exists('..\$(Configuration)\arm64\driver\wintun.sys') And Exists('..\$(Configuration)\arm64\setupapihost.dll')">BUILT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="Exists('..\$(Configuration)\amd64\driver\wintun.sys') And Exists('..\$(Configuration)\amd64\setupapihost.dll')">BUILT_AMD64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Platform)'=='Win32'">WANT_ARM64_WOW64;WANT_AMD64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Platform)'=='x64'">WANT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions Condition="'$(Platform)'=='ARM'">WANT_ARM64_WOW64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <DelayLoadDLLs>advapi32.dll;api-ms-win-devices-query-l1-1-0.dll;api-ms-win-devices-swdevice-l1-1-0.dll;cfgmgr32.dll;iphlpapi.dll;ole32.dll;nci.dll;setupapi.dll;shlwapi.dll;version.dll</DelayLoadDLLs>
+ <DelayLoadDLLs Condition="'$(Platform)'!='ARM64'">shell32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <AdditionalDependencies>Cfgmgr32.lib;Iphlpapi.lib;onecore.lib;$(IntDir)nci.lib;ntdll.lib;Setupapi.lib;shlwapi.lib;swdevice.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
+ <SubSystem>Windows</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ResourceCompile Include="resources.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="exports.def" />
+ <None Include="nci.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="adapter_win7.h" />
+ <ClInclude Include="main.h" />
+ <ClInclude Include="adapter.h" />
+ <ClInclude Include="driver.h" />
+ <ClInclude Include="logger.h" />
+ <ClInclude Include="namespace.h" />
+ <ClInclude Include="nci.h" />
+ <ClInclude Include="ntdll.h" />
+ <ClInclude Include="registry.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="rundll32.h" />
+ <ClInclude Include="wintun.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="main.c" />
+ <ClCompile Include="adapter.c" />
+ <ClCompile Include="driver.c" />
+ <ClCompile Include="logger.c" />
+ <ClCompile Include="namespace.c" />
+ <ClCompile Include="registry.c" />
+ <ClCompile Include="resource.c" />
+ <ClCompile Include="session.c" />
+ <ClCompile Include="rundll32.c" />
+ </ItemGroup>
+ <Import Project="..\wintun.props.user" Condition="exists('..\wintun.props.user')" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets" />
+ <PropertyGroup>
+ <CleanDependsOn>CleanInfVersion;CleanNci;$(CleanDependsOn)</CleanDependsOn>
+ </PropertyGroup>
+ <Target Name="BuildInfVersion" BeforeTargets="ClCompile" Inputs="$(OutDir)driver\wintun.inf" Outputs="$(IntDir)wintun-inf.h">
+ <Exec Command="cscript.exe /nologo &quot;extract-driverver.js&quot; &lt; &quot;$(OutDir)driver\wintun.inf&quot; &gt; &quot;$(IntDir)wintun-inf.h&quot;" />
+ </Target>
+ <Target Name="CleanInfVersion">
+ <Delete Files="$(IntDir)wintun-inf.h" />
+ </Target>
+ <Target Name="BuildNci" BeforeTargets="Link" Inputs="$(ProjectDir)nci.def;$(ProjectDir)nci.h" Outputs="$(IntDir)nci.lib">
+ <Exec Command="cl.exe /nologo /DGENERATE_LIB /Ob0 /c /Fo&quot;$(IntDir)nci.obj&quot; /Tc &quot;nci.h&quot;" />
+ <Exec Command="lib.exe /def:&quot;$(ProjectDir)nci.def&quot; /out:&quot;$(IntDir)nci.lib&quot; /machine:$(PlatformTarget) /nologo &quot;$(IntDir)nci.obj&quot;" />
+ </Target>
+ <Target Name="CleanNci">
+ <Delete Files="$(IntDir)nci.obj;$(IntDir)nci.lib" />
+ </Target>
+</Project>
diff --git a/api/api.vcxproj.filters b/api/api.vcxproj.filters
new file mode 100644
index 0000000..5fb8b10
--- /dev/null
+++ b/api/api.vcxproj.filters
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="resources.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="exports.def">
+ <Filter>Source Files</Filter>
+ </None>
+ <None Include="nci.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="nci.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="namespace.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="registry.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="logger.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="adapter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="wintun.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ntdll.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="rundll32.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="driver.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="adapter_win7.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="namespace.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rundll32.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="logger.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="resource.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="adapter.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="session.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="driver.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="registry.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project>
diff --git a/api/driver.c b/api/driver.c
new file mode 100644
index 0000000..4ed0d76
--- /dev/null
+++ b/api/driver.c
@@ -0,0 +1,519 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include <Windows.h>
+#include <winternl.h>
+#include <cfgmgr32.h>
+#include <SetupAPI.h>
+#include <devguid.h>
+#include <ndisguid.h>
+#include <Shlwapi.h>
+#include <shellapi.h>
+#include <wchar.h>
+
+#include "driver.h"
+#include "adapter.h"
+#include "logger.h"
+#include "namespace.h"
+#include "resource.h"
+#include "registry.h"
+#include "ntdll.h"
+#include "rundll32.h"
+#include "wintun-inf.h"
+
+#pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */
+
+struct _SP_DEVINFO_DATA_LIST
+{
+ SP_DEVINFO_DATA Data;
+ struct _SP_DEVINFO_DATA_LIST *Next;
+};
+
+static _Return_type_success_(return != FALSE)
+BOOL
+DisableAllOurAdapters(_In_ HDEVINFO DevInfo, _Inout_ SP_DEVINFO_DATA_LIST **DisabledAdapters)
+{
+ DWORD LastError = ERROR_SUCCESS;
+ for (DWORD EnumIndex = 0;; ++EnumIndex)
+ {
+ SP_DEVINFO_DATA_LIST *DeviceNode = Zalloc(sizeof(*DeviceNode));
+ if (!DeviceNode)
+ return FALSE;
+ DeviceNode->Data.cbSize = sizeof(SP_DEVINFO_DATA);
+ if (!SetupDiEnumDeviceInfo(DevInfo, EnumIndex, &DeviceNode->Data))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ {
+ Free(DeviceNode);
+ break;
+ }
+ goto cleanupDeviceNode;
+ }
+
+ DEVPROPTYPE PropType;
+ WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>";
+ SetupDiGetDevicePropertyW(
+ DevInfo,
+ &DeviceNode->Data,
+ &DEVPKEY_Wintun_Name,
+ &PropType,
+ (PBYTE)Name,
+ MAX_ADAPTER_NAME * sizeof(Name[0]),
+ NULL,
+ 0);
+
+ ULONG Status, ProblemCode;
+ if (CM_Get_DevNode_Status(&Status, &ProblemCode, DeviceNode->Data.DevInst, 0) != CR_SUCCESS ||
+ ((Status & DN_HAS_PROBLEM) && ProblemCode == CM_PROB_DISABLED))
+ goto cleanupDeviceNode;
+
+ LOG(WINTUN_LOG_INFO, L"Disabling adapter \"%s\"", Name);
+ if (!AdapterDisableInstance(DevInfo, &DeviceNode->Data))
+ {
+ LOG_LAST_ERROR(L"Failed to disable adapter \"%s\"", Name);
+ LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError();
+ goto cleanupDeviceNode;
+ }
+
+ DeviceNode->Next = *DisabledAdapters;
+ *DisabledAdapters = DeviceNode;
+ continue;
+
+ cleanupDeviceNode:
+ Free(DeviceNode);
+ }
+ return RET_ERROR(TRUE, LastError);
+}
+
+static _Return_type_success_(return != FALSE)
+BOOL
+EnableAllOurAdapters(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA_LIST *AdaptersToEnable)
+{
+ DWORD LastError = ERROR_SUCCESS;
+ for (SP_DEVINFO_DATA_LIST *DeviceNode = AdaptersToEnable; DeviceNode; DeviceNode = DeviceNode->Next)
+ {
+ DEVPROPTYPE PropType;
+ WCHAR Name[MAX_ADAPTER_NAME] = L"<unknown>";
+ SetupDiGetDevicePropertyW(
+ DevInfo,
+ &DeviceNode->Data,
+ &DEVPKEY_Wintun_Name,
+ &PropType,
+ (PBYTE)Name,
+ MAX_ADAPTER_NAME * sizeof(Name[0]),
+ NULL,
+ 0);
+
+ LOG(WINTUN_LOG_INFO, L"Enabling adapter \"%s\"", Name);
+ if (!AdapterEnableInstance(DevInfo, &DeviceNode->Data))
+ {
+ LOG_LAST_ERROR(L"Failed to enable adapter \"%s\"", Name);
+ LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError();
+ }
+ }
+ return RET_ERROR(TRUE, LastError);
+}
+
+static BOOL
+IsNewer(
+ _In_ const FILETIME *DriverDate1,
+ _In_ DWORDLONG DriverVersion1,
+ _In_ const FILETIME *DriverDate2,
+ _In_ DWORDLONG DriverVersion2)
+{
+ if (DriverDate1->dwHighDateTime > DriverDate2->dwHighDateTime)
+ return TRUE;
+ if (DriverDate1->dwHighDateTime < DriverDate2->dwHighDateTime)
+ return FALSE;
+
+ if (DriverDate1->dwLowDateTime > DriverDate2->dwLowDateTime)
+ return TRUE;
+ if (DriverDate1->dwLowDateTime < DriverDate2->dwLowDateTime)
+ return FALSE;
+
+ if (DriverVersion1 > DriverVersion2)
+ return TRUE;
+ if (DriverVersion1 < DriverVersion2)
+ return FALSE;
+
+ return FALSE;
+}
+
+static _Return_type_success_(return != 0)
+DWORD
+VersionOfFile(_In_z_ LPCWSTR Filename)
+{
+ DWORD Zero;
+ DWORD Len = GetFileVersionInfoSizeW(Filename, &Zero);
+ if (!Len)
+ {
+ LOG_LAST_ERROR(L"Failed to query %s version info size", Filename);
+ return 0;
+ }
+ VOID *VersionInfo = Alloc(Len);
+ if (!VersionInfo)
+ return 0;
+ DWORD LastError = ERROR_SUCCESS, Version = 0;
+ VS_FIXEDFILEINFO *FixedInfo;
+ UINT FixedInfoLen = sizeof(*FixedInfo);
+ if (!GetFileVersionInfoW(Filename, 0, Len, VersionInfo))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to get %s version info", Filename);
+ goto out;
+ }
+ if (!VerQueryValueW(VersionInfo, L"\\", &FixedInfo, &FixedInfoLen))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to get %s version info root", Filename);
+ goto out;
+ }
+ Version = FixedInfo->dwFileVersionMS;
+ if (!Version)
+ {
+ LOG(WINTUN_LOG_WARN, L"Determined version of %s, but was v0.0, so returning failure", Filename);
+ LastError = ERROR_VERSION_PARSE_ERROR;
+ }
+out:
+ Free(VersionInfo);
+ return RET_ERROR(Version, LastError);
+}
+
+static DWORD WINAPI
+MaybeGetRunningDriverVersion(BOOL ReturnOneIfRunningInsteadOfVersion)
+{
+ PRTL_PROCESS_MODULES Modules;
+ ULONG BufferSize = 128 * 1024;
+ for (;;)
+ {
+ Modules = Alloc(BufferSize);
+ if (!Modules)
+ return 0;
+ NTSTATUS Status = NtQuerySystemInformation(SystemModuleInformation, Modules, BufferSize, &BufferSize);
+ if (NT_SUCCESS(Status))
+ break;
+ Free(Modules);
+ if (Status == STATUS_INFO_LENGTH_MISMATCH)
+ continue;
+ LOG(WINTUN_LOG_ERR, L"Failed to enumerate drivers (status: 0x%x)", Status);
+ SetLastError(RtlNtStatusToDosError(Status));
+ return 0;
+ }
+ DWORD LastError = ERROR_SUCCESS, Version = 0;
+ for (ULONG i = Modules->NumberOfModules; i-- > 0;)
+ {
+ LPCSTR NtPath = (LPCSTR)Modules->Modules[i].FullPathName;
+ if (!_stricmp(&NtPath[Modules->Modules[i].OffsetToFileName], "wintun.sys"))
+ {
+ if (ReturnOneIfRunningInsteadOfVersion)
+ {
+ Version = 1;
+ goto cleanupModules;
+ }
+ WCHAR FilePath[MAX_PATH * 3 + 15];
+ if (_snwprintf_s(FilePath, _countof(FilePath), _TRUNCATE, L"\\\\?\\GLOBALROOT%S", NtPath) == -1)
+ continue;
+ Version = VersionOfFile(FilePath);
+ if (!Version)
+ LastError = GetLastError();
+ goto cleanupModules;
+ }
+ }
+ LastError = ERROR_FILE_NOT_FOUND;
+cleanupModules:
+ Free(Modules);
+ return RET_ERROR(Version, LastError);
+}
+
+_Use_decl_annotations_
+DWORD WINAPI WintunGetRunningDriverVersion(VOID)
+{
+ return MaybeGetRunningDriverVersion(FALSE);
+}
+
+static BOOL EnsureWintunUnloaded(VOID)
+{
+ BOOL Loaded;
+ for (DWORD Tries = 0; Tries < 1500; ++Tries)
+ {
+ if (Tries)
+ Sleep(50);
+ Loaded = MaybeGetRunningDriverVersion(TRUE) != 0;
+ if (!Loaded)
+ break;
+ }
+ return !Loaded;
+}
+
+_Use_decl_annotations_
+VOID
+DriverInstallDeferredCleanup(HDEVINFO DevInfoExistingAdapters, SP_DEVINFO_DATA_LIST *ExistingAdapters)
+{
+ if (ExistingAdapters)
+ {
+ EnableAllOurAdapters(DevInfoExistingAdapters, ExistingAdapters);
+ while (ExistingAdapters)
+ {
+ SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next;
+ Free(ExistingAdapters);
+ ExistingAdapters = Next;
+ }
+ }
+ if (DevInfoExistingAdapters != INVALID_HANDLE_VALUE)
+ SetupDiDestroyDeviceInfoList(DevInfoExistingAdapters);
+}
+
+_Use_decl_annotations_
+BOOL
+DriverInstall(HDEVINFO *DevInfoExistingAdaptersForCleanup, SP_DEVINFO_DATA_LIST **ExistingAdaptersForCleanup)
+{
+ static const FILETIME OurDriverDate = WINTUN_INF_FILETIME;
+ static const DWORDLONG OurDriverVersion = WINTUN_INF_VERSION;
+ HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex();
+ if (!DriverInstallationLock)
+ {
+ LOG(WINTUN_LOG_ERR, L"Failed to take driver installation mutex");
+ return FALSE;
+ }
+ DWORD LastError = ERROR_SUCCESS;
+ HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
+ if (DevInfo == INVALID_HANDLE_VALUE)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create empty device information set");
+ goto cleanupDriverInstallationLock;
+ }
+ SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
+ if (!SetupDiCreateDeviceInfoW(DevInfo, WINTUN_HWID, &GUID_DEVCLASS_NET, NULL, NULL, DICD_GENERATE_ID, &DevInfoData))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create new device information element");
+ goto cleanupDevInfo;
+ }
+ static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID;
+ if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids)))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to set adapter hardware ID");
+ goto cleanupDevInfo;
+ }
+ if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed building adapter driver info list");
+ goto cleanupDevInfo;
+ }
+ FILETIME DriverDate = { 0 };
+ DWORDLONG DriverVersion = 0;
+ HDEVINFO DevInfoExistingAdapters = INVALID_HANDLE_VALUE;
+ SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL;
+ for (DWORD EnumIndex = 0;; ++EnumIndex)
+ {
+ SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) };
+ if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, EnumIndex, &DrvInfoData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ continue;
+ }
+ if (IsNewer(&OurDriverDate, OurDriverVersion, &DrvInfoData.DriverDate, DrvInfoData.DriverVersion))
+ {
+ if (DevInfoExistingAdapters == INVALID_HANDLE_VALUE)
+ {
+ DevInfoExistingAdapters = SetupDiGetClassDevsExW(
+ &GUID_DEVCLASS_NET, WINTUN_ENUMERATOR, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
+ if (DevInfoExistingAdapters == INVALID_HANDLE_VALUE)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to get present adapters");
+ SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
+ goto cleanupExistingAdapters;
+ }
+ _Analysis_assume_(DevInfoExistingAdapters != NULL);
+ DisableAllOurAdapters(DevInfoExistingAdapters, &ExistingAdapters);
+ LOG(WINTUN_LOG_INFO, L"Waiting for existing driver to unload from kernel");
+ if (!EnsureWintunUnloaded())
+ LOG(WINTUN_LOG_WARN,
+ L"Failed to unload existing driver, which means a reboot will likely be required");
+ }
+ LOG(WINTUN_LOG_INFO,
+ L"Removing existing driver %u.%u",
+ (DWORD)((DrvInfoData.DriverVersion & 0xffff000000000000) >> 48),
+ (DWORD)((DrvInfoData.DriverVersion & 0x0000ffff00000000) >> 32));
+ BYTE LargeBuffer[0x2000];
+ DWORD Size = sizeof(LargeBuffer);
+ SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = (SP_DRVINFO_DETAIL_DATA_W *)LargeBuffer;
+ DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
+ if (!SetupDiGetDriverInfoDetailW(DevInfo, &DevInfoData, &DrvInfoData, DrvInfoDetailData, Size, &Size))
+ {
+ LOG(WINTUN_LOG_WARN, L"Failed getting adapter driver info detail");
+ continue;
+ }
+ LPWSTR InfFileName = PathFindFileNameW(DrvInfoDetailData->InfFileName);
+ if (!SetupUninstallOEMInfW(InfFileName, SUOI_FORCEDELETE, NULL))
+ LOG_LAST_ERROR(L"Unable to remove existing driver %s", InfFileName);
+ continue;
+ }
+ if (!IsNewer(&DrvInfoData.DriverDate, DrvInfoData.DriverVersion, &DriverDate, DriverVersion))
+ continue;
+ DriverDate = DrvInfoData.DriverDate;
+ DriverVersion = DrvInfoData.DriverVersion;
+ }
+ SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
+
+ if (DriverVersion)
+ {
+ LOG(WINTUN_LOG_INFO,
+ L"Using existing driver %u.%u",
+ (DWORD)((DriverVersion & 0xffff000000000000) >> 48),
+ (DWORD)((DriverVersion & 0x0000ffff00000000) >> 32));
+ LastError = ERROR_SUCCESS;
+ goto cleanupExistingAdapters;
+ }
+
+ LOG(WINTUN_LOG_INFO,
+ L"Installing driver %u.%u",
+ (DWORD)((OurDriverVersion & 0xffff000000000000) >> 48),
+ (DWORD)((OurDriverVersion & 0x0000ffff00000000) >> 32));
+ WCHAR RandomTempSubDirectory[MAX_PATH];
+ if (!ResourceCreateTemporaryDirectory(RandomTempSubDirectory))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create temporary folder %s", RandomTempSubDirectory);
+ goto cleanupExistingAdapters;
+ }
+
+ WCHAR CatPath[MAX_PATH] = { 0 };
+ WCHAR SysPath[MAX_PATH] = { 0 };
+ WCHAR InfPath[MAX_PATH] = { 0 };
+ if (!PathCombineW(CatPath, RandomTempSubDirectory, L"wintun.cat") ||
+ !PathCombineW(SysPath, RandomTempSubDirectory, L"wintun.sys") ||
+ !PathCombineW(InfPath, RandomTempSubDirectory, L"wintun.inf"))
+ {
+ LastError = ERROR_BUFFER_OVERFLOW;
+ goto cleanupDirectory;
+ }
+
+ WCHAR *CatSource, *SysSource, *InfSource;
+ if (NativeMachine == IMAGE_FILE_PROCESS)
+ {
+ CatSource = L"wintun.cat";
+ SysSource = L"wintun.sys";
+ InfSource = L"wintun.inf";
+ }
+ else if (NativeMachine == IMAGE_FILE_MACHINE_AMD64)
+ {
+ CatSource = L"wintun-amd64.cat";
+ SysSource = L"wintun-amd64.sys";
+ InfSource = L"wintun-amd64.inf";
+ }
+ else if (NativeMachine == IMAGE_FILE_MACHINE_ARM64)
+ {
+ CatSource = L"wintun-arm64.cat";
+ SysSource = L"wintun-arm64.sys";
+ InfSource = L"wintun-arm64.inf";
+ }
+ else
+ {
+ LastError = LOG_ERROR(ERROR_NOT_SUPPORTED, L"Unsupported platform 0x%x", NativeMachine);
+ goto cleanupDirectory;
+ }
+
+ LOG(WINTUN_LOG_INFO, L"Extracting driver");
+ if (!ResourceCopyToFile(CatPath, CatSource) || !ResourceCopyToFile(SysPath, SysSource) ||
+ !ResourceCopyToFile(InfPath, InfSource))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to extract driver");
+ goto cleanupDelete;
+ }
+
+ LOG(WINTUN_LOG_INFO, L"Installing driver");
+ if (!SetupCopyOEMInfW(InfPath, NULL, SPOST_NONE, 0, NULL, 0, NULL, NULL))
+ LastError = LOG_LAST_ERROR(L"Could not install driver %s to store", InfPath);
+
+cleanupDelete:
+ DeleteFileW(CatPath);
+ DeleteFileW(SysPath);
+ DeleteFileW(InfPath);
+cleanupDirectory:
+ RemoveDirectoryW(RandomTempSubDirectory);
+cleanupExistingAdapters:
+ if (LastError == ERROR_SUCCESS)
+ {
+ *DevInfoExistingAdaptersForCleanup = DevInfoExistingAdapters;
+ *ExistingAdaptersForCleanup = ExistingAdapters;
+ }
+ else
+ DriverInstallDeferredCleanup(DevInfoExistingAdapters, ExistingAdapters);
+cleanupDevInfo:
+ SetupDiDestroyDeviceInfoList(DevInfo);
+cleanupDriverInstallationLock:
+ NamespaceReleaseMutex(DriverInstallationLock);
+ return RET_ERROR(TRUE, LastError);
+}
+
+_Use_decl_annotations_
+BOOL WINAPI WintunDeleteDriver(VOID)
+{
+ DWORD LastError = ERROR_SUCCESS;
+
+ AdapterCleanupOrphanedDevices();
+
+ HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex();
+ if (!DriverInstallationLock)
+ {
+ LastError = LOG(WINTUN_LOG_ERR, L"Failed to take driver installation mutex");
+ goto cleanup;
+ }
+
+ HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
+ if (DevInfo == INVALID_HANDLE_VALUE)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create empty device information set");
+ goto cleanupDriverInstallationLock;
+ }
+ SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
+ if (!SetupDiCreateDeviceInfoW(DevInfo, WINTUN_HWID, &GUID_DEVCLASS_NET, NULL, NULL, DICD_GENERATE_ID, &DevInfoData))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create new device information element");
+ goto cleanupDevInfo;
+ }
+ static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID;
+ if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids)))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to set adapter hardware ID");
+ goto cleanupDevInfo;
+ }
+ if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed building adapter driver info list");
+ goto cleanupDevInfo;
+ }
+ for (DWORD EnumIndex = 0;; ++EnumIndex)
+ {
+ SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) };
+ if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, EnumIndex, &DrvInfoData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ break;
+ continue;
+ }
+ BYTE LargeBuffer[0x2000];
+ DWORD Size = sizeof(LargeBuffer);
+ SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData = (SP_DRVINFO_DETAIL_DATA_W *)LargeBuffer;
+ DrvInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
+ if (!SetupDiGetDriverInfoDetailW(DevInfo, &DevInfoData, &DrvInfoData, DrvInfoDetailData, Size, &Size))
+ {
+ LOG(WINTUN_LOG_WARN, L"Failed getting adapter driver info detail");
+ continue;
+ }
+ LPCWSTR Path = PathFindFileNameW(DrvInfoDetailData->InfFileName);
+ LOG(WINTUN_LOG_INFO, L"Removing driver %s", Path);
+ if (!SetupUninstallOEMInfW(Path, 0, NULL))
+ {
+ LOG_LAST_ERROR(L"Unable to remove driver %s", Path);
+ LastError = LastError != ERROR_SUCCESS ? LastError : GetLastError();
+ }
+ }
+ SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
+cleanupDevInfo:
+ SetupDiDestroyDeviceInfoList(DevInfo);
+cleanupDriverInstallationLock:
+ NamespaceReleaseMutex(DriverInstallationLock);
+cleanup:
+ return RET_ERROR(TRUE, LastError);
+}
diff --git a/api/driver.h b/api/driver.h
new file mode 100644
index 0000000..dae4e9b
--- /dev/null
+++ b/api/driver.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+#include "wintun.h"
+#include <Windows.h>
+#include <SetupAPI.h>
+
+#define WINTUN_HWID L"Wintun"
+
+typedef struct _SP_DEVINFO_DATA_LIST SP_DEVINFO_DATA_LIST;
+
+VOID
+DriverInstallDeferredCleanup(_In_ HDEVINFO DevInfoExistingAdapters, _In_opt_ SP_DEVINFO_DATA_LIST *ExistingAdapters);
+
+_Must_inspect_result_
+_Return_type_success_(return != FALSE)
+BOOL
+DriverInstall(
+ _Out_ HDEVINFO *DevInfoExistingAdaptersForCleanup,
+ _Out_ SP_DEVINFO_DATA_LIST **ExistingAdaptersForCleanup);
+
+/**
+ * @copydoc WINTUN_DELETE_DRIVER_FUNC
+ */
+WINTUN_DELETE_DRIVER_FUNC WintunDeleteDriver;
+
+/**
+ * @copydoc WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC
+ */
+WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC WintunGetRunningDriverVersion;
diff --git a/api/exports.def b/api/exports.def
new file mode 100644
index 0000000..c12db57
--- /dev/null
+++ b/api/exports.def
@@ -0,0 +1,16 @@
+LIBRARY wintun.dll
+EXPORTS
+ WintunAllocateSendPacket
+ WintunCreateAdapter
+ WintunEndSession
+ WintunOpenAdapter
+ WintunCloseAdapter
+ WintunGetAdapterLUID
+ WintunGetReadWaitEvent
+ WintunGetRunningDriverVersion
+ WintunReceivePacket
+ WintunReleaseReceivePacket
+ WintunSendPacket
+ WintunDeleteDriver
+ WintunSetLogger
+ WintunStartSession
diff --git a/api/extract-driverver.js b/api/extract-driverver.js
new file mode 100644
index 0000000..ee60b8a
--- /dev/null
+++ b/api/extract-driverver.js
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+while (!WScript.StdIn.AtEndOfStream) {
+ var line = WScript.StdIn.ReadLine();
+ if (line.substr(0, 12) != "DriverVer = ")
+ continue;
+ var val = line.substr(12).split(",");
+ var date = val[0].split("/");
+ var ver = val[1].split(".");
+ var time = Date.UTC(date[2], date[0] - 1, date[1]).toString()
+ WScript.Echo("#define WINTUN_INF_FILETIME { (DWORD)((" + time + "0000ULL + 116444736000000000ULL) & 0xffffffffU), (DWORD)((" + time + "0000ULL + 116444736000000000ULL) >> 32) }")
+ WScript.Echo("#define WINTUN_INF_VERSION ((" + ver[0] + "ULL << 48) | (" + ver[1] + "ULL << 32) | (" + ver[2] + "ULL << 16) | (" + ver[3] + "ULL << 0))")
+ break;
+}
diff --git a/api/logger.c b/api/logger.c
new file mode 100644
index 0000000..94ce525
--- /dev/null
+++ b/api/logger.c
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include "logger.h"
+#include "adapter.h"
+#include "ntdll.h"
+#include <Windows.h>
+#include <iphlpapi.h>
+#include <winternl.h>
+#include <wchar.h>
+#include <stdlib.h>
+
+static BOOL CALLBACK
+NopLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_ DWORD64 Timestamp, _In_z_ LPCWSTR LogLine)
+{
+ return TRUE;
+}
+
+WINTUN_LOGGER_CALLBACK Logger = NopLogger;
+
+static DWORD64 Now(VOID)
+{
+ LARGE_INTEGER Timestamp;
+ NtQuerySystemTime(&Timestamp);
+ return Timestamp.QuadPart;
+}
+
+_Use_decl_annotations_
+VOID WINAPI
+WintunSetLogger(WINTUN_LOGGER_CALLBACK NewLogger)
+{
+ if (!NewLogger)
+ NewLogger = NopLogger;
+ Logger = NewLogger;
+}
+
+static VOID
+StrTruncate(_Inout_count_(StrChars) LPWSTR Str, _In_ SIZE_T StrChars)
+{
+ Str[StrChars - 2] = L'\u2026'; /* Horizontal Ellipsis */
+ Str[StrChars - 1] = 0;
+}
+
+_Use_decl_annotations_
+DWORD
+LoggerLog(WINTUN_LOGGER_LEVEL Level, LPCWSTR LogLine)
+{
+ DWORD LastError = GetLastError();
+ Logger(Level, Now(), LogLine);
+ SetLastError(LastError);
+ return LastError;
+}
+
+_Use_decl_annotations_
+DWORD
+LoggerLogV(WINTUN_LOGGER_LEVEL Level, LPCWSTR Format, va_list Args)
+{
+ DWORD LastError = GetLastError();
+ WCHAR LogLine[0x400];
+ if (_vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, Args) == -1)
+ StrTruncate(LogLine, _countof(LogLine));
+ Logger(Level, Now(), LogLine);
+ SetLastError(LastError);
+ return LastError;
+}
+
+_Use_decl_annotations_
+DWORD
+LoggerError(DWORD Error, LPCWSTR Prefix)
+{
+ LPWSTR SystemMessage = NULL, FormattedMessage = NULL;
+ FormatMessageW(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ NULL,
+ HRESULT_FROM_SETUPAPI(Error),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (VOID *)&SystemMessage,
+ 0,
+ NULL);
+ FormatMessageW(
+ FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ SystemMessage ? L"%1: %3(Code 0x%2!08X!)" : L"%1: Code 0x%2!08X!",
+ 0,
+ 0,
+ (VOID *)&FormattedMessage,
+ 0,
+ (va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage });
+ if (FormattedMessage)
+ Logger(WINTUN_LOG_ERR, Now(), FormattedMessage);
+ LocalFree(FormattedMessage);
+ LocalFree(SystemMessage);
+ return Error;
+}
+
+_Use_decl_annotations_
+DWORD
+LoggerErrorV(DWORD Error, LPCWSTR Format, va_list Args)
+{
+ WCHAR LogLine[0x400];
+ if (_vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, Args) == -1)
+ StrTruncate(LogLine, _countof(LogLine));
+ return LoggerError(Error, LogLine);
+}
+
+_Use_decl_annotations_
+VOID
+LoggerGetRegistryKeyPath(HKEY Key, LPWSTR Path)
+{
+ DWORD LastError = GetLastError();
+ if (Key == NULL)
+ {
+ wcsncpy_s(Path, MAX_REG_PATH, L"<null>", _TRUNCATE);
+ goto out;
+ }
+ if (_snwprintf_s(Path, MAX_REG_PATH, _TRUNCATE, L"0x%p", Key) == -1)
+ StrTruncate(Path, MAX_REG_PATH);
+ union
+ {
+ KEY_NAME_INFORMATION KeyNameInfo;
+ WCHAR Data[offsetof(KEY_NAME_INFORMATION, Name) + MAX_REG_PATH];
+ } Buffer;
+ DWORD Size;
+ if (!NT_SUCCESS(NtQueryKey(Key, 3, &Buffer, sizeof(Buffer), &Size)) ||
+ Size < offsetof(KEY_NAME_INFORMATION, Name) || Buffer.KeyNameInfo.NameLength >= MAX_REG_PATH * sizeof(WCHAR))
+ goto out;
+ Buffer.KeyNameInfo.NameLength /= sizeof(WCHAR);
+ wmemcpy_s(Path, MAX_REG_PATH, Buffer.KeyNameInfo.Name, Buffer.KeyNameInfo.NameLength);
+ Path[Buffer.KeyNameInfo.NameLength] = L'\0';
+out:
+ SetLastError(LastError);
+}
diff --git a/api/logger.h b/api/logger.h
new file mode 100644
index 0000000..d83839e
--- /dev/null
+++ b/api/logger.h
@@ -0,0 +1,175 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+#include "wintun.h"
+#include "main.h"
+#include "registry.h"
+#include <Windows.h>
+#include <intsafe.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+extern WINTUN_LOGGER_CALLBACK Logger;
+
+/**
+ * @copydoc WINTUN_SET_LOGGER_FUNC
+ */
+WINTUN_SET_LOGGER_FUNC WintunSetLogger;
+
+_Post_equals_last_error_
+DWORD
+LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ LPCWSTR LogLine);
+
+_Post_equals_last_error_
+DWORD
+LoggerLogV(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args);
+
+_Post_equals_last_error_
+static inline DWORD
+LoggerLogFmt(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
+{
+ va_list Args;
+ va_start(Args, Format);
+ DWORD LastError = LoggerLogV(Level, Format, Args);
+ va_end(Args);
+ return LastError;
+}
+
+_Post_equals_last_error_
+DWORD
+LoggerError(_In_ DWORD Error, _In_z_ LPCWSTR Prefix);
+
+_Post_equals_last_error_
+DWORD
+LoggerErrorV(_In_ DWORD Error, _In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args);
+
+_Post_equals_last_error_
+static inline DWORD
+LoggerErrorFmt(_In_ DWORD Error, _In_z_ _Printf_format_string_ LPCWSTR Format, ...)
+{
+ va_list Args;
+ va_start(Args, Format);
+ DWORD LastError = LoggerErrorV(Error, Format, Args);
+ va_end(Args);
+ return LastError;
+}
+
+_Post_equals_last_error_
+static inline DWORD
+LoggerLastErrorV(_In_z_ _Printf_format_string_ LPCWSTR Format, _In_ va_list Args)
+{
+ DWORD LastError = GetLastError();
+ LoggerErrorV(LastError, Format, Args);
+ SetLastError(LastError);
+ return LastError;
+}
+
+_Post_equals_last_error_
+static inline DWORD
+LoggerLastErrorFmt(_In_z_ _Printf_format_string_ LPCWSTR Format, ...)
+{
+ va_list Args;
+ va_start(Args, Format);
+ DWORD LastError = LoggerLastErrorV(Format, Args);
+ va_end(Args);
+ return LastError;
+}
+
+VOID
+LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_writes_z_(MAX_REG_PATH) LPWSTR Path);
+
+#define LOG(lvl, msg, ...) (LoggerLogFmt((lvl), msg, __VA_ARGS__))
+#define LOG_ERROR(err, msg, ...) (LoggerErrorFmt((err), msg, __VA_ARGS__))
+#define LOG_LAST_ERROR(msg, ...) (LoggerLastErrorFmt(msg, __VA_ARGS__))
+
+#define RET_ERROR(Ret, Error) ((Error) == ERROR_SUCCESS ? (Ret) : (SetLastError(Error), 0))
+
+_Must_inspect_result_
+DECLSPEC_ALLOCATOR
+static inline _Return_type_success_(return != NULL)
+_Post_maybenull_
+_Post_writable_byte_size_(Size)
+VOID *
+LoggerAlloc(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _In_ SIZE_T Size)
+{
+ VOID *Data = HeapAlloc(ModuleHeap, Flags, Size);
+ if (!Data)
+ {
+ LoggerLogFmt(WINTUN_LOG_ERR, Function, L"Out of memory (flags: 0x%x, requested size: 0x%zx)", Flags, Size);
+ SetLastError(ERROR_OUTOFMEMORY);
+ }
+ return Data;
+}
+_Must_inspect_result_
+DECLSPEC_ALLOCATOR
+static inline _Return_type_success_(return != NULL)
+_Post_maybenull_
+_Post_writable_byte_size_(Size)
+VOID *
+LoggerReAlloc(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _Frees_ptr_opt_ LPVOID Mem, _In_ SIZE_T Size)
+{
+ VOID *Data = Mem ? HeapReAlloc(ModuleHeap, Flags, Mem, Size) : HeapAlloc(ModuleHeap, Flags, Size);
+ if (!Data)
+ {
+ LoggerLogFmt(WINTUN_LOG_ERR, Function, L"Out of memory (flags: 0x%x, requested size: 0x%zx)", Flags, Size);
+ SetLastError(ERROR_OUTOFMEMORY);
+ }
+ return Data;
+}
+
+#define __L(x) L##x
+#define _L(x) __L(x)
+#define Alloc(Size) LoggerAlloc(_L(__FUNCTION__), 0, Size)
+#define ReAlloc(Mem, Size) LoggerReAlloc(_L(__FUNCTION__), 0, Mem, Size)
+#define Zalloc(Size) LoggerAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Size)
+#define ReZalloc(Mem, Size) LoggerReAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Mem, Size)
+
+_Must_inspect_result_
+DECLSPEC_ALLOCATOR
+static inline _Return_type_success_(return != NULL)
+_Post_maybenull_
+_Post_writable_byte_size_((NumberOfElements) * (SizeOfOneElement))
+VOID *
+LoggerAllocArray(_In_z_ LPCWSTR Function, _In_ DWORD Flags, _In_ SIZE_T NumberOfElements, _In_ SIZE_T SizeOfOneElement)
+{
+ SIZE_T Size;
+ if (FAILED(SIZETMult(NumberOfElements, SizeOfOneElement, &Size)))
+ return NULL;
+ return LoggerAlloc(Function, Flags, Size);
+}
+_Must_inspect_result_
+DECLSPEC_ALLOCATOR
+static inline _Return_type_success_(return != NULL)
+_Post_maybenull_
+_Post_writable_byte_size_((NumberOfElements) * (SizeOfOneElement))
+VOID *
+LoggerReAllocArray(
+ _In_z_ LPCWSTR Function,
+ _In_ DWORD Flags,
+ _Frees_ptr_opt_ LPVOID Mem,
+ _In_ SIZE_T NumberOfElements,
+ _In_ SIZE_T SizeOfOneElement)
+{
+ SIZE_T Size;
+ if (FAILED(SIZETMult(NumberOfElements, SizeOfOneElement, &Size)))
+ return NULL;
+ return LoggerReAlloc(Function, Flags, Mem, Size);
+}
+#define AllocArray(Count, Size) LoggerAllocArray(_L(__FUNCTION__), 0, Count, Size)
+#define ReAllocArray(Mem, Count, Size) LoggerReAllocArray(_L(__FUNCTION__), 0, Mem, Count, Size)
+#define ZallocArray(Count, Size) LoggerAllocArray(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Count, Size)
+#define ReZallocArray(Mem, Count, Size) LoggerReAllocArray(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Mem, Count, Size)
+
+static inline VOID
+Free(_Frees_ptr_opt_ VOID *Ptr)
+{
+ if (!Ptr)
+ return;
+ DWORD LastError = GetLastError();
+ HeapFree(ModuleHeap, 0, Ptr);
+ SetLastError(LastError);
+}
diff --git a/api/main.c b/api/main.c
new file mode 100644
index 0000000..032225e
--- /dev/null
+++ b/api/main.c
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include "logger.h"
+#include "adapter.h"
+#include "main.h"
+#include "namespace.h"
+#include "registry.h"
+#include "ntdll.h"
+
+#include <Windows.h>
+#include <delayimp.h>
+#include <sddl.h>
+#include <winefs.h>
+#include <stdlib.h>
+
+HINSTANCE ResourceModule;
+HANDLE ModuleHeap;
+SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SECURITY_ATTRIBUTES) };
+BOOL IsLocalSystem;
+USHORT NativeMachine = IMAGE_FILE_PROCESS;
+
+#if NTDDI_VERSION == NTDDI_WIN7
+BOOL IsWindows7;
+#endif
+#if NTDDI_VERSION < NTDDI_WIN10
+BOOL IsWindows10;
+#endif
+
+static FARPROC WINAPI
+DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
+{
+ if (dliNotify != dliNotePreLoadLibrary)
+ return NULL;
+ HMODULE Library = LoadLibraryExA(pdli->szDll, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
+ if (!Library)
+ abort();
+ return (FARPROC)Library;
+}
+
+const PfnDliHook __pfnDliNotifyHook2 = DelayedLoadLibraryHook;
+
+static BOOL InitializeSecurityObjects(VOID)
+{
+ BYTE LocalSystemSid[MAX_SID_SIZE];
+ DWORD RequiredBytes = sizeof(LocalSystemSid);
+ HANDLE CurrentProcessToken;
+ struct
+ {
+ TOKEN_USER MaybeLocalSystem;
+ CHAR LargeEnoughForLocalSystem[MAX_SID_SIZE];
+ } TokenUserBuffer;
+ BOOL Ret = FALSE;
+
+ if (!CreateWellKnownSid(WinLocalSystemSid, NULL, LocalSystemSid, &RequiredBytes))
+ return FALSE;
+
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken))
+ return FALSE;
+
+ if (!GetTokenInformation(CurrentProcessToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes))
+ goto cleanupProcessToken;
+
+ IsLocalSystem = EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid);
+ Ret = ConvertStringSecurityDescriptorToSecurityDescriptorW(
+ IsLocalSystem ? L"O:SYD:P(A;;GA;;;SY)(A;;GA;;;BA)S:(ML;;NWNRNX;;;HI)"
+ : L"O:BAD:P(A;;GA;;;SY)(A;;GA;;;BA)S:(ML;;NWNRNX;;;HI)",
+ SDDL_REVISION_1,
+ &SecurityAttributes.lpSecurityDescriptor,
+ NULL);
+
+cleanupProcessToken:
+ CloseHandle(CurrentProcessToken);
+ return Ret;
+}
+
+static void EnvInit(VOID)
+{
+ DWORD MajorVersion, MinorVersion;
+ RtlGetNtVersionNumbers(&MajorVersion, &MinorVersion, NULL);
+
+#if NTDDI_VERSION == NTDDI_WIN7
+ IsWindows7 = MajorVersion == 6 && MinorVersion == 1;
+#endif
+#if NTDDI_VERSION < NTDDI_WIN10
+ IsWindows10 = MajorVersion >= 10;
+#endif
+
+#ifdef MAYBE_WOW64
+ HANDLE Kernel32;
+ BOOL(WINAPI * IsWow64Process2)
+ (_In_ HANDLE Process, _Out_ USHORT * ProcessMachine, _Out_opt_ USHORT * NativeMachine);
+ USHORT ProcessMachine;
+ if ((Kernel32 = GetModuleHandleW(L"kernel32.dll")) == NULL ||
+ (*(FARPROC *)&IsWow64Process2 = GetProcAddress(Kernel32, "IsWow64Process2")) == NULL ||
+ !IsWow64Process2(GetCurrentProcess(), &ProcessMachine, &NativeMachine))
+ {
+ BOOL IsWoW64;
+ NativeMachine =
+ IsWow64Process(GetCurrentProcess(), &IsWoW64) && IsWoW64 ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_PROCESS;
+ }
+#endif
+}
+
+BOOL APIENTRY
+DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ ResourceModule = hinstDLL;
+ ModuleHeap = HeapCreate(0, 0, 0);
+ if (!ModuleHeap)
+ return FALSE;
+ if (!InitializeSecurityObjects())
+ {
+ HeapDestroy(ModuleHeap);
+ return FALSE;
+ }
+ EnvInit();
+ NamespaceInit();
+ AdapterCleanupLegacyDevices();
+ break;
+
+ case DLL_PROCESS_DETACH:
+ NamespaceDone();
+ LocalFree(SecurityAttributes.lpSecurityDescriptor);
+ HeapDestroy(ModuleHeap);
+ break;
+ }
+ return TRUE;
+}
diff --git a/api/main.h b/api/main.h
new file mode 100644
index 0000000..04ba7dd
--- /dev/null
+++ b/api/main.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+#include <Windows.h>
+
+#if defined(_M_IX86)
+# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_I386
+#elif defined(_M_AMD64)
+# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_AMD64
+#elif defined(_M_ARM)
+# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARMNT
+#elif defined(_M_ARM64)
+# define IMAGE_FILE_PROCESS IMAGE_FILE_MACHINE_ARM64
+#else
+# error Unsupported architecture
+#endif
+
+extern HINSTANCE ResourceModule;
+extern HANDLE ModuleHeap;
+extern SECURITY_ATTRIBUTES SecurityAttributes;
+extern BOOL IsLocalSystem;
+extern USHORT NativeMachine;
+
+#if NTDDI_VERSION > NTDDI_WIN7
+# define IsWindows7 FALSE
+#else
+extern BOOL IsWindows7;
+#endif
+
+#if NTDDI_VERSION >= NTDDI_WIN10
+# define IsWindows10 TRUE
+#else
+extern BOOL IsWindows10;
+#endif \ No newline at end of file
diff --git a/api/namespace.c b/api/namespace.c
new file mode 100644
index 0000000..3248edb
--- /dev/null
+++ b/api/namespace.c
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include "logger.h"
+#include "main.h"
+#include "namespace.h"
+
+#include <Windows.h>
+#include <winternl.h>
+#include <winefs.h>
+#include <wchar.h>
+#include <stdlib.h>
+
+static HANDLE PrivateNamespace = NULL;
+static HANDLE BoundaryDescriptor = NULL;
+static CRITICAL_SECTION Initializing;
+
+static _Return_type_success_(return != FALSE)
+BOOL NamespaceRuntimeInit(VOID)
+{
+ DWORD LastError;
+
+ EnterCriticalSection(&Initializing);
+ if (PrivateNamespace)
+ {
+ LeaveCriticalSection(&Initializing);
+ return TRUE;
+ }
+
+ BYTE Sid[MAX_SID_SIZE];
+ DWORD SidSize = sizeof(Sid);
+ if (!CreateWellKnownSid(IsLocalSystem ? WinLocalSystemSid : WinBuiltinAdministratorsSid, NULL, Sid, &SidSize))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create SID");
+ goto cleanupLeaveCriticalSection;
+ }
+
+ BoundaryDescriptor = CreateBoundaryDescriptorW(L"Wintun", 0);
+ if (!BoundaryDescriptor)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create boundary descriptor");
+ goto cleanupLeaveCriticalSection;
+ }
+ if (!AddSIDToBoundaryDescriptor(&BoundaryDescriptor, Sid))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to add SID to boundary descriptor");
+ goto cleanupBoundaryDescriptor;
+ }
+
+ for (;;)
+ {
+ if ((PrivateNamespace = CreatePrivateNamespaceW(&SecurityAttributes, BoundaryDescriptor, L"Wintun")) != NULL)
+ break;
+ if ((LastError = GetLastError()) == ERROR_ALREADY_EXISTS)
+ {
+ if ((PrivateNamespace = OpenPrivateNamespaceW(BoundaryDescriptor, L"Wintun")) != NULL)
+ break;
+ if ((LastError = GetLastError()) == ERROR_PATH_NOT_FOUND)
+ continue;
+ LOG_ERROR(LastError, L"Failed to open private namespace");
+ }
+ else
+ LOG_ERROR(LastError, L"Failed to create private namespace");
+ goto cleanupBoundaryDescriptor;
+ }
+
+ LeaveCriticalSection(&Initializing);
+ return TRUE;
+
+cleanupBoundaryDescriptor:
+ DeleteBoundaryDescriptor(BoundaryDescriptor);
+cleanupLeaveCriticalSection:
+ LeaveCriticalSection(&Initializing);
+ SetLastError(LastError);
+ return FALSE;
+}
+
+_Use_decl_annotations_
+HANDLE
+NamespaceTakeDriverInstallationMutex(VOID)
+{
+ if (!NamespaceRuntimeInit())
+ return NULL;
+ HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Driver-Installation-Mutex");
+ if (!Mutex)
+ {
+ LOG_LAST_ERROR(L"Failed to create mutex");
+ return NULL;
+ }
+ DWORD Result = WaitForSingleObject(Mutex, INFINITE);
+ switch (Result)
+ {
+ case WAIT_OBJECT_0:
+ case WAIT_ABANDONED:
+ return Mutex;
+ }
+ LOG(WINTUN_LOG_ERR, L"Failed to get mutex (status: 0x%x)", Result);
+ CloseHandle(Mutex);
+ SetLastError(ERROR_GEN_FAILURE);
+ return NULL;
+}
+
+_Use_decl_annotations_
+HANDLE
+NamespaceTakeDeviceInstallationMutex(VOID)
+{
+ if (!NamespaceRuntimeInit())
+ return NULL;
+ HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Device-Installation-Mutex");
+ if (!Mutex)
+ {
+ LOG_LAST_ERROR(L"Failed to create mutex");
+ return NULL;
+ }
+ DWORD Result = WaitForSingleObject(Mutex, INFINITE);
+ switch (Result)
+ {
+ case WAIT_OBJECT_0:
+ case WAIT_ABANDONED:
+ return Mutex;
+ }
+ LOG(WINTUN_LOG_ERR, L"Failed to get mutex (status: 0x%x)", Result);
+ CloseHandle(Mutex);
+ SetLastError(ERROR_GEN_FAILURE);
+ return NULL;
+}
+
+_Use_decl_annotations_
+VOID
+NamespaceReleaseMutex(HANDLE Mutex)
+{
+ ReleaseMutex(Mutex);
+ CloseHandle(Mutex);
+}
+
+VOID NamespaceInit(VOID)
+{
+ InitializeCriticalSection(&Initializing);
+}
+
+VOID NamespaceDone(VOID)
+{
+ EnterCriticalSection(&Initializing);
+ if (PrivateNamespace)
+ {
+ ClosePrivateNamespace(PrivateNamespace, 0);
+ DeleteBoundaryDescriptor(BoundaryDescriptor);
+ PrivateNamespace = NULL;
+ }
+ LeaveCriticalSection(&Initializing);
+ DeleteCriticalSection(&Initializing);
+}
diff --git a/api/namespace.h b/api/namespace.h
new file mode 100644
index 0000000..a0397be
--- /dev/null
+++ b/api/namespace.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+#include <Windows.h>
+
+_Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+_Acquires_lock_(_Curr_)
+HANDLE
+NamespaceTakeDriverInstallationMutex(VOID);
+
+_Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+_Acquires_lock_(_Curr_)
+HANDLE
+NamespaceTakeDeviceInstallationMutex(VOID);
+
+_Releases_lock_(Mutex)
+VOID
+NamespaceReleaseMutex(_In_ HANDLE Mutex);
+
+VOID NamespaceInit(VOID);
+
+VOID NamespaceDone(VOID);
diff --git a/api/nci.def b/api/nci.def
new file mode 100644
index 0000000..db484b7
--- /dev/null
+++ b/api/nci.def
@@ -0,0 +1,4 @@
+LIBRARY nci.dll
+EXPORTS
+ NciGetConnectionName
+ NciSetConnectionName
diff --git a/api/nci.h b/api/nci.h
new file mode 100644
index 0000000..ba99fa6
--- /dev/null
+++ b/api/nci.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+#include <Windows.h>
+
+#ifdef GENERATE_LIB
+# define DECLSPEC __declspec(dllexport)
+# define STUB \
+ { \
+ return 0; \
+ }
+#else
+# define DECLSPEC __declspec(dllimport)
+# define STUB ;
+#endif
+
+EXTERN_C
+DECLSPEC DWORD WINAPI
+NciSetConnectionName(_In_ const GUID *Guid, _In_z_ LPCWSTR NewName) STUB
+
+ EXTERN_C
+DECLSPEC DWORD WINAPI
+NciGetConnectionName(
+ _In_ const GUID *Guid,
+ _Out_z_bytecap_(InDestNameBytes) LPWSTR Name,
+ _In_ DWORD InDestNameBytes,
+ _Out_opt_ DWORD *OutDestNameBytes) STUB \ No newline at end of file
diff --git a/api/ntdll.h b/api/ntdll.h
new file mode 100644
index 0000000..2eb2786
--- /dev/null
+++ b/api/ntdll.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+#include <Windows.h>
+
+enum
+{
+ SystemModuleInformation = 11
+};
+
+typedef struct _RTL_PROCESS_MODULE_INFORMATION
+{
+ HANDLE Section;
+ PVOID MappedBase;
+ PVOID ImageBase;
+ ULONG ImageSize;
+ ULONG Flags;
+ USHORT LoadOrderIndex;
+ USHORT InitOrderIndex;
+ USHORT LoadCount;
+ USHORT OffsetToFileName;
+ UCHAR FullPathName[256];
+} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
+
+typedef struct _RTL_PROCESS_MODULES
+{
+ ULONG NumberOfModules;
+ RTL_PROCESS_MODULE_INFORMATION Modules[1];
+} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
+
+typedef struct _KEY_NAME_INFORMATION
+{
+ ULONG NameLength;
+ WCHAR Name[1];
+} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;
+
+#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) // TODO: #include <ntstatus.h> instead of this
+
+/* We can't use RtlGetVersion, because appcompat's aclayers.dll shims it to report Vista
+ * when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers.
+ *
+ * Another way would be reading from the PEB directly:
+ * ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(VOID *) == 8 ? 70 : 41]
+ * Or just read from KUSER_SHARED_DATA the same way on 32-bit and 64-bit:
+ * *(DWORD *)0x7FFE026C
+ */
+EXTERN_C
+DECLSPEC_IMPORT VOID NTAPI
+RtlGetNtVersionNumbers(_Out_opt_ DWORD *MajorVersion, _Out_opt_ DWORD *MinorVersion, _Out_opt_ DWORD *BuildNumber);
+
+EXTERN_C
+DECLSPEC_IMPORT DWORD NTAPI
+NtQueryKey(
+ _In_ HANDLE KeyHandle,
+ _In_ int KeyInformationClass,
+ _Out_bytecap_post_bytecount_(Length, *ResultLength) PVOID KeyInformation,
+ _In_ ULONG Length,
+ _Out_ PULONG ResultLength);
diff --git a/api/registry.c b/api/registry.c
new file mode 100644
index 0000000..4f1001c
--- /dev/null
+++ b/api/registry.c
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include "logger.h"
+#include "registry.h"
+#include <Windows.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <strsafe.h>
+
+_Use_decl_annotations_
+BOOL
+RegistryGetString(LPWSTR *Buf, DWORD Len, DWORD ValueType)
+{
+ if (wcsnlen(*Buf, Len) >= Len)
+ {
+ /* String is missing zero-terminator. */
+ LPWSTR BufZ = ReZallocArray(*Buf, (SIZE_T)Len + 1, sizeof(*BufZ));
+ if (!BufZ)
+ return FALSE;
+ _Analysis_assume_((wmemset(BufZ, L'A', (SIZE_T)Len + 1), TRUE));
+ *Buf = BufZ;
+ }
+
+ if (ValueType != REG_EXPAND_SZ)
+ return TRUE;
+
+ /* ExpandEnvironmentStringsW() returns strlen on success or 0 on error. Bail out on empty input strings to
+ * disambiguate. */
+ if (!(*Buf)[0])
+ return TRUE;
+
+ for (;;)
+ {
+ LPWSTR Expanded = AllocArray(Len, sizeof(*Expanded));
+ if (!Expanded)
+ return FALSE;
+ DWORD Result = ExpandEnvironmentStringsW(*Buf, Expanded, Len);
+ if (!Result)
+ {
+ LOG_LAST_ERROR(L"Failed to expand environment variables: %s", *Buf);
+ Free(Expanded);
+ return FALSE;
+ }
+ if (Result > Len)
+ {
+ Free(Expanded);
+ Len = Result;
+ continue;
+ }
+ Free(*Buf);
+ *Buf = Expanded;
+ return TRUE;
+ }
+}
+
+_Must_inspect_result_
+static _Return_type_success_(return != NULL)
+_Post_maybenull_
+_Post_writable_byte_size_(*BufLen)
+VOID *
+RegistryQuery(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_opt_ DWORD *ValueType, _Inout_ DWORD *BufLen, _In_ BOOL Log)
+{
+ for (;;)
+ {
+ BYTE *p = Alloc(*BufLen);
+ if (!p)
+ return NULL;
+ LSTATUS LastError = RegQueryValueExW(Key, Name, NULL, ValueType, p, BufLen);
+ if (LastError == ERROR_SUCCESS)
+ return p;
+ Free(p);
+ if (LastError != ERROR_MORE_DATA)
+ {
+ if (Log)
+ {
+ WCHAR RegPath[MAX_REG_PATH];
+ LoggerGetRegistryKeyPath(Key, RegPath);
+ LOG_ERROR(LastError, L"Failed to query registry value %.*s\\%s", MAX_REG_PATH, RegPath, Name);
+ }
+ SetLastError(LastError);
+ return NULL;
+ }
+ }
+}
+
+_Use_decl_annotations_
+LPWSTR
+RegistryQueryString(HKEY Key, LPCWSTR Name, BOOL Log)
+{
+ DWORD LastError, ValueType, Size = 256 * sizeof(WCHAR);
+ LPWSTR Value = RegistryQuery(Key, Name, &ValueType, &Size, Log);
+ if (!Value)
+ return NULL;
+ switch (ValueType)
+ {
+ case REG_SZ:
+ case REG_EXPAND_SZ:
+ case REG_MULTI_SZ:
+ if (RegistryGetString(&Value, Size / sizeof(*Value), ValueType))
+ return Value;
+ LastError = GetLastError();
+ break;
+ default: {
+ WCHAR RegPath[MAX_REG_PATH];
+ LoggerGetRegistryKeyPath(Key, RegPath);
+ LOG(WINTUN_LOG_ERR,
+ L"Registry value %.*s\\%s is not a string (type: %u)",
+ MAX_REG_PATH,
+ RegPath,
+ Name,
+ ValueType);
+ LastError = ERROR_INVALID_DATATYPE;
+ }
+ }
+ Free(Value);
+ SetLastError(LastError);
+ return NULL;
+}
+
+_Use_decl_annotations_
+BOOL
+RegistryQueryDWORD(HKEY Key, LPCWSTR Name, DWORD *Value, BOOL Log)
+{
+ DWORD ValueType, Size = sizeof(DWORD);
+ DWORD LastError = RegQueryValueExW(Key, Name, NULL, &ValueType, (BYTE *)Value, &Size);
+ if (LastError != ERROR_SUCCESS)
+ {
+ if (Log)
+ {
+ WCHAR RegPath[MAX_REG_PATH];
+ LoggerGetRegistryKeyPath(Key, RegPath);
+ LOG_ERROR(LastError, L"Failed to query registry value %.*s\\%s", MAX_REG_PATH, RegPath, Name);
+ }
+ SetLastError(LastError);
+ return FALSE;
+ }
+ if (ValueType != REG_DWORD)
+ {
+ WCHAR RegPath[MAX_REG_PATH];
+ LoggerGetRegistryKeyPath(Key, RegPath);
+ LOG(WINTUN_LOG_ERR, L"Value %.*s\\%s is not a DWORD (type: %u)", MAX_REG_PATH, RegPath, Name, ValueType);
+ SetLastError(ERROR_INVALID_DATATYPE);
+ return FALSE;
+ }
+ if (Size != sizeof(DWORD))
+ {
+ WCHAR RegPath[MAX_REG_PATH];
+ LoggerGetRegistryKeyPath(Key, RegPath);
+ LOG(WINTUN_LOG_ERR, L"Value %.*s\\%s size is not 4 bytes (size: %u)", MAX_REG_PATH, RegPath, Name, Size);
+ SetLastError(ERROR_INVALID_DATA);
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/api/registry.h b/api/registry.h
new file mode 100644
index 0000000..6beed2f
--- /dev/null
+++ b/api/registry.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+#include "wintun.h"
+#include <Windows.h>
+
+#define MAX_REG_PATH \
+ 256 /* Maximum registry path length \
+ https://support.microsoft.com/en-us/help/256986/windows-registry-information-for-advanced-users */
+
+/**
+ * Validates and/or sanitizes string value read from registry.
+ *
+ * @param Buf On input, it contains a pointer to pointer where the data is stored. The data must be allocated
+ * using HeapAlloc(ModuleHeap, 0). On output, it contains a pointer to pointer where the sanitized
+ * data is stored. It must be released with HeapFree(ModuleHeap, 0, *Buf) after use.
+ *
+ * @param Len Length of data string in wide characters.
+ *
+ * @param ValueType Type of data. Must be either REG_SZ or REG_EXPAND_SZ. REG_MULTI_SZ is treated like REG_SZ; only
+ * the first string of a multi-string is to be used.
+ *
+ * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
+ * get extended error information, call GetLastError.
+ */
+_Must_inspect_result_
+_Return_type_success_(return != FALSE)
+BOOL
+RegistryGetString(_Inout_ LPWSTR *Buf, _In_ DWORD Len, _In_ DWORD ValueType);
+
+/**
+ * Reads string value from registry key.
+ *
+ * @param Key Handle of the registry key to read from. Must be opened with read access.
+ *
+ * @param Name Name of the value to read.
+ *
+ * @param Value Pointer to string to retrieve registry value. If the value type is REG_EXPAND_SZ the value is
+ * expanded using ExpandEnvironmentStrings(). If the value type is REG_MULTI_SZ, only the first
+ * string from the multi-string is returned. The string must be released with
+ * HeapFree(ModuleHeap, 0, Value) after use.
+ *
+ * @Log Set to TRUE to log all failures; FALSE to skip logging the innermost errors. Skipping innermost
+ * errors reduces log clutter when we are using RegistryQueryString() from
+ * RegistryQueryStringWait() and some errors are expected to occur.
+ *
+ * @return String with registry value on success; If the function fails, the return value is zero. To get extended error
+ * information, call GetLastError.
+ */
+_Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+LPWSTR
+RegistryQueryString(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _In_ BOOL Log);
+
+/**
+ * Reads a 32-bit DWORD value from registry key.
+ *
+ * @param Key Handle of the registry key to read from. Must be opened with read access.
+ *
+ * @param Name Name of the value to read.
+ *
+ * @param Value Pointer to DWORD to retrieve registry value.
+ *
+ * @Log Set to TRUE to log all failures; FALSE to skip logging the innermost errors. Skipping innermost
+ * errors reduces log clutter when we are using RegistryQueryDWORD() from
+ * RegistryQueryDWORDWait() and some errors are expected to occur.
+ *
+ * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
+ * get extended error information, call GetLastError.
+ */
+_Must_inspect_result_
+_Return_type_success_(return != FALSE)
+BOOL
+RegistryQueryDWORD(_In_ HKEY Key, _In_opt_z_ LPCWSTR Name, _Out_ DWORD *Value, _In_ BOOL Log);
diff --git a/api/resource.c b/api/resource.c
new file mode 100644
index 0000000..648f568
--- /dev/null
+++ b/api/resource.c
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include "logger.h"
+#include "main.h"
+#include "resource.h"
+#include <Windows.h>
+#include <Shlwapi.h>
+#include <NTSecAPI.h>
+
+_Use_decl_annotations_
+const VOID *
+ResourceGetAddress(LPCWSTR ResourceName, DWORD *Size)
+{
+ HRSRC FoundResource = FindResourceW(ResourceModule, ResourceName, RT_RCDATA);
+ if (!FoundResource)
+ {
+ LOG_LAST_ERROR(L"Failed to find resource %s", ResourceName);
+ return NULL;
+ }
+ *Size = SizeofResource(ResourceModule, FoundResource);
+ if (!*Size)
+ {
+ LOG_LAST_ERROR(L"Failed to query resource %s size", ResourceName);
+ return NULL;
+ }
+ HGLOBAL LoadedResource = LoadResource(ResourceModule, FoundResource);
+ if (!LoadedResource)
+ {
+ LOG_LAST_ERROR(L"Failed to load resource %s", ResourceName);
+ return NULL;
+ }
+ BYTE *Address = LockResource(LoadedResource);
+ if (!Address)
+ {
+ LOG(WINTUN_LOG_ERR, L"Failed to lock resource %s", ResourceName);
+ SetLastError(ERROR_LOCK_FAILED);
+ return NULL;
+ }
+ return Address;
+}
+
+_Use_decl_annotations_
+BOOL
+ResourceCopyToFile(LPCWSTR DestinationPath, LPCWSTR ResourceName)
+{
+ DWORD SizeResource;
+ const VOID *LockedResource = ResourceGetAddress(ResourceName, &SizeResource);
+ if (!LockedResource)
+ {
+ LOG(WINTUN_LOG_ERR, L"Failed to locate resource %s", ResourceName);
+ return FALSE;
+ }
+ HANDLE DestinationHandle = CreateFileW(
+ DestinationPath,
+ GENERIC_WRITE,
+ 0,
+ &SecurityAttributes,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY,
+ NULL);
+ if (DestinationHandle == INVALID_HANDLE_VALUE)
+ {
+ LOG_LAST_ERROR(L"Failed to create file %s", DestinationPath);
+ return FALSE;
+ }
+ DWORD BytesWritten;
+ DWORD LastError;
+ if (!WriteFile(DestinationHandle, LockedResource, SizeResource, &BytesWritten, NULL))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to write file %s", DestinationPath);
+ goto cleanupDestinationHandle;
+ }
+ if (BytesWritten != SizeResource)
+ {
+ LOG(WINTUN_LOG_ERR,
+ L"Incomplete write to %s (written: %u, expected: %u)",
+ DestinationPath,
+ BytesWritten,
+ SizeResource);
+ LastError = ERROR_WRITE_FAULT;
+ goto cleanupDestinationHandle;
+ }
+ LastError = ERROR_SUCCESS;
+cleanupDestinationHandle:
+ CloseHandle(DestinationHandle);
+ return RET_ERROR(TRUE, LastError);
+}
+
+_Return_type_success_(return != FALSE)
+BOOL
+ResourceCreateTemporaryDirectory(_Out_writes_z_(MAX_PATH) LPWSTR RandomTempSubDirectory)
+{
+ WCHAR WindowsDirectory[MAX_PATH];
+ if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
+ {
+ LOG_LAST_ERROR(L"Failed to get Windows folder");
+ return FALSE;
+ }
+ WCHAR WindowsTempDirectory[MAX_PATH];
+ if (!PathCombineW(WindowsTempDirectory, WindowsDirectory, L"Temp"))
+ {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return FALSE;
+ }
+ UCHAR RandomBytes[32] = { 0 };
+ if (!RtlGenRandom(RandomBytes, sizeof(RandomBytes)))
+ {
+ LOG(WINTUN_LOG_ERR, L"Failed to generate random");
+ SetLastError(ERROR_GEN_FAILURE);
+ return FALSE;
+ }
+ WCHAR RandomSubDirectory[sizeof(RandomBytes) * 2 + 1];
+ for (int i = 0; i < sizeof(RandomBytes); ++i)
+ swprintf_s(&RandomSubDirectory[i * 2], 3, L"%02x", RandomBytes[i]);
+ if (!PathCombineW(RandomTempSubDirectory, WindowsTempDirectory, RandomSubDirectory))
+ {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return FALSE;
+ }
+ if (!CreateDirectoryW(RandomTempSubDirectory, &SecurityAttributes))
+ {
+ LOG_LAST_ERROR(L"Failed to create temporary folder %s", RandomTempSubDirectory);
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/api/resource.h b/api/resource.h
new file mode 100644
index 0000000..ae1210b
--- /dev/null
+++ b/api/resource.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+#include "wintun.h"
+#include <Windows.h>
+
+/**
+ * Locates RT_RCDATA resource memory address and size.
+ *
+ * @param ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
+ *
+ * @param Size Pointer to a variable to receive resource size.
+ *
+ * @return Resource address on success. If the function fails, the return value is NULL. To get extended error
+ * information, call GetLastError.
+ */
+_Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+_Post_readable_byte_size_(*Size) const VOID *ResourceGetAddress(_In_z_ LPCWSTR ResourceName, _Out_ DWORD *Size);
+
+/**
+ * Copies resource to a file.
+ *
+ * @param DestinationPath File path
+ *
+ * @param ResourceName Name of the RT_RCDATA resource. Use MAKEINTRESOURCEW to locate resource by ID.
+ *
+ * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
+ * get extended error information, call GetLastError.
+ */
+_Return_type_success_(return != FALSE)
+BOOL
+ResourceCopyToFile(_In_z_ LPCWSTR DestinationPath, _In_z_ LPCWSTR ResourceName);
+
+/**
+ * Creates a temporary directory.
+ *
+ * @param RandomTempSubDirectory Name of random temporary directory.
+ *
+ * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
+ * get extended error information, call GetLastError.
+ */
+_Return_type_success_(return != FALSE)
+BOOL
+ResourceCreateTemporaryDirectory(_Out_writes_z_(MAX_PATH) LPWSTR RandomTempSubDirectory);
diff --git a/api/resources.rc b/api/resources.rc
new file mode 100644
index 0000000..e7fab9c
--- /dev/null
+++ b/api/resources.rc
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include <windows.h>
+#include <ntverp.h>
+
+#pragma code_page(1252)
+
+wintun.cat RCDATA "driver\\wintun.cat"
+wintun.inf RCDATA "driver\\wintun.inf"
+wintun.sys RCDATA "driver\\wintun.sys"
+
+#if defined(WANT_AMD64_WOW64)
+# if defined(BUILT_AMD64_WOW64)
+wintun-amd64.cat RCDATA "amd64\\driver\\wintun.cat"
+wintun-amd64.inf RCDATA "amd64\\driver\\wintun.inf"
+wintun-amd64.sys RCDATA "amd64\\driver\\wintun.sys"
+setupapihost-amd64.dll RCDATA "amd64\\setupapihost.dll"
+# else
+# pragma message("AMD64 wintun.sys was not built, so this will not work from WOW64")
+# endif
+#endif
+#if defined(WANT_ARM64_WOW64)
+# if defined(BUILT_ARM64_WOW64)
+wintun-arm64.cat RCDATA "arm64\\driver\\wintun.cat"
+wintun-arm64.inf RCDATA "arm64\\driver\\wintun.inf"
+wintun-arm64.sys RCDATA "arm64\\driver\\wintun.sys"
+setupapihost-arm64.dll RCDATA "arm64\\setupapihost.dll"
+# else
+# pragma message("ARM64 wintun.sys was not built, so this will not work from WOW64")
+# endif
+#endif
+
+#define STRINGIZE(x) #x
+#define EXPAND(x) STRINGIZE(x)
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION WINTUN_VERSION_MAJ, WINTUN_VERSION_MIN, WINTUN_VERSION_REL, 0
+PRODUCTVERSION WINTUN_VERSION_MAJ, WINTUN_VERSION_MIN, WINTUN_VERSION_REL, 0
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "WireGuard LLC"
+ VALUE "FileDescription", "Wintun API Library"
+ VALUE "FileVersion", EXPAND(WINTUN_VERSION)
+ VALUE "InternalName", "wintun.dll"
+ VALUE "LegalCopyright", "Copyright \xa9 2018-2021 WireGuard LLC. All Rights Reserved."
+ VALUE "OriginalFilename", "wintun.dll"
+ VALUE "ProductName", "Wintun Driver"
+ VALUE "ProductVersion", EXPAND(WINTUN_VERSION)
+ VALUE "Comments", "https://www.wintun.net/"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/api/rundll32.c b/api/rundll32.c
new file mode 100644
index 0000000..5ea2b15
--- /dev/null
+++ b/api/rundll32.c
@@ -0,0 +1,398 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include "rundll32.h"
+#include "adapter.h"
+#include "main.h"
+#include "logger.h"
+#include "resource.h"
+#include <Windows.h>
+#include <shellapi.h>
+#include <Shlwapi.h>
+#include <cfgmgr32.h>
+#include <objbase.h>
+#include <assert.h>
+
+#ifdef MAYBE_WOW64
+
+_Return_type_success_(return != FALSE)
+static BOOL
+AppendToBuffer(_Inout_ LPWSTR *Buffer, _In_ CONST WCHAR Addition, _Inout_ SIZE_T *BufferPos, _Inout_ SIZE_T *BufferLen)
+{
+ SIZE_T NewPos;
+ if (FAILED(SIZETAdd(*BufferPos, sizeof(Addition), &NewPos)))
+ return FALSE;
+ if (NewPos >= *BufferLen)
+ {
+ SIZE_T NewLen;
+ if (FAILED(SIZETMult(NewPos, 3, &NewLen)))
+ return FALSE;
+ LPWSTR NewBuffer = ReZalloc(*Buffer, NewLen);
+ if (!NewBuffer)
+ return FALSE;
+ *Buffer = NewBuffer;
+ *BufferLen = NewLen;
+ }
+ SIZE_T NewIndex = *BufferPos / sizeof(**Buffer);
+ if (*Buffer + NewIndex < *Buffer)
+ return FALSE;
+ (*Buffer)[NewIndex] = Addition;
+ *BufferPos = NewPos;
+ return TRUE;
+}
+
+_Must_inspect_result_
+static _Return_type_success_(return != NULL)
+_Post_maybenull_
+LPWSTR
+ArgvToCommandLineW(_In_ SIZE_T ArgCount, ...)
+{
+ LPWSTR Output = NULL;
+ SIZE_T BufferPos = 0, BufferLen = 0;
+# define Append(Char) \
+ do \
+ { \
+ if (!AppendToBuffer(&Output, Char, &BufferPos, &BufferLen)) \
+ goto cleanupBuffer; \
+ } while (0)
+
+ va_list Args;
+ va_start(Args, ArgCount);
+ for (SIZE_T i = 0; i < ArgCount; ++i)
+ {
+ LPCWSTR Arg = va_arg(Args, LPCWSTR);
+ SIZE_T ArgLen = wcslen(Arg);
+ if (ArgLen >= DWORD_MAX >> 3)
+ goto cleanupBuffer;
+ if (i)
+ Append(L' ');
+ Append(L'"');
+ for (SIZE_T j = 0;; ++j)
+ {
+ SIZE_T NumberBackslashes = 0;
+
+ while (j < ArgLen && Arg[j] == L'\\')
+ {
+ ++j;
+ ++NumberBackslashes;
+ }
+ if (j >= ArgLen)
+ {
+ for (SIZE_T k = 0; k < NumberBackslashes * 2; ++k)
+ Append(L'\\');
+ break;
+ }
+ else if (Arg[j] == L'"')
+ {
+ for (SIZE_T k = 0; k < NumberBackslashes * 2 + 1; ++k)
+ Append(L'\\');
+ Append(Arg[j]);
+ }
+ else
+ {
+ for (SIZE_T k = 0; k < NumberBackslashes; ++k)
+ Append(L'\\');
+ Append(Arg[j]);
+ }
+ }
+ Append(L'"');
+ }
+ va_end(Args);
+ return Output;
+
+cleanupBuffer:
+ Free(Output);
+ return NULL;
+# undef Append
+}
+
+typedef struct _PROCESS_STDOUT_STATE
+{
+ HANDLE Stdout;
+ LPWSTR Response;
+ DWORD ResponseCapacity;
+} PROCESS_STDOUT_STATE;
+
+_Return_type_success_(return != ERROR_SUCCESS)
+static DWORD WINAPI
+ProcessStdout(_Inout_ PROCESS_STDOUT_STATE *State)
+{
+ for (DWORD Offset = 0, MaxLen = State->ResponseCapacity - 1; Offset < MaxLen;)
+ {
+ DWORD Size;
+ if (FAILED(DWordMult(MaxLen - Offset, sizeof(WCHAR), &Size)))
+ return ERROR_BUFFER_OVERFLOW;
+ if (!ReadFile(State->Stdout, State->Response + Offset, Size, &Size, NULL))
+ return ERROR_SUCCESS;
+ if (Size % sizeof(WCHAR))
+ return ERROR_INVALID_DATA;
+ Offset += Size / sizeof(WCHAR);
+ State->Response[Offset] = 0;
+ }
+ return ERROR_BUFFER_OVERFLOW;
+}
+
+static DWORD WINAPI
+ProcessStderr(_In_ HANDLE Stderr)
+{
+ WCHAR Msg[0x200], Buf[0x220], LevelRune;
+ DWORD64 Timestamp;
+ DWORD SizeRead;
+ WINTUN_LOGGER_LEVEL Level;
+ for (;;)
+ {
+ if (!ReadFile(Stderr, Buf, sizeof(Buf), &SizeRead, NULL) || !SizeRead)
+ return ERROR_SUCCESS;
+ if (SizeRead % sizeof(*Buf))
+ return ERROR_INVALID_DATA;
+ Msg[0] = Buf[SizeRead / sizeof(*Buf) - 1] = L'\0';
+ if (swscanf_s(Buf, L"[%c %I64u] %[^\n]", &LevelRune, 1, &Timestamp, Msg, (DWORD)_countof(Msg)) != 3 || !Msg[0])
+ return ERROR_INVALID_DATA;
+ if (!((Level = WINTUN_LOG_INFO, LevelRune == L'+') || (Level = WINTUN_LOG_WARN, LevelRune == L'-') ||
+ (Level = WINTUN_LOG_ERR, LevelRune == L'!')))
+ return ERROR_INVALID_DATA;
+ Logger(Level, Timestamp, Msg);
+ }
+}
+
+static _Return_type_success_(return != FALSE)
+BOOL
+ExecuteRunDll32(
+ _In_z_ LPCWSTR Function,
+ _In_z_ LPCWSTR Arguments,
+ _Out_z_cap_c_(ResponseCapacity) LPWSTR Response,
+ _In_ DWORD ResponseCapacity)
+{
+ WCHAR WindowsDirectory[MAX_PATH];
+ if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
+ {
+ LOG_LAST_ERROR(L"Failed to get Windows folder");
+ return FALSE;
+ }
+ WCHAR RunDll32Path[MAX_PATH];
+ if (!PathCombineW(RunDll32Path, WindowsDirectory, L"Sysnative\\rundll32.exe"))
+ {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return FALSE;
+ }
+
+ DWORD LastError;
+ WCHAR RandomTempSubDirectory[MAX_PATH];
+ if (!ResourceCreateTemporaryDirectory(RandomTempSubDirectory))
+ {
+ LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder");
+ return FALSE;
+ }
+ WCHAR DllPath[MAX_PATH] = { 0 };
+ if (!PathCombineW(DllPath, RandomTempSubDirectory, L"setupapihost.dll"))
+ {
+ LastError = ERROR_BUFFER_OVERFLOW;
+ goto cleanupDirectory;
+ }
+ LPCWSTR WintunDllResourceName;
+ switch (NativeMachine)
+ {
+ case IMAGE_FILE_MACHINE_AMD64:
+ WintunDllResourceName = L"setupapihost-amd64.dll";
+ break;
+ case IMAGE_FILE_MACHINE_ARM64:
+ WintunDllResourceName = L"setupapihost-arm64.dll";
+ break;
+ default:
+ LOG(WINTUN_LOG_ERR, L"Unsupported platform 0x%x", NativeMachine);
+ LastError = ERROR_NOT_SUPPORTED;
+ goto cleanupDirectory;
+ }
+ if (!ResourceCopyToFile(DllPath, WintunDllResourceName))
+ {
+ LastError = LOG(WINTUN_LOG_ERR, L"Failed to copy resource %s to %s", WintunDllResourceName, DllPath);
+ goto cleanupDelete;
+ }
+ size_t CommandLineLen = 10 + MAX_PATH + 2 + wcslen(Arguments) + 1 + wcslen(Function) + 1;
+ LPWSTR CommandLine = AllocArray(CommandLineLen, sizeof(*CommandLine));
+ if (!CommandLine)
+ {
+ LastError = GetLastError();
+ goto cleanupDelete;
+ }
+ if (_snwprintf_s(
+ CommandLine,
+ CommandLineLen,
+ _TRUNCATE,
+ L"rundll32 \"%.*s\",%s %s",
+ MAX_PATH,
+ DllPath,
+ Function,
+ Arguments) == -1)
+ {
+ LOG(WINTUN_LOG_ERR, L"Command line too long");
+ LastError = ERROR_INVALID_PARAMETER;
+ goto cleanupDelete;
+ }
+ HANDLE StreamRStdout = INVALID_HANDLE_VALUE, StreamRStderr = INVALID_HANDLE_VALUE,
+ StreamWStdout = INVALID_HANDLE_VALUE, StreamWStderr = INVALID_HANDLE_VALUE;
+ if (!CreatePipe(&StreamRStdout, &StreamWStdout, &SecurityAttributes, 0) ||
+ !CreatePipe(&StreamRStderr, &StreamWStderr, &SecurityAttributes, 0))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create pipes");
+ goto cleanupPipes;
+ }
+ if (!SetHandleInformation(StreamWStdout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
+ !SetHandleInformation(StreamWStderr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to set handle info");
+ goto cleanupPipes;
+ }
+ if (ResponseCapacity)
+ Response[0] = 0;
+ PROCESS_STDOUT_STATE ProcessStdoutState = { .Stdout = StreamRStdout,
+ .Response = Response,
+ .ResponseCapacity = ResponseCapacity };
+ HANDLE ThreadStdout = NULL, ThreadStderr = NULL;
+ if ((ThreadStdout = CreateThread(NULL, 0, ProcessStdout, &ProcessStdoutState, 0, NULL)) == NULL ||
+ (ThreadStderr = CreateThread(NULL, 0, ProcessStderr, StreamRStderr, 0, NULL)) == NULL)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to spawn readers");
+ goto cleanupThreads;
+ }
+ STARTUPINFOW si = { .cb = sizeof(STARTUPINFO),
+ .dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES,
+ .wShowWindow = SW_HIDE,
+ .hStdOutput = StreamWStdout,
+ .hStdError = StreamWStderr };
+ PROCESS_INFORMATION pi;
+ if (!CreateProcessW(RunDll32Path, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create process: %s", CommandLine);
+ goto cleanupThreads;
+ }
+ LastError = ERROR_SUCCESS;
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+cleanupThreads:
+ if (ThreadStderr)
+ {
+ CloseHandle(StreamWStderr);
+ StreamWStderr = INVALID_HANDLE_VALUE;
+ WaitForSingleObject(ThreadStderr, INFINITE);
+ CloseHandle(ThreadStderr);
+ }
+ if (ThreadStdout)
+ {
+ CloseHandle(StreamWStdout);
+ StreamWStdout = INVALID_HANDLE_VALUE;
+ WaitForSingleObject(ThreadStdout, INFINITE);
+ DWORD ThreadResult;
+ if (!GetExitCodeThread(ThreadStdout, &ThreadResult))
+ LastError = LOG_LAST_ERROR(L"Failed to retrieve stdout reader result");
+ else if (ThreadResult != ERROR_SUCCESS)
+ LastError = LOG_ERROR(ThreadResult, L"Failed to read process output");
+ CloseHandle(ThreadStdout);
+ }
+cleanupPipes:
+ CloseHandle(StreamRStderr);
+ CloseHandle(StreamWStderr);
+ CloseHandle(StreamRStdout);
+ CloseHandle(StreamWStdout);
+ Free(CommandLine);
+cleanupDelete:
+ DeleteFileW(DllPath);
+cleanupDirectory:
+ RemoveDirectoryW(RandomTempSubDirectory);
+ return RET_ERROR(TRUE, LastError);
+}
+
+static _Return_type_success_(return != FALSE)
+BOOL
+InvokeClassInstaller(_In_ LPCWSTR Action, _In_ LPCWSTR Function, _In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData)
+{
+ LOG(WINTUN_LOG_INFO, L"Spawning native process to %s instance", Action);
+
+ WCHAR InstanceId[MAX_DEVICE_ID_LEN];
+ DWORD RequiredChars = _countof(InstanceId);
+ if (!SetupDiGetDeviceInstanceIdW(DevInfo, DevInfoData, InstanceId, RequiredChars, &RequiredChars))
+ {
+ LOG_LAST_ERROR(L"Failed to get adapter instance ID");
+ return FALSE;
+ }
+ LPWSTR Arguments = ArgvToCommandLineW(1, InstanceId);
+ if (!Arguments)
+ {
+ SetLastError(LOG_ERROR(ERROR_INVALID_PARAMETER, L"Command line too long"));
+ return FALSE;
+ }
+ DWORD LastError;
+ WCHAR Response[8 + 1];
+ if (!ExecuteRunDll32(Function, Arguments, Response, _countof(Response)))
+ {
+ LastError = LOG_LAST_ERROR(L"Error executing worker process: %s", Arguments);
+ goto cleanupArguments;
+ }
+ int Argc;
+ LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
+ if (Argc < 1)
+ {
+ LastError = LOG_ERROR(ERROR_INVALID_PARAMETER, L"Incomplete response: %s", Response);
+ goto cleanupArgv;
+ }
+ LastError = wcstoul(Argv[0], NULL, 16);
+cleanupArgv:
+ LocalFree(Argv);
+cleanupArguments:
+ Free(Arguments);
+ return RET_ERROR(TRUE, LastError);
+}
+
+_Use_decl_annotations_
+BOOL
+RemoveInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData)
+{
+ return InvokeClassInstaller(L"remove", L"RemoveInstance", DevInfo, DevInfoData);
+}
+
+_Use_decl_annotations_
+BOOL
+EnableInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData)
+{
+ return InvokeClassInstaller(L"enable", L"EnableInstance", DevInfo, DevInfoData);
+}
+
+_Use_decl_annotations_
+BOOL
+DisableInstanceViaRundll32(HDEVINFO DevInfo, SP_DEVINFO_DATA *DevInfoData)
+{
+ return InvokeClassInstaller(L"disable", L"DisableInstance", DevInfo, DevInfoData);
+}
+
+_Use_decl_annotations_
+BOOL
+CreateInstanceWin7ViaRundll32(LPWSTR InstanceId)
+{
+ LOG(WINTUN_LOG_INFO, L"Spawning native process to create instance");
+
+ DWORD LastError;
+ WCHAR Response[MAX_DEVICE_ID_LEN + 1];
+ if (!ExecuteRunDll32(L"CreateInstanceWin7", L"", Response, _countof(Response)))
+ {
+ LastError = LOG_LAST_ERROR(L"Error executing worker process");
+ goto cleanup;
+ }
+ int Argc;
+ LPWSTR *Argv = CommandLineToArgvW(Response, &Argc);
+ if (Argc < 2)
+ {
+ LastError = LOG_ERROR(ERROR_INVALID_PARAMETER, L"Incomplete response: %s", Response);
+ goto cleanupArgv;
+ }
+ LastError = wcstoul(Argv[0], NULL, 16);
+ if (LastError == ERROR_SUCCESS)
+ wcsncpy_s(InstanceId, MAX_DEVICE_ID_LEN, Argv[1], _TRUNCATE);
+cleanupArgv:
+ LocalFree(Argv);
+cleanup:
+ return RET_ERROR(TRUE, LastError);
+}
+#endif
diff --git a/api/rundll32.h b/api/rundll32.h
new file mode 100644
index 0000000..762bfcf
--- /dev/null
+++ b/api/rundll32.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+#include <Windows.h>
+#include <SetupAPI.h>
+#include "adapter.h"
+
+_Return_type_success_(return != FALSE)
+BOOL
+RemoveInstanceViaRundll32(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
+
+_Return_type_success_(return != FALSE)
+BOOL
+EnableInstanceViaRundll32(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
+
+_Return_type_success_(return != FALSE)
+BOOL
+DisableInstanceViaRundll32(_In_ HDEVINFO DevInfo, _In_ SP_DEVINFO_DATA *DevInfoData);
+
+_Return_type_success_(return != FALSE)
+BOOL
+CreateInstanceWin7ViaRundll32(_Out_writes_z_(MAX_DEVICE_ID_LEN) LPWSTR InstanceId); \ No newline at end of file
diff --git a/api/session.c b/api/session.c
new file mode 100644
index 0000000..ab96c64
--- /dev/null
+++ b/api/session.c
@@ -0,0 +1,309 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include "adapter.h"
+#include "logger.h"
+#include "main.h"
+#include "wintun.h"
+#include <Windows.h>
+#include <devioctl.h>
+#include <stdlib.h>
+
+#pragma warning(disable : 4200) /* nonstandard: zero-sized array in struct/union */
+
+#define TUN_ALIGNMENT sizeof(ULONG)
+#define TUN_ALIGN(Size) (((ULONG)(Size) + ((ULONG)TUN_ALIGNMENT - 1)) & ~((ULONG)TUN_ALIGNMENT - 1))
+#define TUN_IS_ALIGNED(Size) (!((ULONG)(Size) & ((ULONG)TUN_ALIGNMENT - 1)))
+#define TUN_MAX_PACKET_SIZE TUN_ALIGN(sizeof(TUN_PACKET) + WINTUN_MAX_IP_PACKET_SIZE)
+#define TUN_RING_CAPACITY(Size) ((Size) - sizeof(TUN_RING) - (TUN_MAX_PACKET_SIZE - TUN_ALIGNMENT))
+#define TUN_RING_SIZE(Capacity) (sizeof(TUN_RING) + (Capacity) + (TUN_MAX_PACKET_SIZE - TUN_ALIGNMENT))
+#define TUN_RING_WRAP(Value, Capacity) ((Value) & (Capacity - 1))
+#define LOCK_SPIN_COUNT 0x10000
+#define TUN_PACKET_RELEASE ((DWORD)0x80000000)
+
+typedef struct _TUN_PACKET
+{
+ ULONG Size;
+ UCHAR Data[];
+} TUN_PACKET;
+
+typedef struct _TUN_RING
+{
+ volatile ULONG Head;
+ volatile ULONG Tail;
+ volatile LONG Alertable;
+ UCHAR Data[];
+} TUN_RING;
+
+#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
+
+typedef struct _TUN_REGISTER_RINGS
+{
+ struct
+ {
+ ULONG RingSize;
+ TUN_RING *Ring;
+ HANDLE TailMoved;
+ } Send, Receive;
+} TUN_REGISTER_RINGS;
+
+typedef struct _TUN_SESSION
+{
+ ULONG Capacity;
+ struct
+ {
+ ULONG Tail;
+ ULONG TailRelease;
+ ULONG PacketsToRelease;
+ CRITICAL_SECTION Lock;
+ } Receive;
+ struct
+ {
+ ULONG Head;
+ ULONG HeadRelease;
+ ULONG PacketsToRelease;
+ CRITICAL_SECTION Lock;
+ } Send;
+ TUN_REGISTER_RINGS Descriptor;
+ HANDLE Handle;
+} TUN_SESSION;
+
+WINTUN_START_SESSION_FUNC WintunStartSession;
+_Use_decl_annotations_
+TUN_SESSION *WINAPI
+WintunStartSession(WINTUN_ADAPTER *Adapter, DWORD Capacity)
+{
+ DWORD LastError;
+ TUN_SESSION *Session = Zalloc(sizeof(TUN_SESSION));
+ if (!Session)
+ {
+ LastError = GetLastError();
+ goto cleanup;
+ }
+ const ULONG RingSize = TUN_RING_SIZE(Capacity);
+ BYTE *AllocatedRegion = VirtualAlloc(0, (size_t)RingSize * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ if (!AllocatedRegion)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to allocate ring memory (requested size: 0x%zx)", (size_t)RingSize * 2);
+ goto cleanupRings;
+ }
+ Session->Descriptor.Send.RingSize = RingSize;
+ Session->Descriptor.Send.Ring = (TUN_RING *)AllocatedRegion;
+ Session->Descriptor.Send.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
+ if (!Session->Descriptor.Send.TailMoved)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create send event");
+ goto cleanupAllocatedRegion;
+ }
+
+ Session->Descriptor.Receive.RingSize = RingSize;
+ Session->Descriptor.Receive.Ring = (TUN_RING *)(AllocatedRegion + RingSize);
+ Session->Descriptor.Receive.TailMoved = CreateEventW(&SecurityAttributes, FALSE, FALSE, NULL);
+ if (!Session->Descriptor.Receive.TailMoved)
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to create receive event");
+ goto cleanupSendTailMoved;
+ }
+
+ Session->Handle = AdapterOpenDeviceObject(Adapter);
+ if (Session->Handle == INVALID_HANDLE_VALUE)
+ {
+ LastError = LOG(WINTUN_LOG_ERR, L"Failed to open adapter device object");
+ goto cleanupReceiveTailMoved;
+ }
+ DWORD BytesReturned;
+ if (!DeviceIoControl(
+ Session->Handle,
+ TUN_IOCTL_REGISTER_RINGS,
+ &Session->Descriptor,
+ sizeof(TUN_REGISTER_RINGS),
+ NULL,
+ 0,
+ &BytesReturned,
+ NULL))
+ {
+ LastError = LOG_LAST_ERROR(L"Failed to register rings");
+ goto cleanupHandle;
+ }
+ Session->Capacity = Capacity;
+ (VOID) InitializeCriticalSectionAndSpinCount(&Session->Receive.Lock, LOCK_SPIN_COUNT);
+ (VOID) InitializeCriticalSectionAndSpinCount(&Session->Send.Lock, LOCK_SPIN_COUNT);
+ return Session;
+cleanupHandle:
+ CloseHandle(Session->Handle);
+cleanupReceiveTailMoved:
+ CloseHandle(Session->Descriptor.Receive.TailMoved);
+cleanupSendTailMoved:
+ CloseHandle(Session->Descriptor.Send.TailMoved);
+cleanupAllocatedRegion:
+ VirtualFree(AllocatedRegion, 0, MEM_RELEASE);
+cleanupRings:
+ Free(Session);
+cleanup:
+ SetLastError(LastError);
+ return NULL;
+}
+
+WINTUN_END_SESSION_FUNC WintunEndSession;
+_Use_decl_annotations_
+VOID WINAPI
+WintunEndSession(TUN_SESSION *Session)
+{
+ DeleteCriticalSection(&Session->Send.Lock);
+ DeleteCriticalSection(&Session->Receive.Lock);
+ CloseHandle(Session->Handle);
+ CloseHandle(Session->Descriptor.Send.TailMoved);
+ CloseHandle(Session->Descriptor.Receive.TailMoved);
+ VirtualFree(Session->Descriptor.Send.Ring, 0, MEM_RELEASE);
+ Free(Session);
+}
+
+WINTUN_GET_READ_WAIT_EVENT_FUNC WintunGetReadWaitEvent;
+_Use_decl_annotations_
+HANDLE WINAPI
+WintunGetReadWaitEvent(TUN_SESSION *Session)
+{
+ return Session->Descriptor.Send.TailMoved;
+}
+
+WINTUN_RECEIVE_PACKET_FUNC WintunReceivePacket;
+_Use_decl_annotations_
+BYTE *WINAPI
+WintunReceivePacket(TUN_SESSION *Session, DWORD *PacketSize)
+{
+ DWORD LastError;
+ EnterCriticalSection(&Session->Send.Lock);
+ if (Session->Send.Head >= Session->Capacity)
+ {
+ LastError = ERROR_HANDLE_EOF;
+ goto cleanup;
+ }
+ const ULONG BuffTail = ReadULongAcquire(&Session->Descriptor.Send.Ring->Tail);
+ if (BuffTail >= Session->Capacity)
+ {
+ LastError = ERROR_HANDLE_EOF;
+ goto cleanup;
+ }
+ if (Session->Send.Head == BuffTail)
+ {
+ LastError = ERROR_NO_MORE_ITEMS;
+ goto cleanup;
+ }
+ const ULONG BuffContent = TUN_RING_WRAP(BuffTail - Session->Send.Head, Session->Capacity);
+ if (BuffContent < sizeof(TUN_PACKET))
+ {
+ LastError = ERROR_INVALID_DATA;
+ goto cleanup;
+ }
+ TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Send.Ring->Data[Session->Send.Head];
+ if (BuffPacket->Size > WINTUN_MAX_IP_PACKET_SIZE)
+ {
+ LastError = ERROR_INVALID_DATA;
+ goto cleanup;
+ }
+ const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + BuffPacket->Size);
+ if (AlignedPacketSize > BuffContent)
+ {
+ LastError = ERROR_INVALID_DATA;
+ goto cleanup;
+ }
+ *PacketSize = BuffPacket->Size;
+ BYTE *Packet = BuffPacket->Data;
+ Session->Send.Head = TUN_RING_WRAP(Session->Send.Head + AlignedPacketSize, Session->Capacity);
+ Session->Send.PacketsToRelease++;
+ LeaveCriticalSection(&Session->Send.Lock);
+ return Packet;
+cleanup:
+ LeaveCriticalSection(&Session->Send.Lock);
+ SetLastError(LastError);
+ return NULL;
+}
+
+WINTUN_RELEASE_RECEIVE_PACKET_FUNC WintunReleaseReceivePacket;
+_Use_decl_annotations_
+VOID WINAPI
+WintunReleaseReceivePacket(TUN_SESSION *Session, const BYTE *Packet)
+{
+ EnterCriticalSection(&Session->Send.Lock);
+ TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data));
+ ReleasedBuffPacket->Size |= TUN_PACKET_RELEASE;
+ while (Session->Send.PacketsToRelease)
+ {
+ const TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Send.Ring->Data[Session->Send.HeadRelease];
+ if ((BuffPacket->Size & TUN_PACKET_RELEASE) == 0)
+ break;
+ const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + (BuffPacket->Size & ~TUN_PACKET_RELEASE));
+ Session->Send.HeadRelease = TUN_RING_WRAP(Session->Send.HeadRelease + AlignedPacketSize, Session->Capacity);
+ Session->Send.PacketsToRelease--;
+ }
+ WriteULongRelease(&Session->Descriptor.Send.Ring->Head, Session->Send.HeadRelease);
+ LeaveCriticalSection(&Session->Send.Lock);
+}
+
+WINTUN_ALLOCATE_SEND_PACKET_FUNC WintunAllocateSendPacket;
+_Use_decl_annotations_
+BYTE *WINAPI
+WintunAllocateSendPacket(TUN_SESSION *Session, DWORD PacketSize)
+{
+ DWORD LastError;
+ EnterCriticalSection(&Session->Receive.Lock);
+ if (Session->Receive.Tail >= Session->Capacity)
+ {
+ LastError = ERROR_HANDLE_EOF;
+ goto cleanup;
+ }
+ const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize);
+ const ULONG BuffHead = ReadULongAcquire(&Session->Descriptor.Receive.Ring->Head);
+ if (BuffHead >= Session->Capacity)
+ {
+ LastError = ERROR_HANDLE_EOF;
+ goto cleanup;
+ }
+ const ULONG BuffSpace = TUN_RING_WRAP(BuffHead - Session->Receive.Tail - TUN_ALIGNMENT, Session->Capacity);
+ if (AlignedPacketSize > BuffSpace)
+ {
+ LastError = ERROR_BUFFER_OVERFLOW;
+ goto cleanup;
+ }
+ TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Receive.Ring->Data[Session->Receive.Tail];
+ BuffPacket->Size = PacketSize | TUN_PACKET_RELEASE;
+ BYTE *Packet = BuffPacket->Data;
+ Session->Receive.Tail = TUN_RING_WRAP(Session->Receive.Tail + AlignedPacketSize, Session->Capacity);
+ Session->Receive.PacketsToRelease++;
+ LeaveCriticalSection(&Session->Receive.Lock);
+ return Packet;
+cleanup:
+ LeaveCriticalSection(&Session->Receive.Lock);
+ SetLastError(LastError);
+ return NULL;
+}
+
+WINTUN_SEND_PACKET_FUNC WintunSendPacket;
+_Use_decl_annotations_
+VOID WINAPI
+WintunSendPacket(TUN_SESSION *Session, const BYTE *Packet)
+{
+ EnterCriticalSection(&Session->Receive.Lock);
+ TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data));
+ ReleasedBuffPacket->Size &= ~TUN_PACKET_RELEASE;
+ while (Session->Receive.PacketsToRelease)
+ {
+ const TUN_PACKET *BuffPacket =
+ (TUN_PACKET *)&Session->Descriptor.Receive.Ring->Data[Session->Receive.TailRelease];
+ if (BuffPacket->Size & TUN_PACKET_RELEASE)
+ break;
+ const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + BuffPacket->Size);
+ Session->Receive.TailRelease =
+ TUN_RING_WRAP(Session->Receive.TailRelease + AlignedPacketSize, Session->Capacity);
+ Session->Receive.PacketsToRelease--;
+ }
+ if (Session->Descriptor.Receive.Ring->Tail != Session->Receive.TailRelease)
+ {
+ WriteULongRelease(&Session->Descriptor.Receive.Ring->Tail, Session->Receive.TailRelease);
+ if (ReadAcquire(&Session->Descriptor.Receive.Ring->Alertable))
+ SetEvent(Session->Descriptor.Receive.TailMoved);
+ }
+ LeaveCriticalSection(&Session->Receive.Lock);
+}
diff --git a/api/wintun.h b/api/wintun.h
new file mode 100644
index 0000000..bcf5ccc
--- /dev/null
+++ b/api/wintun.h
@@ -0,0 +1,274 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#pragma once
+
+#include <winsock2.h>
+#include <windows.h>
+#include <ipexport.h>
+#include <ifdef.h>
+#include <ws2ipdef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef ALIGNED
+# if defined(_MSC_VER)
+# define ALIGNED(n) __declspec(align(n))
+# elif defined(__GNUC__)
+# define ALIGNED(n) __attribute__((aligned(n)))
+# else
+# error "Unable to define ALIGNED"
+# endif
+#endif
+
+/* MinGW is missing this one, unfortunately. */
+#ifndef _Post_maybenull_
+# define _Post_maybenull_
+#endif
+
+#if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable : 4324) /* structure was padded due to alignment specifier */
+#endif
+
+/**
+ * A handle representing Wintun adapter
+ */
+typedef struct _WINTUN_ADAPTER *WINTUN_ADAPTER_HANDLE;
+
+/**
+ * Creates a new Wintun adapter.
+ *
+ * @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
+ * characters.
+ *
+ * @param TunnelType Name of the adapter tunnel type. Zero-terminated string of up to MAX_ADAPTER_NAME-1
+ * characters.
+ *
+ * @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation deterministically.
+ * If it is set to NULL, the GUID is chosen by the system at random, and hence a new NLA entry is
+ * created for each new adapter. It is called "requested" GUID because the API it uses is
+ * completely undocumented, and so there could be minor interesting complications with its usage.
+ *
+ * @return If the function succeeds, the return value is the adapter handle. Must be released with
+ * WintunCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call
+ * GetLastError.
+ */
+typedef _Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_CREATE_ADAPTER_FUNC)
+(_In_z_ LPCWSTR Name, _In_z_ LPCWSTR TunnelType, _In_opt_ const GUID *RequestedGUID);
+
+/**
+ * Opens an existing Wintun adapter.
+ *
+ * @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
+ * characters.
+ *
+ * @return If the function succeeds, the return value is the adapter handle. Must be released with
+ * WintunCloseAdapter. If the function fails, the return value is NULL. To get extended error information, call
+ * GetLastError.
+ */
+typedef _Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+WINTUN_ADAPTER_HANDLE(WINAPI WINTUN_OPEN_ADAPTER_FUNC)(_In_z_ LPCWSTR Name);
+
+/**
+ * Releases Wintun adapter resources and, if adapter was created with WintunCreateAdapter, removes adapter.
+ *
+ * @param Adapter Adapter handle obtained with WintunCreateAdapter or WintunOpenAdapter.
+ */
+typedef VOID(WINAPI WINTUN_CLOSE_ADAPTER_FUNC)(_In_opt_ WINTUN_ADAPTER_HANDLE Adapter);
+
+/**
+ * Deletes the Wintun driver if there are no more adapters in use.
+ *
+ * @return If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To
+ * get extended error information, call GetLastError.
+ */
+typedef _Return_type_success_(return != FALSE)
+BOOL(WINAPI WINTUN_DELETE_DRIVER_FUNC)(VOID);
+
+/**
+ * Returns the LUID of the adapter.
+ *
+ * @param Adapter Adapter handle obtained with WintunCreateAdapter or WintunOpenAdapter
+ *
+ * @param Luid Pointer to LUID to receive adapter LUID.
+ */
+typedef VOID(WINAPI WINTUN_GET_ADAPTER_LUID_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _Out_ NET_LUID *Luid);
+
+/**
+ * Determines the version of the Wintun driver currently loaded.
+ *
+ * @return If the function succeeds, the return value is the version number. If the function fails, the return value is
+ * zero. To get extended error information, call GetLastError. Possible errors include the following:
+ * ERROR_FILE_NOT_FOUND Wintun not loaded
+ */
+typedef _Return_type_success_(return != 0)
+DWORD(WINAPI WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC)(VOID);
+
+/**
+ * Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK.
+ */
+typedef enum
+{
+ WINTUN_LOG_INFO, /**< Informational */
+ WINTUN_LOG_WARN, /**< Warning */
+ WINTUN_LOG_ERR /**< Error */
+} WINTUN_LOGGER_LEVEL;
+
+/**
+ * Called by internal logger to report diagnostic messages
+ *
+ * @param Level Message level.
+ *
+ * @param Timestamp Message timestamp in in 100ns intervals since 1601-01-01 UTC.
+ *
+ * @param Message Message text.
+ */
+typedef VOID(CALLBACK *WINTUN_LOGGER_CALLBACK)(
+ _In_ WINTUN_LOGGER_LEVEL Level,
+ _In_ DWORD64 Timestamp,
+ _In_z_ LPCWSTR Message);
+
+/**
+ * Sets logger callback function.
+ *
+ * @param NewLogger Pointer to callback function to use as a new global logger. NewLogger may be called from various
+ * threads concurrently. Should the logging require serialization, you must handle serialization in
+ * NewLogger. Set to NULL to disable.
+ */
+typedef VOID(WINAPI WINTUN_SET_LOGGER_FUNC)(_In_ WINTUN_LOGGER_CALLBACK NewLogger);
+
+/**
+ * Minimum ring capacity.
+ */
+#define WINTUN_MIN_RING_CAPACITY 0x20000 /* 128kiB */
+
+/**
+ * Maximum ring capacity.
+ */
+#define WINTUN_MAX_RING_CAPACITY 0x4000000 /* 64MiB */
+
+/**
+ * A handle representing Wintun session
+ */
+typedef struct _TUN_SESSION *WINTUN_SESSION_HANDLE;
+
+/**
+ * Starts Wintun session.
+ *
+ * @param Adapter Adapter handle obtained with WintunOpenAdapter or WintunCreateAdapter
+ *
+ * @param Capacity Rings capacity. Must be between WINTUN_MIN_RING_CAPACITY and WINTUN_MAX_RING_CAPACITY (incl.)
+ * Must be a power of two.
+ *
+ * @return Wintun session handle. Must be released with WintunEndSession. If the function fails, the return value is
+ * NULL. To get extended error information, call GetLastError.
+ */
+typedef _Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+WINTUN_SESSION_HANDLE(WINAPI WINTUN_START_SESSION_FUNC)(_In_ WINTUN_ADAPTER_HANDLE Adapter, _In_ DWORD Capacity);
+
+/**
+ * Ends Wintun session.
+ *
+ * @param Session Wintun session handle obtained with WintunStartSession
+ */
+typedef VOID(WINAPI WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session);
+
+/**
+ * Gets Wintun session's read-wait event handle.
+ *
+ * @param Session Wintun session handle obtained with WintunStartSession
+ *
+ * @return Pointer to receive event handle to wait for available data when reading. Should
+ * WintunReceivePackets return ERROR_NO_MORE_ITEMS (after spinning on it for a while under heavy
+ * load), wait for this event to become signaled before retrying WintunReceivePackets. Do not call
+ * CloseHandle on this event - it is managed by the session.
+ */
+typedef HANDLE(WINAPI WINTUN_GET_READ_WAIT_EVENT_FUNC)(_In_ WINTUN_SESSION_HANDLE Session);
+
+/**
+ * Maximum IP packet size
+ */
+#define WINTUN_MAX_IP_PACKET_SIZE 0xFFFF
+
+/**
+ * Retrieves one or packet. After the packet content is consumed, call WintunReleaseReceivePacket with Packet returned
+ * from this function to release internal buffer. This function is thread-safe.
+ *
+ * @param Session Wintun session handle obtained with WintunStartSession
+ *
+ * @param PacketSize Pointer to receive packet size.
+ *
+ * @return Pointer to layer 3 IPv4 or IPv6 packet. Client may modify its content at will. If the function fails, the
+ * return value is NULL. To get extended error information, call GetLastError. Possible errors include the
+ * following:
+ * ERROR_HANDLE_EOF Wintun adapter is terminating;
+ * ERROR_NO_MORE_ITEMS Wintun buffer is exhausted;
+ * ERROR_INVALID_DATA Wintun buffer is corrupt
+ */
+typedef _Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+_Post_writable_byte_size_(*PacketSize)
+BYTE *(WINAPI WINTUN_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _Out_ DWORD *PacketSize);
+
+/**
+ * Releases internal buffer after the received packet has been processed by the client. This function is thread-safe.
+ *
+ * @param Session Wintun session handle obtained with WintunStartSession
+ *
+ * @param Packet Packet obtained with WintunReceivePacket
+ */
+typedef VOID(
+ WINAPI WINTUN_RELEASE_RECEIVE_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
+
+/**
+ * Allocates memory for a packet to send. After the memory is filled with packet data, call WintunSendPacket to send
+ * and release internal buffer. WintunAllocateSendPacket is thread-safe and the WintunAllocateSendPacket order of
+ * calls define the packet sending order.
+ *
+ * @param Session Wintun session handle obtained with WintunStartSession
+ *
+ * @param PacketSize Exact packet size. Must be less or equal to WINTUN_MAX_IP_PACKET_SIZE.
+ *
+ * @return Returns pointer to memory where to prepare layer 3 IPv4 or IPv6 packet for sending. If the function fails,
+ * the return value is NULL. To get extended error information, call GetLastError. Possible errors include the
+ * following:
+ * ERROR_HANDLE_EOF Wintun adapter is terminating;
+ * ERROR_BUFFER_OVERFLOW Wintun buffer is full;
+ */
+typedef _Must_inspect_result_
+_Return_type_success_(return != NULL)
+_Post_maybenull_
+_Post_writable_byte_size_(PacketSize)
+BYTE *(WINAPI WINTUN_ALLOCATE_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD PacketSize);
+
+/**
+ * Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket
+ * order of calls define the packet sending order. This means the packet is not guaranteed to be sent in the
+ * WintunSendPacket yet.
+ *
+ * @param Session Wintun session handle obtained with WintunStartSession
+ *
+ * @param Packet Packet obtained with WintunAllocateSendPacket
+ */
+typedef VOID(WINAPI WINTUN_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const BYTE *Packet);
+
+#if defined(_MSC_VER)
+# pragma warning(pop)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/atomic.h b/atomic.h
deleted file mode 100644
index 01dd35e..0000000
--- a/atomic.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
- */
-
-#pragma once
-
-#include <wdm.h>
-
-static __forceinline VOID
-InterlockedSet(_Inout_ _Interlocked_operand_ LONG volatile *Target, _In_ LONG Value)
-{
- *Target = Value;
-}
-
-static __forceinline VOID
-InterlockedSetU(_Inout_ _Interlocked_operand_ ULONG volatile *Target, _In_ ULONG Value)
-{
- *Target = Value;
-}
-
-static __forceinline VOID
-InterlockedSetPointer(_Inout_ _Interlocked_operand_ VOID *volatile *Target, _In_opt_ VOID *Value)
-{
- *Target = Value;
-}
-
-static __forceinline LONG
-InterlockedGet(_In_ _Interlocked_operand_ LONG volatile *Value)
-{
- return *Value;
-}
-
-static __forceinline ULONG
-InterlockedGetU(_In_ _Interlocked_operand_ ULONG volatile *Value)
-{
- return *Value;
-}
-
-static __forceinline PVOID
-InterlockedGetPointer(_In_ _Interlocked_operand_ PVOID volatile *Value)
-{
- return *Value;
-}
-
-static __forceinline LONG64
-InterlockedGet64(_In_ _Interlocked_operand_ LONG64 volatile *Value)
-{
-#ifdef _WIN64
- return *Value;
-#else
- return InterlockedCompareExchange64(Value, 0, 0);
-#endif
-} \ No newline at end of file
diff --git a/driver/driver.vcxproj b/driver/driver.vcxproj
new file mode 100644
index 0000000..63795e5
--- /dev/null
+++ b/driver/driver.vcxproj
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{F7679B65-2FEC-469A-8BAC-B07BF4439422}</ProjectGuid>
+ <RootNamespace>driver</RootNamespace>
+ <ProjectName>driver</ProjectName>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>WDM</DriverType>
+ </PropertyGroup>
+ <Import Project="..\wintun.props" />
+ <PropertyGroup>
+ <TargetName>wintun</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <PreprocessorDefinitions>NDIS_MINIPORT_DRIVER=1;NDIS620_MINIPORT=1;NDIS683_MINIPORT=1;NDIS_WDM=1;POOL_ZERO_DOWN_LEVEL_SUPPORT;POOL_NX_OPTIN=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalOptions>/volatile:iso %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>ndis.lib;wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
+ <Inf>
+ <TimeStamp>$(WintunVersion)</TimeStamp>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
+ <Inf>
+ <TimeStamp>*</TimeStamp>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="wintun.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="wintun.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="wintun.inf" />
+ <FilesToPackage Include="$(TargetPath)" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="undocumented.h" />
+ </ItemGroup>
+ <Import Project="..\wintun.props.user" Condition="exists('..\wintun.props.user')" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets" />
+</Project>
diff --git a/wintun.vcxproj.filters b/driver/driver.vcxproj.filters
index 467cc48..3e19120 100644
--- a/wintun.vcxproj.filters
+++ b/driver/driver.vcxproj.filters
@@ -33,8 +33,5 @@
<ClInclude Include="undocumented.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="atomic.h">
- <Filter>Header Files</Filter>
- </ClInclude>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/undocumented.h b/driver/undocumented.h
index cf85823..c642361 100644
--- a/undocumented.h
+++ b/driver/undocumented.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
- * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#pragma once
@@ -31,11 +31,23 @@ typedef struct _SYSTEM_HANDLE_INFORMATION_EX
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[ANYSIZE_ARRAY];
} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
-extern NTSTATUS
+NTSYSAPI
+NTSTATUS
+NTAPI
ZwQuerySystemInformation(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
ULONG *ReturnLength);
-extern NTSTATUS ZwYieldExecution(VOID);
+NTSYSAPI
+NTSTATUS
+NTAPI
+ZwYieldExecution(VOID);
+
+NTSTATUS
+NTAPI
+SeSddlSecurityDescriptorFromSDDL(
+ const PUNICODE_STRING SecurityDescriptorString,
+ BOOLEAN SuppliedByDefaultMechanism,
+ PSECURITY_DESCRIPTOR *SecurityDescriptor);
diff --git a/wintun.c b/driver/wintun.c
index 624de2f..ad4b16b 100644
--- a/wintun.c
+++ b/driver/wintun.c
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0
*
- * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#include <ntifs.h>
@@ -9,7 +9,6 @@
#include <ndis.h>
#include <ntstrsafe.h>
#include "undocumented.h"
-#include "atomic.h"
#pragma warning(disable : 4100) /* unreferenced formal parameter */
#pragma warning(disable : 4200) /* nonstandard: zero-sized array in struct/union */
@@ -50,7 +49,7 @@
((((ULONG)(x)&0x000000ff) << 24) | (((ULONG)(x)&0x0000ff00) << 8) | (((ULONG)(x)&0x00ff0000) >> 8) | \
(((ULONG)(x)&0xff000000) >> 24))
#else
-# error "Unable to determine endianess"
+# error "Unable to determine endianness"
#endif
#define TUN_MEMORY_TAG HTONL('wtun')
@@ -100,12 +99,29 @@ typedef struct _TUN_REGISTER_RINGS
} Send, Receive;
} TUN_REGISTER_RINGS;
+#ifdef _WIN64
+typedef struct _TUN_REGISTER_RINGS_32
+{
+ struct
+ {
+ /* Size of the ring */
+ ULONG RingSize;
+
+ /* 32-bit address of client allocated ring */
+ ULONG Ring;
+
+ /* On send: An event created by the client the Wintun signals after it moves the Tail member of the send ring.
+ * On receive: An event created by the client the client will signal when it moves the Tail member of
+ * the receive ring if receive ring is alertable. */
+ ULONG TailMoved;
+ } Send, Receive;
+} TUN_REGISTER_RINGS_32;
+#endif
+
/* Register rings hosted by the client.
* The lpInBuffer and nInBufferSize parameters of DeviceIoControl() must point to an TUN_REGISTER_RINGS struct.
* Client must wait for this IOCTL to finish before adding packets to the ring. */
#define TUN_IOCTL_REGISTER_RINGS CTL_CODE(51820U, 0x970U, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
-/* Force close all open handles to allow for updating. */
-#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
typedef struct _TUN_CTX
{
@@ -163,10 +179,18 @@ typedef struct _TUN_CTX
static UINT NdisVersion;
static NDIS_HANDLE NdisMiniportDriverHandle;
-static DRIVER_DISPATCH *NdisDispatchDeviceControl, *NdisDispatchClose;
+static DRIVER_DISPATCH *NdisDispatchDeviceControl, *NdisDispatchClose, *NdisDispatchPnp;
static ERESOURCE TunDispatchCtxGuard, TunDispatchDeviceListLock;
static RTL_STATIC_LIST_HEAD(TunDispatchDeviceList);
-static SECURITY_DESCRIPTOR *TunDispatchSecurityDescriptor;
+/* Binary representation of O:SYD:P(A;;FA;;;SY)(A;;FA;;;BA)S:(ML;;NWNRNX;;;HI) */
+static SECURITY_DESCRIPTOR *TunDispatchSecurityDescriptor = (SECURITY_DESCRIPTOR *)(__declspec(align(8)) UCHAR[]){
+ 0x01, 0x00, 0x14, 0x90, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x1c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x14, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x00, 0x00, 0x02, 0x00, 0x34, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x14, 0x00, 0xff, 0x01, 0x1f, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x00, 0xff, 0x01, 0x1f, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00,
+ 0x00, 0x20, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00
+};
_IRQL_requires_max_(DISPATCH_LEVEL)
static VOID
@@ -250,7 +274,7 @@ TunSendNetBufferLists(
KIRQL Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock);
NDIS_STATUS Status;
- if ((Status = NDIS_STATUS_PAUSED, !InterlockedGet(&Ctx->Running)) ||
+ if ((Status = NDIS_STATUS_PAUSED, !ReadAcquire(&Ctx->Running)) ||
(Status = NDIS_STATUS_MEDIA_DISCONNECTED, KeReadStateEvent(&Ctx->Device.Disconnected)))
goto skipNbl;
@@ -258,7 +282,7 @@ TunSendNetBufferLists(
ULONG RingCapacity = Ctx->Device.Send.Capacity;
/* Allocate space for packets in the ring. */
- ULONG RingHead = InterlockedGetU(&Ring->Head);
+ ULONG RingHead = ReadULongAcquire(&Ring->Head);
if (Status = NDIS_STATUS_ADAPTER_NOT_READY, RingHead >= RingCapacity)
goto skipNbl;
@@ -325,7 +349,7 @@ TunSendNetBufferLists(
{
NET_BUFFER_LIST *CompletedNbl = Ctx->Device.Send.ActiveNbls.Head;
Ctx->Device.Send.ActiveNbls.Head = NET_BUFFER_LIST_NEXT_NBL_EX(CompletedNbl);
- InterlockedSetU(&Ring->Tail, TunNblGetOffset(CompletedNbl));
+ WriteULongRelease(&Ring->Tail, TunNblGetOffset(CompletedNbl));
KeSetEvent(Ctx->Device.Send.TailMoved, IO_NETWORK_INCREMENT, FALSE);
NdisMSendNetBufferListsComplete(
Ctx->MiniportAdapterHandle, CompletedNbl, NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL);
@@ -343,11 +367,11 @@ skipNbl:
ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql);
NdisMSendNetBufferListsComplete(Ctx->MiniportAdapterHandle, NetBufferLists, 0);
updateStatistics:
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCOutOctets, SentPacketsSize);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCOutUcastOctets, SentPacketsSize);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCOutUcastPkts, SentPacketsCount);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifOutErrors, ErrorPacketsCount);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifOutDiscards, DiscardedPacketsCount);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutOctets, SentPacketsSize);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutUcastOctets, SentPacketsSize);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutUcastPkts, SentPacketsCount);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifOutErrors, ErrorPacketsCount);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifOutDiscards, DiscardedPacketsCount);
}
static MINIPORT_CANCEL_SEND TunCancelSend;
@@ -393,15 +417,25 @@ TunReturnNetBufferLists(NDIS_HANDLE MiniportAdapterContext, PNET_BUFFER_LIST Net
if (!Ctx->Device.Receive.ActiveNbls.Head)
KeSetEvent(&Ctx->Device.Receive.ActiveNbls.Empty, IO_NO_INCREMENT, FALSE);
KeReleaseInStackQueuedSpinLock(&LockHandle);
- InterlockedSetU(&Ring->Head, TunNblGetOffset(CompletedNbl));
+ WriteULongRelease(&Ring->Head, TunNblGetOffset(CompletedNbl));
+ const MDL *TargetMdl = Ctx->Device.Receive.Mdl;
+ for (MDL *Mdl = NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(CompletedNbl)); Mdl; Mdl = Mdl->Next)
+ {
+ if (MmGetMdlVirtualAddress(Mdl) < MmGetMdlVirtualAddress(TargetMdl) ||
+ (UCHAR *)MmGetMdlVirtualAddress(Mdl) + MmGetMdlByteCount(Mdl) >
+ (UCHAR *)MmGetMdlVirtualAddress(TargetMdl) + MmGetMdlByteCount(TargetMdl))
+ continue;
+ IoFreeMdl(Mdl);
+ break;
+ }
NdisFreeNetBufferList(CompletedNbl);
}
}
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCInOctets, ReceivedPacketsSize);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCInUcastOctets, ReceivedPacketsSize);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifHCInUcastPkts, ReceivedPacketsCount);
- InterlockedAdd64((LONG64 *)&Ctx->Statistics.ifInErrors, ErrorPacketsCount);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCInOctets, ReceivedPacketsSize);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCInUcastOctets, ReceivedPacketsSize);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifHCInUcastPkts, ReceivedPacketsCount);
+ InterlockedAddNoFence64((LONG64 *)&Ctx->Statistics.ifInErrors, ErrorPacketsCount);
}
_IRQL_requires_max_(PASSIVE_LEVEL)
@@ -419,20 +453,20 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
VOID *Events[] = { &Ctx->Device.Disconnected, Ctx->Device.Receive.TailMoved };
ASSERT(RTL_NUMBER_OF(Events) <= THREAD_WAIT_OBJECTS);
- ULONG RingHead = InterlockedGetU(&Ring->Head);
+ ULONG RingHead = ReadULongAcquire(&Ring->Head);
if (RingHead >= RingCapacity)
goto cleanup;
while (!KeReadStateEvent(&Ctx->Device.Disconnected))
{
/* Get next packet from the ring. */
- ULONG RingTail = InterlockedGetU(&Ring->Tail);
+ ULONG RingTail = ReadULongAcquire(&Ring->Tail);
if (RingHead == RingTail)
{
LARGE_INTEGER SpinStart = KeQueryPerformanceCounter(NULL);
for (;;)
{
- RingTail = InterlockedGetU(&Ring->Tail);
+ RingTail = ReadULongAcquire(&Ring->Tail);
if (RingTail != RingHead)
break;
if (KeReadStateEvent(&Ctx->Device.Disconnected))
@@ -444,16 +478,16 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
}
if (RingHead == RingTail)
{
- InterlockedSet(&Ring->Alertable, TRUE);
- RingTail = InterlockedGetU(&Ring->Tail);
+ WriteRelease(&Ring->Alertable, TRUE);
+ RingTail = ReadULongAcquire(&Ring->Tail);
if (RingHead == RingTail)
{
KeWaitForMultipleObjects(
RTL_NUMBER_OF(Events), Events, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
- InterlockedSet(&Ring->Alertable, FALSE);
+ WriteRelease(&Ring->Alertable, FALSE);
continue;
}
- InterlockedSet(&Ring->Alertable, FALSE);
+ WriteRelease(&Ring->Alertable, FALSE);
KeClearEvent(Ctx->Device.Receive.TailMoved);
}
}
@@ -465,7 +499,7 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
break;
TUN_PACKET *Packet = (TUN_PACKET *)(Ring->Data + RingHead);
- ULONG PacketSize = Packet->Size;
+ ULONG PacketSize = *(volatile ULONG *)&Packet->Size;
if (PacketSize > TUN_MAX_IP_PACKET_SIZE)
break;
@@ -473,6 +507,8 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
if (AlignedPacketSize > RingContent)
break;
+ RingHead = TUN_RING_WRAP(RingHead + AlignedPacketSize, RingCapacity);
+
ULONG NblFlags;
USHORT NblProto;
if (PacketSize >= 20 && Packet->Data[0] >> 4 == 4)
@@ -486,14 +522,17 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
NblProto = HTONS(NDIS_ETH_TYPE_IPV6);
}
else
- break;
-
- RingHead = TUN_RING_WRAP(RingHead + AlignedPacketSize, RingCapacity);
+ goto skipNbl;
- NET_BUFFER_LIST *Nbl = NdisAllocateNetBufferAndNetBufferList(
- Ctx->NblPool, 0, 0, Ctx->Device.Receive.Mdl, (ULONG)(Packet->Data - (UCHAR *)Ring), PacketSize);
- if (!Nbl)
+ VOID *PacketAddr =
+ (UCHAR *)MmGetMdlVirtualAddress(Ctx->Device.Receive.Mdl) + (ULONG)(Packet->Data - (UCHAR *)Ring);
+ MDL *Mdl = IoAllocateMdl(PacketAddr, PacketSize, FALSE, FALSE, NULL);
+ if (!Mdl)
goto skipNbl;
+ IoBuildPartialMdl(Ctx->Device.Receive.Mdl, Mdl, PacketAddr, PacketSize);
+ NET_BUFFER_LIST *Nbl = NdisAllocateNetBufferAndNetBufferList(Ctx->NblPool, 0, 0, Mdl, 0, PacketSize);
+ if (!Nbl)
+ goto cleanupMdl;
Nbl->SourceHandle = Ctx->MiniportAdapterHandle;
NdisSetNblFlag(Nbl, NblFlags);
NET_BUFFER_LIST_INFO(Nbl, NetBufferListFrameType) = (PVOID)NblProto;
@@ -501,7 +540,7 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
TunNblSetOffsetAndMarkActive(Nbl, RingHead);
KIRQL Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock);
- if (!InterlockedGet(&Ctx->Running))
+ if (!ReadAcquire(&Ctx->Running))
goto cleanupNbl;
KLOCK_QUEUE_HANDLE LockHandle;
@@ -529,17 +568,19 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
cleanupNbl:
ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql);
NdisFreeNetBufferList(Nbl);
+ cleanupMdl:
+ IoFreeMdl(Mdl);
skipNbl:
- InterlockedIncrement64((LONG64 *)&Ctx->Statistics.ifInDiscards);
+ InterlockedIncrementNoFence64((LONG64 *)&Ctx->Statistics.ifInDiscards);
KeWaitForSingleObject(&Ctx->Device.Receive.ActiveNbls.Empty, Executive, KernelMode, FALSE, NULL);
- InterlockedSetU(&Ring->Head, RingHead);
+ WriteULongRelease(&Ring->Head, RingHead);
}
/* Wait for all NBLs to return: 1. To prevent race between proceeding and invalidating ring head. 2. To have
* TunDispatchUnregisterBuffers() implicitly wait before releasing ring MDL used by NBL(s). */
KeWaitForSingleObject(&Ctx->Device.Receive.ActiveNbls.Empty, Executive, KernelMode, FALSE, NULL);
cleanup:
- InterlockedSetU(&Ring->Head, MAXULONG);
+ WriteULongRelease(&Ring->Head, MAXULONG);
}
#define IS_POW2(x) ((x) && !((x) & ((x)-1)))
@@ -559,34 +600,52 @@ TunRegisterBuffers(_Inout_ TUN_CTX *Ctx, _Inout_ IRP *Irp)
goto cleanupMutex;
Ctx->Device.OwningFileObject = Stack->FileObject;
- TUN_REGISTER_RINGS *Rrb = Irp->AssociatedIrp.SystemBuffer;
- if (Status = STATUS_INVALID_PARAMETER, Stack->Parameters.DeviceIoControl.InputBufferLength != sizeof(*Rrb))
+ TUN_REGISTER_RINGS Rrb;
+ if (Stack->Parameters.DeviceIoControl.InputBufferLength == sizeof(Rrb))
+ NdisMoveMemory(&Rrb, Irp->AssociatedIrp.SystemBuffer, sizeof(Rrb));
+#ifdef _WIN64
+ else if (
+ IoIs32bitProcess(Irp) && Stack->Parameters.DeviceIoControl.InputBufferLength == sizeof(TUN_REGISTER_RINGS_32))
+ {
+ TUN_REGISTER_RINGS_32 *Rrb32 = Irp->AssociatedIrp.SystemBuffer;
+ Rrb.Send.RingSize = Rrb32->Send.RingSize;
+ Rrb.Send.Ring = (TUN_RING *)Rrb32->Send.Ring;
+ Rrb.Send.TailMoved = (HANDLE)Rrb32->Send.TailMoved;
+ Rrb.Receive.RingSize = Rrb32->Receive.RingSize;
+ Rrb.Receive.Ring = (TUN_RING *)Rrb32->Receive.Ring;
+ Rrb.Receive.TailMoved = (HANDLE)Rrb32->Receive.TailMoved;
+ }
+#endif
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
goto cleanupResetOwner;
+ }
- Ctx->Device.Send.Capacity = TUN_RING_CAPACITY(Rrb->Send.RingSize);
+ Ctx->Device.Send.Capacity = TUN_RING_CAPACITY(Rrb.Send.RingSize);
if (Status = STATUS_INVALID_PARAMETER,
(Ctx->Device.Send.Capacity < TUN_MIN_RING_CAPACITY || Ctx->Device.Send.Capacity > TUN_MAX_RING_CAPACITY ||
- !IS_POW2(Ctx->Device.Send.Capacity) || !Rrb->Send.TailMoved || !Rrb->Send.Ring))
+ !IS_POW2(Ctx->Device.Send.Capacity) || !Rrb.Send.TailMoved || !Rrb.Send.Ring))
goto cleanupResetOwner;
if (!NT_SUCCESS(
Status = ObReferenceObjectByHandle(
- Rrb->Send.TailMoved,
+ Rrb.Send.TailMoved,
/* We will not wait on send ring tail moved event. */
EVENT_MODIFY_STATE,
*ExEventObjectType,
- UserMode,
+ Irp->RequestorMode,
&Ctx->Device.Send.TailMoved,
NULL)))
goto cleanupResetOwner;
- Ctx->Device.Send.Mdl = IoAllocateMdl(Rrb->Send.Ring, Rrb->Send.RingSize, FALSE, FALSE, NULL);
+ Ctx->Device.Send.Mdl = IoAllocateMdl(Rrb.Send.Ring, Rrb.Send.RingSize, FALSE, FALSE, NULL);
if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Send.Mdl)
goto cleanupSendTailMoved;
try
{
Status = STATUS_INVALID_USER_BUFFER;
- MmProbeAndLockPages(Ctx->Device.Send.Mdl, UserMode, IoWriteAccess);
+ MmProbeAndLockPages(Ctx->Device.Send.Mdl, Irp->RequestorMode, IoWriteAccess);
}
except(EXCEPTION_EXECUTE_HANDLER) { goto cleanupSendMdl; }
@@ -595,34 +654,34 @@ TunRegisterBuffers(_Inout_ TUN_CTX *Ctx, _Inout_ IRP *Irp)
if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Send.Ring)
goto cleanupSendUnlockPages;
- Ctx->Device.Send.RingTail = InterlockedGetU(&Ctx->Device.Send.Ring->Tail);
+ Ctx->Device.Send.RingTail = ReadULongAcquire(&Ctx->Device.Send.Ring->Tail);
if (Status = STATUS_INVALID_PARAMETER, Ctx->Device.Send.RingTail >= Ctx->Device.Send.Capacity)
goto cleanupSendUnlockPages;
- Ctx->Device.Receive.Capacity = TUN_RING_CAPACITY(Rrb->Receive.RingSize);
+ Ctx->Device.Receive.Capacity = TUN_RING_CAPACITY(Rrb.Receive.RingSize);
if (Status = STATUS_INVALID_PARAMETER,
(Ctx->Device.Receive.Capacity < TUN_MIN_RING_CAPACITY || Ctx->Device.Receive.Capacity > TUN_MAX_RING_CAPACITY ||
- !IS_POW2(Ctx->Device.Receive.Capacity) || !Rrb->Receive.TailMoved || !Rrb->Receive.Ring))
+ !IS_POW2(Ctx->Device.Receive.Capacity) || !Rrb.Receive.TailMoved || !Rrb.Receive.Ring))
goto cleanupSendUnlockPages;
if (!NT_SUCCESS(
Status = ObReferenceObjectByHandle(
- Rrb->Receive.TailMoved,
+ Rrb.Receive.TailMoved,
/* We need to clear receive ring TailMoved event on transition to non-alertable state. */
SYNCHRONIZE | EVENT_MODIFY_STATE,
*ExEventObjectType,
- UserMode,
+ Irp->RequestorMode,
&Ctx->Device.Receive.TailMoved,
NULL)))
goto cleanupSendUnlockPages;
- Ctx->Device.Receive.Mdl = IoAllocateMdl(Rrb->Receive.Ring, Rrb->Receive.RingSize, FALSE, FALSE, NULL);
+ Ctx->Device.Receive.Mdl = IoAllocateMdl(Rrb.Receive.Ring, Rrb.Receive.RingSize, FALSE, FALSE, NULL);
if (Status = STATUS_INSUFFICIENT_RESOURCES, !Ctx->Device.Receive.Mdl)
goto cleanupReceiveTailMoved;
try
{
Status = STATUS_INVALID_USER_BUFFER;
- MmProbeAndLockPages(Ctx->Device.Receive.Mdl, UserMode, IoWriteAccess);
+ MmProbeAndLockPages(Ctx->Device.Receive.Mdl, Irp->RequestorMode, IoWriteAccess);
}
except(EXCEPTION_EXECUTE_HANDLER) { goto cleanupReceiveMdl; }
@@ -709,7 +768,7 @@ TunUnregisterBuffers(_Inout_ TUN_CTX *Ctx, _In_ FILE_OBJECT *Owner)
}
ZwClose(Ctx->Device.Receive.Thread);
- InterlockedSetU(&Ctx->Device.Send.Ring->Tail, MAXULONG);
+ WriteULongRelease(&Ctx->Device.Send.Ring->Tail, MAXULONG);
KeSetEvent(Ctx->Device.Send.TailMoved, IO_NO_INCREMENT, FALSE);
MmUnlockPages(Ctx->Device.Receive.Mdl);
@@ -724,104 +783,6 @@ TunUnregisterBuffers(_Inout_ TUN_CTX *Ctx, _In_ FILE_OBJECT *Owner)
_IRQL_requires_max_(PASSIVE_LEVEL)
static VOID
-TunForceHandlesClosed(_Inout_ DEVICE_OBJECT *DeviceObject)
-{
- NTSTATUS Status;
- PEPROCESS Process;
- KAPC_STATE ApcState;
- PVOID Object = NULL;
- ULONG VerifierFlags = 0;
- OBJECT_HANDLE_INFORMATION HandleInfo;
- SYSTEM_HANDLE_INFORMATION_EX *HandleTable = NULL;
-
- MmIsVerifierEnabled(&VerifierFlags);
-
- for (ULONG Size = 0, RequestedSize;
- (Status = ZwQuerySystemInformation(SystemExtendedHandleInformation, HandleTable, Size, &RequestedSize)) ==
- STATUS_INFO_LENGTH_MISMATCH;
- Size = RequestedSize)
- {
- if (HandleTable)
- ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG);
- HandleTable = ExAllocatePoolWithTag(PagedPool, RequestedSize, TUN_MEMORY_TAG);
- if (!HandleTable)
- return;
- }
- if (!NT_SUCCESS(Status) || !HandleTable)
- goto cleanup;
-
- HANDLE CurrentProcessId = PsGetCurrentProcessId();
- for (ULONG_PTR Index = 0; Index < HandleTable->NumberOfHandles; ++Index)
- {
- FILE_OBJECT *FileObject = HandleTable->Handles[Index].Object;
- if (!FileObject || FileObject->Type != 5 || FileObject->DeviceObject != DeviceObject)
- continue;
- HANDLE ProcessId = HandleTable->Handles[Index].UniqueProcessId;
- if (ProcessId == CurrentProcessId)
- continue;
- Status = PsLookupProcessByProcessId(ProcessId, &Process);
- if (!NT_SUCCESS(Status))
- continue;
- KeStackAttachProcess(Process, &ApcState);
- if (!VerifierFlags)
- Status = ObReferenceObjectByHandle(
- HandleTable->Handles[Index].HandleValue, 0, NULL, UserMode, &Object, &HandleInfo);
- if (NT_SUCCESS(Status))
- {
- if (VerifierFlags || Object == FileObject)
- ObCloseHandle(HandleTable->Handles[Index].HandleValue, UserMode);
- if (!VerifierFlags)
- ObfDereferenceObject(Object);
- }
- KeUnstackDetachProcess(&ApcState);
- ObfDereferenceObject(Process);
- }
-cleanup:
- if (HandleTable)
- ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG);
-}
-
-static NTSTATUS TunInitializeDispatchSecurityDescriptor(VOID)
-{
- NTSTATUS Status;
- SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
- SID LocalSystem = { 0 };
- if (!NT_SUCCESS(Status = RtlInitializeSid(&LocalSystem, &NtAuthority, 1)))
- return Status;
- LocalSystem.SubAuthority[0] = 18;
- struct
- {
- ACL Dacl;
- ACCESS_ALLOWED_ACE AceFiller;
- SID SidFiller;
- } DaclStorage = { 0 };
- if (!NT_SUCCESS(Status = RtlCreateAcl(&DaclStorage.Dacl, sizeof(DaclStorage), ACL_REVISION)))
- return Status;
- ACCESS_MASK AccessMask = GENERIC_ALL;
- RtlMapGenericMask(&AccessMask, IoGetFileObjectGenericMapping());
- if (!NT_SUCCESS(Status = RtlAddAccessAllowedAce(&DaclStorage.Dacl, ACL_REVISION, AccessMask, &LocalSystem)))
- return Status;
- SECURITY_DESCRIPTOR SecurityDescriptor = { 0 };
- if (!NT_SUCCESS(Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION)))
- return Status;
- if (!NT_SUCCESS(Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, &DaclStorage.Dacl, FALSE)))
- return Status;
- SecurityDescriptor.Control |= SE_DACL_PROTECTED;
- ULONG RequiredBytes = 0;
- Status = RtlAbsoluteToSelfRelativeSD(&SecurityDescriptor, NULL, &RequiredBytes);
- if (Status != STATUS_BUFFER_TOO_SMALL)
- return NT_SUCCESS(Status) ? STATUS_INSUFFICIENT_RESOURCES : Status;
- TunDispatchSecurityDescriptor = ExAllocatePoolWithTag(NonPagedPoolNx, RequiredBytes, TUN_MEMORY_TAG);
- if (!TunDispatchSecurityDescriptor)
- return STATUS_INSUFFICIENT_RESOURCES;
- Status = RtlAbsoluteToSelfRelativeSD(&SecurityDescriptor, TunDispatchSecurityDescriptor, &RequiredBytes);
- if (!NT_SUCCESS(Status))
- return Status;
- return STATUS_SUCCESS;
-}
-
-_IRQL_requires_max_(PASSIVE_LEVEL)
-static VOID
TunProcessNotification(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create)
{
if (Create)
@@ -851,8 +812,7 @@ static NTSTATUS
TunDispatchDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp)
{
IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp);
- if (Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_REGISTER_RINGS &&
- Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_FORCE_CLOSE_HANDLES)
+ if (Stack->Parameters.DeviceIoControl.IoControlCode != TUN_IOCTL_REGISTER_RINGS)
return NdisDispatchDeviceControl(DeviceObject, Irp);
SECURITY_SUBJECT_CONTEXT SubjectContext;
@@ -887,10 +847,6 @@ TunDispatchDeviceControl(DEVICE_OBJECT *DeviceObject, IRP *Irp)
KeLeaveCriticalRegion();
break;
}
- case TUN_IOCTL_FORCE_CLOSE_HANDLES:
- TunForceHandlesClosed(Stack->FileObject->DeviceObject);
- Status = STATUS_SUCCESS;
- break;
}
cleanup:
Irp->IoStatus.Status = Status;
@@ -916,13 +872,88 @@ TunDispatchClose(DEVICE_OBJECT *DeviceObject, IRP *Irp)
return NdisDispatchClose(DeviceObject, Irp);
}
+_Dispatch_type_(IRP_MJ_PNP)
+static DRIVER_DISPATCH_PAGED TunDispatchPnp;
+_Use_decl_annotations_
+static NTSTATUS
+TunDispatchPnp(DEVICE_OBJECT *DeviceObject, IRP *Irp)
+{
+ IO_STACK_LOCATION *Stack = IoGetCurrentIrpStackLocation(Irp);
+ if (Stack->MinorFunction != IRP_MN_QUERY_REMOVE_DEVICE && Stack->MinorFunction != IRP_MN_SURPRISE_REMOVAL)
+ goto ndisDispatch;
+
+#pragma warning(suppress : 28175)
+ TUN_CTX *Ctx = DeviceObject->Reserved;
+ if (!Ctx)
+ goto ndisDispatch;
+
+ ExAcquireResourceExclusiveLite(&Ctx->Device.RegistrationLock, TRUE);
+ if (!Ctx->Device.OwningFileObject || Ctx->Device.OwningFileObject == Stack->FileObject)
+ goto cleanupLock;
+
+ NTSTATUS Status;
+ PEPROCESS Process;
+ KAPC_STATE ApcState;
+ PVOID Object = NULL;
+ OBJECT_HANDLE_INFORMATION HandleInfo;
+ SYSTEM_HANDLE_INFORMATION_EX *HandleTable = NULL;
+ ULONG VerifierFlags = 0;
+
+ for (ULONG Size = 0, RequestedSize;
+ (Status = ZwQuerySystemInformation(SystemExtendedHandleInformation, HandleTable, Size, &RequestedSize)) ==
+ STATUS_INFO_LENGTH_MISMATCH;
+ Size = RequestedSize)
+ {
+ if (HandleTable)
+ ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG);
+ HandleTable = ExAllocatePoolUninitialized(PagedPool, RequestedSize, TUN_MEMORY_TAG);
+ if (!HandleTable)
+ break;
+ }
+ if (!NT_SUCCESS(Status) || !HandleTable)
+ goto cleanupHandleTable;
+
+ MmIsVerifierEnabled(&VerifierFlags);
+
+ for (ULONG_PTR Index = 0; Index < HandleTable->NumberOfHandles; ++Index)
+ {
+ FILE_OBJECT *FileObject = HandleTable->Handles[Index].Object;
+ if (FileObject != Ctx->Device.OwningFileObject)
+ continue;
+ Status = PsLookupProcessByProcessId(HandleTable->Handles[Index].UniqueProcessId, &Process);
+ if (!NT_SUCCESS(Status))
+ continue;
+ KeStackAttachProcess(Process, &ApcState);
+ if (!VerifierFlags)
+#pragma warning(suppress : 28126)
+ Status = ObReferenceObjectByHandle(
+ HandleTable->Handles[Index].HandleValue, 0, NULL, UserMode, &Object, &HandleInfo);
+ if (NT_SUCCESS(Status))
+ {
+ if (VerifierFlags || Object == FileObject)
+ ObCloseHandle(HandleTable->Handles[Index].HandleValue, UserMode);
+ if (!VerifierFlags)
+ ObfDereferenceObject(Object);
+ }
+ KeUnstackDetachProcess(&ApcState);
+ ObfDereferenceObject(Process);
+ }
+cleanupHandleTable:
+ if (HandleTable)
+ ExFreePoolWithTag(HandleTable, TUN_MEMORY_TAG);
+cleanupLock:
+ ExReleaseResourceLite(&Ctx->Device.RegistrationLock);
+ndisDispatch:
+ return NdisDispatchPnp(DeviceObject, Irp);
+}
+
static MINIPORT_RESTART TunRestart;
_Use_decl_annotations_
static NDIS_STATUS
TunRestart(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_RESTART_PARAMETERS MiniportRestartParameters)
{
TUN_CTX *Ctx = (TUN_CTX *)MiniportAdapterContext;
- InterlockedSet(&Ctx->Running, TRUE);
+ WriteRelease(&Ctx->Running, TRUE);
return NDIS_STATUS_SUCCESS;
}
@@ -933,7 +964,7 @@ TunPause(NDIS_HANDLE MiniportAdapterContext, PNDIS_MINIPORT_PAUSE_PARAMETERS Min
{
TUN_CTX *Ctx = (TUN_CTX *)MiniportAdapterContext;
- InterlockedSet(&Ctx->Running, FALSE);
+ WriteRelease(&Ctx->Running, FALSE);
ExReleaseSpinLockExclusive(
&Ctx->TransitionLock,
ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */
@@ -965,10 +996,10 @@ TunInitializeEx(
/* Leaking memory 'Ctx'. Note: 'Ctx' is freed in TunHaltEx or on failure. */
#pragma warning(suppress : 6014)
- TUN_CTX *Ctx = ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(*Ctx), TUN_MEMORY_TAG);
+#pragma warning(suppress : 28160)
+ TUN_CTX *Ctx = ExAllocatePoolZero(NonPagedPool, sizeof(*Ctx), TUN_MEMORY_TAG);
if (!Ctx)
return NDIS_STATUS_FAILURE;
- NdisZeroMemory(Ctx, sizeof(*Ctx));
Ctx->MiniportAdapterHandle = MiniportAdapterHandle;
@@ -1075,6 +1106,7 @@ TunInitializeEx(
.RcvLinkSpeed = TUN_LINK_SPEED,
.XmitLinkSpeed = TUN_LINK_SPEED,
.MediaConnectState = MediaConnectStateDisconnected,
+ .MediaDuplexState = MediaDuplexStateFull,
.LookaheadSize = TUN_MAX_IP_PACKET_SIZE,
.MacOptions =
NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | NDIS_MAC_OPTION_NO_LOOPBACK,
@@ -1100,10 +1132,6 @@ TunInitializeEx(
MiniportAdapterHandle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&AdapterGeneralAttributes)))
goto cleanupFreeNblPool;
- /* A miniport driver can call NdisMIndicateStatusEx after setting its
- * registration attributes even if the driver is still in the context
- * of the MiniportInitializeEx function. */
- TunIndicateStatus(Ctx->MiniportAdapterHandle, MediaConnectStateDisconnected);
return NDIS_STATUS_SUCCESS;
cleanupFreeNblPool:
@@ -1127,9 +1155,10 @@ TunHaltEx(NDIS_HANDLE MiniportAdapterContext, NDIS_HALT_ACTION HaltAction)
ExAcquireSpinLockExclusive(&Ctx->TransitionLock)); /* Ensure above change is visible to all readers. */
NdisFreeNetBufferListPool(Ctx->NblPool);
- InterlockedSetPointer(&Ctx->MiniportAdapterHandle, NULL);
-#pragma warning(suppress : 28175)
- InterlockedSetPointer(&Ctx->FunctionalDeviceObject->Reserved, NULL);
+#pragma warning(suppress : 6387)
+ WritePointerNoFence(&Ctx->MiniportAdapterHandle, NULL);
+#pragma warning(suppress : 6387 28175)
+ WritePointerNoFence(&Ctx->FunctionalDeviceObject->Reserved, NULL);
KeEnterCriticalRegion();
ExAcquireResourceExclusiveLite(&TunDispatchCtxGuard, TRUE); /* Ensure above change is visible to all readers. */
ExReleaseResourceLite(&TunDispatchCtxGuard);
@@ -1238,16 +1267,16 @@ TunOidQuery(_Inout_ TUN_CTX *Ctx, _Inout_ NDIS_OID_REQUEST *OidRequest)
case OID_GEN_XMIT_OK:
return TunOidQueryWrite32or64(
OidRequest,
- InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCOutUcastPkts) +
- InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCOutMulticastPkts) +
- InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCOutBroadcastPkts));
+ ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutUcastPkts) +
+ ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutMulticastPkts) +
+ ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCOutBroadcastPkts));
case OID_GEN_RCV_OK:
return TunOidQueryWrite32or64(
OidRequest,
- InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCInUcastPkts) +
- InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCInMulticastPkts) +
- InterlockedGet64((LONG64 *)&Ctx->Statistics.ifHCInBroadcastPkts));
+ ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCInUcastPkts) +
+ ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCInMulticastPkts) +
+ ReadNoFence64((LONG64 *)&Ctx->Statistics.ifHCInBroadcastPkts));
case OID_GEN_STATISTICS:
return TunOidQueryWriteBuf(OidRequest, &Ctx->Statistics, (ULONG)sizeof(Ctx->Statistics));
@@ -1387,18 +1416,19 @@ TunUnload(PDRIVER_OBJECT DriverObject)
NdisMDeregisterMiniportDriver(NdisMiniportDriverHandle);
ExDeleteResourceLite(&TunDispatchCtxGuard);
ExDeleteResourceLite(&TunDispatchDeviceListLock);
- ExFreePoolWithTag(TunDispatchSecurityDescriptor, TUN_MEMORY_TAG);
}
DRIVER_INITIALIZE DriverEntry;
+#ifdef ALLOC_PRAGMA
+# pragma alloc_text(INIT, DriverEntry)
+#endif
_Use_decl_annotations_
NTSTATUS
DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath)
{
NTSTATUS Status;
- if (!NT_SUCCESS(Status = TunInitializeDispatchSecurityDescriptor()))
- return Status;
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
NdisVersion = NdisGetVersion();
if (NdisVersion < NDIS_MINIPORT_VERSION_MIN)
@@ -1451,8 +1481,10 @@ DriverEntry(DRIVER_OBJECT *DriverObject, UNICODE_STRING *RegistryPath)
NdisDispatchDeviceControl = DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
NdisDispatchClose = DriverObject->MajorFunction[IRP_MJ_CLOSE];
+ NdisDispatchPnp = DriverObject->MajorFunction[IRP_MJ_PNP];
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TunDispatchDeviceControl;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = TunDispatchClose;
+ DriverObject->MajorFunction[IRP_MJ_PNP] = TunDispatchPnp;
return STATUS_SUCCESS;
@@ -1461,6 +1493,5 @@ cleanupNotifier:
cleanupResources:
ExDeleteResourceLite(&TunDispatchCtxGuard);
ExDeleteResourceLite(&TunDispatchDeviceListLock);
- ExFreePoolWithTag(TunDispatchSecurityDescriptor, TUN_MEMORY_TAG);
return Status;
}
diff --git a/wintun.inf b/driver/wintun.inf
index ca7dd9b..4b69802 100644
--- a/wintun.inf
+++ b/driver/wintun.inf
@@ -1,6 +1,6 @@
; SPDX-License-Identifier: GPL-2.0
;
-; Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
+; Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
[Version]
Signature = "$Windows NT$"
@@ -8,6 +8,7 @@ Class = Net
ClassGUID = {4D36E972-E325-11CE-BFC1-08002BE10318}
Provider = %Wintun.CompanyName%
CatalogFile.NT = wintun.cat
+PnpLockdown = 1
[Manufacturer]
%Wintun.CompanyName% = %Wintun.Name%, NT$ARCH$
@@ -31,17 +32,20 @@ wintun.sys, , , 0x00004002 ; COPYFLG_IN_USE_RENAME | COPYFLG_NOSKIP
[Wintun.Install]
Characteristics = 0x1 ; NCF_VIRTUAL
AddReg = Wintun.Ndi
+AddProperty = Wintun.Properties
CopyFiles = Wintun.CopyFiles.Sys
*IfType = 53 ; IF_TYPE_PROP_VIRTUAL
*MediaType = 19 ; NdisMediumIP
*PhysicalMediaType = 0 ; NdisPhysicalMediumUnspecified
EnableDhcp = 0 ; Disable DHCP
+[Wintun.Properties]
+DeviceVendorWebsite,,,,"https://www.wintun.net/"
+
[Wintun.Install.Services]
AddService = wintun, 2, Wintun.Service, Wintun.EventLog ; 2=SPSVCINST_ASSOCSERVICE
[Wintun.Ndi]
-HKR, , DeviceVxDs, , wintun.sys
HKR, Ndi, Service, 0, wintun
HKR, Ndi\Interfaces, UpperRange, , "ndis5"
HKR, Ndi\Interfaces, LowerRange, , "nolower"
@@ -53,7 +57,6 @@ ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %12%\wintun.sys
-LoadOrderGroup = NDIS
[Wintun.EventLog]
HKR, , EventMessageFile, 0x00020000, "%11%\IoLogMsg.dll;%12%\wintun.sys"
diff --git a/wintun.rc b/driver/wintun.rc
index 7fff283..10ef9f5 100644
--- a/wintun.rc
+++ b/driver/wintun.rc
@@ -1,20 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0
*
- * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
*/
#include <windows.h>
#include <ntverp.h>
+#pragma code_page(1252)
+
#define STRINGIZE(x) #x
#define EXPAND(x) STRINGIZE(x)
VS_VERSION_INFO VERSIONINFO
-FILEVERSION WINTUN_VERSION_MAJ, WINTUN_VERSION_MIN, 0, 0
-PRODUCTVERSION WINTUN_VERSION_MAJ, WINTUN_VERSION_MIN, 0, 0
+FILEVERSION WINTUN_VERSION_MAJ, WINTUN_VERSION_MIN, WINTUN_VERSION_REL, 0
+PRODUCTVERSION WINTUN_VERSION_MAJ, WINTUN_VERSION_MIN, WINTUN_VERSION_REL, 0
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DRV
-FILESUBTYPE VFT2_DRV_SYSTEM
+FILESUBTYPE VFT2_DRV_NETWORK
BEGIN
BLOCK "StringFileInfo"
BEGIN
@@ -22,12 +24,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "WireGuard LLC"
VALUE "FileDescription", "Wintun Driver"
- VALUE "FileVersion", EXPAND(WINTUN_VERSION_STR)
+ VALUE "FileVersion", EXPAND(WINTUN_VERSION)
VALUE "InternalName", "wintun.sys"
- VALUE "LegalCopyright", "Copyright \xa9 2018-2019 WireGuard LLC. All Rights Reserved."
+ VALUE "LegalCopyright", "Copyright \xa9 2018-2021 WireGuard LLC. All Rights Reserved."
VALUE "OriginalFilename", "wintun.sys"
VALUE "ProductName", "Wintun Driver"
- VALUE "ProductVersion", EXPAND(WINTUN_VERSION_STR)
+ VALUE "ProductVersion", EXPAND(WINTUN_VERSION)
VALUE "Comments", "https://www.wintun.net/"
END
END
diff --git a/example/example.c b/example/example.c
new file mode 100644
index 0000000..3642355
--- /dev/null
+++ b/example/example.c
@@ -0,0 +1,379 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include <winsock2.h>
+#include <Windows.h>
+#include <ws2ipdef.h>
+#include <iphlpapi.h>
+#include <mstcpip.h>
+#include <ip2string.h>
+#include <winternl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "wintun.h"
+
+static WINTUN_CREATE_ADAPTER_FUNC *WintunCreateAdapter;
+static WINTUN_CLOSE_ADAPTER_FUNC *WintunCloseAdapter;
+static WINTUN_OPEN_ADAPTER_FUNC *WintunOpenAdapter;
+static WINTUN_GET_ADAPTER_LUID_FUNC *WintunGetAdapterLUID;
+static WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC *WintunGetRunningDriverVersion;
+static WINTUN_DELETE_DRIVER_FUNC *WintunDeleteDriver;
+static WINTUN_SET_LOGGER_FUNC *WintunSetLogger;
+static WINTUN_START_SESSION_FUNC *WintunStartSession;
+static WINTUN_END_SESSION_FUNC *WintunEndSession;
+static WINTUN_GET_READ_WAIT_EVENT_FUNC *WintunGetReadWaitEvent;
+static WINTUN_RECEIVE_PACKET_FUNC *WintunReceivePacket;
+static WINTUN_RELEASE_RECEIVE_PACKET_FUNC *WintunReleaseReceivePacket;
+static WINTUN_ALLOCATE_SEND_PACKET_FUNC *WintunAllocateSendPacket;
+static WINTUN_SEND_PACKET_FUNC *WintunSendPacket;
+
+static HMODULE
+InitializeWintun(void)
+{
+ HMODULE Wintun =
+ LoadLibraryExW(L"wintun.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
+ if (!Wintun)
+ return NULL;
+#define X(Name) ((*(FARPROC *)&Name = GetProcAddress(Wintun, #Name)) == NULL)
+ if (X(WintunCreateAdapter) || X(WintunCloseAdapter) || X(WintunOpenAdapter) || X(WintunGetAdapterLUID) ||
+ X(WintunGetRunningDriverVersion) || X(WintunDeleteDriver) || X(WintunSetLogger) || X(WintunStartSession) ||
+ X(WintunEndSession) || X(WintunGetReadWaitEvent) || X(WintunReceivePacket) || X(WintunReleaseReceivePacket) ||
+ X(WintunAllocateSendPacket) || X(WintunSendPacket))
+#undef X
+ {
+ DWORD LastError = GetLastError();
+ FreeLibrary(Wintun);
+ SetLastError(LastError);
+ return NULL;
+ }
+ return Wintun;
+}
+
+static void CALLBACK
+ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_ DWORD64 Timestamp, _In_z_ const WCHAR *LogLine)
+{
+ SYSTEMTIME SystemTime;
+ FileTimeToSystemTime((FILETIME *)&Timestamp, &SystemTime);
+ WCHAR LevelMarker;
+ switch (Level)
+ {
+ case WINTUN_LOG_INFO:
+ LevelMarker = L'+';
+ break;
+ case WINTUN_LOG_WARN:
+ LevelMarker = L'-';
+ break;
+ case WINTUN_LOG_ERR:
+ LevelMarker = L'!';
+ break;
+ default:
+ return;
+ }
+ fwprintf(
+ stderr,
+ L"%04u-%02u-%02u %02u:%02u:%02u.%04u [%c] %s\n",
+ SystemTime.wYear,
+ SystemTime.wMonth,
+ SystemTime.wDay,
+ SystemTime.wHour,
+ SystemTime.wMinute,
+ SystemTime.wSecond,
+ SystemTime.wMilliseconds,
+ LevelMarker,
+ LogLine);
+}
+
+static DWORD64 Now(VOID)
+{
+ LARGE_INTEGER Timestamp;
+ NtQuerySystemTime(&Timestamp);
+ return Timestamp.QuadPart;
+}
+
+static DWORD
+LogError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error)
+{
+ WCHAR *SystemMessage = NULL, *FormattedMessage = NULL;
+ FormatMessageW(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ NULL,
+ HRESULT_FROM_SETUPAPI(Error),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (void *)&SystemMessage,
+ 0,
+ NULL);
+ FormatMessageW(
+ FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ SystemMessage ? L"%1: %3(Code 0x%2!08X!)" : L"%1: Code 0x%2!08X!",
+ 0,
+ 0,
+ (void *)&FormattedMessage,
+ 0,
+ (va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)Error, (DWORD_PTR)SystemMessage });
+ if (FormattedMessage)
+ ConsoleLogger(WINTUN_LOG_ERR, Now(), FormattedMessage);
+ LocalFree(FormattedMessage);
+ LocalFree(SystemMessage);
+ return Error;
+}
+
+static DWORD
+LogLastError(_In_z_ const WCHAR *Prefix)
+{
+ DWORD LastError = GetLastError();
+ LogError(Prefix, LastError);
+ SetLastError(LastError);
+ return LastError;
+}
+
+static void
+Log(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Format, ...)
+{
+ WCHAR LogLine[0x200];
+ va_list args;
+ va_start(args, Format);
+ _vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, args);
+ va_end(args);
+ ConsoleLogger(Level, Now(), LogLine);
+}
+
+static HANDLE QuitEvent;
+static volatile BOOL HaveQuit;
+
+static BOOL WINAPI
+CtrlHandler(_In_ DWORD CtrlType)
+{
+ switch (CtrlType)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ case CTRL_CLOSE_EVENT:
+ case CTRL_LOGOFF_EVENT:
+ case CTRL_SHUTDOWN_EVENT:
+ Log(WINTUN_LOG_INFO, L"Cleaning up and shutting down...");
+ HaveQuit = TRUE;
+ SetEvent(QuitEvent);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+PrintPacket(_In_ const BYTE *Packet, _In_ DWORD PacketSize)
+{
+ if (PacketSize < 20)
+ {
+ Log(WINTUN_LOG_INFO, L"Received packet without room for an IP header");
+ return;
+ }
+ BYTE IpVersion = Packet[0] >> 4, Proto;
+ WCHAR Src[46], Dst[46];
+ if (IpVersion == 4)
+ {
+ RtlIpv4AddressToStringW((struct in_addr *)&Packet[12], Src);
+ RtlIpv4AddressToStringW((struct in_addr *)&Packet[16], Dst);
+ Proto = Packet[9];
+ Packet += 20, PacketSize -= 20;
+ }
+ else if (IpVersion == 6 && PacketSize < 40)
+ {
+ Log(WINTUN_LOG_INFO, L"Received packet without room for an IP header");
+ return;
+ }
+ else if (IpVersion == 6)
+ {
+ RtlIpv6AddressToStringW((struct in6_addr *)&Packet[8], Src);
+ RtlIpv6AddressToStringW((struct in6_addr *)&Packet[24], Dst);
+ Proto = Packet[6];
+ Packet += 40, PacketSize -= 40;
+ }
+ else
+ {
+ Log(WINTUN_LOG_INFO, L"Received packet that was not IP");
+ return;
+ }
+ if (Proto == 1 && PacketSize >= 8 && Packet[0] == 0)
+ Log(WINTUN_LOG_INFO, L"Received IPv%d ICMP echo reply from %s to %s", IpVersion, Src, Dst);
+ else
+ Log(WINTUN_LOG_INFO, L"Received IPv%d proto 0x%x packet from %s to %s", IpVersion, Proto, Src, Dst);
+}
+
+static USHORT
+IPChecksum(_In_reads_bytes_(Len) BYTE *Buffer, _In_ DWORD Len)
+{
+ ULONG Sum = 0;
+ for (; Len > 1; Len -= 2, Buffer += 2)
+ Sum += *(USHORT *)Buffer;
+ if (Len)
+ Sum += *Buffer;
+ Sum = (Sum >> 16) + (Sum & 0xffff);
+ Sum += (Sum >> 16);
+ return (USHORT)(~Sum);
+}
+
+static void
+MakeICMP(_Out_writes_bytes_all_(28) BYTE Packet[28])
+{
+ memset(Packet, 0, 28);
+ Packet[0] = 0x45;
+ *(USHORT *)&Packet[2] = htons(28);
+ Packet[8] = 255;
+ Packet[9] = 1;
+ *(ULONG *)&Packet[12] = htonl((10 << 24) | (6 << 16) | (7 << 8) | (8 << 0)); /* 10.6.7.8 */
+ *(ULONG *)&Packet[16] = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */
+ *(USHORT *)&Packet[10] = IPChecksum(Packet, 20);
+ Packet[20] = 8;
+ *(USHORT *)&Packet[22] = IPChecksum(&Packet[20], 8);
+ Log(WINTUN_LOG_INFO, L"Sending IPv4 ICMP echo request to 10.6.7.8 from 10.6.7.7");
+}
+
+static DWORD WINAPI
+ReceivePackets(_Inout_ DWORD_PTR SessionPtr)
+{
+ WINTUN_SESSION_HANDLE Session = (WINTUN_SESSION_HANDLE)SessionPtr;
+ HANDLE WaitHandles[] = { WintunGetReadWaitEvent(Session), QuitEvent };
+
+ while (!HaveQuit)
+ {
+ DWORD PacketSize;
+ BYTE *Packet = WintunReceivePacket(Session, &PacketSize);
+ if (Packet)
+ {
+ PrintPacket(Packet, PacketSize);
+ WintunReleaseReceivePacket(Session, Packet);
+ }
+ else
+ {
+ DWORD LastError = GetLastError();
+ switch (LastError)
+ {
+ case ERROR_NO_MORE_ITEMS:
+ if (WaitForMultipleObjects(_countof(WaitHandles), WaitHandles, FALSE, INFINITE) == WAIT_OBJECT_0)
+ continue;
+ return ERROR_SUCCESS;
+ default:
+ LogError(L"Packet read failed", LastError);
+ return LastError;
+ }
+ }
+ }
+ return ERROR_SUCCESS;
+}
+
+static DWORD WINAPI
+SendPackets(_Inout_ DWORD_PTR SessionPtr)
+{
+ WINTUN_SESSION_HANDLE Session = (WINTUN_SESSION_HANDLE)SessionPtr;
+ while (!HaveQuit)
+ {
+ BYTE *Packet = WintunAllocateSendPacket(Session, 28);
+ if (Packet)
+ {
+ MakeICMP(Packet);
+ WintunSendPacket(Session, Packet);
+ }
+ else if (GetLastError() != ERROR_BUFFER_OVERFLOW)
+ return LogLastError(L"Packet write failed");
+
+ switch (WaitForSingleObject(QuitEvent, 1000 /* 1 second */))
+ {
+ case WAIT_ABANDONED:
+ case WAIT_OBJECT_0:
+ return ERROR_SUCCESS;
+ }
+ }
+ return ERROR_SUCCESS;
+}
+
+int __cdecl main(void)
+{
+ HMODULE Wintun = InitializeWintun();
+ if (!Wintun)
+ return LogError(L"Failed to initialize Wintun", GetLastError());
+ WintunSetLogger(ConsoleLogger);
+ Log(WINTUN_LOG_INFO, L"Wintun library loaded");
+
+ DWORD LastError;
+ HaveQuit = FALSE;
+ QuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+ if (!QuitEvent)
+ {
+ LastError = LogError(L"Failed to create event", GetLastError());
+ goto cleanupWintun;
+ }
+ if (!SetConsoleCtrlHandler(CtrlHandler, TRUE))
+ {
+ LastError = LogError(L"Failed to set console handler", GetLastError());
+ goto cleanupQuit;
+ }
+
+ GUID ExampleGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
+ WINTUN_ADAPTER_HANDLE Adapter = WintunCreateAdapter(L"Demo", L"Example", &ExampleGuid);
+ if (!Adapter)
+ {
+ LastError = GetLastError();
+ LogError(L"Failed to create adapter", LastError);
+ goto cleanupQuit;
+ }
+
+ DWORD Version = WintunGetRunningDriverVersion();
+ Log(WINTUN_LOG_INFO, L"Wintun v%u.%u loaded", (Version >> 16) & 0xff, (Version >> 0) & 0xff);
+
+ MIB_UNICASTIPADDRESS_ROW AddressRow;
+ InitializeUnicastIpAddressEntry(&AddressRow);
+ WintunGetAdapterLUID(Adapter, &AddressRow.InterfaceLuid);
+ AddressRow.Address.Ipv4.sin_family = AF_INET;
+ AddressRow.Address.Ipv4.sin_addr.S_un.S_addr = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */
+ AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */
+ AddressRow.DadState = IpDadStatePreferred;
+ LastError = CreateUnicastIpAddressEntry(&AddressRow);
+ if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS)
+ {
+ LogError(L"Failed to set IP address", LastError);
+ goto cleanupAdapter;
+ }
+
+ WINTUN_SESSION_HANDLE Session = WintunStartSession(Adapter, 0x400000);
+ if (!Session)
+ {
+ LastError = LogLastError(L"Failed to create adapter");
+ goto cleanupAdapter;
+ }
+
+ Log(WINTUN_LOG_INFO, L"Launching threads and mangling packets...");
+
+ HANDLE Workers[] = { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceivePackets, (LPVOID)Session, 0, NULL),
+ CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendPackets, (LPVOID)Session, 0, NULL) };
+ if (!Workers[0] || !Workers[1])
+ {
+ LastError = LogError(L"Failed to create threads", GetLastError());
+ goto cleanupWorkers;
+ }
+ WaitForMultipleObjectsEx(_countof(Workers), Workers, TRUE, INFINITE, TRUE);
+ LastError = ERROR_SUCCESS;
+
+cleanupWorkers:
+ HaveQuit = TRUE;
+ SetEvent(QuitEvent);
+ for (size_t i = 0; i < _countof(Workers); ++i)
+ {
+ if (Workers[i])
+ {
+ WaitForSingleObject(Workers[i], INFINITE);
+ CloseHandle(Workers[i]);
+ }
+ }
+ WintunEndSession(Session);
+cleanupAdapter:
+ WintunCloseAdapter(Adapter);
+cleanupQuit:
+ SetConsoleCtrlHandler(CtrlHandler, FALSE);
+ CloseHandle(QuitEvent);
+cleanupWintun:
+ FreeLibrary(Wintun);
+ return LastError;
+}
diff --git a/example/example.vcxproj b/example/example.vcxproj
new file mode 100644
index 0000000..22b1eac
--- /dev/null
+++ b/example/example.vcxproj
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{2abac503-245d-4f53-85c5-0f844def738b}</ProjectGuid>
+ <RootNamespace>example</RootNamespace>
+ <ProjectName>example</ProjectName>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ForcedTargetVersion>Windows10</ForcedTargetVersion>
+ </PropertyGroup>
+ <Import Project="..\wintun.props" />
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>..\api</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>iphlpapi.lib;kernel32.lib;ntdll.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="example.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\api\api.vcxproj">
+ <Project>{897f02e3-3eaa-40af-a6dc-17eb2376edaf}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="..\wintun.props.user" Condition="exists('..\wintun.props.user')" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets" />
+</Project>
diff --git a/example/example.vcxproj.filters b/example/example.vcxproj.filters
new file mode 100644
index 0000000..eb29fb9
--- /dev/null
+++ b/example/example.vcxproj.filters
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="example.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/installer/exports.def b/installer/exports.def
deleted file mode 100644
index 95eafde..0000000
--- a/installer/exports.def
+++ /dev/null
@@ -1,5 +0,0 @@
-EXPORTS
- InstallWintun
- UninstallWintun
- MsiEvaluate
- MsiProcess
diff --git a/installer/installation.c b/installer/installation.c
deleted file mode 100644
index cd93ffb..0000000
--- a/installer/installation.c
+++ /dev/null
@@ -1,660 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
- */
-
-#include "installation.h"
-#include <Windows.h>
-#include <NTSecAPI.h>
-#include <SetupAPI.h>
-#include <newdev.h>
-#include <Shlwapi.h>
-#include <Psapi.h>
-#include <sddl.h>
-#include <devguid.h>
-#include <ndisguid.h>
-#include <cfgmgr32.h>
-#include <WinCrypt.h>
-#include <tchar.h>
-#include <stdio.h>
-
-#pragma warning(disable : 4100) /* unreferenced formal parameter */
-#pragma warning(disable : 4204) /* nonstandard: non-constant aggregate initializer */
-#pragma warning(disable : 4221) /* nonstandard: address of automatic in initializer */
-
-typedef struct _SP_DEVINFO_DATA_LIST
-{
- SP_DEVINFO_DATA Data;
- struct _SP_DEVINFO_DATA_LIST *Next;
-} SP_DEVINFO_DATA_LIST;
-
-static VOID
-NopLogger(_In_ LOGGER_LEVEL Level, _In_ const TCHAR *LogLine)
-{
-}
-
-static LoggerFunction Logger = NopLogger;
-
-VOID
-SetLogger(_In_ LoggerFunction NewLogger)
-{
- Logger = NewLogger;
-}
-
-static VOID
-PrintError(_In_ LOGGER_LEVEL Level, _In_ const TCHAR *Prefix)
-{
- DWORD ErrorCode = GetLastError();
- TCHAR *SystemMessage = NULL, *FormattedMessage = NULL;
- FormatMessage(
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK,
- NULL,
- HRESULT_FROM_SETUPAPI(ErrorCode),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (VOID *)&SystemMessage,
- 0,
- NULL);
- FormatMessage(
- FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_ARGUMENT_ARRAY |
- FORMAT_MESSAGE_MAX_WIDTH_MASK,
- SystemMessage ? TEXT("%1: %3(Code 0x%2!08X!)") : TEXT("%1: Code 0x%2!08X!"),
- 0,
- 0,
- (VOID *)&FormattedMessage,
- 0,
- (va_list *)(DWORD_PTR[]){ (DWORD_PTR)Prefix, (DWORD_PTR)ErrorCode, (DWORD_PTR)SystemMessage });
- if (FormattedMessage)
- Logger(Level, FormattedMessage);
- LocalFree(FormattedMessage);
- LocalFree(SystemMessage);
-}
-
-HINSTANCE ResourceModule;
-
-static BOOL IsWintunLoaded(VOID)
-{
- DWORD RequiredSize = 0, CurrentSize = 0;
- VOID **Drivers = NULL;
- BOOL Found = FALSE;
- for (;;)
- {
- if (!EnumDeviceDrivers(Drivers, CurrentSize, &RequiredSize))
- goto out;
- if (CurrentSize == RequiredSize)
- break;
- free(Drivers);
- Drivers = malloc(RequiredSize);
- if (!Drivers)
- goto out;
- CurrentSize = RequiredSize;
- }
- TCHAR MaybeWintun[11];
- for (DWORD i = CurrentSize / sizeof(Drivers[0]); i-- > 0;)
- {
- if (GetDeviceDriverBaseName(Drivers[i], MaybeWintun, _countof(MaybeWintun)) == 10 &&
- !_tcsicmp(MaybeWintun, TEXT("wintun.sys")))
- {
- Found = TRUE;
- goto out;
- }
- }
-out:
- free(Drivers);
- return Found;
-}
-
-static BOOL EnsureWintunUnloaded(VOID)
-{
- BOOL Loaded;
- for (int i = 0; (Loaded = IsWintunLoaded()) != 0 && i < 300; ++i)
- Sleep(50);
- return !Loaded;
-}
-
-static BOOL
-CopyResource(
- _In_ const TCHAR *DestinationPath,
- _In_opt_ SECURITY_ATTRIBUTES *SecurityAttributes,
- _In_ const TCHAR *ResourceName)
-{
- HRSRC FoundResource = FindResource(ResourceModule, ResourceName, RT_RCDATA);
- if (!FoundResource)
- return FALSE;
- DWORD SizeResource = SizeofResource(ResourceModule, FoundResource);
- if (!SizeResource)
- return FALSE;
- HGLOBAL LoadedResource = LoadResource(ResourceModule, FoundResource);
- if (!LoadedResource)
- return FALSE;
- LPVOID LockedResource = LockResource(LoadedResource);
- if (!LockedResource)
- return FALSE;
- HANDLE DestinationHandle = CreateFile(
- DestinationPath,
- GENERIC_WRITE,
- 0,
- SecurityAttributes,
- CREATE_NEW,
- FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY,
- NULL);
- if (DestinationHandle == INVALID_HANDLE_VALUE)
- return FALSE;
- DWORD BytesWritten;
- BOOL Ret =
- WriteFile(DestinationHandle, LockedResource, SizeResource, &BytesWritten, NULL) && BytesWritten == SizeResource;
- CloseHandle(DestinationHandle);
- return Ret;
-}
-
-static BOOL
-InstallWintunCertificate(const TCHAR *SignedResource)
-{
- DWORD LastError = ERROR_SUCCESS;
- Logger(LOG_INFO, TEXT("Trusting code signing certificate"));
- BOOL Ret = TRUE;
- HRSRC FoundResource = FindResource(ResourceModule, SignedResource, RT_RCDATA);
- if (!FoundResource)
- return FALSE;
- DWORD SizeResource = SizeofResource(ResourceModule, FoundResource);
- if (!SizeResource)
- return FALSE;
- HGLOBAL LoadedResource = LoadResource(ResourceModule, FoundResource);
- if (!LoadedResource)
- return FALSE;
- LPVOID LockedResource = LockResource(LoadedResource);
- if (!LockedResource)
- return FALSE;
- const CERT_BLOB CertBlob = { .cbData = SizeResource, .pbData = LockedResource };
- HCERTSTORE QueriedStore;
- if (!CryptQueryObject(
- CERT_QUERY_OBJECT_BLOB,
- &CertBlob,
- CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
- CERT_QUERY_FORMAT_FLAG_ALL,
- 0,
- 0,
- 0,
- 0,
- &QueriedStore,
- 0,
- NULL))
- return FALSE;
- HCERTSTORE TrustedStore =
- CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, TEXT("TrustedPublisher"));
- if (!TrustedStore)
- {
- LastError = GetLastError();
- goto cleanupQueriedStore;
- }
- LPSTR CodeSigningOid[] = { szOID_PKIX_KP_CODE_SIGNING };
- CERT_ENHKEY_USAGE EnhancedUsage = { .cUsageIdentifier = 1, .rgpszUsageIdentifier = CodeSigningOid };
- for (const CERT_CONTEXT *CertContext = NULL; (CertContext = CertFindCertificateInStore(
- QueriedStore,
- X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
- CERT_FIND_ENHKEY_USAGE,
- &EnhancedUsage,
- CertContext)) != NULL;)
- {
- CERT_EXTENSION *Ext = CertFindExtension(
- szOID_BASIC_CONSTRAINTS2, CertContext->pCertInfo->cExtension, CertContext->pCertInfo->rgExtension);
- CERT_BASIC_CONSTRAINTS2_INFO Constraints;
- DWORD Size = sizeof(Constraints);
- if (Ext &&
- CryptDecodeObjectEx(
- X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- szOID_BASIC_CONSTRAINTS2,
- Ext->Value.pbData,
- Ext->Value.cbData,
- 0,
- NULL,
- &Constraints,
- &Size) &&
- !Constraints.fCA)
- Ret &= CertAddCertificateContextToStore(TrustedStore, CertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL);
- if (!Ret)
- LastError = LastError ? LastError : GetLastError();
- }
- CertCloseStore(TrustedStore, 0);
-cleanupQueriedStore:
- CertCloseStore(QueriedStore, 0);
- SetLastError(LastError);
- return Ret;
-}
-
-/* We can't use RtlGetVersion, because appcompat's aclayers.dll shims it to report Vista
- * when run from MSI context. So, we instead use the undocumented RtlGetNtVersionNumbers.
- *
- * Another way would be reading from the PEB directly:
- * ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(void *) == 8 ? 70 : 41]
- * Or just read from KUSER_SHARED_DATA the same way on 32-bit and 64-bit:
- * *(DWORD *)0x7FFE026C
- */
-extern VOID NTAPI
-RtlGetNtVersionNumbers(_Out_opt_ DWORD *MajorVersion, _Out_opt_ DWORD *MinorVersion, _Out_opt_ DWORD *BuildNumber);
-
-static BOOL
-InstallWintun(BOOL UpdateExisting)
-{
- DWORD LastError = ERROR_SUCCESS;
- TCHAR WindowsDirectory[MAX_PATH];
- if (!GetWindowsDirectory(WindowsDirectory, _countof(WindowsDirectory)))
- return FALSE;
- TCHAR WindowsTempDirectory[MAX_PATH];
- if (!PathCombine(WindowsTempDirectory, WindowsDirectory, TEXT("Temp")))
- return FALSE;
- UCHAR RandomBytes[32] = { 0 };
-#pragma warning(suppress : 6387)
- if (!RtlGenRandom(RandomBytes, sizeof(RandomBytes)))
- return FALSE;
- TCHAR RandomSubDirectory[sizeof(RandomBytes) * 2 + 1];
- for (int i = 0; i < sizeof(RandomBytes); ++i)
- _stprintf_s(&RandomSubDirectory[i * 2], 3, TEXT("%02x"), RandomBytes[i]);
- TCHAR RandomTempSubDirectory[MAX_PATH];
- if (!PathCombine(RandomTempSubDirectory, WindowsTempDirectory, RandomSubDirectory))
- return FALSE;
- SECURITY_ATTRIBUTES SecurityAttributes = { .nLength = sizeof(SecurityAttributes) };
- if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
- TEXT("O:SYD:P(A;;GA;;;SY)"), SDDL_REVISION_1, &SecurityAttributes.lpSecurityDescriptor, NULL))
- return FALSE;
- BOOL Ret = CreateDirectory(RandomTempSubDirectory, &SecurityAttributes);
- if (!Ret)
- goto cleanupFree;
-
- TCHAR CatPath[MAX_PATH] = { 0 };
- if (!PathCombine(CatPath, RandomTempSubDirectory, TEXT("wintun.cat")))
- goto cleanupFree;
- TCHAR SysPath[MAX_PATH] = { 0 };
- if (!PathCombine(SysPath, RandomTempSubDirectory, TEXT("wintun.sys")))
- goto cleanupFree;
- TCHAR InfPath[MAX_PATH] = { 0 };
- if (!PathCombine(InfPath, RandomTempSubDirectory, TEXT("wintun.inf")))
- goto cleanupFree;
-
- BOOL UseWHQL = FALSE;
-#ifdef HAVE_WHQL
- DWORD MajorVersion;
- RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL);
- UseWHQL = MajorVersion >= 10;
-#endif
- if (!UseWHQL && !InstallWintunCertificate(TEXT("wintun.sys")))
- PrintError(LOG_WARN, TEXT("Unable to install code signing certificate"));
-
- Logger(LOG_INFO, TEXT("Copying resources to temporary path"));
- Ret = CopyResource(CatPath, &SecurityAttributes, UseWHQL ? TEXT("wintun-whql.cat") : TEXT("wintun.cat")) &&
- CopyResource(SysPath, &SecurityAttributes, UseWHQL ? TEXT("wintun-whql.sys") : TEXT("wintun.sys")) &&
- CopyResource(InfPath, &SecurityAttributes, UseWHQL ? TEXT("wintun-whql.inf") : TEXT("wintun.inf"));
- if (!Ret)
- goto cleanupDelete;
-
- Logger(LOG_INFO, TEXT("Installing driver"));
- Ret = SetupCopyOEMInf(InfPath, NULL, SPOST_PATH, 0, NULL, 0, NULL, NULL);
- BOOL RebootRequired = FALSE;
- if (UpdateExisting &&
- !UpdateDriverForPlugAndPlayDevices(
- NULL, TEXT("Wintun"), InfPath, INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE, &RebootRequired))
- PrintError(LOG_WARN, TEXT("Could not update existing adapters"));
- if (RebootRequired)
- Logger(LOG_WARN, TEXT("A reboot might be required, which really should not be the case"));
-
-cleanupDelete:
- LastError = GetLastError();
- DeleteFile(CatPath);
- DeleteFile(SysPath);
- DeleteFile(InfPath);
- RemoveDirectory(RandomTempSubDirectory);
-cleanupFree:
- LastError = LastError ? LastError : GetLastError();
- LocalFree(SecurityAttributes.lpSecurityDescriptor);
- SetLastError(LastError);
- return Ret;
-}
-
-static BOOL RemoveWintun(VOID)
-{
- BOOL Ret = FALSE;
- HDEVINFO DeviceInfoSet = SetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL, 0);
- if (!DeviceInfoSet)
- return FALSE;
- if (!SetupDiBuildDriverInfoList(DeviceInfoSet, NULL, SPDIT_CLASSDRIVER))
- goto cleanupDeviceInfoSet;
- Ret = TRUE;
- for (DWORD EnumIndex = 0;; ++EnumIndex)
- {
- SP_DRVINFO_DATA DriverInfo = { .cbSize = sizeof(DriverInfo) };
- if (!SetupDiEnumDriverInfo(DeviceInfoSet, NULL, SPDIT_CLASSDRIVER, EnumIndex, &DriverInfo))
- {
- if (GetLastError() == ERROR_NO_MORE_ITEMS)
- break;
- goto cleanupDriverInfoList;
- }
- DWORD RequiredSize;
- if (SetupDiGetDriverInfoDetail(DeviceInfoSet, NULL, &DriverInfo, NULL, 0, &RequiredSize) ||
- GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- goto cleanupDriverInfoList;
- PSP_DRVINFO_DETAIL_DATA DriverDetail = calloc(1, RequiredSize);
- if (!DriverDetail)
- goto cleanupDriverInfoList;
- DriverDetail->cbSize = sizeof(*DriverDetail);
- if (!SetupDiGetDriverInfoDetail(DeviceInfoSet, NULL, &DriverInfo, DriverDetail, RequiredSize, &RequiredSize))
- {
- free(DriverDetail);
- goto cleanupDriverInfoList;
- }
- if (!_tcsicmp(DriverDetail->HardwareID, TEXT("wintun")))
- {
- PathStripPath(DriverDetail->InfFileName);
- Logger(LOG_INFO, TEXT("Removing existing driver"));
- if (!SetupUninstallOEMInf(DriverDetail->InfFileName, SUOI_FORCEDELETE, NULL))
- {
- PrintError(LOG_ERR, TEXT("Unable to remove existing driver"));
- Ret = FALSE;
- }
- }
- free(DriverDetail);
- }
-
-cleanupDriverInfoList:
- SetupDiDestroyDriverInfoList(DeviceInfoSet, NULL, SPDIT_CLASSDRIVER);
-cleanupDeviceInfoSet:
- SetupDiDestroyDeviceInfoList(DeviceInfoSet);
- return Ret;
-}
-
-static BOOL
-IsWintunAdapter(_In_ HDEVINFO DeviceInfoSet, _Inout_ SP_DEVINFO_DATA *DeviceInfo)
-{
- BOOL Found = FALSE;
- if (!SetupDiBuildDriverInfoList(DeviceInfoSet, DeviceInfo, SPDIT_COMPATDRIVER))
- return FALSE;
- for (DWORD EnumIndex = 0;; ++EnumIndex)
- {
- SP_DRVINFO_DATA DriverInfo = { .cbSize = sizeof(SP_DRVINFO_DATA) };
- if (!SetupDiEnumDriverInfo(DeviceInfoSet, DeviceInfo, SPDIT_COMPATDRIVER, EnumIndex, &DriverInfo))
- {
- if (GetLastError() == ERROR_NO_MORE_ITEMS)
- break;
- continue;
- }
- DWORD RequiredSize;
- if (SetupDiGetDriverInfoDetail(DeviceInfoSet, DeviceInfo, &DriverInfo, NULL, 0, &RequiredSize) ||
- GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- continue;
- PSP_DRVINFO_DETAIL_DATA DriverDetail = calloc(1, RequiredSize);
- if (!DriverDetail)
- continue;
- DriverDetail->cbSize = sizeof(*DriverDetail);
- if (SetupDiGetDriverInfoDetail(
- DeviceInfoSet, DeviceInfo, &DriverInfo, DriverDetail, RequiredSize, &RequiredSize) &&
- !_tcsicmp(DriverDetail->HardwareID, TEXT("wintun")))
- {
- free(DriverDetail);
- Found = TRUE;
- break;
- }
- free(DriverDetail);
- }
- SetupDiDestroyDriverInfoList(DeviceInfoSet, DeviceInfo, SPDIT_COMPATDRIVER);
- return Found;
-}
-
-#define TUN_IOCTL_FORCE_CLOSE_HANDLES CTL_CODE(51820U, 0x971U, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
-
-static BOOL
-ForceCloseWintunAdapterHandle(_In_ HDEVINFO DeviceInfoSet, _In_ SP_DEVINFO_DATA *DeviceInfo)
-{
- DWORD RequiredBytes;
- if (SetupDiGetDeviceInstanceId(DeviceInfoSet, DeviceInfo, NULL, 0, &RequiredBytes) ||
- GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- return FALSE;
- TCHAR *InstanceId = calloc(sizeof(*InstanceId), RequiredBytes);
- if (!InstanceId)
- return FALSE;
- BOOL Ret = FALSE;
- if (!SetupDiGetDeviceInstanceId(DeviceInfoSet, DeviceInfo, InstanceId, RequiredBytes, &RequiredBytes))
- goto out;
- TCHAR *InterfaceList = NULL;
- for (;;)
- {
- free(InterfaceList);
- if (CM_Get_Device_Interface_List_Size(
- &RequiredBytes, (LPGUID)&GUID_DEVINTERFACE_NET, InstanceId, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) !=
- CR_SUCCESS)
- goto out;
- InterfaceList = calloc(sizeof(*InterfaceList), RequiredBytes);
- if (!InterfaceList)
- goto out;
- CONFIGRET CRet = CM_Get_Device_Interface_List(
- (LPGUID)&GUID_DEVINTERFACE_NET,
- InstanceId,
- InterfaceList,
- RequiredBytes,
- CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
- if (CRet == CR_SUCCESS)
- break;
- if (CRet != CR_BUFFER_SMALL)
- {
- free(InterfaceList);
- goto out;
- }
- }
-
- HANDLE NdisHandle = CreateFile(
- InterfaceList,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL);
- free(InterfaceList);
- if (NdisHandle == INVALID_HANDLE_VALUE)
- goto out;
- Ret = DeviceIoControl(NdisHandle, TUN_IOCTL_FORCE_CLOSE_HANDLES, NULL, 0, NULL, 0, &RequiredBytes, NULL);
- DWORD LastError = GetLastError();
- CloseHandle(NdisHandle);
- SetLastError(LastError);
-out:
- free(InstanceId);
- return Ret;
-}
-
-static BOOL
-DisableWintunAdapters(_In_ HDEVINFO DeviceInfoSet, _Inout_ SP_DEVINFO_DATA_LIST **DisabledAdapters)
-{
- SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
- .InstallFunction = DIF_PROPERTYCHANGE },
- .StateChange = DICS_DISABLE,
- .Scope = DICS_FLAG_GLOBAL };
- BOOL Ret = TRUE;
- DWORD LastError = ERROR_SUCCESS;
- for (DWORD EnumIndex = 0;; ++EnumIndex)
- {
- SP_DEVINFO_DATA_LIST *DeviceNode = malloc(sizeof(SP_DEVINFO_DATA_LIST));
- if (!DeviceNode)
- return FALSE;
- DeviceNode->Data.cbSize = sizeof(SP_DEVINFO_DATA);
- if (!SetupDiEnumDeviceInfo(DeviceInfoSet, EnumIndex, &DeviceNode->Data))
- {
- if (GetLastError() == ERROR_NO_MORE_ITEMS)
- {
- free(DeviceNode);
- break;
- }
- goto cleanupDeviceInfoData;
- }
- if (!IsWintunAdapter(DeviceInfoSet, &DeviceNode->Data))
- goto cleanupDeviceInfoData;
-
- ULONG Status, ProblemCode;
- if (CM_Get_DevNode_Status(&Status, &ProblemCode, DeviceNode->Data.DevInst, 0) != CR_SUCCESS ||
- ((Status & DN_HAS_PROBLEM) && ProblemCode == CM_PROB_DISABLED))
- goto cleanupDeviceInfoData;
-
- Logger(LOG_INFO, TEXT("Force closing all open handles for existing adapter"));
- if (!ForceCloseWintunAdapterHandle(DeviceInfoSet, &DeviceNode->Data))
- PrintError(LOG_WARN, TEXT("Failed to force close adapter handles"));
- Sleep(200);
-
- Logger(LOG_INFO, TEXT("Disabling existing adapter"));
- if (!SetupDiSetClassInstallParams(
- DeviceInfoSet, &DeviceNode->Data, &Params.ClassInstallHeader, sizeof(Params)) ||
- !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DeviceInfoSet, &DeviceNode->Data))
- {
- PrintError(LOG_WARN, TEXT("Unable to disable existing adapter"));
- LastError = LastError ? LastError : GetLastError();
- Ret = FALSE;
- goto cleanupDeviceInfoData;
- }
-
- DeviceNode->Next = *DisabledAdapters;
- *DisabledAdapters = DeviceNode;
- continue;
-
- cleanupDeviceInfoData:
- free(&DeviceNode->Data);
- }
- SetLastError(LastError);
- return Ret;
-}
-
-static BOOL
-RemoveWintunAdapters(_In_ HDEVINFO DeviceInfoSet)
-{
- SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
- .InstallFunction = DIF_REMOVE },
- .Scope = DI_REMOVEDEVICE_GLOBAL };
- BOOL Ret = TRUE;
- DWORD LastError = ERROR_SUCCESS;
- for (DWORD EnumIndex = 0;; ++EnumIndex)
- {
- SP_DEVINFO_DATA DeviceInfo = { .cbSize = sizeof(SP_DEVINFO_DATA) };
- if (!SetupDiEnumDeviceInfo(DeviceInfoSet, EnumIndex, &DeviceInfo))
- {
- if (GetLastError() == ERROR_NO_MORE_ITEMS)
- break;
- continue;
- }
- if (!IsWintunAdapter(DeviceInfoSet, &DeviceInfo))
- continue;
-
- Logger(LOG_INFO, TEXT("Force closing all open handles for existing adapter"));
- if (!ForceCloseWintunAdapterHandle(DeviceInfoSet, &DeviceInfo))
- PrintError(LOG_WARN, TEXT("Failed to force close adapter handles"));
- Sleep(200);
-
- Logger(LOG_INFO, TEXT("Removing existing adapter"));
- if (!SetupDiSetClassInstallParams(DeviceInfoSet, &DeviceInfo, &Params.ClassInstallHeader, sizeof(Params)) ||
- !SetupDiCallClassInstaller(DIF_REMOVE, DeviceInfoSet, &DeviceInfo))
- {
- PrintError(LOG_WARN, TEXT("Unable to remove existing adapter"));
- LastError = LastError ? LastError : GetLastError();
- Ret = FALSE;
- }
- }
- SetLastError(LastError);
- return Ret;
-}
-
-static BOOL
-EnableWintunAdapters(_In_ HDEVINFO DeviceInfoSet, _In_ SP_DEVINFO_DATA_LIST *AdaptersToEnable)
-{
- SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
- .InstallFunction = DIF_PROPERTYCHANGE },
- .StateChange = DICS_ENABLE,
- .Scope = DICS_FLAG_GLOBAL };
- BOOL Ret = TRUE;
- DWORD LastError = ERROR_SUCCESS;
-
- for (SP_DEVINFO_DATA_LIST *DeviceNode = AdaptersToEnable; DeviceNode; DeviceNode = DeviceNode->Next)
- {
- Logger(LOG_INFO, TEXT("Enabling existing adapter"));
- if (!SetupDiSetClassInstallParams(
- DeviceInfoSet, &DeviceNode->Data, &Params.ClassInstallHeader, sizeof(Params)) ||
- !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DeviceInfoSet, &DeviceNode->Data))
- {
- LastError = LastError ? LastError : GetLastError();
- PrintError(LOG_WARN, TEXT("Unable to enable existing adapter"));
- Ret = FALSE;
- }
- }
- SetLastError(LastError);
- return Ret;
-}
-
-BOOL InstallOrUpdate(VOID)
-{
- BOOL Ret = FALSE;
- HDEVINFO DeviceInfoSet = SetupDiGetClassDevsEx(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
- if (DeviceInfoSet == INVALID_HANDLE_VALUE)
- {
- PrintError(LOG_ERR, TEXT("Failed to get present class devices"));
- return FALSE;
- }
- SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL;
- if (IsWintunLoaded())
- {
- DisableWintunAdapters(DeviceInfoSet, &ExistingAdapters);
- Logger(LOG_INFO, TEXT("Waiting for driver to unload from kernel"));
- if (!EnsureWintunUnloaded())
- Logger(LOG_WARN, TEXT("Unable to unload driver, which means a reboot will likely be required"));
- }
- if (!RemoveWintun())
- {
- PrintError(LOG_ERR, TEXT("Failed to uninstall old drivers"));
- goto cleanupAdapters;
- }
- if (!InstallWintun(!!ExistingAdapters))
- {
- PrintError(LOG_ERR, TEXT("Failed to install driver"));
- goto cleanupAdapters;
- }
- Logger(LOG_INFO, TEXT("Installation successful"));
- Ret = TRUE;
-
-cleanupAdapters:
- if (ExistingAdapters)
- {
- EnableWintunAdapters(DeviceInfoSet, ExistingAdapters);
- while (ExistingAdapters)
- {
- SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next;
- free(ExistingAdapters);
- ExistingAdapters = Next;
- }
- }
- SetupDiDestroyDeviceInfoList(DeviceInfoSet);
- return Ret;
-}
-
-BOOL Uninstall(VOID)
-{
- HDEVINFO DeviceInfoSet = SetupDiGetClassDevsEx(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
- if (DeviceInfoSet == INVALID_HANDLE_VALUE)
- {
- PrintError(LOG_ERR, TEXT("Failed to get present class devices"));
- return FALSE;
- }
- RemoveWintunAdapters(DeviceInfoSet);
- BOOL Ret = RemoveWintun();
- if (!Ret)
- PrintError(LOG_ERR, TEXT("Failed to uninstall driver"));
- else
- Logger(LOG_INFO, TEXT("Uninstallation successful"));
- return Ret;
-}
-
-BOOL APIENTRY
-DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
-{
- switch (fdwReason)
- {
- case DLL_PROCESS_ATTACH:
- ResourceModule = hinstDLL;
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- case DLL_PROCESS_DETACH:
- break;
- }
- return TRUE;
-}
diff --git a/installer/installation.h b/installer/installation.h
deleted file mode 100644
index e5ce781..0000000
--- a/installer/installation.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
- */
-
-#pragma once
-
-#include <Windows.h>
-
-typedef enum _LOGGER_LEVEL
-{
- LOG_INFO = 0,
- LOG_WARN,
- LOG_ERR
-} LOGGER_LEVEL;
-typedef VOID (*LoggerFunction)(_In_ LOGGER_LEVEL, _In_ const TCHAR *);
-VOID
-SetLogger(_In_ LoggerFunction NewLogger);
-
-BOOL InstallOrUpdate(VOID);
-BOOL Uninstall(VOID);
-
-extern HINSTANCE ResourceModule;
diff --git a/installer/installer.vcxproj b/installer/installer.vcxproj
deleted file mode 100644
index b40bd90..0000000
--- a/installer/installer.vcxproj
+++ /dev/null
@@ -1,234 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|ARM64">
- <Configuration>Debug</Configuration>
- <Platform>ARM64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|ARM64">
- <Configuration>Release</Configuration>
- <Platform>ARM64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <PropertyGroup Label="Globals">
- <VCProjectVersion>16.0</VCProjectVersion>
- <ProjectGuid>{D19E6354-A643-4ACC-82D5-B2780BB83475}</ProjectGuid>
- <Keyword>Win32Proj</Keyword>
- <RootNamespace>installer</RootNamespace>
- <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
- <ProjectName>installer</ProjectName>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>v142</PlatformToolset>
- <UseDebugLibraries>true</UseDebugLibraries>
- <SpectreMitigation>false</SpectreMitigation>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>v142</PlatformToolset>
- <SpectreMitigation>false</SpectreMitigation>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>v142</PlatformToolset>
- <UseDebugLibraries>true</UseDebugLibraries>
- <SpectreMitigation>false</SpectreMitigation>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>v142</PlatformToolset>
- <UseDebugLibraries>true</UseDebugLibraries>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>v142</PlatformToolset>
- <SpectreMitigation>false</SpectreMitigation>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- <PlatformToolset>v142</PlatformToolset>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Label="Shared">
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project="..\wintun.props" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project="..\wintun.props" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project="..\wintun.props" />
- </ImportGroup>
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project="..\wintun.props" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project="..\wintun.props" />
- </ImportGroup>
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project="..\wintun.props" />
- </ImportGroup>
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup>
- <OutDir>..\$(WintunPlatform)\$(Configuration)\</OutDir>
- <IntDir>..\$(WintunPlatform)\$(Configuration)\installer-intermediate\</IntDir>
- <CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet>
- <RunCodeAnalysis>true</RunCodeAnalysis>
- <LocalDebuggerCommand>rundll32.exe</LocalDebuggerCommand>
- <LocalDebuggerCommandArguments>$(OutDir)$(TargetName)$(TargetExt),InstallWintun</LocalDebuggerCommandArguments>
- <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
- <WixArch Condition="'$(Platform)'=='Win32'">x86</WixArch>
- <WixArch Condition="'$(Platform)'=='x64'">x64</WixArch>
- <WixArch Condition="'$(Platform)'=='ARM64'">arm64</WixArch>
- <WixCandleFlags>$(WixCandleFlags) -nologo -arch $(WixArch) -dWINTUN_PLATFORM=$(WintunPlatform) -dWINTUN_VERSION=$(WintunVersion) -sw1086</WixCandleFlags>
- <WixLightFlags>$(WixLightFlags) -nologo -b output_dir="$(OutDir.TrimEnd('\'))" -spdb -sw1076 -sw1079</WixLightFlags>
- <WixOutputPath>$(OutDir)</WixOutputPath>
- <WixOutputName>wintun</WixOutputName>
- <WixOutputExt>.msm</WixOutputExt>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)'=='Release'">
- <WixOutputPath>..\$(DistributionDir)</WixOutputPath>
- <WixOutputName>wintun-$(WintunPlatform)-$(WintunVersionStr)</WixOutputName>
- </PropertyGroup>
- <ItemDefinitionGroup>
- <ClCompile>
- <PreprocessorDefinitions>_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <PreprocessorDefinitions Condition="Exists('..\$(WintunPlatform)\$(Configuration)\whql\')">HAVE_WHQL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- <ResourceCompile>
- <AdditionalIncludeDirectories>..\$(WintunPlatform)\$(Configuration);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions Condition="Exists('..\$(WintunPlatform)\$(Configuration)\whql\')">HAVE_WHQL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ResourceCompile>
- <Link>
- <ModuleDefinitionFile>exports.def</ModuleDefinitionFile>
- <AdditionalDependencies>newdev.lib;ntdll.lib;Crypt32.lib;Msi.lib;Setupapi.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <SubSystem>Windows</SubSystem>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
- <ClCompile>
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
- </ClCompile>
- <ResourceCompile>
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ResourceCompile>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
- <ClCompile>
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
- </ClCompile>
- <ResourceCompile>
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ResourceCompile>
- <Link>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" />
- <ItemGroup>
- <ClCompile Include="installation.c" />
- <ClCompile Include="msi.c" />
- <ClCompile Include="rundll32.c" />
- </ItemGroup>
- <ItemGroup>
- <ResourceCompile Include="resources.rc" />
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="installation.h" />
- </ItemGroup>
- <ItemGroup>
- <None Include="exports.def" />
- <None Include="installer.wxs" />
- </ItemGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
- <ImportGroup Label="ExtensionTargets">
- </ImportGroup>
- <Import Project="..\wintun.vcxproj.user" Condition="exists('..\wintun.vcxproj.user')" />
- <PropertyGroup>
- <BuildDependsOn>$(BuildDependsOn);TestSignTarget;ProductionSignTarget</BuildDependsOn>
- <MSMDependsOn>$(MSMDependsOn);WixCompile;WixLink;WixTestSign;WixProductionSign</MSMDependsOn>
- <CleanDependsOn>CleanSignTarget;WixClean;$(CleanDependsOn)</CleanDependsOn>
- </PropertyGroup>
- <Target Name="TestSignTarget" Condition="$(SignMode)=='TestSign'" Inputs="$(TargetPath)" Outputs="$(IntermediateOutputPath)$(TargetName).sign">
- <Exec Command="&quot;$(SignToolPath)&quot; sign /sha1 &quot;$(TestCertificate)&quot; /fd sha256 &quot;$(TargetPath)&quot;" />
- <Touch Files="$(IntermediateOutputPath)$(TargetName).sign" AlwaysCreate="true" />
- </Target>
- <Target Name="ProductionSignTarget" Condition="$(SignMode)=='ProductionSign'" Inputs="$(TargetPath)" Outputs="$(IntermediateOutputPath)$(TargetName).sign">
- <Exec Command="&quot;$(SignToolPath)&quot; sign /sha1 &quot;$(ProductionCertificate)&quot; /fd sha256 /tr &quot;$(TimeStampServer)&quot; /td sha256 &quot;$(TargetPath)&quot;" />
- <Touch Files="$(IntermediateOutputPath)$(TargetName).sign" AlwaysCreate="true" />
- </Target>
- <Target Name="CleanSignTarget">
- <Delete Files="$(IntermediateOutputPath)$(TargetName).sign" />
- </Target>
- <Target Name="HashInstallerLibrary" DependsOnTargets="Build">
- <GetFileHash Files="$(OutDir)$(TargetName)$(TargetExt)" Algorithm="SHA256" HashEncoding="hex">
- <Output TaskParameter="Items" ItemName="InstallerLibraryHash" />
- </GetFileHash>
- <PropertyGroup>
- <WixCandleFlags>$(WixCandleFlags) -dINSTALLER_LIBRARY_HASH=@(InstallerLibraryHash->Metadata('FileHash')) -dINSTALLER_LIBRARY_TIME=$([System.IO.File]::GetLastWriteTime('$(OutDir)$(TargetName)$(TargetExt)').Ticks)</WixCandleFlags>
- </PropertyGroup>
- </Target>
- <Target Name="WixCompile" DependsOnTargets="HashInstallerLibrary" Inputs="installer.wxs" Outputs="$(IntDir)installer.wixobj">
- <Exec Command="&quot;$(WIX)bin\candle.exe&quot; $(WixCandleFlags) -out &quot;$(IntDir)installer.wixobj&quot; installer.wxs" />
- </Target>
- <Target Name="WixLink" DependsOnTargets="Build;WixCompile" Inputs="$(IntDir)installer.wixobj;$(OutDir)$(TargetName)$(TargetExt)" Outputs="$(WixOutputPath)$(WixOutputName)$(WixOutputExt)">
- <Exec Command="&quot;$(WIX)bin\light.exe&quot; $(WixLightFlags) -out &quot;$(WixOutputPath)$(WixOutputName)$(WixOutputExt)&quot; &quot;$(IntDir)installer.wixobj&quot;" />
- </Target>
- <Target Name="WixTestSign" Condition="$(SignMode)=='TestSign'" DependsOnTargets="WixLink" Inputs="$(WixOutputPath)$(WixOutputName)$(WixOutputExt)" Outputs="$(IntDir)$(WixOutputName).sign">
- <Exec Command="&quot;$(SignToolPath)&quot; sign /sha1 &quot;$(TestCertificate)&quot; /fd sha256 &quot;$(WixOutputPath)$(WixOutputName)$(WixOutputExt)&quot;" />
- <Touch Files="$(IntDir)$(WixOutputName).sign" AlwaysCreate="true" />
- </Target>
- <Target Name="WixProductionSign" Condition="$(SignMode)=='ProductionSign'" DependsOnTargets="WixLink" Inputs="$(WixOutputPath)$(WixOutputName)$(WixOutputExt)" Outputs="$(IntDir)$(WixOutputName).sign">
- <Exec Command="&quot;$(SignToolPath)&quot; sign /sha1 &quot;$(ProductionCertificate)&quot; /fd sha256 /tr &quot;$(TimeStampServer)&quot; /td sha256 &quot;$(WixOutputPath)$(WixOutputName)$(WixOutputExt)&quot;" />
- <Touch Files="$(IntDir)$(WixOutputName).sign" AlwaysCreate="true" />
- </Target>
- <Target Name="WixClean">
- <Delete Files="$(IntDir)installer.wixobj;$(WixOutputPath)$(WixOutputName)$(WixOutputExt);$(IntDir)$(WixOutputName).sign" />
- </Target>
- <Target Name="MSM" DependsOnTargets="$(MSMDependsOn)" />
-</Project> \ No newline at end of file
diff --git a/installer/installer.vcxproj.filters b/installer/installer.vcxproj.filters
deleted file mode 100644
index e9d0282..0000000
--- a/installer/installer.vcxproj.filters
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup>
- <Filter Include="Source Files">
- <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
- <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
- </Filter>
- <Filter Include="Header Files">
- <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
- <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
- </Filter>
- <Filter Include="Resource Files">
- <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
- <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
- </Filter>
- <Filter Include="MSM">
- <UniqueIdentifier>{1ae72c39-669d-49e5-85c7-f6956595e079}</UniqueIdentifier>
- </Filter>
- </ItemGroup>
- <ItemGroup>
- <ClCompile Include="msi.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="installation.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="rundll32.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- </ItemGroup>
- <ItemGroup>
- <ResourceCompile Include="resources.rc">
- <Filter>Resource Files</Filter>
- </ResourceCompile>
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="installation.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- </ItemGroup>
- <ItemGroup>
- <None Include="exports.def">
- <Filter>Source Files</Filter>
- </None>
- <None Include="installer.wxs">
- <Filter>MSM</Filter>
- </None>
- </ItemGroup>
-</Project> \ No newline at end of file
diff --git a/installer/installer.wxs b/installer/installer.wxs
deleted file mode 100644
index 1883618..0000000
--- a/installer/installer.wxs
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- SPDX-License-Identifier: GPL-2.0
-
- Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
--->
-<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
- <Module Id="wintun" Language="0" Version="$(var.WINTUN_VERSION)">
- <Package
- Id="c28309d9-1954-4f2d-a7d1-228850092460"
- Description="Wintun Userspace Tunnel"
- Manufacturer="WireGuard LLC"
- InstallerVersion="200"
- InstallPrivileges="elevated"
- InstallScope="perMachine"
- ReadOnly="yes" />
-
- <Directory Id="TARGETDIR" Name="SourceDir">
- <Component Guid="b668d4c7-abb3-485a-b8df-d34200489a43">
- <RegistryValue
- Root="HKLM"
- Key="SOFTWARE\Wintun"
- Type="integer"
- Value="1"
- KeyPath="yes" />
- </Component>
- </Directory>
-
- <Property Id="WintunInstallerHash" Value="$(var.INSTALLER_LIBRARY_HASH)" SuppressModularization="yes" />
- <Property Id="WintunInstallerBuildtime" Value="$(var.INSTALLER_LIBRARY_TIME)" SuppressModularization="yes" />
- <Property Id="WintunVersion" Value="$(var.WINTUN_VERSION)" SuppressModularization="yes" />
-
- <Binary Id="installer.dll" SourceFile="!(bindpath.output_dir)installer.dll" />
- <CustomAction Id="EvaluateWintun" SuppressModularization="yes" BinaryKey="installer.dll" DllEntry="MsiEvaluate" Execute="immediate" />
- <CustomAction Id="ProcessWintun" SuppressModularization="yes" BinaryKey="installer.dll" DllEntry="MsiProcess" Execute="deferred" Impersonate="no" />
- <InstallExecuteSequence>
- <Custom Action="EvaluateWintun" After="CostFinalize" />
- <Custom Action="ProcessWintun" After="InstallFiles" />
- </InstallExecuteSequence>
-
- <?if $(var.WINTUN_PLATFORM) = "x86"?>
- <CustomAction Id="WoW64Unsupported" Error="You are attempting to install the 32-bit variant of [ProductName] on a 64-bit operating system, which is not supported. Please install the 64-bit variant instead." />
- <InstallExecuteSequence>
- <Custom Action="WoW64Unsupported" After="LaunchConditions"><![CDATA[VersionNT64]]></Custom>
- </InstallExecuteSequence>
- <InstallUISequence>
- <Custom Action="WoW64Unsupported" After="LaunchConditions"><![CDATA[VersionNT64]]></Custom>
- </InstallUISequence>
- <?endif?>
- </Module>
-</Wix>
diff --git a/installer/msi.c b/installer/msi.c
deleted file mode 100644
index 348ef42..0000000
--- a/installer/msi.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
- */
-
-#include "installation.h"
-#include <Windows.h>
-#include <Msi.h>
-#include <MsiQuery.h>
-#include <tchar.h>
-
-#pragma warning(disable : 4100) /* unreferenced formal parameter */
-
-static MSIHANDLE MsiHandle;
-
-#define ANCHOR_COMPONENT TEXT("{B668D4C7-ABB3-485A-B8DF-D34200489A43}")
-#define PROCESS_ACTION TEXT("ProcessWintun")
-#define ACTION_INSTALL TEXT("/WintunAction=Install")
-#define ACTION_INSTALL_SEPERATOR TEXT('-')
-#define ACTION_INSTALL_SEPERATORS TEXT("-%s-%s-%s")
-#define ACTION_UNINSTALL TEXT("/WintunAction=Uninstall")
-#define PROPERTY_INSTALLER_HASH TEXT("WintunInstallerHash")
-#define PROPERTY_INSTALLER_BUILDTIME TEXT("WintunInstallerBuildtime")
-#define PROPERTY_VERSION TEXT("WintunVersion")
-#define REGKEY_WINTUN TEXT("Software\\Wintun")
-#define REGKEY_INSTALLER_HASH TEXT("InstallerHash")
-#define REGKEY_INSTALLER_BUILDTIME TEXT("InstallerBuildtime")
-#define REGKEY_VERSION TEXT("Version")
-
-static VOID
-MsiLogger(_In_ LOGGER_LEVEL Level, _In_ const TCHAR *LogLine)
-{
- MSIHANDLE Record = MsiCreateRecord(2);
- if (!Record)
- return;
- TCHAR *Template;
- INSTALLMESSAGE Type;
- switch (Level)
- {
- case LOG_INFO:
- Template = TEXT("Wintun: [1]");
- Type = INSTALLMESSAGE_INFO;
- break;
- case LOG_WARN:
- Template = TEXT("Wintun warning: [1]");
- Type = INSTALLMESSAGE_INFO;
- break;
- case LOG_ERR:
- Template = TEXT("Wintun error: [1]");
- Type = INSTALLMESSAGE_ERROR;
- break;
- default:
- goto cleanup;
- }
- MsiRecordSetString(Record, 0, Template);
- MsiRecordSetString(Record, 1, LogLine);
- MsiProcessMessage(MsiHandle, Type, Record);
-cleanup:
- MsiCloseHandle(Record);
-}
-
-static BOOL
-IsInstalling(_In_ INSTALLSTATE InstallState, _In_ INSTALLSTATE ActionState)
-{
- return INSTALLSTATE_LOCAL == ActionState || INSTALLSTATE_SOURCE == ActionState ||
- (INSTALLSTATE_DEFAULT == ActionState &&
- (INSTALLSTATE_LOCAL == InstallState || INSTALLSTATE_SOURCE == InstallState));
-}
-
-static BOOL
-IsReInstalling(_In_ INSTALLSTATE InstallState, _In_ INSTALLSTATE ActionState)
-{
- return (INSTALLSTATE_LOCAL == ActionState || INSTALLSTATE_SOURCE == ActionState ||
- INSTALLSTATE_DEFAULT == ActionState) &&
- (INSTALLSTATE_LOCAL == InstallState || INSTALLSTATE_SOURCE == InstallState);
-}
-
-static BOOL
-IsUninstalling(_In_ INSTALLSTATE InstallState, _In_ INSTALLSTATE ActionState)
-{
- return (INSTALLSTATE_ABSENT == ActionState || INSTALLSTATE_REMOVED == ActionState) &&
- (INSTALLSTATE_LOCAL == InstallState || INSTALLSTATE_SOURCE == InstallState);
-}
-
-static UINT64
-ParseVersion(_In_ const TCHAR *Version)
-{
- ULONG Major = 0, Minor = 0, Revision = 0, Build = 0;
- _stscanf_s(Version, TEXT("%u.%u.%u.%u"), &Major, &Minor, &Revision, &Build);
- return ((UINT64)Major << 48) | ((UINT64)Minor << 32) | ((UINT64)Revision << 16) | ((UINT64)Build << 0);
-}
-
-_Success_(return )
-static BOOL
-Newer(_In_ MSIHANDLE Handle, _In_ BOOL SkipHashComparison, _Out_ TCHAR *InstallAction, _In_ SIZE_T InstallActionSize)
-{
- INT64 NewTime, OldTime;
- UINT64 NewVersion, OldVersion;
- TCHAR NewHash[0x100], OldHash[0x100], NewTimeString[0x100], OldTimeString[0x100], NewVersionString[0x100],
- OldVersionString[0x100];
- DWORD Size, Type;
- HKEY Key;
- BOOL Ret = TRUE;
-
- Size = _countof(NewHash);
- if (MsiGetProperty(Handle, PROPERTY_INSTALLER_HASH, NewHash, &Size) != ERROR_SUCCESS)
- return FALSE;
- Size = _countof(NewTimeString);
- if (MsiGetProperty(Handle, PROPERTY_INSTALLER_BUILDTIME, NewTimeString, &Size) != ERROR_SUCCESS)
- return FALSE;
- NewTime = _tstoll(NewTimeString);
- Size = _countof(NewVersionString);
- if (MsiGetProperty(Handle, PROPERTY_VERSION, NewVersionString, &Size) != ERROR_SUCCESS)
- return FALSE;
- NewVersion = ParseVersion(NewVersionString);
-
- _stprintf_s(
- InstallAction,
- InstallActionSize,
- ACTION_INSTALL ACTION_INSTALL_SEPERATORS,
- NewHash,
- NewTimeString,
- NewVersionString);
-
- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WINTUN, 0, KEY_READ, &Key) != ERROR_SUCCESS)
- return TRUE;
- Size = sizeof(OldHash);
- if (RegQueryValueEx(Key, REGKEY_INSTALLER_HASH, NULL, &Type, (LPBYTE)OldHash, &Size) != ERROR_SUCCESS ||
- Type != REG_SZ)
- goto cleanup;
- Size = sizeof(OldTimeString);
- if (RegQueryValueEx(Key, REGKEY_INSTALLER_BUILDTIME, NULL, &Type, (LPBYTE)OldTimeString, &Size) != ERROR_SUCCESS ||
- Type != REG_SZ)
- goto cleanup;
- OldTime = _tstoll(OldTimeString);
- Size = sizeof(OldVersionString);
- if (RegQueryValueEx(Key, REGKEY_VERSION, NULL, &Type, (LPBYTE)OldVersionString, &Size) != ERROR_SUCCESS ||
- Type != REG_SZ)
- goto cleanup;
- OldVersion = ParseVersion(OldVersionString);
-
- Ret = NewVersion >= OldVersion && NewTime >= OldTime && (SkipHashComparison || _tcscmp(NewHash, OldHash));
-
-cleanup:
- RegCloseKey(Key);
- return Ret;
-}
-
-UINT __stdcall MsiEvaluate(MSIHANDLE Handle)
-{
- MsiHandle = Handle;
- SetLogger(MsiLogger);
- BOOL IsComInitialized = SUCCEEDED(CoInitialize(NULL));
- UINT Ret = ERROR_INSTALL_FAILURE;
- MSIHANDLE View = 0, Record = 0, Database = MsiGetActiveDatabase(Handle);
- if (!Database)
- goto cleanup;
- Ret = MsiDatabaseOpenView(
- Database, TEXT("SELECT `Component` FROM `Component` WHERE `ComponentId` = '" ANCHOR_COMPONENT "'"), &View);
- if (Ret != ERROR_SUCCESS)
- goto cleanup;
- Ret = MsiViewExecute(View, 0);
- if (Ret != ERROR_SUCCESS)
- goto cleanup;
- Ret = MsiViewFetch(View, &Record);
- if (Ret != ERROR_SUCCESS)
- goto cleanup;
- TCHAR ComponentName[0x1000];
- DWORD Size = _countof(ComponentName);
- Ret = MsiRecordGetString(Record, 1, ComponentName, &Size);
- if (Ret != ERROR_SUCCESS)
- goto cleanup;
- INSTALLSTATE InstallState, ActionState;
- Ret = MsiGetComponentState(Handle, ComponentName, &InstallState, &ActionState);
- if (Ret != ERROR_SUCCESS)
- goto cleanup;
- TCHAR InstallAction[0x400];
- if ((IsReInstalling(InstallState, ActionState) || IsInstalling(InstallState, ActionState)) &&
- Newer(Handle, IsReInstalling(InstallState, ActionState), InstallAction, _countof(InstallAction)))
- Ret = MsiSetProperty(Handle, PROCESS_ACTION, InstallAction);
- else if (IsUninstalling(InstallState, ActionState))
- Ret = MsiSetProperty(Handle, PROCESS_ACTION, ACTION_UNINSTALL);
- if (Ret != ERROR_SUCCESS)
- goto cleanup;
-
- Ret = MsiDoAction(Handle, TEXT("DisableRollback"));
-
-cleanup:
- if (View)
- MsiCloseHandle(View);
- if (Record)
- MsiCloseHandle(Record);
- if (Database)
- MsiCloseHandle(Database);
- if (IsComInitialized)
- CoUninitialize();
- return Ret;
-}
-
-static BOOL
-WriteRegKeys(_In_ TCHAR *Values)
-{
- TCHAR *Hash, *Time, *Version;
- Hash = Values;
- Time = _tcschr(Hash, ACTION_INSTALL_SEPERATOR);
- if (!Time)
- return FALSE;
- *Time++ = TEXT('\0');
- Version = _tcschr(Time, ACTION_INSTALL_SEPERATOR);
- if (!Version)
- return FALSE;
- *Version++ = TEXT('\0');
-
- HKEY Key;
- if (RegCreateKeyEx(
- HKEY_LOCAL_MACHINE, REGKEY_WINTUN, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &Key, NULL) !=
- ERROR_SUCCESS)
- return FALSE;
- BOOL Ret =
- RegSetValueEx(
- Key, REGKEY_INSTALLER_HASH, 0, REG_SZ, (LPBYTE)Hash, ((DWORD)_tcslen(Hash) + 1) * sizeof(*Hash)) ==
- ERROR_SUCCESS &&
- RegSetValueEx(
- Key, REGKEY_INSTALLER_BUILDTIME, 0, REG_SZ, (LPBYTE)Time, ((DWORD)_tcslen(Time) + 1) * sizeof(*Time)) ==
- ERROR_SUCCESS &&
- RegSetValueEx(
- Key, REGKEY_VERSION, 0, REG_SZ, (LPBYTE)Version, ((DWORD)_tcslen(Version) + 1) * sizeof(*Version)) ==
- ERROR_SUCCESS;
- RegCloseKey(Key);
- return Ret;
-}
-
-UINT __stdcall MsiProcess(MSIHANDLE Handle)
-{
- MsiHandle = Handle;
- SetLogger(MsiLogger);
- BOOL IsComInitialized = SUCCEEDED(CoInitialize(NULL));
- DWORD LastError = ERROR_SUCCESS;
- BOOL Ret = FALSE;
- TCHAR Value[0x1000], *RegValues;
- DWORD Size = _countof(Value);
- LastError = MsiGetProperty(Handle, TEXT("CustomActionData"), Value, &Size);
- if (LastError != ERROR_SUCCESS)
- goto cleanup;
- if ((RegValues = _tcschr(Value, ACTION_INSTALL_SEPERATOR)) != NULL)
- *RegValues++ = TEXT('\0');
- if (!_tcscmp(Value, ACTION_INSTALL))
- {
- Ret = InstallOrUpdate();
- if (RegValues && Ret)
- Ret = WriteRegKeys(RegValues);
- }
- else if (!_tcscmp(Value, ACTION_UNINSTALL))
- {
- Ret = Uninstall();
- if (Ret)
- RegDeleteKeyEx(HKEY_LOCAL_MACHINE, REGKEY_WINTUN, 0, 0);
- }
- else
- Ret = TRUE;
- LastError = GetLastError();
-cleanup:
- if (IsComInitialized)
- CoUninitialize();
- return Ret ? ERROR_SUCCESS : LastError ? LastError : ERROR_INSTALL_FAILED;
-}
diff --git a/installer/resources.rc b/installer/resources.rc
deleted file mode 100644
index fd73afd..0000000
--- a/installer/resources.rc
+++ /dev/null
@@ -1,48 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
- */
-
-#include <windows.h>
-#include <ntverp.h>
-
-wintun.cat RCDATA "wintun\\wintun.cat"
-wintun.inf RCDATA "wintun\\wintun.inf"
-wintun.sys RCDATA "wintun\\wintun.sys"
-
-#ifdef HAVE_WHQL
-wintun-whql.cat RCDATA "whql\\wintun.cat"
-wintun-whql.inf RCDATA "whql\\wintun.inf"
-wintun-whql.sys RCDATA "whql\\wintun.sys"
-#endif
-
-#define STRINGIZE(x) #x
-#define EXPAND(x) STRINGIZE(x)
-
-VS_VERSION_INFO VERSIONINFO
-FILEVERSION WINTUN_VERSION_MAJ, WINTUN_VERSION_MIN, 0, 0
-PRODUCTVERSION WINTUN_VERSION_MAJ, WINTUN_VERSION_MIN, 0, 0
-FILEOS VOS_NT_WINDOWS32
-FILETYPE VFT_DLL
-FILESUBTYPE VFT2_UNKNOWN
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "CompanyName", "WireGuard LLC"
- VALUE "FileDescription", "Wintun Installer Library"
- VALUE "FileVersion", EXPAND(WINTUN_VERSION_STR)
- VALUE "InternalName", "installer.dll"
- VALUE "LegalCopyright", "Copyright \xa9 2018-2019 WireGuard LLC. All Rights Reserved."
- VALUE "OriginalFilename", "installer.dll"
- VALUE "ProductName", "Wintun Driver"
- VALUE "ProductVersion", EXPAND(WINTUN_VERSION_STR)
- VALUE "Comments", "https://www.wintun.net/"
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
diff --git a/installer/rundll32.c b/installer/rundll32.c
deleted file mode 100644
index 17295e0..0000000
--- a/installer/rundll32.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
- */
-
-#include "installation.h"
-#include <Windows.h>
-#include <tlhelp32.h>
-#include <stdio.h>
-#include <conio.h>
-#include <tchar.h>
-
-#pragma warning(disable : 4100) /* unreferenced formal parameter */
-
-static VOID
-ConsoleLogger(_In_ LOGGER_LEVEL Level, _In_ const TCHAR *LogLine)
-{
- TCHAR *Template;
- switch (Level)
- {
- case LOG_INFO:
- Template = TEXT("[+] %s\n");
- break;
- case LOG_WARN:
- Template = TEXT("[-] %s\n");
- break;
- case LOG_ERR:
- Template = TEXT("[!] %s\n");
- break;
- default:
- return;
- }
- _ftprintf(stdout, Template, LogLine);
-}
-
-static BOOL ElevateToSystem(VOID)
-{
- HANDLE CurrentProcessToken, ThreadToken, ProcessSnapshot, WinlogonProcess, WinlogonToken, DuplicatedToken;
- PROCESSENTRY32 ProcessEntry = { .dwSize = sizeof(PROCESSENTRY32) };
- BOOL Ret;
- DWORD LastError = ERROR_SUCCESS;
- TOKEN_PRIVILEGES Privileges = { .PrivilegeCount = 1, .Privileges = { { .Attributes = SE_PRIVILEGE_ENABLED } } };
- CHAR LocalSystemSid[0x400];
- DWORD RequiredBytes = sizeof(LocalSystemSid);
- struct
- {
- TOKEN_USER MaybeLocalSystem;
- CHAR LargeEnoughForLocalSystem[0x400];
- } TokenUserBuffer;
-
- Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes);
- LastError = GetLastError();
- if (!Ret)
- goto cleanup;
- Ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken);
- LastError = GetLastError();
- if (!Ret)
- goto cleanup;
- Ret =
- GetTokenInformation(CurrentProcessToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes);
- LastError = GetLastError();
- CloseHandle(CurrentProcessToken);
- if (!Ret)
- goto cleanup;
- if (EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
- return TRUE;
- Ret = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Privileges.Privileges[0].Luid);
- LastError = GetLastError();
- if (!Ret)
- goto cleanup;
- ProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
- LastError = GetLastError();
- if (ProcessSnapshot == INVALID_HANDLE_VALUE)
- goto cleanup;
- for (Ret = Process32First(ProcessSnapshot, &ProcessEntry); Ret; Ret = Process32Next(ProcessSnapshot, &ProcessEntry))
- {
- if (_tcsicmp(ProcessEntry.szExeFile, TEXT("winlogon.exe")))
- continue;
- RevertToSelf();
- Ret = ImpersonateSelf(SecurityImpersonation);
- LastError = GetLastError();
- if (!Ret)
- continue;
- Ret = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &ThreadToken);
- LastError = GetLastError();
- if (!Ret)
- continue;
- Ret = AdjustTokenPrivileges(ThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL);
- LastError = GetLastError();
- CloseHandle(ThreadToken);
- if (!Ret)
- continue;
-
- WinlogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessEntry.th32ProcessID);
- LastError = GetLastError();
- if (!WinlogonProcess)
- continue;
- Ret = OpenProcessToken(WinlogonProcess, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &WinlogonToken);
- LastError = GetLastError();
- CloseHandle(WinlogonProcess);
- if (!Ret)
- continue;
- Ret = DuplicateToken(WinlogonToken, SecurityImpersonation, &DuplicatedToken);
- LastError = GetLastError();
- CloseHandle(WinlogonToken);
- if (!Ret)
- continue;
- if (!GetTokenInformation(DuplicatedToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes))
- goto next;
- if (SetLastError(ERROR_ACCESS_DENIED), !EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
- goto next;
- if (!SetThreadToken(NULL, DuplicatedToken))
- goto next;
- CloseHandle(DuplicatedToken);
- CloseHandle(ProcessSnapshot);
- SetLastError(ERROR_SUCCESS);
- return TRUE;
- next:
- LastError = GetLastError();
- CloseHandle(DuplicatedToken);
- }
- RevertToSelf();
- CloseHandle(ProcessSnapshot);
-cleanup:
- SetLastError(LastError);
- return FALSE;
-}
-
-static VOID
-RunAsAdministrator(HWND hwnd, TCHAR *Verb, int nCmdShow)
-{
- TOKEN_ELEVATION Elevation;
- DWORD Required;
- HANDLE CurrentProcessToken;
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken))
- return;
- BOOL Ret = GetTokenInformation(CurrentProcessToken, TokenElevation, &Elevation, sizeof(Elevation), &Required);
- CloseHandle(CurrentProcessToken);
- if (!Ret)
- return;
- if (Elevation.TokenIsElevated)
- return;
- TCHAR ProcessPath[MAX_PATH], DllPath[MAX_PATH];
- if (!GetModuleFileName(NULL, ProcessPath, _countof(ProcessPath)) ||
- !GetModuleFileName(ResourceModule, DllPath, _countof(DllPath)))
- return;
- TCHAR Params[0x1000];
- _stprintf_s(Params, _countof(Params), TEXT("\"%s\",%s"), DllPath, Verb);
- ShellExecute(hwnd, TEXT("runas"), ProcessPath, Params, NULL, nCmdShow);
- exit(0);
-}
-
-static VOID
-Do(BOOL Install, BOOL ShowConsole)
-{
- if (ShowConsole)
- {
- AllocConsole();
- FILE *Stream;
- freopen_s(&Stream, "CONOUT$", "w", stdout);
- }
- SetLogger(ConsoleLogger);
- ElevateToSystem();
- Install ? InstallOrUpdate() : Uninstall();
- RevertToSelf();
- _putws(TEXT("\nPress any key to close . . ."));
- (VOID) _getch();
-}
-
-VOID __stdcall InstallWintun(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
-{
- RunAsAdministrator(hwnd, TEXT(__FUNCTION__), nCmdShow);
- Do(TRUE, !!nCmdShow);
-}
-
-VOID __stdcall UninstallWintun(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
-{
- RunAsAdministrator(hwnd, TEXT(__FUNCTION__), nCmdShow);
- Do(FALSE, !!nCmdShow);
-} \ No newline at end of file
diff --git a/msi-example/README.md b/msi-example/README.md
deleted file mode 100644
index 4197de7..0000000
--- a/msi-example/README.md
+++ /dev/null
@@ -1,38 +0,0 @@
-## Example Standalone MSI
-
-The best way to include Wintun in your software is by including the MSMs in your final MSI,
-as described by [the main README](../README.md). However, if you're stuck with an installation
-system such as NSIS, which can not bundle MSM files, then you must build your own MSI, which
-NSIS can then invoke. ***Do not use an MSI from elsewhere. You must build it yourself and
-distribute only the MSI that you yourself build.*** Otherwise different projects will wind up
-uninstalling each other by accident and disturbing the MSM reference counting. The steps in
-this file should only be taken if you're not able to include an MSM into a MSI, something that
-is easily possible using WiX or most commercial installation solutions.
-
-This `msi-example` folder contains a WiX skeleton and a build script that handles all
-dependencies. use it as follows below.
-
-#### Steps:
-
-1. Generate a UUID using uuidgen.exe and replace `{{{FIXED 64BIT UUID}}}` in exampletun.wxs
-with that UUID. For the life time of your entire product, even across versions, do not change
-that UUID.
-
-2. Generate another UUID using uuidgen.exe and replace `{{{FIXED 32BIT UUID}}}` in
-exampletun.wxs with that UUID. For the life time of your entire product, even across versions,
-do not change that UUID.
-
-3. Go to [Wintun.net](https://www.wintun.net/) and look at what the latest version is (`0.6`,
-for example). Replace `{{{VERSION}}}` in build.bat with that version.
-
-4. Download the amd64 MSM from [Wintun.net](https://www.wintun.net/) and compute its SHA2-256
-sum in all lowercase hex digits using `CertUtil -hashfile "path/to/file" SHA256`, and replace
-`{{{64BIT HASH}}}` in build.bat with that value.
-
-5. Download the x86 MSM from [Wintun.net](https://www.wintun.net/) and compute its SHA2-256
-sum in all lowercase hex digits using `CertUtil -hashfile "path/to/file" SHA256`, and replace
-`{{{32BIT HASH}}}` in build.bat with that value.
-
-6. Run build.bat.
-
-7. Distribute dist\exampletun-*.msi for your own software only.
diff --git a/msi-example/build.bat b/msi-example/build.bat
deleted file mode 100644
index cbf2570..0000000
--- a/msi-example/build.bat
+++ /dev/null
@@ -1,60 +0,0 @@
-@echo off
-rem SPDX-License-Identifier: GPL-2.0
-rem Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
-
-setlocal
-set PATHEXT=.exe
-set BUILDDIR=%~dp0
-cd /d %BUILDDIR% || exit /b 1
-
-set WIX_CANDLE_FLAGS=-nologo
-set WIX_LIGHT_FLAGS=-nologo -spdb -sice:ICE71 -sice:ICE61
-
-if exist .deps\prepared goto :build
-:installdeps
- rmdir /s /q .deps 2> NUL
- mkdir .deps || goto :error
- cd .deps || goto :error
- call :download wintun-x86.msm https://www.wintun.net/builds/wintun-x86-{{{VERSION}}}.msm {{{32BIT HASH}}} || goto :error
- call :download wintun-amd64.msm https://www.wintun.net/builds/wintun-amd64-{{{VERSION}}}.msm {{{64BIT HASH}}} || goto :error
- call :download wix-binaries.zip http://wixtoolset.org/downloads/v3.14.0.2812/wix314-binaries.zip 923892298f37514622c58cbbd9c2cadf2822d9bb53df8ee83aaeb05280777611 || goto :error
- echo [+] Extracting wix-binaries.zip
- mkdir wix\bin || goto :error
- tar -xf wix-binaries.zip -C wix\bin || goto :error
- echo [+] Cleaning up wix-binaries.zip
- del wix-binaries.zip || goto :error
- copy /y NUL prepared > NUL || goto :error
- cd .. || goto :error
-
-:build
- set WIX=%BUILDDIR%.deps\wix\
- call :msi x86 i686 x86 || goto :error
- call :msi amd64 x86_64 x64 || goto :error
- if exist ..\sign.bat call ..\sign.bat
- if "%SigningCertificate%"=="" goto :success
- if "%TimestampServer%"=="" goto :success
- echo [+] Signing
- signtool sign /sha1 "%SigningCertificate%" /fd sha256 /tr "%TimestampServer%" /td sha256 /d "ExampleTun Setup" "dist\exampletun-*.msi" || goto :error
-
-:success
- echo [+] Success.
- exit /b 0
-
-:download
- echo [+] Downloading %1
- curl -#fLo %1 %2 || exit /b 1
- echo [+] Verifying %1
- for /f %%a in ('CertUtil -hashfile %1 SHA256 ^| findstr /r "^[0-9a-f]*$"') do if not "%%a"=="%~3" exit /b 1
- goto :eof
-
-:msi
- if not exist "%~1" mkdir "%~1"
- echo [+] Compiling %1
- "%WIX%bin\candle" %WIX_CANDLE_FLAGS% -dEXAMPLETUN_PLATFORM="%~1" -out "%~1\exampletun.wixobj" -arch %3 exampletun.wxs || exit /b %errorlevel%
- echo [+] Linking %1
- "%WIX%bin\light" %WIX_LIGHT_FLAGS% -out "dist\exampletun-%~1.msi" "%~1\exampletun.wixobj" || exit /b %errorlevel%
- goto :eof
-
-:error
- echo [-] Failed with error #%errorlevel%.
- cmd /c exit %errorlevel%
diff --git a/msi-example/exampletun.wxs b/msi-example/exampletun.wxs
deleted file mode 100644
index d5faf52..0000000
--- a/msi-example/exampletun.wxs
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- SPDX-License-Identifier: GPL-2.0
-
- Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
--->
-<?if $(var.EXAMPLETUN_PLATFORM) = "amd64"?>
- <?define UpgradeCode = "{{{FIXED 64BIT UUID}}}"?>
-<?elseif $(var.EXAMPLETUN_PLATFORM) = "x86"?>
- <?define UpgradeCode = "{{{FIXED 32BIT UUID}}}"?>
-<?else?>
- <?error Unknown platform ?>
-<?endif?>
-
-
-<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
- <Product
- Id="*"
- Name="ExampleTun"
- Language="1033"
- Version="1.0"
- Manufacturer="Acme Widgets Corporation"
- UpgradeCode="$(var.UpgradeCode)">
- <Package
- InstallerVersion="400"
- Compressed="yes"
- InstallScope="perMachine"
- Description="ExampleTun: Acme Widget's Distribution of Wintun"
- ReadOnly="yes" />
-
- <MediaTemplate EmbedCab="yes" CompressionLevel="high" />
-
- <Property Id="ARPNOMODIFY" Value="yes" />
- <Property Id="ARPSYSTEMCOMPONENT" Value="1" />
- <Property Id="DISABLEADVTSHORTCUTS" Value="yes" />
- <Property Id="DISABLEROLLBACK" Value="yes" />
- <Property Id="MSIDISABLERMRESTART" Value="1" />
- <Property Id="MSIRMSHUTDOWN" Value="1" />
-
- <MajorUpgrade
- AllowDowngrades="no"
- AllowSameVersionUpgrades="yes"
- DowngradeErrorMessage="A newer version of [ProductName] is already installed."
- Schedule="afterInstallExecute" />
-
- <Directory Id="TARGETDIR" Name="SourceDir">
- <Merge Id="WintunMergeModule" Language="0" DiskId="1" SourceFile=".deps\wintun-$(var.EXAMPLETUN_PLATFORM).msm" />
- </Directory>
-
- <Feature Id="WintunFeature" Title="Wintun" Level="1">
- <MergeRef Id="WintunMergeModule" />
- </Feature>
- </Product>
-</Wix>
diff --git a/prebuilt-binaries-license.txt b/prebuilt-binaries-license.txt
new file mode 100644
index 0000000..9ed5018
--- /dev/null
+++ b/prebuilt-binaries-license.txt
@@ -0,0 +1,84 @@
+Prebuilt Binaries License
+-------------------------
+
+1. DEFINITIONS. "Software" means the precise contents of the "wintun.dll"
+ files that are included in the .zip file that contains this document as
+ downloaded from wintun.net/builds.
+
+2. LICENSE GRANT. WireGuard LLC grants to you a non-exclusive and
+ non-transferable right to use Software for lawful purposes under certain
+ obligations and limited rights as set forth in this agreement.
+
+3. RESTRICTIONS. Software is owned and copyrighted by WireGuard LLC. It is
+ licensed, not sold. Title to Software and all associated intellectual
+ property rights are retained by WireGuard. You must not:
+ a. reverse engineer, decompile, disassemble, extract from, or otherwise
+ modify the Software;
+ b. modify or create derivative work based upon Software in whole or in
+ parts, except insofar as only the API interfaces of the "wintun.h" file
+ distributed alongside the Software (the "Permitted API") are used;
+ c. remove any proprietary notices, labels, or copyrights from the Software;
+ d. resell, redistribute, lease, rent, transfer, sublicense, or otherwise
+ transfer rights of the Software without the prior written consent of
+ WireGuard LLC, except insofar as the Software is distributed alongside
+ other software that uses the Software only via the Permitted API;
+ e. use the name of WireGuard LLC, the WireGuard project, the Wintun
+ project, or the names of its contributors to endorse or promote products
+ derived from the Software without specific prior written consent.
+
+4. LIMITED WARRANTY. THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF
+ ANY KIND. WIREGUARD LLC HEREBY EXCLUDES AND DISCLAIMS ALL IMPLIED OR
+ STATUTORY WARRANTIES, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS
+ FOR A PARTICULAR PURPOSE, QUALITY, NON-INFRINGEMENT, TITLE, RESULTS,
+ EFFORTS, OR QUIET ENJOYMENT. THERE IS NO WARRANTY THAT THE PRODUCT WILL BE
+ ERROR-FREE OR WILL FUNCTION WITHOUT INTERRUPTION. YOU ASSUME THE ENTIRE
+ RISK FOR THE RESULTS OBTAINED USING THE PRODUCT. TO THE EXTENT THAT
+ WIREGUARD LLC MAY NOT DISCLAIM ANY WARRANTY AS A MATTER OF APPLICABLE LAW,
+ THE SCOPE AND DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER
+ SUCH LAW. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
+ WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR
+ A PARTICULAR PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE
+ EXTENT THAT THESE DISCLAIMERS ARE HELD TO BE LEGALLY INVALID.
+
+5. LIMITATION OF LIABILITY. To the extent not prohibited by law, in no event
+ WireGuard LLC or any third-party-developer will be liable for any lost
+ revenue, profit or data or for special, indirect, consequential, incidental
+ or punitive damages, however caused regardless of the theory of liability,
+ arising out of or related to the use of or inability to use Software, even
+ if WireGuard LLC has been advised of the possibility of such damages.
+ Solely you are responsible for determining the appropriateness of using
+ Software and accept full responsibility for all risks associated with its
+ exercise of rights under this agreement, including but not limited to the
+ risks and costs of program errors, compliance with applicable laws, damage
+ to or loss of data, programs or equipment, and unavailability or
+ interruption of operations. The foregoing limitations will apply even if
+ the above stated warranty fails of its essential purpose. You acknowledge,
+ that it is in the nature of software that software is complex and not
+ completely free of errors. In no event shall WireGuard LLC or any
+ third-party-developer be liable to you under any theory for any damages
+ suffered by you or any user of Software or for any special, incidental,
+ indirect, consequential or similar damages (including without limitation
+ damages for loss of business profits, business interruption, loss of
+ business information or any other pecuniary loss) arising out of the use or
+ inability to use Software, even if WireGuard LLC has been advised of the
+ possibility of such damages and regardless of the legal or quitable theory
+ (contract, tort, or otherwise) upon which the claim is based.
+
+6. TERMINATION. This agreement is affected until terminated. You may
+ terminate this agreement at any time. This agreement will terminate
+ immediately without notice from WireGuard LLC if you fail to comply with
+ the terms and conditions of this agreement. Upon termination, you must
+ delete Software and all copies of Software and cease all forms of
+ distribution of Software.
+
+7. SEVERABILITY. If any provision of this agreement is held to be
+ unenforceable, this agreement will remain in effect with the provision
+ omitted, unless omission would frustrate the intent of the parties, in
+ which case this agreement will immediately terminate.
+
+8. RESERVATION OF RIGHTS. All rights not expressly granted in this agreement
+ are reserved by WireGuard LLC. For example, WireGuard LLC reserves the
+ right at any time to cease development of Software, to alter distribution
+ details, features, specifications, capabilities, functions, licensing
+ terms, release dates, APIs, ABIs, general availability, or other
+ characteristics of the Software.
diff --git a/setupapihost/host.c b/setupapihost/host.c
new file mode 100644
index 0000000..e930358
--- /dev/null
+++ b/setupapihost/host.c
@@ -0,0 +1,184 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include <windows.h>
+#include <delayimp.h>
+#include <setupapi.h>
+#include <devguid.h>
+#include <shellapi.h>
+#include <intsafe.h>
+#include <stdlib.h>
+
+#define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
+
+static FARPROC WINAPI
+DelayedLoadLibraryHook(unsigned dliNotify, PDelayLoadInfo pdli)
+{
+ if (dliNotify != dliNotePreLoadLibrary)
+ return NULL;
+ HMODULE Library = LoadLibraryExA(pdli->szDll, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
+ if (!Library)
+ abort();
+ return (FARPROC)Library;
+}
+
+const PfnDliHook __pfnDliNotifyHook2 = DelayedLoadLibraryHook;
+
+static DWORD
+WriteFormatted(_In_ DWORD StdHandle, _In_z_ LPCWSTR Template, ...)
+{
+ LPWSTR FormattedMessage = NULL;
+ DWORD Size;
+ va_list Arguments;
+ va_start(Arguments, Template);
+ DWORD Len = FormatMessageW(
+ FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ Template,
+ 0,
+ 0,
+ (VOID *)&FormattedMessage,
+ 0,
+ &Arguments);
+ if (SUCCEEDED(DWordMult(Len, sizeof(*FormattedMessage), &Size)))
+ WriteFile(GetStdHandle(StdHandle), FormattedMessage, Size, &Size, NULL);
+ else
+ Size = 0;
+ LocalFree(FormattedMessage);
+ va_end(Arguments);
+ return Size / sizeof(*FormattedMessage);
+}
+
+VOID __stdcall RemoveInstance(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
+{
+#pragma EXPORT
+
+ DWORD LastError = ERROR_SUCCESS;
+ int Argc;
+ LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
+
+ if (Argc < 3)
+ goto cleanup;
+ WCHAR *InstanceId = Argv[2];
+
+ HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
+ if (DevInfo == INVALID_HANDLE_VALUE)
+ {
+ LastError = GetLastError();
+ goto cleanup;
+ }
+ SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
+ if (!SetupDiOpenDeviceInfoW(DevInfo, InstanceId, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+ SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
+ .InstallFunction = DIF_REMOVE },
+ .Scope = DI_REMOVEDEVICE_GLOBAL };
+ if (!SetupDiSetClassInstallParamsW(
+ DevInfo, &DevInfoData, &RemoveDeviceParams.ClassInstallHeader, sizeof(RemoveDeviceParams)) ||
+ !SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+
+cleanupDevInfo:
+ SetupDiDestroyDeviceInfoList(DevInfo);
+cleanup:
+ LocalFree(Argv);
+
+ WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError);
+}
+
+VOID __stdcall EnableInstance(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
+{
+#pragma EXPORT
+
+ DWORD LastError = ERROR_SUCCESS;
+ int Argc;
+ LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
+
+ if (Argc < 3)
+ goto cleanup;
+ WCHAR *InstanceId = Argv[2];
+
+ HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
+ if (DevInfo == INVALID_HANDLE_VALUE)
+ {
+ LastError = GetLastError();
+ goto cleanup;
+ }
+ SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
+ if (!SetupDiOpenDeviceInfoW(DevInfo, InstanceId, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+ SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
+ .InstallFunction = DIF_PROPERTYCHANGE },
+ .StateChange = DICS_ENABLE,
+ .Scope = DICS_FLAG_GLOBAL };
+ if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) ||
+ !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DevInfoData))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+
+cleanupDevInfo:
+ SetupDiDestroyDeviceInfoList(DevInfo);
+cleanup:
+ LocalFree(Argv);
+
+ WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError);
+}
+
+VOID __stdcall DisableInstance(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
+{
+#pragma EXPORT
+
+ DWORD LastError = ERROR_SUCCESS;
+ int Argc;
+ LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
+
+ if (Argc < 3)
+ goto cleanup;
+ WCHAR *InstanceId = Argv[2];
+
+ HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
+ if (DevInfo == INVALID_HANDLE_VALUE)
+ {
+ LastError = GetLastError();
+ goto cleanup;
+ }
+ SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
+ if (!SetupDiOpenDeviceInfoW(DevInfo, InstanceId, NULL, DIOD_INHERIT_CLASSDRVS, &DevInfoData))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+ SP_PROPCHANGE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
+ .InstallFunction = DIF_PROPERTYCHANGE },
+ .StateChange = DICS_DISABLE,
+ .Scope = DICS_FLAG_GLOBAL };
+ if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) ||
+ !SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, DevInfo, &DevInfoData))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+
+cleanupDevInfo:
+ SetupDiDestroyDeviceInfoList(DevInfo);
+cleanup:
+ LocalFree(Argv);
+
+ WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", LastError);
+}
+
+#if NTDDI_VERSION == NTDDI_WIN7
+#include "host_win7.h"
+#endif
diff --git a/setupapihost/host_win7.h b/setupapihost/host_win7.h
new file mode 100644
index 0000000..2640c26
--- /dev/null
+++ b/setupapihost/host_win7.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
+ */
+
+#include <devguid.h>
+#include <cfgmgr32.h>
+
+#define WINTUN_HWID L"Wintun"
+
+VOID __stdcall CreateInstanceWin7(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
+{
+#pragma EXPORT
+
+ DWORD LastError = ERROR_SUCCESS;
+ WCHAR InstanceId[MAX_DEVICE_ID_LEN] = { 0 };
+
+ HDEVINFO DevInfo = SetupDiCreateDeviceInfoListExW(&GUID_DEVCLASS_NET, NULL, NULL, NULL);
+ if (DevInfo == INVALID_HANDLE_VALUE)
+ {
+ LastError = GetLastError();
+ goto cleanup;
+ }
+ SP_DEVINFO_DATA DevInfoData = { .cbSize = sizeof(DevInfoData) };
+ if (!SetupDiCreateDeviceInfoW(
+ DevInfo, WINTUN_HWID, &GUID_DEVCLASS_NET, NULL, NULL, DICD_GENERATE_ID, &DevInfoData))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+ SP_DEVINSTALL_PARAMS_W DevInstallParams = { .cbSize = sizeof(DevInstallParams) };
+ if (!SetupDiGetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+ DevInstallParams.Flags |= DI_QUIETINSTALL;
+ if (!SetupDiSetDeviceInstallParamsW(DevInfo, &DevInfoData, &DevInstallParams))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+ if (!SetupDiSetSelectedDevice(DevInfo, &DevInfoData))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+ static const WCHAR Hwids[_countof(WINTUN_HWID) + 1 /*Multi-string terminator*/] = WINTUN_HWID;
+ if (!SetupDiSetDeviceRegistryPropertyW(DevInfo, &DevInfoData, SPDRP_HARDWAREID, (const BYTE *)Hwids, sizeof(Hwids)))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+ if (!SetupDiBuildDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+ SP_DRVINFO_DATA_W DrvInfoData = { .cbSize = sizeof(SP_DRVINFO_DATA_W) };
+ if (!SetupDiEnumDriverInfoW(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER, 0, &DrvInfoData) ||
+ !SetupDiSetSelectedDriverW(DevInfo, &DevInfoData, &DrvInfoData))
+ {
+ LastError = GetLastError();
+ goto cleanupDriverInfo;
+ }
+
+ if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DevInfo, &DevInfoData))
+ {
+ LastError = GetLastError();
+ goto cleanupDevInfo;
+ }
+ SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS, DevInfo, &DevInfoData);
+ SetupDiCallClassInstaller(DIF_INSTALLINTERFACES, DevInfo, &DevInfoData);
+ if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE, DevInfo, &DevInfoData))
+ {
+ LastError = GetLastError();
+ goto cleanupDevice;
+ }
+ DWORD RequiredChars = _countof(InstanceId);
+ if (!SetupDiGetDeviceInstanceIdW(DevInfo, &DevInfoData, InstanceId, RequiredChars, &RequiredChars))
+ {
+ LastError = GetLastError();
+ goto cleanupDevice;
+ }
+
+cleanupDevice:
+ if (LastError != ERROR_SUCCESS)
+ {
+ SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
+ .InstallFunction = DIF_REMOVE },
+ .Scope = DI_REMOVEDEVICE_GLOBAL };
+ if (SetupDiSetClassInstallParamsW(
+ DevInfo, &DevInfoData, &RemoveDeviceParams.ClassInstallHeader, sizeof(RemoveDeviceParams)))
+ SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData);
+ }
+cleanupDriverInfo:
+ SetupDiDestroyDriverInfoList(DevInfo, &DevInfoData, SPDIT_COMPATDRIVER);
+cleanupDevInfo:
+ SetupDiDestroyDeviceInfoList(DevInfo);
+cleanup:
+ WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!s!", LastError, LastError == ERROR_SUCCESS ? InstanceId : L"\"\"");
+}
diff --git a/setupapihost/setupapihost.vcxproj b/setupapihost/setupapihost.vcxproj
new file mode 100644
index 0000000..147c429
--- /dev/null
+++ b/setupapihost/setupapihost.vcxproj
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{9911D673-CF5F-4B41-B190-807AA1BE445B}</ProjectGuid>
+ <RootNamespace>setupapihost</RootNamespace>
+ <ProjectName>setupapihost</ProjectName>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="..\wintun.props" />
+ <PropertyGroup>
+ <TargetName>setupapihost</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <PreprocessorDefinitions>_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalOptions>/volatile:iso %(AdditionalOptions)</AdditionalOptions>
+ <DisableSpecificWarnings>4100;4201;$(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <DelayLoadDLLs>setupapi.dll;shell32.dll</DelayLoadDLLs>
+ <AdditionalDependencies>Setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SubSystem>Windows</SubSystem>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="host.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="host_win7.h" />
+ </ItemGroup>
+ <Import Project="..\wintun.props.user" Condition="exists('..\wintun.props.user')" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets" />
+</Project>
diff --git a/wintun.proj b/wintun.proj
index ea24c0d..00eb862 100644
--- a/wintun.proj
+++ b/wintun.proj
@@ -2,83 +2,106 @@
<!--
SPDX-License-Identifier: GPL-2.0
- Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
+ Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
+ <PropertyGroup>
+ <Configuration Condition="'$(Configuration)'==''">Release</Configuration>
+ </PropertyGroup>
<!--
General Properties
-->
<Import Project="wintun.props" />
- <Import Project="wintun.vcxproj.user" Condition="exists('wintun.vcxproj.user')" />
+ <Import Project="wintun.props.user" Condition="exists('wintun.props.user')" />
- <Target Name="Build" DependsOnTargets="Driver-x86;Driver-amd64;Driver-arm64" />
- <Target Name="MSM" DependsOnTargets="MSM-x86;MSM-amd64" />
+ <Target Name="Driver" DependsOnTargets="Driver-x86;Driver-amd64;Driver-arm64" />
+ <Target Name="Dll" DependsOnTargets="Dll-x86;Dll-amd64;Dll-arm64" />
<Target Name="Clean">
- <RemoveDir Directories="x86\Release\" />
- <RemoveDir Directories="amd64\Release\" />
- <RemoveDir Directories="arm64\Release\" />
- <RemoveDir Directories="$(SDVDir)" />
- <RemoveDir Directories="$(DistributionDir)" />
- <Delete Files="smvbuild.log;smvstats.txt;wintun.DVL.XML" />
+ <RemoveDir Directories="$(Configuration)\amd64\" />
+ <RemoveDir Directories="$(Configuration)\arm\" />
+ <RemoveDir Directories="$(Configuration)\arm64\" />
+ <RemoveDir Directories="$(Configuration)\x86\" />
+ <RemoveDir Directories="dist\" />
</Target>
- <Target Name="Rebuild" DependsOnTargets="Clean;Build" />
<!--
Driver Building
Note: Use explicit Inputs/Outputs as WindowsDriver.Common.targets triggers driver re-packaging and signing on every invocation.
-->
<PropertyGroup>
- <DriverInputs>atomic.h;undocumented.h;wintun.c;wintun.inf;wintun.props;wintun.rc;wintun.vcxproj;$(DriverInputs)</DriverInputs>
+ <DriverInputs>driver\undocumented.h;driver\wintun.c;driver\wintun.inf;wintun.props;driver\wintun.rc;driver\driver.vcxproj;$(DriverInputs)</DriverInputs>
</PropertyGroup>
<Target Name="Driver-x86"
- Outputs="x86\Release\wintun\wintun.sys;x86\Release\wintun\wintun.inf;x86\Release\wintun\wintun.cat"
+ Outputs="$(Configuration)\x86\driver\wintun.sys;$(Configuration)\x86\driver\wintun.inf;$(Configuration)\x86\driver\wintun.cat"
Inputs="$(DriverInputs)">
- <MSBuild Projects="wintun.vcxproj" Targets="Build" Properties="Configuration=Release;Platform=Win32" />
+ <MSBuild Projects="driver\driver.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=Win32" />
</Target>
<Target Name="Driver-amd64"
- Outputs="amd64\Release\wintun\wintun.sys;amd64\Release\wintun\wintun.inf;amd64\Release\wintun\wintun.cat"
+ Outputs="$(Configuration)\amd64\driver\wintun.sys;$(Configuration)\amd64\driver\wintun.inf;$(Configuration)\amd64\driver\wintun.cat"
+ Inputs="$(DriverInputs)">
+ <MSBuild Projects="driver\driver.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=x64" />
+ </Target>
+ <Target Name="Driver-arm"
+ Outputs="$(Configuration)\arm\driver\wintun.sys;$(Configuration)\arm\driver\wintun.inf;$(Configuration)\arm\driver\wintun.cat"
Inputs="$(DriverInputs)">
- <MSBuild Projects="wintun.vcxproj" Targets="Build" Properties="Configuration=Release;Platform=x64" />
+ <MSBuild Projects="driver\driver.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=ARM" />
</Target>
<Target Name="Driver-arm64"
- Outputs="arm64\Release\wintun\wintun.sys;arm64\Release\wintun\wintun.inf;arm64\Release\wintun\wintun.cat"
+ Outputs="$(Configuration)\arm64\driver\wintun.sys;$(Configuration)\arm64\driver\wintun.inf;$(Configuration)\arm64\driver\wintun.cat"
Inputs="$(DriverInputs)">
- <MSBuild Projects="wintun.vcxproj" Targets="Build" Properties="Configuration=Release;Platform=ARM64" />
+ <MSBuild Projects="driver\driver.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=ARM64" />
</Target>
<!--
- Static Driver Verifier
+ wintun.dll Building
-->
- <Target Name="SDV" Outputs="$(SDVDir)SDV.DVL.xml;amd64\Release\vc.nativecodeanalysis.all.xml">
- <MSBuild Projects="wintun.vcxproj" Targets="sdv" Properties="Inputs=/check:*;Configuration=Release;Platform=x64" />
+ <Target Name="Dll-x86"
+ Outputs="$(Configuration)\x86\wintun.dll"
+ DependsOnTargets="Dll-amd64;Dll-arm64">
+ <MSBuild Projects="setupapihost\setupapihost.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=Win32" />
</Target>
- <Target Name="SDVView">
- <MSBuild Projects="wintun.vcxproj" Targets="sdv" Properties="Inputs=/view;Configuration=Release;Platform=x64" />
+ <Target Name="Dll-amd64"
+ Outputs="$(Configuration)\amd64\wintun.dll"
+ DependsOnTargets="Dll-arm64">
+ <MSBuild Projects="setupapihost\setupapihost.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=x64" />
</Target>
-
- <!--
- Driver Verification Log
- -->
- <Target Name="DVL" DependsOnTargets="SDV"
- Outputs="wintun.DVL.XML"
- Inputs="$(SDVDir)SDV.DVL.xml;amd64\Release\vc.nativecodeanalysis.all.xml">
- <MSBuild Projects="wintun.vcxproj" Targets="dvl" Properties="Configuration=Release;Platform=x64" />
+ <Target Name="Dll-arm"
+ Outputs="$(Configuration)\arm\wintun.dll"
+ DependsOnTargets="Dll-arm64">
+ <MSBuild Projects="setupapihost\setupapihost.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=ARM" />
+ </Target>
+ <Target Name="Dll-arm64"
+ Outputs="$(Configuration)\arm64\wintun.dll">
+ <MSBuild Projects="setupapihost\setupapihost.vcxproj;api\api.vcxproj" Targets="Build" Properties="Configuration=$(Configuration);Platform=ARM64" />
</Target>
<!--
- MSM Building
+ Zip Building
-->
- <Target Name="MSM-x86"
- Outputs="$(DistributionDir)wintun-x86-$(WintunVersionStr).msm">
- <MSBuild Projects="installer\installer.vcxproj" Targets="MSM" Properties="Configuration=Release;Platform=Win32" />
- </Target>
- <Target Name="MSM-amd64"
- Outputs="$(DistributionDir)wintun-amd64-$(WintunVersionStr).msm">
- <MSBuild Projects="installer\installer.vcxproj" Targets="MSM" Properties="Configuration=Release;Platform=x64" />
- </Target>
- <Target Name="MSM-ARM64"
- Outputs="$(DistributionDir)wintun-arm64-$(WintunVersionStr).msm">
- <MSBuild Projects="installer\installer.vcxproj" Targets="MSM" Properties="Configuration=Release;Platform=ARM64" />
+ <PropertyGroup>
+ <ZipTargetPath>dist\wintun-$(WintunVersion).zip</ZipTargetPath>
+ <ZipIntDir>dist\zip-intermediate\</ZipIntDir>
+ </PropertyGroup>
+ <ItemGroup>
+ <ZipFilesSrc Include="prebuilt-binaries-license.txt" /><ZipFilesDst Include="$(ZipIntDir)wintun\LICENSE.txt" />
+ <ZipFilesSrc Include="README.md" /><ZipFilesDst Include="$(ZipIntDir)wintun\README.md" />
+ <ZipFilesSrc Include="api\wintun.h" /><ZipFilesDst Include="$(ZipIntDir)wintun\include\wintun.h" />
+ <ZipFilesSrc Include="$(Configuration)\amd64\wintun.dll" /><ZipFilesDst Include="$(ZipIntDir)wintun\bin\amd64\wintun.dll" />
+ <ZipFilesSrc Include="$(Configuration)\arm64\wintun.dll" /><ZipFilesDst Include="$(ZipIntDir)wintun\bin\arm64\wintun.dll" />
+ <ZipFilesSrc Include="$(Configuration)\x86\wintun.dll" /><ZipFilesDst Include="$(ZipIntDir)wintun\bin\x86\wintun.dll" />
+ </ItemGroup>
+ <Target Name="Zip"
+ Inputs="@(ZipFilesSrc)"
+ Outputs="$(ZipTargetPath)"
+ DependsOnTargets="Dll">
+ <RemoveDir Directories="$(ZipIntDir)" />
+ <Copy SourceFiles="@(ZipFilesSrc)" DestinationFiles="@(ZipFilesDst)" />
+ <ZipDirectory DestinationFile="$(ZipTargetPath)" Overwrite="true" SourceDirectory="$(ZipIntDir)" />
+ <RemoveDir Directories="$(ZipIntDir)" />
+ <GetFileHash Files="$(ZipTargetPath)" Algorithm="SHA256" HashEncoding="hex">
+ <Output TaskParameter="Items" ItemName="InstallerLibraryHash" />
+ </GetFileHash>
+ <Message Text="SHA256(&quot;$(ZipTargetPath)&quot;) = @(InstallerLibraryHash->Metadata('FileHash')->ToLower())"/>
</Target>
</Project>
diff --git a/wintun.props b/wintun.props
index 5b31926..4b43ab9 100644
--- a/wintun.props
+++ b/wintun.props
@@ -2,31 +2,125 @@
<!--
SPDX-License-Identifier: GPL-2.0
- Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
+ Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
-->
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|ARM">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|ARM64">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM">
+ <Configuration>Release</Configuration>
+ <Platform>ARM</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM64">
+ <Configuration>Release</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>16.0</VCProjectVersion>
+ <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration">
+ <CharacterSet>Unicode</CharacterSet>
+ <Driver_SpectreMitigation>false</Driver_SpectreMitigation>
+ <Inf2CatUseLocalTime Condition="'$(ConfigurationType)'=='Driver'">true</Inf2CatUseLocalTime>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+ <UseDebugLibraries>true</UseDebugLibraries>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Platform)'=='Win32'" Label="Configuration">
+ <TargetVersion>Windows7</TargetVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Platform)'=='ARM'" Label="Configuration">
+ <TargetVersion>Windows8</TargetVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Platform)'=='x64'" Label="Configuration">
+ <TargetVersion>Windows7</TargetVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Platform)'=='ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(ForcedTargetVersion)'!=''">
+ <TargetVersion>$(ForcedTargetVersion)</TargetVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings" />
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
<PropertyGroup>
<WintunVersionMaj>0</WintunVersionMaj>
- <WintunVersionMin>8</WintunVersionMin>
- <WintunVersionStr>0.8</WintunVersionStr><!-- Used in filenames and ProductVersion resource string, may contain strings. -->
- <WintunVersion>$(WintunVersionMaj).$(WintunVersionMin)</WintunVersion><!-- Used for versioning, must be n.n[.n[.n]]. -->
+ <WintunVersionMin>14</WintunVersionMin>
+ <WintunVersionRel>1</WintunVersionRel>
+
+ <!-- Used for versioning, must be n.n[.n[.n]]. -->
+ <WintunVersion>$(WintunVersionMaj).$(WintunVersionMin)</WintunVersion>
+ <WintunVersion Condition="'$(WintunVersionRel)'!='0'">$(WintunVersion).$(WintunVersionRel)</WintunVersion>
<!-- .vcxproj are using different platform names. -->
+ <WintunPlatform Condition="'$(Platform)'=='ARM'">arm</WintunPlatform>
+ <WintunPlatform Condition="'$(Platform)'=='ARM64'">arm64</WintunPlatform>
<WintunPlatform Condition="'$(Platform)'=='Win32'">x86</WintunPlatform>
<WintunPlatform Condition="'$(Platform)'=='x64'">amd64</WintunPlatform>
- <WintunPlatform Condition="'$(Platform)'=='ARM64'">arm64</WintunPlatform>
- <DistributionDir>dist\</DistributionDir>
- <SDVDir>sdv\</SDVDir>
+ <IntDir>..\$(Configuration)\$(WintunPlatform)\$(ProjectName)-intermediate\</IntDir>
+ <OutDir>..\$(Configuration)\$(WintunPlatform)\</OutDir>
+ <OutDir Condition="'$(ConfigurationType)'=='Driver'">$(IntDir)</OutDir>
+ <PackageDir>..\$(Configuration)\$(WintunPlatform)\$(ProjectName)\</PackageDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(SDVHacks)'=='true'">
+ <RunCodeAnalysis>false</RunCodeAnalysis>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(RunCodeAnalysis)'=='true'">
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ <ClCompile>
+ <EnablePREfast>true</EnablePREfast>
+ </ClCompile>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
- <PreprocessorDefinitions>WINTUN_VERSION_MAJ=$(WintunVersionMaj);WINTUN_VERSION_MIN=$(WintunVersionMin);WINTUN_VERSION_STR="$(WintunVersionStr)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>WINTUN_VERSION_MAJ=$(WintunVersionMaj);WINTUN_VERSION_MIN=$(WintunVersionMin);WINTUN_VERSION_REL=$(WintunVersionRel);WINTUN_VERSION="$(WintunVersion)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
<ResourceCompile>
- <PreprocessorDefinitions>WINTUN_VERSION_MAJ=$(WintunVersionMaj);WINTUN_VERSION_MIN=$(WintunVersionMin);WINTUN_VERSION_STR="$(WintunVersionStr)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>WINTUN_VERSION_MAJ=$(WintunVersionMaj);WINTUN_VERSION_MIN=$(WintunVersionMin);WINTUN_VERSION_REL=$(WintunVersionRel);WINTUN_VERSION="$(WintunVersion)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
+ <Link>
+ <ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <ProgramDatabaseFile Condition="'$(ConfigurationType)'=='Driver'">$(PackageDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <ImportLibrary Condition="'$(ConfigurationType)'=='DynamicLibrary'">$(IntDir)$(TargetName).lib</ImportLibrary>
+ </Link>
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
@@ -34,15 +128,33 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
</ClCompile>
+ <Link>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+ </Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<Optimization>Disabled</Optimization>
</ClCompile>
</ItemDefinitionGroup>
- <PropertyGroup>
- <WindowsSdkToolchainPlatform>$(PROCESSOR_ARCHITECTURE)</WindowsSdkToolchainPlatform>
- <WindowsSdkToolchainPlatform Condition="'$(PROCESSOR_ARCHITECTURE)'=='AMD64'">x64</WindowsSdkToolchainPlatform>
- <SignToolPath>$(WindowsSdkDir)bin\$(TargetPlatformVersion)\$(WindowsSdkToolchainPlatform)\signtool.exe</SignToolPath>
- </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(PlatformToolset)|$(Configuration)'=='WindowsApplicationForDrivers10.0|Release'">
+ <ClCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(PlatformToolset)|$(Configuration)'=='WindowsApplicationForDrivers10.0|Debug'">
+ <ClCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
</Project>
diff --git a/wintun.sln b/wintun.sln
index 67dd803..4bc1f91 100644
--- a/wintun.sln
+++ b/wintun.sln
@@ -1,18 +1,21 @@
-
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28922.388
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "installer", "installer\installer.vcxproj", "{D19E6354-A643-4ACC-82D5-B2780BB83475}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example", "example\example.vcxproj", "{2ABAC503-245D-4F53-85C5-0F844DEF738B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "api", "api\api.vcxproj", "{897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}"
ProjectSection(ProjectDependencies) = postProject
{F7679B65-2FEC-469A-8BAC-B07BF4439422} = {F7679B65-2FEC-469A-8BAC-B07BF4439422}
+ {9911D673-CF5F-4B41-B190-807AA1BE445B} = {9911D673-CF5F-4B41-B190-807AA1BE445B}
EndProjectSection
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wintun", "wintun.vcxproj", "{F7679B65-2FEC-469A-8BAC-B07BF4439422}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "driver", "driver\driver.vcxproj", "{F7679B65-2FEC-469A-8BAC-B07BF4439422}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "setupapihost", "setupapihost\setupapihost.vcxproj", "{9911D673-CF5F-4B41-B190-807AA1BE445B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3A98F138-EE02-4488-B856-B3C48500BEA8}"
ProjectSection(SolutionItems) = preProject
- COPYING = COPYING
README.md = README.md
wintun.proj = wintun.proj
wintun.props = wintun.props
@@ -21,44 +24,83 @@ EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|amd64 = Debug|amd64
+ Debug|arm = Debug|arm
Debug|arm64 = Debug|arm64
Debug|x86 = Debug|x86
Release|amd64 = Release|amd64
+ Release|arm = Release|arm
Release|arm64 = Release|arm64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|amd64.ActiveCfg = Debug|x64
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|amd64.Build.0 = Debug|x64
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|arm.ActiveCfg = Debug|ARM
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|arm.Build.0 = Debug|ARM
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|arm64.ActiveCfg = Debug|ARM64
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|arm64.Build.0 = Debug|ARM64
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|x86.ActiveCfg = Debug|Win32
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Debug|x86.Build.0 = Debug|Win32
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|amd64.ActiveCfg = Release|x64
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|amd64.Build.0 = Release|x64
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|arm.ActiveCfg = Release|ARM
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|arm.Build.0 = Release|ARM
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|arm64.ActiveCfg = Release|ARM64
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|arm64.Build.0 = Release|ARM64
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|x86.ActiveCfg = Release|Win32
+ {2ABAC503-245D-4F53-85C5-0F844DEF738B}.Release|x86.Build.0 = Release|Win32
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Debug|amd64.ActiveCfg = Debug|x64
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Debug|amd64.Build.0 = Debug|x64
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Debug|arm.ActiveCfg = Debug|ARM
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Debug|arm.Build.0 = Debug|ARM
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Debug|arm64.ActiveCfg = Debug|ARM64
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Debug|arm64.Build.0 = Debug|ARM64
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Debug|x86.ActiveCfg = Debug|Win32
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Debug|x86.Build.0 = Debug|Win32
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Release|amd64.ActiveCfg = Release|x64
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Release|amd64.Build.0 = Release|x64
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Release|arm.ActiveCfg = Release|ARM
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Release|arm.Build.0 = Release|ARM
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Release|arm64.ActiveCfg = Release|ARM64
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Release|arm64.Build.0 = Release|ARM64
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Release|x86.ActiveCfg = Release|Win32
+ {897F02E3-3EAA-40AF-A6DC-17EB2376EDAF}.Release|x86.Build.0 = Release|Win32
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Debug|amd64.ActiveCfg = Debug|x64
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Debug|amd64.Build.0 = Debug|x64
+ {F7679B65-2FEC-469A-8BAC-B07BF4439422}.Debug|arm.ActiveCfg = Debug|ARM
+ {F7679B65-2FEC-469A-8BAC-B07BF4439422}.Debug|arm.Build.0 = Debug|ARM
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Debug|arm64.ActiveCfg = Debug|ARM64
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Debug|arm64.Build.0 = Debug|ARM64
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Debug|x86.ActiveCfg = Debug|Win32
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Debug|x86.Build.0 = Debug|Win32
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|amd64.ActiveCfg = Release|x64
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|amd64.Build.0 = Release|x64
+ {F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|arm.ActiveCfg = Release|ARM
+ {F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|arm.Build.0 = Release|ARM
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|arm64.ActiveCfg = Release|ARM64
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|arm64.Build.0 = Release|ARM64
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|x86.ActiveCfg = Release|Win32
{F7679B65-2FEC-469A-8BAC-B07BF4439422}.Release|x86.Build.0 = Release|Win32
- {D19E6354-A643-4ACC-82D5-B2780BB83475}.Debug|amd64.ActiveCfg = Debug|x64
- {D19E6354-A643-4ACC-82D5-B2780BB83475}.Debug|amd64.Build.0 = Debug|x64
- {D19E6354-A643-4ACC-82D5-B2780BB83475}.Debug|arm64.ActiveCfg = Debug|ARM64
- {D19E6354-A643-4ACC-82D5-B2780BB83475}.Debug|arm64.Build.0 = Debug|ARM64
- {D19E6354-A643-4ACC-82D5-B2780BB83475}.Debug|x86.ActiveCfg = Debug|Win32
- {D19E6354-A643-4ACC-82D5-B2780BB83475}.Debug|x86.Build.0 = Debug|Win32
- {D19E6354-A643-4ACC-82D5-B2780BB83475}.Release|amd64.ActiveCfg = Release|x64
- {D19E6354-A643-4ACC-82D5-B2780BB83475}.Release|amd64.Build.0 = Release|x64
- {D19E6354-A643-4ACC-82D5-B2780BB83475}.Release|arm64.ActiveCfg = Release|ARM64
- {D19E6354-A643-4ACC-82D5-B2780BB83475}.Release|arm64.Build.0 = Release|ARM64
- {D19E6354-A643-4ACC-82D5-B2780BB83475}.Release|x86.ActiveCfg = Release|Win32
- {D19E6354-A643-4ACC-82D5-B2780BB83475}.Release|x86.Build.0 = Release|Win32
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|amd64.ActiveCfg = Debug|x64
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|amd64.Build.0 = Debug|x64
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|arm.ActiveCfg = Debug|ARM
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|arm.Build.0 = Debug|ARM
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|arm64.ActiveCfg = Debug|ARM64
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|arm64.Build.0 = Debug|ARM64
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|x86.ActiveCfg = Debug|Win32
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Debug|x86.Build.0 = Debug|Win32
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|amd64.ActiveCfg = Release|x64
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|amd64.Build.0 = Release|x64
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|arm.ActiveCfg = Release|ARM
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|arm.Build.0 = Release|ARM
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|arm64.ActiveCfg = Release|ARM64
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|arm64.Build.0 = Release|ARM64
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|x86.ActiveCfg = Release|Win32
+ {9911D673-CF5F-4B41-B190-807AA1BE445B}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {2B5DA7D8-C56A-4E93-BE93-79388A8007AF} = {3A98F138-EE02-4488-B856-B3C48500BEA8}
- EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {254563AF-E0B3-48F0-B564-A45AEC95591F}
EndGlobalSection
diff --git a/wintun.vcxproj b/wintun.vcxproj
deleted file mode 100644
index 3bb61d1..0000000
--- a/wintun.vcxproj
+++ /dev/null
@@ -1,179 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|ARM64">
- <Configuration>Debug</Configuration>
- <Platform>ARM64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Debug|x64">
- <Configuration>Debug</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|ARM64">
- <Configuration>Release</Configuration>
- <Platform>ARM64</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|x64">
- <Configuration>Release</Configuration>
- <Platform>x64</Platform>
- </ProjectConfiguration>
- </ItemGroup>
- <PropertyGroup Label="Globals">
- <ProjectGuid>{F7679B65-2FEC-469A-8BAC-B07BF4439422}</ProjectGuid>
- <RootNamespace>wintun</RootNamespace>
- <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
- <ProjectName>wintun</ProjectName>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <TargetVersion>Windows7</TargetVersion>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
- <ConfigurationType>Driver</ConfigurationType>
- <DriverType>WDM</DriverType>
- <SpectreMitigation>false</SpectreMitigation>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <TargetVersion>Windows7</TargetVersion>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
- <ConfigurationType>Driver</ConfigurationType>
- <DriverType>WDM</DriverType>
- <SpectreMitigation>false</SpectreMitigation>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <TargetVersion>Windows7</TargetVersion>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
- <ConfigurationType>Driver</ConfigurationType>
- <DriverType>WDM</DriverType>
- <SpectreMitigation>false</SpectreMitigation>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
- <TargetVersion>Windows10</TargetVersion>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
- <ConfigurationType>Driver</ConfigurationType>
- <DriverType>WDM</DriverType>
- <SpectreMitigation>false</SpectreMitigation>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
- <TargetVersion>Windows7</TargetVersion>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
- <ConfigurationType>Driver</ConfigurationType>
- <DriverType>WDM</DriverType>
- <SpectreMitigation>false</SpectreMitigation>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
- <TargetVersion>Windows10</TargetVersion>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
- <ConfigurationType>Driver</ConfigurationType>
- <DriverType>WDM</DriverType>
- <SpectreMitigation>false</SpectreMitigation>
- </PropertyGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
- <ImportGroup Label="ExtensionSettings">
- </ImportGroup>
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <Import Project="wintun.props" />
- <PropertyGroup Label="UserMacros" />
- <PropertyGroup>
- <_ProjectFileVersion>15.0.28127.55</_ProjectFileVersion>
- <IntDir>$(WintunPlatform)\$(ConfigurationName)\</IntDir>
- <OutDir>$(WintunPlatform)\$(ConfigurationName)\</OutDir>
- <RunCodeAnalysis>true</RunCodeAnalysis>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)'=='Release'">
- <CodeAnalysisRuleSet>$(WDKContentRoot)CodeAnalysis\DriverMustFixRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)'=='Debug'">
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" />
- <ItemDefinitionGroup>
- <ClCompile>
- <PreprocessorDefinitions>NDIS_MINIPORT_DRIVER=1;NDIS620_MINIPORT=1;NDIS683_MINIPORT=1;NDIS_WDM=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <AdditionalOptions>/volatile:ms %(AdditionalOptions)</AdditionalOptions>
- <EnablePREfast>true</EnablePREfast>
- </ClCompile>
- <ResourceCompile>
- <PreprocessorDefinitions>NDIS_MINIPORT_DRIVER=1;NDIS620_MINIPORT=1;NDIS683_MINIPORT=1;NDIS_WDM=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ResourceCompile>
- <Link>
- <AdditionalDependencies>ndis.lib;wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- <DriverSign>
- <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
- </DriverSign>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
- <Inf>
- <TimeStamp>$(WintunVersion)</TimeStamp>
- </Inf>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
- <ClCompile>
- <PreprocessorDefinitions>DBG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- <ResourceCompile>
- <PreprocessorDefinitions>DBG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ResourceCompile>
- <Inf>
- <TimeStamp>*</TimeStamp>
- </Inf>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" />
- <ItemGroup>
- <ClCompile Include="wintun.c" />
- </ItemGroup>
- <ItemGroup>
- <ResourceCompile Include="wintun.rc" />
- </ItemGroup>
- <ItemGroup>
- <Inf Include="wintun.inf" />
- <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="atomic.h" />
- <ClInclude Include="undocumented.h" />
- </ItemGroup>
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
- <ImportGroup Label="ExtensionTargets" />
-</Project>