aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authorSimon Rozman <simon@rozman.si>2020-10-25 00:23:33 +0200
committerSimon Rozman <simon@rozman.si>2020-10-31 06:55:58 +0100
commit202f1dc9b88e2d962573e694a9abf38472575f9d (patch)
treeeab98197015c2760df25f5aa698383530c060d6f /README.md
parentapi: allow wintun.h use in C++ (diff)
downloadwintun-202f1dc9b88e2d962573e694a9abf38472575f9d.tar.xz
wintun-202f1dc9b88e2d962573e694a9abf38472575f9d.zip
api: update README.md
Signed-off-by: Simon Rozman <simon@rozman.si>
Diffstat (limited to 'README.md')
-rw-r--r--README.md195
1 files changed, 80 insertions, 115 deletions
diff --git a/README.md b/README.md
index 98107d3..0745d17 100644
--- a/README.md
+++ b/README.md
@@ -5,158 +5,123 @@ This is a layer 3 TUN driver for Windows 7, 8, 8.1, and 10. Originally created f
## 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`.
-
-```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>
-```
-
-It is advisable to use the prebuilt and Microsoft-signed MSM files from [Wintun.net](https://www.wintun.net/).
+Wintun is deployed as a platform-specific `wintun.dll` file. Install the `wintun.dll` file side-by-side with your application.
## Usage
-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:
-
-```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)
- 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);
-...
-```
+Include `wintun.h` file in your project 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).
-### Ring layout
-
-You must allocate two ring structs, one for receiving and one for sending:
+Each function has its function typedef in `wintun.h` with additional usage documentation.
```C
-typedef struct _TUN_RING {
- volatile ULONG Head;
- volatile ULONG Tail;
- volatile LONG Alertable;
- UCHAR Data[];
-} TUN_RING;
+#include "wintun.h"
+⋮
+HMODULE Wintun = LoadLibraryExW(L"wintun.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
+if (!Wintun)
+ return GetLastError();
+WINTUN_CREATE_ADAPTER_FUNC WintunCreateAdapter = (WINTUN_CREATE_ADAPTER_FUNC)GetProcAddress(Wintun, "WintunCreateAdapter");
+WINTUN_DELETE_ADAPTER_FUNC WintunDeleteAdapter = (WINTUN_DELETE_ADAPTER_FUNC)GetProcAddress(Wintun, "WintunDeleteAdapter");
```
-- `Head`: Byte offset of the first packet in the ring. Its value must be a multiple of 4 and less than ring capacity.
-
-- `Tail`: Byte offset of the start of free space in the ring. Its value must be multiple of 4 and less than ring capacity.
-
-- `Alertable`: Zero when the consumer is processing packets, non-zero when the consumer has processed all packets and is waiting for `TailMoved` event.
-
-- `Data`: The ring data.
+### Adapter management
-In order to determine the size of the `Data` array:
+Adapters are grouped together in pools to allow various clients on the same machine. Each client vendor should pick own unique pool name.
-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.
+Manage the network adapters using following functions:
-The total ring size memory is then `sizeof(TUN_RING) + capacity + 0x10000`.
+- `WintunCreateAdapter()` creates a new adapter.
+- `WintunDeleteAdapter()` deletes the adapter.
+- `WintunEnumAdapters()` enumerates all existing adapters.
+- `WintunGetAdapter()` gets existing adapter handle.
+- `WintunFreeAdapter()` frees adapter handle.
+- `WintunGetAdapterDeviceObject()` opens adapter device object.
+- `WintunGetAdapterGUID()` gets adapter GUID.
+- `WintunGetAdapterLUID()` gets adapter LUID.
+- `WintunGetAdapterName()` gets adapter name.
+- `WintunSetAdapterName()` sets adapter name.
-Each packet is stored in the ring aligned to `sizeof(ULONG)` as:
+Example:
```C
-typedef struct _TUN_PACKET {
- ULONG Size;
- UCHAR Data[];
-} TUN_PACKET;
+DWORD Result;
+WINTUN_ADAPTER_HANDLE Adapter;
+BOOL RebootRequired;
+Result = WintunCreateAdapter(L"com.contoso.myapp", "My VPN adapter", NULL, &Adapter, &RebootRequired);
+if (Result != ERROR_SUCCESS)
+ return Result;
```
-- `Size`: Size of packet (max 0xFFFF).
+### Session management
-- `Data`: Layer 3 IPv4 or IPv6 packet.
+Once adapter is created, use the following functions to start a session and transfer packets:
-### Registering rings
+- `WintunStartSession()` starts a session. One adapter may have only one session.
+- `WintunEndSession()` ends and frees the session.
+- `WintunIsPacketAvailable()` checks if there is a receive packet available.
+- `WintunWaitForPacket()` waits for a receive packet to become available.
+- `WintunReceivePackets()` receives one or more packets.
+- `WintunSendPackets()` sends one or more packets.
-In order to register the two `TUN_RING`s, prepare a registration struct as:
+#### Writing to and from rings
+
+Reading packets from the adapter may be done as:
```C
-typedef struct _TUN_REGISTER_RINGS {
- struct {
- ULONG RingSize;
- TUN_RING *Ring;
- HANDLE TailMoved;
- } Send, Receive;
-} TUN_REGISTER_RINGS;
+// TODO: Preallocate WINTUN_PACKET *Queue linked list with WINTUN_MAX_IP_PACKET_SIZE packets.
+for (;;) {
+ if (!WintunIsPacketAvailable(Session))
+ WintunWaitForPacket(Session, INFINITE);
+ for (WINTUN_PACKET *p = Queue; p && p->Size <= WINTUN_MAX_IP_PACKET_SIZE; p = p->Next)
+ p->Size = DWORD_MAX;
+ DWORD Result = WintunReceivePackets(Session, Queue);
+ if (Result != ERROR_SUCCESS && Result != ERROR_NO_MORE_ITEMS)
+ return Result;
+ for (WINTUN_PACKET *p = Queue; p && p->Size <= WINTUN_MAX_IP_PACKET_SIZE; p = p->Next) {
+ // TODO: Process packet p.
+ }
+}
```
-- `Send.RingSize`, `Receive.RingSize`: Sizes of the rings (`sizeof(TUN_RING) + capacity + 0x10000`, as above).
-
-- `Send.Ring`, `Receive.Ring`: Pointers to the rings.
-
-- `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.
-
-- `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.
-
-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.
-
-
-### Writing to and from rings
+It may be desirable to spin on `WintunIsPacketAvailable()` for some time under heavy use before waiting with `WintunWaitForPacket()`, in order to reduce latency.
-Reading packets from the send ring may be done as:
+Writing packets to the adapter may be done as:
```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);
-}
+// TODO: Prepare WINTUN_PACKET *Queue linked list with packets.
+DWORD Result = WintunSendPackets(Session, Queue);
```
-It may be desirable to spin for some time under heavy use before waiting on the `TailMoved` event, in order to reduce latency.
+### Misc functions
+
+Other `wintun.dll` functions are:
-When closing the handle, Wintun will set the `Tail` to 0xFFFFFFFF and set the `TailMoved` event to unblock the waiting user process.
+- `WintunGetVersion()` returns driver and NDIS major and minor versions.
+- `WintunSetLogger()` sets global logging callback function.
-Writing packets to the receive ring may be done as:
+Example:
```C
-for (;;) {
- TUN_PACKET *Next = ReceiveFromClientProgram();
- WriteToRing(Rings->Receive.Ring, Next);
- if (Rings->Receive.Ring->Alertable)
- SetEvent(Rings->Recieve.TailMoved);
+static BOOL CALLBACK
+ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_ const WCHAR *LogLine)
+{
+ const WCHAR *Template;
+ switch (Level)
+ {
+ case WINTUN_LOG_INFO: Template = L"[+] %s\n"; break;
+ case WINTUN_LOG_WARN: Template = L"[-] %s\n"; break;
+ case WINTUN_LOG_ERR: Template = L"[!] %s\n"; break;
+ default: return FALSE;
+ }
+ fwprintf(stderr, Template, LogLine);
+ return TRUE;
}
+⋮
+WintunSetLogger(ConsoleLogger);
```
-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.
-
## 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 named "Wintun", as they will most certainly clash with official deployments. Instead distribute `wintun.dll`.**
General requirements: