SSH – Start to Finish Architecture – TCP Tunneling

One of the great benefits of SSH is the ability to create port forwarding redirects for temporary access to a system that otherwise might not be able to access a machine. This is really easy to set up, and works quite well for many scenarios, but the downside to this is… it’s really easy to set up and works quite well for many scenarios you might not WANT it to work for. This can be used to punch holes in firewall rules, and that can get you in hot water with the wrong people, so make sure you understand your corporate policy before attempting to use anything like this at work.

SSH provides several kinds of TCP port forwarding, so we’ll cover them one at a time.
We will NOT be covering the tunneling of “TUN” devices via the -w flag this time. That will be covered at a later date.
We will also NOT be covering standard input/output forwarding via the -W flag this time. This is only going to cover TCP forwarding.

The first type of TCP forwarding we will look at is the Dynamic Port Forwarding (using SOCKS4/SOCKS5 protocol.) The flag for this is -D and takes an optional “bind_address” and a required “port” be passed to it.
-D [bind_address:]port

This creates a listening socket locally on the provided port and optionally the given bind_address that will act as a SOCKS4 / SOCKS5 application-level proxy. It’s best to set this up to bind to localhost, and then use one of the other tunneling options to point to this in order to protect the proxy from users you don’t want using it. Of course, anyone that can access the machine via ssh, will be able to use this, so be selective about where you set this up. Any application that is SOCKS aware may take advantage of this, as long as it can hit the listening port.

The next two options are really the same thing, but one sets up a listening port on the local (client) machine, and the other sets up a listening port on the remote (server) machine. The flags are -L and -R, respectively.

-L [bind_address:]port:host:hostport
-R [bind_address:]port:host:hostport

When you want to forward a local (client) listening port to the remote machine, use “L” for “local.”
When you want to forward a remote (server) listening port to the client machine, use “R” for “remote.”

In other words, that “listening port” is bound either locally, or remotely, and is one end of the tunnel. The “host” and “hostport” are not necessarily the same as the destination server you are connecting to with SSH. They just have to be a host and port that the remote system can actually get to.

“-L” would bind a local port 8080 to the client when it establishes the connection to the remote ssh server. Then the remote ssh server would tie a connection to port 80 at on its end. From there, you should be able to connect to port 8080 locally on your client machine, and talk to that remote server on its port 80, all tunneled via ssh to the ssh server.

“-R 2222:localhost:22” would create a listening “localhost” bind on port 2222 on the remote server, that points to port 22 on the local client. If you were to connect outside of your network with this, it would allow people outside of the network to ssh in from that remote machine, assuming they have the correct credentials.

All of these options as given create a shell on login. You can establish JUST the tunnel by using the “-N” “-T” and “-f” options.

“-N” says to not call a remote command, just establish the tunnels.
“-T” says not to establish a pseudo TTY (PTY) terminal, which is appropriate since you aren’t passing any commands.
“-f” says to background ssh, since you probably want to do more work after the session is established.

ssh -fNT -L User_B@jumphost

This says to background ssh after establishing a tunnel, and don’t allocate a PTY. Establish the tunnel with a locally bound port 8080, and have the remote ssh server “jumphost” establish a tunnel to “” on port 80. Connect as User_B to the ssh server.

You can check with “netstat -an | grep LISTEN” to see if you have a listening port 8080 after establishing this. You can test the tunnel with netcat or telnet to localhost on port 8080 and enter “GET /” then hit enter. You might need to hit enter twice, depending. You’ll have to replace “User_B” and “jumphost” with an actual system you have access to, that also has access to the internet, of course.

I hope this didn’t muddy the waters more than it cleared them up a bit. If so, let me know in the comments, and I’ll try to clarify later.