Files
rustunnel/droid-wiki/how-to-contribute/patterns-and-conventions.md
T
bzuccaro 2bf8da739b
CI / cargo fmt (push) Canceled after 0s
CI / cargo clippy (macos-latest) (push) Canceled after 0s
CI / cargo clippy (ubuntu-latest) (push) Canceled after 0s
CI / cargo clippy (windows-latest) (push) Canceled after 0s
CI / cargo test (macos-latest) (push) Canceled after 0s
CI / cargo test (ubuntu-latest) (push) Canceled after 0s
CI / cargo test (windows-latest) (push) Canceled after 0s
CI / cargo build (macos-latest) (push) Canceled after 0s
CI / cargo build (ubuntu-latest) (push) Canceled after 0s
CI / cargo build (windows-latest) (push) Canceled after 0s
CI / cargo build --release (macos-latest) (push) Canceled after 0s
CI / cargo build --release (ubuntu-latest) (push) Canceled after 0s
CI / cargo build --release (windows-latest) (push) Canceled after 0s
CI / CLI smoke (macos-latest) (push) Canceled after 0s
CI / CLI smoke (ubuntu-latest) (push) Canceled after 0s
CI / CLI smoke (windows-latest) (push) Canceled after 0s
CI / Minimal E2E (macos-latest) (push) Canceled after 0s
CI / Minimal E2E (ubuntu-latest) (push) Canceled after 0s
CI / Minimal E2E (windows-latest) (push) Canceled after 0s
feat: replace connection keys with short seed-derived rtun3 keys
Connection keys are now a ~49-char seed (rtun3.) instead of a bundled
~1740-char certificate blob. Both endpoints deterministically derive an
identical Ed25519 CA from the seed and mint ephemeral server/client leaves
at startup (keyderive.rs); the app-layer auth token is derived from the seed.
Target is passed separately on connect (resocks-style).

- connkey.rs: rtun3 seed parse/format
- keyderive.rs: CA/server/client/token derivation
- keygen takes no args; connect requires --target
- remove miniz_oxide; TLS layer unchanged
- add determinism + key-based e2e + wrong-seed-rejected tests
- update wiki, README, design spec, CI smoke
2026-08-02 12:31:53 -06:00

2.5 KiB

Patterns and conventions

Error handling

The project uses a layered error strategy:

  • thiserror enums for domain-specific errors (TlsError, AuthError, TunnelError, HostError, Socks5Error, FrameError). These live in src/errors.rs and src/socks5.rs / src/framing.rs.
  • anyhow for application-level propagation. CLI commands return anyhow::Result and main exits with process::exit(exit_code).
  • All errors are designed to be actionable and fail-closed. There are no silent degradation paths to insecure modes.

Secret handling

  • The Redacted wrapper in src/redact.rs must be used before logging any secret.
  • Redacted::inner() and into_inner() are marked #[allow(dead_code)] to discourage use, but available for file writes.
  • is_sensitive() detects PEM private key blocks. is_auth_token() detects long alphanumeric strings.
  • is_connection_key() detects strings starting with rtun3..

Async patterns

  • Tokio's multi-threaded runtime is used on both listener and connector sides.
  • tokio::spawn is used for per-connection and per-stream tasks.
  • tokio::select! with biased; prioritizes shutdown signals over new connections.
  • watch::channel is used for publishing the active StreamMux to the SOCKS5 proxy (supports reconnect).
  • mpsc::channel and oneshot::channel are used for stream data and CONNECT_REPLY coordination.

Constant-time comparison

Auth token comparison in src/tunnel.rs uses a manual constant-time XOR loop to prevent timing attacks:

fn constant_time_compare(a: &str, b: &str) -> bool {
    let a_bytes = a.as_bytes();
    let b_bytes = b.as_bytes();
    if a_bytes.len() != b_bytes.len() {
        return false;
    }
    let mut result: u8 = 0;
    for (x, y) in a_bytes.iter().zip(b_bytes.iter()) {
        result |= x ^ y;
    }
    result == 0
}

Frame reader partial read discipline

FrameReader in src/framing.rs never consumes bytes from the buffer until a complete frame (header + payload) is available. This prevents corruption when TCP segments arrive in arbitrary chunks.

TLS material as enum

Both ServerTlsMaterial and ClientTlsMaterial are enums with Paths and Pem variants. This lets the listener and connector accept either file paths (from CLI args) or embedded PEM strings (from connection keys).

Insecure mode

--insecure-skip-tls-verify exists for DPI/intercepted environments only. When enabled, the listener skips client certificate verification and the connector skips server certificate verification. This is logged at warn level.