A Simple Socksifying Router in three easy steps: 1) iptables, 2) redsocks, and 3) openssh

A socksifying router is a useful tool - in most cases when its easy to set up on a running system without making too many permanent modifications, and when it doesn't interfere with the running system in any significant way. A common use case for this tool is the road warrior who wants to tunnel back into the corporate network with her entire mobile networked infrastructure, and not just a single laptop. Other use cases might include things like ex-pats wanting to use some home-grown functionality that they couldn't otherwise have, or sports fans watching games from the great blackout zone. Executing a single bash script will have them happily socksing away in no time.

The router hardware I'm using for this tool is a typical laptop - one that is wirelessly connected to the internet and has an available wired ethernet port as well. My laptop is running ubuntu raring - but extension of these instructions to other versions of linux should be pretty straightforward.

Router setup

For the purpose of these instructions, we'll assume that the wireless interface is named wlan0, and the wired interface is named eth0. We'll create a router using a dhcp server to allocate addresses to nodes on eth0 and iptables to route the traffic through the router. Note that the subnet defined on eth0 must be different from that defined on wlan0.

To set up the dhcp server, install the package isc-dhcp-server as follows:

 sudo apt-get install isc-dhcp-server

Configure the server by editing /etc/dhcp/dhcpd.conf as follows:

# Sample configuration file for ISC dhcpd for Debian
#
# Attention: If /etc/ltsp/dhcpd.conf exists, that will be used as
# configuration file instead of this file.
#
#

# The ddns-updates-style parameter controls whether or not the server will
# attempt to do a DNS update when a lease is confirmed. We default to the
# behavior of the version 2 packages ('none', since DHCP v2 didn't
# have support for DDNS.)
ddns-update-style none;

# option definitions common to all supported networks...
option domain-name "example.org";
option domain-name-servers 8.8.8.8,8.8.4.4;

default-lease-time 86400;
max-lease-time 172800;

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
authoritative;

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
log-facility local7;

# this is our subnet on eth0
# the dhcp server will assign addresses within the ranges specified
# eth0 should be configured with the addres 192.168.1.1

subnet 192.168.1.0 netmask 255.255.255.0 {
  range 192.168.1.10 192.168.1.100;
  range 192.168.1.150 192.168.1.200;
  option routers 192.168.1.1;
  option broadcast-address 192.168.1.255;
}

Finally, start the dhcp server with the command:

 sudo service isc-dhcp-server start

Socksifying router script

In order for this script to work, you must install the following packages:

 sudo apt-get install redsocks openssh-client

The following script will configure redsocks to accept input to the proxy on port 1081, and output the proxy data on port 1080 where it will be sent to the destination server through the ssh tunnel.

#!/bin/bash
########################################################################
# This bash script will create a socksifying router and pass all subnet
# traffic over an ssh tunnel to a server at a different location through
# a socks5 proxy. As the script is now written, local traffic is not
# proxied, however, make the change noted below and it will be.
#
# Assumptions here are that you are using a laptop with an internet
# connection on wlan0, and an additional wired ethernet port eth0.
#
# The script requires that a dhcp server be running using the
# isc-dhcp-server package on ubuntu, or equivalent on other O/S varieties.
# This dhcp server will serve addresses on eth0 to nodes trying to
# connect.  Either that or all of the subnet clients have to have static
# addresses. To configure dhcpd, add the following to /etc/dhcp/dhcpd.conf
# (changing the subnet address as appropriate):
#
#subnet 192.168.1.0 netmask 255.255.255.0 {
#  range 192.168.1.10 192.168.1.100;
#  range 192.168.1.150 192.168.1.200;
#  option routers 192.168.1.254;
#  option broadcast-address 192.168.1.255;
#}
#
# Also, the script requires the redsocks, openssh-client, and iptables
# packages be installed as well.
#
# Finally, you need to edit /etc/sysctl.conf as follows:
#
# Uncomment the next line to enable packet forwarding for IPv4
# net.ipv4.ip_forward=1
########################################################################

########################################################################
# Define various configuration parameters.
########################################################################

SSH_PORT=22
SSH_USER_SERVER="target.ssh.server.address"
SOCKS_PORT=1080
REDSOCKS_TCP_PORT=$(expr $SOCKS_PORT + 1)
TMP=/tmp/subnetproxy ; mkdir -p $TMP
REDSOCKS_LOG=$TMP/redsocks.log
REDSOCKS_CONF=$TMP/redsocks.conf
SUBNET_INTERFACE=eth0
SUBNET_PORT_ADDRESS="192.168.1.1" #can't be the same subnet as wlan0
INTERNET_INTERFACE=wlan0

########################################################################
#standard router setup - sets up subnet SUBNET_PORT_ADDRESS/24 on eth0
########################################################################

# note - if you just want a standard router without the proxy/tunnel
# business, you only need to execute this block of code.

sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
sudo ifconfig eth0 $SUBNET_PORT_ADDRESS netmask 255.255.255.0
sudo iptables -A FORWARD -o wlan0 -i eth0 -s $SUBNET_PORT_ADDRESS/24 \
     -m conntrack --ctstate NEW -j ACCEPT
sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED \
     -j ACCEPT
sudo iptables -A POSTROUTING -t nat -j MASQUERADE

########################################################################
#redsocks configuration
########################################################################

cat >$REDSOCKS_CONF <<EOF
base {
  log_info = on;
  log = "file:$REDSOCKS_LOG";
  daemon = on;
  redirector = iptables;
}
redsocks {
  local_ip = 0.0.0.0;
  local_port = $REDSOCKS_TCP_PORT;
  ip = 127.0.0.1;
  port = $SOCKS_PORT;
  type = socks5;
}
EOF

########################################################################
# start openssh tunnel
########################################################################

ssh -qfN -D $SOCKS_PORT -p $SSH_PORT $SSH_USER_SERVER

# To use tor just change the redsocks output port from 1080 to 9050 and
# replace the ssh tunnel with a tor instance.

########################################################################
# start redsocks
########################################################################

sudo redsocks -c $REDSOCKS_CONF -p /dev/null

########################################################################
# proxy iptables setup
########################################################################

# create the REDSOCKS target
sudo iptables -t nat -N REDSOCKS

# don't route unroutable addresses
sudo iptables -t nat -A REDSOCKS -d 0.0.0.0/8 -j RETURN
sudo iptables -t nat -A REDSOCKS -d 10.0.0.0/8 -j RETURN
sudo iptables -t nat -A REDSOCKS -d 127.0.0.0/8 -j RETURN
sudo iptables -t nat -A REDSOCKS -d 169.254.0.0/16 -j RETURN
sudo iptables -t nat -A REDSOCKS -d 172.16.0.0/12 -j RETURN
#sudo iptables -t nat -A REDSOCKS -d 192.168.0.0/16 -j RETURN
sudo iptables -t nat -A REDSOCKS -d 224.0.0.0/4 -j RETURN
sudo iptables -t nat -A REDSOCKS -d 240.0.0.0/4 -j RETURN

# redirect statement sends everything else to the redsocks
# proxy input port
sudo iptables -t nat -A REDSOCKS -p tcp -j REDIRECT \
     --to-ports $REDSOCKS_TCP_PORT

# if it came in on eth0, and it is tcp, send it to REDSOCKS
sudo iptables -t nat -A PREROUTING -i $SUBNET_INTERFACE \
     -p tcp -j REDSOCKS

# Use this one instead of the above if you want to proxy the local
# networking in addition to the subnet stuff. Redsocks listens on
# all interfaces with local_ip = 0.0.0.0 so no other changes are
# necessary.
#sudo iptables -t nat -A PREROUTING -p tcp -j REDSOCKS

# don't forget to accept the tcp packets from eth0
sudo iptables -A INPUT -i eth0 -p tcp --dport $REDSOCKS_TCP_PORT \
     -j ACCEPT

Its useful to note here that if you want an anonymous tunnel, rather than point the output of the redsocks proxy to port 1080, you can point it to port 9050 (default tor socks port), and run tor. A caveat here: the proxy only tunnels tcp data. Since dns is udp by default, your dns resolver packets are not tunneled. In some cases, this is of no consequence, but if you would like to use dns over tcp in order to have these requests tunneled as well, installing pdnsd and invoking it with the command: sudo pdnsd -d -mto will add that functionality.

Finally, here's a script to take down the router and return the networking to its normal state.

#!/bin/bash
########################################################################
# This script will purge the socksifying router you set up with the
# socks_router.sh script.
########################################################################

sudo iptables -t nat -F REDSOCKS
sudo iptables -t nat -F PREROUTING
sudo iptables -t nat -F POSTROUTING
sudo iptables -F INPUT
sudo iptables -F FORWARD
sudo iptables -t nat -X REDSOCKS
sudo killall redsocks
sudo killall ssh
sudo service isc-dhcp-server stop
sudo ip addr flush eth0
All code, text and images are Copyright © 2013-2017 by David R. Andersen. All rights reserved unless otherwise specified.
This site is produced using the Haggis static site generator.