There are many cases where a system administrator or user needs to access a resource or system that resides on a remote LAN, often behind a firewall such that the service cannot be accessed directly from the internet. The usual solution to this scenario is to set up a VPN. VPNs are great for secure remote access—don't get me wrong. But there are a few aspects that make them less-than-convenient for many use cases that I encounter on regular basis.
Generally speaking:
We'll take a look at a few ways to gain comparable access to remote networks, although I'm not going to talk about performance at all here.
I see lots of tutorials online about how to use SSH port forwarding, so I'm not going to repeat what's been said. However, it doesn't get enough credit where it's deserved. This is the way I most frequently choose to access remote networks: through dynamic port forwarding, where the SSH client runs a SOCKS proxy server, which can be thought of as a TCP proxy of sorts.
So:
ssh -CD 1080 user@your-remote-server
It's that easy. Now, you can configure your browser to use the SOCKS proxy somewhere in the proxy settings (see that tutorial I linked for Firefox instructions; make sure to enable remote DNS as well). You can additionally remove the local address filter so you can access services on "localhost" that are actually running on the remote machine. Also, there are a number of Chrome/Firefox plugins that allow you to switch proxies at the touch of a button, which I would highly recommend using in order to save your sanity. Generally, my Firefox browser is set to use this SSH proxy by default.
Great, the browser is easy to configure. What about other applications? Enter
ProxyChains (also see
tsocks), which uses LD_PRELOAD
magic to, in
simple terms, hook library functions used to make TCP connections. ProxyChains,
as the name suggests, allows you to chain multiple proxies together (just one
is fine here). It is ideal for pushing things through our SSH tunnel, and can
also be used to push things through other services like Tor.
ProxyChains is available through the package manager on most distributions, but
I recommend using ProxyChains-ng as
it is more recently developed and it will use DNS on your remote system instead
of the hardcoded 4.2.2.2
present in the original version.
Once installed, the following in /etc/proxychains.conf
is all that is needed
to get it working:
[ProxyList]
socks5 127.0.0.1 1080
Now, you can use it after running the SSH command above (the following may be
proxychains4
depending how it was installed):
$ proxychains curl my-internal-site.lan # needs proxychains-ng in most cases
$ proxychains curl example.com # fetch example.com through the remote server
$ proxychains nc mailserver.lan 25 # talk to a mail server
$ proxychains nmap -sT 192.168.1.0/24 # Perform remote Nmap scan (no SYN scans)
The first example will only work with ProxyChains-ng since we are using the remote network's local DNS. If you don't have that working, an IP address will suffice instead.
I like to be able to type commands as quickly as possible, so naturally my shell's rc file contains the following shortcuts:
alias pc=proxychains # don't like typing "proxychains"
tun () {ssh -CNPD1080 "$1"} # quickly open tunnel
After reloading the shell, the commands are a bit shorter :)
$ tun my-remote-ssh-server.com & # run in background
$ pc curl example.com
As of OpenSSH 7.3, jumping through one or more SSH hosts has become dead simple. Most of the information on this can be found here, but I'll copy some of the highlights over.
Let's say you have an internal domain work.space that has one public-facing
SSH-capable host (ssh-hop.example.com), and others that are only on the
internal network. We'd add the following to our .ssh/config
:
Host *.work.space
ProxyJump user@ssh-hop.example.com
And that's it. Now, if you run ssh dev.work.space
, you will be quietly passed
through ssh-hop.example.com
and will be sitting on the internal server
dev.work.space
! It's that easy.
Now, let's say you have an additional internal network where the only way in
is through router.work.space
, a machine on both the work.space network and
your secret internal network, secret.lan. We'd add the following below the
above config:
Host *.secret.lan
ProxyJump user@router.work.space
Note that this will use our previous config in order to reach the machine that is only on the work.space network, and is equivalent to:
Host *.secret.lan
ProxyJump user@ssh-hop.example.com,user@router.work.space
An arbitrary number of hosts can be chained together with commas, each with their own user and/or port defined.
This setup is great if you have a few well-defined networks. But what if a machine doesn't have a resolvable hostname, or you want to jump across some other network? The above-linked wiki page provides this sed-powered config:
Host *+*
ProxyCommand ssh -W $(echo %h | sed 's/^.*+//;s/^\([^:]*$\)/\1:22/') $(echo %h | sed 's/+[^+]*$//;s/\([^+%%]*\)%%\([^+]*\)$/\2 -l \1/;s/:\([^:+]*\)$/ -p \1/')
Looks crazy, and what it does is crazy too. It allows for chaining of hosts
when ssh
is invoked:
$ ssh -l user3 user1%host1:2222+user2%host2+host3
Here, %
is used as a delimiter for the username. To replicate our above
scenario to access a machine on the secret.lan network, we'd simply do:
ssh ssh-hop.example.com+router.work.space+secret-server.secret.lan
With the configuration we added for those domains, this is not necessary.
Note that ProxyJump can be accessed when calling SSH through the -J
flag.
Chances are, you already have SSH access to a system that is multi-homed on a network you can reach and the one you are trying to remotely access. SSH has a built in capability for tunneling, i.e. the ability to send arbitrary TCP traffic over the encrypted, authenticated SSH connection. Because of this, SSH can more-or-less accomplish the same end result as that of a tunnel VPN (for tap VPNs, different story), and sshuttle was developed to do exactly that. You don't need to configure anything on the remote server; you just need root access on your local machine and SSH access on the remote server with Python installed.
Setting up sshuttle to act like a full VPN is as simple as this:
$ sudo sshuttle --dns -r user@your-remote-server 0/0
This will route all outbound traffic, including DNS requests, through the
remote server (0/0
is short for 0.0.0.0/0
). The last parameter can be
tweaked to modify what traffic will be routed, in case you only want to use the
tunnel for traffic destined to a specific remote network.
Very cool stuff.
Well, there it is. I hope you start incorporating some of these techniques to make your life easier!