SSH Port Forwarding
All too frequently, after people setup a firewall to protect themselves, they discover it sometimes keeps them out as well. There are several solutions to consider when this comes up:
1. Poke holes in the firewall with firewall rules (if the firewall is under your control).
2. Use a virtual private network to tunnel all client traffic through the firewall.
3. Use ssh port forwarding to tunnel specific TCP connections though the firewall.
4. Use ssh port forwarding to tunnel another ssh session (including all its port forwardings) through a firewall.
SSH port forwarding is probably the simplest and least well understood, so what follows will attempt to show what it can do and when it is useful.
For starters, ssh port forwarding is useful if (and only if) there exists another host to which you can ssh, which (by virtue of its different location on the network) has access to what you want.
SSH Port forwarding always forwards traffic bidirectionally but you must specify which end of the ssh tunnel accepts connections to forward. If the same host which initiates the ssh connection also accepts connections to forward, that’s called “local port forwarding”. Local port forwarding is probably the most convenient to use and easiest to understand so that’s mostly what will be described here. (Just remember that for the most part, forwarding a local port on an outbound ssh connection is equivalent to forwarding a remote port on an inbound ssh connection.)
STATIC PORT FORWARDING
SSH version 1 only implements static port forwarding. Static port forwarding requires no application configuration changes to use but does require explicit references to the forwarded ports. (If you can configure your applications to use it, you may prefer Dynamic Port Forwarding (described later) because it is more transparent to use.)
Example 1: Statically forwarding a URL
If you establish the following ssh connection from host “foo” to host “bar” with port forwarding:
ssh -L3210:www.rave.ac.uk:80 bar
and then access the URL below from “foo”:
you will find it behaves as if you’d accessed:
directly from “bar”
In the example above, the data would travel encrypted/tunneled between “foo” and “bar” and then be sent unencrypted between “bar” and “www.rave.ac.uk”.
You can forward as many ports to as many hosts as you want on one connection or you can login repeatedly forwarding new ports as needed on multiple ssh connections.
As a security precaution, modern versions of ssh forbid other computers on the internet from connecting to the forwarded port (3210 on “foo” in the example above) unless you explicitly allow it with the “ssh -g” flag. With the “-g” flag, ssh will allow any host on the internet to connect to and use the tunnel so use this with caution.
Probably the best thing about static ssh port forwarding is that it is so easy to do for occasional tunnels from dynamic IP addresses (which are hard to pre-configure into firewall rules). Also, no system, application or protocol configuration changes are needed to use them. On the other hand, it can be confusing to keep track of which ports are forwarded to which hosts so this probably will be impractical for more than a few forwarded ports.
DYNAMIC PORT FORWARDING
In addition to Static Port Forwarding (described above), SSH version 2 from ssh.com and recent versions of “OpenSSH” and “PuTTY” (both free) have an additional “dynamic” port forwarding option which is implemented as a “socks proxy server”. This allows you to configure just one local port for all remote destinations. To use this “dynamic” port forwarding, you need to reconfigure applications (such as your web browser) to send all their traffic using the “socks protocol” to this one local port. The application (eg. browser) uses the “socks” protocol to specify where the traffic should be sent when it leaves the other end of the ssh tunnel. (Note OpenSSH is free and available for Unix/Linux, Mac OS/X, and Windows (under cygwin (also free)).
Example 2: Using dynamic port forwarding with a web browser
If you establish the following ssh connection from host “foo” to “bar ” with dynamic port forwarding:
ssh -2 -D 3210 bar
and then configure your browser to use a “socks4 proxy” at
IP address: localhost (127.0.0.1) and port: 3210
and then access any unmodified URL (such as below) from “foo”
you will find it behaves as if you’d accessed it directly from bar.
As with static port forwarding, in the example above, the data would travel encrypted/tunneled between “foo” and “bar” and then be sent unencrypted between “bar” and www.rave.ac.uk
As a security precaution, modern versions of ssh forbid other computers on the internet from connecting to the socks proxy port (3210 on “foo” in the example above) unless you explicitly allow it with the “ssh -g” flag. With the “-g” flag, ssh will allow any host on the internet to connect to and use the tunnel so use this with caution.
OTHER EXAMPLES:
Example 3: Helping an application use a non-standard port
If you have an application (such as an email client) which has no configuration option to send to an arbitrary port but can be configured to send to localhost, you can use ssh port forwarding to make it send on an arbitrary port..
If you can ssh to “localhost”, the first line will do, otherwise you can use something like the second:
ssh -L25:relay.rave.ac.uk:587 localhost
or
ssh -L25: relay.rave.ac.uk:587 foo
Here, any traffic the email client sends to localhost or “foo“ on port 25 will be forwarded to “relay.rave.ac.uk ” on port 587.
Example 4: Remote port forwarding – exposing an internal webserver
Remote port forwarding is sometimes useful for granting temporary access to services on clients which are otherwise unreachable (perhaps the client has an unreachable address behind a NAT or firewall). If the client is not configured to accept inbound SSH connections, this can be done with remote port forwarding on an outbound connection.
Consider a PC which is running a webserver but is protected by firewall rules to accept no inbound connections (except from itself). Furthermore imagine this host has the unrouted private address 192.168.1.1 and can access the internet only outbound through a NAT. If you believe it is not too risky, you can briefly make that server publicly available with ssh port forwarding (such as while you’re on the phone with someone) if you think the risk of serving sensitive data to a random hacker while it is publicly exposed is acceptably low and you CAN ssh from the PC to a host with a public address.
To do so, you can establish an ssh connection such as this:
ssh -R4567:localhost:80 some-server
which will make it look like your PC’s webserver is a server on “some-server” at port: 4567.
Anyone who connects to:
http://some-server:4567/some/path
will get the same webpage you get on your PC when you connect to:
If you CAN ssh into your PC, you can do something similar (but probably more convenient) with an inbound ssh connection to gain similar access to the protected webserver on YourPC:
ssh -L4567:localhost:80 YourPC
which you would use from wherever you’re coming from as:
http://localhost:4567:/some/path
Note that this is similar to Example 1 above but with the unencrypted part of the forwarding just going to localhost.
Example 5: Rerouting traffic for debugging
Imagine you’re trying to debug a service on a remote server and you’d like to be able to see all the network traffic to/from the server with a network sniffer.
You can temporarily change the server to offer its service on a different/temporary port; use ssh to forward/tunnel the original service port to your PC, and from your PC, send the traffic back to the different/temporary port on the remote server.
This allows you to sniff it as it travels between your PC and the different/temporary port on the remote server.
For example, if you changed SMTP (email) service on “some-server” to listen on port 5432 instead of port 25 and then established this ssh connection from your PC:
ssh -R25:some-server:5432 some-server
Data sent to port 25 on “some-server” would be sent tunneled/encrypted to your PC and then sent unencrypted back to “some-server” at port 5432 (to the real application). You would then be able to conveniently “sniff” it on your PC.
Example 6: Tunnelling SSH (with all its port forwardings) through SSH
This may sound silly at first but it is really quite a useful trick.
Imagine that “final_host” will not accept any connections from you directly however it will accept them from “intermediate_host”. The goal is to ssh to “final_host” in as normal a way as possible. Assuming that the number 4022 is an unused local port, consider this:
1) ssh -L4022:final_host:22 intermediate_host
2) ssh -p4022 localhost
Line #1 encrypts and forwards port 4022 traffic from localhost to “intermediate_host” where it then heads “in the clear” to “final_host”, however in this case, port 4022 will carry ssh traffic, which is end- to-end encrypted, so it is really singly encrypted between “intermediate_host” and “final_host” and doubly_encrypted between localhost and “intermediate_host”.
Line #2 lets you log into “final_host” in one easy step (such as in a script) without scripting a secondary login through “intermediate_host” (which is hard to do).
Note that if you have different passwords on “intermediate_host” and “final_host”, the tunneled ssh connection to “final_host” is encrypted end-to-end and your password on “final_host” will be secure even if “intermediate_host” is compromised and running a compromised sshd (as long as your public key for “final_host” on localhost is correct).
Similarly note that if you use a form of passwordless keypair authentication between localhost and “final_host”, that should also work transparently and securely through the tunnel via “intermediate_host”.
Note: Some of the ideas and text in this document come from the University of Washington’s tech documents