Languages
๐บ๐ธ English | ๐ท๐บ ะ ัััะบะธะน
Cross-platform Rust library for TUN/TAP tunnel interfaces, designed to compose with the rest of the Lattice networking stack.
0.4.0 published, active design/implementation. See
ARCHITECTURE.md for the crate architecture โ nothing in
it is API-frozen yet; every type, trait, and feature flag may still change
in a future 0.x release (see versioning.md's pre-1.0 policy).
- Creates and configures TUN (raw IP) and TAP (Ethernet-framed) devices on
Linux, Windows, and macOS through the
tun-rscrate; - Transfers packets on an open device, synchronously by default and, with
the optional
async-ioortokiofeature (mutually exclusive), through afutures::Streamโ no async runtime is pulled in unless one of them is enabled; - Re-reads and patches an open device's MTU and administrative state;
- On Linux, marks a device persistent across process exit and duplicates a
hardware-scheduled queue on the same device for another thread โ see
crates/tunnel-lattice/README.md, "Persistent devices and multi-queue."
Tunnel Lattice does not assign IP addresses to the interfaces it creates โ see "Interop with net-lattice" below.
Tunnel Lattice and net-lattice never share a process-independent object
identity: a tunnel_lattice::DeviceId and a net_lattice::InterfaceId are
distinct phantom-typed wrappers even when their underlying native index
happens to coincide, so the two crates never let you pass one where the
other is expected by accident. Bridge them through the OS-assigned
interface name instead โ the one field both sides expose in the same
shape:
use net_lattice::Lattice;
use tunnel_lattice::{DeviceConfig, DeviceKind, Tunnel};
let tunnel = Tunnel::connect();
let device = tunnel.open(DeviceConfig::new(DeviceKind::Tun))?;
let snapshot = device.snapshot()?; // has `snapshot.name`, e.g. "tun0"
let lattice = Lattice::connect()?;
let interface = lattice
.interfaces()?
.into_iter()
.find(|i| i.name == snapshot.name)
.ok_or(net_lattice::Error::NotFound)?;
// assign an address, bring it up, etc. through `net-lattice` from here.
# Ok::<(), Box<dyn std::error::Error>>(())name is advisory on DeviceConfig (see its docs) โ a backend may assign a
different name than requested, especially on Windows โ so always read the
name back from snapshot()/the returned Device, never from the
DeviceConfig you passed in.
use tunnel_lattice::{DeviceConfig, DeviceKind, Result, Tunnel};
fn main() -> Result<()> {
let tunnel = Tunnel::connect();
let device = tunnel.open(DeviceConfig::new(DeviceKind::Tun).with_mtu(1500))?;
let mut buf = vec![0u8; 1500];
let len = device.recv(&mut buf)?;
println!("{len} bytes");
Ok(())
}See crates/tunnel-lattice/README.md for feature flags and a fuller usage
walkthrough.
The workspace is split into focused crates. Each crate has its own crate-level README with its scope and a usage example:
| Crate | Purpose |
|---|---|
tunnel-lattice |
Public facade: Tunnel/Handle, feature-gated backend selection |
tunnel-lattice-model |
Observed/desired device types (Device, DeviceConfig, DeviceConfigPatch) |
tunnel-lattice-platform |
Provider traits and Capability contract |
tunnel-lattice-core |
Shared errors, results, and IDs |
tunnel-lattice-async |
Runtime-independent futures::Stream: native over a backend's AsyncPacketIo, thread-bridged otherwise |
tunnel-lattice-backend-tunrs |
tun-rs-backed cross-platform TUN/TAP implementation |
| Crate | Purpose |
|---|---|
| net-lattice | OS networking inspection and configuration (routes, DNS, interfaces) |
| tunnel-lattice | TUN/TAP tunnel interfaces |
| dns-lattice | Programmable DNS control plane |
| flow-lattice | Policy compiler: rules -> platform-neutral network plans |
| sdk-lattice | Application-facing SDK composing the crates above |
See CONTRIBUTING.md. Feedback on the crate architecture and API shape in ARCHITECTURE.md is the most valuable contribution at this stage.
Licensed under the Mozilla Public License 2.0.