Skip to main content

tun_rs/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3/*!
4# tun-rs: Cross-platform TUN/TAP Library
5
6A high-performance, cross-platform Rust library for creating and managing TUN (Layer 3) and TAP (Layer 2)
7network interfaces. This library provides both synchronous and asynchronous APIs with support for advanced
8features like offload (TSO/GSO) on Linux and multi-queue support.
9
10## Features
11
12- **Multi-platform Support**: Windows, Linux, macOS, FreeBSD, OpenBSD, NetBSD, Android, iOS, tvOS, and OpenHarmony
13- **TUN and TAP Modes**: Support for both Layer 3 (TUN) and Layer 2 (TAP) interfaces
14- **Multiple IP Addresses**: Configure multiple IPv4 and IPv6 addresses on a single interface
15- **Async Runtime Integration**: Optional integration with Tokio or async-io/async-std
16- **Advanced Linux Features**:
17  - Offload support (TSO/GSO) for improved performance
18  - Multi-queue support for parallel packet processing
19  - Generic Receive Offload (GRO) for packet coalescing
20- **Platform Consistency**: Uniform packet format across platforms (optional packet information header)
21- **Mobile Support**: Direct file descriptor support for iOS (PacketTunnelProvider) and Android (VpnService)
22
23## Device Types
24
25The library provides three main device types:
26
271. **`SyncDevice`**: Synchronous I/O operations, suitable for single-threaded or blocking code
282. **`AsyncDevice`**: Asynchronous I/O operations, requires the `async` feature flag
293. **`BorrowedDevice`**: Borrowed file descriptor variants that don't take ownership
30
31## Quick Start
32
33### Basic Synchronous Example
34
35Create a TUN interface with IPv4 and IPv6 addresses:
36
37```no_run
38use tun_rs::DeviceBuilder;
39
40let dev = DeviceBuilder::new()
41    .name("utun7")
42    .ipv4("10.0.0.12", 24, None)
43    .ipv6("CDCD:910A:2222:5498:8475:1111:3900:2021", 64)
44    .mtu(1400)
45    .build_sync()
46    .unwrap();
47
48let mut buf = [0; 65535];
49loop {
50    let len = dev.recv(&mut buf).unwrap();
51    println!("Received packet: {:?}", &buf[..len]);
52}
53```
54
55### Asynchronous Example (with Tokio)
56
57Add to your `Cargo.toml`:
58```toml
59[dependencies]
60tun-rs = { version = "2", features = ["async"] }
61```
62
63Then use async I/O:
64
65```no_run
66use tun_rs::DeviceBuilder;
67
68# #[tokio::main]
69# async fn main() -> std::io::Result<()> {
70let dev = DeviceBuilder::new()
71    .ipv4("10.0.0.1", 24, None)
72    .build_async()?;
73
74let mut buf = vec![0; 65536];
75loop {
76    let len = dev.recv(&mut buf).await?;
77    println!("Received: {:?}", &buf[..len]);
78}
79# }
80```
81
82### Mobile Platforms (iOS/Android)
83
84For iOS and Android, use the file descriptor from the system VPN APIs:
85
86```no_run
87#[cfg(unix)]
88{
89    use tun_rs::SyncDevice;
90    // On iOS: from PacketTunnelProvider.packetFlow
91    // On Android: from VpnService.Builder.establish()
92    let fd = 7799; // Example value only - obtain from platform VPN APIs
93    let dev = unsafe { SyncDevice::from_fd(fd).unwrap() };
94
95    let mut buf = [0; 65535];
96    loop {
97        let len = dev.recv(&mut buf).unwrap();
98        println!("Received packet: {:?}", &buf[..len]);
99    }
100}
101```
102
103## Advanced Features
104
105### Multiple IP Addresses
106
107You can add multiple IPv4 and IPv6 addresses to an interface:
108
109```no_run
110# use tun_rs::DeviceBuilder;
111# #[tokio::main]
112# async fn main() -> std::io::Result<()> {
113let dev = DeviceBuilder::new()
114    .ipv4("10.0.0.1", 24, None)
115    .build_async()?;
116
117dev.add_address_v4("10.1.0.1", 24)?;
118dev.add_address_v4("10.2.0.1", 24)?;
119dev.add_address_v6("CDCD:910A:2222:5498:8475:1111:3900:2021", 64)?;
120# Ok(())
121# }
122```
123
124### Linux Offload (TSO/GSO)
125
126On Linux, enable offload for improved throughput:
127
128```no_run
129#[cfg(target_os = "linux")]
130{
131    use tun_rs::{DeviceBuilder, GROTable, IDEAL_BATCH_SIZE, VIRTIO_NET_HDR_LEN};
132
133    let dev = DeviceBuilder::new()
134        .offload(true)  // Enable TSO/GSO
135        .ipv4("10.0.0.1", 24, None)
136        .build_sync()?;
137
138    let mut original_buffer = vec![0; VIRTIO_NET_HDR_LEN + 65535];
139    let mut bufs = vec![vec![0u8; 1500]; IDEAL_BATCH_SIZE];
140    let mut sizes = vec![0; IDEAL_BATCH_SIZE];
141
142    loop {
143        let num = dev.recv_multiple(&mut original_buffer, &mut bufs, &mut sizes, 0)?;
144        for i in 0..num {
145            println!("Packet {}: {:?}", i, &bufs[i][..sizes[i]]);
146        }
147    }
148}
149# Ok(())
150```
151
152## Platform-Specific Notes
153
154### Windows
155- TUN mode requires the [Wintun driver](https://wintun.net/)
156- TAP mode requires [tap-windows](https://build.openvpn.net/downloads/releases/)
157- Administrator privileges required
158
159### Linux
160- Requires the `tun` kernel module (`modprobe tun`)
161- Root privileges required for creating interfaces
162- Supports advanced features: offload, multi-queue
163
164### macOS
165- TUN interfaces are named `utunN`
166- TAP mode uses a pair of `feth` interfaces
167- Routes are automatically configured
168
169### BSD (FreeBSD, OpenBSD, NetBSD)
170- Routes are automatically configured
171- Platform-specific syscall interfaces
172
173## Feature Flags
174
175- **`async`** (alias for `async_tokio`): Enable async support with Tokio runtime
176- **`async_tokio`**: Use Tokio for async I/O operations
177- **`async_io`**: Use async-io for async operations (async-std, smol, etc.)
178- **`async_framed`**: Enable framed I/O with futures
179- **`interruptible`**: Enable interruptible I/O operations
180- **`experimental`**: Enable experimental features (unstable)
181
182## Safety
183
184This library uses `unsafe` code in several places:
185- File descriptor manipulation on Unix platforms
186- FFI calls to platform-specific APIs (Windows, BSD)
187- Direct memory access for performance-critical operations
188
189All unsafe code is carefully audited and documented with safety invariants.
190
191## Performance Considerations
192
193- Use `recv_multiple`/`send_multiple` on Linux with offload enabled for best throughput
194- Enable multi-queue on Linux for parallel packet processing across CPU cores
195- Consider the async API for high-concurrency scenarios
196- Adjust MTU based on your network requirements (default varies by platform)
197
198## Error Handling
199
200All I/O operations return `std::io::Result` with platform-specific error codes.
201Common error scenarios include:
202- Permission denied (need root/administrator)
203- Device name conflicts
204- Platform-specific driver issues
205- Invalid configuration parameters
206*/
207
208#[cfg(any(
209    target_os = "windows",
210    all(target_os = "linux", not(target_env = "ohos")),
211    target_os = "macos",
212    target_os = "freebsd",
213    target_os = "openbsd",
214    target_os = "netbsd",
215))]
216pub use crate::builder::*;
217pub use crate::platform::*;
218
219#[cfg_attr(docsrs, doc(cfg(any(feature = "async_io", feature = "async_tokio"))))]
220#[cfg(any(feature = "async_io", feature = "async_tokio"))]
221mod async_device;
222
223#[cfg_attr(docsrs, doc(cfg(any(feature = "async_io", feature = "async_tokio"))))]
224#[cfg(any(feature = "async_io", feature = "async_tokio"))]
225pub use async_device::*;
226
227#[cfg(any(
228    target_os = "windows",
229    all(target_os = "linux", not(target_env = "ohos")),
230    target_os = "macos",
231    target_os = "freebsd",
232    target_os = "openbsd",
233    target_os = "netbsd",
234))]
235mod builder;
236mod platform;
237
238/// Length of the protocol information header used on some platforms.
239///
240/// On certain Unix-like platforms (macOS, iOS), TUN interfaces may include a 4-byte
241/// protocol information header before each packet. This constant represents that header length.
242///
243/// When `packet_information` is enabled in [`DeviceBuilder`], packets will include this header.
244/// The header typically contains the protocol family (e.g., AF_INET for IPv4, AF_INET6 for IPv6).
245///
246/// # Example
247///
248/// ```no_run
249/// use tun_rs::PACKET_INFORMATION_LENGTH;
250///
251/// let mut buf = vec![0u8; PACKET_INFORMATION_LENGTH + 1500];
252/// // Read packet with header
253/// // let len = dev.recv(&mut buf)?;
254/// // Skip the header to get the actual packet
255/// // let packet = &buf[PACKET_INFORMATION_LENGTH..len];
256/// ```
257pub const PACKET_INFORMATION_LENGTH: usize = 4;