Last active
January 2, 2025 16:34
-
-
Save kriswebdev/c19e103bd69c994a1c16ced004908c76 to your computer and use it in GitHub Desktop.
Revisions
-
kriswebdev revised this gist
Jan 2, 2022 . No changes.There are no files selected for viewing
-
kriswebdev revised this gist
Dec 22, 2019 . 1 changed file with 94 additions and 33 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -5,7 +5,7 @@ # Description: Force VPN tunnel for specific applications. # If the VPN is down => blackhole the app network traffic. # Better than a killswitch. IPv4. VERSION="2.3.0" # Author: KrisWebDev # Requirements: Linux with kernel > 2.6.4 (released in 2008). # This version is only tested on Ubuntu 19.10 with bash. @@ -78,6 +78,8 @@ vpn_interface_gateway=`ip route | grep "dev ${vpn_interface}" | awk '/^default/ action="command" background=false skip=false allow_localhost=false disable_localhost=false init_nb_args="$#" sudok=false @@ -88,6 +90,9 @@ while [ "$#" -gt 0 ]; do -u|--unbind) action="unbind"; shift 1;; -l|--list) action="list"; shift 1;; -s|--skip) skip=true; shift 1;; -L|--localhost) allow_localhost=true; shift 1;; -P|--no-localhost) disable_localhost=true; shift 1;; -I|--info) action="info"; shift 1;; -c|--clean) action="clean"; shift 1;; --conf-restart) action="conf-restart"; shift 1;; -h|--help) action="help"; shift 1;; @@ -100,17 +105,20 @@ done if [ "$init_nb_args" -lt 1 ] || [ "$action" = "help" ] ; then me=`basename "$0"` echo -e "Usage : \e[1m$me [\e[4mOPTIONS\e[24m] \e[4mCOMMAND\e[24m [\e[4mCOMMAND PARAMETERS\e[24m]\e[0m" echo -e " or : \e[1m$me [\e[4mOPTIONS\e[24m] { --bind | --unbind } \e[4mLIST\e[24m\e[0m" echo -e "Force (bind) program \e[4mCOMMAND\e[24m inside the VPN tunnel interface." echo echo -e "\e[1m\e[4mOPTIONS\e[0m:" echo -e "\e[1m-b, --background\e[0m Start \e[4mCOMMAND\e[24m as background process (release the shell)." echo -e "\e[1m-i, --bind \e[4mLIST\e[24m\e[0m Force (bind) running process \e[4mLIST\e[24m inside tunnel. \e[1mBROKEN!\e[0m" echo -e "\e[1m-u, --unbind \e[4mLIST\e[24m\e[0m Cancel force bind for running process \e[4mLIST\e[24m." echo -e "\e[1m-l, --list\e[0m List processes binded inside tunnel." echo -e "\e[1m-s, --skip\e[0m Don't setup system config & don't ask for root;\n just perform public routing test and run \e[4mCOMMAND\e[24m." echo -e "\e[1m-L, --localhost\e[0m Add rule to allow traffic with localhost (disabled by default)." echo -e "\e[1m-P, --no-localhost\e[0m Remove rule to allow traffic with localhost." echo -e "\e[1m-l, --list\e[0m List processes binded inside tunnel." echo -e "\e[1m-I, --info\e[0m Display debug information and exit." echo -e "\e[1m-c, --clean\e[0m Move back all proceses to initial routing settings and remove system config." echo -e "\e[1m-v, --version\e[0m Print this program version." echo -e "\e[1m-h, --help\e[0m This help." @@ -119,6 +127,27 @@ if [ "$init_nb_args" -lt 1 ] || [ "$action" = "help" ] ; then exit 1 fi # This program can't ask for root outside terminal if [ ! -t 1 ] && [ "$(id -u)" -ne 0 ]; then skip=true fi if [ "$allow_localhost" = true ] && [ "$disable_localhost" = true ]; then echo -e "\e[31mCan't use --localhost with --no-localhost. Aborting.\e[0m" >&2 exit 1 fi if [ "$skip" = true ]; then if [ "$allow_localhost" = true ] || [ "$disable_localhost" = true ]; then echo -e "\e[33mWARNING: Ignoring localhost traffic setup options as --skip option is enabled.\e[0m" >&2 fi if [ "$action" = "clean" ]; then echo -e "\e[31mCan't use --skip with --clean. Aborting.\e[0m" >&2 exit 1 fi fi # Helper functions # Check the presence of required system packages @@ -163,30 +192,47 @@ list_bind(){ iptable_checked=false setup_iptables(){ if ! sudo iptables -C OUTPUT -m cgroup --cgroup "$net_cls_classid" -j "$iptables_rule_set_name" 2>/dev/null; then echo "Adding iptables rule to drop packets with class identifier $net_cls_classid not exiting through ${vpn_interface} or locally (DNS)" >&2 sudo iptables -N "$iptables_rule_set_name" # Moved to Networkmanager dispatcher script for better security #if [ "$allow_localhost" = true ]; then # sudo iptables -I "$iptables_rule_set_name" -o lo -j RETURN #fi # Bad alternative that leads to massive quick retries hence CPU load: -j REJECT --reject-with icmp-net-prohibited sudo iptables -A "$iptables_rule_set_name" ! -o "$vpn_interface" -j DROP sudo iptables -I OUTPUT -m cgroup --cgroup "$net_cls_classid" -j "$iptables_rule_set_name" fi iptable_checked=true } setup_iptables_localhost(){ if ! sudo iptables -C "$iptables_rule_set_name" -d "127.0.0.1" -j ACCEPT 2>/dev/null; then if [ "$allow_localhost" = true ]; then echo "Adding iptables rule to allow localhost trafic" >&2 sudo iptables -I "$iptables_rule_set_name" -d "127.0.0.1" -j ACCEPT fi elif [ "$disable_localhost" = true ]; then echo "Adding iptables rule to allow localhost trafic" >&2 sudo iptables -D "$iptables_rule_set_name" -d "127.0.0.1" -j ACCEPT fi iptable_checked=true } # Test if config is working, IPv4 only testresult=true test_routing(){ exit_ip="$(cgexec -g net_cls:"$cgroup_name" traceroute -n -m 1 8.8.8.8 | sed -n '2{p;q}' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)" if [ -z "$exit_ip" ]; then # Old traceroute exit_ip="$(cgexec -g net_cls:"$cgroup_name" traceroute -m 1 8.8.8.8 | sed -n '2{p;q}' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)" if [ -z "$exit_ip" ]; then echo -e "\e[31mTest failed: Unable to determine source exit IP (found \"$exit_ip\").\e[0m" >&2 if [ "$skip" = true ]; then echo -e "\e[31mYou should remove --skip option to perform setup.\e[0m" >&2 fi testresult=false return 0 fi @@ -196,49 +242,60 @@ test_forced(){ testresult=false return 0 fi ping6 -t 1 -c 1 -n 2001:4860:4860::8888 2>/dev/null retcode=$? if [ "$retcode" -ne 2 ]; then echo -e "\e[31mTest failed: IPv6 is not disabled or unable to test.\e[0m" >&2 fi if [ "$exit_ip" == "$vpn_interface_gateway" ]; then echo -e "\e[32mTest OK. Trafic exits with IP \"$exit_ip\".\e[0m" >&2 testresult=true return 0 else echo -e "\e[31mTest failed: Trafic exits with \"$exit_ip\" instead of \"$vpn_interface_gateway\". Aborting.\e[0m" >&2 testresult=false return 1 fi } # Reconfigure routing reroute(){ if [ -z "$vpn_interface_gateway" ]; then echo -e "\e[31mCan't find default gateway of VPN interface \"${vpn_interface}\". Is it up?\e[0m" >&2 echo -e "\e[31mAborting.\e[0m" >&2 exit 1 fi if [ "$skip" = false ]; then if [ -z "`lscgroup net_cls:$cgroup_name`" ] || [ `stat -c "%U" /sys/fs/cgroup/net_cls/${cgroup_name}/tasks` != "$USER" ]; then echo "Creating cgroup net_cls:${cgroup_name}. User $USER will be able to move tasks in it without root permissions." >&2 sudo cgcreate -t "$USER":"$USER" -a `id -g -n "$USER"`:`id -g -n "$USER"` -g net_cls:"$cgroup_name" check_iptables=true fi if [ "$check_iptables" = true ]; then setup_iptables fi if [ "$allow_localhost" = true ] || [ "$disable_localhost" = true ]; then setup_iptables_localhost fi echo "Disabling IPv6 (not supported/implemented)" sudo ip -6 route add blackhole default metric 1 echo 1 | sudo tee "/proc/sys/net/ipv6/conf/lo/disable_ipv6" > /dev/null echo 1 | sudo tee "/proc/sys/net/ipv6/conf/all/disable_ipv6" > /dev/null echo 1 | sudo tee "/proc/sys/net/ipv6/conf/default/disable_ipv6" > /dev/null fi # TEST test_routing if [ "$skip" = false ]; then if [ "$testresult" = false ]; then if [ "$iptable_checked" = false ] && [ "$skip" = false ]; then echo -e "Trying to setup iptables and redo test..." >&2 setup_iptables test_routing fi fi if [ "$testresult" = false ]; then @@ -371,6 +428,12 @@ elif [ "$action" = "unbind" ]; then list_bind # INFO elif [ "$action" = "info" ]; then echo -e "\e[2msudo iptables -L -v --line-numbers\e[0m" sudo iptables -L -v --line-numbers # CLEAN the mess elif [ "$action" = "clean" ]; then echo -e "Cleaning forced routing config generated by this script." @@ -409,7 +472,5 @@ fi # BONUS: Useful commands: # ./forcevpn.sh ping 8.8.8.8 # ./forcevpn.sh --localhost --background biglybt # killall firefox; ./forcevpn.sh --background firefox -
kriswebdev revised this gist
Nov 11, 2019 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -11,6 +11,7 @@ VERSION="2.2.0" # This version is only tested on Ubuntu 19.10 with bash. # Main dependencies are automatically installed. # Script will guide you for iptables 1.6.0 install if needed. # Note: This script will disable IPv6 (enable with --clean) # dnsmasq users: You're usinq dnsmasq if you find "dns=dsnmasq" in /etc/NetworkManager/NetworkManager.conf # gksudo gedit /etc/NetworkManager/dispatcher.d/forcevpn-dispatcher.sh @@ -229,7 +230,6 @@ reroute(){ echo 1 | sudo tee "/proc/sys/net/ipv6/conf/lo/disable_ipv6" > /dev/null echo 1 | sudo tee "/proc/sys/net/ipv6/conf/all/disable_ipv6" > /dev/null echo 1 | sudo tee "/proc/sys/net/ipv6/conf/default/disable_ipv6" > /dev/null # TEST forced bind test_forced -
kriswebdev revised this gist
Nov 11, 2019 . 1 changed file with 52 additions and 20 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -3,23 +3,22 @@ # === INFO === # ForceVPN # Description: Force VPN tunnel for specific applications. # If the VPN is down => blackhole the app network traffic. # Better than a killswitch. IPv4. VERSION="2.2.0" # Author: KrisWebDev # Requirements: Linux with kernel > 2.6.4 (released in 2008). # This version is only tested on Ubuntu 19.10 with bash. # Main dependencies are automatically installed. # Script will guide you for iptables 1.6.0 install if needed. # dnsmasq users: You're usinq dnsmasq if you find "dns=dsnmasq" in /etc/NetworkManager/NetworkManager.conf # gksudo gedit /etc/NetworkManager/dispatcher.d/forcevpn-dispatcher.sh # Insert content of below commented script # sudo chmod +x /etc/NetworkManager/dispatcher.d/forcevpn-dispatcher.sh # See for more info: http://askubuntu.com/a/703665/263353 # Change uint32 value with your VPN provider DNS server IP converted to Integer: # http://www.aboutmyip.com/AboutMyXApp/IP2Integer.jsp : ' #!/bin/bash @@ -79,6 +78,7 @@ action="command" background=false skip=false init_nb_args="$#" sudok=false while [ "$#" -gt 0 ]; do case "$1" in @@ -91,6 +91,7 @@ while [ "$#" -gt 0 ]; do --conf-restart) action="conf-restart"; shift 1;; -h|--help) action="help"; shift 1;; -v|--version) echo "forcevpn v$VERSION"; exit 0;; --sudok) sudok=true; shift 1;; -*) echo "Unknown option: $1. Try --help." >&2; exit 1;; *) break;; # Start of COMMAND or LIST esac @@ -120,11 +121,11 @@ fi # Helper functions # Check the presence of required system packages check_install_package(){ nothing_installed=1 for package_name in "$@" do if ! dpkg -s "$package_name" &> /dev/null; then echo "Installing $package_name" sudo apt-get install "$package_name" nothing_installed=0 @@ -133,6 +134,18 @@ check_package(){ return $nothing_installed } check_package(){ for package_name in "$@" do if ! dpkg -s "$package_name" &> /dev/null; then #echo "Installing $package_name" #sudo apt-get install "$package_name" return 0 fi done return 1 } # List processes binded to the VPN tunnel list_bind(){ return_status=1 @@ -167,13 +180,27 @@ setup_iptables(){ # Test if config is working, IPv4 only testresult=true test_forced(){ exit_ip="$(cgexec -g net_cls:"$cgroup_name" traceroute -n -m 1 8.8.8.8 | sed -n '2{p;q}' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)" if [ -z "$exit_ip" ]; then # Old traceroute exit_ip="$(cgexec -g net_cls:"$cgroup_name" traceroute -m 1 8.8.8.8 | sed -n '2{p;q}' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)" if [ -z "$exit_ip" ]; then echo -e "\e[31mTest failed: Unable to determine source exit IP (found \"$exit_ip\").\e[0m" >&2 testresult=false return 0 fi fi if [ -z "$vpn_interface_gateway" ]; then echo -e "\e[31mTest failed: Unable to determine VPN interface gateway IP (found \"$vpn_interface_gateway\").\e[0m" >&2 testresult=false return 0 fi if [ "$exit_ip" == "$vpn_interface_gateway" ]; then echo -e "\e[32mTest OK. Trafic exits with IP \"$exit_ip\".\e[0m" >&2 testresult=true return 0 else echo -e "\e[31mTest failed: Trafic exits with \"$exit_ip\" instead of \"$vpn_interface_gateway\".\e[0m" >&2 testresult=false return 1 fi @@ -197,11 +224,12 @@ reroute(){ setup_iptables fi echo "Disabling IPv6 (not supported/implemented)" sudo ip -6 route add blackhole default metric 1 echo 1 | sudo tee "/proc/sys/net/ipv6/conf/lo/disable_ipv6" > /dev/null echo 1 | sudo tee "/proc/sys/net/ipv6/conf/all/disable_ipv6" > /dev/null echo 1 | sudo tee "/proc/sys/net/ipv6/conf/default/disable_ipv6" > /dev/null # TEST forced bind test_forced @@ -229,12 +257,15 @@ if [ "$action" = "command" ] || [ "$action" = "bind" ]; then if [ "$skip" = false ]; then echo "Checking/setting forced routing config (skip with $0 -s ...)" >&2 if check_install_package cgroup-lite traceroute cgroup-tools; then if check_package cgroup-lite traceroute cgroup-tools; then echo "Required packages not properly installed. Aborting." >&2 exit 1 fi fi iptables_version=$(iptables --version | grep -oP "iptables v\K[0-9.]+") if dpkg --compare-versions "$iptables_version" "lt" "1.6"; then echo -e "\e[31mYou need iptables 1.6.0+. Please install manually. Aborting.\e[0m" >&2 echo "Find latest iptables at http://www.netfilter.org/projects/iptables/downloads.html" >&2 echo "Commands to install iptables 1.6.0:" >&2 @@ -271,6 +302,9 @@ fi # RUN command if [ "$action" = "command" ]; then if [ "$sudok" = true ]; then sudo -K fi if [ "$#" -eq 0 ]; then echo "Error: COMMAND not provided." >&2 exit 1 @@ -378,6 +412,4 @@ fi # ./forcevpn.sh --bind ping # ./forcevpn.sh vuze # ./forcevpn.sh --bind java # ./forcevpn.sh --background vuze -
kriswebdev revised this gist
Aug 25, 2018 . 1 changed file with 18 additions and 6 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -3,9 +3,9 @@ # === INFO === # ForceVPN # Description: Force VPN tunnel for specific applications. # If the VPN is down => block the app network traffic. # Better than a killswitch. IPv4. VERSION="2.1.0" # Author: KrisWebDev # Requirements: Linux with kernel > 2.6.4 (released in 2008). # Only tested on Ubuntu 16 with bash. @@ -15,8 +15,11 @@ VERSION="2.0.0" # gksudo gedit /etc/NetworkManager/dispatcher.d/forcevpn-dispatcher.sh # Insert content of below commented script # sudo chmod +x /etc/NetworkManager/dispatcher.d/forcevpn-dispatcher.sh # See for more info: http://askubuntu.com/a/703665/263353 # Change uint32 value with your VPN provider DNS server IP converted to Integer: # http://www.aboutmyip.com/AboutMyXApp/IP2Integer.jsp # Note: This script will disable IPv6 (enable with --clean) : ' #!/bin/bash @@ -84,7 +87,7 @@ while [ "$#" -gt 0 ]; do -u|--unbind) action="unbind"; shift 1;; -l|--list) action="list"; shift 1;; -s|--skip) skip=true; shift 1;; -c|--clean) action="clean"; shift 1;; --conf-restart) action="conf-restart"; shift 1;; -h|--help) action="help"; shift 1;; -v|--version) echo "forcevpn v$VERSION"; exit 0;; @@ -164,7 +167,7 @@ setup_iptables(){ # Test if config is working, IPv4 only testresult=true test_forced(){ exit_ip=`cgexec -g net_cls:"$cgroup_name" traceroute -m 1 8.8.8.8 | sed -n '2{p;q}' | grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"` if [ "$exit_ip" == "$vpn_interface_gateway" ]; then echo -e "\e[32mTest OK. Trafic exits with IP $exit_ip.\e[0m" >&2 testresult=true @@ -194,6 +197,11 @@ reroute(){ setup_iptables fi sudo ip -6 route add blackhole default metric 1 echo 1 | sudo tee "/proc/sys/net/ipv6/conf/lo/disable_ipv6" > /dev/null echo 1 | sudo tee "/proc/sys/net/ipv6/conf/all/disable_ipv6" > /dev/null echo 1 | sudo tee "/proc/sys/net/ipv6/conf/default/disable_ipv6" > /dev/null # TEST forced bind test_forced @@ -348,6 +356,10 @@ elif [ "$action" = "clean" ]; then sudo iptables -D OUTPUT -m cgroup --cgroup "$net_cls_classid" -j "$iptables_rule_set_name" sudo iptables -F "$iptables_rule_set_name" sudo iptables -X "$iptables_rule_set_name" echo 1 | sudo tee "/proc/sys/net/ipv6/conf/lo/disable_ipv6" > /dev/null echo 1 | sudo tee "/proc/sys/net/ipv6/conf/all/disable_ipv6" > /dev/null echo 1 | sudo tee "/proc/sys/net/ipv6/conf/default/disable_ipv6" > /dev/null if [ -n "`lscgroup net_cls:$cgroup_name`" ]; then sudo cgdelete net_cls:"$cgroup_name" -
kriswebdev revised this gist
Jul 2, 2016 . 1 changed file with 51 additions and 21 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -5,12 +5,45 @@ # Description: Force VPN tunnel for specific applications. # If the VPN is down => blackhole the app network traffic. # Better than a killswitch. IPv4. VERSION="2.0.0" # Author: KrisWebDev # Requirements: Linux with kernel > 2.6.4 (released in 2008). # Only tested on Ubuntu 16 with bash. # Main dependencies are automatically installed. # Script will guide you for iptables 1.6.0 install. # dnsmasq users: You're usinq dnsmasq if you find "dns=dsnmasq" in /etc/networkManager/NetworkManager.conf # gksudo gedit /etc/NetworkManager/dispatcher.d/forcevpn-dispatcher.sh # Insert content of below commented script # sudo chmod +x /etc/NetworkManager/dispatcher.d/forcevpn-dispatcher.sh # See: http://askubuntu.com/a/703665/263353 # Change uint32 value with your DNS server IP converted to Integer: http://www.aboutmyip.com/AboutMyXApp/IP2Integer.jsp : ' #!/bin/bash interface=$1 status=$2 case $status in vpn-up) # because dnsmasq keep DNS LAN and leak our DNS, hard-code DNS servers dbus-send --system --dest=org.freedesktop.NetworkManager.dnsmasq --type=method_call /uk/org/thekelleys/dnsmasq uk.org.thekelleys.SetServers dbus-send --system --dest=org.freedesktop.NetworkManager.dnsmasq --type=method_call /uk/org/thekelleys/dnsmasq uk.org.thekelleys.SetServers uint32:3250021018 dbus-send --system --dest=org.freedesktop.NetworkManager.dnsmasq --type=method_call /uk/org/thekelleys/dnsmasq uk.org.thekelleys.SetServers uint32:3112519796 # flush DNS cache pkill --signal SIGHUP dnsmasq # provide access to dnsmasq when vpn is up iptables -N forcevpn_rule_set iptables -I forcevpn_rule_set -o lo -p udp --dport 53 -j RETURN ;; vpn-down) # flush DNS cache pkill --signal SIGHUP dnsmasq # deny access to dnsmasq when vpn is down iptables -D forcevpn_rule_set -o lo -p udp --dport 53 -j RETURN ;; esac ' # === LICENSE === # This program is free software: you can redistribute it and/or modify @@ -31,14 +64,8 @@ vpn_interface="tun0" # === ADVANCED CONFIGURATION === cgroup_name="forcevpn" # Better keep it with purely lowercase alphabetic & underscore iptables_rule_set_name="${cgroup_name}_rule_set" net_cls_classid="0x00220022" # Anything from 0x00000001 to 0xFFFFFFFF # === CODE === vpn_interface_gateway=`ip route | grep "dev ${vpn_interface}" | awk '/^default/ { print $3 }'` @@ -118,9 +145,18 @@ list_bind(){ # Check and setup iptables - requires root even for check iptable_checked=false setup_iptables(){ if ! sudo iptables -C OUTPUT -m cgroup --cgroup "$net_cls_classid" -j "$iptables_rule_set_name" 2>/dev/null; then echo "Adding iptables rule drop packets with class identifier $net_cls_classid not exiting through ${vpn_interface} or locally (DNS)" >&2 sudo iptables -N "$iptables_rule_set_name" # Moved to Networkmanager dispatcher script for better security #if [ "$allow_localhost" = true ]; then # sudo iptables -I "$iptables_rule_set_name" -o lo -j RETURN #fi # Bad alternative that leads to massive quick retries hence CPU load: -j REJECT --reject-with icmp-net-prohibited sudo iptables -A "$iptables_rule_set_name" ! -o "$vpn_interface" -j DROP sudo iptables -I OUTPUT -m cgroup --cgroup "$net_cls_classid" -j "$iptables_rule_set_name" fi iptable_checked=true } @@ -218,7 +254,6 @@ iptables --version\e[0m" >&2 echo "Applying net_cls class identifier $net_cls_classid to cgroup $cgroup_name" >&2 echo "$net_cls_classid" | sudo tee "/sys/fs/cgroup/net_cls/$cgroup_name/net_cls.classid" > /dev/null fi fi if [ "$action" = "command" ]; then @@ -309,15 +344,10 @@ elif [ "$action" = "clean" ]; then sudo find "/sys/fs/cgroup/net_cls/${cgroup_name}" -depth -type d -print -exec rmdir {} \; fi # Debug: sudo iptables -L -v sudo iptables -D OUTPUT -m cgroup --cgroup "$net_cls_classid" -j "$iptables_rule_set_name" sudo iptables -F "$iptables_rule_set_name" sudo iptables -X "$iptables_rule_set_name" if [ -n "`lscgroup net_cls:$cgroup_name`" ]; then sudo cgdelete net_cls:"$cgroup_name" -
kriswebdev revised this gist
Jun 23, 2016 . 1 changed file with 13 additions and 12 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -5,7 +5,7 @@ # Description: Force VPN tunnel for specific applications. # If the VPN is down => blackhole the app network traffic. # Better than a killswitch. IPv4. VERSION="1.2.0" # Author: KrisWebDev # Requirements: Linux with kernel > 2.6.4 (released in 2008). # Only tested on Ubuntu 16 with bash. @@ -53,8 +53,8 @@ init_nb_args="$#" while [ "$#" -gt 0 ]; do case "$1" in -b|--background) background=true; shift 1;; -i|--bind) action="bind"; shift 1;; -u|--unbind) action="unbind"; shift 1;; -l|--list) action="list"; shift 1;; -s|--skip) skip=true; shift 1;; -l|--clean) action="clean"; shift 1;; @@ -69,13 +69,13 @@ done if [ "$init_nb_args" -lt 1 ] || [ "$action" = "help" ] ; then me=`basename "$0"` echo -e "Usage : \e[1m$me [\e[4mOPTIONS\e[24m] [\e[4mCOMMAND\e[24m [\e[4mCOMMAND PARAMETERS\e[24m]]\e[0m" echo -e " or : \e[1m$me [\e[4mOPTIONS\e[24m] { --bind | --unbind } \e[4mLIST\e[24m\e[0m" echo -e "Force (bind) program inside the VPN tunnel." echo echo -e "\e[1m\e[4mOPTIONS\e[0m:" echo -e "\e[1m-b, --background\e[0m Start \e[4mCOMMAND\e[24m as background process (release the shell)." echo -e "\e[1m-i, --bind \e[4mLIST\e[24m\e[0m Force (bind) running process \e[4mLIST\e[24m inside tunnel." echo -e "\e[1m-u, --unbind \e[4mLIST\e[24m\e[0m Cancel force bind for running process \e[4mLIST\e[24m." echo -e "\e[1m-l, --list\e[0m List processes binded inside tunnel." echo -e "\e[1m-s, --skip\e[0m Don't check/setup system config & don't ask for root,\n\ run \e[4mCOMMAND\e[24m or move process \e[4mLIST\e[24m even if tunnel bind fails." @@ -118,9 +118,9 @@ list_bind(){ # Check and setup iptables - requires root even for check iptable_checked=false setup_iptables(){ if ! sudo iptables -C OUTPUT -m cgroup --cgroup "0x00220022" \! -o tun0 -j DROP 2>/dev/null; then echo "Adding iptables MANGLE rule to set firewall mark $ip_table_fwmark on packets with class identifier $net_cls_classid" >&2 sudo iptables -A OUTPUT -m cgroup --cgroup "0x00220022" \! -o tun0 -j DROP 2>/dev/null fi iptable_checked=true } @@ -150,7 +150,7 @@ reroute(){ fi if [ -z "`lscgroup net_cls:$cgroup_name`" ] || [ `stat -c "%U" /sys/fs/cgroup/net_cls/${cgroup_name}/tasks` != "$USER" ]; then echo "Creating cgroup net_cls:${cgroup_name}. User $USER will be able to move tasks in it without root permissions." >&2 sudo cgcreate -t "$USER":"$USER" -a `id -g -n "$USER"`:`id -g -n "$USER"` -g net_cls:"$cgroup_name" check_iptables=true fi @@ -233,10 +233,10 @@ if [ "$action" = "command" ]; then exit 1 fi if [ "$background" = true ]; then cgexec -g net_cls:"$cgroup_name" --sticky "$@" &>/dev/null & exit 0 else cgexec -g net_cls:"$cgroup_name" --sticky "$@" exit $? fi @@ -309,7 +309,8 @@ elif [ "$action" = "clean" ]; then sudo find "/sys/fs/cgroup/net_cls/${cgroup_name}" -depth -type d -print -exec rmdir {} \; fi # Bad alternative that leads to massive quick retries hence CPU load: -j REJECT --reject-with icmp-net-prohibited sudo iptables -D OUTPUT -m cgroup --cgroup "$net_cls_classid" \! -o tun0 -j DROP sudo ip rule del fwmark "$ip_table_fwmark" table "$ip_table_name" sudo ip route del default table "$ip_table_name" -
kriswebdev revised this gist
Jun 18, 2016 . 1 changed file with 4 additions and 52 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -5,17 +5,12 @@ # Description: Force VPN tunnel for specific applications. # If the VPN is down => blackhole the app network traffic. # Better than a killswitch. IPv4. VERSION="1.1.0" # Author: KrisWebDev # Requirements: Linux with kernel > 2.6.4 (released in 2008). # Only tested on Ubuntu 16 with bash. # Main dependencies are automatically installed. # Script will guide you for iptables 1.6.0 install. # === LICENSE === # This program is free software: you can redistribute it and/or modify @@ -123,13 +118,9 @@ list_bind(){ # Check and setup iptables - requires root even for check iptable_checked=false setup_iptables(){ if ! sudo iptables -C OUTPUT -m cgroup --cgroup "0x00220022" \! -o tun0 -j REJECT 2>/dev/null; then echo "Adding iptables MANGLE rule to set firewall mark $ip_table_fwmark on packets with class identifier $net_cls_classid" >&2 sudo iptables -A OUTPUT -m cgroup --cgroup "0x00220022" \! -o tun0 -j REJECT --reject-with icmp-net-prohibited 2>/dev/null fi iptable_checked=true } @@ -158,44 +149,6 @@ reroute(){ exit 1 fi if [ -z "`lscgroup net_cls:$cgroup_name`" ] || [ `stat -c "%U" /sys/fs/cgroup/net_cls/${cgroup_name}/tasks` != "$USER" ]; then echo "Creating cgroup net_cls:${cgroup_name}. User $USER will be able to move tasks to it without root permissions." >&2 sudo cgcreate -t "$USER":"$USER" -a `id -g -n "$USER"`:`id -g -n "$USER"` -g net_cls:"$cgroup_name" @@ -356,8 +309,7 @@ elif [ "$action" = "clean" ]; then sudo find "/sys/fs/cgroup/net_cls/${cgroup_name}" -depth -type d -print -exec rmdir {} \; fi sudo iptables -D OUTPUT -m cgroup --cgroup "$net_cls_classid" \! -o tun0 -j REJECT --reject-with icmp-net-prohibited sudo ip rule del fwmark "$ip_table_fwmark" table "$ip_table_name" sudo ip route del default table "$ip_table_name" -
kriswebdev created this gist
Jun 18, 2016 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,388 @@ #!/bin/bash # === INFO === # ForceVPN # Description: Force VPN tunnel for specific applications. # If the VPN is down => blackhole the app network traffic. # Better than a killswitch. IPv4. VERSION="1.0.0" # Author: KrisWebDev # Requirements: Linux with kernel > 2.6.4 (released in 2008). # Only tested on Ubuntu 16 with bash. # Main dependencies are automatically installed. # Script will guide you for iptables 1.6.0 install. # Tip: Add these lines to /etc/network/interfaces # to route the app again when the interface is restarted: # auto tun0 # iface tun0 inet manual # post-up ip route add default via `ip route | grep "dev tun0" | awk '/^default/ { print $3 }'` dev tun0 table forcevpn # === LICENSE === # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # === CONFIGURATION === vpn_interface="tun0" # === ADVANCED CONFIGURATION === cgroup_name="forcevpn" # Better keep it with purely lowercase alphabetic & underscore net_cls_classid="0x00220022" # Anything from 0x00000001 to 0xFFFFFFFF ip_table_fwmark="22" # Anything from 1 to 2147483647 ip_table_number="22" # Anything from 1 to 252 ip_table_name="$cgroup_name" ip_rule_priority="30022" # Anything from 1 to 32764, with the next rule free. See "ip rule list". ip_table_number_blackhole="66" # Anything from 1 to 252 ip_table_name_blackhole="blackhole" ip_rule_priority_blackhole=$((ip_rule_priority+1)) # === CODE === vpn_interface_gateway=`ip route | grep "dev ${vpn_interface}" | awk '/^default/ { print $3 }'` #vpn_interface_ip=`ip addr show "$vpn_interface" | awk '$1 == "inet" {gsub(/\/.*$/, "", $2); print $2}'` # Handle options action="command" background=false skip=false init_nb_args="$#" while [ "$#" -gt 0 ]; do case "$1" in -b|--background) background=true; shift 1;; -o|--bind) action="bind"; shift 1;; -i|--unbind) action="unbind"; shift 1;; -l|--list) action="list"; shift 1;; -s|--skip) skip=true; shift 1;; -l|--clean) action="clean"; shift 1;; --conf-restart) action="conf-restart"; shift 1;; -h|--help) action="help"; shift 1;; -v|--version) echo "forcevpn v$VERSION"; exit 0;; -*) echo "Unknown option: $1. Try --help." >&2; exit 1;; *) break;; # Start of COMMAND or LIST esac done if [ "$init_nb_args" -lt 1 ] || [ "$action" = "help" ] ; then me=`basename "$0"` echo -e "Usage : \e[1m$me [\e[4mOPTIONS\e[24m] [\e[4mCOMMAND\e[24m [\e[4mCOMMAND PARAMETERS\e[24m]]\e[0m" echo -e " or : \e[1m$me [\e[4mOPTIONS\e[24m] { --inside | --outside } \e[4mLIST\e[24m\e[0m" echo -e "Force (bind) program inside the VPN tunnel." echo echo -e "\e[1m\e[4mOPTIONS\e[0m:" echo -e "\e[1m-b, --background\e[0m Start \e[4mCOMMAND\e[24m as background process (release the shell)." echo -e "\e[1m-i, --bind \e[4mLIST\e[24m\e[0m Force (bind) running process \e[4mLIST\e[24m inside tunnel." echo -e "\e[1m-o, --unbind \e[4mLIST\e[24m\e[0m Cancel force bind for running process \e[4mLIST\e[24m." echo -e "\e[1m-l, --list\e[0m List processes binded inside tunnel." echo -e "\e[1m-s, --skip\e[0m Don't check/setup system config & don't ask for root,\n\ run \e[4mCOMMAND\e[24m or move process \e[4mLIST\e[24m even if tunnel bind fails." echo -e "\e[1m-c, --clean\e[0m Move back all proceses to initial routing settings and remove system config." echo -e "\e[1m-v, --version\e[0m Print this program version." echo -e "\e[1m-h, --help\e[0m This help." echo echo -e "\e[1m\e[4mLIST\e[0m: List of process ID or names separated by spaces." exit 1 fi # Helper functions # Check the presence of required system packages check_package(){ nothing_installed=1 for package_name in "$@" do if ! dpkg -l "$package_name" &> /dev/null; then echo "Installing $package_name" sudo apt-get install "$package_name" nothing_installed=0 fi done return $nothing_installed } # List processes binded to the VPN tunnel list_bind(){ return_status=1 echo -e "PID""\t""CMD" while read task_pid do echo -e "${task_pid}""\t""`ps -p ${task_pid} -o comm=`"; return_status=0 done < /sys/fs/cgroup/net_cls/${cgroup_name}/tasks return $return_status } # Check and setup iptables - requires root even for check iptable_checked=false setup_iptables(){ if ! sudo iptables -t mangle -C OUTPUT -m cgroup --cgroup "$net_cls_classid" -j MARK --set-mark "$ip_table_fwmark" 2>/dev/null; then echo "Adding iptables MANGLE rule to set firewall mark $ip_table_fwmark on packets with class identifier $net_cls_classid" >&2 sudo iptables -t mangle -A OUTPUT -m cgroup --cgroup "$net_cls_classid" -j MARK --set-mark "$ip_table_fwmark" fi if ! sudo iptables -t nat -C POSTROUTING -m cgroup --cgroup "$net_cls_classid" -o "$vpn_interface" -j MASQUERADE 2>/dev/null; then echo "Adding iptables NAT rule force the packets with class identifier $net_cls_classid to exit through $vpn_interface" >&2 sudo iptables -t nat -A POSTROUTING -m cgroup --cgroup "$net_cls_classid" -o "$vpn_interface" -j MASQUERADE fi iptable_checked=true } # Test if config is working, IPv4 only testresult=true test_forced(){ exit_ip=`cgexec -g net_cls:"$cgroup_name" traceroute -m 1 -n 8.8.8.8 | sed -n '2{p;q}' | grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"` if [ "$exit_ip" == "$vpn_interface_gateway" ]; then echo -e "\e[32mTest OK. Trafic exits with IP $exit_ip.\e[0m" >&2 testresult=true return 0 else echo -e "\e[31mTest failed: Trafic exits with $exit_ip instead of $vpn_interface_gateway.\e[0m" >&2 testresult=false return 1 fi } # Reconfigure routing reroute(){ if [ -z "$vpn_interface_gateway" ]; then echo -e "\e[31mCan't find default gateway of interface ${vpn_interface}. Is it up?\e[0m" >&2 echo -e "\e[31mAborting.\e[0m" >&2 exit 1 fi if ! grep -E "^${ip_table_number}\s+$ip_table_name" /etc/iproute2/rt_tables &>/dev/null; then if grep -E "^${ip_table_number}\s+" /etc/iproute2/rt_tables; then echo "ERROR: Table ${ip_table_number} already exists in /etc/iproute2/rt_tables with a different name than $ip_table_name" >&2 exit 1 fi echo "Creating ip routing table: number=$ip_table_number name=$ip_table_name" >&2 echo "$ip_table_number $ip_table_name" | sudo tee -a /etc/iproute2/rt_tables > /dev/null check_iptables=true fi if ! grep -E "^${ip_table_number_blackhole}\s+$ip_table_name_blackhole" /etc/iproute2/rt_tables &>/dev/null; then if grep -E "^${ip_table_number_blackhole}\s+" /etc/iproute2/rt_tables; then echo "ERROR: Table ${ip_table_number_blackhole} already exists in /etc/iproute2/rt_tables with a different name than $ip_table_name_blackhole" >&2 exit 1 fi echo "Creating ip routing table: number=$ip_table_number_blackhole name=$ip_table_name_blackhole" >&2 echo "$ip_table_number_blackhole $ip_table_name_blackhole" | sudo tee -a /etc/iproute2/rt_tables > /dev/null check_iptables=true fi if ! ip rule list | grep " lookup $ip_table_name" | grep " fwmark " &>/dev/null; then echo "Adding rule to use ip routing table $ip_table_name for packets with firewall mark $ip_table_fwmark" >&2 sudo ip rule add prio "$ip_rule_priority" fwmark "$ip_table_fwmark" table "$ip_table_name" check_iptables=true fi if ! ip rule list | grep " lookup $ip_table_name_blackhole" | grep " fwmark " &>/dev/null; then echo "Adding rule to use ip routing table $ip_table_name_blackhole for packets with firewall mark $ip_table_fwmark" >&2 sudo ip rule add prio "$ip_rule_priority_blackhole" fwmark "$ip_table_fwmark" table "$ip_table_name_blackhole" check_iptables=true fi if [ -z "`ip route list table "$ip_table_name" default via $vpn_interface_gateway dev ${vpn_interface} 2>/dev/null`" ]; then echo "Adding default route in ip routing table $ip_table_name via $vpn_interface_gateway dev $vpn_interface" >&2 sudo ip route add default via "$vpn_interface_gateway" dev "$vpn_interface" table "$ip_table_name" check_iptables=true fi if [ -z "`ip route list table "$ip_table_name_blackhole" default 2>/dev/null`" ]; then echo "Adding blackhole default route in ip routing table $ip_table_name_blackhole" >&2 sudo ip route add blackhole default table "$ip_table_name_blackhole" check_iptables=true fi if [ -z "`lscgroup net_cls:$cgroup_name`" ] || [ `stat -c "%U" /sys/fs/cgroup/net_cls/${cgroup_name}/tasks` != "$USER" ]; then echo "Creating cgroup net_cls:${cgroup_name}. User $USER will be able to move tasks to it without root permissions." >&2 sudo cgcreate -t "$USER":"$USER" -a `id -g -n "$USER"`:`id -g -n "$USER"` -g net_cls:"$cgroup_name" check_iptables=true fi if [ "$check_iptables" = true ]; then setup_iptables fi # TEST forced bind test_forced if [ "$force" != true ]; then if [ "$testresult" = false ]; then if [ "$iptable_checked" = false ]; then echo -e "Trying to setup iptables and redo test..." >&2 setup_iptables test_forced fi fi if [ "$testresult" = false ]; then echo -e "\e[31mAborting.\e[0m" >&2 exit 1 fi fi } check_iptables=false if [ "$action" = "command" ] || [ "$action" = "bind" ]; then # SETUP config if [ "$skip" = false ]; then echo "Checking/setting forced routing config (skip with $0 -s ...)" >&2 if check_package cgroup-lite cgmanager cgroup-tools; then echo "You may want to reboot now. But that's probably not necessary." >&2 exit 1 fi if dpkg --compare-versions `iptables --version | grep -oP "iptables v\K.*$"` "lt" "1.6"; then echo -e "\e[31mYou need iptables 1.6.0+. Please install manually. Aborting.\e[0m" >&2 echo "Find latest iptables at http://www.netfilter.org/projects/iptables/downloads.html" >&2 echo "Commands to install iptables 1.6.0:" >&2 echo -e "\e[34msudo apt-get install dh-autoreconf bison flex cd /tmp curl http://www.netfilter.org/projects/iptables/files/iptables-1.6.0.tar.bz2 | tar xj cd iptables-1.6.0 ./configure --prefix=/usr \\ --sbindir=/sbin \\ --disable-nftables \\ --enable-libipq \\ --with-xtlibdir=/lib/xtables \\ && make \\ && sudo make install iptables --version\e[0m" >&2 exit 1 fi if [ ! -d "/sys/fs/cgroup/net_cls/$cgroup_name" ]; then echo "Creating net_cls control group $cgroup_name" >&2 sudo mkdir -p "/sys/fs/cgroup/net_cls/$cgroup_name" check_iptables=true fi if [ `cat "/sys/fs/cgroup/net_cls/$cgroup_name/net_cls.classid" | xargs -n 1 printf "0x%08x"` != "$net_cls_classid" ]; then echo "Applying net_cls class identifier $net_cls_classid to cgroup $cgroup_name" >&2 echo "$net_cls_classid" | sudo tee "/sys/fs/cgroup/net_cls/$cgroup_name/net_cls.classid" > /dev/null fi # Set up script to restore gateway once VPN is up again? fi if [ "$action" = "command" ]; then reroute fi fi # RUN command if [ "$action" = "command" ]; then if [ "$#" -eq 0 ]; then echo "Error: COMMAND not provided." >&2 exit 1 fi if [ "$background" = true ]; then cgexec -g net_cls:"$cgroup_name" "$@" &>/dev/null & exit 0 else cgexec -g net_cls:"$cgroup_name" "$@" exit $? fi # List process BINDED to VPN tunnel # Exit code 0 (true) if at least 1 process is binded elif [ "$action" = "list" ]; then echo "List of processes binded to VPN tunnel:" list_bind exit $? # Force process BIND to VPN tunnel elif [ "$action" = "bind" ]; then exit_code=1 for process in "$@" do if [ "$process" -eq "$process" ] 2>/dev/null; then # Is integer (PID) echo "$process" | sudo tee /sys/fs/cgroup/net_cls/${cgroup_name}/tasks > /dev/null exit_code=0 else # Is process name pids=$(pidof "$process") for pid in $pids do echo "$pid" | sudo tee /sys/fs/cgroup/net_cls/${cgroup_name}/tasks > /dev/null exit_code=0 done fi done echo "List of processes binded to VPN tunnel:" list_bind reroute exit $exit_code # UNBIND process elif [ "$action" = "unbind" ]; then for process in "$@" do if [ "$process" -eq "$process" ] 2>/dev/null; then # Is integer (PID) echo "$process" | sudo tee /sys/fs/cgroup/net_cls/tasks > /dev/null else # Is process name pids=$(pidof "$process") for pid in $pids do echo "$pid" | sudo tee /sys/fs/cgroup/net_cls/tasks > /dev/null done fi done echo "Remaining processes binded to VPN tunnel:" list_bind # CLEAN the mess elif [ "$action" = "clean" ]; then echo -e "Cleaning forced routing config generated by this script." echo -e "Don't bother with errors meaning there's nothing to remove." # Remove tasks if [ -f "/sys/fs/cgroup/net_cls/${cgroup_name}/tasks" ]; then while read task_pid; do echo ${task_pid} | sudo tee /sys/fs/cgroup/net_cls/tasks > /dev/null; done < "/sys/fs/cgroup/net_cls/${cgroup_name}/tasks" fi # Delete cgroup if [ -d "/sys/fs/cgroup/net_cls/${cgroup_name}" ]; then sudo find "/sys/fs/cgroup/net_cls/${cgroup_name}" -depth -type d -print -exec rmdir {} \; fi sudo iptables -t mangle -D OUTPUT -m cgroup --cgroup "$net_cls_classid" -j MARK --set-mark "$ip_table_fwmark" sudo iptables -t nat -D POSTROUTING -m cgroup --cgroup "$net_cls_classid" -o "$vpn_interface" -j MASQUERADE sudo ip rule del fwmark "$ip_table_fwmark" table "$ip_table_name" sudo ip route del default table "$ip_table_name" sudo ip route del default table "$ip_table_name_blackhole" sudo sed -i '/^${ip_table_number}\s\+${ip_table_name}\s*$/d' /etc/iproute2/rt_tables sudo sed -i '/^${ip_table_number_blackhole}\s\+${ip_table_name_blackhole}\s*$/d' /etc/iproute2/rt_tables if [ -n "`lscgroup net_cls:$cgroup_name`" ]; then sudo cgdelete net_cls:"$cgroup_name" fi if [ -n "`lscgroup net_cls:$cgroup_name_blackhole`" ]; then sudo cgdelete net_cls:"$cgroup_name_blackhole" fi echo "All done." fi # BONUS: Useful commands: # ./forcevpn.sh ping 8.8.8.8 # ./forcevpn.sh --bind ping # ./forcevpn.sh vuze # ./forcevpn.sh --bind java # ./forcevpn.sh --background vuze # To restore connectivity once VPN is restarted: # ./forcevpn.sh :