CI / cargo fmt (push) Has been cancelled
CI / cargo clippy (macos-latest) (push) Has been cancelled
CI / cargo clippy (ubuntu-latest) (push) Has been cancelled
CI / cargo clippy (windows-latest) (push) Has been cancelled
CI / cargo test (macos-latest) (push) Has been cancelled
CI / cargo test (ubuntu-latest) (push) Has been cancelled
CI / cargo test (windows-latest) (push) Has been cancelled
CI / cargo build (macos-latest) (push) Has been cancelled
CI / cargo build (ubuntu-latest) (push) Has been cancelled
CI / cargo build (windows-latest) (push) Has been cancelled
CI / cargo build --release (macos-latest) (push) Has been cancelled
CI / cargo build --release (ubuntu-latest) (push) Has been cancelled
CI / cargo build --release (windows-latest) (push) Has been cancelled
CI / CLI smoke (macos-latest) (push) Has been cancelled
CI / CLI smoke (ubuntu-latest) (push) Has been cancelled
CI / CLI smoke (windows-latest) (push) Has been cancelled
CI / Minimal E2E (macos-latest) (push) Has been cancelled
CI / Minimal E2E (ubuntu-latest) (push) Has been cancelled
CI / Minimal E2E (windows-latest) (push) Has been cancelled
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
87 lines
4.0 KiB
Markdown
87 lines
4.0 KiB
Markdown
# 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.
|