SSHClient: add 'sock' parameter to connect() for tunneling

Re #77

This parameter, if set, can be used to make Paramiko wrap an existing socket
connected to a remote SSH server. For instance, you could set up another
SSHClient directly connected to a "gateway" host, and then create a direct-tcpip
tunnel to a "target" host directly accessible from the gateway's perspective
(e.g. think of trying to establish an SSH connection to hosts behind a NAT).
The gateway host would then establish a TCP connection to the target host
directly, and a channel is exposed on the client side. This channel could be
wrapped by an SSHClient class using the connect() function, avoiding the need
to establish a new TCP connnection.

This effectively allows you to create tunneled SSH connections.

Based on work by Oskari Saarenmaa <os@ohmu.fi>, in Paramiko pull request #39.

Signed-off-by: Steven Noonan <steven@uplinklabs.net>
This commit is contained in:
Steven Noonan 2012-10-15 04:09:33 -07:00 committed by Jeff Forcier
parent fd5e29b5a8
commit 31ea4f0734
1 changed files with 21 additions and 16 deletions

View File

@ -229,7 +229,7 @@ class SSHClient (object):
def connect(self, hostname, port=SSH_PORT, username=None, password=None, pkey=None, def connect(self, hostname, port=SSH_PORT, username=None, password=None, pkey=None,
key_filename=None, timeout=None, allow_agent=True, look_for_keys=True, key_filename=None, timeout=None, allow_agent=True, look_for_keys=True,
compress=False): compress=False, sock=None):
""" """
Connect to an SSH server and authenticate to it. The server's host key Connect to an SSH server and authenticate to it. The server's host key
is checked against the system host keys (see L{load_system_host_keys}) is checked against the system host keys (see L{load_system_host_keys})
@ -272,6 +272,9 @@ class SSHClient (object):
@type look_for_keys: bool @type look_for_keys: bool
@param compress: set to True to turn on compression @param compress: set to True to turn on compression
@type compress: bool @type compress: bool
@param sock: an open socket or direct-tcpip channel from another
SSHClient class to use for communication with the target host.
@type channel: socket
@raise BadHostKeyException: if the server's host key could not be @raise BadHostKeyException: if the server's host key could not be
verified verified
@ -280,6 +283,7 @@ class SSHClient (object):
establishing an SSH session establishing an SSH session
@raise socket.error: if a socket error occurred while connecting @raise socket.error: if a socket error occurred while connecting
""" """
if not sock:
for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM): for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM):
if socktype == socket.SOCK_STREAM: if socktype == socket.SOCK_STREAM:
af = family af = family
@ -295,6 +299,7 @@ class SSHClient (object):
except: except:
pass pass
retry_on_signal(lambda: sock.connect(addr)) retry_on_signal(lambda: sock.connect(addr))
t = self._transport = Transport(sock) t = self._transport = Transport(sock)
t.use_compression(compress=compress) t.use_compression(compress=compress)
if self._log_channel is not None: if self._log_channel is not None: