Posted: 04 Jul 2012
Tagged: trick ssh
##Why?
As tools go, ssh is easily one of the most useful in my computer toolbox. There are a lot of tricks up its sleeve, and a lot of little gripes with it as well. These are some of my favorite ways to get it to do really cool things, and diminish problems at the same time.
##The configuration
This is a very stripped down version of my configuration file, and the primary way I mitigate the aforementioned little problems.
Host charon
hostname <alternate hostname>
Host ice5
Protocol 2
HostName ice5
ProxyCommand ssh charon nc -q 0 ice5 22
Host ice6
Protocol 2
HostName ice6
ProxyCommand ssh charon nc -q 0 ice6 22
Host armor2
Protocol 2
HostName armor2
#forward local port 5902 to the VNC port on armor2
LocalForward 5902 localhost:5900
ProxyCommand ssh charon nc -q 0 armor2 22
Host *
#use my local keys on remote machines
ForwardAgent yes
#keep the connection alive for finnecky servers, and kill it when the
#connection has died
ServerAliveInterval 15
ServerAliveCountMax 3
#allow local and proxy commands
PermitLocalCommand yes
#Set up control sockets so multiple ssh/scp/sftp sessions can share one
#connection
ControlPath ~/.ssh/master-%r@%h:%p
ControlMaster auto
The first section is important, it applies to all hosts, unless the settings are overridden by a specific host section later on. Each item in this version either fixes an issue or makes life easier in some way. ForwardAgent for example allows my local ssh-agent to be used from any target computer. In that way, all of my keys are stored on machines I control, but they can still be used from others so long as I am connecting originally from the machine they are on. Aside from that, there are a couple of settings to allow proxying, and keep finicky servers from causing disconnects, or connections from living too long after they are actually dead.
The last one of importance is the Control{Path,Mater} pair. These create a local socket whenever an ssh connection is made, and allow all simultaneous connections to that destination to use that socket. This has several consequences, the first is that one does not need to type their password again until the first connection is closed and a new one must be established. Additionally, it avoids connection setup, which can save a great deal of time on systems which insist on reverse DNS.
##Trick 1: Forwarding ports
Frequently I find that services are only listed as available on local networks, or only on a local machine for that matter. My own machines have local-only screen sharing, or VNC, enabled for example. On the face, that sounds rather useless, why would one want to connect to that locally? The reason is that I want to connect to these services with encryption, and they frequently do not support that option. The solution? SSH port forwarding. For example, when I want to connect to a local VNC server on armor2 I might use the following.
ssh -L 5901:localhost:5900 armor2
Now, it’s important to see what this does. The -L
flag specifies that this is
a local port forward command, 5901 is the local port to use, 5900 is the port to
connect to on armor2, and localhost is the host to connect to. Armor2 is the
target host for the ssh connection. After establishing that connection
vncviewer localhost:1
would connect to the VNC server on armor2 over an ssh
encrypted pipe. Alternatively, since armor2 is behind another machine charon, it could be
written as follows.
ssh -L 5901:armor2:5900 charon
This version assumes that VNC connections are allowed from charon to armor2, but skips the extra hop of the proxy. It works by connecting the local port, over a tunnel to charon, to armor2 without the need to be able to directly ssh to armor2. Used this way, one can connect to any port on a target machine from any (non-restricted) local port through any machine they can ssh to. It is an extremely flexible option, and one I am constantly finding new uses for.
##Trick 2: Connecting to a machine behind a firewall
It is a relatively common issue to need to connect to one machine through another, both through SSH. Normally, that means that one must explicitly conenct to the first, then ssh to the second from there, while not a huge issue, it is a definite annoyance. Using another great multitasker, netcat, we can fix this problem, as in this excerpt from the above configuration.
Host ice5
Protocol 2
HostName ice5
ProxyCommand ssh charon nc -q 0 ice5 22 OR
Host ice5
Protocol 2
HostName ice5
ProxyCommand ssh charon -W ice5:22
This rule allows one to ssh directly to ice5 from outside, even though it must
be accessed by first sshing to charon. The ProxyCommand is the key, when one
types ssh ice5
the system automatically runs the proxycommand, which opens an
ssh connection to charon, and connects the pipe from that connection to a netcat
process on charon which points to the ssh port on ice5. That connection is then
used to communicate with ice5, completely skipping the need to explicitly log in
to charon, and if ones ssh keys and forwarding are set up, it’s all automatic.
###UPDATE:
Thanks to Lorenzofh for pointing out that ssh offers the -W <host>:<port>
option to
accomplish this as well. It is always nice to save a process, not to mention
not requiring that netcat be installed.
##Trick 3: Transferring files without scp/sftp
As much as scp and sftp are well thought out, and work well much of the time, sometimes one wants an alternative. The most common reason for this is when I have a large number of small files to transfer, and would prefer to use one persistent connection to transfer them all rather than restarting for each file. Another would be using a different compression algorithm than that built into scp. With ssh and tar, it’s quite easy to set up. For example, lets say I want to transfer a mailder format directory called email on charon to my local machine.
ssh charon tar c emails/ | tar xv
That’s all it takes. Lets break that down for a moment. It connects to charon
over ssh, opening a non-interactive terminal with the tar command to create an
archive of the email directory on standard output. The |
breaks the command
in the local shell, in that way the output pipe from ssh is fed into a tar
extraction command, which extracts the folder verbosely in the current
directory.
Ok, so that gets us to having all the files in one pipe, which is a pretty big win on connection setup and teardown, but there is no compression. One could certainly add a compression option to tar, say ‘j’ for bzip2, but since this is a pipe, so we can use whatever we want. This version is even better.
ssh charon sh -c 'tar c emails/ | xz -9 --stdout --compress' | xz --decompress --stdout | tar xv
Now we have all of the files packed into a single tar stream, compressed to the maximum with lzma in xz, piped back to the local machine, decompressed, and untarred. Of course, if you want to archive the remote machine instead of recreating the original, the pipe from ssh can simply be directed to a file, which is a great way to create archives of systems which do not have enough local space to hold the archive.
##Trick 4: Full SOCKS proxy courtesy of ssh
Need a proxy to connect outside of your firewall? My most recent use for this was to make connections out of China to various sites in the US. The command is deceptively simple.
ssh -D <port> charon
Where charon is the hostname. With that, ssh creates a SOCKS4/5 proxy on the specified port, setting your browser or operating system to use that proxy can forward essentially any kind of traffic through, which will appear to have come from the target machine. Simple, but extremely useful in the right situation.
##Wrap-up
Thanks to these, ssh is in my top-tier of command line tools, right up there with vim, zsh and the members of coreutils. It never seems to run out of tricks, if you know of any other cool ones, drop me a line, I’d love to hear about them.
blog comments powered by Disqus