FAQ
What is Subnetra, in one sentence?
A pure-Zig, zero-dependency Layer-3 UDP tunnel that ships as a single static binary under 512 KB and connects sites and devices in a hub-and-spoke overlay with full per-link encryption.
Is it a VPN? How is it different from WireGuard?
It is a Layer-3 encrypted overlay, so it solves a similar problem to WireGuard. The differences are deliberate trade-offs:
- No handshake. Subnetra is stateless and handshake-free; the per-packet epoch plus a static config replaces session negotiation. There is no Noise handshake, no rekey timer, no roaming handshake.
- Single static binary, no kernel module, no third-party libraries — it runs entirely in userspace on a TUN device and cross-compiles to musl targets down to armv5.
- Hub-and-spoke by design, with an in-binary CIDR policy engine for site-to-site routing and hub relay, hot-updated without a restart.
It is not trying to be a drop-in WireGuard replacement; it targets fixed, operator-managed deployments where a tiny auditable binary and static topology are the priority.
How is it different from n2n?
Both build an encrypted overlay, but the designs are near-opposites:
- Star, not P2P. n2n’s signature is supernode-assisted NAT hole-punching so edges talk directly. Subnetra is strict hub-and-spoke and deliberately has no P2P / hole-punching — every spoke-to-spoke packet relays through the hub, for one predictable path (a non-goal).
- Layer 3, not Layer 2. n2n is an Ethernet (TAP) overlay with broadcast, ARP and any protocol. Subnetra routes IPv4 by CIDR only — no broadcast domain.
- Handshake-free, one fixed cipher. n2n has a registration protocol and per-community selectable ciphers. Subnetra has no registration round-trip and one mandatory AEAD (ChaCha20-Poly1305) with a unique key per link.
- Static, not discovered. n2n finds peers dynamically via supernodes. Subnetra uses static numeric endpoints with no in-daemon discovery or DNS.
Pick n2n for plug-and-play P2P and L2 LAN semantics; pick Subnetra for a tiny, auditable binary with a deterministic single-path topology.
Why no handshake? Isn’t that insecure?
No. Every packet is encrypted and authenticated with ChaCha20-Poly1305 under a per-link key. Replay is stopped by a 64-bit monotonic nonce and a sliding-window filter, and a per-restart session epoch is mixed into key derivation so old captures can’t be replayed across a restart. “Handshake-free” means there is no negotiation round-trip — not that packets are unauthenticated. See the Security Model.
Does it hide that it’s a tunnel? Is it “stealth”?
Partly. Obfuscation is stateless and best-effort: a malformed or unauthenticated datagram is silently dropped with no error reply, so the listener does not advertise itself to blind scanners. Subnetra does not claim to defeat a sophisticated DPI adversary, and it is honest about that — see Design Principles → Stateless obfuscation.
The mesh-wide obfuscate setting is on by default: it masks the 20-byte header so
the datagram looks random to a passive observer and de-periodizes the keepalive cadence
(it hides the fingerprint, not packet length or timing). Set obfuscate: false to send a
readable cleartext header (e.g. for packet-capture debugging), which a passive observer
can then fingerprint.
See Wire Protocol → Header obfuscation.
What platforms are supported?
- Linux is the production target:
x86_64,aarch64,armv7(hard float), andarmv5(soft float), all static musl. The hub typically runs on Linux. - macOS is a supported spoke / developer platform via the native
utundevice (minimal-dynamic, linking only libSystem). It is not a production hub target.
How big / fast is it?
The Linux release binary is a single static musl executable under 512 KB. The
data plane is single-threaded, lock-free, and strictly allocation-free on the
hot path, so memory use is bounded and predictable. For a throughput baseline on
your own hardware, run
test/integration/bench.sh.
What MTU should I use?
The fixed wire overhead is 64 bytes (20-byte header + 16-byte tag + 28-byte
outer IPv4/UDP). The safe tunnel MTU is therefore path_mtu − 64 — e.g. 1452 on a
1500-byte underlay. Set local_tun_mtu accordingly, and use
subnetrad --print-network-plan --path-mtu <n> to compute and preview the host
plan. See the Network Plan.
Does Subnetra configure the host network for me?
No — by design it only prints the plan; it never mutates host routing or
firewall state. subnetrad --print-network-plan emits the exact ip/route
commands so you (or your config-management tool) apply them deliberately and
auditable. The daemon does create and manage its own TUN device.
How do PSKs work? Can two links share a key?
Each link (each peer pair, per direction) uses its own 64-hex pre-shared key.
Keys must be unique per link — never reuse a PSK across peers. Generate them
with zig build tool:keygen. Directional keys are derived from the PSK, so the A→B
and B→A directions use different keys.
How do I route a real LAN behind a spoke (site-to-site)?
Set the LAN prefix in remote_routes/local_routes and add policy rules that
forward the destination prefix to the right mesh id. The hub relays between spokes.
See Configuration → Roles and the
policy add examples.
How do I run it on RouterOS / MikroTik?
Via the RouterOS container feature (a static-binary container on the device). See Operations → RouterOS.
The hub has a dynamic IP — now what?
Endpoints are numeric on purpose (no in-daemon DNS). Solve it operationally: run a
small DDNS watcher on the spoke that rewrites the hub endpoint and reloads. The
spoke’s NAT keepalive keeps the path open. See
Security Model → NAT keepalive.
Is there a built-in failover / multi-path?
No. The data plane is intentionally single-path; failover is an external decision (VRRP / health-checked DNS / orchestration). This keeps the daemon small and predictable. See Deployment → High Availability and the Roadmap.
When is v2 (kcp_arq / fec_xor) coming?
Those are reserved interface points, design-only, returning
error.NotImplemented until the maintainer approves the design RFC. v1 ships
raw_direct only. See the Roadmap.
Why Zig, and why zero dependencies?
To get a tiny, statically-linked, auditable binary with predictable memory and no supply chain — the whole data plane is the standard library plus raw syscalls. The Design Principles (“eight iron laws”) explain the reasoning in full.
Where is the authoritative spec?
The normative on-wire contract is
docs/PROTOCOL.md;
the product requirements are
docs/subnetra-develop.md.
This site summarizes and operationalizes them; where they disagree with this site,
they win.