OpenSSH – Exit Control Master Process Without lsof or fuser

opensshssh

Is there a more direct way to exit an OpenSSH control master process and delete its socket file than with the help of the programs lsof or fuser and without knowing the destination host (connection details) as suggested by the accepted answer of this question? I thought of something like this along the lines of:

$ ssh -O exit -S ~/.ssh/7eb92b0827f3e8e1e8591fb3d1a5cd1b94b758cb.socket

I'm asking because I'm looking for a scriptable way to exit every open control master connection each time when I log out of my user account. Not doing so causes my sytemd-powered openSUSE computer to wait for a timeout of two minutes until it forcefully terminates the still open control master connection powering off eventually.

Unfortunately OpenSSH's client program ssh requires the destination host and the ControlPath file name pattern in order to deduce the actual file path to the socket file. I on the contrary thought of the more direct method of providing the concrete socket file via the program's -S ctl_path option.

In the global section of my system-wide OpenSSH client config file I configured OpenSSH's connection multiplexing feature as follows:

ControlMaster auto      
ControlPath ~/.ssh/%C.socket
ControlPersist 30m

Please note that I want to keep the file name pattern for socket files, i.e. hashing the token string %l%h%p%r with the token %C.

Any ideas?

Best Answer

This works for me using just the socket file for the control master:

$ ssh -o ControlPath=~/.ssh/<controlfile> -O check <bogus arg>

NOTE: You can also use ssh -S ~/.ssh/<controlfile> ... as well, which is a bit shorter form of the above.

Example

Here's an example where I've already established a connection to a remote server:

$ ssh -S ~/.ssh/master-57db26a0499dfd881986e23a2e4dd5c5c63e26c2 -O check blah
Master running (pid=89228)
$

And with it disconnected:

$ ssh -S ~/.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 -S ~/.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 -S ~/.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.

UPDATE #1

I raised this as a potential bug to the OpenSSH upstream and they replied as follows:

Yes - this is intentional.

ControlPath may contain %-expansions that need a hostname to expand fully.

We could conceivably check to see whether ControlPath actually needs this and make the hostname optional but 1) ControlPaths that use %h are common and 2) I'd rather not make the argument parsing code more of a maze than it already is.

References