appium-ios-tuntap 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.4.0](https://github.com/appium/appium-ios-tuntap/compare/v0.3.0...v0.4.0) (2026-05-30)
2
+
3
+ ### Features
4
+
5
+ * implement Windows (WinTun) JavaScript platform layer ([#44](https://github.com/appium/appium-ios-tuntap/issues/44)) ([da2a9bb](https://github.com/appium/appium-ios-tuntap/commit/da2a9bba1d7226f67ce0f00c533df72164aac858))
6
+
1
7
  ## [0.3.0](https://github.com/appium/appium-ios-tuntap/compare/v0.2.5...v0.3.0) (2026-05-22)
2
8
 
3
9
  ### Features
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TunTap Bridge
2
2
 
3
- A native TUN/TAP interface module for Node.js that works on both macOS and Linux, with enhanced error handling, signal management, and thread safety.
3
+ A native TUN/TAP interface module for Node.js that works on macOS, Linux, and Windows, with enhanced error handling, signal management, and thread safety.
4
4
 
5
5
  ## Description
6
6
 
@@ -8,7 +8,7 @@ This module provides a Node.js interface to TUN/TAP virtual network devices, all
8
8
 
9
9
  ## Features
10
10
 
11
- - **Cross-platform**: Works on macOS (utun) and Linux (TUN/TAP)
11
+ - **Cross-platform**: Works on macOS (utun), Linux (TUN/TAP), and Windows (WinTun)
12
12
  - **TypeScript support**: Full TypeScript definitions included
13
13
  - **Signal handling**: Graceful shutdown on SIGINT/SIGTERM
14
14
  - **Thread safety**: Safe to use from multiple Node.js worker threads
@@ -88,6 +88,14 @@ On Linux, the module requires:
88
88
  sudo pacman -S linux-headers
89
89
  ```
90
90
 
91
+ ### Windows
92
+
93
+ On Windows the module uses [WinTun](https://www.wintun.net/) (the same userspace TUN driver shipped with WireGuard). Requirements:
94
+
95
+ 1. **`wintun.dll`**: ships with the package. The official signed binaries for `amd64`, `arm64`, `x86`, and `arm` are bundled under `vendor/wintun/bin/<arch>/wintun.dll`; the addon discovers the right one automatically based on its own compile-time architecture. No download or copy step is required.
96
+ 2. **Administrator privileges**: required to create the kernel adapter and configure addresses/routes via `netsh`. Launch your shell with **Run as administrator**.
97
+ 3. **Build toolchain (only if compiling from source)**: Visual Studio Build Tools 2022 with the C++ workload, the Windows 10 SDK, and Python 3.x on `PATH`.
98
+
91
99
  ## Usage
92
100
 
93
101
  ### Basic Usage
@@ -207,7 +215,7 @@ socket.connect(port, host, async () => {
207
215
 
208
216
  #### Properties
209
217
  - `name: string` - The device name (e.g., 'utun0', 'tun0')
210
- - `fd: number` - The file descriptor of the device
218
+ - `fd: number` - The native file descriptor on POSIX (macOS/Linux). Returns `-1` on Windows; Wintun does not expose a numeric file descriptor.
211
219
 
212
220
  ### Error Types
213
221
 
@@ -294,3 +302,12 @@ This ensures the signal handler works as intended.
294
302
  ## License
295
303
 
296
304
  Apache-2.0
305
+
306
+ ### Third-party software
307
+
308
+ This package redistributes the official signed **WinTun** DLLs (version 0.14.1) from [wintun.net](https://www.wintun.net/) under the bundled-binary license shipped by the WinTun project. The unmodified binaries and the upstream license live under [vendor/wintun/](vendor/wintun/):
309
+
310
+ - `vendor/wintun/bin/{amd64,arm64,x86,arm}/wintun.dll`
311
+ - `vendor/wintun/LICENSE.txt` &mdash; the upstream WinTun license; required when redistributing the DLL
312
+
313
+ Maintainers can refresh the bundled binaries with `npm run refresh:wintun` after bumping `WINTUN_VERSION` in [scripts/fetch-wintun.mjs](scripts/fetch-wintun.mjs).
package/binding.gyp CHANGED
@@ -51,7 +51,7 @@
51
51
  "VCCLCompilerTool": {
52
52
  "ExceptionHandling": 1,
53
53
  "AdditionalOptions": [
54
- "/std:c++17",
54
+ "/std:c++20",
55
55
  "/O2"
56
56
  ]
57
57
  }
@@ -1,6 +1,7 @@
1
1
  import { DarwinTunTapPlatform } from './darwin.js';
2
2
  import { LinuxTunTapPlatform } from './linux.js';
3
3
  import { UnsupportedTunTapPlatform } from './unsupported.js';
4
+ import { WindowsTunTapPlatform } from './windows.js';
4
5
  /** @internal Built-in {@link TunTapPlatform} for a Node `process.platform` value. */
5
6
  export function createTunTapPlatform(platform) {
6
7
  switch (platform) {
@@ -8,6 +9,8 @@ export function createTunTapPlatform(platform) {
8
9
  return new DarwinTunTapPlatform();
9
10
  case 'linux':
10
11
  return new LinuxTunTapPlatform();
12
+ case 'win32':
13
+ return new WindowsTunTapPlatform();
11
14
  default:
12
15
  return new UnsupportedTunTapPlatform(platform);
13
16
  }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Throws {@link TunTapPermissionError} unless the current process is an
3
+ * elevated (Administrator) Windows process. Mirrors `assertEffectiveRoot`
4
+ * from {@link ./require-root.ts} for POSIX.
5
+ */
6
+ export declare function assertAdminOnWindows(): Promise<void>;
7
+ /**
8
+ * Returns true when the current process is running with Administrator
9
+ * privileges on Windows. Implementation runs `net session` (which always
10
+ * exists, regardless of locale) and inspects the exit code.
11
+ *
12
+ * The result is memoized for the lifetime of the process; admin status cannot
13
+ * change between calls without restarting the shell.
14
+ */
15
+ export declare const isAdministrator: (() => Promise<boolean>) & {
16
+ cache: Map<unknown, Promise<boolean>>;
17
+ };
@@ -0,0 +1,32 @@
1
+ import { util } from '@appium/support';
2
+ import { TunTapPermissionError } from '../errors.js';
3
+ import { execFileAsync } from './exec.js';
4
+ /**
5
+ * Throws {@link TunTapPermissionError} unless the current process is an
6
+ * elevated (Administrator) Windows process. Mirrors `assertEffectiveRoot`
7
+ * from {@link ./require-root.ts} for POSIX.
8
+ */
9
+ export async function assertAdminOnWindows() {
10
+ if (await isAdministrator()) {
11
+ return;
12
+ }
13
+ throw new TunTapPermissionError('TUN interface configuration and routing require Administrator privileges on Windows. ' +
14
+ 'Re-launch the shell with "Run as administrator".');
15
+ }
16
+ /**
17
+ * Returns true when the current process is running with Administrator
18
+ * privileges on Windows. Implementation runs `net session` (which always
19
+ * exists, regardless of locale) and inspects the exit code.
20
+ *
21
+ * The result is memoized for the lifetime of the process; admin status cannot
22
+ * change between calls without restarting the shell.
23
+ */
24
+ export const isAdministrator = util.memoize(async function isAdministratorUncached() {
25
+ try {
26
+ await execFileAsync('net', ['session'], { windowsHide: true });
27
+ return true;
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ });
@@ -0,0 +1,13 @@
1
+ import type { TunTapInterfaceStats, TunTapPlatform } from './types.js';
2
+ /** Windows implementation backed by `netsh` for configuration/routing and
3
+ * PowerShell `Get-NetAdapterStatistics` for byte counters. */
4
+ export declare class WindowsTunTapPlatform implements TunTapPlatform {
5
+ /** @inheritdoc */
6
+ configure(interfaceName: string, address: string, mtu: number): Promise<void>;
7
+ /** @inheritdoc */
8
+ addRoute(interfaceName: string, destination: string): Promise<void>;
9
+ /** @inheritdoc */
10
+ removeRoute(interfaceName: string, destination: string): Promise<void>;
11
+ /** @inheritdoc */
12
+ getStats(interfaceName: string): Promise<TunTapInterfaceStats>;
13
+ }
@@ -0,0 +1,195 @@
1
+ import { TunTapError } from '../errors.js';
2
+ import { log } from '../logger.js';
3
+ import { assertAdminOnWindows } from './require-admin.js';
4
+ import { execFileAsync } from './exec.js';
5
+ /** Tightly-restricted character set for adapter names passed into PowerShell. */
6
+ const SAFE_NAME_RE = /^[A-Za-z0-9_\- ]+$/;
7
+ /** Phrases that indicate `netsh` could not find the requested route/address. */
8
+ const MISSING_TARGET_HINTS = [
9
+ 'element not found',
10
+ 'cannot find',
11
+ 'no matching',
12
+ 'does not exist',
13
+ 'not found',
14
+ ];
15
+ /** Windows implementation backed by `netsh` for configuration/routing and
16
+ * PowerShell `Get-NetAdapterStatistics` for byte counters. */
17
+ export class WindowsTunTapPlatform {
18
+ /** @inheritdoc */
19
+ async configure(interfaceName, address, mtu) {
20
+ await assertAdminOnWindows();
21
+ assertSafeAdapterName(interfaceName);
22
+ log.debug(`[win] configure: interface=${interfaceName} address=${address} mtu=${mtu}`);
23
+ await addIpv6Address(interfaceName, address);
24
+ await setIpv6Mtu(interfaceName, mtu);
25
+ }
26
+ /** @inheritdoc */
27
+ async addRoute(interfaceName, destination) {
28
+ await assertAdminOnWindows();
29
+ assertSafeAdapterName(interfaceName);
30
+ log.debug(`[win] addRoute: interface=${interfaceName} destination=${destination}`);
31
+ await addIpv6Route(interfaceName, destination);
32
+ // WinTun presents as an Ethernet adapter, so Windows requires Neighbor
33
+ // Discovery (NDP) before it will send packets through the interface.
34
+ // For /128 host routes we seed a static neighbor entry so NDP is bypassed
35
+ // and the first connection attempt is not silently dropped.
36
+ if (destination.endsWith('/128')) {
37
+ const address = destination.slice(0, -4);
38
+ await addStaticNeighbor(interfaceName, address);
39
+ }
40
+ }
41
+ /** @inheritdoc */
42
+ async removeRoute(interfaceName, destination) {
43
+ await assertAdminOnWindows();
44
+ assertSafeAdapterName(interfaceName);
45
+ await deleteIpv6Route(interfaceName, destination);
46
+ }
47
+ /** @inheritdoc */
48
+ async getStats(interfaceName) {
49
+ assertSafeAdapterName(interfaceName);
50
+ const script = `Get-NetAdapterStatistics -Name '${interfaceName}' ` +
51
+ '| Select-Object ReceivedBytes,SentBytes,ReceivedUnicastPackets,' +
52
+ 'SentUnicastPackets,ReceivedDiscardedPackets,OutboundDiscardedPackets ' +
53
+ '| ConvertTo-Json -Compress';
54
+ const { stdout } = await execFileAsync('powershell', [
55
+ '-NoProfile',
56
+ '-NonInteractive',
57
+ '-ExecutionPolicy',
58
+ 'Bypass',
59
+ '-Command',
60
+ script,
61
+ ]);
62
+ let parsed;
63
+ try {
64
+ parsed = JSON.parse(stdout);
65
+ }
66
+ catch {
67
+ throw new TunTapError(`Failed to parse Get-NetAdapterStatistics output: ${stdout.trim()}`);
68
+ }
69
+ const num = (key) => {
70
+ const value = parsed[key];
71
+ const n = typeof value === 'number' ? value : parseInt(String(value ?? ''), 10);
72
+ return Number.isFinite(n) ? n : 0;
73
+ };
74
+ return {
75
+ rxBytes: num('ReceivedBytes'),
76
+ rxPackets: num('ReceivedUnicastPackets'),
77
+ rxErrors: num('ReceivedDiscardedPackets'),
78
+ txBytes: num('SentBytes'),
79
+ txPackets: num('SentUnicastPackets'),
80
+ txErrors: num('OutboundDiscardedPackets'),
81
+ };
82
+ }
83
+ }
84
+ /** Validates an adapter name before embedding in a PowerShell expression. */
85
+ function assertSafeAdapterName(interfaceName) {
86
+ if (!SAFE_NAME_RE.test(interfaceName)) {
87
+ throw new TunTapError(`Refusing to use adapter name with unsupported characters: ${JSON.stringify(interfaceName)}`);
88
+ }
89
+ }
90
+ function isMissingTargetError(err) {
91
+ const message = String(err?.message ?? '').toLowerCase();
92
+ return MISSING_TARGET_HINTS.some((hint) => message.includes(hint));
93
+ }
94
+ async function addIpv6Address(interfaceName, address) {
95
+ try {
96
+ const r = await execFileAsync('netsh', [
97
+ 'interface',
98
+ 'ipv6',
99
+ 'add',
100
+ 'address',
101
+ `interface=${interfaceName}`,
102
+ `address=${address}/64`,
103
+ 'store=active',
104
+ ]);
105
+ log.debug(`[win] add address ok: ${r.stdout.trim() || '(no output)'}`);
106
+ }
107
+ catch (err) {
108
+ const message = err.message ?? '';
109
+ log.warn(`[win] add address err: ${message}`);
110
+ if (!/already exists|object already/i.test(message)) {
111
+ throw err;
112
+ }
113
+ log.warn(`Address ${address} may already be configured on ${interfaceName}`);
114
+ }
115
+ }
116
+ async function setIpv6Mtu(interfaceName, mtu) {
117
+ try {
118
+ const r = await execFileAsync('netsh', [
119
+ 'interface',
120
+ 'ipv6',
121
+ 'set',
122
+ 'subinterface',
123
+ interfaceName,
124
+ `mtu=${mtu}`,
125
+ 'store=active',
126
+ ]);
127
+ log.debug(`[win] set mtu ok: ${r.stdout.trim() || '(no output)'}`);
128
+ }
129
+ catch (err) {
130
+ log.warn(`[win] set mtu err: ${err.message ?? err}`);
131
+ throw err;
132
+ }
133
+ }
134
+ async function addIpv6Route(interfaceName, destination) {
135
+ try {
136
+ const r = await execFileAsync('netsh', [
137
+ 'interface',
138
+ 'ipv6',
139
+ 'add',
140
+ 'route',
141
+ destination,
142
+ interfaceName,
143
+ 'store=active',
144
+ ]);
145
+ log.debug(`[win] add route ok: ${r.stdout.trim() || '(no output)'}`);
146
+ }
147
+ catch (err) {
148
+ const message = err.message ?? '';
149
+ log.warn(`[win] add route err: ${message}`);
150
+ if (/already exists|object already/i.test(message)) {
151
+ log.debug(`Route to ${destination} already exists`);
152
+ return;
153
+ }
154
+ throw err;
155
+ }
156
+ }
157
+ async function deleteIpv6Route(interfaceName, destination) {
158
+ try {
159
+ await execFileAsync('netsh', [
160
+ 'interface',
161
+ 'ipv6',
162
+ 'delete',
163
+ 'route',
164
+ destination,
165
+ interfaceName,
166
+ 'store=active',
167
+ ]);
168
+ }
169
+ catch (err) {
170
+ if (isMissingTargetError(err)) {
171
+ return;
172
+ }
173
+ throw err;
174
+ }
175
+ }
176
+ async function addStaticNeighbor(interfaceName, address) {
177
+ log.debug(`[win] addStaticNeighbor: interface=${interfaceName} address=${address}`);
178
+ try {
179
+ const r = await execFileAsync('netsh', [
180
+ 'interface',
181
+ 'ipv6',
182
+ 'add',
183
+ 'neighbor',
184
+ interfaceName,
185
+ address,
186
+ '00-00-00-00-00-01',
187
+ 'store=active',
188
+ ]);
189
+ log.debug(`[win] add neighbor ok: ${r.stdout.trim() || '(no output)'}`);
190
+ }
191
+ catch (err) {
192
+ const msg = err.message ?? String(err);
193
+ log.warn(`[win] add neighbor err: ${msg}`);
194
+ }
195
+ }
package/lib/tunnel.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { TunTap } from './TunTap.js';
2
2
  import { EventEmitter } from 'node:events';
3
- import { Socket } from 'node:net';
3
+ import type { Socket } from 'node:net';
4
4
  import { Buffer } from 'node:buffer';
5
5
  export interface PacketData {
6
6
  protocol: 'TCP' | 'UDP';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-ios-tuntap",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Native TUN/TAP interface module for Node.js",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -15,16 +15,19 @@
15
15
  "format": "prettier -w ./src ./test",
16
16
  "format:check": "prettier --check ./src ./test",
17
17
  "install": "node-gyp-build",
18
+ "refresh:wintun": "node scripts/fetch-wintun.mjs",
18
19
  "prepare": "npm run build",
19
20
  "test": "npm run test:integration && npm run test:unit",
20
- "test:unit": "mocha 'test/unit/**/*.spec.mjs' --exit --timeout 2m",
21
- "test:integration": "mocha 'test/integration/**/*.spec.mjs' --exit --timeout 2m"
21
+ "test:unit": "mocha \"test/unit/**/*.spec.mjs\" --exit --timeout 2m",
22
+ "test:integration": "mocha \"test/integration/**/*.spec.mjs\" --exit --timeout 2m"
22
23
  },
23
24
  "files": [
24
25
  "src/tuntap.cc",
25
26
  "src/native",
26
27
  "lib",
27
28
  "prebuilds",
29
+ "scripts",
30
+ "vendor",
28
31
  "binding.gyp",
29
32
  "package.json",
30
33
  "README.md",
@@ -56,6 +59,7 @@
56
59
  "@semantic-release/changelog": "^6.0.3",
57
60
  "@semantic-release/git": "^10.0.1",
58
61
  "@types/node": "^25.0.1",
62
+ "commander": "^14.0.3",
59
63
  "conventional-changelog-conventionalcommits": "^9.0.0",
60
64
  "mocha": "^11.7.5",
61
65
  "prebuildify": "^6.0.1",
@@ -0,0 +1,70 @@
1
+ // Maintainer-only helper that refreshes the bundled WinTun binaries committed
2
+ // under vendor/wintun/. The npm `install` hook does NOT invoke this script —
3
+ // the package ships with the official signed DLLs already checked in. Run
4
+ // `npm run refresh:wintun -- --version <semver>` to pull a different release.
5
+
6
+ import {fs, logger, net, tempDir, zip} from '@appium/support';
7
+ import {Command} from 'commander';
8
+ import {join, dirname} from 'node:path';
9
+ import {fileURLToPath} from 'node:url';
10
+
11
+ const log = logger.getLogger('refresh-wintun');
12
+
13
+ const DEFAULT_WINTUN_VERSION = '0.14.1';
14
+ const BUNDLED_ARCHES = ['amd64', 'arm64', 'x86', 'arm'];
15
+
16
+ const rootDir = join(dirname(fileURLToPath(import.meta.url)), '..');
17
+ const vendorDir = join(rootDir, 'vendor', 'wintun');
18
+
19
+ async function deployDll(arch, extractDir) {
20
+ const destDir = join(vendorDir, 'bin', arch);
21
+ await fs.mkdir(destDir, {recursive: true});
22
+ const src = join(extractDir, 'wintun', 'bin', arch, 'wintun.dll');
23
+ const dest = join(destDir, 'wintun.dll');
24
+ await fs.copyFile(src, dest);
25
+ log.info(`wintun.dll (${arch}) -> ${dest}`);
26
+ }
27
+
28
+ async function deployLicense(extractDir) {
29
+ const src = join(extractDir, 'wintun', 'LICENSE.txt');
30
+ const dest = join(vendorDir, 'LICENSE.txt');
31
+ await fs.copyFile(src, dest);
32
+ log.info(`LICENSE.txt -> ${dest}`);
33
+ }
34
+
35
+ async function refreshWintun(version) {
36
+ const url = `https://www.wintun.net/builds/wintun-${version}.zip`;
37
+ const tmpDir = await tempDir.openDir();
38
+ try {
39
+ const zipPath = join(tmpDir, 'wintun.zip');
40
+ const extractDir = join(tmpDir, 'out');
41
+ await fs.mkdir(extractDir, {recursive: true});
42
+
43
+ log.info(`Downloading WinTun ${version}...`);
44
+ await net.downloadFile(url, zipPath);
45
+ await zip.extractAllTo(zipPath, extractDir);
46
+
47
+ await fs.mkdir(vendorDir, {recursive: true});
48
+ await Promise.all([
49
+ ...BUNDLED_ARCHES.map((arch) => deployDll(arch, extractDir)),
50
+ deployLicense(extractDir),
51
+ ]);
52
+ } finally {
53
+ await fs.rimraf(tmpDir);
54
+ }
55
+ }
56
+
57
+ const program = new Command();
58
+ program
59
+ .name('refresh-wintun')
60
+ .description('Refresh the bundled WinTun binaries under vendor/wintun/')
61
+ .option(
62
+ '-v, --version <semver>',
63
+ 'WinTun release version to download',
64
+ DEFAULT_WINTUN_VERSION,
65
+ )
66
+ .action(async (options) => {
67
+ await refreshWintun(options.version);
68
+ });
69
+
70
+ await program.parseAsync(process.argv);
@@ -8,6 +8,22 @@ namespace {
8
8
 
9
9
  constexpr LPCWSTR kWintunDllName = L"wintun.dll";
10
10
 
11
+ // Compile-time arch slug used to find the bundled DLL under
12
+ // vendor/wintun/bin/<arch>/wintun.dll. The .node addon is built per-arch, so
13
+ // the arch of the host process is the same as the arch of this translation
14
+ // unit.
15
+ #if defined(_M_X64) || defined(__x86_64__)
16
+ constexpr LPCWSTR kVendoredArch = L"amd64";
17
+ #elif defined(_M_ARM64) || defined(__aarch64__)
18
+ constexpr LPCWSTR kVendoredArch = L"arm64";
19
+ #elif defined(_M_IX86) || defined(__i386__)
20
+ constexpr LPCWSTR kVendoredArch = L"x86";
21
+ #elif defined(_M_ARM) || defined(__arm__)
22
+ constexpr LPCWSTR kVendoredArch = L"arm";
23
+ #else
24
+ constexpr LPCWSTR kVendoredArch = L"amd64";
25
+ #endif
26
+
11
27
  // Returns the directory that contains the addon module that this code is
12
28
  // linked into. Used to locate `wintun.dll` shipped next to `tuntap.node`.
13
29
  std::wstring GetAddonDirectory() {
@@ -75,6 +91,16 @@ bool WintunApi::Load(std::string& error) {
75
91
  if (TryLoadFrom(local.c_str())) {
76
92
  return ResolveEntryPoints(error);
77
93
  }
94
+
95
+ // Bundled fallback: the package ships the official signed DLL under
96
+ // vendor/wintun/bin/<arch>/wintun.dll. Both build/Release and
97
+ // prebuilds/<plat>-<arch> are two directories below the package root,
98
+ // so the same relative path works in either install layout.
99
+ std::wstring vendored = addon_dir + L"\\..\\..\\vendor\\wintun\\bin\\" +
100
+ kVendoredArch + L"\\" + kWintunDllName;
101
+ if (TryLoadFrom(vendored.c_str())) {
102
+ return ResolveEntryPoints(error);
103
+ }
78
104
  }
79
105
 
80
106
  // Fall back to the OS-default search list (Application dir, System32, …)
@@ -0,0 +1,84 @@
1
+ Prebuilt Binaries License
2
+ -------------------------
3
+
4
+ 1. DEFINITIONS. "Software" means the precise contents of the "wintun.dll"
5
+ files that are included in the .zip file that contains this document as
6
+ downloaded from wintun.net/builds.
7
+
8
+ 2. LICENSE GRANT. WireGuard LLC grants to you a non-exclusive and
9
+ non-transferable right to use Software for lawful purposes under certain
10
+ obligations and limited rights as set forth in this agreement.
11
+
12
+ 3. RESTRICTIONS. Software is owned and copyrighted by WireGuard LLC. It is
13
+ licensed, not sold. Title to Software and all associated intellectual
14
+ property rights are retained by WireGuard. You must not:
15
+ a. reverse engineer, decompile, disassemble, extract from, or otherwise
16
+ modify the Software;
17
+ b. modify or create derivative work based upon Software in whole or in
18
+ parts, except insofar as only the API interfaces of the "wintun.h" file
19
+ distributed alongside the Software (the "Permitted API") are used;
20
+ c. remove any proprietary notices, labels, or copyrights from the Software;
21
+ d. resell, redistribute, lease, rent, transfer, sublicense, or otherwise
22
+ transfer rights of the Software without the prior written consent of
23
+ WireGuard LLC, except insofar as the Software is distributed alongside
24
+ other software that uses the Software only via the Permitted API;
25
+ e. use the name of WireGuard LLC, the WireGuard project, the Wintun
26
+ project, or the names of its contributors to endorse or promote products
27
+ derived from the Software without specific prior written consent.
28
+
29
+ 4. LIMITED WARRANTY. THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF
30
+ ANY KIND. WIREGUARD LLC HEREBY EXCLUDES AND DISCLAIMS ALL IMPLIED OR
31
+ STATUTORY WARRANTIES, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS
32
+ FOR A PARTICULAR PURPOSE, QUALITY, NON-INFRINGEMENT, TITLE, RESULTS,
33
+ EFFORTS, OR QUIET ENJOYMENT. THERE IS NO WARRANTY THAT THE PRODUCT WILL BE
34
+ ERROR-FREE OR WILL FUNCTION WITHOUT INTERRUPTION. YOU ASSUME THE ENTIRE
35
+ RISK FOR THE RESULTS OBTAINED USING THE PRODUCT. TO THE EXTENT THAT
36
+ WIREGUARD LLC MAY NOT DISCLAIM ANY WARRANTY AS A MATTER OF APPLICABLE LAW,
37
+ THE SCOPE AND DURATION OF SUCH WARRANTY WILL BE THE MINIMUM PERMITTED UNDER
38
+ SUCH LAW. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
39
+ WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR
40
+ A PARTICULAR PURPOSE OR NON-INFRINGEMENT ARE DISCLAIMED, EXCEPT TO THE
41
+ EXTENT THAT THESE DISCLAIMERS ARE HELD TO BE LEGALLY INVALID.
42
+
43
+ 5. LIMITATION OF LIABILITY. To the extent not prohibited by law, in no event
44
+ WireGuard LLC or any third-party-developer will be liable for any lost
45
+ revenue, profit or data or for special, indirect, consequential, incidental
46
+ or punitive damages, however caused regardless of the theory of liability,
47
+ arising out of or related to the use of or inability to use Software, even
48
+ if WireGuard LLC has been advised of the possibility of such damages.
49
+ Solely you are responsible for determining the appropriateness of using
50
+ Software and accept full responsibility for all risks associated with its
51
+ exercise of rights under this agreement, including but not limited to the
52
+ risks and costs of program errors, compliance with applicable laws, damage
53
+ to or loss of data, programs or equipment, and unavailability or
54
+ interruption of operations. The foregoing limitations will apply even if
55
+ the above stated warranty fails of its essential purpose. You acknowledge,
56
+ that it is in the nature of software that software is complex and not
57
+ completely free of errors. In no event shall WireGuard LLC or any
58
+ third-party-developer be liable to you under any theory for any damages
59
+ suffered by you or any user of Software or for any special, incidental,
60
+ indirect, consequential or similar damages (including without limitation
61
+ damages for loss of business profits, business interruption, loss of
62
+ business information or any other pecuniary loss) arising out of the use or
63
+ inability to use Software, even if WireGuard LLC has been advised of the
64
+ possibility of such damages and regardless of the legal or quitable theory
65
+ (contract, tort, or otherwise) upon which the claim is based.
66
+
67
+ 6. TERMINATION. This agreement is affected until terminated. You may
68
+ terminate this agreement at any time. This agreement will terminate
69
+ immediately without notice from WireGuard LLC if you fail to comply with
70
+ the terms and conditions of this agreement. Upon termination, you must
71
+ delete Software and all copies of Software and cease all forms of
72
+ distribution of Software.
73
+
74
+ 7. SEVERABILITY. If any provision of this agreement is held to be
75
+ unenforceable, this agreement will remain in effect with the provision
76
+ omitted, unless omission would frustrate the intent of the parties, in
77
+ which case this agreement will immediately terminate.
78
+
79
+ 8. RESERVATION OF RIGHTS. All rights not expressly granted in this agreement
80
+ are reserved by WireGuard LLC. For example, WireGuard LLC reserves the
81
+ right at any time to cease development of Software, to alter distribution
82
+ details, features, specifications, capabilities, functions, licensing
83
+ terms, release dates, APIs, ABIs, general availability, or other
84
+ characteristics of the Software.
@@ -0,0 +1,37 @@
1
+ # WinTun (vendored)
2
+
3
+ This directory contains the unmodified, official signed [WinTun](https://www.wintun.net/) binaries that this package loads at runtime on Windows.
4
+
5
+ - **Upstream:** https://www.wintun.net/
6
+ - **Version:** 0.14.1
7
+ - **Source archive:** https://www.wintun.net/builds/wintun-0.14.1.zip
8
+ - **License:** see [`LICENSE.txt`](./LICENSE.txt). The DLLs are redistributed under the upstream prebuilt-binary license, which permits bundling unmodified copies alongside software that uses the official `wintun.h` API.
9
+
10
+ ## Layout
11
+
12
+ ```
13
+ vendor/wintun/
14
+ LICENSE.txt # Upstream license — MUST ship with the DLLs
15
+ bin/amd64/wintun.dll # x64 (Intel/AMD)
16
+ bin/arm64/wintun.dll # ARM64
17
+ bin/x86/wintun.dll # 32-bit Intel/AMD
18
+ bin/arm/wintun.dll # 32-bit ARM
19
+ ```
20
+
21
+ The package's CI prebuild matrix only produces `win32-x64` and `win32-arm64` artifacts, so most users only ever load the `amd64` or `arm64` DLL. The 32-bit binaries are bundled for completeness so anyone compiling the native addon from source on `_M_IX86` / `_M_ARM` finds a matching DLL via the addon's compile-time arch lookup.
22
+
23
+ The native addon (`src/native/wintun_loader.cc`) discovers the DLL through this layout, so no install-time copy step is required.
24
+
25
+ ## Refreshing the binaries
26
+
27
+ Maintainers can pull the latest official release with:
28
+
29
+ ```sh
30
+ npm run refresh:wintun
31
+ ```
32
+
33
+ This invokes [`scripts/fetch-wintun.mjs`](../../scripts/fetch-wintun.mjs), which downloads the ZIP from `wintun.net`, extracts the per-architecture DLLs and `LICENSE.txt` into this directory, and overwrites the existing files. Bump `WINTUN_VERSION` in that script before running.
34
+
35
+ ## Do not modify
36
+
37
+ The DLLs MUST be redistributed unmodified. Do not recompile, repackage, or rename them. If you need to update WinTun, run the refresh script against a new upstream release rather than hand-editing files in this directory.
Binary file
Binary file