SOCKS VPN Overview
The following example illustrates using stunnel for a transparent VPN based on the SSL-encrypted SOCKS protocol with the Tor RESOLVE [F0] extension.
Unlike most other VPNs, SOCKS-based VPNs do not introduce any persistent control connection. This is highly preferable for battery-powered clients, as there are no keepalives. This also performs as good as direct TCP connections when clients frequently change their IP addresses, which is common in mobile environments.
Server Prerequisites
- stunnel 5.24b1 or later on any platform supported by stunnel
The server configuration does not require any specific operating systems nor administrative privileges. Consequently, it is possible to setup VPN servers on most shared hosting platforms.
Client Prerequisites
- stunnel 5.23 or later on the Linux platform
- stunnel 5.24b2 or later on the FreeBSD, OpenBSD or OSX platform
- Administrative (root) privileges
- Tor-DNS for optional encrypted DNS support
The socksvpn client is not supported on the Windows platform.
Create Shared Secrets
Create the secrets.txt file containing long pre-shared secrets. The secrets.txt file on each client needs to contain just one username/secret pair. The secrets.txt on the server needs to contain the secrets of all permitted clients, for example:
user1:hooxaa4bohFa9booNo1meZaishie3e
user2:this is a very long and sufficiently secure passphrase
It is also possible, although more complex, to use PKI for authentication.
Setup the Server
The configuration file (stunnel.conf) template:
[SOCKS Server]
PSKsecrets = secrets.txt
accept = :::9080
protocol = socks
Setup the Client
The VPN client can be either a Linux gateway routing the traffic for an internal network (which needs the IP forwarding to be enabled), or a single Linux host (server or workstation).
Setup stunnel and run it as root
The configuration file (stunnel.conf) template:
[SOCKS Client Direct]
client = yes
PSKsecrets = secrets.txt
accept = :::9050
connect = <server_address>:9080
[SOCKS Client Transparent IPv4]
client = yes
PSKsecrets = secrets.txt
accept = 127.0.0.1:9051
connect = <server_address>:9080
protocol = socks
[SOCKS Client Transparent IPv6]
client = yes
PSKsecrets = secrets.txt
accept = ::1:9051
connect = <server_address>:9080
protocol = socks
Setup the firewall (as root)
On Linux the Netfilter is used:
VPN_HOST=<server_address>
iptables -t nat -A OUTPUT -p tcp -d $VPN_HOST --dport 9080 -j ACCEPT 2>/dev/null
iptables -t nat -A OUTPUT -o lo -j ACCEPT # internal OS IPC
iptables -t nat -A OUTPUT -p tcp --dport 9050 -j ACCEPT # non-transparent SOCKS
iptables -t nat -A OUTPUT -p tcp -j REDIRECT --to-ports 9051
iptables -t nat -A PREROUTING -p tcp --dport 9050 -j ACCEPT # non-transparent SOCKS
iptables -t nat -A PREROUTING -p tcp -j REDIRECT --to-ports 9051
ip6tables -t nat -A OUTPUT -p tcp -d $VPN_HOST --dport 9080 -j ACCEPT 2>/dev/null
ip6tables -t nat -A OUTPUT -o lo -j ACCEPT # internal OS IPC
ip6tables -t nat -A OUTPUT -p tcp --dport 9050 -j ACCEPT # non-transparent SOCKS
ip6tables -t nat -A OUTPUT -p tcp -j REDIRECT --to-ports 9051
ip6tables -t nat -A PREROUTING -p tcp --dport 9050 -j ACCEPT # non-transparent SOCKS
ip6tables -t nat -A PREROUTING -p tcp -j REDIRECT --to-ports 9051
On FreeBSD, OpenBSD or OS X a PF configuration is required. Please contribute your configuration if you use one of these operating systems.
Setup DNS
Setup Tor-DNS to resolve DNS requests with SOCKS service on port 9050.
Configure your resolver configuration with DHCP, or by editing /etc/resolv.conf if DHCP is not used.
Client Configuration Script
The following script can be used to automate the client configuration on Linux (FreeBSD, OpenBSD and OSX support is also planned):
#!/bin/bash
# socksvpn SOCKS VPN start/stop script
# Copyright (C) 2015 Michal Trojnara <[email protected]>
# Version: 1.03
# Release date: 2015.09.07
VPN_HOST=example.com
VPN_PORT=9080
SECRETS=/usr/local/etc/stunnel/secrets.txt
PID_DIR=/run
PID_STUNNEL=$PID_DIR/socksvpn.pid
PID_TOR_DNS=$PID_DIR/tor-dns.pid
stunnel_start() {
stunnel -fd 0 << EOT
pid = $PID_STUNNEL
client = yes
PSKsecrets = $SECRETS
connect = $VPN_HOST:$VPN_PORT
[SOCKS Client Direct]
accept = :::9050
[SOCKS Client Transparent IPv4]
accept = 127.0.0.1:9051
protocol = socks
[SOCKS Client Transparent IPv6]
accept = ::1:9051
protocol = socks
EOT
}
do_netfilter() {
$1 -t nat -F $2
if [[ $2 = OUTPUT ]]; then # traffic of local processes
$1 -t nat -A $2 -p tcp -d $VPN_HOST --dport $VPN_PORT -j ACCEPT 2>/dev/null
$1 -t nat -A $2 -o lo -j ACCEPT # internal OS IPC
fi
$1 -t nat -A $2 -p tcp --dport 9050 -j ACCEPT # non-transparent SOCKS
$1 -t nat -A $2 -p tcp -j REDIRECT --to-ports 9051
}
netfilter_start() {
for PROG in iptables ip6tables; do
for TABLE in PREROUTING OUTPUT; do
do_netfilter $PROG $TABLE
done
done
}
netfilter_stop() {
for PROG in iptables ip6tables; do
for TABLE in PREROUTING OUTPUT; do
$PROG -t nat -F $TABLE
done
done
}
pf_start() {
sysctl -w net.inet.ip.forwarding=1
# the PF configuration needs to be implemented:
# echo "rdr on en2 inet proto tcp to any port 443 -> 127.0.0.1 port 9051" >"$0.pf"
# pfctl -f "$0.pf"
pfctl -e
}
pf_stop() {
pfctl -d
}
do_start() {
stunnel_start
netfilter_start
rm -f $PID_TOR_DNS
nohup tor-dns >/dev/null 2>&1 &
echo $! >$PID_TOR_DNS
cp /etc/resolv.conf /etc/resolv.conf.socksvpn-backup
echo "nameserver 127.0.0.1" >/etc/resolv.conf
echo "$0 started"
}
do_stop() {
cp /etc/resolv.conf.socksvpn-backup /etc/resolv.conf
netfilter_stop
kill -TERM $(cat $PID_STUNNEL)
kill -TERM $(cat $PID_TOR_DNS)
rm -f $PID_TOR_DNS
echo "$0 stopped"
}
if [[ $EUID -ne 0 ]]; then
echo "$0 must be run as root" >&2
exit 1
fi
case "$1" in
start)
do_start
;;
restart|reload|force-reload)
do_stop
sleep 3
do_start
;;
stop)
do_stop
;;
*)
echo "Usage: $0 start|stop|restart|reload|force-reload" >&2
exit 3
;;
esac