summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorSteven Noonan <steven@uplinklabs.net>2012-10-15 04:09:33 -0700
committerJeff Forcier <jeff@bitprophet.org>2012-11-05 13:30:48 -0800
commit31ea4f0734a086f2345aaea57fd6fc1c3ea4a87e (patch)
tree095d36d97a64b27a95a610c3c9466a9da06bda85
parentfd5e29b5a8aff1fe9f11f9f7bee5f0eb85ae569a (diff)
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>
-rw-r--r--paramiko/client.py37
1 files changed, 21 insertions, 16 deletions
diff --git a/paramiko/client.py b/paramiko/client.py
index 0f408977..0a9ced7e 100644
--- a/paramiko/client.py
+++ b/paramiko/client.py
@@ -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: