Last active
April 27, 2024 09:21
-
-
Save itzloop/f995cd386803b43f484307202f170e85 to your computer and use it in GitHub Desktop.
isolate_process.sh
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
#!/usr/bin/env bash | |
# Inspired by novpn to setup the cgroup v1 and all of it's edge cases | |
# general config | |
GP_NAME=${GP_NAME:="susgp"} | |
IF_NAME=${IF_NAME:="susif"} | |
IF_ADDR=${IF_ADDR:="10.20.30.40/24"} | |
DEF_ROUTE=${DEF_ROUTE:="10.20.30.1"} | |
PROXY=${PROXY:="socks5://127.0.0.1:2080"} | |
# Advanced config | |
RT_NAME=${RT_NAME:="susrt"} | |
RT_ID=${RT_ID:="1234"} | |
CG_ROOT=${CG_ROOT:="/sys/fs/cgroup"} | |
NET_CLS_ROOT=${NET_CLS_ROOT:="$CG_ROOT/net_cls"} | |
RT_DIR=${RT_DIR:="/etc/iproute2"} | |
RT_FILE=${RT_FILE:="$RT_DIR/rt_tables"} | |
FW_MARK=${FW_MARK:="20"} | |
CLASSID=${CLASSID:="0x10f2c"} | |
# logging configuration | |
readonly LOG_LEVEL_DEBUG=1 | |
readonly LOG_LEVEL_INFO=2 | |
readonly LOG_LEVEL_ERROR=3 | |
readonly COLOR_INFO="\033[32m" # Green | |
readonly COLOR_DEBUG="\033[34m" # Blue | |
readonly COLOR_ERROR="\033[31m" # Red | |
readonly COLOR_RESET="\033[0m" # Reset color | |
LOG_LEVEL=${LOG_LEVEL:="info"} | |
log() { | |
local level="$1" | |
local message="$2" | |
# Check if log level is enabled | |
if [[ $level -ge $LOG_LEVEL ]]; then | |
local color="" | |
case $level in | |
$LOG_LEVEL_INFO) | |
color="$COLOR_INFO" | |
;; | |
$LOG_LEVEL_DEBUG) | |
color="$COLOR_DEBUG" | |
;; | |
$LOG_LEVEL_ERROR) | |
color="$COLOR_ERROR" | |
;; | |
esac | |
echo -e "$color[$(date +'%Y-%m-%d %H:%M:%S')] $message$COLOR_RESET" | |
fi | |
} | |
# Specific log level functions (call the general log function) | |
info() { | |
log $LOG_LEVEL_INFO "$@" | |
} | |
debug() { | |
log $LOG_LEVEL_DEBUG "$@" | |
} | |
error() { | |
log $LOG_LEVEL_ERROR "$@" | |
} | |
show_help() { | |
echo "Usage: $0 [--i-know-what-im-doing] [--log-level level] [--help]" | |
echo " -h, --help Display help message." | |
echo " -i, --i-know-what-im-doing Skip confirmation prompt." | |
echo " -l, --log-level level Set log level (debug, info, error)." | |
} | |
VALID_ARGS=$(getopt -o "hil:" -l "help,i-know-what-im-doing,log-level:" -- "$@") | |
if [[ $? -ne 0 ]]; then | |
exit 1; | |
fi | |
eval set -- "$VALID_ARGS" | |
while [ : ]; do | |
case "$1" in | |
-i | --i-know-what-im-doing) | |
CONFIRMATION=true | |
shift | |
;; | |
-l | --log-level) | |
shift | |
LOG_LEVEL="$1" | |
shift | |
;; | |
-h | --help) | |
show_help | |
exit 0 | |
;; | |
\?) | |
error "Invalid option: -$OPTARG" | |
show_help | |
exit 1 | |
;; | |
--) shift; | |
break | |
;; | |
esac | |
done | |
shift "$((OPTIND-1))" # Shift past processed options | |
# Convert LOG_LEVEL string to integer level (lowercase for case-insensitive matching) | |
case $(tr [:upper:] [:lower:] <<< "$LOG_LEVEL") in | |
"debug") | |
LOG_LEVEL="$LOG_LEVEL_DEBUG" | |
;; | |
"info") | |
LOG_LEVEL="$LOG_LEVEL_INFO" | |
;; | |
"error") | |
LOG_LEVEL="$LOG_LEVEL_ERROR" | |
;; | |
*) | |
error "Invalid LOG_LEVEL: '$LOG_LEVEL' possible values are: debug, info, error" | |
exit 1 | |
;; | |
esac | |
debug "Log level set to: $LOG_LEVEL" | |
debug "Confirmation skipped with --i-know-what-im-doing flag." | |
# check if tun2socks exists on the machinie | |
tun2socks -version 2>&1 > /dev/null || (error "this script requires tun2socks\ninstall tun2socks from here: https://github.com/xjasonlyu/tun2socks/wiki/Install-from-Source#build"; exit 1) | |
# Exit on error | |
set -e | |
# Uncomment for debugging | |
# set -x | |
check_sudo() { | |
if ! sudo -n true > /dev/null 2>&1; then | |
error "This script requires root privileges. Please run with sudo." | |
exit 1 | |
fi | |
# Confirmation check (skipped with --i-know-what-im-doing) | |
if [[ -z "$CONFIRMATION" ]]; then | |
echo -e "This script will be using root privileges (run with --i-know-what-im-doing if you don't want to see this confirmation).\nAre you sure you want to continue? (y/N)" | |
read -r confirmation | |
if [[ "$confirmation" != [Yy] ]]; then | |
echo "Exiting script." | |
exit 0 | |
fi | |
fi | |
} | |
create_rt() { | |
local rt="$1" | |
local rt_path="$2" | |
local fwmark="$3" | |
local def_route="$4" | |
info "creating routing table: $1" | |
echo "$rt" >> "$rt_path" | |
} | |
setup_routes_and_rules() { | |
local rt="$1" | |
local fwmark="$2" | |
local def_route="$3" | |
info "adding default route" | |
ip route add default via $def_route table $rt | |
info "adding ip rule" | |
ip rule add fwmark $fwmark table $rt | |
} | |
remove_routes_and_rules() { | |
local rt="$1" | |
local fwmark="$2" | |
local def_route="$3" | |
info "removing default route" | |
ip route del default via $def_route table $rt | |
info "removing ip rule" | |
ip rule del fwmark $fwmark table $rt | |
} | |
create_iface() { | |
local ifname=$1 | |
local ifaddr=$2 | |
info "creating tun interface: $ifname" | |
ip tuntap add mode tun dev $ifname | |
info "adding addr to interface: $ifaddr" | |
ip addr add $ifaddr dev $ifname | |
info "bringing up the interface" | |
ip link set dev $ifname up | |
} | |
remove_iface() { | |
local ifname=$1 | |
local ifaddr=$2 | |
info "bringing down the interface" | |
ip link set dev $ifname down | |
info "removing addr to interface: $ifaddr" | |
ip addr del $ifaddr dev $ifname | |
info "removing tun interface: $ifname" | |
ip link del $ifname | |
} | |
create_cgroup() { | |
local cgpath="$1" | |
local classid="$2" | |
info "creating new cgroup $cgpath" | |
mkdir $cgpath | |
info "setting classid to $classid" | |
echo -n "$classid" | tee "$cgpath/net_cls.classid" 2>&1 > /dev/null | |
} | |
remove_cgroup() { | |
local cgpath="$1" | |
local cgroot="$2" | |
info "moving all processes to default net_cls groups" | |
while read -r pid; do | |
echo $pid | tee -a /sys/fs/cgroup/net_cls/cgroup.procs 2>&1 > /dev/null | |
done < "$cgpath/cgroup.procs" | |
info "removing net_cls group" | |
rmdir "$cgpath" | |
if [ $NET_CLS_MOUNTED == "1" ]; then | |
info "unmount net_cls" | |
umount "$cgroot" | |
info "removing net_cls default group" | |
rmdir "$cgroot" | |
fi | |
} | |
check_sudo | |
if [ ! -d "$CG_ROOT" ]; then | |
error "$CG_ROOT does not exists" | |
exit 1 | |
fi | |
NET_CLS_MOUNTED="0" | |
if [ ! -d "$NET_CLS_ROOT" ]; then | |
info "net_cls is not mounted, mounting on $NET_CLS_ROOT" | |
mkdir "$NET_CLS_ROOT" | |
mount -t cgroup -o net_cls net_cls "$NET_CLS_ROOT" | |
NET_CLS_MOUNTED="1" | |
fi | |
if [ ! -d "$RT_DIR" ]; then | |
info "$RT_DIR does not exist, creating..." | |
mkdir "$RT_DIR" | |
fi | |
if [ ! -f "$RT_FILE" ]; then | |
info "$RT_FILE does not exist, creating..." | |
touch "$RT_FILE" | |
fi | |
# check if rt exists if not create it | |
# | |
[ "$(grep -nc $RT_NAME $RT_FILE)" != "0" ] || info "creating routing table: $1"; echo "$RT_ID $RT_NAME" >> $RT_FILE | |
[ $(ip -j link | jq -rc ".[] | select(.ifname==\"$IF_NAME\")" | wc -l) != "0" ] || create_iface $IF_NAME $IF_ADDR | |
setup_routes_and_rules $RT_NAME $FW_MARK $DEF_ROUTE | |
create_cgroup "$NET_CLS_ROOT/$GP_NAME" $CLASSID | |
info "adding firewall rule to mark packets" | |
iptables -t mangle -A OUTPUT -m cgroup --cgroup $CLASSID -j MARK --set-mark $FW_MARK | |
info "bring up tun2socks" | |
tun2socks -device $IF_NAME -proxy $PROXY -interface lo --loglevel error | |
info "removing firewall rule to mark packets" | |
iptables -t mangle -D OUTPUT -m cgroup --cgroup $CLASSID -j MARK --set-mark $FW_MARK | |
remove_cgroup "$NET_CLS_ROOT/$GP_NAME" "$NET_CLS_ROOT" | |
remove_routes_and_rules $RT_NAME $FW_MARK $DEF_ROUTE | |
remove_iface $IF_NAME $IF_ADDR |
Also, it runs on my machine 😉
$ uname -msr
Linux 6.1.55-1-MANJARO x86_64
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How to use the script
This script assumes that you have a socks5 proxy running at
127.0.0.1:2080
. You can overwrite this by changingPROXY
variable.Run it with different log_level:
Possible log values: [debug, info, error]
Bringing a process to or out of the group
After running the script, in a different shell, put the process ids you want to tunnel in the created CGroup with the following command
If you have changed
GP_NAME
in the script, you have to use that insteada.To put a process to the default group: