summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorScott Kuhl <kuhl@mtu.edu>2020-09-07 15:39:36 -0400
committerScott Kuhl <kuhl@mtu.edu>2020-09-07 15:46:33 -0400
commit5d6b14673f2043c3511f221201f0255171ae474a (patch)
tree947b19dd303c70b1166906fc8bd139980632fc14
parent19f653df36d818531e35a03c02df4bda8a192bc0 (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.txt1
-rw-r--r--sshuttle/client.py20
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()