zapret/init.d/macos/functions
2021-09-28 22:43:43 +03:00

488 lines
11 KiB
Plaintext

[ -n "$ZAPRET_BASE" ] || ZAPRET_BASE=/opt/zapret
IPSET_DIR=$ZAPRET_BASE/ipset
. "$IPSET_DIR/def.sh"
HOSTLIST="$ZHOSTLIST.gz"
[ -f "$HOSTLIST" ] || HOSTLIST="$ZHOSTLIST"
[ -f "$HOSTLIST" ] || HOSTLIST="$ZUSERLIST"
PIDDIR=/var/run
[ -n "$TPPORT" ] || TPPORT=988
TPWS_USER=daemon
TPWS_WAIT="--bind-wait-ifup=30 --bind-wait-ip=30"
TPWS_WAIT_SOCKS6="$TPWS_WAIT --bind-wait-ip-linklocal=30"
TPWS="$ZAPRET_BASE/tpws/tpws"
PF_MAIN="/etc/pf.conf"
PF_ANCHOR_DIR=/etc/pf.anchors
PF_ANCHOR_ZAPRET="$PF_ANCHOR_DIR/zapret"
PF_ANCHOR_ZAPRET_V4="$PF_ANCHOR_DIR/zapret-v4"
PF_ANCHOR_ZAPRET_V6="$PF_ANCHOR_DIR/zapret-v6"
CUSTOM_SCRIPT="$ZAPRET_BASE/init.d/macos/custom"
[ -f "$CUSTOM_SCRIPT" ] && . "$CUSTOM_SCRIPT"
existf()
{
type "$1" >/dev/null 2>/dev/null
}
on_off_function()
{
# $1 : function name on
# $2 : function name off
# $3 : 0 - off, 1 - on
local F="$1"
[ "$3" = "1" ] || F="$2"
shift
shift
shift
"$F" "$@"
}
run_daemon()
{
# $1 - daemon number : 1,2,3,...
# $2 - daemon
# $3 - daemon args
# use $PIDDIR/$DAEMONBASE$1.pid as pidfile
local DAEMONBASE="$(basename $2)"
local PIDFILE="$PIDDIR/$DAEMONBASE$1.pid"
local ARGS="--daemon --pidfile=$PIDFILE $3"
[ -f "$PIDFILE" ] && pgrep -qF "$PIDFILE" && {
echo Already running $1: $2
return 0
}
echo "Starting daemon $1: $2 $ARGS"
"$2" $ARGS
}
stop_daemon()
{
# $1 - daemon number : 1,2,3,...
# $2 - daemon
# use $PIDDIR/$DAEMONBASE$1.pid as pidfile
local PID
local DAEMONBASE="$(basename $2)"
local PIDFILE="$PIDDIR/$DAEMONBASE$1.pid"
[ -f "$PIDFILE" ] && read PID <"$PIDFILE"
[ -n "$PID" ] && {
echo "Stopping daemon $1: $2 (PID=$PID)"
kill $PID
rm -f "$PIDFILE"
}
return 0
}
do_daemon()
{
# $1 - 1 - run, 0 - stop
on_off_function run_daemon stop_daemon "$@"
}
filter_apply_hostlist_target()
{
# $1 - var name of tpws or nfqws params
[ "$MODE_FILTER" = "hostlist" ] && eval $1="\"\$$1 --hostlist=$HOSTLIST\""
}
tpws_apply_binds()
{
local o
[ "$DISABLE_IPV4" = "1" ] || o="--bind-addr=127.0.0.1"
[ "$DISABLE_IPV6" = "1" ] || {
for i in lo0 $IFACE_LAN; do
o="$o --bind-iface6=$i --bind-linklocal=force $TPWS_WAIT"
done
}
eval $1="\"\$$1 $o\""
}
tpws_apply_socks_binds()
{
local o
[ "$DISABLE_IPV4" = "1" ] || o="--bind-addr=127.0.0.1"
[ "$DISABLE_IPV6" = "1" ] || o="$o --bind-addr=::1"
for lan in $IFACE_LAN; do
[ "$DISABLE_IPV4" = "1" ] || o="$o --bind-iface4=$lan $TPWS_WAIT"
[ "$DISABLE_IPV6" = "1" ] || o="$o --bind-iface6=$lan --bind-linklocal=unwanted $TPWS_WAIT_SOCKS6"
done
eval $1="\"\$$1 $o\""
}
wait_interface_ll()
{
echo waiting for an ipv6 link local address on $1 ...
"$TPWS" --bind-wait-only --bind-iface6=$1 --bind-linklocal=force $TPWS_WAIT
}
wait_lan_ll()
{
[ "$DISABLE_IPV6" != "1" ] && {
for lan in $IFACE_LAN; do
wait_interface_ll $lan >&2 || {
echo "wait interface failed on $lan"
return 1
}
done
}
return 0
}
get_ipv6_linklocal()
{
ifconfig $1 | sed -nEe 's/^.*inet6 (fe80:[a-f0-9:]+).*/\1/p'
}
pf_anchor_root_reload()
{
echo reloading PF root anchor
pfctl -qf "$PF_MAIN"
}
pf_anchor_root()
{
local patch
[ -f "$PF_MAIN" ] && {
grep -q '^rdr-anchor "zapret"$' "$PF_MAIN" || {
echo patching rdr-anchor in $PF_MAIN
patch=1
sed -i '' -e '/^rdr-anchor "com\.apple\/\*"$/i \
rdr-anchor "zapret"
' $PF_MAIN
}
grep -q '^anchor "zapret"$' "$PF_MAIN" || {
echo patching anchor in $PF_MAIN
patch=1
sed -i '' -e '/^anchor "com\.apple\/\*"$/i \
anchor "zapret"
' $PF_MAIN
}
grep -q "^set limit table-entries" "$PF_MAIN" || {
echo patching table-entries limit
patch=1
sed -i '' -e '/^scrub-anchor "com\.apple\/\*"$/i \
set limit table-entries 5000000
' $PF_MAIN
}
grep -q '^anchor "zapret"$' "$PF_MAIN" &&
grep -q '^rdr-anchor "zapret"$' "$PF_MAIN" &&
grep -q '^set limit table-entries' "$PF_MAIN" && {
if [ -n "$patch" ]; then
echo successfully patched $PF_MAIN
pf_anchor_root_reload
else
echo successfully checked zapret anchors in $PF_MAIN
fi
return 0
}
}
echo ----------------------------------
echo Automatic $PF_MAIN patching failed. You must apply root anchors manually in your PF config.
echo rdr-anchor \"zapret\"
echo anchor \"zapret\"
echo ----------------------------------
return 1
}
pf_anchor_root_del()
{
sed -i '' -e '/^anchor "zapret"$/d' -e '/^rdr-anchor "zapret"$/d' -e '/^set limit table-entries/d' "$PF_MAIN"
}
pf_anchor_zapret()
{
[ "$DISABLE_IPV4" = "1" ] || {
if [ -f "$ZIPLIST_EXCLUDE" ]; then
echo "table <nozapret> persist file \"$ZIPLIST_EXCLUDE\""
else
echo "table <nozapret> persist"
fi
}
[ "$DISABLE_IPV6" = "1" ] || {
if [ -f "$ZIPLIST_EXCLUDE6" ]; then
echo "table <nozapret6> persist file \"$ZIPLIST_EXCLUDE6\""
else
echo "table <nozapret6> persist"
fi
}
[ "$DISABLE_IPV4" = "1" ] || echo "rdr-anchor \"/zapret-v4\" inet to !<nozapret>"
[ "$DISABLE_IPV6" = "1" ] || echo "rdr-anchor \"/zapret-v6\" inet6 to !<nozapret6>"
[ "$DISABLE_IPV4" = "1" ] || echo "anchor \"/zapret-v4\" inet to !<nozapret>"
[ "$DISABLE_IPV6" = "1" ] || echo "anchor \"/zapret-v6\" inet6 to !<nozapret6>"
}
pf_anchor_zapret_tables()
{
# $1 - variable to receive applied table names
# $2/$3 $4/$5 ... table_name/table_file
local tblv=$1
local _tbl
shift
[ "$MODE_FILTER" = "ipset" ] &&
{
while [ -n "$1" ] && [ -n "$2" ] ; do
[ -f "$2" ] && {
echo "table <$1> file \"$2\""
_tbl="$_tbl<$1> "
}
shift
shift
done
}
[ -n "$_tbl" ] || _tbl="any"
eval $tblv="\"\$_tbl\""
}
pf_anchor_port_target()
{
if [ "$MODE_HTTP" = "1" ] && [ "$MODE_HTTPS" = "1" ]; then
echo "{80,443}"
elif [ "$MODE_HTTPS" = "1" ]; then
echo "443"
elif [ "$MODE_HTTP" = "1" ]; then
echo "80"
fi
}
pf_anchor_zapret_v4_tpws()
{
# $1 - port
local rule port=$(pf_anchor_port_target)
for lan in $IFACE_LAN; do
for t in $tbl; do
echo "rdr on $lan inet proto tcp from any to $t port $port -> 127.0.0.1 port $1"
done
done
echo "rdr on lo0 inet proto tcp from !127.0.0.0/8 to any port $port -> 127.0.0.1 port $1"
for t in $tbl; do
rule="route-to (lo0 127.0.0.1) inet proto tcp from !127.0.0.0/8 to $t port $port user { >root }"
if [ -n "$IFACE_WAN" ] ; then
for wan in $IFACE_WAN; do
echo "pass out on $wan $rule"
done
else
echo "pass out $rule"
fi
done
}
pf_anchor_zapret_v4()
{
local tbl port
[ "$DISABLE_IPV4" = "1" ] || {
case $MODE in
tpws)
[ ! "$MODE_HTTP" = "1" ] && [ ! "$MODE_HTTPS" = "1" ] && return
pf_anchor_zapret_tables tbl zapret-user "$ZIPLIST_USER" zapret "$ZIPLIST"
pf_anchor_zapret_v4_tpws $TPPORT
;;
custom)
pf_anchor_zapret_tables tbl zapret-user "$ZIPLIST_USER" zapret "$ZIPLIST"
existf zapret_custom_firewall_v4 && zapret_custom_firewall_v4
;;
esac
}
}
pf_anchor_zapret_v6_tpws()
{
# $1 - port
local LL_LAN rule port=$(pf_anchor_port_target)
# LAN link local is only for router
for lan in $IFACE_LAN; do
LL_LAN=$(get_ipv6_linklocal $lan)
[ -n "$LL_LAN" ] && {
for t in $tbl; do
echo "rdr on $lan inet6 proto tcp from any to $t port $port -> $LL_LAN port $1"
done
}
done
echo "rdr on lo0 inet6 proto tcp from !::1 to any port $port -> fe80::1 port $1"
for t in $tbl; do
rule="route-to (lo0 fe80::1) inet6 proto tcp from !::1 to $t port $port user { >root }"
if [ -n "$IFACE_WAN" ] ; then
for wan in $IFACE_WAN; do
echo "pass out on $wan $rule"
done
else
echo "pass out $rule"
fi
done
}
pf_anchor_zapret_v6()
{
local tbl port
[ "$DISABLE_IPV6" = "1" ] || {
case $MODE in
tpws)
[ ! "$MODE_HTTP" = "1" ] && [ ! "$MODE_HTTPS" = "1" ] && return
pf_anchor_zapret_tables tbl zapret6-user "$ZIPLIST_USER6" zapret6 "$ZIPLIST6"
pf_anchor_zapret_v6_tpws $TPPORT
;;
custom)
pf_anchor_zapret_tables tbl zapret6-user "$ZIPLIST_USER6" zapret6 "$ZIPLIST6"
existf zapret_custom_firewall_v6 && zapret_custom_firewall_v6
;;
esac
}
}
pf_anchors_create()
{
wait_lan_ll
pf_anchor_zapret >"$PF_ANCHOR_ZAPRET"
pf_anchor_zapret_v4 >"$PF_ANCHOR_ZAPRET_V4"
pf_anchor_zapret_v6 >"$PF_ANCHOR_ZAPRET_V6"
}
pf_anchors_del()
{
rm -f "$PF_ANCHOR_ZAPRET" "$PF_ANCHOR_ZAPRET_V4" "$PF_ANCHOR_ZAPRET_V6"
}
pf_anchors_load()
{
echo loading zapret anchor from "$PF_ANCHOR_ZAPRET"
pfctl -qa zapret -f "$PF_ANCHOR_ZAPRET" || {
echo error loading zapret anchor
return 1
}
if [ "$DISABLE_IPV4" = "1" ]; then
echo clearing zapret-v4 anchor
pfctl -qa zapret-v4 -F all 2>/dev/null
else
echo loading zapret-v4 anchor from "$PF_ANCHOR_ZAPRET_V4"
pfctl -qa zapret-v4 -f "$PF_ANCHOR_ZAPRET_V4" || {
echo error loading zapret-v4 anchor
return 1
}
fi
if [ "$DISABLE_IPV6" = "1" ]; then
echo clearing zapret-v6 anchor
pfctl -qa zapret-v6 -F all 2>/dev/null
else
echo loading zapret-v6 anchor from "$PF_ANCHOR_ZAPRET_V6"
pfctl -qa zapret-v6 -f "$PF_ANCHOR_ZAPRET_V6" || {
echo error loading zapret-v6 anchor
return 1
}
fi
echo successfully loaded PF anchors
return 0
}
pf_anchors_clear()
{
echo clearing zapret anchors
pfctl -qa zapret-v4 -F all 2>/dev/null
pfctl -qa zapret-v6 -F all 2>/dev/null
pfctl -qa zapret -F all 2>/dev/null
}
pf_enable()
{
echo enabling PF
pfctl -qe
}
pf_table_reload()
{
echo reloading zapret tables
[ "$DISABLE_IPV4" = "1" ] || pfctl -qTl -a zapret-v4 -f "$PF_ANCHOR_ZAPRET_V4"
[ "$DISABLE_IPV6" = "1" ] || pfctl -qTl -a zapret-v6 -f "$PF_ANCHOR_ZAPRET_V6"
pfctl -qTl -a zapret -f "$PF_ANCHOR_ZAPRET"
}
zapret_do_firewall()
{
# $1 - 1 - add, 0 - del
case "${MODE}" in
tpws|filter|custom)
if [ "$1" = "1" ] ; then
pf_anchor_root || return 1
pf_anchors_create
pf_anchors_load || return 1
pf_enable
else
pf_anchors_clear
fi
;;
tpws-socks)
;;
*)
echo "unsupported MODE=$MODE"
return 1
;;
esac
return 0
}
zapret_apply_firewall()
{
zapret_do_firewall 1 "$@"
}
zapret_unapply_firewall()
{
zapret_do_firewall 0 "$@"
}
zapret_restart_firewall()
{
zapret_unapply_firewall "$@"
zapret_apply_firewall "$@"
}
zapret_do_daemons()
{
# $1 - 1 - run, 0 - stop
local opt
case "${MODE}" in
tpws)
[ "$1" = "1" ] && [ "$DISABLE_IPV4" = "1" ] && [ "$DISABLE_IPV6" = "1" ] && {
echo "both ipv4 and ipv6 are disabled. nothing to do"
return 0
}
# MacOS requires root. kernel hardcoded requirement for /dev/pf ioctls
opt="--user=root --port=$TPPORT"
filter_apply_hostlist_target opt
tpws_apply_binds opt
opt="$opt $TPWS_OPT"
do_daemon $1 1 "$TPWS" "$opt"
;;
tpws-socks)
[ "$1" = "1" ] && [ "$DISABLE_IPV4" = "1" ] && [ "$DISABLE_IPV6" = "1" ] && {
echo "both ipv4 and ipv6 are disabled. nothing to do"
return 0
}
opt="--socks --user=$TPWS_USER --port=$TPPORT"
tpws_apply_socks_binds opt
filter_apply_hostlist_target opt
opt="$opt $TPWS_OPT"
do_daemon $1 1 "$TPWS" "$opt"
;;
filter)
;;
custom)
existf zapret_custom_daemons && zapret_custom_daemons $1
;;
*)
echo "unsupported MODE=$MODE"
return 1
;;
esac
}
zapret_run_daemons()
{
zapret_do_daemons 1 "$@"
}
zapret_stop_daemons()
{
zapret_do_daemons 0 "$@"
}
zapret_restart_daemons()
{
zapret_stop_daemons "$@"
zapret_run_daemons "$@"
}