Last active
December 1, 2024 07:52
-
-
Save Ghosthree3/21323ece7b5461eb634fdee3d3530b01 to your computer and use it in GitHub Desktop.
Script for setting up locked down Network Namespaces with a different VPN in each
This file contains hidden or 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
#!/usr/bin/env bash | |
set -o pipefail | |
# This script sets up an additional network namespace for every VPN you wish so that you may | |
# use any VPN at any time for any program without tunneling everything else on your system. | |
# Usage: | |
# Review and edit every line of this script not in a function, then run it as root | |
# on system startup (yes every reboot), eg. crontab @reboot /root/bin/vpnns.sh | |
# It is recommended that you run this script manually at least once as you will | |
# more easily discover the reason for any failures. | |
# Don't rerun for the same VPNs without either undoing its work | |
# or rebooting, as it will likely create a lot of mess. | |
if [[ $EUID -ne 0 ]]; then | |
echo "This must be run as root." | |
exit 1 | |
fi | |
# This script uses nftables, so if you are currently using iptables, or an iptables wrapper, | |
# it is suggested you convert all the nft rules into iptables ones, or simply upgrade to nftables. | |
# This script assumes you have an inet filter table with an input chain, and an | |
# ip nat table with a postrouting chain already set up in nftables on your system. | |
# If this is not the case uncomment the four lines below. | |
#nft add table inet filter | |
#nft add chain inet filter input { type filter hook input priority 0 \; policy accept \; } | |
#nft add table ip nat | |
#nft add chain ip nat postrouting { type nat hook postrouting priority 0 \; policy accept \; } | |
# If you already have veth devices on your system, set this to the next in line. | |
# ie. If you already have veth0 and veth1, set veth_count to 2. | |
veth_count=0 | |
# This is the starting point for the third octet in the subnets we'll be using (10.154.?.0/24). | |
# If this is set to 101 the first subnet used will be 10.154.101.0/24, then 10.154.102.0/24, etc. | |
oct3=101 | |
# This dir will be used to store the current and previous log for all the OpenVPN instances. | |
log_dir=/etc/openvpn/logs/ | |
if [[ ! -d $log_dir ]]; then | |
mkdir -p $log_dir | |
fi | |
# Call with create_namespace openvpn_config_filename [vpn_server_ip] | |
# If vpn_server_ip is not provided then the script will attempt to guess it. | |
create_namespace () { | |
veths=($((veth_count++)) $((veth_count++))) | |
if [[ -z ${2} ]]; then | |
remote_ip=$(grep '^remote ' /etc/openvpn/client/${1}.conf | cut -d' ' -f2 || \ | |
echo "Could not resolve the server IP for /etc/openvpn/client/${1}.conf" ; exit 1) | |
else | |
remote_ip=${2} | |
fi | |
ip netns add ${1} | |
ip netns exec ${1} ip addr add 127.0.0.1/8 dev lo | |
ip netns exec ${1} ip link set lo up | |
ip link add veth${veths[0]} type veth peer name veth${veths[1]} | |
ip link set veth${veths[0]} up | |
ip link set veth${veths[1]} netns ${1} up | |
ip addr add 10.154.${oct3}.1/24 dev veth${veths[0]} | |
ip netns exec ${1} ip addr add 10.154.${oct3}.2/24 dev veth${veths[1]} | |
ip netns exec ${1} ip route add default via 10.154.${oct3}.1 dev veth${veths[1]} | |
ip netns exec ${1} ip route add 192.168.0.0/16 via 10.154.${oct3}.1 | |
nft add rule inet filter input iifname != veth${veths[0]} ip saddr 10.154.${oct3}.0/24 drop | |
nft add rule ip nat postrouting oifname != veth${veths[0]} ip saddr 10.154.${oct3}.0/24 masquerade | |
ip netns exec ${1} bash -c "\ | |
nft add table inet filter && \ | |
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; } && \ | |
nft add chain inet filter output { type filter hook output priority 0 \; policy drop \; } && \ | |
nft add rule inet filter input iifname tun0 accept && \ | |
nft add rule inet filter output oifname tun0 accept && \ | |
nft add rule inet filter input iifname veth${veths[1]} ip saddr 192.168.0.0/16 accept && \ | |
nft add rule inet filter output oifname veth${veths[1]} ip daddr 192.168.0.0/16 accept && \ | |
nft add rule inet filter input iifname veth${veths[1]} ip saddr ${remote_ip} accept && \ | |
nft add rule inet filter output oifname veth${veths[1]} ip daddr ${remote_ip} accept" | |
mkdir -p /etc/netns/${1} | |
cat << 'EOF' > /etc/netns/${1}/resolv.conf | |
# OpenDNS IPv4 nameservers | |
nameserver 208.67.222.222 | |
nameserver 208.67.220.220 | |
EOF | |
mv ${log_dir}/${1}.log ${log_dir}/${1}.log.old | |
ip netns exec ${1} openvpn --log ${log_dir}/${1}.log --config /etc/openvpn/client/${1}.conf & | |
((oct3++)) | |
} | |
# Call with create_binary /path/to/binary | |
create_binary () { | |
if [[ ! -d $(dirname "$1") ]]; then | |
(umask 022 && mkdir -p $(dirname "$1")) | |
fi | |
cat << 'EOF' > "$1" | |
#!/usr/bin/env bash | |
if [[ $EUID -ne 0 ]]; then | |
sudo "$0" "$@" | |
exit $? | |
fi | |
ip netns exec $1 sudo -u $SUDO_USER PULSE_SERVER=unix:/run/user/$SUDO_UID/pulse/native "${@:2}" | |
EOF | |
chmod 755 "$1" | |
} | |
#create_namespace vpn1 | |
#create_namespace vpn2 | |
#create_namespace vpn3 vpn3.server.ip.addr | |
# Uncomment the final line if you wish to have a 'binary' created to more easily use your VPNs. | |
# Usage: Prefix any command you wish to run with 'vpn openvpn_config_filename' and the program | |
# will be opened in that namespace instead of the system default, tunneling all its traffic. | |
# The line 'youruser ALL=(root) NOPASSWD: /path/to/binary' can be added to sudoers to avoid | |
# the requirement of a password every time you open a program, this shouldn't be a security | |
# concern (read the 'binary' script). | |
#create_binary /usr/local/bin/vpn |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment