Server Side - Bash
#!/bin/bash
[[ $# -lt 3 ]] && echo "Usage: $0 tunID udp-port remote.lan.ip/net" && exit 255
TUN_ID=$(echo $1 | tr -d '[a-zA-Z]+')
[[ "$TUN_ID" != "$(( $TUN_ID / 1 ))" ]] && echo "tunID:\"$1\" must suffix with a number!" && exit 254
## Debug
TUN_DEV=$1
LOCAL_INT="192.168.2.$(( $TUN_ID % 64 * 4 + 1 ))/30"
REMOTE_INT="192.168.2.$(( $TUN_ID % 64 * 4 + 2 ))"
UDP_PORT=$2
REMOTE_LAN=$3
# kill exists
pkill -f "tun-name=$TUN_DEV"
socat tun:$LOCAL_INT,tun-name=$TUN_DEV,up udp4-listen:$UDP_PORT,fork &
sleep 3
# tunX options
ip link set $TUN_DEV mtu 1452
shift 2
# Add all the given subnet to SNAT
for net in $*;do
ip route add $net dev $TUN_DEV
iptables -t nat -I POSTROUTING -s $net -j SNAT --to-source $(hostname -i)
done
Client Side - BusyBox
#!/bin/sh
[[ $# -lt 2 ]] && echo "Usage: $0 tunID remote.ip.udp:port" && exit 255
TUN_ID=$(echo $1 | tr -d '[A-Za-z]+')
[[ "$TUN_ID" != "$(( $TUN_ID / 1 ))" ]] && echo "tunID:\"$1\" must suffix with a number!" && exit 254
TUN_DEV=$1
LOCAL_INT="192.168.2.$(( $TUN_ID % 64 * 4 + 2 ))/30"
REMOTE_INT="192.168.2.$(( $TUN_ID % 64 * 4 + 1 ))"
REMOTE_UDP=$2
kill $(ps | grep tun-name=$TUN_DEV | cut -d ' ' -f 1) 2>/dev/null
socat tun:$LOCAL_INT,tun-name=$TUN_DEV,up udp4-connect:$REMOTE_UDP &
sleep 3
# MTU
ip link set $TUN_DEV mtu 1452
# IP Route2
ip route add default via $REMOTE_INT table $TUN_DEV
ip rule add from $REMOTE_INT table $TUN_DEV