#!/bin/bash

# socksvpn      SOCKS VPN start/stop script
# Copyright (C) 2015 Michal Trojnara <Michal.Trojnara@stunnel.org>
# 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
