# Architecture rustunnel is organized as a single Rust binary crate with a modular source tree. The architecture separates CLI parsing, credential generation, TLS configuration, SOCKS5 handling, binary framing, and the core tunnel engine into distinct modules. ## Component diagram ```mermaid graph TD A[CLI `src/cli.rs`] --> B[Main dispatch `src/main.rs`] B --> C[Credential generation `src/generate.rs`] B --> D[Tunnel engine `src/tunnel.rs`] B --> E[Connection keys `src/connkey.rs`] D --> F[TLS stack `src/tls.rs`] D --> G[SOCKS5 proxy `src/socks5.rs`] D --> H[Framing protocol `src/framing.rs`] D --> I[Signal handling `src/signal.rs`] F --> J[Rustls + ring] G --> K[Tokio TCP] H --> L[Bytes + tokio-util] C --> M[rcgen] ``` ## Data flow A typical tunnel session flows like this: 1. **Listener** binds a TCP socket and wraps it with `tokio_rustls::TlsAcceptor`. 2. Connector initiates a TCP connection and upgrades it with `tokio_rustls::TlsConnector`. 3. Both sides perform mTLS handshakes: the listener requires a client certificate signed by the shared CA; the connector validates the server certificate against the same CA. 4. The connector sends an HTTP POST to `/tunnel` with an `X-Rustunnel-Token` header. 5. The listener validates the token with a constant-time comparison (`src/tunnel.rs`). 6. On success, both sides switch from HTTP/1.1 to a binary framing protocol (`src/framing.rs`). 7. The connector's local SOCKS5 proxy accepts client connections and opens multiplexed streams over the single persistent tunnel. 8. The listener decodes each stream's target address, opens a local TCP connection to that target, and forwards data bidirectionally. ```mermaid sequenceDiagram participant Client as Local app participant Socks as SOCKS5 proxy participant Conn as Connector participant TLS as mTLS tunnel participant List as Listener participant Target as Target server Client->>Socks: SOCKS5 CONNECT Socks->>Conn: open stream Conn->>TLS: TLS handshake TLS->>List: accept + verify client cert Conn->>List: POST /tunnel + auth token List->>Conn: 200 OK Conn->>List: binary framing CONNECT frame List->>Target: TCP connect Target->>List: response List->>Conn: DATA frame Conn->>Socks: raw bytes Socks->>Client: response ``` ## Module responsibilities | Module | Responsibility | | ------ | -------------- | | `src/cli.rs` | clap-based CLI definitions for all subcommands and arguments | | `src/main.rs` | Entry point, crypto provider installation, tracing init, command dispatch | | `src/tunnel.rs` | Core tunnel engine: listener accept loop, connector reconnect loop, SOCKS5 proxy, stream mux, HTTP auth handshake, framing loop | | `src/tls.rs` | rustls server and client config builders, certificate loading, identity validation, insecure verifier | | `src/socks5.rs` | SOCKS5 greeting, auth, CONNECT request parsing, target resolution | | `src/framing.rs` | Binary frame serialization/deserialization, `FrameReader`, `FrameWriter` | | `src/generate.rs` | Self-signed CA, server cert, client cert, and auth token generation with rcgen | | `src/connkey.rs` | `ConnectionKey` struct: encode/decode all material as a base64 string | | `src/redact.rs` | `Redacted` wrapper and helpers to prevent secrets from leaking into logs | | `src/errors.rs` | `thiserror`-based error enums for TLS, auth, tunnel, and host operations | | `src/config.rs` | JSON configuration file format for generated credential sets | | `src/signal.rs` | Cross-platform shutdown signal handler (SIGINT/SIGTERM on Unix, Ctrl+C on Windows) | ## Threading model The project uses Tokio's multi-threaded runtime. Each side (listener and connector) spawns tasks for: - Accepting new TCP connections - TLS handshakes - Per-tunnel framing loops - Per-stream target forwarding - SOCKS5 client handling The connector's SOCKS5 proxy stays bound permanently while a background reconnect loop maintains the tunnel. When the tunnel drops, existing streams receive EOF and new streams wait for the reconnect loop to re-establish the session.