How to close (kill) ssh ControlMaster connections manually
From the manual:
-O ctl_cmd
Control an active connection multiplexing master process. When the-O
option is specified, thectl_cmd
argument is interpreted and passed to the master process. Valid commands are:check
(check that the master process is running),forward
(request forwardings without command execution),cancel
(cancel forwardings),exit
(request the master to exit), andstop
(request the master to stop accepting further multiplexing requests).
Older versions only have check
and exit
, but that's enough for your purpose.
ssh -O check host.example.com
If you want to delete all connections (not just the connection to a particular host) in one fell swoop, then fuser /tmp/ssh_mux_*
or lsof /tmp/ssh_mux_*
will list the ssh clients that are controlling each socket. Use fuser -HUP -k tmp/ssh_mux_*
to kill them all cleanly (using SIGHUP as the signal is best as it lets the clients properly remove their socket).
I wrote an open source utility, cmc
, to manage ControlMaster sessions: ClockworkNet/cmc:
Usage: cmc [ -c HOST | -o HOST | -x HOST ]
cmc [ -L | -l | -O | -X ]
cmc -h
ControlMaster Controller - Eases management of SSH ControlMaster connections
Options:
-h show this help message and exit
-c HOST check HOST ControlMaster connection status (maybe specified more
than once)
-L list ControlMasters defined in SSH_CONFIG
-l list ControlMaster connection sockets in ~/.ssh/ and check their
connection status
-O open all ControlMasters defined in SSH_CONFIG
-o HOST open a ControlMaster session (maybe specified more than once)
-x HOST close ControlMaster session (maybe specified more than once)
-X exit all ControlMaster connections with sockets in ~/.ssh/
Notes:
* Any unopened sockets in ~/.ssh/ are removed with -l and -X
This works for me using just the socket file for the control master:
$ ssh -o ControlPath=~/.ssh/<controlfile> -O check <bogus arg>
Example
Here's an example where I've already established a connection to a remote server:
$ ssh -o ControlPath=~/.ssh/master-57db26a0499dfd881986e23a2e4dd5c5c63e26c2 -O check blah
Master running (pid=89228)
$
And with it disconnected:
$ ssh -o ControlPath=~/.ssh/master-66496a62823573e4760469df70e57ce4c15afd74 -O check blah
Control socket connect(/Users/user1/.ssh/master-66496a62823573e4760469df70e57ce4c15afd74): No such file or directory
$
If it were still connected, this would force it to exit immediately:
$ ssh -o ControlPath=~/.ssh/master-66496a62823573e4760469df70e57ce4c15afd74 -O exit blah
Exit request sent.
$
It's unclear to me, but it would appear to potentially be a bug in ssh
that it requires an additional argument at the end, even though blah
is meaningless in the context of the switches I'm using.
Without it gives me this:
$ ssh -o ControlPath=~/.ssh/master-57db26a0499dfd881986e23a2e4dd5c5c63e26c2 -O check
usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]
[-D [bind_address:]port] [-E log_file] [-e escape_char]
[-F configfile] [-I pkcs11] [-i identity_file]
[-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec]
[-O ctl_cmd] [-o option] [-p port]
[-Q cipher | cipher-auth | mac | kex | key]
[-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port]
[-w local_tun[:remote_tun]] [user@]hostname [command]
Version info
OSX$ ssh -V
OpenSSH_6.9p1, LibreSSL 2.1.8
CentOS 7.x
$ ssh -V
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips 26 Jan 2017
I confirmed that on both of these versions, the need for the additional bogus argument was required.
References
- How to tell if an ssh ControlMaster connection is in use
- How to exit OpenSSH control master process without using lsof or fuser?