Multi-Hop SSH Tunneling: Two Chilkat Arrangements
Reach a second SSH server through a first SSH server by using either ConnectThroughSsh directly or a local dynamic SOCKS forwarder as the transport for a second SSH session.
Both arrangements create two independent SSH sessions. SSH Server 1 terminates the first session and forwards an opaque connection carrying the second. SSH Server 2 terminates the second session and opens the final destination connection.
Arrangement A: ConnectThroughSsh
An Ssh object owns the first session. An SshTunnel object borrows it as transport for the second.
Arrangement B: Dynamic SOCKS + Socket
An outer SshTunnel exposes a local SOCKS listener. A Socket uses it to negotiate the second SSH session.
Use SshTunnel.ConnectThroughSsh
The existing Ssh object is borrowed, not copied. It must remain alive, connected, and authenticated while the second tunnel is in use.
The second-session path visibly enters and exits SSH Server 1. Server 1 removes only the outer SSH protection and forwards the still-encrypted SSH 2 byte stream.
API sequence
Ssh object to Server 1.ConnectThroughSsh(ssh1, server2, 22).SshTunnel.HostKeyFingerprint.SshTunnel independently to Server 2.BeginAccepting.Chilkat.Ssh ssh1 = new Chilkat.Ssh();
bool success = ssh1.Connect("bastion.example.com", 22);
// Verify ssh1.HostKeyFingerprint.
success = ssh1.AuthenticatePw("jump-user", "jump-password");
Chilkat.SshTunnel tunnel = new Chilkat.SshTunnel();
success = tunnel.ConnectThroughSsh(ssh1, "ssh2.internal", 22);
// Verify tunnel.HostKeyFingerprint for Server 2.
success = tunnel.AuthenticatePw("internal-user", "internal-password");
tunnel.DestHostname = "db.internal";
tunnel.DestPort = 5432;
success = tunnel.BeginAccepting(15432);
SshTunnel and its clients before disconnecting ssh1.Use dynamic SOCKS forwarding and a Socket SSH session
The outer SshTunnel connects to Server A and runs a local SOCKS server. Socket tunnelB connects to that SOCKS listener and negotiates an independent SSH session with Server B.
The inner Socket first connects to the local SOCKS listener. The listener forwards the request through Server A to Server B:22. SSH session 2 remains end-to-end between tunnelB and Server B.
API sequence
SshTunnel to Server A.DynamicPortForwarding = true and call BeginAccepting(1080).tunnelB.Socks* for localhost:1080.SshOpenTunnel, verify Server B's host key, and authenticate independently.SshNewChannel to obtain a destination channel as another Socket byte stream.Chilkat.SshTunnel outer = new Chilkat.SshTunnel();
bool success = outer.Connect("www.ssh-serverA.com", 22);
// Verify outer.HostKeyFingerprint.
success = outer.AuthenticatePw("loginA", "passwordA");
outer.DynamicPortForwarding = true;
outer.InboundSocksUsername = "chilkat123";
outer.InboundSocksPassword = "password123";
success = outer.BeginAccepting(1080);
Chilkat.Socket tunnelB = new Chilkat.Socket();
tunnelB.SocksHostname = "localhost";
tunnelB.SocksPort = 1080;
tunnelB.SocksVersion = 5;
tunnelB.SocksUsername = "chilkat123";
tunnelB.SocksPassword = "password123";
success = tunnelB.SshOpenTunnel("www.ssh-serverB.com", 22);
// Verify Server B's host key, then authenticate.
success = tunnelB.SshAuthenticatePw("loginB", "passwordB");
Chilkat.Socket channel = new Chilkat.Socket();
success = tunnelB.SshNewChannel("time-c.nist.gov", 37, false, 4000, channel);
Comparison
| Concept | Arrangement A | Arrangement B |
|---|---|---|
| First SSH session | Ssh | Outer SshTunnel |
| Second-session transport | Directly borrowed by ConnectThroughSsh | Local SOCKS5 connection forwarded through the outer tunnel |
| Second SSH session | SshTunnel | Socket tunnelB |
| Application-facing result | Static or dynamic local forwarding listener | A Socket channel returned by SshNewChannel |
| SSH identities | Server 1 and Server 2 have independent host keys and credentials. | |
| At Server 1 | The outer session ends; the still-encrypted second SSH session is forwarded rather than terminated. | |
| After Server 2 | The destination connection is ordinary unless the destination protocol adds TLS or another security layer. | |