No description
  • Rust 97.3%
  • Shell 2.7%
Find a file
Jan De Landtsheer 63f4e0c255
chore: bump workspace version to 0.3.0
v0.2.0 is tagged at f5c5127 (userspace NAPT complete, PRD-0002).
ADR-0020 kernel-delegated NAPT starts the v0.3.x line.
2026-04-24 13:20:32 +02:00
contrib feat: ADR-0020 wire kernel NAPT into daemon + stress + bench (commit 3/4) 2026-04-21 13:28:17 +02:00
crates fix(tun): use libc::Ioctl alias for TUN* constants 2026-04-21 15:56:45 +02:00
docs docs: reflect ADR-0020 in README, operator notes, and examples 2026-04-21 13:40:07 +02:00
examples docs: reflect ADR-0020 in README, operator notes, and examples 2026-04-21 13:40:07 +02:00
fuzz feat: TSO4/TSO6 + CHECKSUM_PARTIAL on TUN (ADR-0017 phases 2+3) 2026-04-20 19:16:23 +02:00
.gitignore chore: gitignore local .claude/ harness state 2026-04-21 13:35:06 +02:00
Cargo.lock feat: nat64-stress crate — in-process scenario driver (PRD-0003 Phase 2) 2026-04-16 11:17:03 +02:00
Cargo.toml chore: bump workspace version to 0.3.0 2026-04-24 13:20:32 +02:00
nat64.toml nat64 v0.1: stateless RFC 7915 translator 2026-04-15 15:11:52 +02:00
README.md docs: reflect ADR-0020 in README, operator notes, and examples 2026-04-21 13:40:07 +02:00

nat64

Stateful NAT64 daemon (RFC 6146 + RFC 7915) in Rust. Replaces Tayga at the routing level for Mycelium-overlay workloads that need to reach the IPv4 internet.

Build

cargo build --release

Binary is target/release/nat64. Run nat64 --help for subcommands.

Prefix selection

NAT64 can use either the RFC 6052 Well-Known Prefix (64:ff9b::/96) or an operator-chosen Network-Specific Prefix (NSP). Pick based on where your v6 clients live:

  • Global IPv6 → public v4 internet: use 64:ff9b::/96. RFC 6052 §3.1 forbids combining it with RFC1918 / loopback pools; the daemon enforces that check at startup.
  • Overlay networks with a constrained range (e.g. Mycelium, which only carries 400::/7): carve a /96 out of the overlay's routable range and use that as your NSP. Example: prefix = "400:dead:beef::/96". No RFC 6052 §3.1 restriction applies to NSPs, so RFC1918 pools are fine.
  • Corporate / lab IPv6: any /96 out of your own space works.

Side-effect worth knowing: daemon-originated ICMP (TTL-exceeded, and PTB in v0.2) uses prefix || gateway_v4 as its v6 source per ADR-0011. When the prefix sits inside your overlay's routable range, replies from the translator are automatically reachable over the overlay — no extra route needed.

NAPT modes (ADR-0020)

Two backends, selected by the napt config key:

  • napt = "daemon" (default, v0.2). Userspace NAPT over a provider-allocated v4 pool. Each v6 source gets per-flow port allocation; distinct clients take distinct pool v4s. Right choice when a provider gives you a /28 (or similar) of routable v4.

  • napt = "kernel" (ADR-0020). 1:1 v6 -> inner-v4 mapping; the host kernel's MASQUERADE hook owns port allocation and conntrack. The daemon never binds any v4 address on any interface, so the F-001 local-table collision class cannot occur. --config geomind auto-selects this mode.

See docs/operator.md "NAPT mode selection" for the per-mode plumbing.

Status

v0.1 scope: /96 prefix only, TCP/UDP/ICMP, stateless per-fragment translation, 1:1 v6→v4 mapping, in-memory bindings with a 5-minute reaper. v0.2 (PRD-0002) adds NAPT, Prometheus metrics, UDS show, and pool affinity. ADR-0020 layers a kernel-delegated NAPT option on top without changing the v0.2 default.

Workspace layout

  • crates/nat64-core — library (translation core, binding table, pool)
  • crates/nat64 — daemon binary (CLI, TUN I/O, reaper, ICMP rate limiter)