Truncated history

This commit is contained in:
bol-van
2024-10-28 09:32:24 +03:00
commit 2aaa2f7cf3
300 changed files with 43184 additions and 0 deletions

340
common/base.sh Normal file
View File

@@ -0,0 +1,340 @@
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
}
done
return 1
}
exists()
{
which "$1" >/dev/null 2>/dev/null
}
existf()
{
type "$1" >/dev/null 2>/dev/null
}
whichq()
{
which $1 2>/dev/null
}
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
local F="$1"
[ "$3" = "1" ] || F="$2"
shift
shift
shift
"$F" "$@"
}
contains()
{
# check if substring $2 contains in $1
[ "${1#*$2}" != "$1" ]
}
starts_with()
{
# $1 : what
# $2 : starts with
case "$1" in
"$2"*)
return 0
;;
esac
return 1
}
find_str_in_list()
{
[ -n "$1" ] && {
for v in $2; do
[ "$v" = "$1" ] && return 0
done
}
return 1
}
end_with_newline()
{
local c="$(tail -c 1)"
[ "$c" = "" ]
}
append_separator_list()
{
# $1 - var name to receive result
# $2 - separator
# $3 - quoter
# $4,$5,... - elements
local _var="$1" sep="$2" quo="$3" i
eval i="\$$_var"
shift; shift; shift
while [ -n "$1" ]; do
if [ -n "$i" ] ; then
i="$i$sep$quo$1$quo"
else
i="$quo$1$quo"
fi
shift
done
eval $_var="\$i"
}
make_separator_list()
{
eval $1=''
append_separator_list "$@"
}
make_comma_list()
{
# $1 - var name to receive result
# $2,$3,... - elements
local var="$1"
shift
make_separator_list $var , '' "$@"
}
make_quoted_comma_list()
{
# $1 - var name to receive result
# $2,$3,... - elements
local var="$1"
shift
make_separator_list $var , '"' "$@"
}
unique()
{
local i
for i in "$@"; do echo $i; done | sort -u | xargs
}
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%busybox*}" != "$P" ] && return
done
}
get_dir_inode()
{
local dir="$1"
[ -L "$dir" ] && dir=$(readlink "$dir")
ls -id "$dir" | awk '{print $1}'
}
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()
{
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
SUBSYS=openwrt
elif [ -x "/bin/ndm" ] ; then
SUBSYS=keenetic
else
# generic linux
SUBSYS=
fi
}
openwrt_fw3()
{
[ ! -x /sbin/fw4 -a -x /sbin/fw3 ]
}
openwrt_fw4()
{
[ -x /sbin/fw4 ]
}
openwrt_fw3_integration()
{
[ "$FWTYPE" = iptables ] && openwrt_fw3
}
create_dev_stdin()
{
[ -e /dev/stdin ] || ln -s /proc/self/fd/0 /dev/stdin
}
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
[ -n "$item" ] && {
if [ -n "$items" ]; then
items="$items $item"
else
items="$item"
fi
}
done
eval $2=\"$items\"
}
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"
export PATH
}
# it can calculate floating point expr
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
else
FSLEEP=0
fi
fi
}
}
msleep()
{
# $1 - milliseconds
case "$FSLEEP" in
1)
sleep $(calc $1/1000)
;;
2)
busybox usleep $(calc $1*1000)
;;
3)
read -t $(calc $1/1000)
;;
4)
ucode -e "system(['sleep','2147483647'], $1)"
;;
5)
lua -e "require 'nixio'.nanosleep($(($1/1000)),$(calc $1%1000*1000000))"
;;
*)
sleep $((($1+999)/1000))
esac
}
minsleep()
{
msleep 100
}
replace_char()
{
local a=$1
local b=$2
shift; shift
echo "$@" | tr $a $b
}
setup_md5()
{
[ -n "$MD5" ] && return
MD5=md5sum
exists $MD5 || MD5=md5
}
random()
{
# $1 - min, $2 - max
local r rs
setup_md5
if [ -c /dev/urandom ]; then
read rs </dev/urandom
else
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 ))
}
shell_name()
{
[ -n "$SHELL_NAME" ] || {
[ -n "$UNAME" ] || UNAME="$(uname)"
if [ "$UNAME" = "Linux" ]; then
SHELL_NAME="$(readlink /proc/$$/exe)"
SHELL_NAME="$(basename "$SHELL_NAME")"
else
SHELL_NAME=$(ps -p $$ -o comm=)
fi
[ -n "$SHELL_NAME" ] || SHELL_NAME="$(basename "$SHELL")"
}
}
process_exists()
{
if exists pgrep; then
pgrep ^$1$ >/dev/null
elif exists pidof; then
pidof $1 >/dev/null
else
return 1
fi
}
win_process_exists()
{
tasklist /NH /FI "IMAGENAME eq ${1}.exe" | grep -q "^${1}.exe"
}
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)
}

25
common/custom.sh Normal file
View File

@@ -0,0 +1,25 @@
custom_runner()
{
# $1 - function name
# $2+ - params
local n script FUNC=$1
shift
[ -f "$CUSTOM_DIR/custom" ] && {
unset -f $FUNC
. "$CUSTOM_DIR/custom"
existf $FUNC && $FUNC "$@"
}
[ -d "$CUSTOM_DIR/custom.d" ] && {
n=$(ls "$CUSTOM_DIR/custom.d" | wc -c | xargs)
[ "$n" = 0 ] || {
for script in "$CUSTOM_DIR/custom.d/"*; do
unset -f $FUNC
. "$script"
existf $FUNC && $FUNC "$@"
done
}
}
}

58
common/dialog.sh Normal file
View File

@@ -0,0 +1,58 @@
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()
{
# $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
}
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
else
eval $1=0
fi
}
ask_list()
{
# $1 - mode var
# $2 - space separated value list
# $3 - (optional) default value
local M_DEFAULT
eval M_DEFAULT="\$$1"
local M_ALL=$M_DEFAULT
local M=""
local m
[ -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))
done
printf "your choice (default : $M_DEFAULT) : "
read m
[ -n "$m" ] && M=$(echo $2 | cut -d ' ' -f$m 2>/dev/null)
[ -z "$M" ] && M="$M_DEFAULT"
echo selected : $M
eval $1="\"$M\""
[ "$M" != "$M_OLD" ]
}

13
common/elevate.sh Normal file
View File

@@ -0,0 +1,13 @@
require_root()
{
local exe
echo \* checking privileges
[ $(id -u) -ne "0" ] && {
echo root is required
exe="$EXEDIR/$(basename "$0")"
exists sudo && exec sudo sh "$exe"
exists su && exec su root -c "sh \"$exe\""
echo su or sudo not found
exitp 2
}
}

64
common/fwtype.sh Normal file
View File

@@ -0,0 +1,64 @@
linux_ipt_avail()
{
exists iptables && exists ip6tables
}
linux_maybe_iptables_fwtype()
{
linux_ipt_avail && FWTYPE=iptables
}
linux_nft_avail()
{
exists nft
}
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
FWTYPE=nftables
else
linux_maybe_iptables_fwtype
fi
else
SUBSYS=
# generic linux
# flowtable is implemented since kernel 4.16
if linux_nft_avail && linux_min_version 4 16; then
FWTYPE=nftables
else
linux_maybe_iptables_fwtype
fi
fi
export 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
;;
*)
FWTYPE=unsupported
;;
esac
export FWTYPE
}

689
common/installer.sh Normal file
View File

@@ -0,0 +1,689 @@
GET_LIST_PREFIX=/ipset/get_
SYSTEMD_DIR=/lib/systemd
[ -d "$SYSTEMD_DIR" ] || SYSTEMD_DIR=/usr/lib/systemd
[ -d "$SYSTEMD_DIR" ] && SYSTEMD_SYSTEM_DIR="$SYSTEMD_DIR/system"
INIT_SCRIPT=/etc/init.d/zapret
exitp()
{
echo
echo press enter to continue
read A
exit $1
}
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\"
}
parse_vars_checked()
{
# $1 - file name
# $2,$3,... - var names
local f="$1"
shift
while [ -n "$1" ]; do
parse_var_checked "$f" $1
shift
done
}
edit_file()
{
# $1 - file name
local ed="$EDITOR"
[ -n "$ed" ] || {
for e in mcedit nano vim vi; do
exists "$e" && {
ed="$e"
break
}
done
}
[ -n "$ed" ] && "$ed" "$1"
}
edit_vars()
{
# $1,$2,... - var names
local n=1 var v tmp="/tmp/zvars"
rm -f "$tmp"
while [ 1=1 ]; do
eval var="\${$n}"
[ -n "$var" ] || break
eval v="\$$var"
echo $var=\"$v\" >>"$tmp"
n=$(($n+1))
done
edit_file "$tmp" && parse_vars_checked "$tmp" "$@"
rm -f "$tmp"
}
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()
{
# $1 - nonempty = do not fail on unknown rc system
echo \* checking system
SYSTEM=
SUBSYS=
SYSTEMCTL=$(whichq systemctl)
get_fwtype
OPENWRT_FW3=
local info
UNAME=$(uname)
if [ "$UNAME" = "Linux" ]; then
# do not use 'exe' because it requires root
local INIT="$(sed 's/\x0/\n/g' /proc/1/cmdline | head -n 1)"
[ -L "$INIT" ] && INIT=$(readlink "$INIT")
INIT="$(basename "$INIT")"
# 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."
fi
elif openwrt_fw4; then
info="openwrt firewall uses fw4. flow offloading requires nftables."
fi
}
elif openrc_test; then
SYSTEM=openrc
else
echo system is not either systemd, openrc or openwrt based
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
else
exitp 5
fi
fi
linux_get_subsys
elif [ "$UNAME" = "Darwin" ]; then
SYSTEM=macos
else
echo easy installer only supports Linux and MacOS. check readme.txt for supported systems and manual setup info.
exitp 5
fi
echo system is based on $SYSTEM
[ -n "$info" ] && echo $info
}
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_mb()
{
local R=$(get_ram_kb)
echo $(($R/1024))
}
crontab_del()
{
exists crontab || return
echo \* removing crontab entry
CRONTMP=/tmp/cron.tmp
crontab -l >$CRONTMP 2>/dev/null
if grep -q "$GET_LIST_PREFIX" $CRONTMP; then
echo removing following entries from crontab :
grep "$GET_LIST_PREFIX" $CRONTMP
grep -v "$GET_LIST_PREFIX" $CRONTMP >$CRONTMP.2
crontab $CRONTMP.2
rm -f $CRONTMP.2
fi
rm -f $CRONTMP
}
crontab_del_quiet()
{
exists crontab || return
CRONTMP=/tmp/cron.tmp
crontab -l >$CRONTMP 2>/dev/null
if grep -q "$GET_LIST_PREFIX" $CRONTMP; then
grep -v "$GET_LIST_PREFIX" $CRONTMP >$CRONTMP.2
crontab $CRONTMP.2
rm -f $CRONTMP.2
fi
rm -f $CRONTMP
}
crontab_add()
{
# $1 - hour min
# $2 - hour max
[ -x "$GET_LIST" ] && {
echo \* adding crontab entry
if exists crontab; then
CRONTMP=/tmp/cron.tmp
crontab -l >$CRONTMP 2>/dev/null
if grep -q "$GET_LIST_PREFIX" $CRONTMP; then
echo some entries already exist in crontab. check if this is corrent :
grep "$GET_LIST_PREFIX" $CRONTMP
else
end_with_newline <"$CRONTMP" || echo >>"$CRONTMP"
echo "$(random 0 59) $(random $1 $2) */2 * * $GET_LIST" >>$CRONTMP
crontab $CRONTMP
fi
rm -f $CRONTMP
else
echo '!!! CRON IS ABSENT !!! LISTS AUTO UPDATE WILL NOT WORK !!!'
fi
}
}
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()
{
echo \* starting zapret service
"$SYSTEMCTL" start zapret || {
echo could not start zapret service
exitp 30
}
}
service_stop_systemd()
{
echo \* stopping zapret service
"$SYSTEMCTL" daemon-reload
"$SYSTEMCTL" disable zapret
"$SYSTEMCTL" stop zapret
}
service_remove_systemd()
{
echo \* removing zapret service
rm -f "$SYSTEMD_SYSTEM_DIR/zapret.service"
"$SYSTEMCTL" daemon-reload
}
timer_remove_systemd()
{
echo \* removing zapret-list-update timer
"$SYSTEMCTL" daemon-reload
"$SYSTEMCTL" disable zapret-list-update.timer
"$SYSTEMCTL" stop zapret-list-update.timer
rm -f "$SYSTEMD_SYSTEM_DIR/zapret-list-update.service" "$SYSTEMD_SYSTEM_DIR/zapret-list-update.timer"
"$SYSTEMCTL" daemon-reload
}
install_sysv_init()
{
# $1 - "0"=disable
echo \* installing init script
[ -x "$INIT_SCRIPT" ] && {
"$INIT_SCRIPT" stop
"$INIT_SCRIPT" disable
}
ln -fs "$INIT_SCRIPT_SRC" "$INIT_SCRIPT"
[ "$1" != "0" ] && "$INIT_SCRIPT" enable
}
install_openrc_init()
{
# $1 - "0"=disable
echo \* installing init script
[ -x "$INIT_SCRIPT" ] && {
"$INIT_SCRIPT" stop
rc-update del zapret
}
ln -fs "$INIT_SCRIPT_SRC" "$INIT_SCRIPT"
[ "$1" != "0" ] && rc-update add zapret
}
service_remove_openrc()
{
echo \* removing zapret service
[ -x "$INIT_SCRIPT" ] && {
rc-update del zapret
"$INIT_SCRIPT" stop
}
rm -f "$INIT_SCRIPT"
}
service_start_sysv()
{
[ -x "$INIT_SCRIPT" ] && {
echo \* starting zapret service
"$INIT_SCRIPT" start || {
echo could not start zapret service
exitp 30
}
}
}
service_stop_sysv()
{
[ -x "$INIT_SCRIPT" ] && {
echo \* stopping zapret service
"$INIT_SCRIPT" stop
}
}
service_remove_sysv()
{
echo \* removing zapret service
[ -x "$INIT_SCRIPT" ] && {
"$INIT_SCRIPT" disable
"$INIT_SCRIPT" stop
}
rm -f "$INIT_SCRIPT"
}
check_kmod()
{
[ -f "/lib/modules/$(uname -r)/$1.ko" ]
}
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)"
[ -n "$what" ] || return 1
[ -n "$(opkg list-installed $what)" ]
}
check_packages_openwrt()
{
for pkg in $@; do
check_package_openwrt $pkg || return
done
}
install_openwrt_iface_hook()
{
echo \* installing ifup hook
ln -fs "$OPENWRT_IFACE_HOOK" /etc/hotplug.d/iface
}
remove_openwrt_iface_hook()
{
echo \* removing ifup hook
rm -f /etc/hotplug.d/iface/??-zapret
}
openwrt_fw_section_find()
{
# $1 - fw include postfix
# echoes section number
i=0
while true
do
path=$(uci -q get firewall.@include[$i].path)
[ -n "$path" ] || break
[ "$path" = "$OPENWRT_FW_INCLUDE$1" ] && {
echo $i
return 0
}
i=$(($i+1))
done
return 1
}
openwrt_fw_section_del()
{
# $1 - fw include postfix
local id="$(openwrt_fw_section_find $1)"
[ -n "$id" ] && {
uci delete firewall.@include[$id] && uci commit firewall
rm -f "$OPENWRT_FW_INCLUDE$1"
}
}
openwrt_fw_section_add()
{
openwrt_fw_section_find ||
{
uci add firewall include >/dev/null || return
echo -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
}
}
install_openwrt_firewall()
{
echo \* installing firewall script $1
[ -n "MODE" ] || {
echo should specify MODE in $ZAPRET_CONFIG
exitp 7
}
echo "linking : $FW_SCRIPT_SRC => $OPENWRT_FW_INCLUDE"
ln -fs "$FW_SCRIPT_SRC" "$OPENWRT_FW_INCLUDE"
openwrt_fw_section_configure $1
}
restart_openwrt_firewall()
{
echo \* restarting firewall
local FW=fw4
[ -n "$OPENWRT_FW3" ] && FW=fw3
$FW -q restart || {
echo could not restart firewall $FW
exitp 30
}
}
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()
{
echo "* clearing ipset(s)"
# free some RAM
"$IPSET_DIR/create_ipset.sh" clear
}
service_install_macos()
{
echo \* installing zapret service
ln -fs "$ZAPRET_BASE/init.d/macos/zapret.plist" /Library/LaunchDaemons
}
service_start_macos()
{
echo \* starting zapret service
"$INIT_SCRIPT_SRC" start
}
service_stop_macos()
{
echo \* stopping zapret service
"$INIT_SCRIPT_SRC" stop
}
service_remove_macos()
{
echo \* removing zapret service
rm -f /Library/LaunchDaemons/zapret.plist
zapret_stop_daemons
}
remove_macos_firewall()
{
echo \* removing zapret PF hooks
pf_anchors_clear
pf_anchors_del
pf_anchor_root_del
pf_anchor_root_reload
}
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 '' "$@"
else
sed -i "$@"
fi
}
write_config_var()
{
# $1 - mode var
local M
eval M="\$$1"
if grep -q "^$1=\|^#$1=" "$ZAPRET_CONFIG"; then
# replace / => \/
#M=${M//\//\\\/}
M=$(echo $M | sed 's/\//\\\//g')
if [ -n "$M" ]; then
if contains "$M" " "; then
sedi -Ee "s/^#?$1=.*$/$1=\"$M\"/" "$ZAPRET_CONFIG"
else
sedi -Ee "s/^#?$1=.*$/$1=$M/" "$ZAPRET_CONFIG"
fi
else
# write with comment at the beginning
sedi -Ee "s/^#?$1=.*$/#$1=/" "$ZAPRET_CONFIG"
fi
else
# var does not exist in config. add it
contains "$M" " " && M="\"$M\""
if [ -n "$M" ]; then
echo "$1=$M" >>"$ZAPRET_CONFIG"
else
echo "#$1=$M" >>"$ZAPRET_CONFIG"
fi
fi
}
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"
;;
esac
PKGS=$(for s in $req; do echo $s; done |
while read cmd; do
read pkg
exists $cmd || echo $pkg
done | sort -u | xargs)
UTILS=$(for s in $req; do echo $s; done |
while read cmd; do
read pkg
echo $cmd
done | sort -u | xargs)
if [ -z "$PKGS" ] ; then
echo required utilities exist : $UTILS
else
echo \* installing prerequisites
echo packages required : $PKGS
APTGET=$(whichq apt-get)
YUM=$(whichq yum)
PACMAN=$(whichq pacman)
ZYPPER=$(whichq zypper)
EOPKG=$(whichq eopkg)
APK=$(whichq apk)
if [ -x "$APTGET" ] ; then
"$APTGET" update
"$APTGET" install -y --no-install-recommends $PKGS dnsutils || {
echo could not install prerequisites
exitp 6
}
elif [ -x "$YUM" ] ; then
"$YUM" -y install $PKGS || {
echo could not install prerequisites
exitp 6
}
elif [ -x "$PACMAN" ] ; then
"$PACMAN" -Syy
"$PACMAN" --noconfirm -S $PKGS || {
echo could not install prerequisites
exitp 6
}
elif [ -x "$ZYPPER" ] ; then
"$ZYPPER" --non-interactive install $PKGS || {
echo could not install prerequisites
exitp 6
}
elif [ -x "$EOPKG" ] ; then
"$EOPKG" -y install $PKGS || {
echo could not install prerequisites
exitp 6
}
elif [ -x "$APK" ] ; then
"$APK" update
# for alpine
[ "$FWTYPE" = iptables ] && [ -n "$($APK list ip6tables)" ] && PKGS="$PKGS ip6tables"
"$APK" add $PKGS || {
echo could not install prerequisites
exitp 6
}
else
echo supported package manager not found
echo you must manually install : $UTILS
exitp 5
fi
fi
}
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"
;;
esac
if check_packages_openwrt $PKGS ; then
echo everything is present
else
echo \* installing prerequisites
opkg update
UPD=1
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.
echo ip/host list scripts will run much faster with GNU gzip
echo installer can install GNU gzip but it requires about 100 Kb space
if ask_yes_no N "do you want to install GNU gzip"; then
[ "$UPD" = "0" ] && {
opkg update
UPD=1
}
opkg install --force-overwrite gzip
fi
}
is_linked_to_busybox sort && {
echo
echo your system uses default busybox sort. its much slower and consumes much more RAM than GNU sort
echo ip/host list scripts will run much faster with GNU sort
echo installer can install GNU sort but it requires about 100 Kb space
if ask_yes_no N "do you want to install GNU sort"; then
[ "$UPD" = "0" ] && {
opkg update
UPD=1
}
opkg install --force-overwrite coreutils-sort
fi
}
[ "$FSLEEP" = 0 ] && is_linked_to_busybox sleep && {
echo
echo no methods of sub-second sleep were found.
echo if you want to speed up blockcheck install coreutils-sleep. it requires about 40 Kb space
if ask_yes_no N "do you want to install COREUTILS sleep"; then
[ "$UPD" = "0" ] && {
opkg update
UPD=1
}
opkg install --force-overwrite coreutils-sleep
fsleep_setup
fi
}
}
select_ipv6()
{
local T=N
[ "$DISABLE_IPV6" != '1' ] && T=Y
local old6=$DISABLE_IPV6
echo
if ask_yes_no $T "enable ipv6 support"; then
DISABLE_IPV6=0
else
DISABLE_IPV6=1
fi
[ "$old6" != "$DISABLE_IPV6" ] && write_config_var DISABLE_IPV6
}
select_fwtype()
{
echo
[ $(get_ram_mb) -le 400 ] && {
echo WARNING ! you are running a low RAM system
echo WARNING ! nft requires lots of RAM to load huge ip sets, much more than ipsets require
echo WARNING ! if you need large lists it may be necessary to fall back to iptables+ipset firewall
}
echo select firewall type :
ask_list FWTYPE "iptables nftables" "$FWTYPE" && write_config_var FWTYPE
}

472
common/ipt.sh Normal file
View File

@@ -0,0 +1,472 @@
std_ports
readonly ipt_connbytes="-m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes"
ipt()
{
iptables -C "$@" >/dev/null 2>/dev/null || iptables -I "$@"
}
ipta()
{
iptables -C "$@" >/dev/null 2>/dev/null || iptables -A "$@"
}
ipt_del()
{
iptables -C "$@" >/dev/null 2>/dev/null && iptables -D "$@"
}
ipt_add_del()
{
on_off_function ipt ipt_del "$@"
}
ipta_add_del()
{
on_off_function ipta ipt_del "$@"
}
ipt6()
{
ip6tables -C "$@" >/dev/null 2>/dev/null || ip6tables -I "$@"
}
ipt6a()
{
ip6tables -C "$@" >/dev/null 2>/dev/null || ip6tables -A "$@"
}
ipt6_del()
{
ip6tables -C "$@" >/dev/null 2>/dev/null && ip6tables -D "$@"
}
ipt6_add_del()
{
on_off_function ipt6 ipt6_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
}
filter_apply_port_target()
{
# $1 - var name of iptables filter
local f
if [ "$MODE_HTTP" = "1" ] && [ "$MODE_HTTPS" = "1" ]; then
f="-p tcp -m multiport --dports $HTTP_PORTS_IPT,$HTTPS_PORTS_IPT"
elif [ "$MODE_HTTPS" = "1" ]; then
f="-p tcp -m multiport --dports $HTTPS_PORTS_IPT"
elif [ "$MODE_HTTP" = "1" ]; then
f="-p tcp -m multiport --dports $HTTP_PORTS_IPT"
else
echo WARNING !!! HTTP and HTTPS are both disabled
fi
eval $1="\"\$$1 $f\""
}
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\""
}
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\""
fi
}
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\""
fi
}
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
}
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()
{
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
[ "$DISABLE_IPV4" = "1" ] || {
iptables -N input_rule_zapret 2>/dev/null
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()
{
[ "$DISABLE_IPV4" = "1" ] || {
unprepare_route_localnet
ipt_del INPUT ! -i lo -j input_rule_zapret
iptables -F input_rule_zapret 2>/dev/null
iptables -X input_rule_zapret 2>/dev/null
}
}
unprepare_tpws_fw()
{
unprepare_tpws_fw4
}
ipt_print_op()
{
if [ "$1" = "1" ]; then
echo "Adding ip$4tables rule for $3 : $2"
else
echo "Deleting ip$4tables rule for $3 : $2"
fi
}
_fw_tpws4()
{
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv4
# $3 - tpws port
# $4 - lan interface names space separated
# $5 - wan interface names space separated
[ "$DISABLE_IPV4" = "1" -o -z "$2" ] || {
local i rule
[ "$1" = 1 ] && prepare_tpws_fw4
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
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
done
else
ipt_add_del $1 OUTPUT -t nat $rule
fi
}
}
_fw_tpws6()
{
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv6
# $3 - tpws port
# $4 - lan interface names space separated
# $5 - wan interface names space separated
[ "$DISABLE_IPV6" = "1" -o -z "$2" ] || {
local i rule DNAT6
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
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
done
else
ipt6_add_del $1 OUTPUT -t nat $rule
fi
}
}
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_nfqws_post4()
{
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv4
# $3 - queue number
# $4 - wan interface names space separated
[ "$DISABLE_IPV4" = "1" -o -z "$2" ] || {
local i
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
for i in $4; do
ipt_add_del $1 POSTROUTING -t mangle -o $i $rule
done
else
ipt_add_del $1 POSTROUTING -t mangle $rule
fi
}
}
_fw_nfqws_post6()
{
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv6
# $3 - queue number
# $4 - wan interface names space separated
[ "$DISABLE_IPV6" = "1" -o -z "$2" ] || {
local i
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
for i in $4; do
ipt6_add_del $1 POSTROUTING -t mangle -o $i $rule
done
else
ipt6_add_del $1 POSTROUTING -t mangle $rule
fi
}
}
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_pre4()
{
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv4
# $3 - queue number
# $4 - wan interface names space separated
[ "$DISABLE_IPV4" = "1" -o -z "$2" ] || {
local i
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
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
done
else
ipt_add_del $1 INPUT -t mangle $rule
ipt_add_del $1 FORWARD -t mangle $rule
fi
}
}
_fw_nfqws_pre6()
{
# $1 - 1 - add, 0 - del
# $2 - iptable filter for ipv6
# $3 - queue number
# $4 - wan interface names space separated
[ "$DISABLE_IPV6" = "1" -o -z "$2" ] || {
local i
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
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
done
else
ipt6_add_del $1 INPUT -t mangle $rule
ipt6_add_del $1 FORWARD -t mangle $rule
fi
}
}
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
}
produce_reverse_nfqws_rule()
{
local rule="$1"
if contains "$rule" "$ipt_connbytes"; then
# autohostlist - need several incoming packets
# autottl - need only one incoming packet
[ "$MODE_FILTER" = autohostlist ] || rule=$(echo "$rule" | sed -re "s/$ipt_connbytes [0-9]+:[0-9]+/$ipt_connbytes 1:1/")
else
local n=1
[ "$MODE_FILTER" = autohostlist ] && n=$(first_packets_for_mode)
rule="$ipt_connbytes 1:$n $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_rule6()
{
fw_nfqws_pre6 $1 "$(produce_reverse_nfqws_rule "$2")" $3
}
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
}
zapret_do_firewall_rules_ipt()
{
local mode="${MODE_OVERRIDE:-$MODE}"
local first_packet_only="$ipt_connbytes 1:$(first_packets_for_mode)"
local desync="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK"
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
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)
custom_runner zapret_custom_firewall $1
;;
esac
}
zapret_do_firewall_ipt()
{
# $1 - 1 - add, 0 - del
if [ "$1" = 1 ]; then
echo Applying iptables
else
echo Clearing iptables
fi
local mode="${MODE_OVERRIDE:-$MODE}"
[ "$mode" = "tpws-socks" ] && return 0
# always create ipsets. ip_exclude ipset is required
[ "$1" = 1 ] && create_ipset no-update
zapret_do_firewall_rules_ipt "$@"
if [ "$1" = 1 ] ; then
existf flow_offloading_exempt && flow_offloading_exempt
else
existf flow_offloading_unexempt && flow_offloading_unexempt
unprepare_tpws_fw
fi
return 0
}

53
common/linux_fw.sh Normal file
View File

@@ -0,0 +1,53 @@
set_conntrack_liberal_mode()
{
[ -n "$SKIP_CONNTRACK_LIBERAL_MODE" ] || sysctl -w net.netfilter.nf_conntrack_tcp_be_liberal=$1
}
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 "$@"
;;
esac
# russian DPI sends RST,ACK with wrong ACK.
# this is sometimes treated by conntrack as invalid and connbytes fw rules do not pass RST packet to nfqws.
# 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
[ "$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_do_firewall 1 "$@"
}
zapret_unapply_firewall()
{
zapret_do_firewall 0 "$@"
}
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}))
else
n=6
fi
echo $n
}

127
common/linux_iphelper.sh Normal file
View File

@@ -0,0 +1,127 @@
# there's no route_localnet for ipv6
# the best we can is to route to link local of the incoming interface
# OUTPUT - can DNAT to ::1
# 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_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()
{
# $1 - interface name
[ -f /sys/class/net/$1/operstate ] || return
local state
read state </sys/class/net/$1/operstate
[ "$state" != "down" ]
}
wait_ifup()
{
# $1 - interface name
local ct=0
while
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))
sleep 1
do :; done
false
}
_dnat6_target()
{
# $1 - interface name
# $2 - var to store target ip6
# get target ip address for DNAT. prefer link locals
# tpws should be as inaccessible from outside as possible
# link local address can appear not immediately after ifup
# 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')
eval DNAT6_TARGET="\$$DVAR"
[ -n "$2" ] && eval $2=''
[ -n "$DNAT6_TARGET" ] || {
local ct=0
while
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))
sleep 1
do :; done
[ -n "$DNAT6_TARGET" ] || {
echo $1: no link local. getting global
DNAT6_TARGET=$(get_ipv6_global $1)
[ -n "$DNAT6_TARGET" ] || {
echo $1: could not get any address
DNAT6_TARGET=-
}
}
eval $DVAR="$DNAT6_TARGET"
}
[ -n "$2" ] && eval $2="$DNAT6_TARGET"
}
_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"
shift
done
}
}
prepare_route_localnet()
{
set_route_localnet 1 "$@"
}
unprepare_route_localnet()
{
set_route_localnet 0 "$@"
}
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"
}
}
}

55
common/list.sh Normal file
View File

@@ -0,0 +1,55 @@
find_hostlists()
{
[ -n "$HOSTLIST_BASE" ] || HOSTLIST_BASE="$ZAPRET_BASE/ipset"
HOSTLIST="$HOSTLIST_BASE/zapret-hosts.txt.gz"
[ -f "$HOSTLIST" ] || HOSTLIST="$HOSTLIST_BASE/zapret-hosts.txt"
[ -f "$HOSTLIST" ] || HOSTLIST=
HOSTLIST_USER="$HOSTLIST_BASE/zapret-hosts-user.txt.gz"
[ -f "$HOSTLIST_USER" ] || HOSTLIST_USER="$HOSTLIST_BASE/zapret-hosts-user.txt"
[ -f "$HOSTLIST_USER" ] || HOSTLIST_USER=
HOSTLIST_EXCLUDE="$HOSTLIST_BASE/zapret-hosts-user-exclude.txt.gz"
[ -f "$HOSTLIST_EXCLUDE" ] || HOSTLIST_EXCLUDE="$HOSTLIST_BASE/zapret-hosts-user-exclude.txt"
[ -f "$HOSTLIST_EXCLUDE" ] || HOSTLIST_EXCLUDE=
HOSTLIST_AUTO="$HOSTLIST_BASE/zapret-hosts-auto.txt"
HOSTLIST_AUTO_DEBUGLOG="$HOSTLIST_BASE/zapret-hosts-auto-debug.log"
}
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\""
}
filter_apply_hostlist_target()
{
# $1 - var name of tpws or nfqws params
[ "$MODE_FILTER" = "hostlist" -o "$MODE_FILTER" = "autohostlist" ] || return
local HOSTLIST_BASE HOSTLIST HOSTLIST_USER HOSTLIST_EXCLUDE
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
}
filter_apply_suffix()
{
# $1 - var name of tpws or nfqws params
# $2 - suffix value
local v="${2:+ --new $2}"
eval $1="\"\$$1$v\""
}

750
common/nft.sh Normal file
View File

@@ -0,0 +1,750 @@
[ -n "$ZAPRET_NFT_TABLE" ] || ZAPRET_NFT_TABLE=zapret
readonly nft_connbytes="ct original packets"
# required for : nft -f -
create_dev_stdin
std_ports
nft_create_table()
{
nft add table inet $ZAPRET_NFT_TABLE
}
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_create_set()
{
# $1 - set name
# $2 - params
nft create set inet $ZAPRET_NFT_TABLE $1 "{ $2 }" 2>/dev/null
}
nft_del_set()
{
# $1 - set name
nft delete set inet $ZAPRET_NFT_TABLE $1
}
nft_flush_set()
{
# $1 - set name
nft flush set inet $ZAPRET_NFT_TABLE $1
}
nft_set_exists()
{
# $1 - set name
nft -t list set inet $ZAPRET_NFT_TABLE $1 2>/dev/null >/dev/null
}
nft_flush_chain()
{
# $1 - chain name
nft flush chain inet $ZAPRET_NFT_TABLE $1
}
nft_del_all_chains_from_table()
{
# $1 - table_name with or without family
# delete all chains with possible references to each other
# cannot just delete all in the list because of references
# 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)
[ -n "$chains" ] || break
deleted=
error=
for chain in $chains; do
if nft delete chain $1 $chain 2>/dev/null; then
deleted=1
else
error=1
fi
done
done
}
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; }
flush chain inet $ZAPRET_NFT_TABLE dnat_pre
add chain inet $ZAPRET_NFT_TABLE forward { type filter hook forward priority -1; }
flush chain inet $ZAPRET_NFT_TABLE forward
add chain inet $ZAPRET_NFT_TABLE input { type filter hook input priority -1; }
flush chain inet $ZAPRET_NFT_TABLE input
add chain inet $ZAPRET_NFT_TABLE flow_offload
flush chain inet $ZAPRET_NFT_TABLE flow_offload
add chain inet $ZAPRET_NFT_TABLE localnet_protect
flush chain inet $ZAPRET_NFT_TABLE localnet_protect
add rule inet $ZAPRET_NFT_TABLE localnet_protect ip daddr $TPWS_LOCALHOST4 return comment "route_localnet allow access to tpws"
add rule inet $ZAPRET_NFT_TABLE localnet_protect ip daddr 127.0.0.0/8 drop comment "route_localnet remote access protection"
add rule inet $ZAPRET_NFT_TABLE input iif != lo jump localnet_protect
add chain inet $ZAPRET_NFT_TABLE postrouting { type filter hook postrouting priority 99; }
flush chain inet $ZAPRET_NFT_TABLE postrouting
add chain inet $ZAPRET_NFT_TABLE postnat { type filter hook postrouting priority 101; }
flush chain inet $ZAPRET_NFT_TABLE postnat
add chain inet $ZAPRET_NFT_TABLE prerouting { type filter hook prerouting priority -99; }
flush chain inet $ZAPRET_NFT_TABLE prerouting
add chain inet $ZAPRET_NFT_TABLE prenat { type filter hook prerouting priority -101; }
flush chain inet $ZAPRET_NFT_TABLE prenat
add chain inet $ZAPRET_NFT_TABLE predefrag { type filter hook output priority -401; }
flush chain inet $ZAPRET_NFT_TABLE predefrag
add chain inet $ZAPRET_NFT_TABLE predefrag_nfqws
flush chain inet $ZAPRET_NFT_TABLE predefrag_nfqws
add rule inet $ZAPRET_NFT_TABLE predefrag mark and $DESYNC_MARK !=0 jump predefrag_nfqws comment "nfqws generated : avoid drop by INVALID conntrack state"
add rule inet $ZAPRET_NFT_TABLE predefrag_nfqws mark and $DESYNC_MARK_POSTNAT !=0 notrack comment "postnat traffic"
add rule inet $ZAPRET_NFT_TABLE predefrag_nfqws ip frag-off != 0 notrack comment "ipfrag"
add rule inet $ZAPRET_NFT_TABLE predefrag_nfqws exthdr frag exists notrack comment "ipfrag"
add rule inet $ZAPRET_NFT_TABLE predefrag_nfqws tcp flags ! syn,rst,ack notrack comment "datanoack"
add set inet $ZAPRET_NFT_TABLE lanif { type ifname; }
add set inet $ZAPRET_NFT_TABLE wanif { type ifname; }
add set inet $ZAPRET_NFT_TABLE wanif6 { type ifname; }
add map inet $ZAPRET_NFT_TABLE link_local { type ifname : ipv6_addr; }
EOF
[ -n "$POSTNAT_ALL" ] && {
nft_flush_chain predefrag_nfqws
nft_add_rule predefrag_nfqws notrack comment \"do not track nfqws generated packets to avoid nat tampering and defragmentation\"
}
}
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
delete chain inet $ZAPRET_NFT_TABLE dnat_output
delete chain inet $ZAPRET_NFT_TABLE dnat_pre
delete chain inet $ZAPRET_NFT_TABLE forward
delete chain inet $ZAPRET_NFT_TABLE input
delete chain inet $ZAPRET_NFT_TABLE postrouting
delete chain inet $ZAPRET_NFT_TABLE postnat
delete chain inet $ZAPRET_NFT_TABLE prerouting
delete chain inet $ZAPRET_NFT_TABLE prenat
delete chain inet $ZAPRET_NFT_TABLE predefrag
delete chain inet $ZAPRET_NFT_TABLE predefrag_nfqws
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
}
nft_del_flowtable()
{
nft delete flowtable inet $ZAPRET_NFT_TABLE ft 2>/dev/null
}
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
local flags=$1 devices makelist
shift
# warning ! nft versions at least up to 1.0.1 do not allow interface names starting with digit in flowtable and do not allow quoting
# warning ! openwrt fixes this in post-21.x snapshots with special nft patch
# warning ! in traditional linux distros nft is unpatched and will fail with quoted interface definitions if unfixed
[ -n "$flags" ] && flags="flags $flags;"
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
done
}
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_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_table
nft_del_flowtable
nft_flush_link_local
nft_create_chains
}
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()
{
# $1 - chain
# $2,$3,... - rule(s)
local chain="$1"
shift
nft add rule inet $ZAPRET_NFT_TABLE $chain "$@"
}
nft_add_set_element()
{
# $1 - set or map name
# $2 - element
[ -z "$2" ] || nft add element inet $ZAPRET_NFT_TABLE $1 "{ $2 }"
}
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_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()
{
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()
{
# $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\"
# 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()
{
# "$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\"
}
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
return $res
}
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
}
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\"
# allow only outgoing packets to initiate flow offload
nft_add_rule forward oifname @wanif jump flow_offload
nft_add_rule forward oifname @wanif6 jump flow_offload
}
}
nft_filter_apply_port_target()
{
# $1 - var name of nftables filter
local f
if [ "$MODE_HTTP" = "1" ] && [ "$MODE_HTTPS" = "1" ]; then
f="tcp dport {$HTTP_PORTS,$HTTPS_PORTS}"
elif [ "$MODE_HTTPS" = "1" ]; then
f="tcp dport {$HTTPS_PORTS}"
elif [ "$MODE_HTTP" = "1" ]; then
f="tcp dport {$HTTP_PORTS}"
else
echo WARNING !!! HTTP and HTTPS are both disabled
fi
eval $1="\"\$$1 $f\""
}
nft_filter_apply_port_target_quic()
{
# $1 - var name of nftables filter
local f
f="udp dport {$QUIC_PORTS}"
eval $1="\"\$$1 $f\""
}
nft_filter_apply_ipset_target4()
{
# $1 - var name of ipv4 nftables filter
if [ "$MODE_FILTER" = "ipset" ]; then
eval $1="\"\$$1 ip daddr @zapret\""
fi
}
nft_filter_apply_ipset_target6()
{
# $1 - var name of ipv6 nftables filter
if [ "$MODE_FILTER" = "ipset" ]; then
eval $1="\"\$$1 ip6 daddr @zapret6\""
fi
}
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_script_add_ifset_element()
{
# $1 - set name
# $2 - space separated elements
local elements
[ -n "$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)
local script i j ALLDEVS devs
# if large sets exist nft works very ineffectively
# looks like it analyzes the whole table blob to find required data pieces
# calling all in one shot helps not to waste cpu time many times
script="flush set inet $ZAPRET_NFT_TABLE wanif
flush set inet $ZAPRET_NFT_TABLE wanif6
flush set inet $ZAPRET_NFT_TABLE lanif"
[ "$DISABLE_IPV4" = "1" ] || nft_script_add_ifset_element wanif "$2"
[ "$DISABLE_IPV6" = "1" ] || nft_script_add_ifset_element wanif6 "$3"
nft_script_add_ifset_element lanif "$1"
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
;;
esac
}
nft_only()
{
linux_fwtype
case "$FWTYPE" in
nftables)
"$@"
;;
esac
}
nft_print_op()
{
echo "Adding nftables ipv$3 rule for $2 : $1"
}
_nft_fw_tpws4()
{
# $1 - filter ipv4
# $2 - tpws port
# $3 - not-empty if wan interface filtering required
[ "$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
prepare_route_localnet
}
}
_nft_fw_tpws6()
{
# $1 - filter ipv6
# $2 - tpws port
# $3 - lan interface names space separated
# $4 - not-empty if wan interface filtering required
[ "$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
[ -n "$3" ] && {
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
# can be multiple tpws processes on different ports
[ -n "$DNAT6" -a "$DNAT6" != '-' ] && nft_add_set_element link_local "$i : $DNAT6"
done
}
}
}
nft_fw_tpws()
{
# $1 - filter ipv4
# $2 - filter ipv6
# $3 - tpws port
nft_fw_tpws4 "$1" $3
nft_fw_tpws6 "$2" $3
}
is_postnat()
{
[ "$POSTNAT" != 0 -o "$POSTNAT_ALL" = 1 ]
}
get_postchain()
{
if is_postnat ; then
echo -n postnat
else
echo -n postrouting
fi
}
get_prechain()
{
if is_postnat ; then
echo -n prenat
else
echo -n prerouting
fi
}
_nft_fw_nfqws_post4()
{
# $1 - filter ipv4
# $2 - queue number
# $3 - not-empty if wan interface filtering required
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" rule chain=$(get_postchain) setmark
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_nfqws_flow_exempt_rule "$rule"
}
}
_nft_fw_nfqws_post6()
{
# $1 - filter ipv6
# $2 - queue number
# $3 - not-empty if wan interface filtering required
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" rule chain=$(get_postchain) setmark
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_nfqws_flow_exempt_rule "$rule"
}
}
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_pre4()
{
# $1 - filter ipv4
# $2 - queue number
# $3 - not-empty if wan interface filtering required
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
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_fw_nfqws_pre6()
{
# $1 - filter ipv6
# $2 - queue number
# $3 - not-empty if wan interface filtering required
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
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_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_both4()
{
# $1 - filter ipv4
# $2 - queue number
nft_fw_nfqws_post4 "$@"
nft_fw_nfqws_pre4 "$(nft_reverse_nfqws_rule $1)" $2
}
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_both()
{
# $1 - filter ipv4
# $2 - filter ipv6
# $3 - queue number
nft_fw_nfqws_both4 "$1" "$3"
nft_fw_nfqws_both6 "$2" "$3"
}
zapret_reload_ifsets()
{
nft_only nft_create_table ; nft_fill_ifsets_overload
return 0
}
zapret_list_ifsets()
{
nft_only nft_list_ifsets
return 0
}
zapret_list_table()
{
nft_only nft_list_table
return 0
}
nft_produce_reverse_nfqws_rule()
{
local rule="$1"
if contains "$rule" "$nft_connbytes "; then
# autohostlist - need several incoming packets
# autottl - need only one incoming packet
[ "$MODE_FILTER" = autohostlist ] || rule=$(echo "$rule" | sed -re "s/$nft_connbytes [0-9]+-[0-9]+/$nft_connbytes 1/")
else
# old nft does not swallow 1-1
local range=1
[ "$MODE_FILTER" = autohostlist ] && range=$(first_packets_for_mode)
[ "$range" = 1 ] || range="1-$range"
rule="$nft_connbytes $range $rule"
fi
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_rule6()
{
nft_fw_nfqws_pre6 "$(nft_produce_reverse_nfqws_rule "$1")" $2
}
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
}
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
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
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)
custom_runner zapret_custom_firewall_nft
;;
esac
}
zapret_apply_firewall_nft()
{
echo Applying nftables
local mode="${MODE_OVERRIDE:-$MODE}"
[ "$mode" = "tpws-socks" ] && return 0
create_ipset no-update
nft_create_firewall
nft_fill_ifsets_overload
zapret_apply_firewall_rules_nft
[ "$FLOWOFFLOAD" = 'software' -o "$FLOWOFFLOAD" = 'hardware' ] && nft_apply_flow_offloading
return 0
}
zapret_unapply_firewall_nft()
{
echo Clearing nftables
unprepare_route_localnet
nft_del_firewall
return 0
}
zapret_do_firewall_nft()
{
# $1 - 1 - add, 0 - del
if [ "$1" = 0 ] ; then
zapret_unapply_firewall_nft
else
zapret_apply_firewall_nft
fi
return 0
}

285
common/pf.sh Normal file
View File

@@ -0,0 +1,285 @@
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"
std_ports
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_nat_reorder_rules()
{
# this is dirty hack to move rdr above route-to and remove route-to dups
sort -rfu
}
pf_anchor_port_target()
{
if [ "$MODE_HTTP" = "1" ] && [ "$MODE_HTTPS" = "1" ]; then
echo "{$HTTP_PORTS_IPT,$HTTPS_PORTS_IPT}"
elif [ "$MODE_HTTPS" = "1" ]; then
echo "{$HTTPS_PORTS_IPT}"
elif [ "$MODE_HTTP" = "1" ]; then
echo "{$HTTP_PORTS_IPT}"
fi
}
pf_anchor_zapret_v4_tpws()
{
# $1 - tpws listen port
# $2 - rdr ports. defaults are used if empty
local rule port
if [ -n "$2" ]; then
port="{$2}"
else
port=$(pf_anchor_port_target)
fi
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_OVERRIDE:-$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"
custom_runner zapret_custom_firewall_v4 | pf_nat_reorder_rules
;;
esac
}
}
pf_anchor_zapret_v6_tpws()
{
# $1 - tpws listen port
# $2 - rdr ports. defaults are used if empty
local rule LL_LAN port
if [ -n "$2" ]; then
port="{$2}"
else
port=$(pf_anchor_port_target)
fi
# 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_WAN6:-$IFACE_WAN}" ] ; then
for wan in ${IFACE_WAN6:-$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_OVERRIDE:-$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"
custom_runner zapret_custom_firewall_v6 | pf_nat_reorder_rules
;;
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"
}

85
common/queue.sh Normal file
View File

@@ -0,0 +1,85 @@
apply_unspecified_desync_modes()
{
NFQWS_OPT_DESYNC_HTTP="${NFQWS_OPT_DESYNC_HTTP:-$NFQWS_OPT_DESYNC}"
NFQWS_OPT_DESYNC_HTTP_SUFFIX="${NFQWS_OPT_DESYNC_HTTP_SUFFIX:-$NFQWS_OPT_DESYNC_SUFFIX}"
NFQWS_OPT_DESYNC_HTTPS="${NFQWS_OPT_DESYNC_HTTPS:-$NFQWS_OPT_DESYNC}"
NFQWS_OPT_DESYNC_HTTPS_SUFFIX="${NFQWS_OPT_DESYNC_HTTPS_SUFFIX:-$NFQWS_OPT_DESYNC_SUFFIX}"
NFQWS_OPT_DESYNC_HTTP6="${NFQWS_OPT_DESYNC_HTTP6:-$NFQWS_OPT_DESYNC_HTTP}"
NFQWS_OPT_DESYNC_HTTP6_SUFFIX="${NFQWS_OPT_DESYNC_HTTP6_SUFFIX:-$NFQWS_OPT_DESYNC_HTTP_SUFFIX}"
NFQWS_OPT_DESYNC_HTTPS6="${NFQWS_OPT_DESYNC_HTTPS6:-$NFQWS_OPT_DESYNC_HTTPS}"
NFQWS_OPT_DESYNC_HTTPS6_SUFFIX="${NFQWS_OPT_DESYNC_HTTPS6_SUFFIX:-$NFQWS_OPT_DESYNC_HTTPS_SUFFIX}"
NFQWS_OPT_DESYNC_QUIC6="${NFQWS_OPT_DESYNC_QUIC6:-$NFQWS_OPT_DESYNC_QUIC}"
NFQWS_OPT_DESYNC_QUIC6_SUFFIX="${NFQWS_OPT_DESYNC_QUIC6_SUFFIX:-$NFQWS_OPT_DESYNC_QUIC_SUFFIX}"
}
get_nfqws_qnums()
{
# $1 - var name for ipv4 http
# $2 - var name for ipv4 https
# $3 - var name for ipv6 http
# $4 - var name for ipv6 https
local _qn _qns _qn6 _qns6
[ "$DISABLE_IPV4" = "1" ] || {
_qn=$QNUM
_qns=$_qn
[ "$NFQWS_OPT_DESYNC_HTTP $NFQWS_OPT_DESYNC_HTTP_SUFFIX" = "$NFQWS_OPT_DESYNC_HTTPS $NFQWS_OPT_DESYNC_HTTPS_SUFFIX" ] || _qns=$(($QNUM+1))
}
[ "$DISABLE_IPV6" = "1" ] || {
_qn6=$(($QNUM+2))
_qns6=$(($QNUM+3))
[ "$DISABLE_IPV4" = "1" ] || {
if [ "$NFQWS_OPT_DESYNC_HTTP6 $NFQWS_OPT_DESYNC_HTTP6_SUFFIX" = "$NFQWS_OPT_DESYNC_HTTP $NFQWS_OPT_DESYNC_HTTP_SUFFIX" ]; then
_qn6=$_qn;
elif [ "$NFQWS_OPT_DESYNC_HTTP6 $NFQWS_OPT_DESYNC_HTTP6_SUFFIX" = "$NFQWS_OPT_DESYNC_HTTPS $NFQWS_OPT_DESYNC_HTTPS_SUFFIX" ]; then
_qn6=$_qns;
fi
if [ "$NFQWS_OPT_DESYNC_HTTPS6 $NFQWS_OPT_DESYNC_HTTPS6_SUFFIX" = "$NFQWS_OPT_DESYNC_HTTP $NFQWS_OPT_DESYNC_HTTP_SUFFIX" ]; then
_qns6=$_qn;
elif [ "$NFQWS_OPT_DESYNC_HTTPS6 $NFQWS_OPT_DESYNC_HTTPS6_SUFFIX" = "$NFQWS_OPT_DESYNC_HTTPS $NFQWS_OPT_DESYNC_HTTPS_SUFFIX" ]; then
_qns6=$_qns;
fi
}
[ "$NFQWS_OPT_DESYNC_HTTPS6 $NFQWS_OPT_DESYNC_HTTPS6_SUFFIX" = "$NFQWS_OPT_DESYNC_HTTP6 $NFQWS_OPT_DESYNC_HTTP6_SUFFIX" ] && _qns6=$_qn6;
}
if [ "$MODE_HTTP" = 1 ]; then
eval $1=$_qn
eval $3=$_qn6
else
eval $1=
eval $3=
fi
if [ "$MODE_HTTPS" = 1 ]; then
eval $2=$_qns
eval $4=$_qns6
else
eval $2=
eval $4=
fi
}
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))
}
[ "$DISABLE_IPV6" = "1" ] || {
_qn6=$(($QNUM+11))
[ "$DISABLE_IPV4" = "1" ] || {
if [ "$NFQWS_OPT_DESYNC_QUIC $NFQWS_OPT_DESYNC_QUIC_SUFFIX" = "$NFQWS_OPT_DESYNC_QUIC6 $NFQWS_OPT_DESYNC_QUIC6_SUFFIX" ]; then
_qn6=$_qn;
fi
}
}
if [ "$MODE_QUIC" = 1 ]; then
eval $1=$_qn
eval $2=$_qn6
else
eval $1=
eval $2=
fi
}

39
common/virt.sh Normal file
View File

@@ -0,0 +1,39 @@
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
;;
esac
echo "$vm" | awk '{print tolower($0)}'
}
check_virt()
{
echo \* checking virtualization
local vm="$(get_virt)"
if [ -n "$vm" ]; then
if [ "$vm" = "none" ]; then
echo running on bare metal
else
echo "!!! WARNING. $vm virtualization detected !!!"
echo '!!! WARNING. vmware and virtualbox are known to break most of the DPI bypass techniques when network is NATed using internal hypervisor NAT !!!'
echo '!!! WARNING. if this is your case make sure you are bridged not NATed !!!'
fi
else
echo cannot detect
fi
}