sshtunnel icon indicating copy to clipboard operation
sshtunnel copied to clipboard

Timeout set is not honoured by sshtunnel

Open sjvdm opened this issue 3 years ago • 5 comments

Hi,

Python 3.8.3 (default, Aug 31 2020, 16:03:14) 
[GCC 8.3.1 20191121 (Red Hat 8.3.1-5)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sshtunnel
>>> sshtunnel.__version__
'0.4.0'
>>> 

When specifying SSH_TIMEOUT, this value is not honoured. From the example on the website, note the timestamps on when an exception is thrown. It seems the timeout stays at approx 120seconds.

Code to reproduce:

import sshtunnel
import datetime
sshtunnel.SSH_TIMEOUT = 5.0
sshtunnel.TUNNEL_TIMEOUT = 5.0
print('======START======')
print(datetime.datetime.now())
print('=================')
server = sshtunnel.SSHTunnelForwarder(
    '10.39.254.33',
    ssh_username="pahaz",
    ssh_password="secret",
    remote_bind_address=('127.0.0.1', 8080)
)

server.start()

print(server.local_bind_port)  # show assigned local port

server.stop()
print('======EXCEPTION======')
print(datetime.datetime.now())
print('=================')

OUTPUT:

======START======
2021-01-18 12:36:20.427075
=================
2021-01-18 12:38:30,924| ERROR   | Could not connect to gateway 10.39.254.33:22 : Unable to connect to 10.39.254.33: [Errno 110] Connection timed out

sjvdm avatar Jan 18 '21 10:01 sjvdm

TUNNEL_TIMEOUT and SSH_TIMEOUT consts are for socket.settimeout. It's not related to SSH protocol.

Paramiko has special variables for SSH protocol level timeout tunning (banner_timeout, handshake_timeout, auth_timeout).

Try this example:

import sshtunnel
import datetime

sshtunnel.DEFAULT_LOGLEVEL = 1

print('======START======')
print(datetime.datetime.now())
print('=================')

server = sshtunnel.SSHTunnelForwarder(
    '10.39.254.33',
    ssh_username="pahaz",
    ssh_password="secret",
    remote_bind_address=('127.0.0.1', 8080)
)

# how long (seconds) to wait for the SSH banner
server._transport.banner_timeout = 15
# how long (seconds) to wait for the handshake to finish after SSH banner sent
server._transport.handshake_timeout = 15
# how long (seconds) to wait for the auth response.
server._transport.auth_timeout = 30

server.start()

print(server.local_bind_port)  # show assigned local port

server.stop()
print('======EXCEPTION======')
print(datetime.datetime.now())
print('=================')

Could you please also provide the logs with sshtunnel.DEFAULT_LOGLEVEL = 1

pahaz avatar Jan 22 '21 18:01 pahaz

Thanks for the reply. In your example, the server object has no attribute _transport:

'SSHTunnelForwarder' object has no attribute '_transport'

With my example, running with sshtunnel.DEFAULT_LOGLEVEL = 1, here is the output:

2021-02-01 12:27:19,196| WAR | MainThrea/1032@sshtunnel | Could not read SSH configuration file: ~/.ssh/config
2021-02-01 12:27:19,197| INF | MainThrea/1060@sshtunnel | 0 keys loaded from agent
2021-02-01 12:27:19,218| DEB | MainThrea/1309@sshtunnel | Private key file (/home/fatti/.ssh/id_rsa, <class 'paramiko.rsakey.RSAKey'>) successfully loaded
2021-02-01 12:27:19,219| INF | MainThrea/1117@sshtunnel | 1 key(s) loaded
2021-02-01 12:27:19,220| INF | MainThrea/0978@sshtunnel | Connecting to gateway: 10.39.254.33:22 as user 'pahaz'
2021-02-01 12:27:19,220| DEB | MainThrea/0983@sshtunnel | Concurrent connections allowed: True
2021-02-01 12:27:19,222| DEB | MainThrea/1400@sshtunnel | Trying to log in with key: b'c4eb02e1b3a56952de73f72de91eb528'
======START======
2021-02-01 12:27:19.195555
=================
2021-02-01 12:29:29,796| ERR | MainThrea/1223@sshtunnel | Could not connect to gateway 10.39.254.33:22 : Unable to connect to 10.39.254.33: [Errno 110] Connection timed out
---------------------------------------------------------------------------
BaseSSHTunnelForwarderError               Traceback (most recent call last)
<ipython-input-10-045b309d7b47> in <module>
     14 )
     15 
---> 16 server.start()
     17 
     18 print(server.local_bind_port)  # show assigned local port

~/python_envs/fatti_post_analytics/lib/python3.8/site-packages/sshtunnel.py in start(self)
   1329         self._create_tunnels()
   1330         if not self.is_active:
-> 1331             self._raise(BaseSSHTunnelForwarderError,
   1332                         reason='Could not establish session to SSH gateway')
   1333         for _srv in self._server_list:

~/python_envs/fatti_post_analytics/lib/python3.8/site-packages/sshtunnel.py in _raise(self, exception, reason)
   1172     def _raise(self, exception=BaseSSHTunnelForwarderError, reason=None):
   1173         if self._raise_fwd_exc:
-> 1174             raise exception(reason)
   1175         else:
   1176             self.logger.error(repr(exception(reason)))

BaseSSHTunnelForwarderError: Could not establish session to SSH gateway

sjvdm avatar Feb 01 '21 10:02 sjvdm

This seems to work, except that the transport has been replaced with _get_transport. So the code should be:

# how long (seconds) to wait for the SSH banner
server._get_transport().banner_timeout = 5
# how long (seconds) to wait for the handshake to finish after SSH banner sent
server._get_transport().handshake_timeout = 5
# how long (seconds) to wait for the auth response.
server._get_transport().auth_timeout = 5

Thanks for the help!

sjvdm avatar Jul 04 '22 09:07 sjvdm

FYI, the methods using _get_transport() didn't work for me, but I was able to use socket.setdefaulttimeout instead:

import socket
from paramiko import Transport

# Must be called before the socket is created
socket.setdefaulttimeout(2)

T = Transport((<host>, <port>))

# Optionally, set it back to the default (once you are certain the socket has been created)
socket.setdefaulttimeout(None)

It quickly timed-out:

raise SSHException(
paramiko.ssh_exception.SSHException: Unable to connect to <host>: timed out

nhansendev avatar Jan 28 '23 01:01 nhansendev

sshtunnel.SSH_TIMEOUT = 5, it works

afghanistanyn avatar Feb 10 '23 03:02 afghanistanyn