Contents

1 ssh tunnels

ssh tunnels are considered some of the more difficult features of ssh, so here's my attempt to explain using images from Wikimedia Commons [1]. [2]. The first thing (starting with the basics), ssh tunnels are still ssh, so you need to have ssh between your box (<yourhost> in the first picture and below) and a host you can connect to by ssh (remotehost).

Four different ssh tunnels.

1.1 -L, local port forwarded, outbound

'-L', 'local' or 'outbound', i.e. connection started locally, and is outbound. In other words '-L' forwards a port from your local machine is forwarded to a port on a remote machine.

<localhost>:123 → <yourhost> → remotehost:22 → <localhost>:456

<localhost>:123 → <yourhost> → remotehost:22 → faraway:456

So this facilitates access from a port on your local machine (port 123, on <localhost>=<yourhost>), which is outside outside the 'remotehost', to have access to something on the same network as 'remotehost' (or reachable from 'remotehost'). This can be a port on remotehost itself, or on a machine reachable from remotehost, here 'faraway' host (port 456).

1.2 -R, remote port forwarded, inbound

'-R', 'remote' or 'inbound', connection starts remotely, and is inbound. In other words '-R' forwards a port from a remote machine ('remoehost') to a port on the local machine.

<localhost>:456 ← <yourhost> ← remotehost:22 ← <localhost>:123

nearhost:456 ← <yourhost> ← remotehost:22 ← <localhost>:123

This facilitates access from the outside (i.e. from 'remotehost' or whatever can connect to remotehost to have access to <yourhost>, or something on the same network as <yourhost> (port 456).

1.3 Chaining ssh tunnels

Here's an example that may help with understanding this. Suppose something interesting is happening on port 123 on 'Box 2', which is behind a firewall, and you don't want to open a hole in the firewall (perhaps because whatever happens on port 123 should not be publicly accessible). You want to access this port from Box 1. Suppose that both Box 1 and Box 2 can log into remotehost.net on port 22. Here's now to tie Box 1 and Box 2 together.

Run these commands:

Box 1:

ssh -L 123:localhost:456 user@remotehost.net -p 22

Box 2:

ssh -R 456:localhost:123 user@remotehost.net -p 22

This forwards (outbound) port 123 on Box 1 to port 456 on remotehost.net. Then port 456 on remotehost.net is forwarded (inbound) to Box 2. The net result is that port 123 on Box 1 is now connected to port 123 on Box 2, and you can therefore query the service (running on port 123 on Box 2) by connecting to port 123 on Box 1.

Note that while the '456' actually refers to the same port, you can obviously choose different ports on Box 1 and Box 2 (both labeled 123).

1.4 Forwarding ssh connections

Clearly the above also works if the service is ssh. For this, you would use

Box 1:

ssh -L 2222:localhost:456 user@remotehost.net

Box 2:

ssh -R 456:localhost:22 user@remotehost.net

which means that you can then do this on Box 1:

ssh -p 2222 user@localhost/127.0.0.1

to connect as user 'user' to Box 2.

1.5 Socks proxy and forwarding all connections

Another good aspect is to create a socks proxy for dynamic port forwarding. I.e. rather than choosing the destination port (456 above, in the outbound examples), the socks proxy just forwards the connections.

ssh -D 123 user@remotehost.net -p 22

Any application that can use a socks proxy (e.g. some browsers) can then connect to port 123, and all traffic will be forwarded to remotehost.net.

Often there is a system-wide proxy as well (settable e.g. in OS X Preferences), that means that any application using that setting will use the proxy. However, in the case of OS X, this isn't very low-level, and applications may not always use it. For example, Terminal doesn't use it, so any terminal commands don't use the proxy.

sshutltle can be used to create a lower level proxy, that forces all TCP traffic through the proxy ([3], [4]; "brew install sshuttle" on OS X, or via ap-get). The following sets up a proxy:

sshuttle --dns -vr user@remotehost.net:22 0/0

sshuttle also has an option (-l) that can connect to a local port (or service). The inbound forward, forwards port 456 to port 22 on Box 2. Then sshuttle on Box 1 connects to remotehost, to port 456, which thus links to port 22 on Box 2.

Box 2:

ssh -R 456:localhost:22 user@remotehost.net

Box 1:

sshuttle -l 456 --dns -vr user@remotehost.net:22 0/0

The net effect is that all traffic from Box 1 is now routed via Box 2.