Skip to content

Instantly share code, notes, and snippets.

@gpolitis
Created December 8, 2020 13:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gpolitis/302beeaa7cd56c9ff287b5620dd581d0 to your computer and use it in GitHub Desktop.
Save gpolitis/302beeaa7cd56c9ff287b5620dd581d0 to your computer and use it in GitHub Desktop.
#!/bin/sh -x
errexit() {
echo "$1"
exit 1
}
usage() {
echo "Usage: $0 wrap -c file command"
echo " $0 reset -c file command"
exit 1
}
if [ `id -u` -ne 0 ]; then
errexit "This must be run as root."
fi
if [ "$#" -lt 3 ]; then
usage
fi
COMMAND=$1
shift
shift
CONFIG=$1
shift
if [ ! -f $CONFIG ]; then
errexit "The config file was not found."
fi
set -a
. $CONFIG
set +a
vpnns_check() {
if [ ! -d $VPNNS_HOME ]; then
errexit "The vpnns home directory does not exist."
fi
if [ -z "$VPNNS_NAME" ]; then
errexit "The network namespace name is not defined."
fi
if [ -z "$VETH_IP1" ]; then
errexit "The first IP is not defined."
fi
if [ -z "$VETH_IP2" ]; then
errexit "The second IP is not defined."
fi
if [ -z "$VETH_NET" ]; then
errexit "The virtual ethernet network is not defined."
fi
}
vpnns_up() {
# Create the network namespace
ip netns add $VPNNS_NAME
# Start the loopback interface in the namespace (otherwise many things don’t
# work as expected…)
ip netns exec $VPNNS_NAME ip addr add 127.0.0.1/8 dev lo
ip netns exec $VPNNS_NAME ip link set lo up
# Create virtual network interfaces that will let OpenVPN (in the namespace)
# access the real network, and configure the interface in the namespace (vpn1)
# to use the interface out of the namespace (vpn0) as its default gateway
ip link add vpn0 type veth peer name vpn1
ip link set vpn0 up
ip link set vpn1 netns $VPNNS_NAME up
ip addr add $VETH_IP1/24 dev vpn0
ip netns exec $VPNNS_NAME ip addr add $VETH_IP2/24 dev vpn1
ip netns exec $VPNNS_NAME ip route add default via $VETH_IP1 dev vpn1
# Enable IPv4 routing and NAT for the interface in the namespace. As my default
# interface is a wireless one, I use wl+ (which may match wlan0, wlp3s0, etc.)
# in iptables for the outgoing interface; if you use a wired interface you
# should probably use en+ (or br+ for a bridged interface)
iptables -A INPUT \! -i vpn0 -s $VETH_NET/24 -j DROP
iptables -t nat -A POSTROUTING -s $VETH_NET/24 -o $OUT_INTERFACE -j MASQUERADE
sysctl -q net.ipv4.ip_forward=1
# Configure the nameserver to use inside the namespace
mkdir -p "$VPNNS_HOME"
echo 'nameserver 8.8.8.8' > $VPNNS_HOME/resolv.conf
}
vpnns_down() {
sysctl -q net.ipv4.ip_forward=0
iptables -D INPUT \! -i vpn0 -s $VETH_NET/24 -j DROP
iptables -t nat -D POSTROUTING -s $VETH_NET/24 -o $OUT_INTERFACE -j MASQUERADE
ip link del vpn0
ip netns delete $VPNNS_NAME
}
vpnns_connect() {
# Finally start OpenVPN in the namespace
ip netns exec $VPNNS_NAME openvpn --config $OPENVPN_CONF --auth-user-pass $OPENVPN_AUTH &
while ! ip netns exec $VPNNS_NAME ip -4 a show tun0 | grep inet; do
SLEEP4=5
echo Waiting for $SLEEP4...
sleep $SLEEP4
done
OPENVPN_PID=$!
}
vpnns_disconnect() {
if [ -n "$OPENVPN_PID" ]; then
kill $OPENVPN_PID
wait $OPENVPN_PID
fi
}
if [ "$COMMAND" = "reset" ]; then
vpnns_disconnect
vpnns_down
fi
if [ "$COMMAND" = "wrap" ]; then
vpnns_check
vpnns_up
vpnns_connect
ip netns exec $VPNNS_NAME sudo -u $SUDO_USER "$@"
vpnns_disconnect
vpnns_down
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment