Reverse Proxy Web Access via SSH

I have a server located on a ‘secure’ network; Secure in the sense that it has extremely limited access either in or out to other networks, and specifically, doesn’t have internet access.

Normally, thats a good thing. It does however present some challenges in trying to set things up, or apply patches etc.

One option is to download packages, transfer them by SFTP, and then install by hand – not so easy when there are a string of dependencies, or you’re trying to do something more exotic!

The answer is to use SSH to create a SOCKS proxy and tunnel traffic over the SSH link.

1 – Start a local SOCKS proxy:

$ ssh -f -N -D 54321 localhost

The switches are:

  • -f : run in the background
  • -N : Don’t execute a remote command
  • -D 54321 : Create a dynamic listening port on 54321
  • localhost : connect to localhost

The -D option is the key to creating the SOCKS proxy. According to the man page:

-D [bind_address:]port
Specifies a local “dynamic” application-level port forwarding.

This works by allocating a socket to listen to port on the local side, optionally bound to the specified bind_address. Whenever a connection is made to this port, the connection is forwarded over the secure channel, and the application protocol is then used to determine where to connect to from the remote machine. Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh will act as a SOCKS server. Only root can forward privileged ports. Dynamic port forwardings can also be specified in the configuration file.

IPv6 addresses can be specified by enclosing the address in square brackets. Only the superuser can forward privileged ports. By default, the local port is bound in accordance with the GatewayPorts setting. However, an explicit bind_address may be used to bind the connection to a specific address. The bind_address of “localhost” indicates that the listening port be bound for local use only, while an empty address or `*’ indicates that the port should be available from all interfaces.

2 – Connect to the remote server, and set up reverse port forwarding

$ ssh root@server -R6666:localhost:54321

This creates a normal SSH connection to the remote server, with a tunnel listening on remote port 6666, forwarded to the local port 54321 (which we created in the last command)

3 – Configure the remote server to use the proxy

install proxychains (using whatever method).  The easiest way is to manually download the packages, SFTP to the remote server and install manually.  Thankfully this only needs to be done once.

Proxychains uses a clever technique to redirect traffic via the sock5 server you specify.  It can do a lot of other things, but for our purposes, that’s all we need it to do!

Edit /etc/proxychains.conf, and near the bottom ad:

[ProxyList]
socks5 127.0.0.1 6666

4 – Fix Proxychains DNS

Proxychains does one quite annoying thing.  Is uses dig for DNS lookups, but is hard-coded to use 4.2.2.2 for the DNS server’s IP address.  In my case this wont work (i’m sat behind a corporate firewall which blocks outgoing DNS requests)

Edit the file /usr/lib/proxychains3/proxyresolv

It should look something like:

#!/bin/sh
# This script is called by proxychains to resolve DNS names
# DNS server used to resolve names
DNS_SERVER=4.2.2.2

if [ $# = 0 ] ; then
echo ” usage:”
echo ” proxyresolv <hostname> ”
exit
fi

export LD_PRELOAD=libproxychains.so.3
dig $1 @$DNS_SERVER +tcp | awk ‘/A.+[0-9]+\.[0-9]+\.[0-9]/{print $5;}’

editing the correct DNS server ip in to this file should fix the problem.

5 – Profit!

at this point, prefixing any command with proxychains should make it use the SOCK5 proxy for networking! eg:

$ proxychains apt-get update