Created
December 8, 2020 13:08
-
-
Save gpolitis/302beeaa7cd56c9ff287b5620dd581d0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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