mirror of
https://github.com/springzfx/cgproxy.git
synced 2026-01-07 13:07:56 +08:00
275 lines
11 KiB
Bash
Executable File
275 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
### This script will proxy/noproxy anything running in specific cgroup
|
|
### need cgroup2 support, and iptables cgroup2 path match support
|
|
###
|
|
### script usage:
|
|
### cgroup-tproxy.sh [--help|--config|stop]
|
|
### options:
|
|
### --config=FILE load config from file
|
|
### --help show help info
|
|
### stop clean then stop. Variables may change when stopping, which should be avoid
|
|
### so always stop first in the last context before start new context
|
|
###
|
|
### available variables with default value:
|
|
### cgroup_noproxy="/noproxy.slice"
|
|
### cgroup_proxy="/proxy.slice"
|
|
### port=12345
|
|
### enable_dns=true
|
|
### enable_udp=true
|
|
### enable_tcp=true
|
|
### enable_ipv4=true
|
|
### enable_ipv6=true
|
|
### enable_gateway=false
|
|
### table=10007
|
|
### fwmark=0x9973
|
|
### cgroup_mount_point=$(findmnt -t cgroup2 -n -o TARGET | head -n 1)
|
|
###
|
|
### semicolon to seperate multi cgroup:
|
|
### cgroup_noproxy="/noproxy1.slice:/noproxy2.slice"
|
|
### cgroup_proxy="/proxy1.slice:/proxy2.slice"
|
|
|
|
print_help(){
|
|
sed -rn 's/^### ?//;T;p' "$0"
|
|
}
|
|
|
|
## check root
|
|
[ ! $(id -u) -eq 0 ] && { >&2 echo "iptables: need root to modify iptables";exit -1; }
|
|
|
|
## any process in this cgroup will be proxied
|
|
if [ -z ${cgroup_proxy+x} ]; then
|
|
cgroup_proxy="/proxy.slice"
|
|
else
|
|
IFS=':' read -r -a cgroup_proxy <<< "$cgroup_proxy"
|
|
fi
|
|
|
|
## any process in this cgroup will not be proxied
|
|
if [ -z ${cgroup_noproxy+x} ]; then
|
|
cgroup_noproxy="/noproxy.slice"
|
|
else
|
|
IFS=':' read -r -a cgroup_noproxy <<< "$cgroup_noproxy"
|
|
fi
|
|
|
|
## tproxy listening port
|
|
[ -z ${port+x} ] && port=12345
|
|
|
|
## controll options
|
|
[ -z ${enable_dns+x} ] && enable_dns=true
|
|
[ -z ${enable_udp+x} ] && enable_udp=true
|
|
[ -z ${enable_tcp+x} ] && enable_tcp=true
|
|
[ -z ${enable_ipv4+x} ] && enable_ipv4=true
|
|
[ -z ${enable_ipv6+x} ] && enable_ipv6=true
|
|
[ -z ${enable_gateway+x} ] && enable_gateway=false
|
|
|
|
## mark/route things
|
|
[ -z ${table+x} ] && table=10007
|
|
[ -z ${fwmark+x} ] && fwmark=0x9973
|
|
[ -z ${table_reroute+x} ] && table_reroute=$table
|
|
[ -z ${table_tproxy+x} ] && table_tproxy=$table
|
|
[ -z ${fwmark_reroute+x} ] && fwmark_reroute=$fwmark
|
|
[ -z ${fwmark_tproxy+x} ] && fwmark_tproxy=$fwmark
|
|
|
|
## cgroup mount point things
|
|
[ -z ${cgroup_mount_point+x} ] && cgroup_mount_point=$(findmnt -t cgroup2 -n -o TARGET | head -n 1)
|
|
|
|
|
|
stop(){
|
|
iptables -w 60 -t mangle -L TPROXY_ENT &> /dev/null || return
|
|
echo "iptables: cleaning tproxy iptables"
|
|
|
|
iptables -w 60 -t mangle -D PREROUTING -j TPROXY_PRE
|
|
iptables -w 60 -t mangle -D OUTPUT -j TPROXY_OUT
|
|
|
|
iptables -w 60 -t mangle -F TPROXY_PRE
|
|
iptables -w 60 -t mangle -F TPROXY_ENT
|
|
iptables -w 60 -t mangle -F TPROXY_OUT
|
|
iptables -w 60 -t mangle -F TPROXY_MARK
|
|
|
|
iptables -w 60 -t mangle -X TPROXY_PRE
|
|
iptables -w 60 -t mangle -X TPROXY_ENT
|
|
iptables -w 60 -t mangle -X TPROXY_OUT
|
|
iptables -w 60 -t mangle -X TPROXY_MARK
|
|
|
|
ip rule delete fwmark $fwmark_tproxy lookup $table_tproxy
|
|
ip rule delete fwmark $fwmark_reroute lookup $table_reroute &> /dev/null
|
|
ip route flush table $table_tproxy
|
|
ip route flush table $table_reroute &> /dev/null
|
|
|
|
ip6tables -w 60 -t mangle -D PREROUTING -j TPROXY_PRE
|
|
ip6tables -w 60 -t mangle -D OUTPUT -j TPROXY_OUT
|
|
|
|
ip6tables -w 60 -t mangle -F TPROXY_PRE
|
|
ip6tables -w 60 -t mangle -F TPROXY_OUT
|
|
ip6tables -w 60 -t mangle -F TPROXY_ENT
|
|
ip6tables -w 60 -t mangle -F TPROXY_MARK
|
|
|
|
ip6tables -w 60 -t mangle -X TPROXY_PRE
|
|
ip6tables -w 60 -t mangle -X TPROXY_OUT
|
|
ip6tables -w 60 -t mangle -X TPROXY_ENT
|
|
ip6tables -w 60 -t mangle -X TPROXY_MARK
|
|
|
|
ip -6 rule delete fwmark $fwmark_tproxy lookup $table_tproxy
|
|
ip -6 rule delete fwmark $fwmark_reroute lookup $table_reroute &> /dev/null
|
|
ip -6 route flush table $table_tproxy
|
|
ip -6 route flush table $table_reroute &> /dev/null
|
|
|
|
## may not exist, just ignore, and tracking their existence is not reliable
|
|
iptables -w 60 -t nat -D POSTROUTING -m owner ! --socket-exists -j MASQUERADE &> /dev/null
|
|
ip6tables -w 60 -t nat -D POSTROUTING -m owner ! --socket-exists -s fc00::/7 -j MASQUERADE &> /dev/null
|
|
|
|
## unmount cgroup2
|
|
[ "$(findmnt -M $cgroup_mount_point -n -o FSTYPE)" = "cgroup2" ] && umount $cgroup_mount_point
|
|
}
|
|
|
|
## parse parameter
|
|
for i in "$@"
|
|
do
|
|
case $i in
|
|
stop)
|
|
stop
|
|
exit 0
|
|
;;
|
|
--config=*)
|
|
config=${i#*=}
|
|
source $config
|
|
;;
|
|
--help)
|
|
print_help
|
|
exit 0
|
|
;;
|
|
*)
|
|
print_help
|
|
exit 0
|
|
;;
|
|
esac
|
|
done
|
|
|
|
|
|
## check cgroup_mount_point, create and mount if necessary
|
|
[ -z $cgroup_mount_point ] && { >&2 echo "iptables: no cgroup2 mount point available"; exit -1; }
|
|
[ ! -d $cgroup_mount_point ] && mkdir -p $cgroup_mount_point
|
|
[ "$(findmnt -M $cgroup_mount_point -n -o FSTYPE)" != "cgroup2" ] && mount -t cgroup2 none $cgroup_mount_point
|
|
[ "$(findmnt -M $cgroup_mount_point -n -o FSTYPE)" != "cgroup2" ] && { >&2 echo "iptables: mount $cgroup_mount_point failed"; exit -1; }
|
|
|
|
## only create the first one in arrary
|
|
test -d $cgroup_mount_point$cgroup_proxy || mkdir $cgroup_mount_point$cgroup_proxy || exit -1;
|
|
test -d $cgroup_mount_point$cgroup_noproxy || mkdir $cgroup_mount_point$cgroup_noproxy || exit -1;
|
|
|
|
## filter cgroup that not exist
|
|
_cgroup_noproxy=()
|
|
for cg in ${cgroup_noproxy[@]}; do
|
|
test -d $cgroup_mount_point$cg && _cgroup_noproxy+=($cg) || { >&2 echo "iptables: $cg not exist, ignore";}
|
|
done
|
|
unset cgroup_noproxy && cgroup_noproxy=${_cgroup_noproxy[@]}
|
|
|
|
## filter cgroup that not exist
|
|
_cgroup_proxy=()
|
|
for cg in ${cgroup_proxy[@]}; do
|
|
test -d $cgroup_mount_point$cg && _cgroup_proxy+=($cg) || { >&2 echo "iptables: $cg not exist, ignore";}
|
|
done
|
|
unset cgroup_proxy && cgroup_proxy=${_cgroup_proxy[@]}
|
|
|
|
|
|
## ipv4 #########################################################################
|
|
echo "iptables: applying tproxy iptables"
|
|
## mangle prerouting
|
|
ip rule add fwmark $fwmark_tproxy table $table_tproxy
|
|
ip route add local default dev lo table $table_tproxy
|
|
# core
|
|
iptables -w 60 -t mangle -N TPROXY_ENT
|
|
iptables -w 60 -t mangle -A TPROXY_ENT -m socket -j MARK --set-mark $fwmark_tproxy
|
|
iptables -w 60 -t mangle -A TPROXY_ENT -m socket -j ACCEPT
|
|
iptables -w 60 -t mangle -A TPROXY_ENT -p tcp -j TPROXY --on-ip 127.0.0.1 --on-port $port --tproxy-mark $fwmark_tproxy
|
|
iptables -w 60 -t mangle -A TPROXY_ENT -p udp -j TPROXY --on-ip 127.0.0.1 --on-port $port --tproxy-mark $fwmark_tproxy
|
|
# filter
|
|
iptables -w 60 -t mangle -N TPROXY_PRE
|
|
iptables -w 60 -t mangle -A TPROXY_PRE -m addrtype --dst-type LOCAL -j RETURN
|
|
iptables -w 60 -t mangle -A TPROXY_PRE -m addrtype ! --dst-type UNICAST -j RETURN
|
|
$enable_gateway || iptables -w 60 -t mangle -A TPROXY_PRE -m addrtype ! --src-type LOCAL -j RETURN
|
|
$enable_dns && iptables -w 60 -t mangle -A TPROXY_PRE -p udp --dport 53 -j TPROXY_ENT
|
|
$enable_udp && iptables -w 60 -t mangle -A TPROXY_PRE -p udp -j TPROXY_ENT
|
|
$enable_tcp && iptables -w 60 -t mangle -A TPROXY_PRE -p tcp -j TPROXY_ENT
|
|
# hook
|
|
iptables -w 60 -t mangle -A PREROUTING -j TPROXY_PRE
|
|
|
|
## mangle output
|
|
if [ $fwmark_reroute != $fwmark_tproxy ]; then
|
|
ip rule add fwmark $fwmark_reroute table $table_reroute
|
|
ip route add local default dev lo table $table_reroute
|
|
fi
|
|
# filter
|
|
iptables -w 60 -t mangle -N TPROXY_MARK
|
|
iptables -w 60 -t mangle -A TPROXY_MARK -m addrtype ! --dst-type UNICAST -j RETURN
|
|
$enable_dns && iptables -w 60 -t mangle -A TPROXY_MARK -p udp --dport 53 -j MARK --set-mark $fwmark_reroute
|
|
$enable_udp && iptables -w 60 -t mangle -A TPROXY_MARK -p udp -j MARK --set-mark $fwmark_reroute
|
|
$enable_tcp && iptables -w 60 -t mangle -A TPROXY_MARK -p tcp -j MARK --set-mark $fwmark_reroute
|
|
# cgroup
|
|
iptables -w 60 -t mangle -N TPROXY_OUT
|
|
iptables -w 60 -t mangle -A TPROXY_OUT -m conntrack --ctdir REPLY -j RETURN
|
|
for cg in ${cgroup_noproxy[@]}; do
|
|
iptables -w 60 -t mangle -A TPROXY_OUT -m cgroup --path $cg -j RETURN
|
|
done
|
|
for cg in ${cgroup_proxy[@]}; do
|
|
iptables -w 60 -t mangle -A TPROXY_OUT -m cgroup --path $cg -j TPROXY_MARK
|
|
done
|
|
# hook
|
|
$enable_ipv4 && iptables -w 60 -t mangle -A OUTPUT -j TPROXY_OUT
|
|
|
|
## ipv6 #########################################################################
|
|
## mangle prerouting
|
|
ip -6 rule add fwmark $fwmark_tproxy table $table_tproxy
|
|
ip -6 route add local default dev lo table $table_tproxy
|
|
# core
|
|
ip6tables -w 60 -t mangle -N TPROXY_ENT
|
|
ip6tables -w 60 -t mangle -A TPROXY_ENT -m socket -j MARK --set-mark $fwmark_tproxy
|
|
ip6tables -w 60 -t mangle -A TPROXY_ENT -m socket -j ACCEPT
|
|
ip6tables -w 60 -t mangle -A TPROXY_ENT -p tcp -j TPROXY --on-ip ::1 --on-port $port --tproxy-mark $fwmark_tproxy
|
|
ip6tables -w 60 -t mangle -A TPROXY_ENT -p udp -j TPROXY --on-ip ::1 --on-port $port --tproxy-mark $fwmark_tproxy
|
|
# filter
|
|
ip6tables -w 60 -t mangle -N TPROXY_PRE
|
|
ip6tables -w 60 -t mangle -A TPROXY_PRE -m addrtype --dst-type LOCAL -j RETURN
|
|
ip6tables -w 60 -t mangle -A TPROXY_PRE -m addrtype ! --dst-type UNICAST -j RETURN
|
|
$enable_gateway || ip6tables -w 60 -t mangle -A TPROXY_PRE -m addrtype ! --src-type LOCAL -j RETURN
|
|
$enable_dns && ip6tables -w 60 -t mangle -A TPROXY_PRE -p udp --dport 53 -j TPROXY_ENT
|
|
$enable_udp && ip6tables -w 60 -t mangle -A TPROXY_PRE -p udp -j TPROXY_ENT
|
|
$enable_tcp && ip6tables -w 60 -t mangle -A TPROXY_PRE -p tcp -j TPROXY_ENT
|
|
# hook
|
|
ip6tables -w 60 -t mangle -A PREROUTING -j TPROXY_PRE
|
|
|
|
## mangle output
|
|
if [ $fwmark_reroute != $fwmark_tproxy ]; then
|
|
ip -6 rule add fwmark $fwmark_reroute table $table_reroute
|
|
ip -6 route add local default dev lo table $table_reroute
|
|
fi
|
|
# filter
|
|
ip6tables -w 60 -t mangle -N TPROXY_MARK
|
|
ip6tables -w 60 -t mangle -A TPROXY_MARK -m addrtype ! --dst-type UNICAST -j RETURN
|
|
$enable_dns && ip6tables -w 60 -t mangle -A TPROXY_MARK -p udp --dport 53 -j MARK --set-mark $fwmark_reroute
|
|
$enable_udp && ip6tables -w 60 -t mangle -A TPROXY_MARK -p udp -j MARK --set-mark $fwmark_reroute
|
|
$enable_tcp && ip6tables -w 60 -t mangle -A TPROXY_MARK -p tcp -j MARK --set-mark $fwmark_reroute
|
|
# cgroup
|
|
ip6tables -w 60 -t mangle -N TPROXY_OUT
|
|
ip6tables -w 60 -t mangle -A TPROXY_OUT -m conntrack --ctdir REPLY -j RETURN
|
|
for cg in ${cgroup_noproxy[@]}; do
|
|
ip6tables -w 60 -t mangle -A TPROXY_OUT -m cgroup --path $cg -j RETURN
|
|
done
|
|
for cg in ${cgroup_proxy[@]}; do
|
|
ip6tables -w 60 -t mangle -A TPROXY_OUT -m cgroup --path $cg -j TPROXY_MARK
|
|
done
|
|
# hook
|
|
$enable_ipv6 && ip6tables -w 60 -t mangle -A OUTPUT -j TPROXY_OUT
|
|
|
|
## forward #######################################################################
|
|
if $enable_gateway; then
|
|
iptables -t nat -A POSTROUTING -m owner ! --socket-exists -j MASQUERADE
|
|
ip6tables -w 60 -t nat -A POSTROUTING -m owner ! --socket-exists -s fc00::/7 -j MASQUERADE # only masquerade ipv6 private address
|
|
sysctl -w net.ipv4.ip_forward=1
|
|
sysctl -w net.ipv6.conf.all.forwarding=1
|
|
echo "iptables: gateway enabled"
|
|
fi
|
|
|
|
## message for user
|
|
cat << DOC
|
|
iptables: noproxy cgroup: ${cgroup_noproxy[@]}
|
|
iptables: proxied cgroup: ${cgroup_proxy[@]}
|
|
DOC
|