Skip to content

Conversation

@serverleader
Copy link
Contributor

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()

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()`
@Joannis Joannis linked an issue Oct 9, 2025 that may be closed by this pull request
@Joannis
Copy link
Member

Joannis commented Oct 9, 2025

Incredible work! Thanks for the PR

@Joannis Joannis self-requested a review October 9, 2025 12:12
Copy link
Member

@Joannis Joannis left a 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?

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
@Joannis Joannis merged commit 448cbbe into orlandos-nl:main Oct 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remote Port Forwarding

3 participants