Files
rustunnel/droid-wiki/systems/tunnel-engine.md
T
rootandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> 0166fb6511
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
docs: add comprehensive project wiki for v1.0
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-06-04 14:07:55 -06:00

4.1 KiB

Tunnel engine

The tunnel engine in src/tunnel.rs is the largest module (~3,500 lines). It implements the listener, connector, SOCKS5 proxy, stream multiplexer, reconnect loop, and HTTP auth handshake.

Purpose

The tunnel engine establishes a persistent, authenticated, mTLS-encrypted tunnel between a listener and a connector, then multiplexes multiple SOCKS5 streams over that single connection.

Key abstractions

Type File Description
ListenerConfig src/tunnel.rs Bind address, optional SOCKS5 address, TLS material, auth token, insecure flag
ConnectorConfig src/tunnel.rs Target host/port, TLS material, auth token, insecure flag
ServerTlsMaterial src/tunnel.rs Enum: file paths or embedded PEM strings for server-side TLS
ClientTlsMaterial src/tunnel.rs Enum: file paths or embedded PEM strings for client-side TLS
StreamMux src/tunnel.rs Connector-side multiplexer: manages stream IDs, data channels, and frame dispatch
ServerStreamEntry src/tunnel.rs Listener-side target write half for an active stream
ConnectorStreamEntry src/tunnel.rs Connector-side data channel and reply channel for an active stream

How it works

Listener side

  1. run_listener binds a TCP socket, builds the TLS acceptor from ServerTlsMaterial, and starts accepting connections.
  2. handle_listener_connection performs the TLS accept, verifies the client certificate (unless insecure), reads the HTTP POST to /tunnel, and validates the X-Rustunnel-Token header with constant_time_compare.
  3. On auth success, it calls handle_framing_server to switch to binary framing.
  4. handle_framing_server reads frames from the tunnel. A CONNECT frame triggers a TCP connection to the target address (opened from the listener side). DATA frames are forwarded to the target. CLOSE frames shut down the target connection.
  5. If the listener was started with --socks, a server-side SOCKS5 proxy runs via run_socks5_proxy, receiving the active StreamMux through a watch::channel.

Connector side

  1. run_connector_with_socks builds the client TLS config and starts two concurrent pieces: a reconnect loop and a permanently-bound SOCKS5 proxy.
  2. run_reconnect_loop repeatedly attempts to connect to the listener with exponential backoff (1s to 30s). Each attempt re-runs all security gates: TLS handshake, server cert verification, and auth token exchange.
  3. On success, the loop creates a StreamMux, publishes it via the watch::channel, and waits for the framing task to finish (indicating disconnection).
  4. When the tunnel drops, the loop logs the disconnection and retries.
  5. run_socks5_proxy accepts SOCKS5 connections. For each connection, it checks if the StreamMux is available, opens a stream via mux.open_stream(), and performs bidirectional forwarding.

Stream multiplexing

StreamMux::open_stream allocates the next odd stream ID, registers a data channel and reply channel, sends a CONNECT frame, and waits for a CONNECT_REPLY. The caller receives a mpsc::Receiver<Bytes> for tunnel-to-SOCKS5 data.

StreamMux::dispatch_frame routes inbound CONNECT_REPLY, DATA, CLOSE, and ERROR frames to the correct stream by ID.

graph TD
    A[SOCKS5 client] -->|CONNECT| B[SOCKS5 proxy]
    B -->|open_stream| C[StreamMux]
    C -->|CONNECT frame| D[Framing writer]
    D -->|TLS| E[Listener framing]
    E -->|decode target| F[TCP connect to target]
    F -->|DATA| E
    E -->|DATA frame| D
    D -->|dispatch| C
    C -->|data_rx| B
    B -->|raw bytes| A

Entry points for modification

  • To change auth behavior: modify handle_listener_connection (listener) and authenticate_tunnel (connector) in src/tunnel.rs.
  • To change reconnect strategy: modify run_reconnect_loop in src/tunnel.rs.
  • To add listener-side SOCKS5 behavior: the server-side SOCKS5 proxy is currently minimal; expand run_socks5_proxy in src/tunnel.rs.

Key source files

File Purpose
src/tunnel.rs Full tunnel engine: listener, connector, SOCKS5 proxy, reconnect, framing loops, stream mux