-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
Description
Overview
Allow connecting to RDP servers through an SSH tunnel. This enables secure connections to machines behind firewalls/NATs, and adds an extra encryption layer.
Architecture
Drift Client SSH Server RDP Server
┌──────────────┐ ┌──────────────┐ ┌──────────┐
│ │ │ │ │ │
│ RDP Client │──TCP───►│ SSH Tunnel │──TCP──►│ Port 3389│
│ localhost │ :14389 │ (forwarding) │ │ │
│ :14389 │ │ │ │ │
│ │ │ │ │ │
└──────────────┘ └──────────────┘ └──────────┘
1. Drift opens SSH connection to jump host
2. Creates local port forward: localhost:14389 → rdp-host:3389
3. IronRDP connects to localhost:14389
4. Traffic tunneled through SSH
Implementation Plan
Step 1: SSH connection via russh
russh is a pure-Rust async SSH library (tokio-based):
use russh::client;
use russh_keys::key;
let config = Arc::new(client::Config::default());
let mut session = client::connect(config, (ssh_host, ssh_port), handler).await?;
session.authenticate_publickey(username, key).await?;
// Local port forward
let channel = session.channel_open_direct_tcpip(
rdp_host, rdp_port, // remote destination
"127.0.0.1", local_port // local bind
).await?;Step 2: TCP proxy
Create a local TCP listener on a random port. For each accepted connection, forward data bidirectionally through the SSH channel:
let listener = TcpListener::bind("127.0.0.1:0").await?;
let local_port = listener.local_addr()?.port();
// Accept connection and pipe to SSH channel
tokio::spawn(async move {
let (tcp_stream, _) = listener.accept().await?;
let (tcp_read, tcp_write) = tcp_stream.into_split();
// Bidirectional copy between tcp_stream and ssh_channel
});Step 3: Connection config
Add SSH tunnel settings to ConnectionConfig:
interface ConnectionConfig {
// ... existing fields ...
sshTunnel?: {
enabled: boolean;
host: string; // SSH jump host
port: number; // SSH port (22)
username: string; // SSH username
authMethod: 'key' | 'password';
keyPath?: string; // Path to private key
};
}Step 4: Auth methods
Support:
- SSH key auth (default):
~/.ssh/id_ed25519,~/.ssh/id_rsa - Password auth (fallback)
- SSH agent forwarding
~/.ssh/configProxyJump parsing (reuse existing SSH config import)
Step 5: UI
- "SSH Tunnel" section in Connection Form
- Toggle: Enable SSH tunnel
- Fields: SSH host, port, username, key path
- Status indicator showing tunnel is active
- Auto-detect SSH keys from
~/.ssh/
Files to create/modify
src-tauri/src/rdp/ssh_tunnel.rs— new module: SSH connection + TCP proxysrc-tauri/src/rdp/session.rs— establish tunnel before RDP connectionsrc-tauri/src/rdp/client.rs— connect to localhost tunnel portsrc/types.ts— add SSH tunnel fields to ConnectionConfigsrc/components/connections/ConnectionForm.tsx— SSH tunnel UI sectionsrc-tauri/Cargo.toml— addrussh,russh-keys
Dependencies
russh= "0.46" — async SSH clientrussh-keys= "0.46" — SSH key handling
References
- russh crate — pure Rust SSH
- SSH port forwarding in Rust — tutorial
- MS-RDPBCGR over SSH — standard RDP over any TCP transport
Reactions are currently unavailable