diff options
author | Scott Kuhl <kuhl@mtu.edu> | 2020-09-07 15:39:36 -0400 |
---|---|---|
committer | Scott Kuhl <kuhl@mtu.edu> | 2020-09-07 15:46:33 -0400 |
commit | 5d6b14673f2043c3511f221201f0255171ae474a (patch) | |
tree | 947b19dd303c70b1166906fc8bd139980632fc14 | |
parent | 19f653df36d818531e35a03c02df4bda8a192bc0 (diff) |
Fix #494 sshuttle caught in infinite select() loop.
Improve detection of when the ssh process exits in both daemon and
foreground modes. Previously, sshuttle could infinite loop with 100%
cpu usage if the ssh process died. On machines that use suspend, the
ssh connection might not resume after wakeup. Now, this situation is
detected and sshuttle exits. The fix involves changing the return
value we check for when we call poll() and using a psutil function to
detect when the process exits if we are running sshuttle as a daemon.
-rw-r--r-- | requirements.txt | 1 | ||||
-rw-r--r-- | sshuttle/client.py | 20 |
2 files changed, 17 insertions, 4 deletions
diff --git a/requirements.txt b/requirements.txt index a77026c..291fe15 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ setuptools-scm==4.1.2 +psutil diff --git a/sshuttle/client.py b/sshuttle/client.py index 5f247f4..62fbda6 100644 --- a/sshuttle/client.py +++ b/sshuttle/client.py @@ -6,6 +6,7 @@ import subprocess as ssubprocess import os import sys import platform +import psutil import sshuttle.helpers as helpers import sshuttle.ssnet as ssnet @@ -541,11 +542,22 @@ def _main(tcp_listener, udp_listener, fw, ssh_cmd, remotename, debug1('seed_hosts: %r\n' % seed_hosts) mux.send(0, ssnet.CMD_HOST_REQ, str.encode('\n'.join(seed_hosts))) - while 1: - rv = serverproc.poll() - if rv: - raise Fatal('server died with error code %d' % rv) + def check_ssh_alive(): + if daemon: + # poll() won't tell us when process exited since the + # process is no longer our child (it returns 0 all the + # time). + if not psutil.pid_exists(serverproc.pid): + raise Fatal('ssh connection to server (pid %d) exited.' % serverproc.pid) + else: + rv = serverproc.poll() + # poll returns None if process hasn't exited. + if rv is not None: + raise Fatal('ssh connection to server (pid %d) exited with returncode %d' % (serverproc.pid, rv)) + + while 1: + check_ssh_alive() ssnet.runonce(handlers, mux) if latency_control: mux.check_fullness() |