appium-ios-tuntap
v0.4.3
Published
Native TUN/TAP interface module for Node.js
Downloads
613,139
Readme
TunTap Bridge
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.
Description
This module provides a Node.js interface to TUN/TAP virtual network devices, allowing you to create and manage network tunnels from JavaScript/TypeScript. It's useful for VPNs, network tunneling, and other network-related applications.
Features
- Cross-platform: Works on macOS (utun), Linux (TUN/TAP), and Windows (WinTun)
- TypeScript support: Full TypeScript definitions included
- Signal handling: Graceful shutdown on SIGINT/SIGTERM
- Thread safety: Safe to use from multiple Node.js worker threads
- Resource management: Automatic cleanup of file descriptors and network interfaces
- Enhanced error handling: Custom error types for better debugging
- Input validation: Validates IPv6 addresses, MTU ranges, and buffer sizes
- Performance optimized: Built with C++17 and compiler optimizations
- Network statistics: Get interface statistics (RX/TX bytes, packets, errors)
Installation
npm install appium-ios-tuntapPrerequisites
macOS
On macOS, the module uses the built-in utun interfaces. No additional setup is required, but you'll need administrator privileges to create and configure the interfaces.
Linux
On Linux, the module requires:
TUN/TAP Kernel Module: The TUN/TAP kernel module must be loaded.
# Check if the module is loaded lsmod | grep tun # If not loaded, load it sudo modprobe tun # To load it automatically at boot echo "tun" | sudo tee -a /etc/modulesPermissions: The user running the application needs access to
/dev/net/tun.# Option 1: Run your application with sudo sudo node your-app.js # Option 2: Add your user to the 'tun' group (if it exists) sudo usermod -a -G tun your-username # Option 3: Create a udev rule to set permissions echo 'KERNEL=="tun", GROUP="your-username", MODE="0660"' | sudo tee /etc/udev/rules.d/99-tuntap.rules sudo udevadm control --reload-rules sudo udevadm triggeriproute2 Package: The
ipcommand is required for configuring interfaces.# Debian/Ubuntu sudo apt install iproute2 # CentOS/RHEL sudo yum install iproute # Arch Linux sudo pacman -S iproute2Development Headers: If you're building from source, you'll need the Linux kernel headers.
# Debian/Ubuntu sudo apt install linux-headers-$(uname -r) # CentOS/RHEL sudo yum install kernel-devel # Arch Linux sudo pacman -S linux-headers
Windows
On Windows the module uses WinTun (the same userspace TUN driver shipped with WireGuard). Requirements:
wintun.dll: ships with the package. The official signed binaries foramd64,arm64,x86, andarmare bundled undervendor/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.- Administrator privileges: required to create the kernel adapter and configure addresses/routes via
netsh. Launch your shell with Run as administrator. - 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.
Usage
Basic Usage
import { TunTap } from 'appium-ios-tuntap';
// Create a TUN device
const tun = new TunTap();
// Open the device
if (tun.open()) {
console.log(`Opened TUN device: ${tun.name}`);
// Configure the device with an IPv6 address and MTU
await tun.configure('fd00::1', 1500);
// Add a route
await tun.addRoute('fd00::/64');
// Read from the device
const data = tun.read(4096);
if (data.length > 0) {
console.log(`Read ${data.length} bytes`);
}
// Write to the device
const buffer = Buffer.from([/* your packet data */]);
const bytesWritten = tun.write(buffer);
console.log(`Wrote ${bytesWritten} bytes`);
// Get interface statistics
const stats = await tun.getStats();
console.log('RX bytes:', stats.rxBytes);
console.log('TX bytes:', stats.txBytes);
// Close the device when done
tun.close();
}Error Handling
import { TunTap, TunTapError, TunTapPermissionError, TunTapDeviceError } from 'appium-ios-tuntap';
try {
const tun = new TunTap();
tun.open();
await tun.configure('fe80::1', 1500);
// ... use the device ...
tun.close();
} catch (err) {
if (err instanceof TunTapPermissionError) {
console.error('Permission denied. Please run with sudo.');
} else if (err instanceof TunTapDeviceError) {
console.error('Device error:', err.message);
} else if (err instanceof TunTapError) {
console.error('TUN/TAP error:', err.message);
} else {
console.error('Unexpected error:', err);
}
}Tunnel Manager
import { connectToTunnelLockdown } from 'appium-ios-tuntap';
import { Socket } from 'net';
// Create a socket connection to your tunnel endpoint
const socket = new Socket();
socket.connect(port, host, async () => {
try {
// Establish tunnel connection
const tunnel = await connectToTunnelLockdown(socket);
console.log('Tunnel established:', tunnel.Address);
// Add packet consumer
tunnel.addPacketConsumer({
onPacket: (packet) => {
console.log(`${packet.protocol} packet: ${packet.src}:${packet.sourcePort} → ${packet.dst}:${packet.destPort}`);
}
});
// Or use async iteration
for await (const packet of tunnel.getPacketStream()) {
console.log('Received packet:', packet);
}
// Close tunnel when done
await tunnel.closer();
} catch (err) {
console.error('Tunnel error:', err);
}
});API Reference
TunTap Class
Constructor
new TunTap(name?: string)- Create a new TUN/TAP device instance
Methods
open(): boolean- Open the TUN deviceclose(): boolean- Close the TUN deviceread(maxSize?: number): Buffer- Read data from the device (default: 4096 bytes)write(data: Buffer): number- Write data to the deviceconfigure(address: string, mtu?: number): Promise<void>- Configure IPv6 address and MTUaddRoute(destination: string): Promise<void>- Add a route to the deviceremoveRoute(destination: string): Promise<void>- Remove a route from the devicegetStats(): Promise<Stats>- Get interface statistics
Properties
name: string- The device name (e.g., 'utun0', 'tun0')fd: number- The native file descriptor on POSIX (macOS/Linux). Returns-1on Windows; Wintun does not expose a numeric file descriptor.
Error Types
TunTapError- Base error class for all TUN/TAP errorsTunTapPermissionError- Thrown when there are permission issuesTunTapDeviceError- Thrown when the device is not available or cannot be opened
Signal Handling
The module automatically handles SIGINT and SIGTERM signals for graceful shutdown. All open devices will be closed and network interfaces cleaned up when the process exits.
Troubleshooting
Linux Issues
"TUN/TAP device not available": The TUN/TAP kernel module is not loaded.
- Solution:
sudo modprobe tun
- Solution:
"Permission denied" when opening /dev/net/tun: The user doesn't have sufficient permissions.
- Solution: Run with sudo or add your user to the 'tun' group.
"Permission denied" when configuring the interface: The user doesn't have sudo privileges.
- Solution: Run the application with sudo or configure sudo to allow the specific commands without a password.
"Command not found" when configuring the interface: The
ipcommand is not available.- Solution: Install the iproute2 package.
macOS Issues
"Failed to create control socket": The application doesn't have sufficient permissions.
- Solution: Run with sudo.
"Could not find an available utun device": All utun devices are in use.
- Solution: Close other applications that might be using utun devices.
Debug Mode
Enable debug logging by running your application with the --debug flag:
node your-app.js --debugTesting
Most tests for this module require root privileges (sudo) to create and manage TUN/TAP devices.
- If you run the tests without root, privileged tests will be automatically skipped.
- Some tests may interact with system networking; use caution on production systems.
- The test suite is designed to clean up after itself, but always verify no stray TUN/TAP devices remain after running.
Running the Tests
From the project root, run:
sudo npx mocha test/tuntap-unit.spec.jsOr, to run all tests in the test/ directory:
sudo npx mochaIf you are not running as root, you will see a message that tests are skipped.
Manual Testing for Signal Handling (v0.0.4+)
Automated tests cannot reliably verify process cleanup on SIGINT/SIGTERM due to test runner limitations.
To manually verify the fix for signal handling (introduced in v0.0.4):
- Run the CLI utility:
sudo node test/test-tuntap.js - While it is running, press
Ctrl+Cto send SIGINT. - Confirm that:
- The process exits immediately.
- All TUN/TAP devices are closed and cleaned up.
This ensures the signal handler works as intended.
License
Apache-2.0
Third-party software
This package redistributes the official signed WinTun DLLs (version 0.14.1) from 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/bin/{amd64,arm64,x86,arm}/wintun.dllvendor/wintun/LICENSE.txt— the upstream WinTun license; required when redistributing the DLL
Maintainers can refresh the bundled binaries with npm run refresh:wintun after bumping WINTUN_VERSION in scripts/fetch-wintun.mjs.
