implement ssh *remote port forwarding #7
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_proxy#7
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What you described is remote port forwarding, often called a reverse SSH tunnel. The public SSH server listens on some port, and traffic arriving there gets carried over the SSH connection back to your laptop’s local
127.0.0.1:8080. In OpenSSH terms, that isssh -R ..., not-L.-Lis the opposite direction: a port on your laptop forwards to something reachable from the remote side. ([GitHub][1])Your case looks like this:
Example with OpenSSH:
That means: “on the SSH server, listen on port
9000, and whenever someone connects there, forward the bytes through the SSH session to127.0.0.1:8080on my laptop.” Whether0.0.0.0is allowed depends on the SSH server config, especiallyGatewayPorts; otherwise it may bind only to loopback on the server side. ([Docs.rs][2])For a pure Rust library, the best fit I found is
russh. Its docs describe it as a pure Rust SSH client/server implementation, and its feature list explicitly includes bothdirect-tcpipfor local port forwarding andforward-tcpipfor remote port forwarding. ([Docs.rs][3])The mental model in
russhis:direct-tcpipchannel when a local socket accepts a connectiontcpip_forward, and then handle incomingforwarded-tcpipchannels when the remote server gets new connections. ([Docs.rs][4])So for your server, the flow is:
127.0.0.1:8080.A practical
Cargo.tomlstarting point:A minimal implementation sketch looks like this:
The important part is the callback
channel_open_forwarded_tcpip(...). That callback is the signal that a user hit the remote port. At that moment you connect to local127.0.0.1:8080and pump bytes between the SSH channel and the socket. That matchesrussh’s documented remote-forwarding model, where the server notifies the client by opening a forwarded TCP channel for each incoming remote connection. ([Docs.rs][4])A few implementation notes for putting this into your server:
ssh_host,ssh_user,remote_bind_addr,remote_port,local_target_addr, and auth material.trueincheck_server_key.127.0.0.1or0.0.0.0; public exposure usually requires server-side permission.PURPOSE
e.g. I can forward TCP 80 443 on remote SSH to the local PROXY which will then process it like it was coming in directly over TCP
the configuration happens fully over UDS OPENRPC like we do the rest
adjust server/ openrpc spec/ sdk autogenerates/make some examples in rust how to set this up
Implementation Spec for Issue #7 — SSH Remote Port Forwarding
Objective
Add a managed SSH remote port forwarding service to
hero_proxy_server. Users configure reverse SSH tunnels via the existing UDS OpenRPC API. The proxy establishes outbound SSH connections to remote hosts, requeststcpip-forward, and bridges forwarded channels to local TCP addresses.Requirements
TunnelClientstruct implementingrussh::client::Handlerwithchannel_open_forwarded_tcpipcallbacktunnel.list,tunnel.add,tunnel.get,tunnel.remove,tunnel.start,tunnel.stop,tunnel.statusSshTunnelschemaFiles to Modify/Create
hero_proxy_server/Cargo.tomlrussh,russh-keysdepshero_proxy_server/src/tunnel.rshero_proxy_server/src/main.rstunnel.*RPC methods, spawn tunnels on startuphero_proxy_server/src/proxy.rsactive_tunnelsto AppStatehero_proxy_server/src/db.rsssh_tunnelstable, SshTunnel struct, CRUD methodshero_proxy_server/openrpc.jsonSshTunnelschema andtunnel.*methodshero_proxy_ui/static/admin.htmlhero_proxy_examples/examples/ssh_tunnel.rsImplementation Plan
Step 1: Add russh dependencies and DB schema
Files:
Cargo.toml,db.rsrusshandrussh-keysdependenciesSshTunnelstruct andssh_tunnelstable DDLlistenerspatternStep 2: Implement SSH tunnel module
Files:
tunnel.rs(new)TunnelClientimplementingrussh::client::Handlerproxy_channel_and_socketfor bidirectional copyTunnelHandlestruct with shutdown channelspawn_tunnelfunction with auth, keepalive, reconnect loopStep 3: Wire tunnels into AppState, RPC handler, and startup
Files:
proxy.rs,main.rsactive_tunnelsto AppStatetunnel.*RPC method handlersStep 4: Update the OpenRPC specification
Files:
openrpc.jsonSshTunnelcomponent schematunnel.*method definitionsStep 5: Add "Tunnels" tab to admin UI
Files:
admin.htmlrpc()helperStep 6: Create SDK example
Files:
examples/ssh_tunnel.rsAcceptance Criteria
russh/russh-keysdependencies addedssh_tunnelstable with full CRUD in db.rstunnel.rsimplements russh Handler withchannel_open_forwarded_tcpiptunnel.*RPC methods functional via UDScargo testpasses,cargo clippycleanNotes
remote_bind_addrto0.0.0.0(requires SSH serverGatewayPorts yes)tunnel.startreturns immediately; usetunnel.statusto poll connection stateImplementation Summary
Changes Made
New files:
crates/hero_proxy_server/src/tunnel.rs— Core SSH tunnel module:TunnelClient(russh Handler), bidirectional channel↔socket proxy, reconnect loop with exponential backoff,spawn_tunnel()lifecycle managerModified files:
crates/hero_proxy_server/Cargo.toml— Addedrusshandrussh-keysdependenciescrates/hero_proxy_server/src/db.rs— AddedSshTunnelstruct,ssh_tunnelstable DDL, and full CRUD methods (list, get, add, update, remove)crates/hero_proxy_server/src/proxy.rs— Addedactive_tunnelsfield toAppStatecrates/hero_proxy_server/src/main.rs— Auto-start enabled tunnels on boot, clean shutdown on exitcrates/hero_proxy_server/src/lib.rs— Addedmod tunnel, wired 8 RPC methods (tunnel.list/get/add/update/remove/start/stop/status)crates/hero_proxy_server/openrpc.json— AddedSshTunnelschema and alltunnel.*method definitionscrates/hero_proxy_ui/static/admin.html— Added "Tunnels" tab with full management UI (list, add, start, stop, remove)Test Results
Features
tunnel.list,tunnel.get,tunnel.add,tunnel.update,tunnel.remove,tunnel.start,tunnel.stop,tunnel.statusImplementation committed:
f2a7f96Browse:
f2a7f96