I’m not really keen on writing “tricks” kind of posts for software, especially widely known as OpenSSH, but this stuff tends to be quite intriguing now – to me at least – and I think most people wouldn’t know about that.
If you’ve used cvs, svn or other SSH-connected services in the recent past you probably know that one of the most time-wasting tasks for these systems is to connect the ssh session itself. Thankfully, quite a bit of time ago, OpenSSH introduced the “master” connection feature: the first ssh connection you open to a host (with a given username) creates a Unix socket descriptor, which is used by the following sessions. This was really a godsend for when committing a huge number of packages more or less at the same time, when I was still in the KDE team.
Unfortunately, this still required the first connection to be a persistent one; to solve that, I used to start a screen session that connected a few ssh connections, after asking me for the key passphrase. This didn’t make it any nice on the system or on the security, among other things. But fear not, OpenSSH 5.6 brought magic into the mix!
The new ControlPersist
option allows for the master connection to be created in a detached SSH process when first connecting to a box, so that there is no need to preventively prepare for processes to be kept around. Basically all you have to do to make use of master connections now is something like this in your ~/.ssh/config
:
Host *.gentoo.org
ControlMaster auto
ControlPersist yes
Code language: CSS (css)
and you’re set: ssh takes care of creating the first master connection if not present, and to delete and recreate it if it’s dropped for whatever reason; you can otherwise force the connection to be closed by using ssh $host -O exit
. Lovely!
There is one more trick that I wish to share though, although this time around I’m not sure which OpenSSH version introduced it. You can have from time to time the need to connect to a box that is behind a not-too-hostile firewall, which you have also access to. This is the case at a customer’s of mine where only the main router has a (dynamic) IPv6 address and I have to go through that to connect to the other boxes. The usual trick to follow in such a situation is to use the ProxyCommand
option, using ssh
and nc
(or in my case nc6
) to get a raw connection to the other side. I was always a bit bothered by having to do it this way to be honest. Once again, recent versions of OpenSSH solve the problem with the -W
option:
Host router.mycustomer.example.com
ProxyCommand none
Host *.mycustomer.example.com
ProxyCommand ssh router.mycustomer.example.com -W %h:%p
Code language: CSS (css)
With this method, it will be the ssh on my customer’s router to take care of connecting to the box further down the net and redirect that to the input/output streams, without the need for a nc
process to be spawned. While this doesn’t look like a biggie, it’s still one less package I have to keep installed on the system, among other things.
Awesome, thanks! Been looking for something like this…
Thanks for the tips! Now to wait for OS X to move from OpenSSH 5.2 to 5.6…Btw, I think you meant to say _preemptively_ when you said ” no need to _preventively_ prepare”.
it looks like a ControlPath is also mandatory for the first trick to work 😉
Using “ControlPersist <seconds>” is also possible and I personally prefer it.
hrm, I meant ControlPersist <seconds>
Indeed, ControlMaster doesn’t work without setting ControlPath as well.
Hello,thank you for sharing your tricks, those one are pretty cool !!About the firewall case, what about sharing both sockets ?Host * ControlMaster auto ControlPersist yesHost router.mycustomer.example.com ProxyCommand noneHost *.mycustomer.example.com ProxyCommand ssh router.mycustomer.example.com -W %h:%pI tried this to see if I get any performance improvement, but unfortunately I didn’t notice any speedup. I even receive an error when the master connection (router) is not already established :Bad packet length 1397966893.Disconnecting: Packet corrupt
@dud225 Use the following :Host * ControlMaster auto ControlPath ~/.ssh/control-%r@%h:%p ControlPersist 1hHost 10.17.1.* ProxyCommand ssh -q -o ControlPersist=no relay.net -W %h:%p
I’m really happy with a trick I found somewhere that uses the + symbol to define hops: onceyou have in your .ssh/config fileHost *+* ProxyCommand ssh $(echo %h | sed ‘s/+[^+]*$//;s/([^+%%]*)%%([^+]*)$/2 -l 1/;s/:/ -p /’) nc $(echo %h | sed ‘s/^.*+//;/:/!s/$/ %p/;s/:/ /’)you canssh host1.example.com+privatehostthis will use host1.example.com dns to resolve privatehost and connect to it through the first hop.