Quite apart from replacing Telnet and other insecure protocols as the primary means of choice for contacting and administrating services, the OpenSSH implementation of the SSH protocol has developed into a general-purpose toolbox for all kinds of well-secured communication, whether using both simple challenge-response authentication in the form of user and password logins, or for more complex public key authentication.
SSH is useful in a general sense for tunnelling pretty much any kind of TCP traffic, and doing so securely and with appropriate authentication. This can be used both for ad-hoc purposes such as talking to a process on a remote host that’s only listening locally or within a secured network, or for bypassing restrictive firewall rules, to more stable implementations such as setting up a persistent SSH tunnel between two machines to ensure sensitive traffic that might otherwise be sent in cleartext is not only encrypted but authenticated. I’ll discuss a couple of simple examples here, in addition to talking about the SSH escape sequences, about which I don’t seem to have seen very much information online.
SSH tunnelling for port forwarding
Suppose you’re at work or on a client site and you need some information off a
webserver on your network at home, perhaps a private wiki you run, or a bug
tracker or version control repository. This being private information, and your
HTTP daemon perhaps not the most secure in the world, the server only listens
on its local address of 192.168.1.1
, and HTTP traffic is not allowed through
your firewall anyway. However, SSH traffic is, so all you need to do is set up
a tunnel to port forward a local port on your client machine to a local port on
the remote machine. Assuming your SSH-accessible firewall was listening on
firewall.yourdomain.com
, one possible syntax would be:
$ ssh user@firewall.yourdomain.com -L5080:192.168.1.1:80
If you then pointed your browser to localhost:5080
, your traffic would be
transparently tunnelled to your webserver by your firewall, and you could act
more or less as if you were actually at home on your office network with the
webserver happily trusting all of your requests. This will work as long as the
SSH session is open, and there are means to background it instead if you prefer
— see man ssh
and look for the -f
and
-N
options. As you can see by the use of the 192.168.1.1
address here, this
also works through NAT.
This can work in reverse, too; if you need to be able to access a service on your local network that might be behind a restrictive firewall from a remote machine, a perhaps less typical but still useful case, you could set up a tunnel to listen for SSH connections on the network you’re on from your remote firewall:
$ ssh user@firewall.yourdomain.com -R5022:localhost:22 -f -N
As long as this TCP session stays active on the machine, you’ll be able to
point an SSH client on your firewall to localhost
on port 5022, and it will
open an SSH session as normal:
$ ssh localhost -p 5022
I have used this as an ad-hoc VPN back into a remote site when the established
VPN system was being replaced, and it worked very well. With appropriate
settings for sshd
, you can even allow other machines on that network to use
the forward through the firewall, by allowing GatewayPorts
and providing a
bind_address
to the SSH invocation. This is also in the manual.
SSH’s practicality and transparency in this regard has meant it’s quite typical
for advanced or particularly cautious administrators to make the SSH daemon
the only process on appropriate servers that listens on a network
interface other than localhost
, or as the only port left open on a private
network firewall, since an available SSH service proffers full connectivity for
any legitimate user with a basic knowledge of SSH tunnelling anyway. This has
the added bonus of transparent encryption when working on any sort of insecure
network. This would be a necessity, for example, if you needed to pass
sensitive information to another network while on a public WiFi network at a
café or library; it’s the same rationale for using HTTPS rather than HTTP
wherever possible on public networks.
Escape sequences
If you use these often, however, you’ll probably find it’s a bit inconvenient
to be working on a remote machine through an SSH session, and then have to
start a new SSH session or restart your current one just to forward a local
port to some resource that you discovered you need on the remote machine.
Fortunately, the OpenSSH client provides a shortcut in the form of its escape
sequence, ~C
.
Typed on its own at a fresh Bash prompt in an ssh
session, before any other
character has been inserted or deleted, this will drop you to an ssh>
prompt.
You can type ?
and press Enter here to get a list of the commands available:
$ ~C
ssh> ?
Commands:
-L[bind_address:]port:host:hostport Request local forward
-R[bind_address:]port:host:hostport Request remote forward
-D[bind_address:]port Request dynamic forward
-KR[bind_address:]port Cancel remote forward
The syntax for the -L
and -R
commands is the same as when used as a
parameter for SSH. So to return to our earlier example, if you had an
established SSH session to the firewall of your local network, to forward a
port you could drop to the ssh>
prompt and type -L5080:localhost:80
to get
the same port forward rule working.