Docs: - README.md: index with doc table, ADR table, lifecycle definitions - overview.md: purpose, exports, dependencies, constraints - transport.md: Transport trait, TCP/TLS/iroh implementations, stream join - client.md: SOCKS5 server, port forwarding, channel manager, reconnection - server.md: auth, channel handling, stealth mode, outbound proxy - tun-shim.md: separate privileged process, virtual DNS, --unshare mode - napi-and-pubsub.md: NAPI wrapper, pubsub event target adapter ADRs: - 001: Pluggable transport via AsyncRead+AsyncWrite trait - 002: TUN shim as separate process - 003: iroh stream via tokio::io::join - 004: SSH runs over transport, not alongside - 005: SOCKS5 as primary interface, TUN as add-on - 006(007): NAPI exposes single duplex stream Open questions: 11 items covering TLS certs, iroh relay defaults, Windows TUN, auth expansion, NAPI surface, TCP reconstruction
4.8 KiB
status, last_updated
| status | last_updated |
|---|---|
| draft | 2026-06-01 |
TUN Shim
What
A separate process (wraith-tun) that creates a TUN interface, reads IP packets from it, and forwards them through the core wraith client's SOCKS5 port. Requires root or CAP_NET_ADMIN.
Why
The core wraith binary must never require root. TUN interfaces need elevated privileges. By separating TUN into its own minimal process, we:
- Minimize the root-required code surface (auditable in an afternoon)
- Keep the core binary unprivileged for SOCKS5 and port forwarding
- Allow the TUN shim to crash without affecting the SSH session
- Match the proven tun2proxy architecture
(ADR-002)
Architecture
┌─────────────────┐ ┌──────────────────────────────┐
│ wraith-tun │ │ wraith connect │
│ (root) │ │ (unprivileged) │
│ │ │ │
│ ┌────────────┐ │ │ ┌──────────────────────────┐ │
│ │ TUN Device │ │ │ │ SOCKS5 Server │ │
│ │ (tun-rs) │◄├─────┤├►│ :1080 │ │
│ │ 10.0.0.1/24│ │ │ └──────────────────────────┘ │
│ └────────────┘ │ │ │
│ │ │ ┌──────────────────────────┐ │
│ Route all │ │ │ SSH Client (russh) │ │
│ traffic via │ │ │ connect via Transport │ │
│ TUN device │ │ └──────────────────────────┘ │
└─────────────────┘ └──────────────────────────────┘
Data Flow
- OS routing table sends all traffic through TUN device
tun0 wraith-tunreads IP packets from TUN devicewraith-tunextracts destination IP:port from each packetwraith-tunconnects to127.0.0.1:1080(wraith SOCKS5) withSOCKS5h(domain resolution by proxy)wraith-tunproxies the TCP connection through SOCKS5- wraith's SOCKS5 server opens an SSH direct-tcpip channel to the destination
- Bytes flow: application → TUN → SOCKS5 → SSH channel → server → target
Virtual DNS
The TUN shim implements virtual DNS (same approach as tun2proxy):
- DNS queries to port 53 arriving at the TUN device are intercepted
- Query names are mapped to fake IPs from
198.18.0.0/15 - Connections to fake IPs are resolved to the original domain name via SOCKS5h
- This prevents DNS leaks (all DNS resolution happens server-side)
CLI Interface
# Basic TUN mode (uses wraith's SOCKS5 on 127.0.0.1:1080)
sudo wraith-tun --socks5 127.0.0.1:1080
# With custom TUN address
sudo wraith-tun --socks5 127.0.0.1:1080 --tun-addr 10.0.0.1/24
# With DNS configuration
sudo wraith-tun --socks5 127.0.0.1:1080 --dns virtual
# Unprivileged mode (creates network namespace)
wraith-tun --socks5 127.0.0.1:1080 --unshare
Unprivileged Mode
The --unshare flag creates a new network namespace, sets up the TUN device inside it, and maintains connectivity to the SOCKS5 proxy via the global namespace. This allows running without root, using only CAP_NET_ADMIN capability or namespace creation permissions.
Scope
This is Phase 3 of the implementation plan. The core (wraith serve, wraith connect with SOCKS5 and port forwarding) comes first. TUN is an add-on.
What wraith-tun Does NOT Do
- It does not manage SSH sessions
- It does not know about transports
- It does not handle authentication
- It does not read SSH keys
It only: reads packets from TUN, forwards to SOCKS5. That's it.
Constraints
- Requires root or
CAP_NET_ADMIN(or--unsharenamespace isolation) - IPv4 only in initial release, IPv6 follow-up
- UDP over TCP (DNS queries are handled via SOCKS5h, other UDP is dropped in initial release)
- Approximately 200-500 lines of Rust for the initial implementation
Open Questions
- OQ-03: Windows TUN support scope (wintun.dll dependency)
- OQ-09: Whether to use tun2proxy's
ip-stackcrate for TCP reconstruction or implement a simpler packet-level approach
Design Decisions
| ADR | Decision | Summary |
|---|---|---|
| 002 | TUN separate process | Core never needs root, TUN is thin wrapper |
| 005 | SOCKS5 first | TUN forwards to SOCKS5, not to SSH directly |