docs: add comprehensive project wiki for v1.0
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>
This commit is contained in:
root
2026-06-04 14:07:55 -06:00
co-authored by factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
parent a758e8e0bc
commit 0166fb6511
32 changed files with 1483 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
# 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.
+101
View File
@@ -0,0 +1,101 @@
# Getting started
## Prerequisites
- Rust 1.85+ (the project uses Edition 2024)
- A POSIX shell or PowerShell for running commands
- curl (for E2E testing)
## Build
```sh
cd rustunnel
cargo build --release
```
The release binary is produced at `target/release/rustunnel`.
## Run tests
```sh
cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo check
cargo test --all-targets
```
The test suite includes unit tests for framing, SOCKS5 parsing, TLS config building, credential generation, connection key roundtrips, and full end-to-end tunnel flows.
## Generate credentials
```sh
./target/release/rustunnel generate --out ./creds
```
This creates:
- `creds/ca.pem` — CA certificate
- `creds/ca.key` — CA private key
- `creds/server.crt` — server certificate
- `creds/server.key` — server private key
- `creds/client.crt` — client certificate
- `creds/client.key` — client private key
- `creds/token.txt` — auth token
- `creds/config.json` — configuration file with paths and defaults
## Run a tunnel
### Start the listener
```sh
./target/release/rustunnel listen \
--listen 127.0.0.1:4180 \
--cert ./creds/server.crt \
--key ./creds/server.key \
--ca-cert ./creds/ca.pem \
--auth-token-file ./creds/token.txt
```
### Start the connector
```sh
./target/release/rustunnel connect \
--target 127.0.0.1:4180 \
--socks 127.0.0.1:1180 \
--cert ./creds/client.crt \
--key ./creds/client.key \
--ca-cert ./creds/ca.pem \
--auth-token-file ./creds/token.txt
```
### Use the SOCKS5 proxy
```sh
curl --proxy socks5h://127.0.0.1:1180 http://127.0.0.1:4181/
```
## Using a connection key
Instead of passing individual certificate paths, you can generate a single connection key:
```sh
./target/release/rustunnel keygen --target 127.0.0.1:4180
```
Then start the listener with the key (it auto-generates credentials):
```sh
./target/release/rustunnel listen --connection-key <key>
```
And connect with the same key:
```sh
./target/release/rustunnel connect <key>
```
## Defaults
- Listener bind address: `0.0.0.0:4180`
- Connector target: required (or taken from connection key)
- Connector SOCKS5 proxy: `127.0.0.1:1180`
+19
View File
@@ -0,0 +1,19 @@
# Glossary
**Connection key** — a base64-encoded JSON blob (prefix `rtun1.`) that bundles the CA certificate, server certificate, server key, client certificate, client key, target address, auth token, and version. Generated by `rustunnel keygen` and consumed by `rustunnel listen` and `rustunnel connect`.
**Connector** — the `rustunnel connect` side. Establishes an outbound HTTPS+mTLS connection to the listener, authenticates, then exposes a local SOCKS5 proxy for local applications.
**Framing protocol** — the binary protocol used after the HTTP auth handshake completes. Frame types: CONNECT, CONNECT_REPLY, DATA, CLOSE, ERROR. All multi-byte integers are big-endian. Max payload per frame is 4 MiB.
**Listener** — the `rustunnel listen` side. Binds an HTTPS server that accepts mTLS connections, validates the auth token, then upgrades the connection to the binary framing protocol.
**mTLS** — mutual TLS. Both the listener and connector present certificates and verify the peer's certificate against a shared CA. rustunnel uses rustls with ring as the crypto provider.
**Security gate** — one of the validation steps that must pass before tunnel forwarding begins: TLS handshake, client certificate verification (listener), server certificate verification (connector), application auth token validation.
**SOCKS5 proxy** — the local proxy exposed by the connector. Implements RFC 1928 CONNECT with optional username/password auth (RFC 1929). Supports IPv4 and domain name targets.
**Stream ID** — a monotonically increasing odd integer (1, 3, 5, ...) assigned by the connector for each SOCKS5 connection. Even IDs are reserved for future server-initiated streams.
**StreamMux** — the connector-side structure that manages multiple concurrent streams over a single tunnel connection. Maps stream IDs to per-stream data channels.
+20
View File
@@ -0,0 +1,20 @@
# rustunnel
`rustunnel` is a cross-platform Rust CLI tool for lab and development tunneling over HTTPS with mutual TLS (mTLS) and an application-level auth token. It exposes a local SOCKS5 proxy on the connector side and forwards traffic only after HTTPS, certificate, and auth checks succeed.
The tool is designed for local labs, development environments, and controlled testing where you own or are authorized to operate both endpoints. It is not a production-grade tunnel or a mechanism for accessing systems without permission.
## What it does
- **Listener** (`rustunnel listen`) — binds an HTTPS server that accepts mTLS connections from connectors, validates an auth token, then upgrades the connection to a persistent binary-framed tunnel.
- **Connector** (`rustunnel connect`) — connects to the listener over HTTPS with mTLS, authenticates, then exposes a local SOCKS5 proxy that forwards traffic through the tunnel.
- **Credential generation** (`rustunnel generate`) — creates a self-signed CA, server certificate, client certificate, and auth token for a local session.
- **Connection keys** (`rustunnel keygen`) — bundles all credential material into a single base64-encoded string that can be copy-pasted between machines.
## Quick links
- [Architecture](../overview/architecture.md)
- [Getting started](../overview/getting-started.md)
- [Tunnel engine](../systems/tunnel-engine.md)
- [TLS stack](../systems/tls-stack.md)
- [Security posture](../security.md)