shellcheck linting and formatting shell scripts

This commit is contained in:
conc3rned
2024-09-17 16:18:29 +03:00
parent c1db09b19e
commit a13e4e064f
58 changed files with 2759 additions and 3296 deletions

View File

@@ -1,42 +1,36 @@
which()
{
which() {
# on some systems 'which' command is considered deprecated and not installed by default
# 'command -v' replacement does not work exactly the same way. it outputs shell aliases if present
# $1 - executable name
local IFS=:
for p in $PATH; do
[ -x "$p/$1" ] && {
echo "$p/$1"
return 0
}
[ -x "$p/$1" ] && {
echo "$p/$1"
return 0
}
done
return 1
}
exists()
{
exists() {
which "$1" >/dev/null 2>/dev/null
}
existf()
{
existf() {
type "$1" >/dev/null 2>/dev/null
}
whichq()
{
which $1 2>/dev/null
whichq() {
which "$1" 2>/dev/null
}
exist_all()
{
exist_all() {
while [ -n "$1" ]; do
exists "$1" || return 1
shift
done
return 0
}
on_off_function()
{
# $1 : function name on
# $2 : function name off
# $3 : 0 - off, 1 - on
on_off_function() {
# $1: function name on
# $2: function name off
# $3: 0 - off, 1 - on
local F="$1"
[ "$3" = "1" ] || F="$2"
shift
@@ -44,24 +38,21 @@ on_off_function()
shift
"$F" "$@"
}
contains()
{
contains() {
# check if substring $2 contains in $1
[ "${1#*$2}" != "$1" ]
}
starts_with()
{
# $1 : what
# $2 : starts with
starts_with() {
# $1: what
# $2: starts with
case "$1" in
"$2"*)
return 0
;;
"$2"*)
return 0
;;
esac
return 1
}
find_str_in_list()
{
find_str_in_list() {
[ -n "$1" ] && {
for v in $2; do
[ "$v" = "$1" ] && return 0
@@ -69,14 +60,12 @@ find_str_in_list()
}
return 1
}
end_with_newline()
{
end_with_newline() {
local c="$(tail -c 1)"
[ "$c" = "" ]
}
append_separator_list()
{
append_separator_list() {
# $1 - var name to receive result
# $2 - separator
# $3 - quoter
@@ -84,113 +73,102 @@ append_separator_list()
local _var="$1" sep="$2" quo="$3" i
eval i="\$$_var"
shift; shift; shift
shift
shift
shift
while [ -n "$1" ]; do
if [ -n "$i" ] ; then
if [ -n "$i" ]; then
i="$i$sep$quo$1$quo"
else
i="$quo$1$quo"
fi
shift
done
eval $_var="\$i"
eval "$_var"="\$i"
}
make_separator_list()
{
eval $1=''
make_separator_list() {
eval "$1"=''
append_separator_list "$@"
}
make_comma_list()
{
make_comma_list() {
# $1 - var name to receive result
# $2,$3,... - elements
local var="$1"
shift
make_separator_list $var , '' "$@"
make_separator_list "$var" , '' "$@"
}
make_quoted_comma_list()
{
make_quoted_comma_list() {
# $1 - var name to receive result
# $2,$3,... - elements
local var="$1"
shift
make_separator_list $var , '"' "$@"
make_separator_list "$var" , '"' "$@"
}
unique()
{
unique() {
local i
for i in "$@"; do echo $i; done | sort -u | xargs
for i in "$@"; do echo "$i"; done | sort -u | xargs
}
is_linked_to_busybox()
{
is_linked_to_busybox() {
local IFS F P
IFS=:
for path in $PATH; do
F=$path/$1
P="$(readlink $F)"
if [ -z "$P" ] && [ -x $F ] && [ ! -L $F ]; then return 1; fi
P="$(readlink "$F")"
if [ -z "$P" ] && [ -x "$F" ] && [ ! -L "$F" ]; then return 1; fi
[ "${P%busybox*}" != "$P" ] && return
done
}
get_dir_inode()
{
get_dir_inode() {
local dir="$1"
[ -L "$dir" ] && dir=$(readlink "$dir")
ls -id "$dir" | awk '{print $1}'
}
linux_min_version()
{
linux_min_version() {
# $1 - major ver
# $2 - minor ver
local V1=$(sed -nre 's/^Linux version ([0-9]+)\.[0-9]+.*$/\1/p' /proc/version)
local V2=$(sed -nre 's/^Linux version [0-9]+\.([0-9]+).*$/\1/p' /proc/version)
[ -n "$V1" -a -n "$V2" ] && [ "$V1" -gt "$1" -o "$V1" -eq "$1" -a "$V2" -ge "$2" ]
}
linux_get_subsys()
{
linux_get_subsys() {
local INIT="$(sed 's/\x0/\n/g' /proc/1/cmdline | head -n 1)"
[ -L "$INIT" ] && INIT=$(readlink "$INIT")
INIT="$(basename "$INIT")"
if [ -f "/etc/openwrt_release" ] && [ "$INIT" = "procd" ] ; then
if [ -f "/etc/openwrt_release" ] && [ "$INIT" = "procd" ]; then
SUBSYS=openwrt
elif [ -x "/bin/ndm" ] ; then
elif [ -x "/bin/ndm" ]; then
SUBSYS=keenetic
else
# generic linux
SUBSYS=
fi
}
openwrt_fw3()
{
openwrt_fw3() {
[ ! -x /sbin/fw4 -a -x /sbin/fw3 ]
}
openwrt_fw4()
{
openwrt_fw4() {
[ -x /sbin/fw4 ]
}
openwrt_fw3_integration()
{
openwrt_fw3_integration() {
[ "$FWTYPE" = iptables ] && openwrt_fw3
}
create_dev_stdin()
{
create_dev_stdin() {
[ -e /dev/stdin ] || ln -s /proc/self/fd/0 /dev/stdin
}
call_for_multiple_items()
{
call_for_multiple_items() {
# $1 - function to get an item
# $2 - variable name to put result into
# $3 - space separated parameters to function $1
local i item items
for i in $3; do
$1 item $i
$1 item "$i"
[ -n "$item" ] && {
if [ -n "$items" ]; then
items="$items $item"
@@ -199,91 +177,85 @@ call_for_multiple_items()
fi
}
done
eval $2=\"$items\"
eval "$2"=\""$items"\"
}
fix_sbin_path()
{
fix_sbin_path() {
local IFS=':'
printf "%s\n" $PATH | grep -Fxq '/usr/sbin' || PATH="/usr/sbin:$PATH"
printf "%s\n" $PATH | grep -Fxq '/sbin' || PATH="/sbin:$PATH"
printf "%s\n" "$PATH" | grep -Fxq '/usr/sbin' || PATH="/usr/sbin:$PATH"
printf "%s\n" "$PATH" | grep -Fxq '/sbin' || PATH="/sbin:$PATH"
export PATH
}
# it can calculate floating point expr
calc()
{
awk "BEGIN { print $*}";
calc() {
awk "BEGIN { print $*}"
}
fsleep_setup()
{
[ -n "$FSLEEP" ] || {
if sleep 0.001 2>/dev/null; then
FSLEEP=1
elif busybox usleep 1 2>/dev/null; then
FSLEEP=2
else
local errtext="$(read -t 0.001 2>&1)"
if [ -z "$errtext" ]; then
FSLEEP=3
# newer openwrt has ucode with system function that supports timeout in ms
elif ucode -e "system(['sleep','1'], 1)" 2>/dev/null; then
FSLEEP=4
# older openwrt may have lua and nixio lua module
elif lua -e 'require "nixio".nanosleep(0,1)' 2>/dev/null ; then
FSLEEP=5
fsleep_setup() {
[ -n "$FSLEEP" ] || {
if sleep 0.001 2>/dev/null; then
FSLEEP=1
elif busybox usleep 1 2>/dev/null; then
FSLEEP=2
else
FSLEEP=0
local errtext="$(read -t 0.001 2>&1)"
if [ -z "$errtext" ]; then
FSLEEP=3
# newer OpenWrt has ucode with system function that supports timeout in ms
elif ucode -e "system(['sleep','1'], 1)" 2>/dev/null; then
FSLEEP=4
# older OpenWrt may have lua and nixio lua module
elif lua -e 'require "nixio".nanosleep(0,1)' 2>/dev/null; then
FSLEEP=5
else
FSLEEP=0
fi
fi
fi
}
}
}
msleep()
{
# $1 - milliseconds
case "$FSLEEP" in
msleep() {
# $1 - milliseconds
case "$FSLEEP" in
1)
sleep $(calc $1/1000)
sleep $(calc "$1"/1000)
;;
2)
busybox usleep $(calc $1*1000)
busybox usleep $(calc "$1"*1000)
;;
3)
read -t $(calc $1/1000)
read -t $(calc "$1"/1000)
;;
4)
ucode -e "system(['sleep','2147483647'], $1)"
;;
5)
lua -e "require 'nixio'.nanosleep($(($1/1000)),$(calc $1%1000*1000000))"
lua -e "require 'nixio'.nanosleep($(($1 / 1000)),$(calc "$1"%1000*1000000))"
;;
*)
sleep $((($1+999)/1000))
esac
*)
sleep $((($1 + 999) / 1000))
;;
esac
}
minsleep()
{
minsleep() {
msleep 100
}
replace_char()
{
replace_char() {
local a=$1
local b=$2
shift; shift
echo "$@" | tr $a $b
shift
shift
echo "$@" | tr "$a" "$b"
}
setup_md5()
{
setup_md5() {
[ -n "$MD5" ] && return
MD5=md5sum
exists $MD5 || MD5=md5
}
random()
{
random() {
# $1 - min, $2 - max
local r rs
setup_md5
@@ -293,12 +265,11 @@ random()
rs="$RANDOM$RANDOM$(date)"
fi
# shells use signed int64
r=1$(echo $rs | $MD5 | sed 's/[^0-9]//g' | cut -c 1-17)
echo $(( ($r % ($2-$1+1)) + $1 ))
r=1$(echo "$rs" | $MD5 | sed 's/[^0-9]//g' | cut -c 1-17)
echo $((($r % ($2 - $1 + 1)) + $1))
}
shell_name()
{
shell_name() {
[ -n "$SHELL_NAME" ] || {
[ -n "$UNAME" ] || UNAME="$(uname)"
@@ -313,12 +284,11 @@ shell_name()
}
}
std_ports()
{
HTTP_PORTS=${HTTP_PORTS:-80}
std_ports() {
HTTP_PORTS=${HTTP_PORTS:-80}
HTTPS_PORTS=${HTTPS_PORTS:-443}
QUIC_PORTS=${QUIC_PORTS:-443}
HTTP_PORTS_IPT=$(replace_char - : $HTTP_PORTS)
HTTPS_PORTS_IPT=$(replace_char - : $HTTPS_PORTS)
QUIC_PORTS_IPT=$(replace_char - : $QUIC_PORTS)
HTTP_PORTS_IPT=$(replace_char - : "$HTTP_PORTS")
HTTPS_PORTS_IPT=$(replace_char - : "$HTTPS_PORTS")
QUIC_PORTS_IPT=$(replace_char - : "$QUIC_PORTS")
}

View File

@@ -1,36 +1,32 @@
read_yes_no()
{
read_yes_no() {
# $1 - default (Y/N)
local A
read A
[ -z "$A" ] || ([ "$A" != "Y" ] && [ "$A" != "y" ] && [ "$A" != "N" ] && [ "$A" != "n" ]) && A=$1
[ "$A" = "Y" ] || [ "$A" = "y" ] || [ "$A" = "1" ]
}
ask_yes_no()
{
ask_yes_no() {
# $1 - default (Y/N or 0/1)
# $2 - text
local DEFAULT=$1
[ "$1" = "1" ] && DEFAULT=Y
[ "$1" = "0" ] && DEFAULT=N
[ -z "$DEFAULT" ] && DEFAULT=N
printf "$2 (default : $DEFAULT) (Y/N) ? "
read_yes_no $DEFAULT
printf "$2 (default: $DEFAULT) (Y/N)?"
read_yes_no "$DEFAULT"
}
ask_yes_no_var()
{
# $1 - variable name for answer : 0/1
ask_yes_no_var() {
# $1 - variable name for answer: 0/1
# $2 - text
local DEFAULT
eval DEFAULT="\$$1"
if ask_yes_no "$DEFAULT" "$2"; then
eval $1=1
eval "$1"=1
else
eval $1=0
eval "$1"=0
fi
}
ask_list()
{
ask_list() {
# $1 - mode var
# $2 - space separated value list
# $3 - (optional) default value
@@ -39,20 +35,20 @@ ask_list()
local M_ALL=$M_DEFAULT
local M=""
local m
[ -n "$3" ] && { find_str_in_list "$M_DEFAULT" "$2" || M_DEFAULT="$3" ;}
[ -n "$3" ] && { find_str_in_list "$M_DEFAULT" "$2" || M_DEFAULT="$3"; }
n=1
for m in $2; do
echo $n : $m
n=$(($n+1))
echo $n: "$m"
n=$(($n + 1))
done
printf "your choice (default : $M_DEFAULT) : "
read m
[ -n "$m" ] && M=$(echo $2 | cut -d ' ' -f$m 2>/dev/null)
[ -n "$m" ] && M=$(echo "$2" | cut -d ' ' -f"$m" 2>/dev/null)
[ -z "$M" ] && M="$M_DEFAULT"
echo selected : $M
eval $1="\"$M\""
echo selected: "$M"
eval "$1"="\"$M\""
[ "$M" != "$M_OLD" ]
}

View File

@@ -1,5 +1,4 @@
require_root()
{
require_root() {
local exe
echo \* checking privileges
[ $(id -u) -ne "0" ] && {

View File

@@ -1,25 +1,21 @@
linux_ipt_avail()
{
linux_ipt_avail() {
exists iptables && exists ip6tables
}
linux_maybe_iptables_fwtype()
{
linux_maybe_iptables_fwtype() {
linux_ipt_avail && FWTYPE=iptables
}
linux_nft_avail()
{
linux_nft_avail() {
exists nft
}
linux_fwtype()
{
linux_fwtype() {
[ -n "$FWTYPE" ] && return
FWTYPE=unsupported
linux_get_subsys
if [ "$SUBSYS" = openwrt ] ; then
# linux kernel is new enough if fw4 is there
if [ -x /sbin/fw4 ] && linux_nft_avail ; then
if [ "$SUBSYS" = openwrt ]; then
# Linux kernel is new enough if fw4 is there
if [ -x /sbin/fw4 ] && linux_nft_avail; then
FWTYPE=nftables
else
linux_maybe_iptables_fwtype
@@ -38,26 +34,25 @@ linux_fwtype()
export FWTYPE
}
get_fwtype()
{
get_fwtype() {
[ -n "$FWTYPE" ] && return
local UNAME="$(uname)"
case "$UNAME" in
Linux)
linux_fwtype
;;
FreeBSD)
if exists ipfw ; then
FWTYPE=ipfw
else
FWTYPE=unsupported
fi
;;
*)
Linux)
linux_fwtype
;;
FreeBSD)
if exists ipfw; then
FWTYPE=ipfw
else
FWTYPE=unsupported
;;
fi
;;
*)
FWTYPE=unsupported
;;
esac
export FWTYPE

View File

@@ -6,36 +6,31 @@ SYSTEMD_DIR=/lib/systemd
INIT_SCRIPT=/etc/init.d/zapret
exitp()
{
exitp() {
echo
echo press enter to continue
read A
exit $1
exit "$1"
}
parse_var_checked()
{
parse_var_checked() {
# $1 - file name
# $2 - var name
local sed="sed -nre s/^[[:space:]]*$2=[\\\"|\']?([^\\\"|\']*)[\\\"|\']?/\1/p"
local v="$($sed <"$1" | tail -n 1)"
eval $2=\"$v\"
eval "$2"=\""$v"\"
}
parse_vars_checked()
{
parse_vars_checked() {
# $1 - file name
# $2,$3,... - var names
local f="$1"
shift
while [ -n "$1" ]; do
parse_var_checked "$f" $1
parse_var_checked "$f" "$1"
shift
done
done
}
edit_file()
{
edit_file() {
# $1 - file name
local ed="$EDITOR"
[ -n "$ed" ] || {
@@ -48,8 +43,7 @@ edit_file()
}
[ -n "$ed" ] && "$ed" "$1"
}
edit_vars()
{
edit_vars() {
# $1,$2,... - var names
local n=1 var v tmp="/tmp/zvars"
rm -f "$tmp"
@@ -57,21 +51,19 @@ edit_vars()
eval var="\$$n"
[ -n "$var" ] || break
eval v="\$$var"
echo $var=\"$v\" >>"$tmp"
n=$(($n+1))
echo "$var"=\""$v"\" >>"$tmp"
n=$(($n + 1))
done
edit_file "$tmp" && parse_vars_checked "$tmp" "$@"
rm -f "$tmp"
}
openrc_test()
{
openrc_test() {
exists rc-update || return 1
# some systems do not usse openrc-init but launch openrc from inittab
[ "$INIT" = "openrc-init" ] || grep -qE "sysinit.*openrc" /etc/inittab 2>/dev/null
}
check_system()
{
check_system() {
# $1 - nonempty = do not fail on unknown rc system
echo \* checking system
@@ -93,21 +85,21 @@ check_system()
# some distros include systemctl without systemd
if [ -d "$SYSTEMD_DIR" ] && [ -x "$SYSTEMCTL" ] && [ "$INIT" = "systemd" ]; then
SYSTEM=systemd
elif [ -f "/etc/openwrt_release" ] && exists opkg && exists uci && [ "$INIT" = "procd" ] ; then
{
SYSTEM=openwrt
if openwrt_fw3 ; then
OPENWRT_FW3=1
info="openwrt firewall uses fw3"
if is_ipt_flow_offload_avail; then
info="$info. hardware flow offloading requires iptables."
else
info="$info. flow offloading unavailable."
elif [ -f "/etc/openwrt_release" ] && exists opkg && exists uci && [ "$INIT" = "procd" ]; then
{
SYSTEM=openwrt
if openwrt_fw3; then
OPENWRT_FW3=1
info="openwrt firewall uses fw3"
if is_ipt_flow_offload_avail; then
info="$info. hardware flow offloading requires iptables."
else
info="$info. flow offloading unavailable."
fi
elif openwrt_fw4; then
info="openwrt firewall uses fw4. flow offloading requires nftables."
fi
elif openwrt_fw4; then
info="openwrt firewall uses fw4. flow offloading requires nftables."
fi
}
}
elif openrc_test; then
SYSTEM=openrc
else
@@ -115,9 +107,9 @@ check_system()
echo easy installer can set up config settings but can\'t configure auto start
echo you have to do it manually. check readme.txt for manual setup info.
if [ -n "$1" ] || ask_yes_no N "do you want to continue"; then
SYSTEM=linux
SYSTEM=linux
else
exitp 5
exitp 5
fi
fi
linux_get_subsys
@@ -128,25 +120,21 @@ check_system()
exitp 5
fi
echo system is based on $SYSTEM
[ -n "$info" ] && echo $info
[ -n "$info" ] && echo "$info"
}
get_free_space_mb()
{
df -m $PWD | awk '/[0-9]%/{print $(NF-2)}'
get_free_space_mb() {
df -m "$PWD" | awk '/[0-9]%/{print $(NF-2)}'
}
get_ram_kb()
{
grep MemTotal /proc/meminfo | awk '{print $2}'
get_ram_kb() {
grep MemTotal /proc/meminfo | awk '{print $2}'
}
get_ram_mb()
{
local R=$(get_ram_kb)
echo $(($R/1024))
get_ram_mb() {
local R=$(get_ram_kb)
echo $(($R / 1024))
}
crontab_del()
{
crontab_del() {
exists crontab || return
echo \* removing crontab entry
@@ -162,8 +150,7 @@ crontab_del()
fi
rm -f $CRONTMP
}
crontab_del_quiet()
{
crontab_del_quiet() {
exists crontab || return
CRONTMP=/tmp/cron.tmp
@@ -175,11 +162,10 @@ crontab_del_quiet()
fi
rm -f $CRONTMP
}
crontab_add()
{
crontab_add() {
# $1 - hour min
# $2 - hour max
[ -x "$GET_LIST" ] && {
[ -x "$GET_LIST" ] && {
echo \* adding crontab entry
if exists crontab; then
@@ -190,7 +176,7 @@ crontab_add()
grep "$GET_LIST_PREFIX" $CRONTMP
else
end_with_newline <"$CRONTMP" || echo >>"$CRONTMP"
echo "$(random 0 59) $(random $1 $2) */2 * * $GET_LIST" >>$CRONTMP
echo "$(random 0 59) $(random "$1" "$2") */2 * * $GET_LIST" >>$CRONTMP
crontab $CRONTMP
fi
rm -f $CRONTMP
@@ -199,18 +185,15 @@ crontab_add()
fi
}
}
cron_ensure_running()
{
# if no crontabs present in /etc/cron openwrt init script does not launch crond. this is default
cron_ensure_running() {
# if no crontabs present in /etc/cron OpenWrt init script does not launch crond. this is default
[ "$SYSTEM" = "openwrt" ] && {
/etc/init.d/cron enable
/etc/init.d/cron start
}
}
service_start_systemd()
{
service_start_systemd() {
echo \* starting zapret service
"$SYSTEMCTL" start zapret || {
@@ -218,23 +201,20 @@ service_start_systemd()
exitp 30
}
}
service_stop_systemd()
{
service_stop_systemd() {
echo \* stopping zapret service
"$SYSTEMCTL" daemon-reload
"$SYSTEMCTL" disable zapret
"$SYSTEMCTL" stop zapret
}
service_remove_systemd()
{
service_remove_systemd() {
echo \* removing zapret service
rm -f "$SYSTEMD_SYSTEM_DIR/zapret.service"
"$SYSTEMCTL" daemon-reload
}
timer_remove_systemd()
{
timer_remove_systemd() {
echo \* removing zapret-list-update timer
"$SYSTEMCTL" daemon-reload
@@ -244,8 +224,7 @@ timer_remove_systemd()
"$SYSTEMCTL" daemon-reload
}
install_sysv_init()
{
install_sysv_init() {
# $1 - "0"=disable
echo \* installing init script
@@ -256,8 +235,7 @@ install_sysv_init()
ln -fs "$INIT_SCRIPT_SRC" "$INIT_SCRIPT"
[ "$1" != "0" ] && "$INIT_SCRIPT" enable
}
install_openrc_init()
{
install_openrc_init() {
# $1 - "0"=disable
echo \* installing init script
@@ -268,8 +246,7 @@ install_openrc_init()
ln -fs "$INIT_SCRIPT_SRC" "$INIT_SCRIPT"
[ "$1" != "0" ] && rc-update add zapret
}
service_remove_openrc()
{
service_remove_openrc() {
echo \* removing zapret service
[ -x "$INIT_SCRIPT" ] && {
@@ -278,8 +255,7 @@ service_remove_openrc()
}
rm -f "$INIT_SCRIPT"
}
service_start_sysv()
{
service_start_sysv() {
[ -x "$INIT_SCRIPT" ] && {
echo \* starting zapret service
"$INIT_SCRIPT" start || {
@@ -288,15 +264,13 @@ service_start_sysv()
}
}
}
service_stop_sysv()
{
service_stop_sysv() {
[ -x "$INIT_SCRIPT" ] && {
echo \* stopping zapret service
"$INIT_SCRIPT" stop
}
}
service_remove_sysv()
{
service_remove_sysv() {
echo \* removing zapret service
[ -x "$INIT_SCRIPT" ] && {
@@ -306,104 +280,91 @@ service_remove_sysv()
rm -f "$INIT_SCRIPT"
}
check_kmod()
{
check_kmod() {
[ -f "/lib/modules/$(uname -r)/$1.ko" ]
}
check_package_exists_openwrt()
{
[ -n "$(opkg list $1)" ]
check_package_exists_openwrt() {
[ -n "$(opkg list "$1")" ]
}
check_package_openwrt()
{
[ -n "$(opkg list-installed $1)" ] && return 0
local what="$(opkg whatprovides $1 | tail -n +2 | head -n 1)"
check_package_openwrt() {
[ -n "$(opkg list-installed "$1")" ] && return 0
local what="$(opkg whatprovides "$1" | tail -n +2 | head -n 1)"
[ -n "$what" ] || return 1
[ -n "$(opkg list-installed $what)" ]
[ -n "$(opkg list-installed "$what")" ]
}
check_packages_openwrt()
{
check_packages_openwrt() {
for pkg in $@; do
check_package_openwrt $pkg || return
check_package_openwrt "$pkg" || return
done
}
install_openwrt_iface_hook()
{
install_openwrt_iface_hook() {
echo \* installing ifup hook
ln -fs "$OPENWRT_IFACE_HOOK" /etc/hotplug.d/iface
}
remove_openwrt_iface_hook()
{
remove_openwrt_iface_hook() {
echo \* removing ifup hook
rm -f /etc/hotplug.d/iface/??-zapret
}
openwrt_fw_section_find()
{
openwrt_fw_section_find() {
# $1 - fw include postfix
# echoes section number
i=0
while true
do
while true; do
path=$(uci -q get firewall.@include[$i].path)
[ -n "$path" ] || break
[ "$path" = "$OPENWRT_FW_INCLUDE$1" ] && {
echo $i
return 0
echo $i
return 0
}
i=$(($i+1))
i=$(($i + 1))
done
return 1
}
openwrt_fw_section_del()
{
openwrt_fw_section_del() {
# $1 - fw include postfix
local id="$(openwrt_fw_section_find $1)"
local id="$(openwrt_fw_section_find "$1")"
[ -n "$id" ] && {
uci delete firewall.@include[$id] && uci commit firewall
uci delete firewall.@include["$id"] && uci commit firewall
rm -f "$OPENWRT_FW_INCLUDE$1"
}
}
openwrt_fw_section_add()
{
openwrt_fw_section_add() {
openwrt_fw_section_find ||
{
uci add firewall include >/dev/null || return
echo -1
}
{
uci add firewall include >/dev/null || return
echo -1
}
}
openwrt_fw_section_configure()
{
local id="$(openwrt_fw_section_add $1)"
openwrt_fw_section_configure() {
local id="$(openwrt_fw_section_add "$1")"
[ -z "$id" ] ||
! uci set firewall.@include[$id].path="$OPENWRT_FW_INCLUDE" ||
! uci set firewall.@include[$id].reload="1" ||
! uci commit firewall &&
{
echo could not add firewall include
exitp 50
}
! uci set firewall.@include["$id"].path="$OPENWRT_FW_INCLUDE" ||
! uci set firewall.@include["$id"].reload="1" ||
! uci commit firewall &&
{
echo could not add firewall include
exitp 50
}
}
install_openwrt_firewall()
{
echo \* installing firewall script $1
install_openwrt_firewall() {
echo \* installing firewall script "$1"
[ -n "MODE" ] || {
echo should specify MODE in $ZAPRET_CONFIG
echo should specify MODE in "$ZAPRET_CONFIG"
exitp 7
}
echo "linking : $FW_SCRIPT_SRC => $OPENWRT_FW_INCLUDE"
echo "linking: $FW_SCRIPT_SRC => $OPENWRT_FW_INCLUDE"
ln -fs "$FW_SCRIPT_SRC" "$OPENWRT_FW_INCLUDE"
openwrt_fw_section_configure $1
openwrt_fw_section_configure "$1"
}
restart_openwrt_firewall()
{
restart_openwrt_firewall() {
echo \* restarting firewall
local FW=fw4
@@ -413,52 +374,44 @@ restart_openwrt_firewall()
exitp 30
}
}
remove_openwrt_firewall()
{
remove_openwrt_firewall() {
echo \* removing firewall script
openwrt_fw_section_del
# from old zapret versions. now we use single include
openwrt_fw_section_del 6
}
clear_ipset()
{
clear_ipset() {
echo "* clearing ipset(s)"
# free some RAM
"$IPSET_DIR/create_ipset.sh" clear
}
service_install_macos()
{
service_install_macos() {
echo \* installing zapret service
ln -fs "$ZAPRET_BASE/init.d/macos/zapret.plist" /Library/LaunchDaemons
}
service_start_macos()
{
service_start_macos() {
echo \* starting zapret service
"$INIT_SCRIPT_SRC" start
}
service_stop_macos()
{
service_stop_macos() {
echo \* stopping zapret service
"$INIT_SCRIPT_SRC" stop
}
service_remove_macos()
{
service_remove_macos() {
echo \* removing zapret service
rm -f /Library/LaunchDaemons/zapret.plist
zapret_stop_daemons
}
remove_macos_firewall()
{
remove_macos_firewall() {
echo \* removing zapret PF hooks
pf_anchors_clear
@@ -467,9 +420,8 @@ remove_macos_firewall()
pf_anchor_root_reload
}
sedi()
{
# MacOS doesnt support -i without parameter. busybox doesnt support -i with parameter.
sedi() {
# macOS doesnt support -i without parameter. busybox doesnt support -i with parameter.
# its not possible to put "sed -i ''" to a variable and then use it
if [ "$SYSTEM" = "macos" ]; then
sed -i '' "$@"
@@ -478,8 +430,7 @@ sedi()
fi
}
write_config_var()
{
write_config_var() {
# $1 - mode var
local M
eval M="\$$1"
@@ -487,7 +438,7 @@ write_config_var()
if grep -q "^$1=\|^#$1=" "$ZAPRET_CONFIG"; then
# replace / => \/
#M=${M//\//\\\/}
M=$(echo $M | sed 's/\//\\\//g')
M=$(echo "$M" | sed 's/\//\\\//g')
if [ -n "$M" ]; then
if contains "$M" " "; then
sedi -Ee "s/^#?$1=.*$/$1=\"$M\"/" "$ZAPRET_CONFIG"
@@ -508,37 +459,36 @@ write_config_var()
fi
}
check_prerequisites_linux()
{
check_prerequisites_linux() {
echo \* checking prerequisites
local s cmd PKGS UTILS req="curl curl"
case "$FWTYPE" in
iptables)
req="$req iptables iptables ip6tables iptables ipset ipset"
;;
nftables)
req="$req nft nftables"
;;
iptables)
req="$req iptables iptables ip6tables iptables ipset ipset"
;;
nftables)
req="$req nft nftables"
;;
esac
PKGS=$(for s in $req; do echo $s; done |
PKGS=$(for s in $req; do echo "$s"; done |
while read cmd; do
read pkg
exists $cmd || echo $pkg
exists "$cmd" || echo "$pkg"
done | sort -u | xargs)
UTILS=$(for s in $req; do echo $s; done |
UTILS=$(for s in $req; do echo "$s"; done |
while read cmd; do
read pkg
echo $cmd
echo "$cmd"
done | sort -u | xargs)
if [ -z "$PKGS" ] ; then
echo required utilities exist : $UTILS
if [ -z "$PKGS" ]; then
echo required utilities exist: "$UTILS"
else
echo \* installing prerequisites
echo packages required : $PKGS
echo packages required: "$PKGS"
APTGET=$(whichq apt-get)
YUM=$(whichq yum)
@@ -546,78 +496,77 @@ check_prerequisites_linux()
ZYPPER=$(whichq zypper)
EOPKG=$(whichq eopkg)
APK=$(whichq apk)
if [ -x "$APTGET" ] ; then
if [ -x "$APTGET" ]; then
"$APTGET" update
"$APTGET" install -y --no-install-recommends $PKGS dnsutils || {
"$APTGET" install -y --no-install-recommends "$PKGS" dnsutils || {
echo could not install prerequisites
exitp 6
}
elif [ -x "$YUM" ] ; then
"$YUM" -y install $PKGS || {
elif [ -x "$YUM" ]; then
"$YUM" -y install "$PKGS" || {
echo could not install prerequisites
exitp 6
}
elif [ -x "$PACMAN" ] ; then
elif [ -x "$PACMAN" ]; then
"$PACMAN" -Syy
"$PACMAN" --noconfirm -S $PKGS || {
"$PACMAN" --noconfirm -S "$PKGS" || {
echo could not install prerequisites
exitp 6
}
elif [ -x "$ZYPPER" ] ; then
"$ZYPPER" --non-interactive install $PKGS || {
elif [ -x "$ZYPPER" ]; then
"$ZYPPER" --non-interactive install "$PKGS" || {
echo could not install prerequisites
exitp 6
}
elif [ -x "$EOPKG" ] ; then
"$EOPKG" -y install $PKGS || {
elif [ -x "$EOPKG" ]; then
"$EOPKG" -y install "$PKGS" || {
echo could not install prerequisites
exitp 6
}
elif [ -x "$APK" ] ; then
elif [ -x "$APK" ]; then
"$APK" update
# for alpine
[ "$FWTYPE" = iptables ] && [ -n "$($APK list ip6tables)" ] && PKGS="$PKGS ip6tables"
"$APK" add $PKGS || {
"$APK" add "$PKGS" || {
echo could not install prerequisites
exitp 6
}
else
echo supported package manager not found
echo you must manually install : $UTILS
echo you must manually install: "$UTILS"
exitp 5
fi
fi
}
check_prerequisites_openwrt()
{
check_prerequisites_openwrt() {
echo \* checking prerequisites
local PKGS="curl" UPD=0
case "$FWTYPE" in
iptables)
PKGS="$PKGS ipset iptables iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra"
[ "$DISABLE_IPV6" != "1" ] && PKGS="$PKGS ip6tables ip6tables-mod-nat ip6tables-extra"
;;
nftables)
PKGS="$PKGS nftables kmod-nft-nat kmod-nft-offload kmod-nft-queue"
;;
iptables)
PKGS="$PKGS ipset iptables iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra"
[ "$DISABLE_IPV6" != "1" ] && PKGS="$PKGS ip6tables ip6tables-mod-nat ip6tables-extra"
;;
nftables)
PKGS="$PKGS nftables kmod-nft-nat kmod-nft-offload kmod-nft-queue"
;;
esac
if check_packages_openwrt $PKGS ; then
if check_packages_openwrt "$PKGS"; then
echo everything is present
else
echo \* installing prerequisites
opkg update
UPD=1
opkg install $PKGS || {
opkg install "$PKGS" || {
echo could not install prerequisites
exitp 6
}
fi
is_linked_to_busybox gzip && {
echo
echo your system uses default busybox gzip. its several times slower than GNU gzip.
@@ -659,10 +608,7 @@ check_prerequisites_openwrt()
}
}
select_ipv6()
{
select_ipv6() {
local T=N
[ "$DISABLE_IPV6" != '1' ] && T=Y
@@ -675,8 +621,7 @@ select_ipv6()
fi
[ "$old6" != "$DISABLE_IPV6" ] && write_config_var DISABLE_IPV6
}
select_fwtype()
{
select_fwtype() {
echo
[ $(get_ram_mb) -le 400 ] && {
echo WARNING ! you are running a low RAM system

View File

@@ -1,55 +1,43 @@
std_ports
readonly ipt_connbytes="-m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes"
ipt()
{
ipt() {
iptables -C "$@" >/dev/null 2>/dev/null || iptables -I "$@"
}
ipta()
{
ipta() {
iptables -C "$@" >/dev/null 2>/dev/null || iptables -A "$@"
}
ipt_del()
{
ipt_del() {
iptables -C "$@" >/dev/null 2>/dev/null && iptables -D "$@"
}
ipt_add_del()
{
ipt_add_del() {
on_off_function ipt ipt_del "$@"
}
ipta_add_del()
{
ipta_add_del() {
on_off_function ipta ipt_del "$@"
}
ipt6()
{
ipt6() {
ip6tables -C "$@" >/dev/null 2>/dev/null || ip6tables -I "$@"
}
ipt6a()
{
ipt6a() {
ip6tables -C "$@" >/dev/null 2>/dev/null || ip6tables -A "$@"
}
ipt6_del()
{
ipt6_del() {
ip6tables -C "$@" >/dev/null 2>/dev/null && ip6tables -D "$@"
}
ipt6_add_del()
{
ipt6_add_del() {
on_off_function ipt6 ipt6_del "$@"
}
ipt6a_add_del()
{
ipt6a_add_del() {
on_off_function ipt6 ipt6a_del "$@"
}
is_ipt_flow_offload_avail()
{
# $1 = '' for ipv4, '6' for ipv6
grep -q FLOWOFFLOAD 2>/dev/null /proc/net/ip$1_tables_targets
is_ipt_flow_offload_avail() {
# $1 = '' for IPv4, '6' for IPv6
grep -q FLOWOFFLOAD /proc/net/ip"$1"_tables_targets 2>/dev/null
}
filter_apply_port_target()
{
filter_apply_port_target() {
# $1 - var name of iptables filter
local f
if [ "$MODE_HTTP" = "1" ] && [ "$MODE_HTTPS" = "1" ]; then
@@ -61,62 +49,54 @@ filter_apply_port_target()
else
echo WARNING !!! HTTP and HTTPS are both disabled
fi
eval $1="\"\$$1 $f\""
eval "$1"="\"\$$1 $f\""
}
filter_apply_port_target_quic()
{
filter_apply_port_target_quic() {
# $1 - var name of nftables filter
local f
f="-p udp -m multiport --dports $QUIC_PORTS_IPT"
eval $1="\"\$$1 $f\""
eval "$1"="\"\$$1 $f\""
}
filter_apply_ipset_target4()
{
filter_apply_ipset_target4() {
# $1 - var name of ipv4 iptables filter
if [ "$MODE_FILTER" = "ipset" ]; then
eval $1="\"\$$1 -m set --match-set zapret dst\""
eval "$1"="\"\$$1 -m set --match-set zapret dst\""
fi
}
filter_apply_ipset_target6()
{
filter_apply_ipset_target6() {
# $1 - var name of ipv6 iptables filter
if [ "$MODE_FILTER" = "ipset" ]; then
eval $1="\"\$$1 -m set --match-set zapret6 dst\""
eval "$1"="\"\$$1 -m set --match-set zapret6 dst\""
fi
}
filter_apply_ipset_target()
{
filter_apply_ipset_target() {
# $1 - var name of ipv4 iptables filter
# $2 - var name of ipv6 iptables filter
filter_apply_ipset_target4 $1
filter_apply_ipset_target6 $2
filter_apply_ipset_target4 "$1"
filter_apply_ipset_target6 "$2"
}
reverse_nfqws_rule_stream()
{
reverse_nfqws_rule_stream() {
sed -e 's/-o /-i /g' -e 's/--dport /--sport /g' -e 's/--dports /--sports /g' -e 's/ dst$/ src/' -e 's/ dst / src /g' -e 's/--connbytes-dir=original/--connbytes-dir=reply/g' -e "s/-m mark ! --mark $DESYNC_MARK\/$DESYNC_MARK//g"
}
reverse_nfqws_rule()
{
reverse_nfqws_rule() {
echo "$@" | reverse_nfqws_rule_stream
}
prepare_tpws_fw4()
{
# otherwise linux kernel will treat 127.0.0.0/8 as "martian" ip and refuse routing to it
# NOTE : kernels <3.6 do not have this feature. consider upgrading or change DNAT to REDIRECT and do not bind to 127.0.0.0/8
prepare_tpws_fw4() {
# otherwise Linux kernel will treat 127.0.0.0/8 as "martian" ip and refuse routing to it
# NOTE: kernels <3.6 do not have this feature. consider upgrading or change DNAT to REDIRECT and do not bind to 127.0.0.0/8
[ "$DISABLE_IPV4" = "1" ] || {
iptables -N input_rule_zapret 2>/dev/null
ipt input_rule_zapret -d $TPWS_LOCALHOST4 -j RETURN
ipt input_rule_zapret -d "$TPWS_LOCALHOST4" -j RETURN
ipta input_rule_zapret -d 127.0.0.0/8 -j DROP
ipt INPUT ! -i lo -j input_rule_zapret
prepare_route_localnet
}
}
unprepare_tpws_fw4()
{
unprepare_tpws_fw4() {
[ "$DISABLE_IPV4" = "1" ] || {
unprepare_route_localnet
@@ -125,14 +105,11 @@ unprepare_tpws_fw4()
iptables -X input_rule_zapret 2>/dev/null
}
}
unprepare_tpws_fw()
{
unprepare_tpws_fw() {
unprepare_tpws_fw4
}
ipt_print_op()
{
ipt_print_op() {
if [ "$1" = "1" ]; then
echo "Adding ip$4tables rule for $3 : $2"
else
@@ -140,8 +117,7 @@ ipt_print_op()
fi
}
_fw_tpws4()
{
_fw_tpws4() {
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv4
# $3 - tpws port
@@ -152,25 +128,24 @@ _fw_tpws4()
[ "$1" = 1 ] && prepare_tpws_fw4
ipt_print_op $1 "$2" "tpws (port $3)"
ipt_print_op "$1" "$2" "tpws (port $3)"
rule="$2 $IPSET_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3"
for i in $4 ; do
ipt_add_del $1 PREROUTING -t nat -i $i $rule
done
for i in $4; do
ipt_add_del "$1" PREROUTING -t nat -i "$i" "$rule"
done
rule="-m owner ! --uid-owner $WS_USER $rule"
if [ -n "$5" ]; then
for i in $5; do
ipt_add_del $1 OUTPUT -t nat -o $i $rule
ipt_add_del "$1" OUTPUT -t nat -o "$i" "$rule"
done
else
ipt_add_del $1 OUTPUT -t nat $rule
ipt_add_del "$1" OUTPUT -t nat "$rule"
fi
}
}
_fw_tpws6()
{
_fw_tpws6() {
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv6
# $3 - tpws port
@@ -180,37 +155,34 @@ _fw_tpws6()
[ "$DISABLE_IPV6" = "1" -o -z "$2" ] || {
local i rule DNAT6
ipt_print_op $1 "$2" "tpws (port $3)" 6
ipt_print_op "$1" "$2" "tpws (port $3)" 6
rule="$2 $IPSET_EXCLUDE6 dst"
for i in $4 ; do
_dnat6_target $i DNAT6
[ -n "$DNAT6" -a "$DNAT6" != "-" ] && ipt6_add_del $1 PREROUTING -t nat -i $i $rule -j DNAT --to [$DNAT6]:$3
done
for i in $4; do
_dnat6_target "$i" DNAT6
[ -n "$DNAT6" -a "$DNAT6" != "-" ] && ipt6_add_del "$1" PREROUTING -t nat -i "$i" "$rule" -j DNAT --to ["$DNAT6"]:"$3"
done
rule="-m owner ! --uid-owner $WS_USER $rule -j DNAT --to [::1]:$3"
if [ -n "$5" ]; then
for i in $5; do
ipt6_add_del $1 OUTPUT -t nat -o $i $rule
ipt6_add_del "$1" OUTPUT -t nat -o "$i" "$rule"
done
else
ipt6_add_del $1 OUTPUT -t nat $rule
ipt6_add_del "$1" OUTPUT -t nat "$rule"
fi
}
}
fw_tpws()
{
fw_tpws() {
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv4
# $3 - iptable filter for ipv6
# $4 - tpws port
fw_tpws4 $1 "$2" $4
fw_tpws6 $1 "$3" $4
fw_tpws4 "$1" "$2" "$4"
fw_tpws6 "$1" "$3" "$4"
}
_fw_nfqws_post4()
{
_fw_nfqws_post4() {
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv4
# $3 - queue number
@@ -218,20 +190,19 @@ _fw_nfqws_post4()
[ "$DISABLE_IPV4" = "1" -o -z "$2" ] || {
local i
ipt_print_op $1 "$2" "nfqws postrouting (qnum $3)"
ipt_print_op "$1" "$2" "nfqws postrouting (qnum $3)"
rule="$2 $IPSET_EXCLUDE dst -j NFQUEUE --queue-num $3 --queue-bypass"
if [ -n "$4" ] ; then
if [ -n "$4" ]; then
for i in $4; do
ipt_add_del $1 POSTROUTING -t mangle -o $i $rule
ipt_add_del "$1" POSTROUTING -t mangle -o "$i" "$rule"
done
else
ipt_add_del $1 POSTROUTING -t mangle $rule
ipt_add_del "$1" POSTROUTING -t mangle "$rule"
fi
}
}
_fw_nfqws_post6()
{
_fw_nfqws_post6() {
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv6
# $3 - queue number
@@ -239,30 +210,28 @@ _fw_nfqws_post6()
[ "$DISABLE_IPV6" = "1" -o -z "$2" ] || {
local i
ipt_print_op $1 "$2" "nfqws postrouting (qnum $3)" 6
ipt_print_op "$1" "$2" "nfqws postrouting (qnum $3)" 6
rule="$2 $IPSET_EXCLUDE6 dst -j NFQUEUE --queue-num $3 --queue-bypass"
if [ -n "$4" ] ; then
if [ -n "$4" ]; then
for i in $4; do
ipt6_add_del $1 POSTROUTING -t mangle -o $i $rule
ipt6_add_del "$1" POSTROUTING -t mangle -o "$i" "$rule"
done
else
ipt6_add_del $1 POSTROUTING -t mangle $rule
ipt6_add_del "$1" POSTROUTING -t mangle "$rule"
fi
}
}
fw_nfqws_post()
{
fw_nfqws_post() {
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv4
# $3 - iptable filter for ipv6
# $4 - queue number
fw_nfqws_post4 $1 "$2" $4
fw_nfqws_post6 $1 "$3" $4
fw_nfqws_post4 "$1" "$2" "$4"
fw_nfqws_post6 "$1" "$3" "$4"
}
_fw_nfqws_pre4()
{
_fw_nfqws_pre4() {
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv4
# $3 - queue number
@@ -270,23 +239,22 @@ _fw_nfqws_pre4()
[ "$DISABLE_IPV4" = "1" -o -z "$2" ] || {
local i
ipt_print_op $1 "$2" "nfqws input+forward (qnum $3)"
ipt_print_op "$1" "$2" "nfqws input+forward (qnum $3)"
rule="$2 $IPSET_EXCLUDE src -j NFQUEUE --queue-num $3 --queue-bypass"
if [ -n "$4" ] ; then
if [ -n "$4" ]; then
for i in $4; do
# iptables PREROUTING chain is before NAT. not possible to have DNATed ip's there
ipt_add_del $1 INPUT -t mangle -i $i $rule
ipt_add_del $1 FORWARD -t mangle -i $i $rule
ipt_add_del "$1" INPUT -t mangle -i "$i" "$rule"
ipt_add_del "$1" FORWARD -t mangle -i "$i" "$rule"
done
else
ipt_add_del $1 INPUT -t mangle $rule
ipt_add_del $1 FORWARD -t mangle $rule
ipt_add_del "$1" INPUT -t mangle "$rule"
ipt_add_del "$1" FORWARD -t mangle "$rule"
fi
}
}
_fw_nfqws_pre6()
{
_fw_nfqws_pre6() {
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv6
# $3 - queue number
@@ -294,34 +262,31 @@ _fw_nfqws_pre6()
[ "$DISABLE_IPV6" = "1" -o -z "$2" ] || {
local i
ipt_print_op $1 "$2" "nfqws input+forward (qnum $3)" 6
ipt_print_op "$1" "$2" "nfqws input+forward (qnum $3)" 6
rule="$2 $IPSET_EXCLUDE6 src -j NFQUEUE --queue-num $3 --queue-bypass"
if [ -n "$4" ] ; then
if [ -n "$4" ]; then
for i in $4; do
# iptables PREROUTING chain is before NAT. not possible to have DNATed ip's there
ipt6_add_del $1 INPUT -t mangle -i $i $rule
ipt6_add_del $1 FORWARD -t mangle -i $i $rule
ipt6_add_del "$1" INPUT -t mangle -i "$i" "$rule"
ipt6_add_del "$1" FORWARD -t mangle -i "$i" "$rule"
done
else
ipt6_add_del $1 INPUT -t mangle $rule
ipt6_add_del $1 FORWARD -t mangle $rule
ipt6_add_del "$1" INPUT -t mangle "$rule"
ipt6_add_del "$1" FORWARD -t mangle "$rule"
fi
}
}
fw_nfqws_pre()
{
fw_nfqws_pre() {
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv4
# $3 - iptable filter for ipv6
# $4 - queue number
fw_nfqws_pre4 $1 "$2" $4
fw_nfqws_pre6 $1 "$3" $4
fw_nfqws_pre4 "$1" "$2" "$4"
fw_nfqws_pre6 "$1" "$3" "$4"
}
produce_reverse_nfqws_rule()
{
produce_reverse_nfqws_rule() {
local rule="$1"
if contains "$rule" "$ipt_connbytes"; then
# autohostlist - need several incoming packets
@@ -334,28 +299,23 @@ produce_reverse_nfqws_rule()
fi
echo "$rule" | reverse_nfqws_rule_stream
}
fw_reverse_nfqws_rule4()
{
fw_nfqws_pre4 $1 "$(produce_reverse_nfqws_rule "$2")" $3
fw_reverse_nfqws_rule4() {
fw_nfqws_pre4 "$1" "$(produce_reverse_nfqws_rule "$2")" "$3"
}
fw_reverse_nfqws_rule6()
{
fw_nfqws_pre6 $1 "$(produce_reverse_nfqws_rule "$2")" $3
fw_reverse_nfqws_rule6() {
fw_nfqws_pre6 "$1" "$(produce_reverse_nfqws_rule "$2")" "$3"
}
fw_reverse_nfqws_rule()
{
fw_reverse_nfqws_rule() {
# ensure that modes relying on incoming traffic work
# $1 - 1 - add, 0 - del
# $2 - rule4
# $3 - rule6
# $4 - queue number
fw_reverse_nfqws_rule4 $1 "$2" $4
fw_reverse_nfqws_rule6 $1 "$3" $4
fw_reverse_nfqws_rule4 "$1" "$2" "$4"
fw_reverse_nfqws_rule6 "$1" "$3" "$4"
}
zapret_do_firewall_rules_ipt()
{
zapret_do_firewall_rules_ipt() {
local mode="${MODE_OVERRIDE:-$MODE}"
local first_packet_only="$ipt_connbytes 1:$(first_packets_for_mode)"
@@ -363,87 +323,86 @@ zapret_do_firewall_rules_ipt()
local n f4 f6 qn qns qn6 qns6
case "$mode" in
tpws)
if [ ! "$MODE_HTTP" = "1" ] && [ ! "$MODE_HTTPS" = "1" ]; then
echo both http and https are disabled. not applying redirection.
else
filter_apply_port_target f4
f6=$f4
filter_apply_ipset_target f4 f6
fw_tpws $1 "$f4" "$f6" $TPPORT
fi
;;
nfqws)
# quite complex but we need to minimize nfqws processes to save RAM
get_nfqws_qnums qn qns qn6 qns6
if [ "$MODE_HTTP_KEEPALIVE" != "1" ] && [ -n "$qn" ] && [ "$qn" = "$qns" ]; then
filter_apply_port_target f4
f4="$f4 $first_packet_only"
filter_apply_ipset_target4 f4
fw_nfqws_post4 $1 "$f4 $desync" $qn
fw_reverse_nfqws_rule4 $1 "$f4" $qn
else
if [ -n "$qn" ]; then
f4="-p tcp -m multiport --dports $HTTP_PORTS_IPT"
[ "$MODE_HTTP_KEEPALIVE" = "1" ] || f4="$f4 $first_packet_only"
filter_apply_ipset_target4 f4
fw_nfqws_post4 $1 "$f4 $desync" $qn
fw_reverse_nfqws_rule4 $1 "$f4" $qn
fi
if [ -n "$qns" ]; then
f4="-p tcp -m multiport --dports $HTTPS_PORTS_IPT $first_packet_only"
filter_apply_ipset_target4 f4
fw_nfqws_post4 $1 "$f4 $desync" $qns
fw_reverse_nfqws_rule4 $1 "$f4" $qns
fi
fi
if [ "$MODE_HTTP_KEEPALIVE" != "1" ] && [ -n "$qn6" ] && [ "$qn6" = "$qns6" ]; then
filter_apply_port_target f6
f6="$f6 $first_packet_only"
filter_apply_ipset_target6 f6
fw_nfqws_post6 $1 "$f6 $desync" $qn6
fw_reverse_nfqws_rule6 $1 "$f6" $qn6
else
if [ -n "$qn6" ]; then
f6="-p tcp -m multiport --dports $HTTP_PORTS_IPT"
[ "$MODE_HTTP_KEEPALIVE" = "1" ] || f6="$f6 $first_packet_only"
filter_apply_ipset_target6 f6
fw_nfqws_post6 $1 "$f6 $desync" $qn6
fw_reverse_nfqws_rule6 $1 "$f6" $qn6
fi
if [ -n "$qns6" ]; then
f6="-p tcp -m multiport --dports $HTTPS_PORTS_IPT $first_packet_only"
filter_apply_ipset_target6 f6
fw_nfqws_post6 $1 "$f6 $desync" $qns6
fw_reverse_nfqws_rule6 $1 "$f6" $qns6
fi
fi
tpws)
if [ ! "$MODE_HTTP" = "1" ] && [ ! "$MODE_HTTPS" = "1" ]; then
echo both HTTP and HTTPS are disabled. not applying redirection.
else
filter_apply_port_target f4
f6=$f4
filter_apply_ipset_target f4 f6
fw_tpws "$1" "$f4" "$f6" "$TPPORT"
fi
;;
get_nfqws_qnums_quic qn qn6
nfqws)
# quite complex but we need to minimize nfqws processes to save RAM
get_nfqws_qnums qn qns qn6 qns6
if [ "$MODE_HTTP_KEEPALIVE" != "1" ] && [ -n "$qn" ] && [ "$qn" = "$qns" ]; then
filter_apply_port_target f4
f4="$f4 $first_packet_only"
filter_apply_ipset_target4 f4
fw_nfqws_post4 "$1" "$f4 $desync" "$qn"
fw_reverse_nfqws_rule4 "$1" "$f4" "$qn"
else
if [ -n "$qn" ]; then
f4=
filter_apply_port_target_quic f4
f4="$f4 $first_packet_only"
f4="-p tcp -m multiport --dports $HTTP_PORTS_IPT"
[ "$MODE_HTTP_KEEPALIVE" = "1" ] || f4="$f4 $first_packet_only"
filter_apply_ipset_target4 f4
fw_nfqws_post4 $1 "$f4 $desync" $qn
fw_nfqws_post4 "$1" "$f4 $desync" "$qn"
fw_reverse_nfqws_rule4 "$1" "$f4" "$qn"
fi
if [ -n "$qns" ]; then
f4="-p tcp -m multiport --dports $HTTPS_PORTS_IPT $first_packet_only"
filter_apply_ipset_target4 f4
fw_nfqws_post4 "$1" "$f4 $desync" "$qns"
fw_reverse_nfqws_rule4 "$1" "$f4" "$qns"
fi
fi
if [ "$MODE_HTTP_KEEPALIVE" != "1" ] && [ -n "$qn6" ] && [ "$qn6" = "$qns6" ]; then
filter_apply_port_target f6
f6="$f6 $first_packet_only"
filter_apply_ipset_target6 f6
fw_nfqws_post6 "$1" "$f6 $desync" "$qn6"
fw_reverse_nfqws_rule6 "$1" "$f6" "$qn6"
else
if [ -n "$qn6" ]; then
f6=
filter_apply_port_target_quic f6
f6="$f6 $first_packet_only"
f6="-p tcp -m multiport --dports $HTTP_PORTS_IPT"
[ "$MODE_HTTP_KEEPALIVE" = "1" ] || f6="$f6 $first_packet_only"
filter_apply_ipset_target6 f6
fw_nfqws_post6 $1 "$f6 $desync" $qn6
fw_nfqws_post6 "$1" "$f6 $desync" "$qn6"
fw_reverse_nfqws_rule6 "$1" "$f6" "$qn6"
fi
;;
custom)
existf zapret_custom_firewall && zapret_custom_firewall $1
;;
if [ -n "$qns6" ]; then
f6="-p tcp -m multiport --dports $HTTPS_PORTS_IPT $first_packet_only"
filter_apply_ipset_target6 f6
fw_nfqws_post6 "$1" "$f6 $desync" "$qns6"
fw_reverse_nfqws_rule6 "$1" "$f6" "$qns6"
fi
fi
get_nfqws_qnums_quic qn qn6
if [ -n "$qn" ]; then
f4=
filter_apply_port_target_quic f4
f4="$f4 $first_packet_only"
filter_apply_ipset_target4 f4
fw_nfqws_post4 "$1" "$f4 $desync" "$qn"
fi
if [ -n "$qn6" ]; then
f6=
filter_apply_port_target_quic f6
f6="$f6 $first_packet_only"
filter_apply_ipset_target6 f6
fw_nfqws_post6 "$1" "$f6 $desync" "$qn6"
fi
;;
custom)
existf zapret_custom_firewall && zapret_custom_firewall "$1"
;;
esac
}
zapret_do_firewall_ipt()
{
zapret_do_firewall_ipt() {
# $1 - 1 - add, 0 - del
if [ "$1" = 1 ]; then
@@ -461,7 +420,7 @@ zapret_do_firewall_ipt()
zapret_do_firewall_rules_ipt "$@"
if [ "$1" = 1 ] ; then
if [ "$1" = 1 ]; then
existf flow_offloading_exempt && flow_offloading_exempt
else
existf flow_offloading_unexempt && flow_offloading_unexempt

View File

@@ -1,21 +1,19 @@
set_conntrack_liberal_mode()
{
[ -n "$SKIP_CONNTRACK_LIBERAL_MODE" ] || sysctl -w net.netfilter.nf_conntrack_tcp_be_liberal=$1
set_conntrack_liberal_mode() {
[ -n "$SKIP_CONNTRACK_LIBERAL_MODE" ] || sysctl -w net.netfilter.nf_conntrack_tcp_be_liberal="$1"
}
zapret_do_firewall()
{
zapret_do_firewall() {
linux_fwtype
[ "$1" = 1 -a -n "$INIT_FW_PRE_UP_HOOK" ] && $INIT_FW_PRE_UP_HOOK
[ "$1" = 0 -a -n "$INIT_FW_PRE_DOWN_HOOK" ] && $INIT_FW_PRE_DOWN_HOOK
case "$FWTYPE" in
iptables)
zapret_do_firewall_ipt "$@"
;;
nftables)
zapret_do_firewall_nft "$@"
;;
iptables)
zapret_do_firewall_ipt "$@"
;;
nftables)
zapret_do_firewall_nft "$@"
;;
esac
# russian DPI sends RST,ACK with wrong ACK.
@@ -23,29 +21,26 @@ zapret_do_firewall()
# switch on liberal mode on zapret firewall start and switch off on zapret firewall stop
# this is only required for processing incoming bad RSTs. incoming rules are only applied in autohostlist mode
# calling this after firewall because conntrack module can be not loaded before applying conntrack firewall rules
[ "$MODE_FILTER" = "autohostlist" -a "$MODE" != tpws -a "$MODE" != tpws-socks ] && set_conntrack_liberal_mode $1
[ "$MODE_FILTER" = "autohostlist" -a "$MODE" != tpws -a "$MODE" != tpws-socks ] && set_conntrack_liberal_mode "$1"
[ "$1" = 1 -a -n "$INIT_FW_POST_UP_HOOK" ] && $INIT_FW_POST_UP_HOOK
[ "$1" = 0 -a -n "$INIT_FW_POST_DOWN_HOOK" ] && $INIT_FW_POST_DOWN_HOOK
return 0
}
zapret_apply_firewall()
{
zapret_apply_firewall() {
zapret_do_firewall 1 "$@"
}
zapret_unapply_firewall()
{
zapret_unapply_firewall() {
zapret_do_firewall 0 "$@"
}
first_packets_for_mode()
{
first_packets_for_mode() {
# autohostlist and autottl modes requires incoming traffic sample
# always use conntrack packet limiter or nfqws will deal with gigabytes
local n
if [ "$MODE_FILTER" = "autohostlist" ]; then
n=$((6+${AUTOHOSTLIST_RETRANS_THRESHOLD:-3}))
n=$((6 + ${AUTOHOSTLIST_RETRANS_THRESHOLD:-3}))
else
n=6
fi

View File

@@ -4,54 +4,48 @@
# PREROUTING - can't DNAT to ::1. can DNAT to link local of -i interface or to any global addr
# not a good idea to expose tpws to the world (bind to ::)
get_ipv6_linklocal()
{
# $1 - interface name. if empty - any interface
if exists ip ; then
local dev
[ -n "$1" ] && dev="dev $1"
ip addr show $dev | sed -e 's/^.*inet6 \([^ ]*\)\/[0-9]* scope link.*$/\1/;t;d' | head -n 1
else
ifconfig $1 | sed -re 's/^.*inet6 addr: ([^ ]*)\/[0-9]* Scope:Link.*$/\1/;t;d' | head -n 1
fi
get_ipv6_linklocal() {
# $1 - interface name. if empty - any interface
if exists ip; then
local dev
[ -n "$1" ] && dev="dev $1"
ip addr show "$dev" | sed -e 's/^.*inet6 \([^ ]*\)\/[0-9]* scope link.*$/\1/;t;d' | head -n 1
else
ifconfig "$1" | sed -re 's/^.*inet6 addr: ([^ ]*)\/[0-9]* Scope:Link.*$/\1/;t;d' | head -n 1
fi
}
get_ipv6_global()
{
# $1 - interface name. if empty - any interface
if exists ip ; then
local dev
[ -n "$1" ] && dev="dev $1"
ip addr show $dev | sed -e 's/^.*inet6 \([^ ]*\)\/[0-9]* scope global.*$/\1/;t;d' | head -n 1
else
ifconfig $1 | sed -re 's/^.*inet6 addr: ([^ ]*)\/[0-9]* Scope:Global.*$/\1/;t;d' | head -n 1
fi
get_ipv6_global() {
# $1 - interface name. if empty - any interface
if exists ip; then
local dev
[ -n "$1" ] && dev="dev $1"
ip addr show "$dev" | sed -e 's/^.*inet6 \([^ ]*\)\/[0-9]* scope global.*$/\1/;t;d' | head -n 1
else
ifconfig "$1" | sed -re 's/^.*inet6 addr: ([^ ]*)\/[0-9]* Scope:Global.*$/\1/;t;d' | head -n 1
fi
}
iface_is_up()
{
iface_is_up() {
# $1 - interface name
[ -f /sys/class/net/$1/operstate ] || return
[ -f /sys/class/net/"$1"/operstate ] || return
local state
read state </sys/class/net/$1/operstate
read state </sys/class/net/"$1"/operstate
[ "$state" != "down" ]
}
wait_ifup()
{
wait_ifup() {
# $1 - interface name
local ct=0
while
iface_is_up $1 && return
iface_is_up "$1" && return
[ "$ct" -ge "$IFUP_WAIT_SEC" ] && break
echo waiting for ifup of $1 for another $(($IFUP_WAIT_SEC - $ct)) seconds ...
ct=$(($ct+1))
echo waiting for ifup of "$1" for another $(($IFUP_WAIT_SEC - $ct)) seconds ...
ct=$(($ct + 1))
sleep 1
do :; done
false
}
_dnat6_target()
{
_dnat6_target() {
# $1 - interface name
# $2 - var to store target ip6
# get target ip address for DNAT. prefer link locals
@@ -60,68 +54,64 @@ _dnat6_target()
# DNAT6_TARGET=- means attempt was made but address was not found (to avoid multiple re-attempts)
local DNAT6_TARGET DVAR=DNAT6_TARGET_$1
DVAR=$(echo $DVAR | sed 's/[^a-zA-Z0-9_]/_/g')
DVAR=$(echo "$DVAR" | sed 's/[^a-zA-Z0-9_]/_/g')
eval DNAT6_TARGET="\$$DVAR"
[ -n "$2" ] && eval $2=''
[ -n "$2" ] && eval "$2"=''
[ -n "$DNAT6_TARGET" ] || {
local ct=0
while
DNAT6_TARGET=$(get_ipv6_linklocal $1)
DNAT6_TARGET=$(get_ipv6_linklocal "$1")
[ -n "$DNAT6_TARGET" ] && break
[ "$ct" -ge "$LINKLOCAL_WAIT_SEC" ] && break
echo $1: waiting for the link local for another $(($LINKLOCAL_WAIT_SEC - $ct)) seconds ...
ct=$(($ct+1))
echo "$1": waiting for the link local for another $(($LINKLOCAL_WAIT_SEC - $ct)) seconds ...
ct=$(($ct + 1))
sleep 1
do :; done
[ -n "$DNAT6_TARGET" ] || {
echo $1: no link local. getting global
DNAT6_TARGET=$(get_ipv6_global $1)
echo "$1": no link local. getting global
DNAT6_TARGET=$(get_ipv6_global "$1")
[ -n "$DNAT6_TARGET" ] || {
echo $1: could not get any address
echo "$1": could not get any address
DNAT6_TARGET=-
}
}
eval $DVAR="$DNAT6_TARGET"
eval "$DVAR"="$DNAT6_TARGET"
}
[ -n "$2" ] && eval $2="$DNAT6_TARGET"
[ -n "$2" ] && eval "$2"="$DNAT6_TARGET"
}
_set_route_localnet()
{
_set_route_localnet() {
# $1 - 1 = enable, 0 = disable
# $2,$3,... - interface names
[ "$DISABLE_IPV4" = "1" ] || {
local enable="$1"
shift
while [ -n "$1" ]; do
sysctl -q -w net.ipv4.conf.$1.route_localnet="$enable"
sysctl -q -w net.ipv4.conf."$1".route_localnet="$enable"
shift
done
}
}
prepare_route_localnet()
{
prepare_route_localnet() {
set_route_localnet 1 "$@"
}
unprepare_route_localnet()
{
unprepare_route_localnet() {
set_route_localnet 0 "$@"
}
resolve_lower_devices()
{
resolve_lower_devices() {
# $1 - bridge interface name
[ -d "/sys/class/net/$1" ] && {
find "/sys/class/net/$1" -follow -maxdepth 1 -name "lower_*" |
{
local l lower lowers
while read lower; do
lower="$(basename "$lower")"
l="${lower#lower_*}"
[ "$l" != "$lower" ] && append_separator_list lowers ' ' '' "$l"
done
printf "$lowers"
}
{
local l lower lowers
while read lower; do
lower="$(basename "$lower")"
l="${lower#lower_*}"
[ "$l" != "$lower" ] && append_separator_list lowers ' ' '' "$l"
done
printf "$lowers"
}
}
}

View File

@@ -1,5 +1,4 @@
find_hostlists()
{
find_hostlists() {
[ -n "$HOSTLIST_BASE" ] || HOSTLIST_BASE="$ZAPRET_BASE/ipset"
HOSTLIST="$HOSTLIST_BASE/zapret-hosts.txt.gz"
@@ -18,20 +17,18 @@ find_hostlists()
HOSTLIST_AUTO_DEBUGLOG="$HOSTLIST_BASE/zapret-hosts-auto-debug.log"
}
filter_apply_autohostlist_target()
{
filter_apply_autohostlist_target() {
# $1 - var name of tpws or nfqws params
local parm1="${AUTOHOSTLIST_FAIL_THRESHOLD:+--hostlist-auto-fail-threshold=$AUTOHOSTLIST_FAIL_THRESHOLD}"
local parm2="${AUTOHOSTLIST_FAIL_TIME:+--hostlist-auto-fail-time=$AUTOHOSTLIST_FAIL_TIME}"
local parm3 parm4
[ "$MODE" = "tpws" -o "$MODE" = "tpws-socks" ] || parm3="${AUTOHOSTLIST_RETRANS_THRESHOLD:+--hostlist-auto-retrans-threshold=$AUTOHOSTLIST_RETRANS_THRESHOLD}"
[ "$AUTOHOSTLIST_DEBUGLOG" = 1 ] && parm4="--hostlist-auto-debug=$HOSTLIST_AUTO_DEBUGLOG"
eval $1="\"\$$1 --hostlist-auto=$HOSTLIST_AUTO $parm1 $parm2 $parm3 $parm4\""
eval "$1"="\"\$$1 --hostlist-auto=$HOSTLIST_AUTO $parm1 $parm2 $parm3 $parm4\""
}
filter_apply_hostlist_target()
{
filter_apply_hostlist_target() {
# $1 - var name of tpws or nfqws params
[ "$MODE_FILTER" = "hostlist" -o "$MODE_FILTER" = "autohostlist" ] || return
@@ -40,8 +37,8 @@ filter_apply_hostlist_target()
find_hostlists
[ -n "$HOSTLIST" ] && eval $1="\"\$$1 --hostlist=$HOSTLIST\""
[ -n "$HOSTLIST_USER" ] && eval $1="\"\$$1 --hostlist=$HOSTLIST_USER\""
[ -n "$HOSTLIST_EXCLUDE" ] && eval $1="\"\$$1 --hostlist-exclude=$HOSTLIST_EXCLUDE\""
[ "$MODE_FILTER" = "autohostlist" ] && filter_apply_autohostlist_target $1
[ -n "$HOSTLIST" ] && eval "$1"="\"\$$1 --hostlist=$HOSTLIST\""
[ -n "$HOSTLIST_USER" ] && eval "$1"="\"\$$1 --hostlist=$HOSTLIST_USER\""
[ -n "$HOSTLIST_EXCLUDE" ] && eval "$1"="\"\$$1 --hostlist-exclude=$HOSTLIST_EXCLUDE\""
[ "$MODE_FILTER" = "autohostlist" ] && filter_apply_autohostlist_target "$1"
}

View File

@@ -5,48 +5,39 @@ readonly nft_connbytes="ct original packets"
create_dev_stdin
std_ports
nft_create_table()
{
nft add table inet $ZAPRET_NFT_TABLE
nft_create_table() {
nft add table inet "$ZAPRET_NFT_TABLE"
}
nft_del_table()
{
nft delete table inet $ZAPRET_NFT_TABLE 2>/dev/null
nft_del_table() {
nft delete table inet "$ZAPRET_NFT_TABLE" 2>/dev/null
}
nft_list_table()
{
nft -t list table inet $ZAPRET_NFT_TABLE
nft_list_table() {
nft -t list table inet "$ZAPRET_NFT_TABLE"
}
nft_create_set()
{
nft_create_set() {
# $1 - set name
# $2 - params
nft create set inet $ZAPRET_NFT_TABLE $1 "{ $2 }" 2>/dev/null
nft create set inet "$ZAPRET_NFT_TABLE" "$1" "{ $2 }" 2>/dev/null
}
nft_del_set()
{
nft_del_set() {
# $1 - set name
nft delete set inet $ZAPRET_NFT_TABLE $1
nft delete set inet "$ZAPRET_NFT_TABLE" "$1"
}
nft_flush_set()
{
nft_flush_set() {
# $1 - set name
nft flush set inet $ZAPRET_NFT_TABLE $1
nft flush set inet "$ZAPRET_NFT_TABLE" "$1"
}
nft_set_exists()
{
nft_set_exists() {
# $1 - set name
nft -t list set inet $ZAPRET_NFT_TABLE $1 2>/dev/null >/dev/null
nft -t list set inet "$ZAPRET_NFT_TABLE" "$1" 2>/dev/null >/dev/null
}
nft_flush_chain()
{
nft_flush_chain() {
# $1 - chain name
nft flush chain inet $ZAPRET_NFT_TABLE $1
nft flush chain inet "$ZAPRET_NFT_TABLE" "$1"
}
nft_del_all_chains_from_table()
{
nft_del_all_chains_from_table() {
# $1 - table_name with or without family
# delete all chains with possible references to each other
@@ -54,12 +45,12 @@ nft_del_all_chains_from_table()
# avoid infinite loops
local chains deleted=1 error=1
while [ -n "$deleted" -a -n "$error" ]; do
chains=$(nft -t list table $1 2>/dev/null | sed -nre "s/^[ ]*chain ([^ ]+) \{/\1/p" | xargs)
chains=$(nft -t list table "$1" 2>/dev/null | sed -nre "s/^[ ]*chain ([^ ]+) \{/\1/p" | xargs)
[ -n "$chains" ] || break
deleted=
error=
for chain in $chains; do
if nft delete chain $1 $chain 2>/dev/null; then
if nft delete chain "$1" "$chain" 2>/dev/null; then
deleted=1
else
error=1
@@ -68,9 +59,8 @@ nft_del_all_chains_from_table()
done
}
nft_create_chains()
{
cat << EOF | nft -f -
nft_create_chains() {
cat <<EOF | nft -f -
add chain inet $ZAPRET_NFT_TABLE dnat_output { type nat hook output priority -101; }
flush chain inet $ZAPRET_NFT_TABLE dnat_output
add chain inet $ZAPRET_NFT_TABLE dnat_pre { type nat hook prerouting priority -101; }
@@ -113,12 +103,11 @@ EOF
nft_add_rule predefrag_nfqws notrack comment \"do not track nfqws generated packets to avoid nat tampering and defragmentation\"
}
}
nft_del_chains()
{
nft_del_chains() {
# do not delete all chains because of additional user hooks
# they must be inside zapret table to use nfsets
cat << EOF | nft -f - 2>/dev/null
cat <<EOF | nft -f - 2>/dev/null
delete chain inet $ZAPRET_NFT_TABLE dnat_output
delete chain inet $ZAPRET_NFT_TABLE dnat_pre
delete chain inet $ZAPRET_NFT_TABLE forward
@@ -132,15 +121,13 @@ cat << EOF | nft -f - 2>/dev/null
delete chain inet $ZAPRET_NFT_TABLE flow_offload
delete chain inet $ZAPRET_NFT_TABLE localnet_protect
EOF
# unfortunately this approach breaks udp desync of the connection initiating packet (new, first one)
# delete chain inet $ZAPRET_NFT_TABLE predefrag
# unfortunately this approach breaks udp desync of the connection initiating packet (new, first one)
# delete chain inet $ZAPRET_NFT_TABLE predefrag
}
nft_del_flowtable()
{
nft delete flowtable inet $ZAPRET_NFT_TABLE ft 2>/dev/null
nft_del_flowtable() {
nft delete flowtable inet "$ZAPRET_NFT_TABLE" ft 2>/dev/null
}
nft_create_or_update_flowtable()
{
nft_create_or_update_flowtable() {
# $1 = flags ('offload' for hw offload)
# $2,$3,$4,... - interfaces
# can be called multiple times to add interfaces. interfaces can only be added , not removed
@@ -153,117 +140,102 @@ nft_create_or_update_flowtable()
for makelist in make_quoted_comma_list make_comma_list; do
$makelist devices "$@"
[ -n "$devices" ] && devices="devices={$devices};"
nft add flowtable inet $ZAPRET_NFT_TABLE ft "{ hook ingress priority -1; $flags $devices }" && break
nft add flowtable inet "$ZAPRET_NFT_TABLE" ft "{ hook ingress priority -1; $flags $devices }" && break
done
}
nft_flush_ifsets()
{
cat << EOF | nft -f - 2>/dev/null
nft_flush_ifsets() {
cat <<EOF | nft -f - 2>/dev/null
flush set inet $ZAPRET_NFT_TABLE lanif
flush set inet $ZAPRET_NFT_TABLE wanif
flush set inet $ZAPRET_NFT_TABLE wanif6
flush map inet $ZAPRET_NFT_TABLE link_local
EOF
}
nft_flush_link_local()
{
nft flush map inet $ZAPRET_NFT_TABLE link_local 2>/dev/null
nft_flush_link_local() {
nft flush map inet "$ZAPRET_NFT_TABLE" link_local 2>/dev/null
}
nft_list_ifsets()
{
nft list set inet $ZAPRET_NFT_TABLE lanif
nft list set inet $ZAPRET_NFT_TABLE wanif
nft list set inet $ZAPRET_NFT_TABLE wanif6
nft list map inet $ZAPRET_NFT_TABLE link_local
nft list flowtable inet $ZAPRET_NFT_TABLE ft 2>/dev/null
nft_list_ifsets() {
nft list set inet "$ZAPRET_NFT_TABLE" lanif
nft list set inet "$ZAPRET_NFT_TABLE" wanif
nft list set inet "$ZAPRET_NFT_TABLE" wanif6
nft list map inet "$ZAPRET_NFT_TABLE" link_local
nft list flowtable inet "$ZAPRET_NFT_TABLE" ft 2>/dev/null
}
nft_create_firewall()
{
nft_create_firewall() {
nft_create_table
nft_del_flowtable
nft_flush_link_local
nft_create_chains
}
nft_del_firewall()
{
nft_del_firewall() {
nft_del_chains
nft_del_flowtable
nft_flush_link_local
# leave ifsets and ipsets because they may be used by custom rules
}
nft_add_rule()
{
nft_add_rule() {
# $1 - chain
# $2,$3,... - rule(s)
local chain="$1"
shift
nft add rule inet $ZAPRET_NFT_TABLE $chain "$@"
nft add rule inet "$ZAPRET_NFT_TABLE" "$chain" "$@"
}
nft_add_set_element()
{
nft_add_set_element() {
# $1 - set or map name
# $2 - element
[ -z "$2" ] || nft add element inet $ZAPRET_NFT_TABLE $1 "{ $2 }"
[ -z "$2" ] || nft add element inet "$ZAPRET_NFT_TABLE" "$1" "{ $2 }"
}
nft_add_set_elements()
{
nft_add_set_elements() {
# $1 - set or map name
# $2,$3,... - element(s)
local set="$1" elements
shift
make_comma_list elements "$@"
nft_add_set_element $set "$elements"
nft_add_set_element "$set" "$elements"
}
nft_reverse_nfqws_rule()
{
nft_reverse_nfqws_rule() {
echo "$@" | sed -e 's/oifname /iifname /g' -e 's/dport /sport /g' -e 's/daddr /saddr /g' -e 's/ct original /ct reply /g' -e "s/mark and $DESYNC_MARK == 0//g"
}
nft_clean_nfqws_rule()
{
nft_clean_nfqws_rule() {
echo "$@" | sed -e "s/mark and $DESYNC_MARK == 0//g" -e "s/oifname @wanif6//g" -e "s/oifname @wanif//g"
}
nft_add_nfqws_flow_exempt_rule()
{
nft_add_nfqws_flow_exempt_rule() {
# $1 - rule (must be all filters in one var)
nft_add_rule flow_offload $(nft_clean_nfqws_rule $1) return comment \"direct flow offloading exemption\"
nft_add_rule flow_offload $(nft_clean_nfqws_rule "$1") return comment \"direct flow offloading exemption\"
# do not need this because of oifname @wanif/@wanif6 filter in forward chain
#nft_add_rule flow_offload $(nft_reverse_nfqws_rule $1) return comment \"reverse flow offloading exemption\"
}
nft_add_flow_offload_exemption()
{
nft_add_flow_offload_exemption() {
# "$1" - rule for ipv4
# "$2" - rule for ipv6
# "$3" - comment
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || nft_add_rule flow_offload oifname @wanif $1 ip daddr != @nozapret return comment \"$3\"
[ "$DISABLE_IPV6" = "1" -o -z "$2" ] || nft_add_rule flow_offload oifname @wanif6 $2 ip6 daddr != @nozapret6 return comment \"$3\"
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || nft_add_rule flow_offload oifname @wanif "$1" ip daddr != @nozapret return comment \""$3"\"
[ "$DISABLE_IPV6" = "1" -o -z "$2" ] || nft_add_rule flow_offload oifname @wanif6 "$2" ip6 daddr != @nozapret6 return comment \""$3"\"
}
nft_hw_offload_supported()
{
nft_hw_offload_supported() {
# $1,$2,... - interface names
local devices res=1
make_quoted_comma_list devices "$@"
[ -n "$devices" ] && devices="devices={$devices};"
nft add table ${ZAPRET_NFT_TABLE}_test && nft add flowtable ${ZAPRET_NFT_TABLE}_test ft "{ flags offload; $devices }" 2>/dev/null && res=0
nft delete table ${ZAPRET_NFT_TABLE}_test 2>/dev/null
nft add table "${ZAPRET_NFT_TABLE}"_test && nft add flowtable "${ZAPRET_NFT_TABLE}"_test ft "{ flags offload; $devices }" 2>/dev/null && res=0
nft delete table "${ZAPRET_NFT_TABLE}"_test 2>/dev/null
return $res
}
nft_hw_offload_find_supported()
{
nft_hw_offload_find_supported() {
# $1,$2,... - interface names
local supported_list
while [ -n "$1" ]; do
nft_hw_offload_supported "$1" && append_separator_list supported_list ' ' '' "$1"
shift
done
echo $supported_list
echo "$supported_list"
}
nft_apply_flow_offloading()
{
nft_apply_flow_offloading() {
# ft can be absent
nft_add_rule flow_offload meta l4proto "{ tcp, udp }" flow add @ft 2>/dev/null && {
nft_add_rule flow_offload meta l4proto "{ tcp, udp }" counter comment \"if offload works here must not be too much traffic\"
@@ -273,10 +245,7 @@ nft_apply_flow_offloading()
}
}
nft_filter_apply_port_target()
{
nft_filter_apply_port_target() {
# $1 - var name of nftables filter
local f
if [ "$MODE_HTTP" = "1" ] && [ "$MODE_HTTPS" = "1" ]; then
@@ -288,58 +257,51 @@ nft_filter_apply_port_target()
else
echo WARNING !!! HTTP and HTTPS are both disabled
fi
eval $1="\"\$$1 $f\""
eval "$1"="\"\$$1 $f\""
}
nft_filter_apply_port_target_quic()
{
nft_filter_apply_port_target_quic() {
# $1 - var name of nftables filter
local f
f="udp dport {$QUIC_PORTS}"
eval $1="\"\$$1 $f\""
eval "$1"="\"\$$1 $f\""
}
nft_filter_apply_ipset_target4()
{
nft_filter_apply_ipset_target4() {
# $1 - var name of ipv4 nftables filter
if [ "$MODE_FILTER" = "ipset" ]; then
eval $1="\"\$$1 ip daddr @zapret\""
eval "$1"="\"\$$1 ip daddr @zapret\""
fi
}
nft_filter_apply_ipset_target6()
{
nft_filter_apply_ipset_target6() {
# $1 - var name of ipv6 nftables filter
if [ "$MODE_FILTER" = "ipset" ]; then
eval $1="\"\$$1 ip6 daddr @zapret6\""
eval "$1"="\"\$$1 ip6 daddr @zapret6\""
fi
}
nft_filter_apply_ipset_target()
{
nft_filter_apply_ipset_target() {
# $1 - var name of ipv4 nftables filter
# $2 - var name of ipv6 nftables filter
nft_filter_apply_ipset_target4 $1
nft_filter_apply_ipset_target6 $2
nft_filter_apply_ipset_target4 "$1"
nft_filter_apply_ipset_target6 "$2"
}
nft_script_add_ifset_element()
{
nft_script_add_ifset_element() {
# $1 - set name
# $2 - space separated elements
local elements
[ -n "$2" ] && {
make_quoted_comma_list elements $2
make_quoted_comma_list elements "$2"
script="${script}
add element inet $ZAPRET_NFT_TABLE $1 { $elements }"
}
}
nft_fill_ifsets()
{
# $1 - space separated lan interface names
# $2 - space separated wan interface names
# $3 - space separated wan6 interface names
# 4,5,6 is needed for pppoe+openwrt case. looks like it's not easily possible to resolve ethernet device behind a pppoe interface
# $4 - space separated lan physical interface names (optional)
# $5 - space separated wan physical interface names (optional)
# $6 - space separated wan6 physical interface names (optional)
nft_fill_ifsets() {
# $1 - space separated LAN interface names
# $2 - space separated WAN interface names
# $3 - space separated WAN6 interface names
# 4,5,6 is needed for PPPoE+OpenWrt case. looks like it's not easily possible to resolve Ethernet device behind a PPPoE interface
# $4 - space separated LAN physical interface names (optional)
# $5 - space separated WAN physical interface names (optional)
# $6 - space separated WAN6 physical interface names (optional)
local script i j ALLDEVS devs
@@ -358,51 +320,47 @@ flush set inet $ZAPRET_NFT_TABLE lanif"
echo "$script" | nft -f -
case "$FLOWOFFLOAD" in
software)
ALLDEVS=$(unique $1 $2 $3)
# unbound flowtable may cause error in older nft version
nft_create_or_update_flowtable '' $ALLDEVS 2>/dev/null
;;
hardware)
ALLDEVS=$(unique $1 $2 $3 $4 $5 $6)
# first create unbound flowtable. may cause error in older nft version
nft_create_or_update_flowtable 'offload' 2>/dev/null
# then add elements. some of them can cause error because unsupported
for i in $ALLDEVS; do
if nft_hw_offload_supported $i; then
nft_create_or_update_flowtable 'offload' $i
else
# bridge members must be added instead of the bridge itself
# some members may not support hw offload. example : lan1 lan2 lan3 support, wlan0 wlan1 - not
devs=$(resolve_lower_devices $i)
for j in $devs; do
# do not display error if addition failed
nft_create_or_update_flowtable 'offload' $j 2>/dev/null
done
fi
done
;;
software)
ALLDEVS=$(unique "$1" "$2" "$3")
# unbound flowtable may cause error in older nft version
nft_create_or_update_flowtable '' "$ALLDEVS" 2>/dev/null
;;
hardware)
ALLDEVS=$(unique "$1" "$2" "$3" "$4" "$5" "$6")
# first create unbound flowtable. may cause error in older nft version
nft_create_or_update_flowtable 'offload' 2>/dev/null
# then add elements. some of them can cause error because unsupported
for i in $ALLDEVS; do
if nft_hw_offload_supported "$i"; then
nft_create_or_update_flowtable 'offload' "$i"
else
# bridge members must be added instead of the bridge itself
# some members may not support hw offload. example: lan1 lan2 lan3 support, wlan0 wlan1 - not
devs=$(resolve_lower_devices "$i")
for j in $devs; do
# do not display error if addition failed
nft_create_or_update_flowtable 'offload' "$j" 2>/dev/null
done
fi
done
;;
esac
}
nft_only()
{
nft_only() {
linux_fwtype
case "$FWTYPE" in
nftables)
"$@"
;;
nftables)
"$@"
;;
esac
}
nft_print_op()
{
echo "Adding nftables ipv$3 rule for $2 : $1"
nft_print_op() {
echo "Adding nftables IPv$3 rule for $2: $1"
}
_nft_fw_tpws4()
{
_nft_fw_tpws4() {
# $1 - filter ipv4
# $2 - tpws port
# $3 - not-empty if wan interface filtering required
@@ -410,13 +368,12 @@ _nft_fw_tpws4()
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
local filter="$1" port="$2"
nft_print_op "$filter" "tpws (port $2)" 4
nft_add_rule dnat_output skuid != $WS_USER ${3:+oifname @wanif }$filter ip daddr != @nozapret dnat ip to $TPWS_LOCALHOST4:$port
nft_add_rule dnat_pre iifname @lanif $filter ip daddr != @nozapret dnat ip to $TPWS_LOCALHOST4:$port
nft_add_rule dnat_output skuid != "$WS_USER" ${3:+oifname @wanif }"$filter" ip daddr != @nozapret dnat ip to "$TPWS_LOCALHOST4":"$port"
nft_add_rule dnat_pre iifname @lanif "$filter" ip daddr != @nozapret dnat ip to "$TPWS_LOCALHOST4":"$port"
prepare_route_localnet
}
}
_nft_fw_tpws6()
{
_nft_fw_tpws6() {
# $1 - filter ipv6
# $2 - tpws port
# $3 - lan interface names space separated
@@ -425,48 +382,43 @@ _nft_fw_tpws6()
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" DNAT6 i
nft_print_op "$filter" "tpws (port $port)" 6
nft_add_rule dnat_output skuid != $WS_USER ${4:+oifname @wanif6 }$filter ip6 daddr != @nozapret6 dnat ip6 to [::1]:$port
nft_add_rule dnat_output skuid != "$WS_USER" ${4:+oifname @wanif6 }"$filter" ip6 daddr != @nozapret6 dnat ip6 to [::1]:"$port"
[ -n "$3" ] && {
nft_add_rule dnat_pre $filter ip6 daddr != @nozapret6 dnat ip6 to iifname map @link_local:$port
nft_add_rule dnat_pre "$filter" ip6 daddr != @nozapret6 dnat ip6 to iifname map @link_local:"$port"
for i in $3; do
_dnat6_target $i DNAT6
_dnat6_target "$i" DNAT6
# can be multiple tpws processes on different ports
[ -n "$DNAT6" -a "$DNAT6" != '-' ] && nft_add_set_element link_local "$i : $DNAT6"
done
}
}
}
nft_fw_tpws()
{
nft_fw_tpws() {
# $1 - filter ipv4
# $2 - filter ipv6
# $3 - tpws port
nft_fw_tpws4 "$1" $3
nft_fw_tpws6 "$2" $3
nft_fw_tpws4 "$1" "$3"
nft_fw_tpws6 "$2" "$3"
}
is_postnat()
{
is_postnat() {
[ "$POSTNAT" != 0 -o "$POSTNAT_ALL" = 1 ]
}
get_postchain()
{
if is_postnat ; then
get_postchain() {
if is_postnat; then
echo -n postnat
else
echo -n postrouting
fi
}
get_prechain()
{
if is_postnat ; then
get_prechain() {
if is_postnat; then
echo -n prenat
else
echo -n prerouting
fi
}
_nft_fw_nfqws_post4()
{
_nft_fw_nfqws_post4() {
# $1 - filter ipv4
# $2 - queue number
# $3 - not-empty if wan interface filtering required
@@ -476,12 +428,11 @@ _nft_fw_nfqws_post4()
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 4
rule="${3:+oifname @wanif }$filter ip daddr != @nozapret"
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
nft_add_rule $chain $rule $setmark queue num $port bypass
nft_add_rule "$chain" "$rule" "$setmark" queue num "$port" bypass
nft_add_nfqws_flow_exempt_rule "$rule"
}
}
_nft_fw_nfqws_post6()
{
_nft_fw_nfqws_post6() {
# $1 - filter ipv6
# $2 - queue number
# $3 - not-empty if wan interface filtering required
@@ -491,22 +442,20 @@ _nft_fw_nfqws_post6()
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 6
rule="${3:+oifname @wanif6 }$filter ip6 daddr != @nozapret6"
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
nft_add_rule $chain $rule $setmark queue num $port bypass
nft_add_rule "$chain" "$rule" "$setmark" queue num "$port" bypass
nft_add_nfqws_flow_exempt_rule "$rule"
}
}
nft_fw_nfqws_post()
{
# $1 - filter ipv4
nft_fw_nfqws_post() {
# $1 - filter IPv4
# $2 - filter ipv6
# $3 - queue number
nft_fw_nfqws_post4 "$1" $3
nft_fw_nfqws_post6 "$2" $3
nft_fw_nfqws_post4 "$1" "$3"
nft_fw_nfqws_post6 "$2" "$3"
}
_nft_fw_nfqws_pre4()
{
_nft_fw_nfqws_pre4() {
# $1 - filter ipv4
# $2 - queue number
# $3 - not-empty if wan interface filtering required
@@ -515,11 +464,10 @@ _nft_fw_nfqws_pre4()
local filter="$1" port="$2" rule
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 4
rule="${3:+iifname @wanif }$filter ip saddr != @nozapret"
nft_add_rule $(get_prechain) $rule queue num $port bypass
nft_add_rule $(get_prechain) "$rule" queue num "$port" bypass
}
}
_nft_fw_nfqws_pre6()
{
_nft_fw_nfqws_pre6() {
# $1 - filter ipv6
# $2 - queue number
# $3 - not-empty if wan interface filtering required
@@ -528,35 +476,31 @@ _nft_fw_nfqws_pre6()
local filter="$1" port="$2" rule
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 6
rule="${3:+iifname @wanif6 }$filter ip6 saddr != @nozapret6"
nft_add_rule $(get_prechain) $rule queue num $port bypass
nft_add_rule $(get_prechain) "$rule" queue num "$port" bypass
}
}
nft_fw_nfqws_pre()
{
nft_fw_nfqws_pre() {
# $1 - filter ipv4
# $2 - filter ipv6
# $3 - queue number
nft_fw_nfqws_pre4 "$1" $3
nft_fw_nfqws_pre6 "$2" $3
nft_fw_nfqws_pre4 "$1" "$3"
nft_fw_nfqws_pre6 "$2" "$3"
}
nft_fw_nfqws_both4()
{
nft_fw_nfqws_both4() {
# $1 - filter ipv4
# $2 - queue number
nft_fw_nfqws_post4 "$@"
nft_fw_nfqws_pre4 "$(nft_reverse_nfqws_rule $1)" $2
nft_fw_nfqws_pre4 "$(nft_reverse_nfqws_rule "$1")" "$2"
}
nft_fw_nfqws_both6()
{
nft_fw_nfqws_both6() {
# $1 - filter ipv6
# $2 - queue number
nft_fw_nfqws_post6 "$@"
nft_fw_nfqws_pre6 "$(nft_reverse_nfqws_rule $1)" $2
nft_fw_nfqws_pre6 "$(nft_reverse_nfqws_rule "$1")" "$2"
}
nft_fw_nfqws_both()
{
nft_fw_nfqws_both() {
# $1 - filter ipv4
# $2 - filter ipv6
# $3 - queue number
@@ -564,26 +508,21 @@ nft_fw_nfqws_both()
nft_fw_nfqws_both6 "$2" "$3"
}
zapret_reload_ifsets()
{
nft_only nft_create_table ; nft_fill_ifsets_overload
zapret_reload_ifsets() {
nft_only nft_create_table
nft_fill_ifsets_overload
return 0
}
zapret_list_ifsets()
{
zapret_list_ifsets() {
nft_only nft_list_ifsets
return 0
}
zapret_list_table()
{
zapret_list_table() {
nft_only nft_list_table
return 0
}
nft_produce_reverse_nfqws_rule()
{
nft_produce_reverse_nfqws_rule() {
local rule="$1"
if contains "$rule" "$nft_connbytes "; then
# autohostlist - need several incoming packets
@@ -596,122 +535,117 @@ nft_produce_reverse_nfqws_rule()
[ "$range" = 1 ] || range="1-$range"
rule="$nft_connbytes $range $rule"
fi
nft_reverse_nfqws_rule $rule
nft_reverse_nfqws_rule "$rule"
}
nft_fw_reverse_nfqws_rule4()
{
nft_fw_nfqws_pre4 "$(nft_produce_reverse_nfqws_rule "$1")" $2
nft_fw_reverse_nfqws_rule4() {
nft_fw_nfqws_pre4 "$(nft_produce_reverse_nfqws_rule "$1")" "$2"
}
nft_fw_reverse_nfqws_rule6()
{
nft_fw_nfqws_pre6 "$(nft_produce_reverse_nfqws_rule "$1")" $2
nft_fw_reverse_nfqws_rule6() {
nft_fw_nfqws_pre6 "$(nft_produce_reverse_nfqws_rule "$1")" "$2"
}
nft_fw_reverse_nfqws_rule()
{
nft_fw_reverse_nfqws_rule() {
# ensure that modes relying on incoming traffic work
# $1 - rule4
# $2 - rule6
# $3 - queue number
nft_fw_reverse_nfqws_rule4 "$1" $3
nft_fw_reverse_nfqws_rule6 "$2" $3
nft_fw_reverse_nfqws_rule4 "$1" "$3"
nft_fw_reverse_nfqws_rule6 "$2" "$3"
}
zapret_apply_firewall_rules_nft()
{
zapret_apply_firewall_rules_nft() {
local mode="${MODE_OVERRIDE:-$MODE}"
local first_packets_only
local desync="mark and $DESYNC_MARK == 0"
local f4 f6 qn qns qn6 qns6
first_packets_only="$nft_connbytes 1-$(first_packets_for_mode)"
case "$mode" in
tpws)
if [ ! "$MODE_HTTP" = "1" ] && [ ! "$MODE_HTTPS" = "1" ]; then
echo both http and https are disabled. not applying redirection.
else
nft_filter_apply_port_target f4
f6=$f4
nft_filter_apply_ipset_target f4 f6
nft_fw_tpws "$f4" "$f6" $TPPORT
fi
;;
nfqws)
local POSTNAT_SAVE=$POSTNAT
tpws)
if [ ! "$MODE_HTTP" = "1" ] && [ ! "$MODE_HTTPS" = "1" ]; then
echo both HTTP and HTTPS are disabled. not applying redirection.
else
nft_filter_apply_port_target f4
f6=$f4
nft_filter_apply_ipset_target f4 f6
nft_fw_tpws "$f4" "$f6" "$TPPORT"
fi
;;
nfqws)
local POSTNAT_SAVE=$POSTNAT
POSTNAT=1
# quite complex but we need to minimize nfqws processes to save RAM
get_nfqws_qnums qn qns qn6 qns6
if [ "$MODE_HTTP_KEEPALIVE" != "1" ] && [ -n "$qn" ] && [ "$qn" = "$qns" ]; then
nft_filter_apply_port_target f4
f4="$f4 $first_packets_only"
nft_filter_apply_ipset_target4 f4
nft_fw_nfqws_post4 "$f4 $desync" $qn
nft_fw_reverse_nfqws_rule4 "$f4" $qn
else
if [ -n "$qn" ]; then
f4="tcp dport {$HTTP_PORTS}"
[ "$MODE_HTTP_KEEPALIVE" = "1" ] || f4="$f4 $first_packets_only"
nft_filter_apply_ipset_target4 f4
nft_fw_nfqws_post4 "$f4 $desync" $qn
nft_fw_reverse_nfqws_rule4 "$f4" $qn
fi
if [ -n "$qns" ]; then
f4="tcp dport {$HTTPS_PORTS} $first_packets_only"
nft_filter_apply_ipset_target4 f4
nft_fw_nfqws_post4 "$f4 $desync" $qns
nft_fw_reverse_nfqws_rule4 "$f4" $qns
fi
fi
if [ "$MODE_HTTP_KEEPALIVE" != "1" ] && [ -n "$qn6" ] && [ "$qn6" = "$qns6" ]; then
nft_filter_apply_port_target f6
f6="$f6 $first_packets_only"
nft_filter_apply_ipset_target6 f6
nft_fw_nfqws_post6 "$f6 $desync" $qn6
nft_fw_reverse_nfqws_rule6 "$f6" $qn6
else
if [ -n "$qn6" ]; then
f6="tcp dport {$HTTP_PORTS}"
[ "$MODE_HTTP_KEEPALIVE" = "1" ] || f6="$f6 $first_packets_only"
nft_filter_apply_ipset_target6 f6
nft_fw_nfqws_post6 "$f6 $desync" $qn6
nft_fw_reverse_nfqws_rule6 "$f6" $qn6
fi
if [ -n "$qns6" ]; then
f6="tcp dport {$HTTPS_PORTS} $first_packets_only"
nft_filter_apply_ipset_target6 f6
nft_fw_nfqws_post6 "$f6 $desync" $qns6
nft_fw_reverse_nfqws_rule6 "$f6" $qns6
fi
fi
get_nfqws_qnums_quic qn qn6
POSTNAT=1
# quite complex but we need to minimize nfqws processes to save RAM
get_nfqws_qnums qn qns qn6 qns6
if [ "$MODE_HTTP_KEEPALIVE" != "1" ] && [ -n "$qn" ] && [ "$qn" = "$qns" ]; then
nft_filter_apply_port_target f4
f4="$f4 $first_packets_only"
nft_filter_apply_ipset_target4 f4
nft_fw_nfqws_post4 "$f4 $desync" "$qn"
nft_fw_reverse_nfqws_rule4 "$f4" "$qn"
else
if [ -n "$qn" ]; then
f4=
nft_filter_apply_port_target_quic f4
f4="$f4 $first_packets_only"
f4="tcp dport {$HTTP_PORTS}"
[ "$MODE_HTTP_KEEPALIVE" = "1" ] || f4="$f4 $first_packets_only"
nft_filter_apply_ipset_target4 f4
nft_fw_nfqws_post4 "$f4 $desync" $qn
nft_fw_nfqws_post4 "$f4 $desync" "$qn"
nft_fw_reverse_nfqws_rule4 "$f4" "$qn"
fi
if [ -n "$qns" ]; then
f4="tcp dport {$HTTPS_PORTS} $first_packets_only"
nft_filter_apply_ipset_target4 f4
nft_fw_nfqws_post4 "$f4 $desync" "$qns"
nft_fw_reverse_nfqws_rule4 "$f4" "$qns"
fi
fi
if [ "$MODE_HTTP_KEEPALIVE" != "1" ] && [ -n "$qn6" ] && [ "$qn6" = "$qns6" ]; then
nft_filter_apply_port_target f6
f6="$f6 $first_packets_only"
nft_filter_apply_ipset_target6 f6
nft_fw_nfqws_post6 "$f6 $desync" "$qn6"
nft_fw_reverse_nfqws_rule6 "$f6" "$qn6"
else
if [ -n "$qn6" ]; then
f6=
nft_filter_apply_port_target_quic f6
f6="$f6 $first_packets_only"
f6="tcp dport {$HTTP_PORTS}"
[ "$MODE_HTTP_KEEPALIVE" = "1" ] || f6="$f6 $first_packets_only"
nft_filter_apply_ipset_target6 f6
nft_fw_nfqws_post6 "$f6 $desync" $qn6
nft_fw_nfqws_post6 "$f6 $desync" "$qn6"
nft_fw_reverse_nfqws_rule6 "$f6" "$qn6"
fi
if [ -n "$qns6" ]; then
f6="tcp dport {$HTTPS_PORTS} $first_packets_only"
nft_filter_apply_ipset_target6 f6
nft_fw_nfqws_post6 "$f6 $desync" "$qns6"
nft_fw_reverse_nfqws_rule6 "$f6" "$qns6"
fi
fi
POSTNAT=$POSTNAT_SAVE
;;
custom)
existf zapret_custom_firewall_nft && zapret_custom_firewall_nft
;;
get_nfqws_qnums_quic qn qn6
if [ -n "$qn" ]; then
f4=
nft_filter_apply_port_target_quic f4
f4="$f4 $first_packets_only"
nft_filter_apply_ipset_target4 f4
nft_fw_nfqws_post4 "$f4 $desync" "$qn"
fi
if [ -n "$qn6" ]; then
f6=
nft_filter_apply_port_target_quic f6
f6="$f6 $first_packets_only"
nft_filter_apply_ipset_target6 f6
nft_fw_nfqws_post6 "$f6 $desync" "$qn6"
fi
POSTNAT=$POSTNAT_SAVE
;;
custom)
existf zapret_custom_firewall_nft && zapret_custom_firewall_nft
;;
esac
}
zapret_apply_firewall_nft()
{
zapret_apply_firewall_nft() {
echo Applying nftables
local mode="${MODE_OVERRIDE:-$MODE}"
@@ -728,19 +662,17 @@ zapret_apply_firewall_nft()
return 0
}
zapret_unapply_firewall_nft()
{
zapret_unapply_firewall_nft() {
echo Clearing nftables
unprepare_route_localnet
nft_del_firewall
return 0
}
zapret_do_firewall_nft()
{
zapret_do_firewall_nft() {
# $1 - 1 - add, 0 - del
if [ "$1" = 0 ] ; then
if [ "$1" = 0 ]; then
zapret_unapply_firewall_nft
else
zapret_apply_firewall_nft

View File

@@ -6,14 +6,12 @@ PF_ANCHOR_ZAPRET_V6="$PF_ANCHOR_DIR/zapret-v6"
std_ports
pf_anchor_root_reload()
{
pf_anchor_root_reload() {
echo reloading PF root anchor
pfctl -qf "$PF_MAIN"
}
pf_anchor_root()
{
pf_anchor_root() {
local patch
[ -f "$PF_MAIN" ] && {
grep -q '^rdr-anchor "zapret"$' "$PF_MAIN" || {
@@ -39,8 +37,8 @@ set limit table-entries 5000000
}
grep -q '^anchor "zapret"$' "$PF_MAIN" &&
grep -q '^rdr-anchor "zapret"$' "$PF_MAIN" &&
grep -q '^set limit table-entries' "$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
@@ -57,13 +55,11 @@ set limit table-entries 5000000
echo ----------------------------------
return 1
}
pf_anchor_root_del()
{
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()
{
pf_anchor_zapret() {
[ "$DISABLE_IPV4" = "1" ] || {
if [ -f "$ZIPLIST_EXCLUDE" ]; then
echo "table <nozapret> persist file \"$ZIPLIST_EXCLUDE\""
@@ -83,8 +79,7 @@ pf_anchor_zapret()
[ "$DISABLE_IPV4" = "1" ] || echo "anchor \"/zapret-v4\" inet to !<nozapret>"
[ "$DISABLE_IPV6" = "1" ] || echo "anchor \"/zapret-v6\" inet6 to !<nozapret6>"
}
pf_anchor_zapret_tables()
{
pf_anchor_zapret_tables() {
# $1 - variable to receive applied table names
# $2/$3 $4/$5 ... table_name/table_file
local tblv=$1
@@ -92,22 +87,21 @@ pf_anchor_zapret_tables()
shift
[ "$MODE_FILTER" = "ipset" ] &&
{
while [ -n "$1" ] && [ -n "$2" ] ; do
[ -f "$2" ] && {
echo "table <$1> file \"$2\""
_tbl="$_tbl<$1> "
}
shift
shift
done
}
{
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\""
eval "$tblv"="\"\$_tbl\""
}
pf_anchor_port_target()
{
pf_anchor_port_target() {
if [ "$MODE_HTTP" = "1" ] && [ "$MODE_HTTPS" = "1" ]; then
echo "{$HTTP_PORTS_IPT,$HTTPS_PORTS_IPT}"
elif [ "$MODE_HTTPS" = "1" ]; then
@@ -117,20 +111,19 @@ pf_anchor_port_target()
fi
}
pf_anchor_zapret_v4_tpws()
{
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"
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
if [ -n "$IFACE_WAN" ]; then
for wan in $IFACE_WAN; do
echo "pass out on $wan $rule"
done
@@ -140,31 +133,29 @@ pf_anchor_zapret_v4_tpws()
done
}
pf_anchor_zapret_v4()
{
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
;;
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()
{
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)
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"
@@ -174,7 +165,7 @@ pf_anchor_zapret_v6_tpws()
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_WAN6:-$IFACE_WAN}" ] ; then
if [ -n "${IFACE_WAN6:-$IFACE_WAN}" ]; then
for wan in ${IFACE_WAN6:-$IFACE_WAN}; do
echo "pass out on $wan $rule"
done
@@ -183,38 +174,34 @@ pf_anchor_zapret_v6_tpws()
fi
done
}
pf_anchor_zapret_v6()
{
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
;;
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()
{
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()
{
pf_anchors_del() {
rm -f "$PF_ANCHOR_ZAPRET" "$PF_ANCHOR_ZAPRET_V4" "$PF_ANCHOR_ZAPRET_V6"
}
pf_anchors_load()
{
pf_anchors_load() {
echo loading zapret anchor from "$PF_ANCHOR_ZAPRET"
pfctl -qa zapret -f "$PF_ANCHOR_ZAPRET" || {
echo error loading zapret anchor
@@ -243,20 +230,17 @@ pf_anchors_load()
echo successfully loaded PF anchors
return 0
}
pf_anchors_clear()
{
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()
{
pf_enable() {
echo enabling PF
pfctl -qe
}
pf_table_reload()
{
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"

View File

@@ -1,5 +1,4 @@
apply_unspecified_desync_modes()
{
apply_unspecified_desync_modes() {
NFQWS_OPT_DESYNC_HTTP="${NFQWS_OPT_DESYNC_HTTP:-$NFQWS_OPT_DESYNC}"
NFQWS_OPT_DESYNC_HTTPS="${NFQWS_OPT_DESYNC_HTTPS:-$NFQWS_OPT_DESYNC}"
NFQWS_OPT_DESYNC_HTTP6="${NFQWS_OPT_DESYNC_HTTP6:-$NFQWS_OPT_DESYNC_HTTP}"
@@ -7,8 +6,7 @@ apply_unspecified_desync_modes()
NFQWS_OPT_DESYNC_QUIC6="${NFQWS_OPT_DESYNC_QUIC6:-$NFQWS_OPT_DESYNC_QUIC}"
}
get_nfqws_qnums()
{
get_nfqws_qnums() {
# $1 - var name for ipv4 http
# $2 - var name for ipv4 https
# $3 - var name for ipv6 http
@@ -18,63 +16,62 @@ get_nfqws_qnums()
[ "$DISABLE_IPV4" = "1" ] || {
_qn=$QNUM
_qns=$_qn
[ "$NFQWS_OPT_DESYNC_HTTP" = "$NFQWS_OPT_DESYNC_HTTPS" ] || _qns=$(($QNUM+1))
[ "$NFQWS_OPT_DESYNC_HTTP" = "$NFQWS_OPT_DESYNC_HTTPS" ] || _qns=$(($QNUM + 1))
}
[ "$DISABLE_IPV6" = "1" ] || {
_qn6=$(($QNUM+2))
_qns6=$(($QNUM+3))
_qn6=$(($QNUM + 2))
_qns6=$(($QNUM + 3))
[ "$DISABLE_IPV4" = "1" ] || {
if [ "$NFQWS_OPT_DESYNC_HTTP6" = "$NFQWS_OPT_DESYNC_HTTP" ]; then
_qn6=$_qn;
_qn6=$_qn
elif [ "$NFQWS_OPT_DESYNC_HTTP6" = "$NFQWS_OPT_DESYNC_HTTPS" ]; then
_qn6=$_qns;
_qn6=$_qns
fi
if [ "$NFQWS_OPT_DESYNC_HTTPS6" = "$NFQWS_OPT_DESYNC_HTTP" ]; then
_qns6=$_qn;
_qns6=$_qn
elif [ "$NFQWS_OPT_DESYNC_HTTPS6" = "$NFQWS_OPT_DESYNC_HTTPS" ]; then
_qns6=$_qns;
_qns6=$_qns
fi
}
[ "$NFQWS_OPT_DESYNC_HTTPS6" = "$NFQWS_OPT_DESYNC_HTTP6" ] && _qns6=$_qn6;
[ "$NFQWS_OPT_DESYNC_HTTPS6" = "$NFQWS_OPT_DESYNC_HTTP6" ] && _qns6=$_qn6
}
if [ "$MODE_HTTP" = 1 ]; then
eval $1=$_qn
eval $3=$_qn6
eval "$1"="$_qn"
eval "$3"="$_qn6"
else
eval $1=
eval $3=
eval "$1"=
eval "$3"=
fi
if [ "$MODE_HTTPS" = 1 ]; then
eval $2=$_qns
eval $4=$_qns6
eval "$2"="$_qns"
eval "$4"="$_qns6"
else
eval $2=
eval $4=
eval "$2"=
eval "$4"=
fi
}
get_nfqws_qnums_quic()
{
get_nfqws_qnums_quic() {
# $1 - var name for ipv4 quic
# $2 - var name for ipv6 quic
local _qn _qn6
[ "$DISABLE_IPV4" = "1" ] || {
_qn=$(($QNUM+10))
_qn=$(($QNUM + 10))
}
[ "$DISABLE_IPV6" = "1" ] || {
_qn6=$(($QNUM+11))
_qn6=$(($QNUM + 11))
[ "$DISABLE_IPV4" = "1" ] || {
if [ "$NFQWS_OPT_DESYNC_QUIC" = "$NFQWS_OPT_DESYNC_QUIC6" ]; then
_qn6=$_qn;
_qn6=$_qn
fi
}
}
if [ "$MODE_QUIC" = 1 ]; then
eval $1=$_qn
eval $2=$_qn6
eval "$1"=$_qn
eval "$2"=$_qn6
else
eval $1=
eval $2=
eval "$1"=
eval "$2"=
fi
}

View File

@@ -1,28 +1,26 @@
get_virt()
{
get_virt() {
local vm s v UNAME
UNAME=$(uname)
case "$UNAME" in
Linux)
if exists systemd-detect-virt; then
vm=$(systemd-detect-virt --vm)
elif [ -f /sys/class/dmi/id/product_name ]; then
read s </sys/class/dmi/id/product_name
for v in KVM QEMU VMware VMW VirtualBox Xen Bochs Parallels BHYVE Hyper-V; do
case "$s" in
"$v"*)
vm=$v
break
;;
esac
done
fi
;;
Linux)
if exists systemd-detect-virt; then
vm=$(systemd-detect-virt --vm)
elif [ -f /sys/class/dmi/id/product_name ]; then
read s </sys/class/dmi/id/product_name
for v in KVM QEMU VMware VMW VirtualBox Xen Bochs Parallels BHYVE Hyper-V; do
case "$s" in
"$v"*)
vm=$v
break
;;
esac
done
fi
;;
esac
echo "$vm" | awk '{print tolower($0)}'
}
check_virt()
{
check_virt() {
echo \* checking virtualization
local vm="$(get_virt)"
if [ -n "$vm" ]; then