Linux Kernel Network Namespaces โ€ข Unprivileged

Outbound network access,
sealed off at the kernel.

Language-agnostic sandboxing for pytest, npm test, cargo test, or any binary. No code changes, no mock fixtures, no root privileges.

$ cargo install --locked nullroute
bash
PACKET BOUNDARY VISUALIZATION

Raw Packets vs. Surgical Relays

How nullroute traps untrusted egress, mounts socket decoys, and forwards only whitelisted targets.

Host Network (Unisolated)

Raw Packets Allowed
Host Redis (127.0.0.1:6379)
Host Postgres (127.0.0.1:5432)
Docker Daemon (/var/run/docker.sock)
Public Internet & Cloud Metadata
nullroute Boundary
โ‡„ --port 5432 (Local Bridge)
โ‡„ DNS Sinkhole / Relay (Allowed Hosts)
โœ• Decoy Sockets (HTTP 403)
โœ• Raw Sockets / Port 53 -> ENETUNREACH

nullroute Sandbox (Sealed)

Hermetic Namespace
Localhost Bridge (localhost:5432)
Synthetic Loopback Pool (127.77.0.0/24)
Blocked Decoys (Container Runtimes)
Unlisted Hosts -> Immediate Network Drop
POSIX KERNEL GUARANTEES

Strict Systems Invariants

No magic, no kernel modules. Built purely on standard Linux kernel capabilities. Needs unprivileged user namespaces to be enabled; Ubuntu 23.10+ restricts them by default through AppArmor (see the README).

Subsystem Isolation Mechanism Default Protection Configurable Flags
Network Egress CLONE_NEWNET user namespace Sealed (ENETUNREACH) --allow HOST
DNS Resolution Synthetic Sinkhole on port 53 Blocked (NXDOMAIN) --allow synthetic loopback relay
Container Sockets Mount namespace decoy overlay Decoy 403 Mask --seal-docker / --allow-socket
Host Localhost Private isolated loopback (lo) Bidirectional Isolation --port PORT
Process Leftovers /proc/<pid>/task/<tid>/children traversal Killed on Exit (unless nullroute itself is SIGKILLed) Deterministic exit codes passed to CI