feat: implement remote port forwarding (reverse tunneling)#117
Merged
Joannis merged 4 commits intoorlandos-nl:mainfrom Oct 24, 2025
Merged
feat: implement remote port forwarding (reverse tunneling)#117Joannis merged 4 commits intoorlandos-nl:mainfrom
Joannis merged 4 commits intoorlandos-nl:mainfrom
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()`
Closed
Closed
Member
|
Incredible work! Thanks for the PR |
Examples/RemotePortForwardExample/Sources/RemotePortForwardExample/main.swift
Outdated
Show resolved
Hide resolved
Joannis
reviewed
Oct 9, 2025
Member
Joannis
left a comment
There was a problem hiding this comment.
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
Joannis
reviewed
Oct 9, 2025
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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()