Skip to content

Instantly share code, notes, and snippets.

@rsanden
Last active June 3, 2024 13:35
Show Gist options
  • Save rsanden/ba29b8ea7d5d3bd482e717413a745243 to your computer and use it in GitHub Desktop.
Save rsanden/ba29b8ea7d5d3bd482e717413a745243 to your computer and use it in GitHub Desktop.
tun2socks TCP+UDP user-wide proxy through shadowsocks and udpgw
#--- Build tun2socks and udpgw (as the user who will use the proxy) ---
mkdir -p $HOME/src
cd $HOME/src
git clone "https://github.com/ambrop72/badvpn"
cd badvpn
mkdir -p build
cd build
export OUTDIR=$PWD
export SRCDIR=$(dirname $PWD)
export CC=gcc
export ENDIAN=little
bash $SRCDIR/compile-tun2socks.sh
bash $SRCDIR/compile-udpgw.sh
mkdir -p $HOME/bin/badvpn
cp tun2socks $HOME/bin/badvpn/
cp udpgw $HOME/bin/badvpn/
#--- We also need Shadowsocks ---
export GOPATH="$HOME/go"
go get "github.com/shadowsocks/shadowsocks-go"
go get "github.com/Yawning/chacha20"
go get "golang.org/x/crypto/blowfish"
go get "golang.org/x/crypto/cast5"
go get "golang.org/x/crypto/salsa20/salsa"
cd "$GOPATH/src/github.com/shadowsocks/shadowsocks-go/cmd/shadowsocks-local"
CGO_ENABLED=0 go build
cd "$GOPATH/src/github.com/shadowsocks/shadowsocks-go/cmd/shadowsocks-server"
CGO_ENABLED=0 go build
# Do install -- remember to set SHADOWSOCKS_VERSION
SHADOWSOCKS_VERSION=1.2.1
mkdir -p $HOME/bin/shadowsocks
cd $HOME/bin/shadowsocks
cp "$GOPATH/src/github.com/shadowsocks/shadowsocks-go/cmd/shadowsocks-local/shadowsocks-local" shadowsocks-local-linux64-${SHADOWSOCKS_VERSION}
cp "$GOPATH/src/github.com/shadowsocks/shadowsocks-go/cmd/shadowsocks-server/shadowsocks-server" shadowsocks-server-linux64-${SHADOWSOCKS_VERSION}
ln -sf shadowsocks-local-linux64-${SHADOWSOCKS_VERSION} shadowsocks-local
ln -sf shadowsocks-server-linux64-${SHADOWSOCKS_VERSION} shadowsocks-server
# Sample config file (same for client and server) -- "myserver.conf"
{
"server":"machine1.example.com",
"server_port":8888,
"local_port":8080,
"password":"xxxxxxxxxxxx",
"timeout":600,
"method":"aes-256-cfb",
"fast_open": false,
"workers": 1
}
# Server (with -u for UDP support -- though, I'm not sure if it can be used with tun2socks)
$HOME/bin/shadowsocks/shadowsocks-server -c $HOME/bin/shadowsocks/myserver.conf -u
# Client
$HOME/bin/shadowsocks/shadowsocks-local -c $HOME/bin/shadowsocks/myserver.conf
#--- Now, the start/stop script which proxifies a user ("foo" in this case) ---
##
## First, be sure to start Shadowsocks on 127.0.0.1 (on port 8080 in this case)
## Second, be sure to start the udpgw on the remote server (on port 7300 in this case)
##
## Then, put the following into a script like "tun2socks_proxy_foo.bash" which will be run as root
##
## If you need multple scripts, a more general naming scheme is as follows:
## tun2socks_proxy_${LOCAL_USER}_${NET_IFACE}_${REMOTE_SERVER}_${TCPPORT}_${TUN_IFACE}.bash
##
#!/bin/bash
LOCAL_USER=foo
NET_IFACE=wlan0
TUN_IFACE=tun0
REMOTE_USER=me
REMOTE_SERVER=100.200.300.400
ROUTER_IP=192.168.1.1
TCPPORT=8080
UDPPORT=7300
VPN_TUN_IP=10.0.0.1
VPN_GW_IP=10.0.0.2
TABLE_MARK=11
#--- Get Local Network ---
ROUTER_NET=$(echo $ROUTER_IP | sed -E 's/[[:digit:]]+$/0\/24/g')
#--- Redirect for $LOCAL_USER (as root) ---
echo "Setting up proxy for ${LOCAL_USER}"
ip tuntap add dev ${TUN_IFACE} mode tun user ${LOCAL_USER}
ip addr add ${VPN_TUN_IP}/24 dev ${TUN_IFACE}
ip link set ${TUN_IFACE} up
ip rule add fwmark ${TABLE_MARK} table ${TABLE_MARK}
ip route add $ROUTER_NET dev ${NET_IFACE} table ${TABLE_MARK}
ip route add ${REMOTE_SERVER}/32 via ${ROUTER_IP} table ${TABLE_MARK}
ip route add default via ${VPN_TUN_IP} table ${TABLE_MARK}
iptables -t mangle -A OUTPUT -m owner --uid-owner $(id -u ${LOCAL_USER}) -j MARK --set-mark ${TABLE_MARK}
iptables -t nat -A POSTROUTING -o ${TUN_IFACE} -j SNAT --to-source ${VPN_GW_IP}
sysctl -w net.ipv4.conf.${TUN_IFACE}.rp_filter=2
ip route flush cache
#--- start local redirection daemon (as user) ---
sudo -u ${LOCAL_USER} /home/${LOCAL_USER}/bin/badvpn/tun2socks --tundev ${TUN_IFACE} --netif-ipaddr ${VPN_GW_IP} --netif-netmask 255.255.255.0 --socks-server-addr 127.0.0.1:${TCPPORT} --udpgw-remote-server-addr ${REMOTE_SERVER}:${UDPPORT}
#--- Stop redirect for $LOCAL_USER (as root) ---
echo "Tearing down proxy for ${LOCAL_USER}"
ip rule del fwmark ${TABLE_MARK} table ${TABLE_MARK}
ip route flush table ${TABLE_MARK}
iptables -t mangle -D OUTPUT -m owner --uid-owner $(id -u ${LOCAL_USER}) -j MARK --set-mark ${TABLE_MARK}
iptables -t nat -D POSTROUTING -o ${TUN_IFACE} -j SNAT --to-source ${VPN_GW_IP}
sysctl -w net.ipv4.conf.${TUN_IFACE}.rp_filter=1
ip link set ${TUN_IFACE} down
ip tuntap del dev ${TUN_IFACE} mode tun
ip route flush cache
#--- Start the proxy ---
##
## Just run the script as root to start the proxy, and Ctrl-C to stop it.
##
## In the meantime, you can try "curl ip.ryansanden.com" to see your effective IP as the user ("foo") or another user.
## What should happen is that you see the $REMOTE_SERVER ip from "foo" only.
##
./tun2socks_proxy_foo.bash
#--- GUI applications ---
##
## Since you're usually running this proxy for a separate user, that user needs to be able to access your X session.
## Ensuring that user can access /dev/dri means it can fully use OpenGL (i.e. glxgears) as well.
##
xhost +SI:localuser:foo
sudo usermod -a -G video foo
# For the correct group ("video" in my case), see /dev/dri/card0:
#
# me@MyMachine:~$ getfacl /dev/dri/card0
# getfacl: Removing leading '/' from absolute path names
# # file: dev/dri/card0
# # owner: root
# # group: video
# user::rw-
# user:me:rw-
# group::rw-
# mask::rw-
# other::---
@neestzjov
Copy link

So did both tcp and udp work for you using this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment