diff options
author | Steven Noonan <steven@uplinklabs.net> | 2012-10-15 04:09:33 -0700 |
---|---|---|
committer | Jeff Forcier <jeff@bitprophet.org> | 2012-11-05 13:30:48 -0800 |
commit | 31ea4f0734a086f2345aaea57fd6fc1c3ea4a87e (patch) | |
tree | 095d36d97a64b27a95a610c3c9466a9da06bda85 | |
parent | fd5e29b5a8aff1fe9f11f9f7bee5f0eb85ae569a (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.py | 37 |
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: |