Tunnelling SSH though a firewall with ssh -L

Here’s a little tip on how to tunnel ssh through another machine with the -L option. While not terribly difficult, I did spend some time figuring this out…Maybe this will save someone else some time ;-)

The network setup at work (simplified):

Code:
    [ Workstation ]
          |
          |
     [ Firewall ]
          |
          |
   ~ The Internet ~
          |
          |
   [Public webserver]

The problem is connecting to public webserver from my workstation, I had to first ssh or sftp to the Linux firewall, and from that to the webserver.

There has to be an easier way … And a look at the SSH manpage provided the answer: The -L option.

Excerpt from From ssh(1):

Code:
       -L [bind_address:]port:host:hostport
               Specifies that the given port on the local (client) host is to be
               forwarded to the given host and port on the remote side.  This
               works by allocating a socket to listen to port on the local side,
               optionally bound to the specified bind_address.

Let me just give you an example on how to create the tunnel:

Code:
  $ ssh -f -N -p 22 username@firewall -L 2844/webserver.example.com/22

To briefly explain what the other options mean:

  • -f Runs the tunnel in the background.
  • -N Don't execute a login command, just setup the tunnel.
  • -p Connect to the firewall on port 22

You can now connect with ssh, sftp, or scp though localhost:2844

Code:
  $ ssh -p 2844 myusername@localhost
  $ scp -P 2844 file.tar.gz myusername@localhost:file.tar.gz

Note that ssh(1) requires -p and scp(1) -P.

Testing
For debugging, don’t forget you can specify -v up to three times to get more information about what’s going on. In addition, it’s probably best to test with telnet since this excludes things like authentication problems.

Code:
  $ telnet localhost 2844
  Trying ::1...
  Connected to localhost.
  Escape character is '^]'.
  SSH-2.0-OpenSSH_5.1p1 FreeBSD-20080901

If you don’t see the last line, something is wrong.

Bonus tip
As a free complimentary bonus tip, it’s also very easy to setup a convenient shortcut in ~/.ssh/config

Code:
  Host webserver
  	Hostname localhost
  	Port 2844
  	User myusername

Further reading
ssh(1)
ssh_config(5)
 
Another way to do the same, using nc(1) (aka netcat) and ProxyCommand in OpenSSH:

sshproxy
Code:
#!/bin/sh

# $1 is the proxy server
# $2 is the port on the proxy
# $3 is the remote host to connect to
# $4 is the remote port to connect to

if [ -z "$4" ]; then
        remoteport=22
else
        remoteport=$4
fi

ssh -q -p $2 $1 "nc $3 $remoteport"

.ssh/config
Code:
Host host-you-want-to-connect-to
        ProxyCommand ~/scripts/sshproxy firewall-to-bounce-off 22 %h %p

Then, it's a simple $ ssh host-you-want-to-connect-to and OpenSSH takes care of the rest. First by connecting to firewall-to-bounce-off, then running netcat to the SSH server on host-you-want-to-connect-to, and passing traffic from one SSH connection to the other.

While there are more steps involved in setting this up initially, the nice thing about it is that your SSH commands are always the same: ssh someserver. And, the configuration is saved/handled via the SSH config file, which is portable between systems (so long as the proxyssh script is installed).

If netcat is installed as something other than nc, or if the remote "bounce" server uses the GNU netcat, you would either have to edit the script, or create symlinks. Or, just install a BSD version of netcat, since it works better anyway. :)
 
How does one properly ssh tunnel to a specific computer within a network if
  1. the IP address of the physical location is DHCP,
  2. the computer with the internal address is not on a constant connection and is given an address by DHCP

???

I'm aware that the computer can be allowed direct access to the internet; but, for now, I'd rather have the added safety of the router.

Apologies for necro-posting.
 
sossego said:
How does one properly ssh tunnel to a specific computer within a network if
1) the IP address of the physical location is DHCP,
and
2)the computer with the internal address is not on a constant connection and is given an adress by DHCP
Use the hostname. It doesn't need to resolve on the 'outside' as long as it resolves on the 'inside'.
 
poorman's vpn: sshuttle ;-)

@Carpetsmoker & @phoenix: Thanks for sharing. I used to tunnel either using ssh or nc in the past.

Since I found sshuttle (https://github.com/apenwarr/sshuttle), I have been using it with my GNU/linux local clients. it is like creating vpn without openvpn or ipsec installed on the serverside. Pretty easy and impressive (though gpl2-licensed).

A single command makes a vpn-looking tunnel on the fly including dns-resolution proxied to the remote server:

Code:
%sshuttle -dns -vvr remoteserver_username@remoteserver_address 0/0

However it needs the sudo passwd to reconfigure the iptables for all applications in the local client. Also ask passwords two times: the local client sudo passwd first and then the remote host's user password.

A nice piece of work, I prefer to call poorman's vpn script. have a look at the site.

Maybe something worth porting to *BSD! JFYI.
 
Back
Top