-
-
Notifications
You must be signed in to change notification settings - Fork 63
feat: implement remote port forwarding (reverse tunneling) #117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Implements remote port forwarding (reverse tunneling) API for Citadel. ## What is Remote Port Forwarding? Remote port forwarding allows exposing a local service through a remote SSH server. When someone connects to a port on the remote server, that connection is forwarded back through the SSH tunnel to the client machine. ## Implementation ### Client API - `SSHClient.createRemotePortForward(host:port:handler:)` - Request remote port forward - `SSHClient.cancelRemotePortForward(_:)` - Cancel active forward - Uses NIOSSH's GlobalRequest.TCPForwardingRequest API - Returns `SSHRemotePortForward` with bound port information ### Server API - `RemotePortForwardDelegate` protocol for handling forward requests - `DefaultRemotePortForwardDelegate` implementation with port range restrictions - `SSHServer.enableRemotePortForward(withDelegate:)` to activate feature - Implements `GlobalRequestDelegate.tcpForwardingRequest()`
|
Incredible work! Thanks for the PR |
Examples/RemotePortForwardExample/Sources/RemotePortForwardExample/main.swift
Outdated
Show resolved
Hide resolved
Joannis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work! The NSLog issue needs to be replaced with a structured swift-log approach. Other than that it looks great!
I also have an idea on how to expand the remote port forwarding APIs, but that can and should be a separate PR.
Do you want me to fix the logging, or do you want to take a stab at it yourself?
Sources/Citadel/RemotePortForward/Client/RemotePortForward+Client.swift
Outdated
Show resolved
Hide resolved
No need to access client.logger through the weak reference. Logger is captured once and used safely in the @sendable closure
Adds modern async/await-based APIs for both client and server-side remote
port forwarding, replacing low-level EventLoopFuture patterns with ergonomic
NIOAsyncChannel interfaces.
## Client-Side Enhancements
### High-Level Convenience API
- `withRemotePortForward(forwardingTo:)` - Simplest API for forwarding to local services
- Automatically handles bidirectional forwarding using GlueHandler
- Example: Forward remote port 8080 to local HTTP server on port 3000
### NIOAsyncChannel API
- `withRemotePortForward(configure:onAccept:)` - Generic async/await API
- Supports custom channel pipeline configuration
- Type-safe with generic Inbound/Outbound types
- Uses `channel.executeThenClose { inbound, outbound in }` pattern
### Logger Migration
- Replaced NSLog with structured logging (Logger from swift-log)
- Uses proper log levels (trace, debug, info, error, warning)
- Added metadata for better observability
- Created dedicated logger for inbound channel handling
## Server-Side Enhancements
### AsyncRemotePortForwardDelegate
- High-level RemotePortForwardDelegate implementation using NIOAsyncChannel
- Thread-safe channel storage using Swift actors
- Configurable host and port whitelisting for security
- Automatic lifecycle management (tracks and closes server channels)
- Structured logging throughout
Implements remote port forwarding (reverse tunneling) API for Citadel.
What is Remote Port Forwarding?
Remote port forwarding allows exposing a local service through a remote SSH server.
When someone connects to a port on the remote server, that connection is forwarded
back through the SSH tunnel to the client machine.
Implementation
Client API
SSHClient.createRemotePortForward(host:port:handler:)- Request remote port forwardSSHClient.cancelRemotePortForward(_:)- Cancel active forwardSSHRemotePortForwardwith bound port informationServer API
RemotePortForwardDelegateprotocol for handling forward requestsDefaultRemotePortForwardDelegateimplementation with port range restrictionsSSHServer.enableRemotePortForward(withDelegate:)to activate featureGlobalRequestDelegate.tcpForwardingRequest()