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:
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 (such as TeraTerm) 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.)
If you establish the following ssh connection from host "YourPC" to host "homer.u" with port forwarding:
ssh -L3210:staff.washington.edu:80 homer.uand then access the URL below from "YourPC":
http://localhost:3210/corey/info.cgiyou will find it behaves as if you'd accessed:
http://staff.washington.edu:80/corey/info.cgidirectly from "homer.u" (note the value of REMOTE_HOST in that webpage to confirm). In the example above, the data would travel encrypted/tunneled between "YourPC" and "homer.u" and then be sent unencrypted between "homer.u" and "staff.washington.edu".
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 "YourPC" 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), the commercial version of 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)).
ssh2 -L socks/3210 homer.u # if using commercial ssh2 ssh -2 -D 3210 homer.u # if using a recent OpenSSHand then configure your browser to use a "socks4 proxy" at
IP address: localhost (127.0.0.1) and port: 3210and then access any unmodified URL (such as below) from "YourPC":
http://staff.washington.edu/corey/info.cgiyou will find it behaves as if you'd accessed it directly from homer.u (note the value of "REMOTE_HOST" in that webpage to confirm).
As with static port forwarding, in the example above, the data would travel encrypted/tunneled between "YourPC" and "homer.u" and then be sent unencrypted between "homer.u" and staff.washington.edu.
As a security precaution, modern versions of ssh forbid other computers on the internet from connecting to the socks proxy port (3209 on "YourPC" 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.
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:smtp.washington.edu:587 localhost ssh -L25:smtp.washington.edu:587 homer.uHere, any traffic the email client sends to localhost on port 25 will be forwarded to "smtp.washington.edu" on port 587.
Remote port forwarding is sometimes useful for granting temporary access to services on clients which are otherwise unreachable (perhaps the client has an unreachable rfc1918 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. (For OpenSSH, note that you may need to set "GatewayPorts yes" in "sshd_config" to achieve on the server what "ssh -g" would do on the client (allow any host to connect to the forwarded port).
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-serverwhich 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/pathwill get the same webpage you get on your PC when you connect to:
ssh -L4567:localhost:80 YourPCwhich you would use from wherever you're coming from as:
http://localhost:4567:/some/pathNote that this is similar to Example 1 above but with the unencrypted part of the forwarding just going to localhost.
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-serverData 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.
(This is similar to Example 1 above but with different ports and described in terms of the Windows TeraTerm application.)
If you are off campus and you want to use the Windows Remote Desktop to connect to a Windows PC (with "Campus_IP") which has access restricted to "campus" only:
Macintosh and Linux/Unix users will find steps #1-4 above are equivalent to:
ssh -L3456:Campus_IP:3389 homer.uWindows users, if they prefer, can do something similar by creating a desktop shortcut to Teraterm with similar command-line arguments:
C:\...\ttssh.exe /ssh-L3456:Campus_IP:3389 homer.u
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 #create the tunnel 2) ssh -p4022 localhost somecmd # connect to final_host 3) ssh -p4022 -X localhost # connect to final_host
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 run "somecmd" on "final_host" in one easy step (such as in a script) without scripting a secondary login through "intermediate_host" (which is hard to do).
Line #3 lets you easily and securely tunnel X window connections "directly" from localhost to "final_host". Trying to tunnel X first to "intermediate_host" and then to "final_host" any other way is less satisfactory and/or requires additional software.
Note that you can create an artibrary number of simultaneous ssh connections to "final_host" via the one forwarded port (each will exit the tunnel on a unique port).
Note also 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".
If you need to connect from localhost to more than one "final_host", besides forwarding several different ports, you also need to create and use unique local hostnames (entries in the local "hosts" file) for each "final_host" so ssh can associate the public key of each destination with a unique hostname in its "known_hosts" file. For the example below, these lines would be added to the local "hosts" file:
127.0.0.1 local_final_host 127.0.0.1 local_final_host2
And these would be the ssh commands:
1) ssh -L4022:final_host:22 -L5022:final_host2:22 intermediate_host # create two tunnels 2) ssh -p4022 local_final_host somecmd # to connect to final_host 3) ssh -p4022 -X local_final_host # to connect to final_host 4) ssh -p5022 local_final_host2 somecmd # to connect to final_host2 5) ssh -p5022 -X local_final_host2 # to connect to final_host2
The numbers 4022 and 5022 are arbitrary, choose what makes sense to you.
Email -- corey @ u.washington.edu
Web -- http://staff.washington.edu/corey/
Date -- Fri Feb 8 13:27:47 PST 2008