Forwarding & tunnels

All four of these dedicate an entire SSHConnection to the operation; while one is active, the connection cannot host any other job.

Direct TCP channel

let channel = try await connection.openDirectTCPChannel(
    host: "10.0.0.5",
    port: 6379
)
try await channel.write(Data("PING\r\n".utf8))
let reply = try await channel.read(maximumLength: 64 * 1024)
try await channel.close()

Use this when you have a target host+port reachable from the SSH server and you want to drive the protocol yourself.

Local forward (-L)

The SSH server forwards traffic from a local listener to a remote target.

let forward = try await connection.startLocalForward(
    localHost: "127.0.0.1",
    localPort: 0,        // 0 = let the kernel pick
    remoteHost: "db.internal",
    remotePort: 5432
)
print("listening on \(forward.boundHost):\(forward.boundPort)")
try await forward.close()

Remote forward (-R)

The SSH server listens on its side and forwards connections back to the local target.

let forward = try await connection.startRemoteForward(
    remoteHost: "127.0.0.1",
    remotePort: 0,
    localHost: "127.0.0.1",
    localPort: 8080
)

Dynamic SOCKS (-D)

SSHKit runs a SOCKS5 server on a local bind that routes new TCP connections through the SSH session.

let socks = try await connection.startDynamicForward(
    localHost: "127.0.0.1",
    localPort: 0,
    username: nil,
    password: nil
)
print("SOCKS5 endpoint: \(socks.boundHost):\(socks.boundPort)")

username and password are for SOCKS5 client authentication if you want the local SOCKS server to require them. All forward objects expose the actually-bound host and port via boundHost / boundPort — useful when you passed 0.