Tun/Tap interfaces
This crate allows the creation and usage of Tun and Tap interfaces(supporting both Ipv4 and ipv6), aiming to make this cross-platform.
Features:
- Supporting TUN and TAP
- Supporting both IPv4 and IPv6
- Supporting Synchronous and Asynchronous API
- Supports choosing between Tokio and async-io for asynchronous I/O operations.
- All platforms have consistent IP packets(macOS's 4-byte head information can be eliminated)
- Supporting Offload (
TSO
/GSO
) on Linux - Supporting
multi-queue
on Linux - Having a consistent behavior of setting up routes when creating a device
- Supporting shutdown for Synchronous version
- Implement TAP mode on macOS using
feth
Supported Platforms
Platform | TUN | TAP |
---|---|---|
Windows | ✅ | ✅ |
Linux | ✅ | ✅ |
macOS | ✅ | ✅* |
FreeBSD | ✅ | ✅ |
Android | ✅ | |
iOS | ✅ | |
Other* | ✅ |
For other Unix-like platforms,You can use raw_fd;
Usage
First, add the following to your Cargo.toml
:
[]
# Base sync API (no async runtime)
= "2"
## For async runtime integration
## (choose ONE based on your runtime):
# tokio:
#tun-rs = { version = "2", features = ["async"] }
# async-std, smol, and other
# asynchronous runtimes based on async-io:
#tun-rs = { version = "2", features = ["async_io"] }
Example
The following example creates and configures a TUN interface and reads packets from it synchronously.
use DeviceBuilder;
An example of asynchronously reading packets from an interface
use DeviceBuilder;
async
On Unix, a device can also be directly created using a file descriptor (fd).
use SyncDevice;
More examples are here
Linux
You will need the tun-rs
module to be loaded and root is required to create
interfaces.
TSO
/GSO
and multi-queue
is supported on the Linux platform, enable it via the config
use DeviceBuilder;
use ;
macOS & FreeBSD
tun-rs
will automatically set up a route according to the provided configuration, which does a similar thing like
this:
sudo route -n add -net 10.0.0.0/24 10.0.0.1
Implement TAP mode on macOS using a pair of feth
interfaces. This approach differs from TAP on other Unix platforms—please pay special attention to the following points:
-
The system will not automatically destroy
feth
interfaces (they rely on the destructor to execute theifconfig destroy
command), so killing the process may leave behind residual feth interfaces. This is similar to TAP behavior on Windows. -
Of the
feth
pair, one is used for basic operations such as IP configuration, while the other is used for I/O operations and is accessed via BPF. As a result, multiple file descriptors are involved, so caution is needed when using AsRawFd or IntoRawFd.
iOS
You can pass the file descriptor of the TUN device to tun-rs
to create the interface.
Here is an example to create the TUN device on iOS and pass the fd
to tun-rs
:
// Swift
class PacketTunnelProvider: NEPacketTunnelProvider {
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
let tunnelNetworkSettings = createTunnelSettings() // Configure TUN address, DNS, mtu, routing...
setTunnelNetworkSettings(tunnelNetworkSettings) { [weak self] error in
// The tunnel of this tunFd is contains `Packet Information` prifix.
let tunFd = self?.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int32
DispatchQueue.global(qos: .default).async {
start_tun(tunFd)
}
completionHandler(nil)
}
}
}
pub extern "C"
Android
// use android.net.VpnService
private void
Windows
Tun:
You need to copy the wintun.dll file which matches your architecture to the same directory as your executable and run your program as administrator.
Tap:
When using the tap network interface, you need to manually install tap-windows that matches your architecture.