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:
parent
fd5e29b5a8
commit
31ea4f0734
|
@ -229,7 +229,7 @@ class SSHClient (object):
|
|||
|
||||
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,
|
||||
compress=False):
|
||||
compress=False, sock=None):
|
||||
"""
|
||||
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})
|
||||
|
@ -272,6 +272,9 @@ class SSHClient (object):
|
|||
@type look_for_keys: bool
|
||||
@param compress: set to True to turn on compression
|
||||
@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
|
||||
verified
|
||||
|
@ -280,21 +283,23 @@ class SSHClient (object):
|
|||
establishing an SSH session
|
||||
@raise socket.error: if a socket error occurred while connecting
|
||||
"""
|
||||
for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM):
|
||||
if socktype == socket.SOCK_STREAM:
|
||||
af = family
|
||||
addr = sockaddr
|
||||
break
|
||||
else:
|
||||
# some OS like AIX don't indicate SOCK_STREAM support, so just guess. :(
|
||||
af, _, _, _, addr = socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM)
|
||||
sock = socket.socket(af, socket.SOCK_STREAM)
|
||||
if timeout is not None:
|
||||
try:
|
||||
sock.settimeout(timeout)
|
||||
except:
|
||||
pass
|
||||
retry_on_signal(lambda: sock.connect(addr))
|
||||
if not sock:
|
||||
for (family, socktype, proto, canonname, sockaddr) in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM):
|
||||
if socktype == socket.SOCK_STREAM:
|
||||
af = family
|
||||
addr = sockaddr
|
||||
break
|
||||
else:
|
||||
# some OS like AIX don't indicate SOCK_STREAM support, so just guess. :(
|
||||
af, _, _, _, addr = socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM)
|
||||
sock = socket.socket(af, socket.SOCK_STREAM)
|
||||
if timeout is not None:
|
||||
try:
|
||||
sock.settimeout(timeout)
|
||||
except:
|
||||
pass
|
||||
retry_on_signal(lambda: sock.connect(addr))
|
||||
|
||||
t = self._transport = Transport(sock)
|
||||
t.use_compression(compress=compress)
|
||||
if self._log_channel is not None:
|
||||
|
|
Loading…
Reference in New Issue