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>
56 lines
2.5 KiB
Markdown
56 lines
2.5 KiB
Markdown
# 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 `rtun1.`.
|
|
|
|
## 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:
|
|
|
|
```rust
|
|
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.
|