Skip to content

Instantly share code, notes, and snippets.

@nehaljwani
Created July 30, 2017 09:43
Show Gist options
  • Save nehaljwani/f6e9d12102157161bfceb7eea80c319f to your computer and use it in GitHub Desktop.
Save nehaljwani/f6e9d12102157161bfceb7eea80c319f to your computer and use it in GitHub Desktop.
OpenConnect VPN Inside Linux Network Namespace
#!/bin/bash
# start openconnect tunnel and shell inside Linux network namespace
#
# this is a fork of schnouki's script, see original blog post
# https://schnouki.net/posts/2014/12/12/openvpn-for-a-single-application-on-linux/
#
# original script can be found here
# https://gist.github.com/Schnouki/fd171bcb2d8c556e8fdf
# ------------ adjust values below ------------
NS_NAME="myvpn"
NS_EXEC="sudo -E ip netns exec $NS_NAME"
VPN_ENDPOINT="superawesomevpn.io/someplace"
VPN_USER="nwani"
WIRED_INTERFACE="enp1s0"
WIRELESS_INTERFACE="wlp2s0"
OUT_IF="${NS_NAME}0"
IN_IF="${NS_NAME}1"
OUT_IP="10.200.200.1"
IN_IP="10.200.200.2"
read -s -p "VPN Password: " VPN_PASS
set -uxeo pipefail
start_vpn() {
echo "Add network interface"
# create the network namespace
sudo ip netns add "$NS_NAME"
# start the loopback interface in the namespace
$NS_EXEC ip addr add 127.0.0.1/8 dev lo
$NS_EXEC 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 (${IN_IF}) to use the interface out of the namespace (${OUT_IF})
# as its default gateway
sudo ip link add "${OUT_IF}" type veth peer name "${IN_IF}"
sudo ip link set "${OUT_IF}" up
sudo ip link set "${IN_IF}" netns "${NS_NAME}" up
sudo ip addr add "${OUT_IP}"/24 dev "${OUT_IF}"
$NS_EXEC ip addr add "${IN_IP}"/24 dev "${IN_IF}"
$NS_EXEC ip link set dev "${IN_IF}" mtu 1492
$NS_EXEC ip route add default via "${OUT_IP}" dev "${IN_IF}"
# make sure ipv4 forwarding is enabled
sudo sysctl -w net.ipv4.ip_forward=1
# configure the nameserver to use inside the namespace
# TODO use VPN-provided DNS servers in order to prevent leaks
sudo mkdir -p "/etc/netns/${NS_NAME}"
cat <<EOF | sudo tee "/etc/netns/${NS_NAME}/resolv.conf" || exit 1
nameserver 8.8.8.8
nameserver 8.8.4.4
EOF
# IPv4 NAT, you may need to adjust the interface name prefixes
sudo iptables -t nat -A POSTROUTING -o "${WIRED_INTERFACE}" -m mark --mark 0x29a -j MASQUERADE
sudo iptables -t nat -A POSTROUTING -o "${WIRELESS_INTERFACE}" -m mark --mark 0x29a -j MASQUERADE
sudo iptables -t mangle -A PREROUTING -i "${OUT_IF}" -j MARK --set-xmark 0x29a/0xffffffff
# start openconnect in the namespace
echo "Starting VPN"
set +x
echo -e "${VPN_PASS}\npush" | $NS_EXEC /usr/sbin/openconnect --interface vpn0 $VPN_ENDPOINT -u $VPN_USER --passwd-on-stdin &
# wait for the tunnel interface to come up
while ! $NS_EXEC ip link show dev vpn0 >/dev/null 2>&1 ; do sleep .5 ; done
}
stop_vpn() {
echo "Stopping VPN"
sudo ip netns pids $NS_NAME | sudo xargs -rd'\n' kill -SIGINT
# TODO wait for terminate
sleep 2
# clear NAT
sudo iptables -t nat -D POSTROUTING -o "${WIRED_INTERFACE}" -m mark --mark 0x29a -j MASQUERADE
sudo iptables -t nat -D POSTROUTING -o "${WIRELESS_INTERFACE}" -m mark --mark 0x29a -j MASQUERADE
sudo iptables -t mangle -D PREROUTING -i "${OUT_IF}" -j MARK --set-xmark 0x29a/0xffffffff
echo "Delete network interface"
sudo rm -rf "/etc/netns/${NS_NAME}"
sudo ip netns delete "${NS_NAME}"
sudo ip link delete "${OUT_IF}"
}
start_vpn
# start app inside n/w namespace
$NS_EXEC su ${USER}
trap stop_vpn EXIT
@porjo
Copy link

porjo commented Dec 9, 2019

@nehaljwani thanks for the suggestion. I tried that but couldn't make it work. I've ended up getting it working by replacing the openconnect line with this:

$NS_EXEC /usr/sbin/openconnect -b --authgroup=VPN --interface vpn0 $VPN_ENDPOINT -u $VPN_USER

I enter both passwords manually to stdin, then openconnect goes to the background (-b) and the shell script resumes

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