Skip to content

Instantly share code, notes, and snippets.

@gustavohenrique
Created April 27, 2020 10:29
Show Gist options
  • Select an option

  • Save gustavohenrique/a169a286660efe5abf3bef210ead34de to your computer and use it in GitHub Desktop.

Select an option

Save gustavohenrique/a169a286660efe5abf3bef210ead34de to your computer and use it in GitHub Desktop.
Create a namespace for running applications which are only allowed to use certain network connections
#!/bin/bash
set -Eeuo pipefail
if [ "$#" != 2 ]
then
(
echo "Usage: $0 <vpn-interface> <nameserver>"
echo ""
echo "For example: $0 tun0 8.8.8.8"
echo ""
echo "Warning: This script will flush and create iptables rules!"
exit 1
) >&2
fi
VPN_INTERFACE="${1}"
NNS_NAME="${VPN_INTERFACE}ns"
NNS_VETH_PREFIX="${VPN_INTERFACE}nsi"
NNS_VETH0="${NNS_VETH_PREFIX}0"
NNS_VETH1="${NNS_VETH_PREFIX}1"
IP_ADDRESS_BASE="10.157.0"
NAMESERVER="${2}"
# Clean up old configuration entries
ip link delete "${NNS_VETH0}" || true
ip netns delete "${NNS_NAME}" || true
# Create new network namespace
ip netns add "${NNS_NAME}"
# Create veth pair and move ${NNS_VETH1} into network namespace
ip link add "${NNS_VETH0}" type veth peer name "${NNS_VETH1}"
ip link set "${NNS_VETH1}" netns "${NNS_NAME}"
# Configure non-namespaced interface
ip a a "${IP_ADDRESS_BASE}.1/24" dev "${NNS_VETH0}"
ip link set "${NNS_VETH0}" up
sysctl -q -w "net/ipv6/conf/${NNS_VETH0}/disable_ipv6=1"
# Configure namespaced interface
ip netns exec "${NNS_NAME}" ip a a "${IP_ADDRESS_BASE}.2/24" dev "${NNS_VETH1}"
ip netns exec "${NNS_NAME}" ip link set "${NNS_VETH1}" up
ip netns exec "${NNS_NAME}" ip link set lo up
ip netns exec "${NNS_NAME}" ip route add default via "${IP_ADDRESS_BASE}.1"
ip netns exec "${NNS_NAME}" sysctl -q -w "net/ipv6/conf/${NNS_VETH1}/disable_ipv6=1"
# Enable masquerading for connections from network namespace
iptables -t nat -F
iptables -t nat -A POSTROUTING \
-s "${IP_ADDRESS_BASE}".0/24 -d 0/0 \
-j MASQUERADE
# Ensure that data from/to the network namespace must traverse the VPN
# interface
iptables -t filter -F
iptables -t filter -P FORWARD DROP
iptables -t filter -A FORWARD \
-i "${NNS_VETH0}" -o "${VPN_INTERFACE}" -s "${IP_ADDRESS_BASE}".0/24 -d 0/0 \
-j ACCEPT
iptables -t filter -A FORWARD \
-i "${VPN_INTERFACE}" -o "${NNS_VETH0}" -d "${IP_ADDRESS_BASE}".0/24 -s 0/0 \
-j ACCEPT
# Configure a nameserver for the network namespace
mkdir -p /etc/netns/"${NNS_NAME}"
sh -c 'echo "nameserver '"${NAMESERVER}"'" > /etc/netns/'"${NNS_NAME}"'/resolv.conf'
# Finally, enable forwarding
sysctl -q net.ipv4.ip_forward=1
if [ "${NAMESERVER}" == "8.8.8.8" ]
then
echo -n "Warning: Your nameserver is set to 8.8.8.8, which will "
echo "expose your DNS queries."
fi
echo
echo -n "VPN-only network namespace ${NNS_NAME} has been set up. To run "
echo "applications in this namespace, use:"
echo " sudo ip netns exec \"${NNS_NAME}\" sudo -u \"${SUDO_USER:-<user>}\" <command>"
echo
echo "For example: "
echo " sudo ip netns exec \"${NNS_NAME}\" sudo -u \"${SUDO_USER:-<user>}\" ping heise.de"
echo
echo -n "Warning: Ensure that all programs you start are actually performing "
echo -n "network operations inside the network namespace. For example, if you "
echo -n "use Firefox and a Firefox instance is already running outside the "
echo -n "network namespace, the new instance will also be running outside it. "
echo -n "You can easily check if traffic is limited to the VPN interface by "
echo "disabling the VPN and trying to use the application."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment