mirror of https://github.com/bol-van/zapret/
commit
2aaa2f7cf3
300 changed files with 43184 additions and 0 deletions
@ -0,0 +1,4 @@ |
|||
* text=auto eol=lf |
|||
binaries/win64/readme.txt eol=crlf |
|||
*.cmd eol=crlf |
|||
*.bat eol=crlf |
@ -0,0 +1,12 @@ |
|||
config |
|||
ip2net/ip2net |
|||
mdig/mdig |
|||
nfq/nfqws |
|||
tpws/tpws |
|||
binaries/my/ |
|||
binaries/win64/zapret-winws/autohostlist.txt |
|||
init.d/**/custom |
|||
ipset/zapret-ip*.txt |
|||
ipset/zapret-ip*.gz |
|||
ipset/zapret-hosts*.txt |
|||
ipset/zapret-hosts*.gz |
@ -0,0 +1,48 @@ |
|||
DIRS := nfq tpws ip2net mdig |
|||
DIRS_MAC := tpws ip2net mdig |
|||
TGT := binaries/my |
|||
|
|||
all: clean |
|||
@mkdir -p "$(TGT)"; \
|
|||
for dir in $(DIRS); do \
|
|||
find "$$dir" -type f \( -name "*.c" -o -name "*.h" -o -name "*akefile" \) -exec chmod -x {} \; ; \
|
|||
$(MAKE) -C "$$dir" || exit; \
|
|||
for exe in "$$dir/"*; do \
|
|||
if [ -f "$$exe" ] && [ -x "$$exe" ]; then \
|
|||
mv -f "$$exe" "${TGT}" ; \
|
|||
ln -fs "../${TGT}/$$(basename "$$exe")" "$$exe" ; \
|
|||
fi \
|
|||
done \
|
|||
done |
|||
|
|||
bsd: clean |
|||
@mkdir -p "$(TGT)"; \
|
|||
for dir in $(DIRS); do \
|
|||
find "$$dir" -type f \( -name "*.c" -o -name "*.h" -o -name "*akefile" \) -exec chmod -x {} \; ; \
|
|||
$(MAKE) -C "$$dir" bsd || exit; \
|
|||
for exe in "$$dir/"*; do \
|
|||
if [ -f "$$exe" ] && [ -x "$$exe" ]; then \
|
|||
mv -f "$$exe" "${TGT}" ; \
|
|||
ln -fs "../${TGT}/$$(basename "$$exe")" "$$exe" ; \
|
|||
fi \
|
|||
done \
|
|||
done |
|||
|
|||
mac: clean |
|||
@mkdir -p "$(TGT)"; \
|
|||
for dir in $(DIRS_MAC); do \
|
|||
find "$$dir" -type f \( -name "*.c" -o -name "*.h" -o -name "*akefile" \) -exec chmod -x {} \; ; \
|
|||
$(MAKE) -C "$$dir" mac || exit; \
|
|||
for exe in "$$dir/"*; do \
|
|||
if [ -f "$$exe" ] && [ -x "$$exe" ]; then \
|
|||
mv -f "$$exe" "${TGT}" ; \
|
|||
ln -fs "../${TGT}/$$(basename "$$exe")" "$$exe" ; \
|
|||
fi \
|
|||
done \
|
|||
done |
|||
|
|||
clean: |
|||
@[ -d "$(TGT)" ] && rm -rf "$(TGT)" ; \
|
|||
for dir in $(DIRS); do \
|
|||
$(MAKE) -C "$$dir" clean; \
|
|||
done |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,9 @@ |
|||
Standalone version in zapret-winws folder !! |
|||
From this folder winws can be started only from cygwin shell. |
|||
|
|||
Cygwin refuses to start winws if a copy of cygwin1.dll is present ! |
|||
|
|||
How to get win7 and winws compatible version of cygwin : |
|||
|
|||
curl -O https://www.cygwin.com/setup-x86_64.exe |
|||
setup-x86_64.exe --allow-unsupported-windows --no-verify --site http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,3 @@ |
|||
googlevideo.com |
|||
youtubei.googleapis.com |
|||
i.ytimg.com |
@ -0,0 +1,7 @@ |
|||
start "zapret: http,https,quic" /min "%~dp0winws.exe" ^ |
|||
--wf-tcp=80,443 --wf-udp=443 ^ |
|||
--filter-udp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake --dpi-desync-repeats=11 --dpi-desync-fake-quic="%~dp0quic_initial_www_google_com.bin" --new ^ |
|||
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=11 --new ^ |
|||
--filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --new ^ |
|||
--filter-tcp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls="%~dp0tls_clienthello_www_google_com.bin" --new ^ |
|||
--dpi-desync=fake,disorder2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig |
@ -0,0 +1,7 @@ |
|||
start "zapret: http,https,quic" /min "%~dp0winws.exe" ^ |
|||
--wf-tcp=80,443 --wf-udp=443 ^ |
|||
--filter-udp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake --dpi-desync-repeats=11 --dpi-desync-fake-quic="%~dp0quic_initial_www_google_com.bin" --new ^ |
|||
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=11 --new ^ |
|||
--filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --hostlist-auto="%~dp0autohostlist.txt" --new ^ |
|||
--filter-tcp=443 --hostlist="%~dp0list-youtube.txt" --dpi-desync=fake,split2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls="%~dp0tls_clienthello_www_google_com.bin" --new ^ |
|||
--dpi-desync=fake,disorder2 --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --hostlist-auto="%~dp0autohostlist.txt" |
Binary file not shown.
@ -0,0 +1,12 @@ |
|||
set ARGS=--wf-l3=ipv4,ipv6 --wf-tcp=80,443 --dpi-desync=fake,split --dpi-desync-ttl=7 --dpi-desync-fooling=md5sig |
|||
call :srvinst winws1 |
|||
rem set ARGS=--wf-l3=ipv4,ipv6 --wf-udp=443 --dpi-desync=fake |
|||
rem call :srvinst winws2 |
|||
goto :eof |
|||
|
|||
:srvinst |
|||
net stop %1 |
|||
sc delete %1 |
|||
sc create %1 binPath= "\"%~dp0winws.exe\" %ARGS%" DisplayName= "zapret DPI bypass : %1" start= auto |
|||
sc description %1 "zapret DPI bypass software" |
|||
sc start %1 |
@ -0,0 +1,7 @@ |
|||
call :srvdel winws1 |
|||
rem call :srvdel winws2 |
|||
goto :eof |
|||
|
|||
:srvdel |
|||
net stop %1 |
|||
sc delete %1 |
@ -0,0 +1,2 @@ |
|||
sc start winws1 |
|||
rem sc start winws2 |
@ -0,0 +1,2 @@ |
|||
net stop winws1 |
|||
rem net stop winws2 |
@ -0,0 +1,4 @@ |
|||
set WINWS1=--wf-l3=ipv4,ipv6 --wf-tcp=80,443 --dpi-desync=fake,split --dpi-desync-ttl=7 --dpi-desync-fooling=md5sig |
|||
schtasks /Create /F /TN winws1 /NP /RU "" /SC onstart /TR "\"%~dp0winws.exe\" %WINWS1%" |
|||
rem set WINWS2=--wf-l3=ipv4,ipv6 --wf-udp=443 --dpi-desync=fake |
|||
rem schtasks /Create /F /TN winws2 /NP /RU "" /SC onstart /TR "\"%~dp0winws.exe\" %WINWS2%" |
@ -0,0 +1,4 @@ |
|||
schtasks /End /TN winws1 |
|||
schtasks /Delete /TN winws1 /F |
|||
rem schtasks /End /TN winws2 |
|||
rem schtasks /Delete /TN winws2 /F |
@ -0,0 +1,2 @@ |
|||
schtasks /Run /TN winws1 |
|||
rem schtasks /Run /TN winws2 |
@ -0,0 +1,2 @@ |
|||
schtasks /End /TN winws1 |
|||
rem schtasks /End /TN winws2 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
@ -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) |
|||
} |
@ -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 |
|||
} |
|||
} |
|||
} |
@ -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" ] |
|||
} |
@ -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 |
|||
} |
|||
} |
@ -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 |
|||
} |
@ -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 |
|||
} |
@ -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 |
|||
} |
@ -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 |
|||
} |
@ -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" |
|||
} |
|||
} |
|||
} |
@ -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\"" |
|||
} |
@ -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 |
|||
} |
@ -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" |
|||
} |
@ -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 |
|||
} |
@ -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 |
|||
} |
@ -0,0 +1,126 @@ |
|||
# this file is included from init scripts |
|||
# change values here |
|||
|
|||
# can help in case /tmp has not enough space |
|||
#TMPDIR=/opt/zapret/tmp |
|||
|
|||
# redefine user for zapret daemons. required on Keenetic |
|||
#WS_USER=nobody |
|||
|
|||
# override firewall type : iptables,nftables,ipfw |
|||
#FWTYPE=iptables |
|||
|
|||
# options for ipsets |
|||
# maximum number of elements in sets. also used for nft sets |
|||
SET_MAXELEM=522288 |
|||
# too low hashsize can cause memory allocation errors on low RAM systems , even if RAM is enough |
|||
# too large hashsize will waste lots of RAM |
|||
IPSET_OPT="hashsize 262144 maxelem $SET_MAXELEM" |
|||
# dynamically generate additional ip. $1 = ipset/nfset/table name |
|||
#IPSET_HOOK="/etc/zapret.ipset.hook" |
|||
|
|||
# options for ip2net. "-4" or "-6" auto added by ipset create script |
|||
IP2NET_OPT4="--prefix-length=22-30 --v4-threshold=3/4" |
|||
IP2NET_OPT6="--prefix-length=56-64 --v6-threshold=5" |
|||
# options for auto hostlist |
|||
AUTOHOSTLIST_RETRANS_THRESHOLD=3 |
|||
AUTOHOSTLIST_FAIL_THRESHOLD=3 |
|||
AUTOHOSTLIST_FAIL_TIME=60 |
|||
# 1 = debug autohostlist positives to ipset/zapret-hosts-auto-debug.log |
|||
AUTOHOSTLIST_DEBUGLOG=0 |
|||
|
|||
# number of parallel threads for domain list resolves |
|||
MDIG_THREADS=30 |
|||
|
|||
# ipset/*.sh can compress large lists |
|||
GZIP_LISTS=1 |
|||
# command to reload ip/host lists after update |
|||
# comment or leave empty for auto backend selection : ipset or ipfw if present |
|||
# on BSD systems with PF no auto reloading happens. you must provide your own command |
|||
# set to "-" to disable reload |
|||
#LISTS_RELOAD="pfctl -f /etc/pf.conf" |
|||
|
|||
# override ports |
|||
#HTTP_PORTS=80-81,85 |
|||
#HTTPS_PORTS=443,500-501 |
|||
#QUIC_PORTS=443,444 |
|||
|
|||
# CHOOSE OPERATION MODE |
|||
# MODE : nfqws,tpws,tpws-socks,filter,custom |
|||
# nfqws : nfqws for dpi desync |
|||
# tpws : tpws transparent mode |
|||
# tpws-socks : tpws socks mode |
|||
# filter : no daemon, just create ipset or download hostlist |
|||
# custom : custom mode. should modify custom init script and add your own code |
|||
MODE=tpws |
|||
# apply fooling to http |
|||
MODE_HTTP=1 |
|||
# for nfqws only. support http keep alives. enable only if DPI checks for http request in any outgoing packet |
|||
MODE_HTTP_KEEPALIVE=0 |
|||
# apply fooling to https |
|||
MODE_HTTPS=1 |
|||
# apply fooling to quic |
|||
MODE_QUIC=0 |
|||
# none,ipset,hostlist,autohostlist |
|||
MODE_FILTER=none |
|||
|
|||
# CHOOSE NFQWS DAEMON OPTIONS for DPI desync mode. run "nfq/nfqws --help" for option list |
|||
# SUFFIX VARS define additional lower priority desync profile. it's required if MODE_FILTER=hostlist and strategy has hostlist-incompatible 0-phase desync methods (syndata,wssize) |
|||
DESYNC_MARK=0x40000000 |
|||
DESYNC_MARK_POSTNAT=0x20000000 |
|||
NFQWS_OPT_DESYNC="--dpi-desync=fake --dpi-desync-ttl=0 --dpi-desync-ttl6=0 --dpi-desync-fooling=badsum" |
|||
#NFQWS_OPT_DESYNC_SUFFIX="--dpi-desync=syndata" |
|||
#NFQWS_OPT_DESYNC_HTTP="" |
|||
#NFQWS_OPT_DESYNC_HTTP_SUFFIX="--dpi-desync=syndata" |
|||
#NFQWS_OPT_DESYNC_HTTPS="" |
|||
#NFQWS_OPT_DESYNC_HTTPS_SUFFIX="--wssize 1:6" |
|||
#NFQWS_OPT_DESYNC_HTTP6="" |
|||
#NFQWS_OPT_DESYNC_HTTP6_SUFFIX="--dpi-desync=syndata" |
|||
#NFQWS_OPT_DESYNC_HTTPS6="" |
|||
#NFQWS_OPT_DESYNC_HTTPS6_SUFFIX="--wssize 1:6" |
|||
NFQWS_OPT_DESYNC_QUIC="--dpi-desync=fake --dpi-desync-repeats=6" |
|||
#NFQWS_OPT_DESYNC_QUIC_SUFFIX="" |
|||
#NFQWS_OPT_DESYNC_QUIC6="--dpi-desync=hopbyhop" |
|||
#NFQWS_OPT_DESYNC_QUIC6_SUFFIX="" |
|||
|
|||
# CHOOSE TPWS DAEMON OPTIONS. run "tpws/tpws --help" for option list |
|||
# SUFFIX VARS define additional lower priority desync profile. it's required if MODE_FILTER=hostlist and strategy has hostlist-incompatible 0-phase desync methods (mss) |
|||
TPWS_OPT="--hostspell=HOST --split-http-req=method --split-pos=3 --oob" |
|||
#TPWS_OPT_SUFFIX="--mss 88" |
|||
|
|||
# openwrt only : donttouch,none,software,hardware |
|||
FLOWOFFLOAD=donttouch |
|||
|
|||
# openwrt: specify networks to be treated as LAN. default is "lan" |
|||
#OPENWRT_LAN="lan lan2 lan3" |
|||
# openwrt: specify networks to be treated as WAN. default wans are interfaces with default route |
|||
#OPENWRT_WAN4="wan vpn" |
|||
#OPENWRT_WAN6="wan6 vpn6" |
|||
|
|||
# for routers based on desktop linux and macos. has no effect in openwrt. |
|||
# CHOOSE LAN and optinally WAN/WAN6 NETWORK INTERFACES |
|||
# or leave them commented if its not router |
|||
# it's possible to specify multiple interfaces like this : IFACE_LAN="eth0 eth1 eth2" |
|||
# if IFACE_WAN6 is not defined it take the value of IFACE_WAN |
|||
#IFACE_LAN=eth0 |
|||
#IFACE_WAN=eth1 |
|||
#IFACE_WAN6="ipsec0 wireguard0 he_net" |
|||
|
|||
# should start/stop command of init scripts apply firewall rules ? |
|||
# not applicable to openwrt with firewall3+iptables |
|||
INIT_APPLY_FW=1 |
|||
# firewall apply hooks |
|||
#INIT_FW_PRE_UP_HOOK="/etc/firewall.zapret.hook.pre_up" |
|||
#INIT_FW_POST_UP_HOOK="/etc/firewall.zapret.hook.post_up" |
|||
#INIT_FW_PRE_DOWN_HOOK="/etc/firewall.zapret.hook.pre_down" |
|||
#INIT_FW_POST_DOWN_HOOK="/etc/firewall.zapret.hook.post_down" |
|||
|
|||
# do not work with ipv4 |
|||
#DISABLE_IPV4=1 |
|||
# do not work with ipv6 |
|||
DISABLE_IPV6=1 |
|||
|
|||
# select which init script will be used to get ip or host list |
|||
# possible values : get_user.sh get_antizapret.sh get_combined.sh get_reestr.sh get_hostlist.sh |
|||
# comment if not required |
|||
GETLIST=get_antifilter_ipsmart.sh |
@ -0,0 +1,21 @@ |
|||
MIT License |
|||
|
|||
Copyright (c) 2016-2021 bol-van |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|||
SOFTWARE. |
@ -0,0 +1,611 @@ |
|||
## Table of contents |
|||
|
|||
- [Table of contents](#table-of-contents) |
|||
- [Supported versions](#supported-versions) |
|||
- [BSD features](#bsd-features) |
|||
- [FreeBSD](#freebsd) |
|||
- [`dvtws` quick start](#dvtws-quick-start) |
|||
- [PF in FreeBSD](#pf-in-freebsd) |
|||
- [`pfsense`](#pfsense) |
|||
- [OpenBSD](#openbsd) |
|||
- [MacOS](#macos) |
|||
- [MacOS easy install](#macos-easy-install) |
|||
|
|||
## Supported versions |
|||
|
|||
FreeBSD 11.x+ , OpenBSD 6.x+, partially MacOS Sierra+ |
|||
|
|||
Older versions may work or not. |
|||
|
|||
## BSD features |
|||
|
|||
BSD does not have NFQUEUE. Similar mechanism - divert sockets. In BSD compiling |
|||
the source from nfq directory result in `dvtws` binary instead of `nfqws`. |
|||
`dvtws` shares most of the code with `nfqws` and offers almost identical |
|||
parameters. |
|||
|
|||
FreeBSD has 3 firewalls: IPFilter, ipfw and Packet Filter (PF). OpenBSD has |
|||
only PF. |
|||
|
|||
To compile sources: |
|||
|
|||
- FreeBSD: `make` |
|||
- OpenBSD: `make bsd` |
|||
- MacOS: `make mac` |
|||
|
|||
Compile all programs: |
|||
``` |
|||
make -C /opt/zapret |
|||
``` |
|||
|
|||
Divert sockets are internal type sockets in the BSD kernel. They have no |
|||
relation to network addresses or network packet exchange. They are identified |
|||
by a port number `1..65535`. Its like queue number in NFQUEUE. Traffic can be |
|||
diverted to a divert socket using firewall rule. If nobody listens on the |
|||
specified divert port packets are dropped. Its similar to NFQUEUE without |
|||
`--queue-bypass`. |
|||
|
|||
`ipset/*.sh` scripts work with ipfw lookup tables if ipfw is present. |
|||
|
|||
ipfw table is analog to linux `ipset`. Unlike ipsets ipfw tables share v4 an v6 |
|||
addresses and subnets. |
|||
|
|||
- If ipfw is absent scripts check LISTS_RELOAD config variable. |
|||
- If its present then scripts execute a command from LISTS_RELOAD. |
|||
- If LISTS_RELOAD=- scripts do not load tables even if ipfw exists. |
|||
|
|||
PF can load ip tables from a file. To use this feature with `ipset/*.sh` scripts disable gzip file creation |
|||
using `GZIP_LISTS=0` directive in the `/opt/zapret/config` file. |
|||
|
|||
BSD kernel doesn't implement splice syscall. tpws uses regular recv/send |
|||
operations with data copying to user space. Its slower but not critical. |
|||
|
|||
`tpws` uses nonblocking sockets with linux specific epoll feature. In BSD systems |
|||
epoll is emulated by epoll-shim library on top of kqueue. |
|||
|
|||
`dvtws` uses some programming HACKs, assumptions and knowledge of discovered |
|||
bugs and limitations. BSD systems have many limitations, version specific |
|||
features and bugs in low level networking, especially for ipv6. Many years have |
|||
passed but BSD code still has 15-20 year artificial limiters in the code. `dvtws` |
|||
uses additinal divert socket(s) for layer 3 packet injection if raw sockets do |
|||
not allow it. It works for the moment but who knows. Such a usage is not very |
|||
documented. |
|||
|
|||
`mdig` and `ip2net` are fully compatible with BSD. |
|||
|
|||
|
|||
## FreeBSD |
|||
|
|||
Divert sockets require special kernel module `ipdivert`. |
|||
Write the following to config files: |
|||
|
|||
`/boot/loader.conf` (create if absent): |
|||
``` |
|||
ipdivert_load="YES" |
|||
net.inet.ip.fw.default_to_accept=1 |
|||
``` |
|||
|
|||
`/etc/rc.conf`: |
|||
``` |
|||
firewall_enable="YES" |
|||
firewall_script="/etc/rc.firewall.my" |
|||
``` |
|||
|
|||
`/etc/rc.firewall.my`: |
|||
``` |
|||
ipfw -q -f flush |
|||
``` |
|||
|
|||
Later you will add ipfw commands to `/etc/rc.firewall.my` to be reapplied after reboot. |
|||
You can also run zapret daemons from there. Start them with `--daemon` options, for example |
|||
``` |
|||
pkill ^dvtws$ |
|||
/opt/zapret/nfq/dvtws --port=989 --daemon --dpi-desync=split2 |
|||
``` |
|||
|
|||
To restart firewall and daemons run : `/etc/rc.d/ipfw restart` |
|||
|
|||
Assume `LAN="em1"`, `WAN="em0"`. |
|||
|
|||
`tpws` transparent mode quick start. |
|||
|
|||
For all traffic: |
|||
``` |
|||
ipfw delete 100 |
|||
ipfw add 100 fwd 127.0.0.1,988 tcp from me to any 80,443 proto ip4 xmit em0 not uid daemon |
|||
ipfw add 100 fwd ::1,988 tcp from me to any 80,443 proto ip6 xmit em0 not uid daemon |
|||
ipfw add 100 fwd 127.0.0.1,988 tcp from any to any 80,443 proto ip4 recv em1 |
|||
ipfw add 100 fwd ::1,988 tcp from any to any 80,443 proto ip6 recv em1 |
|||
/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 |
|||
``` |
|||
|
|||
Process only table zapret with the exception of table nozapret: |
|||
``` |
|||
ipfw delete 100 |
|||
ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 |
|||
ipfw add 100 fwd 127.0.0.1,988 tcp from me to table\(zapret\) 80,443 proto ip4 xmit em0 not uid daemon |
|||
ipfw add 100 fwd ::1,988 tcp from me to table\(zapret\) 80,443 proto ip6 xmit em0 not uid daemon |
|||
ipfw add 100 allow tcp from any to table\(nozapret\) 80,443 recv em1 |
|||
ipfw add 100 fwd 127.0.0.1,988 tcp from any to any 80,443 proto ip4 recv em1 |
|||
ipfw add 100 fwd ::1,988 tcp from any to any 80,443 proto ip6 recv em1 |
|||
/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 |
|||
``` |
|||
|
|||
Tables zapret, nozapret, ipban are created by `ipset/*.sh` scripts the same way as in Linux. |
|||
Its a good idea to update tables periodically: |
|||
``` |
|||
crontab -e |
|||
``` |
|||
|
|||
Write the line: |
|||
``` |
|||
0 12 */2 * * /opt/zapret/ipset/get_config.sh |
|||
``` |
|||
|
|||
When using `ipfw`, `tpws` does not require special permissions for transparent |
|||
mode. However without root its not possible to bind to ports less than 1024 and |
|||
change UID/GID. Without changing UID tpws will run into recursive loop, and |
|||
that's why its necessary to write ipfw rules with the right UID. Redirecting to |
|||
ports greater than or equal to 1024 is dangerous. If tpws is not running any |
|||
unprivileged process can listen to that port and intercept traffic. |
|||
|
|||
### `dvtws` quick start |
|||
|
|||
For all traffic: |
|||
``` |
|||
ipfw delete 100 |
|||
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted not sockarg xmit em0 |
|||
# required for autottl mode only |
|||
ipfw add 100 divert 989 tcp from any 80,443 to any tcpflags syn,ack in not diverted not sockarg recv em0 |
|||
/opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2 |
|||
``` |
|||
|
|||
Process only table zapret with the exception of table nozapret: |
|||
``` |
|||
ipfw delete 100 |
|||
ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 |
|||
ipfw add 100 divert 989 tcp from any to table\(zapret\) 80,443 out not diverted not sockarg xmit em0 |
|||
# required for autottl mode only |
|||
ipfw add 100 divert 989 tcp from table\(zapret\) 80,443 to any tcpflags syn,ack in not diverted not sockarg recv em0 |
|||
/opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2 |
|||
``` |
|||
|
|||
Reinjection loop avoidance. FreeBSD artificially ignores sockarg for ipv6 in |
|||
the kernel. This limitation is coming from the ipv6 early age. Code is still in |
|||
"testing" state. 10-20 years. Everybody forgot about it. `dvtws` sends ipv6 |
|||
forged frames using another divert socket (HACK). they can be filtered out |
|||
using 'diverted'. ipv4 frames are filtered using 'sockarg'. |
|||
|
|||
### PF in FreeBSD |
|||
|
|||
The setup is similar to OpenBSD, but there are important nuances. |
|||
1. PF support is disabled by default in FreeBSD. Use parameter `--enable-pf`. |
|||
2. It's not possible to redirect to `::1`. Need to redirect to the link-local |
|||
address of the incoming interface. Look for fe80:... address in ifconfig and |
|||
use it for redirection target. |
|||
3. pf.conf syntax is a bit different from OpenBSD. |
|||
4. How to set maximum table size : sysctl net.pf.request_maxcount=2000000 |
|||
5. `divert-to` is broken. Loop avoidance scheme does not work. |
|||
This makes `dvtws` unusable with pf. |
|||
Someone posted kernel patch but 14-RELEASE is still broken. |
|||
|
|||
`/etc/pf.conf`: |
|||
``` |
|||
rdr pass on em1 inet6 proto tcp to port {80,443} -> fe80::31c:29ff:dee2:1c4d port 988 |
|||
rdr pass on em1 inet proto tcp to port {80,443} -> 127.0.0.1 port 988 |
|||
``` |
|||
|
|||
Then: |
|||
``` |
|||
/opt/zapret/tpws/tpws --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force |
|||
``` |
|||
|
|||
Its not clear how to do rdr-to outgoing traffic. I could not make route-to |
|||
scheme work. |
|||
|
|||
|
|||
### `pfsense` |
|||
|
|||
`pfsense` is based on FreeBSD. Binaries from `binaries/freebsd-x64` are |
|||
compiled in FreeBSD 11 and should work. Use `install_bin.sh`. pfsense uses pf |
|||
firewall which does not support divert. Fortunately ipfw and ipdivert modules |
|||
are present and can be kldload-ed. In older versions it's also necessary to |
|||
change firewall order using sysctl commands. In newer versions those sysctl |
|||
parameters are absent but the system behaves as required without them. |
|||
Sometimes pf may limit `dvtws` abilities. It scrubs ip fragments disabling `dvtws` |
|||
ipfrag2 desync mode. |
|||
|
|||
There's autostart script example in `init.d/pfsense`. It should be placed to |
|||
`/usr/local/etc/rc.d` and edited. Write your ipfw rules and daemon start |
|||
commands. Because git is absent the most convinient way to copy files is ssh. |
|||
curl is present by default. |
|||
|
|||
Copy zip with zapret files to `/opt` and unpack there as it's done in other |
|||
systems. In this case run `dvtws` as `/opt/zapret/nfq/dvtws`. Or just copy |
|||
`dvtws` to `/usr/local/sbin`. As you wish. `ipset` scripts are working, cron is |
|||
present. It's possible to renew lists. |
|||
|
|||
If you dont like poverty of default repos its possible to enable FreeBSD repo. |
|||
Change `no` to `yes` in `/usr/local/etc/pkg/repos/FreeBSD.conf` and `/usr/local/etc/pkg/repos/pfSense.conf`. |
|||
Then it becomes possible to install all the required software including git to download |
|||
zapret from github directly. |
|||
|
|||
|
|||
`/usr/local/etc/rc.d/zapret.sh` (chmod 755) |
|||
``` |
|||
#!/bin/sh |
|||
|
|||
kldload ipfw |
|||
kldload ipdivert |
|||
|
|||
# for older pfsense versions. newer do not have these sysctls |
|||
sysctl net.inet.ip.pfil.outbound=ipfw,pf |
|||
sysctl net.inet.ip.pfil.inbound=ipfw,pf |
|||
sysctl net.inet6.ip6.pfil.outbound=ipfw,pf |
|||
sysctl net.inet6.ip6.pfil.inbound=ipfw,pf |
|||
|
|||
ipfw delete 100 |
|||
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted not sockarg xmit em0 |
|||
pkill ^dvtws$ |
|||
dvtws --daemon --port 989 --dpi-desync=split2 |
|||
|
|||
# required for newer pfsense versions (2.6.0 tested) to return ipfw to functional state |
|||
pfctl -d ; pfctl -e |
|||
``` |
|||
|
|||
I could not make tpws work from ipfw. Looks like there's some conflict between |
|||
two firewalls. Only PF redirection works. PF does not allow to freely add and |
|||
delete rules. Only anchors can be reloaded. To make an anchor work it must be |
|||
referred from the main ruleset. But its managed by pfsense scripts. |
|||
|
|||
One possible solution would be to modify `/etc/inc/filter.inc` as follows: |
|||
``` |
|||
................. |
|||
/* MOD */ |
|||
$natrules .= "# ZAPRET redirection\n"; |
|||
$natrules .= "rdr-anchor \"zapret\"\n"; |
|||
|
|||
$natrules .= "# TFTP proxy\n"; |
|||
$natrules .= "rdr-anchor \"tftp-proxy/*\"\n"; |
|||
................. |
|||
``` |
|||
|
|||
Write the anchor code to `/etc/zapret.anchor`: |
|||
``` |
|||
rdr pass on em1 inet proto tcp to port {80,443} -> 127.0.0.1 port 988 |
|||
rdr pass on em1 inet6 proto tcp to port {80,443} -> fe80::20c:29ff:5ae3:4821 port 988 |
|||
``` |
|||
Replace `fe80::20c:29ff:5ae3:4821` with your link local address of the LAN |
|||
interface or remove the line if ipv6 is not needed. |
|||
|
|||
Autostart `/usr/local/etc/rc.d/zapret.sh`: |
|||
``` |
|||
pfctl -a zapret -f /etc/zapret.anchor |
|||
pkill ^tpws$ |
|||
tpws --daemon --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force --split-http-req=method --split-pos=2 |
|||
``` |
|||
|
|||
After reboot check that anchor is created and referred from the main ruleset: |
|||
``` |
|||
[root@pfSense /]# pfctl -s nat |
|||
no nat proto carp all |
|||
nat-anchor "natearly/*" all |
|||
nat-anchor "natrules/*" all |
|||
................... |
|||
no rdr proto carp all |
|||
rdr-anchor "zapret" all |
|||
rdr-anchor "tftp-proxy/*" all |
|||
rdr-anchor "miniupnpd" all |
|||
[root@pfSense /]# pfctl -s nat -a zapret |
|||
rdr pass on em1 inet proto tcp from any to any port = http -> 127.0.0.1 port 988 |
|||
rdr pass on em1 inet proto tcp from any to any port = https -> 127.0.0.1 port 988 |
|||
rdr pass on em1 inet6 proto tcp from any to any port = http -> fe80::20c:29ff:5ae3:4821 port 988 |
|||
rdr pass on em1 inet6 proto tcp from any to any port = https -> fe80::20c:29ff:5ae3:4821 port 988 |
|||
``` |
|||
|
|||
Also there's a way to add redirect in the pfsense UI and start `tpws` from cron using `@reboot` prefix. |
|||
This way avoids modification of pfsense code. |
|||
|
|||
## OpenBSD |
|||
|
|||
In OpenBSD default `tpws` bind is ipv6 only. To bind to ipv4 specify |
|||
`--bind-addr=0.0.0.0`. |
|||
|
|||
Use `--bind-addr=0.0.0.0 --bind-addr=::` to achieve the same default bind as in |
|||
others OSes. |
|||
|
|||
`tpws` for forwarded traffic only : |
|||
|
|||
`/etc/pf.conf`: |
|||
``` |
|||
pass in quick on em1 inet proto tcp to port {80,443} rdr-to 127.0.0.1 port 988 |
|||
pass in quick on em1 inet6 proto tcp to port {80,443} rdr-to ::1 port 988 |
|||
``` |
|||
|
|||
Then: |
|||
``` |
|||
pfctl -f /etc/pf.conf |
|||
tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 |
|||
``` |
|||
|
|||
Its not clear how to do rdr-to outgoing traffic. I could not make route-to |
|||
scheme work. rdr-to support is done using /dev/pf, that's why transparent mode |
|||
requires root. |
|||
|
|||
`dvtws` for all traffic: |
|||
|
|||
`/etc/pf.conf`: |
|||
``` |
|||
pass in quick on em0 proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 proto tcp from port {80,443} no state |
|||
pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 |
|||
``` |
|||
|
|||
Then: |
|||
``` |
|||
pfctl -f /etc/pf.conf |
|||
./dvtws --port=989 --dpi-desync=split2 |
|||
``` |
|||
|
|||
`dwtws` only for table zapret with the exception of table nozapret : |
|||
|
|||
`/etc/pf.conf`: |
|||
``` |
|||
set limit table-entries 2000000 |
|||
table <zapret> file "/opt/zapret/ipset/zapret-ip.txt" |
|||
table <zapret-user> file "/opt/zapret/ipset/zapret-ip-user.txt" |
|||
table <nozapret> file "/opt/zapret/ipset/zapret-ip-exclude.txt" |
|||
pass out quick on em0 inet proto tcp to <nozapret> port {80,443} |
|||
pass in quick on em0 inet proto tcp from <zapret> port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 inet proto tcp from <zapret> port {80,443} no state |
|||
pass out quick on em0 inet proto tcp to <zapret> port {80,443} divert-packet port 989 no state |
|||
pass in quick on em0 inet proto tcp from <zapret-user> port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 inet proto tcp from <zapret-user> port {80,443} no state |
|||
pass out quick on em0 inet proto tcp to <zapret-user> port {80,443} divert-packet port 989 no state |
|||
table <zapret6> file "/opt/zapret/ipset/zapret-ip6.txt" |
|||
table <zapret6-user> file "/opt/zapret/ipset/zapret-ip-user6.txt" |
|||
table <nozapret6> file "/opt/zapret/ipset/zapret-ip-exclude6.txt" |
|||
pass out quick on em0 inet6 proto tcp to <nozapret6> port {80,443} |
|||
pass in quick on em0 inet6 proto tcp from <zapret6> port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 inet6 proto tcp from <zapret6> port {80,443} no state |
|||
pass out quick on em0 inet6 proto tcp to <zapret6> port {80,443} divert-packet port 989 no state |
|||
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} no state |
|||
pass out quick on em0 inet6 proto tcp to <zapret6-user> port {80,443} divert-packet port 989 no state |
|||
``` |
|||
|
|||
Then: |
|||
``` |
|||
pfctl -f /etc/pf.conf |
|||
./dvtws --port=989 --dpi-desync=split2 |
|||
``` |
|||
|
|||
divert-packet automatically adds the reverse rule. By default also incoming |
|||
traffic will be passwed to `dvtws`. This is highly undesired because it is waste |
|||
of cpu resources and speed limiter. The trick with "no state" and "in" rules |
|||
allows to bypass auto reverse rule. |
|||
|
|||
`dvtws` in OpenBSD sends all fakes through a divert socket because raw sockets |
|||
have critical artificial limitations. Looks like pf automatically prevent |
|||
reinsertion of diverted frames. Loop problem does not exist. |
|||
|
|||
OpenBSD forcibly recomputes tcp checksum after divert. Thats why most likely |
|||
dpi-desync-fooling=badsum will not work. `dvtws` will warn if you specify this |
|||
parameter. |
|||
|
|||
`ipset` scripts do not reload PF by default. To enable reload specify command in |
|||
`/opt/zapret/config`: |
|||
``` |
|||
LISTS_RELOAD="pfctl -f /etc/pf.conf" |
|||
``` |
|||
|
|||
Newer `pfctl` versions can reload tables only: |
|||
``` |
|||
pfctl -Tl -f /etc/pf.conf |
|||
``` |
|||
|
|||
But OpenBSD 6.8 `pfctl` is old enough and does not support that. Newer FreeBSD do. |
|||
|
|||
Don't forget to disable gzip compression: |
|||
``` |
|||
GZIP_LISTS=0 |
|||
``` |
|||
|
|||
If some list files do not exist and have references in pf.conf it leads to |
|||
error. You need to exclude those tables from pf.conf and referencing them |
|||
rules. After configuration is done you can put `ipset` script: |
|||
``` |
|||
crontab -e |
|||
``` |
|||
|
|||
Then write the line: |
|||
``` |
|||
0 12 */2 * * /opt/zapret/ipset/get_config.sh |
|||
``` |
|||
|
|||
## MacOS |
|||
|
|||
Initially, the kernel of this OS was based on BSD. That's why it is still BSD |
|||
but a lot was modified by Apple. As usual a mass commercial project priorities |
|||
differ from their free counterparts. Apple guys do what they want. |
|||
|
|||
MacOS used to have ipfw but it was removed later and replaced by PF. It looks |
|||
like divert sockets are internally replaced with raw. Its possible to request a |
|||
divert socket but it behaves exactly as raw socket with all its BSD inherited + |
|||
apple specific bugs and feature. The fact is that divert-packet in |
|||
`/etc/pf.conf` does not work. pfctl binary does not contain the word `divert`. |
|||
|
|||
`dvtws` does compile but is useless. |
|||
|
|||
After some efforts `tpws` works. Apple has removed some important stuff from |
|||
their newer SDKs (DIOCNATLOOK) making them undocumented and unsupported. |
|||
|
|||
With important definitions copied from an older SDK it was possible to make |
|||
transparent mode working again. But this is not guaranteed to work in the |
|||
future versions. |
|||
|
|||
Another MacOS unique feature is root requirement while polling `/dev/pf`. |
|||
|
|||
By default tpws drops root. Its necessary to specify `--user=root` to stay with |
|||
root. |
|||
|
|||
In other aspects PF behaves very similar to FreeBSD and shares the same pf.conf |
|||
syntax. |
|||
|
|||
In MacOS redirection works both for passthrough and outgoing traffic. Outgoing |
|||
redirection requires route-to rule. Because tpws is forced to run as root to |
|||
avoid loop its necessary to exempt root from the redirection. That's why DPI |
|||
bypass will not work for local requests from root. |
|||
|
|||
If you do ipv6 routing you have to get rid of "secured" ipv6 address |
|||
assignment. |
|||
|
|||
"secured" addresses are designed to be permanent and not related to the MAC |
|||
address. |
|||
|
|||
And they really are. Except for link-locals. |
|||
|
|||
If you just reboot the system link-locals will not change. But next day they |
|||
will change. |
|||
|
|||
Not necessary to wait so long. Just change the system time to tomorrow and reboot. |
|||
Link-locals will change (at least they change in vmware guest). Looks like its a kernel bug. |
|||
Link locals should not change. Its useless and can be harmful. Cant use LL as a gateway. |
|||
|
|||
The easiest solution is to disable "secured" addresses. |
|||
|
|||
Outgoing connections prefer randomly generated temporary addressesas like in other systems. |
|||
|
|||
Put the string `net.inet6.send.opmode=0` to `/etc/sysctl.conf`. If not present |
|||
- create it. |
|||
|
|||
Then reboot the system. |
|||
|
|||
If you dont like this solution you can assign an additional static ipv6 address |
|||
from `fc00::/7` range with `/128` prefix to your LAN interface and use it as |
|||
the gateway address. |
|||
|
|||
`tpws` transparent mode only for outgoing connections. |
|||
|
|||
`/etc/pf.conf`: |
|||
``` |
|||
rdr pass on lo0 inet proto tcp from !127.0.0.0/8 to any port {80,443} -> 127.0.0.1 port 988 |
|||
rdr pass on lo0 inet6 proto tcp from !::1 to any port {80,443} -> fe80::1 port 988 |
|||
pass out route-to (lo0 127.0.0.1) inet proto tcp from any to any port {80,443} user { >root } |
|||
pass out route-to (lo0 fe80::1) inet6 proto tcp from any to any port {80,443} user { >root } |
|||
``` |
|||
|
|||
Then: |
|||
``` |
|||
pfctl -ef /etc/pf.conf |
|||
/opt/zapret/tpws/tpws --user=root --port=988 --bind-addr=127.0.0.1 --bind-iface6=lo0 --bind-linklocal=force |
|||
``` |
|||
|
|||
`tpws` transparent mode for both passthrough and outgoing connections. en1 - LAN. |
|||
|
|||
``` |
|||
ifconfig en1 | grep fe80 |
|||
inet6 fe80::bbbb:bbbb:bbbb:bbbb%en1 prefixlen 64 scopeid 0x8 |
|||
``` |
|||
|
|||
`/etc/pf.conf`: |
|||
``` |
|||
rdr pass on en1 inet proto tcp from any to any port {80,443} -> 127.0.0.1 port 988 |
|||
rdr pass on en1 inet6 proto tcp from any to any port {80,443} -> fe80::bbbb:bbbb:bbbb:bbbb port 988 |
|||
rdr pass on lo0 inet proto tcp from !127.0.0.0/8 to any port {80,443} -> 127.0.0.1 port 988 |
|||
rdr pass on lo0 inet6 proto tcp from !::1 to any port {80,443} -> fe80::1 port 988 |
|||
pass out route-to (lo0 127.0.0.1) inet proto tcp from any to any port {80,443} user { >root } |
|||
pass out route-to (lo0 fe80::1) inet6 proto tcp from any to any port {80,443} user { >root } |
|||
``` |
|||
|
|||
Then: |
|||
``` |
|||
pfctl -ef /etc/pf.conf |
|||
/opt/zapret/tpws/tpws --user=root --port=988 --bind-addr=127.0.0.1 --bind-iface6=lo0 --bind-linklocal=force --bind-iface6=en1 --bind-linklocal=force |
|||
``` |
|||
|
|||
Build from source : `make -C /opt/zapret mac` |
|||
|
|||
`ipset/*.sh` scripts work. |
|||
|
|||
|
|||
### MacOS easy install |
|||
|
|||
`install_easy.sh` supports MacOS |
|||
|
|||
Shipped precompiled binaries are built for 64-bit MacOS with |
|||
`-mmacosx-version-min=10.8` option. They should run on all supported MacOS |
|||
versions. If no - its easy to build your own. Running `make` automatically |
|||
installs developer tools. |
|||
|
|||
**WARNING**: |
|||
**Internet sharing is not supported!** |
|||
|
|||
Routing is supported but only manually configured through PF. If you enable |
|||
internet sharing tpws stops functioning. When you disable internet sharing you |
|||
may lose web site access. |
|||
|
|||
To fix: |
|||
``` |
|||
pfctl -f /etc/pf.conf |
|||
``` |
|||
|
|||
If you need internet sharing use `tpws` socks mode. |
|||
|
|||
`launchd` is used for autostart (`/Library/LaunchDaemons/zapret.plist`) |
|||
|
|||
Control script: `/opt/zapret/init.d/macos/zapret` |
|||
|
|||
The following commands fork with both tpws and firewall (if `INIT_APPLY_FW=1` in config) |
|||
``` |
|||
/opt/zapret/init.d/macos/zapret start |
|||
/opt/zapret/init.d/macos/zapret stop |
|||
/opt/zapret/init.d/macos/zapret restart |
|||
``` |
|||
|
|||
Work with `tpws` only: |
|||
``` |
|||
/opt/zapret/init.d/macos/zapret start-daemons |
|||
/opt/zapret/init.d/macos/zapret stop-daemons |
|||
/opt/zapret/init.d/macos/zapret restart-daemons |
|||
``` |
|||
|
|||
Work with PF only: |
|||
``` |
|||
/opt/zapret/init.d/macos/zapret start-fw |
|||
/opt/zapret/init.d/macos/zapret stop-fw |
|||
/opt/zapret/init.d/macos/zapret restart-fw |
|||
``` |
|||
|
|||
Reloading PF tables: |
|||
``` |
|||
/opt/zapret/init.d/macos/zapret reload-fw-tables |
|||
``` |
|||
|
|||
Installer configures `LISTS_RELOAD` in the config so `ipset *.sh` scripts |
|||
automatically reload PF tables. Installer creates cron job for `ipset |
|||
/get_config.sh`, as in OpenWRT. |
|||
|
|||
start-fw script automatically patches `/etc/pf.conf` inserting there `zapret` |
|||
anchors. Auto patching requires pf.conf with apple anchors preserved. If your |
|||
`pf.conf` is highly customized and patching fails you will see the warning. Do |
|||
not ignore it. |
|||
|
|||
In that case you need to manually insert "zapret" anchors to your `pf.conf` |
|||
(keeping the right rule type ordering): |
|||
``` |
|||
rdr-anchor "zapret" |
|||
anchor "zapret" |
|||
unistall_easy.sh unpatches pf.conf |
|||
``` |
|||
start-fw creates 3 anchor files in `/etc/pf.anchors` : |
|||
zapret,zapret-v4,zapret-v6. |
|||
|
|||
- Last 2 are referenced by anchor `zapret`. |
|||
- Tables `nozapret`,`nozapret6` belong to anchor `zapret`. |
|||
- Tables `zapret`,`zapret-user` belong to anchor `zapret-v4`. |
|||
- Tables `zapret6`,`apret6-user` belong to anchor `zapret-v6`. |
|||
|
|||
If an ip version is disabled then corresponding anchor is empty and is not |
|||
referenced from the anchor `zapret`. Tables are only created for existing list |
|||
files in the `ipset` directory. |
@ -0,0 +1,476 @@ |
|||
Поддерживаемые версии |
|||
--------------------- |
|||
|
|||
FreeBSD 11.x+ , OpenBSD 6.x+, частично MacOS Sierra+ |
|||
|
|||
На более старых может собираться, может не собираться, может работать или не работать. |
|||
На FreeBSD 10 собирается и работает dvtws. С tpws есть проблемы из-за слишком старой версии компилятора clang. |
|||
Вероятно, будет работать, если обновить компилятор. |
|||
Возможна прикрутка к последним версиям pfsense без веб интерфейса в ручном режиме через консоль. |
|||
|
|||
|
|||
Особенности BSD систем |
|||
---------------------- |
|||
|
|||
В BSD нет nfqueue. Похожий механизм - divert sockets. |
|||
Из каталога "nfq" под BSD собирается dvtws вместо nfqws. |
|||
Он разделяет с nfqws большую часть кода и почти совпадает по параметрам командной строки. |
|||
|
|||
FreeBSD содержит 3 фаервола : IPFilter, ipfw и Packet Filter (PF). OpenBSD содержит только PF. |
|||
|
|||
Под FreeBSD tpws и dvtws собираются через "make", под OpenBSD - "make bsd", под MacOS - "make mac". |
|||
FreeBSD make распознает BSDmakefile , OpenBSD и MacOS - нет. Поэтому там используется отдельный target в Makefile. |
|||
Сборка всех исходников : make -C /opt/zapret |
|||
|
|||
divert сокет - внутренний тип сокета ядра BSD. Он не привязывается ни к какому сетевому адресу, не участвует |
|||
в обмене данными через сеть и идентифицируется по номеру порта 1..65535. Аналогия с номером очереди NFQUEUE. |
|||
На divert сокеты заворачивается трафик посредством правил ipfw или PF. |
|||
Если в фаерволе есть правило divert, но на divert порту никто не слушает, то пакеты дропаются. |
|||
Это поведение аналогично правилам NFQUEUE без параметра --queue-bypass. |
|||
На FreeBSD divert сокеты могут быть только ipv4, хотя на них принимаются и ipv4, и ipv6 фреймы. |
|||
На OpenBSD divert сокеты создаются отдельно для ipv4 и ipv6 и работают только с одной версией ip каждый. |
|||
На MacOS похоже, что divert сокеты из ядра вырезаны. См подробнее раздел про MacOS. |
|||
Отсылка в divert сокет работает аналогично отсылке через raw socket на linux. Передается полностью IP фрейм, начиная |
|||
с ip загловка . Эти особенности учитываются в dvtws. |
|||
|
|||
Скрипты ipset/*.sh при наличии ipfw работают с ipfw lookup tables. |
|||
Это прямой аналог ipset. lookup tables не разделены на v4 и v6. Они могут содержать v4 и v6 адреса и подсети одновременно. |
|||
Если ipfw отсутствует, то действие зависит от переменной LISTS_RELOAD в config. |
|||
Если она задана, то выполняется команда из LISTS_RELOAD. В противном случае не делается ничего. |
|||
Если LISTS_RELOAD=-, то заполнение таблиц отключается даже при наличии ipfw. |
|||
|
|||
PF может загружать ip таблицы из файла. Чтобы использовать эту возможность следует отключить сжатие gzip для листов |
|||
через параметр файла config "GZIP_LISTS=0". |
|||
|
|||
BSD не содержит системного вызова splice. tpws работает через переброску данных в user mode в оба конца. |
|||
Это медленнее, но не критически. |
|||
Управление асинхронными сокетами в tpws основано на linux-specific механизме epoll. |
|||
В BSD для его эмуляции используется epoll-shim - прослойка для эмуляции epoll на базе kqueue. |
|||
|
|||
mdig и ip2net полностью работоспособны в BSD. В них нет ничего системо-зависимого. |
|||
|
|||
FreeBSD |
|||
------- |
|||
|
|||
divert сокеты требуют специального модуля ядра ipdivert. |
|||
Поместите следующие строки в /boot/loader.conf (создать, если отсутствует) : |
|||
----------- |
|||
ipdivert_load="YES" |
|||
net.inet.ip.fw.default_to_accept=1 |
|||
----------- |
|||
В /etc/rc.conf : |
|||
----------- |
|||
firewall_enable="YES" |
|||
firewall_script="/etc/rc.firewall.my" |
|||
----------- |
|||
/etc/rc.firewall.my : |
|||
----------- |
|||
ipfw -q -f flush |
|||
----------- |
|||
В /etc/rc.firewall.my можно дописывать правила ipfw, чтобы они восстанавливались после перезагрузки. |
|||
Оттуда же можно запускать и демоны zapret, добавив в параметры "--daemon". Например так : |
|||
----------- |
|||
pkill ^dvtws$ |
|||
/opt/zapret/nfq/dvtws --port=989 --daemon --dpi-desync=split2 |
|||
----------- |
|||
Для перезапуска фаервола и демонов достаточно будет сделать : /etc/rc.d/ipfw restart |
|||
|
|||
|
|||
Краткая инструкция по запуску tpws в прозрачном режиме. |
|||
Предполагается, что интерфейс LAN называется em1, WAN - em0. |
|||
|
|||
Для всего трафика : |
|||
ipfw delete 100 |
|||
ipfw add 100 fwd 127.0.0.1,988 tcp from me to any 80,443 proto ip4 xmit em0 not uid daemon |
|||
ipfw add 100 fwd ::1,988 tcp from me to any 80,443 proto ip6 xmit em0 not uid daemon |
|||
ipfw add 100 fwd 127.0.0.1,988 tcp from any to any 80,443 proto ip4 recv em1 |
|||
ipfw add 100 fwd ::1,988 tcp from any to any 80,443 proto ip6 recv em1 |
|||
/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 |
|||
|
|||
Для трафика только на таблицу zapret, за исключением таблицы nozapret : |
|||
ipfw delete 100 |
|||
ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 |
|||
ipfw add 100 fwd 127.0.0.1,988 tcp from me to table\(zapret\) 80,443 proto ip4 xmit em0 not uid daemon |
|||
ipfw add 100 fwd ::1,988 tcp from me to table\(zapret\) 80,443 proto ip6 xmit em0 not uid daemon |
|||
ipfw add 100 allow tcp from any to table\(nozapret\) 80,443 recv em1 |
|||
ipfw add 100 fwd 127.0.0.1,988 tcp from any to any 80,443 proto ip4 recv em1 |
|||
ipfw add 100 fwd ::1,988 tcp from any to any 80,443 proto ip6 recv em1 |
|||
/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 |
|||
|
|||
Таблицы zapret, nozapret, ipban создаются скриптами из ipset по аналогии с Linux. |
|||
Обновление скриптов можно забить в cron под root : |
|||
crontab -e |
|||
Создать строчку "0 12 */2 * * /opt/zapret/ipset/get_config.sh" |
|||
|
|||
При использовании ipfw tpws не требует повышенных привилегий для реализации прозрачного режима. |
|||
Однако, без рута невозможен бинд на порты <1024 и смена UID/GID. Без смены UID будет рекурсия, |
|||
поэтому правила ipfw нужно создавать с учетом UID, под которым работает tpws. |
|||
Переадресация на порты >=1024 может создать угрозу перехвата трафика непривилегированным |
|||
процессом, если вдруг tpws не запущен. |
|||
|
|||
|
|||
Краткая инструкция по запуску dvtws. |
|||
|
|||
Для всего трафика : |
|||
ipfw delete 100 |
|||
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted xmit em0 |
|||
# required for autottl mode only |
|||
ipfw add 100 divert 989 tcp from any 80,443 to any tcpflags syn,ack in not diverted recv em0 |
|||
/opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2 |
|||
|
|||
Для трафика только на таблицу zapret, за исключением таблицы nozapret : |
|||
ipfw delete 100 |
|||
ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 |
|||
ipfw add 100 divert 989 tcp from any to table\(zapret\) 80,443 out not diverted not sockarg xmit em0 |
|||
# required for autottl mode only |
|||
ipfw add 100 divert 989 tcp from table\(zapret\) 80,443 to any tcpflags syn,ack in not diverted not sockarg recv em0 |
|||
/opt/zapret/nfq/dvtws --port=989 --dpi-desync=split2 |
|||
|
|||
|
|||
PF в FreeBSD: |
|||
Настройка аналогична OpenBSD, но есть важные нюансы. |
|||
1) В FreeBSD поддержка PF в tpws отключена по умолчанию. Чтобы ее включить, нужно использовать параметр --enable-pf. |
|||
2) Нельзя сделать ipv6 rdr на ::1. Нужно делать на link-local адрес входящего интерфейса. |
|||
Смотрите через ifconfig адрес fe80:... и добавляете в правило |
|||
3) Синтаксис pf.conf немного отличается. Более новая версия PF. |
|||
4) Лимит на количество элементов таблиц задается так : sysctl net.pf.request_maxcount=2000000 |
|||
5) divert-to сломан. Он работает, но не работает механизм предотвращения зацикливаний. |
|||
Кто-то уже написал патч, но в 14-RELEASE проблема все еще есть. |
|||
Следовательно, на данный момент работа dvtws через pf невозможна. |
|||
|
|||
/etc/pf.conf |
|||
----------- |
|||
rdr pass on em1 inet6 proto tcp to port {80,443} -> fe80::31c:29ff:dee2:1c4d port 988 |
|||
rdr pass on em1 inet proto tcp to port {80,443} -> 127.0.0.1 port 988 |
|||
----------- |
|||
/opt/zapret/tpws/tpws --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force |
|||
|
|||
В PF непонятно как делать rdr-to с той же системы, где работает proxy. Вариант с route-to у меня не заработал. |
|||
|
|||
|
|||
pfsense |
|||
------- |
|||
|
|||
pfsense основано на FreeBSD. |
|||
pfsense использует фаервол pf, а он имеет проблемы с divert. |
|||
К счастью, модули ipfw и ipdivert присутствуют в поставке последних версий pfsense. |
|||
Их можно подгрузить через kldload. |
|||
В некоторых более старых версиях pfsense требуется изменить порядок фаерволов через sysctl, сделав ipfw первым. |
|||
В более новых эти параметры sysctl отсутствуют, но система работает как надо и без них. |
|||
В некоторых случаях фаервол pf может ограничивать возможности dvtws, в частности в области фрагментации ip. |
|||
Присутствуют по умолчанию правила scrub для реассемблинга фрагментов. |
|||
Бинарики из binaries/freebsd-x64 собраны под FreeBSD 11. Они должны работать и на последующих версиях FreeBSD, |
|||
включая pfsense. Можно пользоваться install_bin.sh. |
|||
|
|||
Пример скрипта автозапуска лежит в init.d/pfsense. Его следует поместить в /usr/local/etc/rc.d и отредактировать |
|||
на предмет правил ipfw и запуска демонов. Есть встроенный редактор edit как более приемлемая альтернатива vi. |
|||
Поскольку git отсутствует, копировать файлы удобнее всего через ssh. curl присутствует по умолчанию. |
|||
Можно скопировать zip с файлами zapret и распаковать в /opt, как это делается на других системах. |
|||
Тогда dvtws нужно запускать как /opt/zapret/nfq/dvtws. Либо скопировать только dvtws в /usr/local/sbin. |
|||
Как вам больше нравится. |
|||
ipset скрипты работают, крон есть. Можно сделать автообновление листов. |
|||
|
|||
Если вас напрягает бедность имеющегося репозитория, можно включить репозиторий от FreeBSD, который по умолчанию выключен. |
|||
Поменяйте no на yes в /usr/local/etc/pkg/repos/FreeBSD.conf |
|||
Можно установить весь привычный soft, включая git, чтобы напрямую скачивать zapret с github. |
|||
|
|||
/usr/local/etc/rc.d/zapret.sh (chmod 755) |
|||
----------- |
|||
#!/bin/sh |
|||
|
|||
kldload ipfw |
|||
kldload ipdivert |
|||
|
|||
# for older pfsense versions. newer do not have these sysctls |
|||
sysctl net.inet.ip.pfil.outbound=ipfw,pf |
|||
sysctl net.inet.ip.pfil.inbound=ipfw,pf |
|||
sysctl net.inet6.ip6.pfil.outbound=ipfw,pf |
|||
sysctl net.inet6.ip6.pfil.inbound=ipfw,pf |
|||
|
|||
ipfw delete 100 |
|||
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted xmit em0 |
|||
pkill ^dvtws$ |
|||
dvtws --daemon --port 989 --dpi-desync=split2 |
|||
|
|||
# required for newer pfsense versions (2.6.0 tested) to return ipfw to functional state |
|||
pfctl -d ; pfctl -e |
|||
----------- |
|||
|
|||
Что касается tpws, то видимо имеется некоторый конфликт двух фаерволов, и правила fwd в ipfw не работают. |
|||
Работает перенаправление средствами pf как описано в разделе по FreeBSD. |
|||
В pf можно изменять правила только целыми блоками - якорями (anchors). Нельзя просто так добавить или удалить что-то. |
|||
Но чтобы какой-то anchor был обработан, на него должна быть ссылка из основного набора правил. |
|||
Его трогать нельзя, иначе порушится весь фаервол. |
|||
Поэтому придется править код скриптов pfsense. Поправьте /etc/inc/filter.inc следующим образом : |
|||
----------- |
|||
................. |
|||
/* MOD */ |
|||
$natrules .= "# ZAPRET redirection\n"; |
|||
$natrules .= "rdr-anchor \"zapret\"\n"; |
|||
|
|||
$natrules .= "# TFTP proxy\n"; |
|||
$natrules .= "rdr-anchor \"tftp-proxy/*\"\n"; |
|||
................. |
|||
----------- |
|||
|
|||
Напишите файл с содержимым anchor-а (например, /etc/zapret.anchor): |
|||
----------- |
|||
rdr pass on em1 inet proto tcp to port {80,443} -> 127.0.0.1 port 988 |
|||
rdr pass on em1 inet6 proto tcp to port {80,443} -> fe80::20c:29ff:5ae3:4821 port 988 |
|||
----------- |
|||
fe80::20c:29ff:5ae3:4821 замените на ваш link local адрес LAN интерфейса, либо уберите строчку, если ipv6 не нужен. |
|||
|
|||
Добавьте в автозапуск /usr/local/etc/rc.d/zapret.sh : |
|||
----------- |
|||
pfctl -a zapret -f /etc/zapret.anchor |
|||
pkill ^tpws$ |
|||
tpws --daemon --port=988 --enable-pf --bind-addr=127.0.0.1 --bind-iface6=em1 --bind-linklocal=force --split-http-req=method --split-pos=2 |
|||
----------- |
|||
|
|||
После перезагрузки проверьте, что правила создались : |
|||
----------- |
|||
[root@pfSense /]# pfctl -s nat |
|||
no nat proto carp all |
|||
nat-anchor "natearly/*" all |
|||
nat-anchor "natrules/*" all |
|||
................... |
|||
no rdr proto carp all |
|||
rdr-anchor "zapret" all |
|||
rdr-anchor "tftp-proxy/*" all |
|||
rdr-anchor "miniupnpd" all |
|||
[root@pfSense /]# pfctl -s nat -a zapret |
|||
rdr pass on em1 inet proto tcp from any to any port = http -> 127.0.0.1 port 988 |
|||
rdr pass on em1 inet proto tcp from any to any port = https -> 127.0.0.1 port 988 |
|||
rdr pass on em1 inet6 proto tcp from any to any port = http -> fe80::20c:29ff:5ae3:4821 port 988 |
|||
rdr pass on em1 inet6 proto tcp from any to any port = https -> fe80::20c:29ff:5ae3:4821 port 988 |
|||
----------- |
|||
|
|||
Так же есть более элегантный способ запуска tpws через @reboot в cron и правило перенаправления в UI. |
|||
Это позволит не редактировать код pfsense. |
|||
|
|||
|
|||
OpenBSD |
|||
------- |
|||
|
|||
В tpws бинд по умолчанию только на ipv6. для бинда на ipv4 указать "--bind-addr=0.0.0.0" |
|||
Используйте --bind-addr=0.0.0.0 --bind-addr=:: для достижения того же результата, как в других ОС по умолчанию. |
|||
(лучше все же так не делать, а сажать на определенные внутренние адреса или интерфейсы) |
|||
|
|||
tpws для проходящего трафика : |
|||
|
|||
/etc/pf.conf |
|||
------------ |
|||
pass in quick on em1 inet proto tcp to port {80,443} rdr-to 127.0.0.1 port 988 |
|||
pass in quick on em1 inet6 proto tcp to port {80,443} rdr-to ::1 port 988 |
|||
------------ |
|||
pfctl -f /etc/pf.conf |
|||
tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 |
|||
|
|||
В PF непонятно как делать rdr-to с той же системы, где работает proxy. Вариант с route-to у меня не заработал. |
|||
Поддержка rdr-to реализована через /dev/pf, поэтому прозрачный режим требует root. |
|||
|
|||
dvtws для всего трафика : |
|||
|
|||
/etc/pf.conf |
|||
------------ |
|||
pass in quick on em0 proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 proto tcp from port {80,443} no state |
|||
pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 no state |
|||
------------ |
|||
pfctl -f /etc/pf.conf |
|||
./dvtws --port=989 --dpi-desync=split2 |
|||
|
|||
dvtws для трафика только на таблицу zapret, за исключением таблицы nozapret : |
|||
|
|||
/etc/pf.conf |
|||
------------ |
|||
set limit table-entries 2000000 |
|||
table <zapret> file "/opt/zapret/ipset/zapret-ip.txt" |
|||
table <zapret-user> file "/opt/zapret/ipset/zapret-ip-user.txt" |
|||
table <nozapret> file "/opt/zapret/ipset/zapret-ip-exclude.txt" |
|||
pass out quick on em0 inet proto tcp to <nozapret> port {80,443} |
|||
pass in quick on em0 inet proto tcp from <zapret> port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 inet proto tcp from <zapret> port {80,443} no state |
|||
pass out quick on em0 inet proto tcp to <zapret> port {80,443} divert-packet port 989 no state |
|||
pass in quick on em0 inet proto tcp from <zapret-user> port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 inet proto tcp from <zapret-user> port {80,443} no state |
|||
pass out quick on em0 inet proto tcp to <zapret-user> port {80,443} divert-packet port 989 no state |
|||
table <zapret6> file "/opt/zapret/ipset/zapret-ip6.txt" |
|||
table <zapret6-user> file "/opt/zapret/ipset/zapret-ip-user6.txt" |
|||
table <nozapret6> file "/opt/zapret/ipset/zapret-ip-exclude6.txt" |
|||
pass out quick on em0 inet6 proto tcp to <nozapret6> port {80,443} |
|||
pass in quick on em0 inet6 proto tcp from <zapret6> port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 inet6 proto tcp from <zapret6> port {80,443} no state |
|||
pass out quick on em0 inet6 proto tcp to <zapret6> port {80,443} divert-packet port 989 no state |
|||
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} no state |
|||
pass out quick on em0 inet6 proto tcp to <zapret6-user> port {80,443} divert-packet port 989 no state |
|||
------------ |
|||
pfctl -f /etc/pf.conf |
|||
./dvtws --port=989 --dpi-desync=split2 |
|||
|
|||
divert-packet автоматически вносит обратное правило для перенаправления. |
|||
Трюк с no state и in правилом позволяет обойти эту проблему, чтобы напрасно не гнать массивный трафик через dvtws. |
|||
|
|||
В OpenBSD dvtws все фейки отсылает через divert socket, поскольку эта возможность через raw sockets заблокирована. |
|||
Видимо pf автоматически предотвращает повторный заворот diverted фреймов, поэтому проблемы зацикливания нет. |
|||
|
|||
OpenBSD принудительно пересчитывает tcp checksum после divert, поэтому скорее всего |
|||
dpi-desync-fooling=badsum у вас не заработает. При использовании этого параметра |
|||
dvtws предупредит о возможной проблеме. |
|||
|
|||
Скрипты из ipset не перезагружают таблицы в PF по умолчанию. |
|||
Чтобы они это делали, добавьте параметр в /opt/zapret/config : |
|||
LISTS_RELOAD="pfctl -f /etc/pf.conf" |
|||
Более новые версии pfctl понимают команду перезагрузить только таблицы : pfctl -Tl -f /etc/pf.conf |
|||
Но это не относится к OpenBSD 6.8. В новых FreeBSD есть. |
|||
Не забудьте выключить сжатие gzip : |
|||
GZIP_LISTS=0 |
|||
Если в вашей конфигурации какого-то файла листа нет, то его необходимо исключить из правил PF. |
|||
Если вдруг листа нет, и он задан в pf.conf, будет ошибка перезагрузки фаервола. |
|||
После настройки обновление листов можно поместить в cron : |
|||
crontab -e |
|||
дописать строчку : 0 12 */2 * * /opt/zapret/ipset/get_config.sh |
|||
|
|||
|
|||
MacOS |
|||
----- |
|||
|
|||
Иначально ядро этой ОС "darwin" основывалось на BSD, потому в ней много похожего на другие версии BSD. |
|||
Однако, как и в других массовых коммерческих проектах, приоритеты смещаются в сторону от оригинала. |
|||
Яблочники что хотят, то и творят. |
|||
Раньше был ipfw, потом его убрали, заменили на PF. |
|||
Есть сомнения, что divert сокеты в ядре остались. Попытка создать divert socket не выдает ошибок, |
|||
но полученный сокет ведет себя точно так же, как raw, со всеми его унаследованными косяками + еще яблочно специфическими. |
|||
В PF divert-packet не работает. Простой grep бинарика pfctl показывает, что там нет слова "divert", |
|||
а в других версиях BSD оно есть. dvtws собирается, но совершенно бесполезен. |
|||
|
|||
tpws удалось адаптировать, он работоспособен. Получение адреса назначения для прозрачного прокси в PF (DIOCNATLOOK) |
|||
убрали из заголовков в новых SDK, сделав фактически недокументированным. |
|||
В tpws перенесены некоторые определения из более старых версий яблочных SDK. С ними удалось завести прозрачный режим. |
|||
Однако, что будет в следующих версиях угадать сложно. Гарантий нет. |
|||
Еще одной особенностью PF в MacOS является проверка на рута в момент обращения к /dev/pf, чего нет в остальных BSD. |
|||
tpws по умолчанию сбрасывает рутовые привилегии. Необходимо явно указать параметр --user=root. |
|||
В остальном PF себя ведет похоже на FreeBSD. Синтаксис pf.conf тот же. |
|||
|
|||
На MacOS работает редирект как с проходящего трафика, так и с локальной системы через route-to. |
|||
Поскольку tpws вынужден работать под root, для исключения рекурсии приходится пускать исходящий от root трафик напрямую. |
|||
Отсюда имеем недостаток : обход DPI для рута работать не будет. |
|||
|
|||
Если вы пользуетесь MaсOS в качестве ipv6 роутера, то нужно будет решить вопрос с регулярно изменяемым link-local адресом. |
|||
С некоторых версий MacOS использует по умолчанию постоянные "secured" ipv6 адреса вместо генерируемых на базе MAC адреса. |
|||
Все замечательно, но есть одна проблема. Постоянными остаются только global scope адреса. |
|||
Link locals периодически меняются. Смена завязана на системное время. Перезагрузки адрес не меняют, |
|||
Но если перевести время на день вперед и перезагрузиться - link local станет другим. (по крайней мере в vmware это так) |
|||
Информации по вопросу крайне мало, но тянет на баг. Не должен меняться link local. Скрывать link local не имеет смысла, |
|||
а динамический link local нельзя использовать в качестве адреса шлюза. |
|||
Проще всего отказаться от "secured" адресов. |
|||
Поместите строчку "net.inet6.send.opmode=0" в /etc/sysctl.conf. Затем перезагрузите систему. |
|||
Все равно для исходящих соединений будут использоваться temporary адреса, как и в других системах. |
|||
Или вам идея не по вкусу, можно прописать дополнительный статический ipv6 из диапазона fc00::/7 - |
|||
выберите любой с длиной префикса 128. Это можно сделать в системных настройках, создав дополнительный адаптер на базе |
|||
того же сетевого интерфейса, отключить в нем ipv4 и вписать статический ipv6. Он добавится к автоматически настраеваемым. |
|||
|
|||
Настройка tpws на macos в прозрачном режиме только для исходящих запросов : |
|||
|
|||
/etc/pf.conf |
|||
------------ |
|||
rdr pass on lo0 inet proto tcp from !127.0.0.0/8 to any port {80,443} -> 127.0.0.1 port 988 |
|||
rdr pass on lo0 inet6 proto tcp from !::1 to any port {80,443} -> fe80::1 port 988 |
|||
pass out route-to (lo0 127.0.0.1) inet proto tcp from any to any port {80,443} user { >root } |
|||
pass out route-to (lo0 fe80::1) inet6 proto tcp from any to any port {80,443} user { >root } |
|||
------------ |
|||
pfctl -ef /etc/pf.conf |
|||
/opt/zapret/tpws/tpws --user=root --port=988 --bind-addr=127.0.0.1 --bind-iface6=lo0 --bind-linklocal=force |
|||
|
|||
|
|||
Настройка tpws на macos роутере в прозрачном режиме, где en1 - LAN. |
|||
|
|||
ifconfig en1 | grep fe80 |
|||
inet6 fe80::bbbb:bbbb:bbbb:bbbb%en1 prefixlen 64 scopeid 0x8 |
|||
/etc/pf.conf |
|||
------------ |
|||
rdr pass on en1 inet proto tcp from any to any port {80,443} -> 127.0.0.1 port 988 |
|||
rdr pass on en1 inet6 proto tcp from any to any port {80,443} -> fe80::bbbb:bbbb:bbbb:bbbb port 988 |
|||
rdr pass on lo0 inet proto tcp from !127.0.0.0/8 to any port {80,443} -> 127.0.0.1 port 988 |
|||
rdr pass on lo0 inet6 proto tcp from !::1 to any port {80,443} -> fe80::1 port 988 |
|||
pass out route-to (lo0 127.0.0.1) inet proto tcp from any to any port {80,443} user { >root } |
|||
pass out route-to (lo0 fe80::1) inet6 proto tcp from any to any port {80,443} user { >root } |
|||
------------ |
|||
pfctl -ef /etc/pf.conf |
|||
/opt/zapret/tpws/tpws --user=root --port=988 --bind-addr=127.0.0.1 --bind-iface6=lo0 --bind-linklocal=force --bind-iface6=en1 --bind-linklocal=force |
|||
|
|||
|
|||
Сборка : make -C /opt/zapret mac |
|||
|
|||
Скрипты получения листов ipset/*.sh работают. |
|||
Если будете пользоваться ipset/get_combined.sh, нужно установить gnu grep через brew. |
|||
Имеющийся очень старый и безумно медленный с оцией -f. |
|||
|
|||
|
|||
MacOS простая установка |
|||
----------------------- |
|||
|
|||
В MacOS поддерживается install_easy.sh |
|||
|
|||
В комплекте идут бинарики, собраные под 64-bit с опцией -mmacosx-version-min=10.8. |
|||
Они должны работать на всех поддерживаемых версиях macos. |
|||
Если вдруг не работают - можно собрать свои. Developer tools ставятся автоматом при запуске make. |
|||
|
|||
!! Internet sharing средствами системы НЕ ПОДДЕРЖИВАЕТСЯ !! |
|||
Поддерживается только роутер, настроенный своими силами через PF. |
|||
Если вы вдруг включили шаринг, а потом выключили, то доступ к сайтам может пропасть совсем. |
|||
Лечение : pfctl -f /etc/pf.conf |
|||
Если вам нужен шаринг интернета, лучше отказаться от прозрачного режима и использовать socks. |
|||
|
|||
Для автостарта используется launchd (/Library/LaunchDaemons/zapret.plist) |
|||
Управляющий скрипт : /opt/zapret/init.d/macos/zapret |
|||
Следующие команды работают с tpws и фаерволом одновременно (если INIT_APPLY_FW=1 в config) |
|||
/opt/zapret/init.d/macos/zapret start |
|||
/opt/zapret/init.d/macos/zapret stop |
|||
/opt/zapret/init.d/macos/zapret restart |
|||
Работа только с tpws : |
|||
/opt/zapret/init.d/macos/zapret start-daemons |
|||
/opt/zapret/init.d/macos/zapret stop-daemons |
|||
/opt/zapret/init.d/macos/zapret restart-daemons |
|||
Работа только с PF : |
|||
/opt/zapret/init.d/macos/zapret start-fw |
|||
/opt/zapret/init.d/macos/zapret stop-fw |
|||
/opt/zapret/init.d/macos/zapret restart-fw |
|||
Перезагрузка всех IP таблиц из файлов : |
|||
/opt/zapret/init.d/macos/zapret reload-fw-tables |
|||
|
|||
Инсталятор настраивает LISTS_RELOAD в config, так что скрипты ipset/*.sh автоматически перезагружают IP таблицы в PF. |
|||
Автоматически создается cron job на ipset/get_config.sh, по аналогии с openwrt. |
|||
|
|||
При start-fw скрипт автоматически модицифирует /etc/pf.conf, вставляя туда anchors "zapret". |
|||
Модификация расчитана на pf.conf, в котором сохранены дефолтные anchors от apple. |
|||
Если у вас измененный pf.conf и модификация не удалась, об этом будет предупреждение. Не игнорируйте его. |
|||
В этом случае вам нужно вставить в свой pf.conf (в соответствии с порядком типов правил) : |
|||
rdr-anchor "zapret" |
|||
anchor "zapret" |
|||
При деинсталяции через uninstall_easy.sh модификации pf.conf убираются. |
|||
|
|||
start-fw создает 3 файла anchors в /etc/pf.anchors : zapret,zapret-v4,zapret-v6. |
|||
Последние 2 подключаются из anchor "zapret". |
|||
Таблицы nozapret,nozapret6 принадлежат anchor "zapret". |
|||
Таблицы zapret,zapret-user - в anchor "zapret-v4". |
|||
Таблицы zapret6,zapret6-user - в anchor "zapret-v6". |
|||
Если какая-то версия протокола отключена - соответствующий anchor пустой и не упоминается в anchor "zapret". |
|||
Таблицы и правила создаются только на те листы, которые фактически есть в директории ipset. |
|||
|
|||
|
|||
MacOS вариант custom |
|||
-------------------- |
|||
|
|||
Так же как и в других системах, поддерживаемых в простом инсталяторе, можно создавать свои custom скрипты. |
|||
Расположение : /opt/zapret/init.d/macos/custom |
|||
|
|||
zapret_custom_daemons() получает в $1 "0" или "1". "0" - stop, "1" - start |
|||
custom firewall отличается от linux варианта. |
|||
Вместо заполнения iptables вам нужно сгенерировать правила для zapret-v4 и zapret-v6 anchors и выдать их в stdout. |
|||
Это делается в функциях zapret_custom_firewall_v4() и zapret_custom_firewall_v6(). |
|||
Определения таблиц заполняются основным скриптом - вам это делать не нужно. |
|||
Можно ссылаться на таблицы zapret и zapret-user в v4, zapret6 и zapret6-user. |
|||
|
|||
Cм. пример в файле custom-tpws |
@ -0,0 +1,97 @@ |
|||
WAN=em0 LAN=em1 |
|||
|
|||
FreeBSD IPFW : |
|||
|
|||
ipfw delete 100 |
|||
ipfw add 100 fwd 127.0.0.1,988 tcp from me to any 80,443 proto ip4 xmit em0 not uid daemon |
|||
ipfw add 100 fwd ::1,988 tcp from me to any 80,443 proto ip6 xmit em0 not uid daemon |
|||
ipfw add 100 fwd 127.0.0.1,988 tcp from any to any 80,443 proto ip4 recv em1 |
|||
ipfw add 100 fwd ::1,988 tcp from any to any 80,443 proto ip6 recv em1 |
|||
|
|||
ipfw delete 100 |
|||
ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 |
|||
ipfw add 100 fwd 127.0.0.1,988 tcp from me to table\(zapret\) 80,443 proto ip4 xmit em0 not uid daemon |
|||
ipfw add 100 fwd ::1,988 tcp from me to table\(zapret\) 80,443 proto ip6 xmit em0 not uid daemon |
|||
ipfw add 100 allow tcp from any to table\(nozapret\) 80,443 recv em1 |
|||
ipfw add 100 fwd 127.0.0.1,988 tcp from any to any 80,443 proto ip4 recv em1 |
|||
ipfw add 100 fwd ::1,988 tcp from any to any 80,443 proto ip6 recv em1 |
|||
|
|||
/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 |
|||
|
|||
|
|||
ipfw delete 100 |
|||
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted xmit em0 |
|||
; required for autottl mode |
|||
ipfw add 100 divert 989 tcp from any 80,443 to any tcpflags syn,ack in not diverted recv em0 |
|||
; udp |
|||
ipfw add 100 divert 989 udp from any to any 443 out not diverted xmit em0 |
|||
|
|||
ipfw delete 100 |
|||
ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 |
|||
ipfw add 100 divert 989 tcp from any to table\(zapret\) 80,443 out not diverted xmit em0 |
|||
|
|||
/opt/zapret/nfq/dvtws --port=989 --debug --dpi-desync=split |
|||
|
|||
|
|||
sample ipfw NAT setup : |
|||
|
|||
WAN=em0 |
|||
LAN=em1 |
|||
ipfw -q flush |
|||
ipfw -q nat 1 config if $WAN unreg_only reset |
|||
ipfw -q add 10 allow ip from any to any via $LAN |
|||
ipfw -q add 20 allow ip from any to any via lo0 |
|||
ipfw -q add 300 nat 1 ip4 from any to any in recv $WAN |
|||
ipfw -q add 301 check-state |
|||
ipfw -q add 350 skipto 390 tcp from any to any out xmit $WAN setup keep-state |
|||
ipfw -q add 350 skipto 390 udp from any to any out xmit $WAN keep-state |
|||
ipfw -q add 360 allow all from any to me in recv $WAN |
|||
ipfw -q add 390 nat 1 ip4 from any to any out xmit $WAN |
|||
ipfw -q add 10000 allow ip from any to any |
|||
|
|||
Forwarding : |
|||
sysctl net.inet.ip.forwarding=1 |
|||
sysctl net.inet6.ip6.forwarding=1 |
|||
|
|||
|
|||
OpenBSD PF : |
|||
|
|||
; dont know how to rdr-to from local system. doesn't seem to work. only works for routed traffic. |
|||
|
|||
/etc/pf.conf |
|||
pass in quick on em1 inet proto tcp to port {80,443} rdr-to 127.0.0.1 port 988 |
|||
pass in quick on em1 inet6 proto tcp to port {80,443} rdr-to ::1 port 988 |
|||
pfctl -f /etc/pf.conf |
|||
/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 |
|||
|
|||
; dvtws works both for routed and local |
|||
|
|||
pass in quick on em0 proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 proto tcp from port {80,443} no state |
|||
pass out quick on em0 proto tcp to port {80,443} divert-packet port 989 no state |
|||
pfctl -f /etc/pf.conf |
|||
./dvtws --port=989 --dpi-desync=split2 |
|||
|
|||
; dvtws with table limitations : to zapret,zapret6 but not to nozapret,nozapret6 |
|||
; reload tables : pfctl -f /etc/pf.conf |
|||
set limit table-entries 2000000 |
|||
table <zapret> file "/opt/zapret/ipset/zapret-ip.txt" |
|||
table <zapret-user> file "/opt/zapret/ipset/zapret-ip-user.txt" |
|||
table <nozapret> file "/opt/zapret/ipset/zapret-ip-exclude.txt" |
|||
pass out quick on em0 inet proto tcp to <nozapret> port {80,443} |
|||
pass in quick on em0 inet proto tcp from <zapret> port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 inet proto tcp from <zapret> port {80,443} no state |
|||
pass out quick on em0 inet proto tcp to <zapret> port {80,443} divert-packet port 989 no state |
|||
pass in quick on em0 inet proto tcp from <zapret-user> port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 inet proto tcp from <zapret-user> port {80,443} no state |
|||
pass out quick on em0 inet proto tcp to <zapret-user> port {80,443} divert-packet port 989 no state |
|||
table <zapret6> file "/opt/zapret/ipset/zapret-ip6.txt" |
|||
table <zapret6-user> file "/opt/zapret/ipset/zapret-ip-user6.txt" |
|||
table <nozapret6> file "/opt/zapret/ipset/zapret-ip-exclude6.txt" |
|||
pass out quick on em0 inet6 proto tcp to <nozapret6> port {80,443} |
|||
pass in quick on em0 inet6 proto tcp from <zapret6> port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 inet6 proto tcp from <zapret6> port {80,443} no state |
|||
pass out quick on em0 inet6 proto tcp to <zapret6> port {80,443} divert-packet port 989 no state |
|||
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} flags SA/SA divert-packet port 989 no state |
|||
pass in quick on em0 inet6 proto tcp from <zapret6-user> port {80,443} no state |
|||
pass out quick on em0 inet6 proto tcp to <zapret6-user> port {80,443} divert-packet port 989 no state |
@ -0,0 +1,325 @@ |
|||
v1 |
|||
|
|||
Initial release |
|||
|
|||
v2 |
|||
|
|||
nfqws : command line options change. now using standard getopt. |
|||
nfqws : added options for window size changing and "Host:" case change |
|||
ISP support : tested on mns.ru and beeline (corbina) |
|||
init scripts : rewritten init scripts for simple choise of ISP |
|||
create_ipset : now using 'ipset restore', it works much faster |
|||
readme : updated. now using UTF-8 charset. |
|||
|
|||
v3 |
|||
|
|||
tpws : added transparent proxy (supports TPROXY and DNAT). |
|||
can help when ISP tracks whole HTTP session, not only the beginning |
|||
ipset : added zapret-hosts-user.txt which contain user defined host names to be resolved |
|||
and added to zapret ip list |
|||
ISP support : dom.ru support via TPROXY/DNAT |
|||
ISP support : successfully tested sknt.ru on 'domru' configuration |
|||
other configs will probably also work, but cannot test |
|||
compile : openwrt compile howto |
|||
|
|||
v4 |
|||
|
|||
tpws : added ability to insert extra space after http method : "GET /" => "GET /" |
|||
ISP support : TKT support |
|||
|
|||
v5 |
|||
|
|||
nfqws : ipv6 support in nfqws |
|||
|
|||
v6 |
|||
|
|||
ipset : added "get_antizapret.sh" |
|||
|
|||
v7 |
|||
|
|||
tpws : added ability to insert "." after Host: name |
|||
|
|||
v8 |
|||
|
|||
openwrt init : removed hotplug.d/firewall because of race conditions. now only use /etc/firewall.user |
|||
|
|||
v9 |
|||
|
|||
ipban : added ipban ipset. place domains banned by ip to zapret-hosts-user-ipban.txt |
|||
these IPs must be soxified for both http and https |
|||
ISP support : tiera support |
|||
ISP support : added DNS filtering to ubuntu and debian scripts |
|||
|
|||
v10 |
|||
|
|||
tpws : added split-pos option. split every message at specified position |
|||
|
|||
v11 |
|||
|
|||
ipset : scripts optimizations |
|||
|
|||
v12 |
|||
|
|||
nfqws : fix wrong tcp checksum calculation if packet length is odd and platform is big-endian |
|||
|
|||
v13 |
|||
|
|||
added binaries |
|||
|
|||
v14 |
|||
|
|||
change get_antizapret script to work with https://github.com/zapret-info/z-i/raw/master/dump.csv |
|||
filter out 192.168.*, 127.*, 10.* from blocked ips |
|||
|
|||
v15 |
|||
|
|||
added --hostspell option to nfqws and tpws |
|||
ISP support : beeline now catches "host" but other spellings still work |
|||
openwrt/LEDE : changed init script to work with procd |
|||
tpws, nfqws : minor cosmetic fixes |
|||
|
|||
v16 |
|||
|
|||
tpws: split-http-req=method : split inside method name, not after |
|||
ISP support : mns.ru changed split pos to 3 (got redirect page with HEAD req : curl -I ej.ru) |
|||
|
|||
v17 |
|||
|
|||
ISP support : athome moved from nfqws to tpws because of instability and http request hangs |
|||
tpws : added options unixeol,methodeol,hosttab |
|||
|
|||
v18 |
|||
|
|||
tpws,nfqws : added hostnospace option |
|||
|
|||
v19 |
|||
|
|||
tpws : added hostlist option |
|||
|
|||
v20 |
|||
|
|||
added ip2net. ip2net groups ips from iplist into subnets and reduces ipset size twice |
|||
|
|||
v21 |
|||
|
|||
added mdig. get_reestr.sh is *real* again |
|||
|
|||
v22 |
|||
|
|||
total review of init script logic |
|||
dropped support of older debian 7 and ubuntu 12/14 systems |
|||
install_bin.sh : auto binaries preparation |
|||
docs: readme review. some new topics added, others deleted |
|||
docs: VPN setup with policy based routing using wireguard |
|||
docs: wireguard modding guide |
|||
|
|||
v23 |
|||
|
|||
major init system rewrite |
|||
openwrt : separate firewall include /etc/firewall.zapret |
|||
install_easy.sh : easy setup on openwrt, debian, ubuntu, centos, fedora, opensuse |
|||
|
|||
v24 |
|||
|
|||
separate config from init scripts |
|||
gzip support in ipset/*.sh and tpws |
|||
|
|||
v25 |
|||
|
|||
init : move to native systemd units |
|||
use links to units, init scripts and firewall includes, no more copying |
|||
|
|||
v26 |
|||
|
|||
ipv6 support |
|||
tpws : advanced bind options |
|||
|
|||
v27 |
|||
|
|||
tpws : major connection code rewrite. originally it was derived from not top quality example , with many bugs and potential problems. |
|||
next generation connection code uses nonblocking sockets. now its in EXPERIMENTAL state. |
|||
|
|||
v28 |
|||
|
|||
tpws : added socks5 support |
|||
ipset : major RKN getlist rewrite. added antifilter.network support |
|||
|
|||
v29 |
|||
|
|||
nfqws : DPI desync attack |
|||
ip exclude system |
|||
|
|||
v30 |
|||
|
|||
nfqws : DPI desync attack modes : fake,rst |
|||
|
|||
v31 |
|||
|
|||
nfqws : DPI desync attack modes : disorder,disorder2,split,split2. |
|||
nfqws : DPI desync fooling mode : badseq. multiple modes supported |
|||
|
|||
v32 |
|||
|
|||
tpws : multiple binds |
|||
init scripts : run only one instance of tpws in any case |
|||
|
|||
v33 |
|||
|
|||
openwrt : flow offloading support |
|||
config : MODE refactoring |
|||
|
|||
v34 |
|||
|
|||
nfqws : dpi-desync 2 mode combos |
|||
nfqws : dpi-desync without parameter no more supported. previously it meant "fake" |
|||
nfqws : custom fake http request and tls client hello |
|||
|
|||
v35 |
|||
|
|||
limited FreeBSD and OpenBSD support |
|||
|
|||
v36 |
|||
|
|||
full FreeBSD and OpenBSD support |
|||
|
|||
v37 |
|||
|
|||
limited MacOS support |
|||
|
|||
v38 |
|||
|
|||
MacOS easy install |
|||
|
|||
v39 |
|||
|
|||
nfqws: conntrack, wssize |
|||
|
|||
v40 |
|||
|
|||
init scripts : IFACE_LAN, IFACE_WAN now accept multiple interfaces |
|||
init scripts : openwrt uses now OPENWRT_LAN parameter to override incoming interfaces for tpws |
|||
|
|||
v41 |
|||
|
|||
install_easy : openrc support |
|||
|
|||
v42 |
|||
|
|||
blockcheck.sh |
|||
|
|||
v43 |
|||
|
|||
nfqws: UDP desync with conntrack support (any-protocol only for now) |
|||
|
|||
v44 |
|||
|
|||
nfqws: ipfrag |
|||
|
|||
v45 |
|||
|
|||
nfqws: hop-by-hop ipv6 desync and fooling |
|||
|
|||
v46 |
|||
|
|||
big startup script refactoring to support nftables and new openwrt snapshot builds with firewall4 |
|||
|
|||
v47 |
|||
|
|||
nfqws: QUIC initial decryption |
|||
nfqws: udplen, fakeknown dpi desync modes |
|||
|
|||
v48 |
|||
|
|||
nfqws, tpws : multiple --hostlist and --hostlist-exclude support |
|||
launch system, ipset : no more list merging. all lists are passed separately to nfqws and tpws |
|||
nfqws : udplen fooling supports packet shrinking (negative increment value) |
|||
|
|||
v49 |
|||
|
|||
QUIC support integrated to the main system and setup |
|||
|
|||
v50 |
|||
|
|||
DHT protocol support. |
|||
DPI desync mode 'tamper' for DHT. |
|||
HEX string support in addition to binary files. |
|||
|
|||
v51 |
|||
|
|||
tpws --tlsrec attack. |
|||
|
|||
v52 |
|||
|
|||
autohostlist mode |
|||
|
|||
v53 |
|||
|
|||
nfqws: tcp session reassemble for TLS ClientHello |
|||
|
|||
v54 |
|||
|
|||
tpws: out of band send when splitting (--oob) |
|||
nfqws: autottl |
|||
nfqws: datanoack fooling |
|||
nftables: use POSTNAT path for tcp redirections to allow NAT-breaking strategies. use additional mark bit DESYNC_MARK_POSTNAT. |
|||
|
|||
v55 |
|||
|
|||
tpws: incompatible oob parameter change. it doesn't take oob byte anymore. instead it takes optional protocol filter - http or tls. |
|||
the same is done with disorder. oob byte can be specified in parameter --oob-data. |
|||
blockcheck: quick mode, strategy order optimizations, QUIC protocol support |
|||
nfqws: syndata desync mode |
|||
|
|||
v56 |
|||
|
|||
tpws: mss fooling |
|||
tpws: multi thread resolver. eliminates blocks related to hostname resolve. |
|||
|
|||
v57 |
|||
|
|||
tpws: --nosplice option |
|||
nfqws: postnat fixes |
|||
nfqws: --dpi-desync-start option |
|||
nfqws: packet delay for kyber TLS and QUIC |
|||
nfqws: --dpi-desync-retrans obsolete |
|||
nfqws: --qnum is mandatory, no more default queue 0 |
|||
|
|||
v58 |
|||
|
|||
winws |
|||
|
|||
v59 |
|||
|
|||
tpws: --split-tls |
|||
tpws: --tlsrec=sniext |
|||
nfqws: --dpi-desync-split-http-req, --dpi-desync-split-tls. multi segment TLS support for split. |
|||
blockcheck: mdig dns cache |
|||
|
|||
v60 |
|||
|
|||
blockcheck: port block test, partial ip block test |
|||
nfqws: seqovl split/disorder modes |
|||
|
|||
v61 |
|||
|
|||
C code cleanups |
|||
dvtws: do not use raw sockets. use divert. |
|||
nfqws,tpws: detect TLS 1.2 ClientHello from very old libraries with SSL 3.0 version in record layer |
|||
nfqws,tpws: debug log to file and syslog |
|||
tpws: --connect-bind-addr option |
|||
tpws: log local endpoint (including source port number) for remote leg |
|||
|
|||
v62: |
|||
|
|||
tpws: connection close logic rewrite. tcp user timeout parameters for local and remote leg. |
|||
nfqws: multi-strategy |
|||
|
|||
v63: |
|||
|
|||
tpws: multi-strategy |
|||
|
|||
v64: |
|||
|
|||
blockcheck: warn if dpi bypass software is already running |
|||
blockcheck: TPWS_EXTRA, NFQWS_EXTRA |
|||
init.d: multiple custom scripts |
@ -0,0 +1,42 @@ |
|||
How to compile native programs for use in openwrt |
|||
------------------------------------------------- |
|||
|
|||
1) <fetch correct version of openwrt> |
|||
|
|||
cd ~ |
|||
|
|||
<chaos calmer> |
|||
git clone git://git.openwrt.org/15.05/openwrt.git |
|||
<barrier breaker> |
|||
git clone git://git.openwrt.org/14.07/openwrt.git |
|||
<trunk> |
|||
git clone git://git.openwrt.org/openwrt.git |
|||
|
|||
cd openwrt |
|||
|
|||
2) ./scripts/feeds update -a |
|||
./scripts/feeds install -a |
|||
|
|||
3) #add zapret packages to build root |
|||
#copy package descriptions |
|||
copy compile/openwrt/* to ~/openwrt |
|||
#copy source code of tpws |
|||
copy tpws to ~/openwrt/package/zapret/tpws |
|||
#copy source code of nfq |
|||
copy nfq to ~/openwrt/package/zapret/nfq |
|||
#copy source code of ip2net |
|||
copy ip2net to ~/openwrt/package/zapret/ip2net |
|||
|
|||
4) make menuconfig |
|||
#select your target architecture |
|||
#select packages Network/Zapret/* as "M" |
|||
|
|||
5) make toolchain/compile |
|||
|
|||
6) make package/tpws/compile |
|||
make package/nfqws/compile |
|||
make package/ip2net/compile |
|||
make package/mdig/compile |
|||
|
|||
7) find bin -name tpws*.ipk |
|||
#take your tpws*.ipk , nfqws*.ipk , ip2net*.ipk, mdig*.ipk from there |
@ -0,0 +1,32 @@ |
|||
#
|
|||
|
|||
include $(TOPDIR)/rules.mk |
|||
|
|||
PKG_NAME:=ip2net |
|||
PKG_RELEASE:=1 |
|||
|
|||
include $(INCLUDE_DIR)/package.mk |
|||
|
|||
define Package/ip2net |
|||
SECTION:=net |
|||
CATEGORY:=Network |
|||
TITLE:=ip2net |
|||
SUBMENU:=Zapret |
|||
endef |
|||
|
|||
define Build/Prepare |
|||
mkdir -p $(PKG_BUILD_DIR) |
|||
$(CP) ./ip2net/* $(PKG_BUILD_DIR)/ |
|||
endef |
|||
|
|||
define Build/Compile |
|||
$(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS) |
|||
endef |
|||
|
|||
define Package/ip2net/install |
|||
$(INSTALL_DIR) $(1)/opt/zapret/ip2net |
|||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/ip2net $(1)/opt/zapret/ip2net |
|||
endef |
|||
|
|||
$(eval $(call BuildPackage,ip2net)) |
|||
|
@ -0,0 +1 @@ |
|||
Copy "ip2net" folder here ! |
@ -0,0 +1,32 @@ |
|||
#
|
|||
|
|||
include $(TOPDIR)/rules.mk |
|||
|
|||
PKG_NAME:=mdig |
|||
PKG_RELEASE:=1 |
|||
|
|||
include $(INCLUDE_DIR)/package.mk |
|||
|
|||
define Package/mdig |
|||
SECTION:=net |
|||
CATEGORY:=Network |
|||
TITLE:=mdig |
|||
SUBMENU:=Zapret |
|||
endef |
|||
|
|||
define Build/Prepare |
|||
mkdir -p $(PKG_BUILD_DIR) |
|||
$(CP) ./mdig/* $(PKG_BUILD_DIR)/ |
|||
endef |
|||
|
|||
define Build/Compile |
|||
$(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS) |
|||
endef |
|||
|
|||
define Package/mdig/install |
|||
$(INSTALL_DIR) $(1)/opt/zapret/mdig |
|||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/mdig $(1)/opt/zapret/mdig |
|||
endef |
|||
|
|||
$(eval $(call BuildPackage,mdig)) |
|||
|
@ -0,0 +1 @@ |
|||
Copy "mdig" folder here ! |
@ -0,0 +1,34 @@ |
|||
#
|
|||
|
|||
include $(TOPDIR)/rules.mk |
|||
|
|||
PKG_NAME:=nfqws |
|||
PKG_RELEASE:=1 |
|||
|
|||
include $(INCLUDE_DIR)/package.mk |
|||
|
|||
define Package/nfqws |
|||
SECTION:=net |
|||
CATEGORY:=Network |
|||
TITLE:=nfqws |
|||
SUBMENU:=Zapret |
|||
DEPENDS:=+libnetfilter-queue +libcap +zlib |
|||
endef |
|||
|
|||
define Build/Prepare |
|||
mkdir -p $(PKG_BUILD_DIR) |
|||
$(CP) ./nfq/* $(PKG_BUILD_DIR)/ |
|||
endef |
|||
|
|||
define Build/Compile |
|||
$(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS) |
|||
endef |
|||
|
|||
define Package/nfqws/install |
|||
$(INSTALL_DIR) $(1)/opt/zapret/nfq |
|||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/nfqws $(1)/opt/zapret/nfq |
|||
endef |
|||
|
|||
$(eval $(call BuildPackage,nfqws)) |
|||
|
|||
|
@ -0,0 +1 @@ |
|||
Copy "nfq" folder here ! |
@ -0,0 +1,33 @@ |
|||
#
|
|||
|
|||
include $(TOPDIR)/rules.mk |
|||
|
|||
PKG_NAME:=tpws |
|||
PKG_RELEASE:=1 |
|||
|
|||
include $(INCLUDE_DIR)/package.mk |
|||
|
|||
define Package/tpws |
|||
SECTION:=net |
|||
CATEGORY:=Network |
|||
TITLE:=tpws |
|||
SUBMENU:=Zapret |
|||
DEPENDS:=+zlib +libcap |
|||
endef |
|||
|
|||
define Build/Prepare |
|||
mkdir -p $(PKG_BUILD_DIR) |
|||
$(CP) ./tpws/* $(PKG_BUILD_DIR)/ |
|||
endef |
|||
|
|||
define Build/Compile |
|||
$(MAKE) -C $(PKG_BUILD_DIR) $(TARGET_CONFIGURE_OPTS) |
|||
endef |
|||
|
|||
define Package/tpws/install |
|||
$(INSTALL_DIR) $(1)/opt/zapret/tpws |
|||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/tpws $(1)/opt/zapret/tpws |
|||
endef |
|||
|
|||
$(eval $(call BuildPackage,tpws)) |
|||
|
@ -0,0 +1 @@ |
|||
Copy "tpws" folder here ! |
@ -0,0 +1,63 @@ |
|||
For window size changing : |
|||
|
|||
iptables -t mangle -I PREROUTING -p tcp --sport 80 --tcp-flags SYN,ACK SYN,ACK -j NFQUEUE --queue-num 200 --queue-bypass |
|||
iptables -t mangle -I PREROUTING -p tcp --sport 80 --tcp-flags SYN,ACK SYN,ACK -m set --match-set zapret src -j NFQUEUE --queue-num 200 --queue-bypass |
|||
|
|||
For dpi desync attack : |
|||
|
|||
iptables -t mangle -I POSTROUTING -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass |
|||
iptables -t mangle -I POSTROUTING -p tcp --dport 443 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass |
|||
iptables -t mangle -I POSTROUTING -p udp --dport 443 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass |
|||
|
|||
# auto hostlist with avoiding wrong ACK numbers in RST,ACK packets sent by russian DPI |
|||
sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1 |
|||
iptables -t mangle -I POSTROUTING -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:12 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass |
|||
iptables -t mangle -I PREROUTING -p tcp -m multiport --sports 80,443 -m connbytes --connbytes-dir=reply --connbytes-mode=packets --connbytes 1:6 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass |
|||
|
|||
|
|||
For TPROXY : |
|||
|
|||
sysctl -w net.ipv4.ip_forward=1 |
|||
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE |
|||
|
|||
ip -f inet rule add fwmark 1 lookup 100 |
|||
ip -f inet route add local default dev lo table 100 |
|||
# prevent loop |
|||
iptables -t filter -I INPUT -p tcp --dport 988 -j REJECT |
|||
iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -j MARK --set-mark 1 |
|||
iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 988 |
|||
|
|||
iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -m set --match-set zapret dst -j MARK --set-mark 1 |
|||
iptables -t mangle -A PREROUTING -i eth1 -p tcp --dport 80 -m mark --mark 0x1/0x1 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 988 |
|||
|
|||
For DNAT : |
|||
|
|||
# run tpws as user "tpws". its required to avoid loops. |
|||
sysctl -w net.ipv4.conf.eth1.route_localnet=1 |
|||
iptables -t nat -I PREROUTING -p tcp --dport 80 -j DNAT --to 127.0.0.127:988 |
|||
iptables -t nat -I OUTPUT -p tcp --dport 80 -m owner ! --uid-owner tpws -j DNAT --to 127.0.0.127:988 |
|||
|
|||
|
|||
Reset all iptable rules : |
|||
|
|||
iptables -F |
|||
iptables -X |
|||
iptables -t nat -F |
|||
iptables -t nat -X |
|||
iptables -t mangle -F |
|||
iptables -t mangle -X |
|||
iptables -t raw -F |
|||
iptables -t raw -X |
|||
|
|||
Reset iptable policies : |
|||
|
|||
iptables -P INPUT ACCEPT |
|||
iptables -P FORWARD ACCEPT |
|||
iptables -P OUTPUT ACCEPT |
|||
iptables -t mangle -P POSTROUTING ACCEPT |
|||
iptables -t mangle -P PREROUTING ACCEPT |
|||
iptables -t mangle -P INPUT ACCEPT |
|||
iptables -t mangle -P FORWARD ACCEPT |
|||
iptables -t mangle -P OUTPUT ACCEPT |
|||
iptables -t raw -P PREROUTING ACCEPT |
|||
iptables -t raw -P OUTPUT ACCEPT |
@ -0,0 +1,282 @@ |
|||
Пример ручной установки на debian-подобную систему |
|||
-------------------------------------------------- |
|||
|
|||
На debian основано большое количество дистрибутивов linux, включая ubuntu. |
|||
Здесь рассматриваются прежде всего Debian 8+ и Ubuntu 16+. |
|||
Но с большой вероятностью может сработать и на производных от них. |
|||
Главное условие - наличие systemd, apt и нескольких стандартных пакетов в репозитории. |
|||
|
|||
Установить пакеты : |
|||
apt-get update |
|||
apt-get install ipset curl dnsutils git |
|||
|
|||
Если хотите использовать nftables, то нужен пакет nftables, а ipset не обязателен. |
|||
|
|||
Скопировать директорию zapret в /opt или скачать через git : |
|||
cd /opt |
|||
git clone --depth 1 https://github.com/bol-van/zapret |
|||
|
|||
Запустить автоинсталятор бинариков. Он сам определит рабочую архитектуру и настроит все бинарики. |
|||
/opt/zapret/install_bin.sh |
|||
АЛЬТЕРНАТИВА : make -C /opt/zapret. Получите динамические бинарики под вашу ось. |
|||
Для сборки требуются dev пакеты : zlib1g-dev libcap-dev libnetfilter-queue-dev |
|||
|
|||
Создать конфиг по умолчанию : |
|||
cp /opt/zapret/config.default /opt/zapret/config |
|||
|
|||
Настроить параметры согласно разделу "Выбор параметров". |
|||
|
|||
Создать user листы по умолчанию : |
|||
cp /opt/zapret/ipset/zapret-hosts-user-exclude.txt.default /opt/zapret/ipset/zapret-hosts-user-exclude.txt |
|||
echo nonexistent.domain >/opt/zapret/ipset/zapret-hosts-user.txt |
|||
touch /opt/zapret/ipset/zapret-hosts-user-ipban.txt |
|||
|
|||
Создать ссылку на service unit в systemd : |
|||
ln -fs /opt/zapret/init.d/systemd/zapret.service /lib/systemd/system |
|||
|
|||
Удалить старые листы, если они были созданы ранее : |
|||
/opt/zapret/ipset/clear_lists.sh |
|||
По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены. |
|||
Выполнить скрипт обновления листа : |
|||
/opt/zapret/ipset/get_config.sh |
|||
Настроить таймер systemd для обновления листа : |
|||
ln -fs /opt/zapret/init.d/systemd/zapret-list-update.service /lib/systemd/system |
|||
ln -fs /opt/zapret/init.d/systemd/zapret-list-update.timer /lib/systemd/system |
|||
|
|||
Принять изменения в systemd : |
|||
systemctl daemon-reload |
|||
|
|||
Включить автозапуск службы : |
|||
systemctl enable zapret |
|||
|
|||
Включить таймер обновления листа : |
|||
systemctl enable zapret-list-update.timer |
|||
|
|||
Запустить службу : |
|||
systemctl start zapret |
|||
|
|||
Шпаргалка по управлению службой и таймером : |
|||
|
|||
enable auto start : systemctl enable zapret |
|||
disable auto start : systemctl disable zapret |
|||
start : systemctl start zapret |
|||
stop : systemctl stop zapret |
|||
status, output messages : systemctl status zapret |
|||
timer info : systemctl list-timer |
|||
delete service : systemctl disable zapret ; rm /lib/systemd/system/zapret.service |
|||
delete timer : systemctl disable zapret-list-update.timer ; rm /lib/systemd/system/zapret-list-update.* |
|||
|
|||
Centos 7+, Fedora |
|||
----------------- |
|||
|
|||
Centos с 7 версии и более-менее новые федоры построены на systemd. |
|||
В качестве пакетного менеджера используется yum. |
|||
|
|||
Установить пакеты : |
|||
yum install -y curl ipset dnsutils git |
|||
|
|||
Далее все аналогично debian. |
|||
|
|||
OpenSUSE |
|||
-------- |
|||
|
|||
Новые OpenSUSE основаны на systemd и менеджере пакетов zypper. |
|||
|
|||
Установить пакеты : |
|||
zypper --non-interactive install curl ipset |
|||
|
|||
Далее все аналогично debian, кроме расположения systemd. |
|||
В opensuse он находится не в /lib/systemd, а в /usr/lib/systemd. |
|||
Правильные команды будут : |
|||
|
|||
ln -fs /opt/zapret/init.d/systemd/zapret.service /usr/lib/systemd/system |
|||
ln -fs /opt/zapret/init.d/systemd/zapret-list-update.service /usr/lib/systemd/system |
|||
ln -fs /opt/zapret/init.d/systemd/zapret-list-update.timer /usr/lib/systemd/system |
|||
|
|||
Arch linux |
|||
---------- |
|||
|
|||
Построен на базе systemd. |
|||
|
|||
Установить пакеты : |
|||
pacman -Syy |
|||
pacman --noconfirm -S ipset curl |
|||
|
|||
Далее все аналогично debian. |
|||
|
|||
Gentoo |
|||
------ |
|||
|
|||
Эта система использует OpenRC - улучшенную версию sysvinit. |
|||
Установка пакетов производится командой : emerge <package_name> |
|||
Пакеты собираются из исходников. |
|||
|
|||
Требуются все те же ipset, curl, git для скачивания с github. |
|||
git и curl по умолчанию могут присутствовать, ipset отсутствует. |
|||
|
|||
emerge ipset |
|||
|
|||
Настроить параметры согласно разделу "Выбор параметров". |
|||
|
|||
Запустить автоинсталятор бинариков. Он сам определит рабочую архитектуру и настроит все бинарики. |
|||
/opt/zapret/install_bin.sh |
|||
АЛЬТЕРНАТИВА : make -C /opt/zapret. Получите динамические бинарики под вашу ось. |
|||
|
|||
Удалить старые листы, если они были созданы ранее : |
|||
/opt/zapret/ipset/clear_lists.sh |
|||
По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены. |
|||
Выполнить скрипт обновления листа : |
|||
/opt/zapret/ipset/get_config.sh |
|||
Зашедулить обновление листа : |
|||
crontab -e |
|||
Создать строчку "0 12 */2 * * /opt/zapret/ipset/get_config.sh" |
|||
|
|||
Подключить init скрипт : |
|||
|
|||
ln -fs /opt/zapret/init.d/openrc/zapret /etc/init.d |
|||
rc-update add zapret |
|||
|
|||
Запустить службу : |
|||
|
|||
rc-service zapret start |
|||
|
|||
Шпаргалка по управлению службой : |
|||
|
|||
enable auto start : rc-update add zapret |
|||
disable auto start : rc-update del zapret |
|||
start : rc-service zapret start |
|||
stop : rc-service zapret stop |
|||
|
|||
|
|||
|
|||
Ручная установка на openwrt/LEDE 15.xx-21.xx |
|||
-------------------------------------------- |
|||
|
|||
!!! Данная инструкция написана для систем, основанных на iptables+firewall3 |
|||
!!! В новых версиях openwrt переходит на nftables+firewall4, инструкция неприменима. Пользуйтесь install_easy.sh |
|||
|
|||
Установить дополнительные пакеты : |
|||
opkg update |
|||
opkg install iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra ipset curl |
|||
(ipv6) opkg install ip6tables-mod-nat |
|||
(опционально) opkg install gzip |
|||
(опционально) opkg install coreutils-sort |
|||
|
|||
ЭКОНОМИЯ МЕСТА : |
|||
|
|||
gzip от busybox в разы медленней полноценного варианта. gzip используется скриптами получения листов. |
|||
sort от busybox медленней полноценного варианта и жрет намного больше памяти. sort используется скриптами получения листов. |
|||
iptables-mod-nfqueue можно выкинуть, если не будем пользоваться nfqws |
|||
curl можно выкинуть, если для получения ip листа будет использоваться только get_user.sh |
|||
|
|||
Самая главная трудность - скомпилировать программы на C. Это можно сделать на linux x64 при помощи SDK, который |
|||
можно скачать с официального сайта openwrt или LEDE. Но процесс кросс компиляции - это всегда сложности. |
|||
Недостаточно запустить make как на традиционной linux системе. |
|||
Поэтому в binaries имеются готовые статические бинарики для всех самых распространенных архитектур. |
|||
Статическая сборка означает, что бинарик не зависит от типа libc (glibc, uclibc или musl) и наличия установленных so. |
|||
Его можно использовать сразу. Лишь бы подходил тип CPU. У ARM и MIPS есть несколько версий. |
|||
Скорее всего найдется рабочий вариант. Если нет - вам придется собирать самостоятельно. |
|||
Для всех поддерживаемых архитектур бинарики запакованы upx. На текущий момент все, кроме mips64. |
|||
|
|||
Скопировать директорию "zapret" в /opt на роутер. |
|||
|
|||
Если места достаточно, самый простой способ : |
|||
opkg update |
|||
opkg install git-http |
|||
mkdir /opt |
|||
cd /opt |
|||
git clone --depth 1 https://github.com/bol-van/zapret |
|||
|
|||
Если места немного : |
|||
opkg update |
|||
opkg install openssh-sftp-server unzip |
|||
ifconfig br-lan |
|||
Скачать на комп с github zip архив кнопкой "Clone or download"->Download ZIP |
|||
Скопировать средствами sftp zip архив на роутер в /tmp. |
|||
mkdir /opt |
|||
cd /opt |
|||
unzip /tmp/zapret-master.zip |
|||
mv zapret-master zapret |
|||
rm /tmp/zapret-master.zip |
|||
|
|||
Если места совсем мало : |
|||
На linux системе скачать и распаковать zapret. Оставить необходимый минимум файлов. |
|||
Запаковать в архив zapret.tar.gz. |
|||
nc -l -p 1111 <zapret.tar.gz |
|||
На роутере |
|||
cd /tmp |
|||
nc <linux_system_ip> 1111 >zapret.tar.gz |
|||
|
|||
Не стоит работать с распакованной версией zapret на windows. Потеряются ссылки и chmod. |
|||
|
|||
Запустить автоинсталятор бинариков. Он сам определит рабочую архитектуру и настроит все бинарики. |
|||
/opt/zapret/install_bin.sh |
|||
|
|||
Создать ссылку на скрипт запуска : |
|||
ln -fs /opt/zapret/init.d/openwrt/zapret /etc/init.d |
|||
Создать ссылку на скрипт события поднятия интерфейса : |
|||
ln -fs /opt/zapret/init.d/openwrt/90-zapret /etc/hotplug.d/iface |
|||
|
|||
Создать конфиг по умолчанию : |
|||
cp /opt/zapret/config.default /opt/zapret/config |
|||
|
|||
Настроить параметры согласно разделу "Выбор параметров". |
|||
|
|||
Создать user листы по умолчанию : |
|||
cp /opt/zapret/ipset/zapret-hosts-user-exclude.txt.default /opt/zapret/ipset/zapret-hosts-user-exclude.txt |
|||
echo nonexistent.domain >/opt/zapret/ipset/zapret-hosts-user.txt |
|||
touch /opt/zapret/ipset/zapret-hosts-user-ipban.txt |
|||
|
|||
Удалить старые листы, если они были созданы ранее : |
|||
/opt/zapret/ipset/clear_lists.sh |
|||
По желанию прописать в /opt/zapret/ipset/zapret-hosts-user.txt свои домены. |
|||
Выполнить скрипт обновления листа : |
|||
/opt/zapret/ipset/get_config.sh |
|||
Зашедулить обновление листа : |
|||
crontab -e |
|||
Создать строчку "0 12 */2 * * /opt/zapret/ipset/get_config.sh" |
|||
|
|||
Включить автозапуск службы и запустить ее : |
|||
/etc/init.d/zapret enable |
|||
/etc/init.d/zapret start |
|||
ПРИМЕЧАНИЕ : на этапе старта системы интерфейсы еще не подняты. в некоторых случаях невозможно правильно |
|||
сформировать параметры запуска демонов, не зная имя физического интерфейса LAN. |
|||
Cкрипт из /etc/hotplug.d/iface перезапустит демоны по событию поднятия LAN. |
|||
|
|||
Создать ссылку на firewall include : |
|||
ln -fs /opt/zapret/init.d/openwrt/firewall.zapret /etc/firewall.zapret |
|||
Проверить была ли создана ранее запись о firewall include : |
|||
uci show firewall | grep firewall.zapret |
|||
Если firewall.zapret нет, значит добавить : |
|||
uci add firewall include |
|||
uci set firewall.@include[-1].path="/etc/firewall.zapret" |
|||
uci set firewall.@include[-1].reload="1" |
|||
uci commit firewall |
|||
Проверить не включен ли flow offload : |
|||
uci show firewall.@defaults[0] |
|||
Если flow_offloading=1 или flow_offloading_hw=1 , |
|||
uci set firewall.@defaults[0].flow_offloading=0 |
|||
uci set firewall.@defaults[0].flow_offloading_hw=0 |
|||
uci commit firewall |
|||
Перезапустить фаервол : |
|||
fw3 restart |
|||
|
|||
Посмотреть через iptables -nL, ip6tables -nL или через luci вкладку "firewall" появились ли нужные правила. |
|||
|
|||
ЭКОНОМИЯ МЕСТА : если его мало, то можно оставить в директории zapret лишь подкаталоги |
|||
ipset, common, файл config, init.d/openwrt. |
|||
Далее нужно создать подкаталоги с реально используемыми бинариками (ip2net, mdig, tpws, nfq) |
|||
и скопировать туда из binaries рабочие executables. |
|||
|
|||
ЕСЛИ ВСЕ ПЛОХО С МЕСТОМ : откажитесь от работы со списком РКН. используйте только get_user.sh |
|||
|
|||
ЕСЛИ СОВСЕМ ВСЕ УЖАСНО С МЕСТОМ : берете tpws и делаете все своими руками. поднятие iptables, автостарт бинарика. |
|||
С некоторых версий скрипты запуска zapret без ipset не работают (он требуется для ip exclude) |
|||
|
|||
СОВЕТ : Покупайте только роутеры с USB. В USB можно воткнуть флэшку и вынести на нее корневую файловую систему |
|||
или использовать ее в качестве оверлея. Не надо мучать себя, запихивая незапихиваемое в 8 мб встроенной флэшки. |
|||
Для комфортной работы с zapret нужен роутер с 16 Mb встроенной памяти или USB разъемом и 128+ Mb RAM. |
|||
На 64 Mb без swap будут проблемы с листами РКН. Если у вас только 64 Mb, и вы хотите листы РКН, подключите swap. |
|||
32 Mb для современных версий openwrt - конфигурация на грани живучести. Возможны хаотические падения процессов в oom. |
|||
Работа с листами РКН невозможна в принципе. |
|||
|
@ -0,0 +1,32 @@ |
|||
nftables test cheat sheet |
|||
simplified rules to test nfqws and tpws |
|||
|
|||
|
|||
For DNAT : |
|||
|
|||
# run tpws as user "tpws". its required to avoid loops. |
|||
|
|||
nft delete table inet ztest |
|||
nft create table inet ztest |
|||
nft add chain inet ztest pre "{type nat hook prerouting priority dstnat;}" |
|||
nft add rule inet ztest pre tcp dport "{80,443}" redirect to :988 |
|||
nft add chain inet ztest out "{type nat hook output priority -100;}" |
|||
nft add rule inet ztest out tcp dport "{80,443}" skuid != tpws redirect to :988 |
|||
|
|||
|
|||
For dpi desync attack : |
|||
|
|||
nft delete table inet ztest |
|||
nft create table inet ztest |
|||
nft add chain inet ztest post "{type filter hook postrouting priority mangle;}" |
|||
nft add rule inet ztest post tcp dport "{80,443}" ct original packets 1-12 queue num 200 bypass |
|||
nft add rule inet ztest post udp dport 443 ct original packets 1-4 queue num 200 bypass |
|||
|
|||
# auto hostlist with avoiding wrong ACK numbers in RST,ACK packets sent by russian DPI |
|||
sysctl net.netfilter.nf_conntrack_tcp_be_liberal=1 |
|||
nft add chain inet ztest pre "{type filter hook prerouting priority filter;}" |
|||
nft add rule inet ztest pre tcp sport "{80,443}" ct reply packets 1-4 queue num 200 bypass |
|||
|
|||
|
|||
show rules : nft list table inet ztest |
|||
delete table : nft delete table inet ztest |
@ -0,0 +1,120 @@ |
|||
nftables - это технология, пришедшая на замену iptables. |
|||
В ней собрали все, что относилось к различным iptables. А их немало. iptables, ip6tables, ebtables, arptables, ipset. |
|||
Весь код из разрозненных, но похожих компонент, собрали в одно целое с единым синтаксисом. |
|||
Добавили различные конструкции языка, позволяющие писать правила более лаконично, не повторяя одни и те же команды с небольшими различиями. |
|||
На nftables можно сделать почти все, что можно было сделать на iptables. Есть то, что можно сделать на nftables, но нельзя на iptables. |
|||
Есть и наоборот. |
|||
|
|||
К сожалению, не обошлось и без боли. |
|||
|
|||
Главная боль N1. Очень серьезная, актуальная для openwrt, и решения не видно. |
|||
|
|||
ipset-ы позволяли загонять пересекающиеся интервалы ip адресов или подсетей. |
|||
nftables sets это не позволяют. Любое пересечение вызывает ошибку. |
|||
Есть auto-merge, но это работает только в user mode в процессе nft, при условии, что весь блок адресов загоняется одной командой |
|||
и нет пересечений с уже имеющимся контентом в set. |
|||
Это не было бы критической проблемой, поскольку скрипты zapret и так загоняют ipset целиком. |
|||
Проблема в катастрофическом расходе памяти при операции загона больших интервальных листов, то есть с подсетями и диапазонами. |
|||
Чтобы загнать 100000 ipv4 записей, едва хватает 300 Mb памяти устройства. |
|||
При успехе операции в ядре список столько не занимает, но суть дела это не меняет. |
|||
Для традиционных linux систем это не проблема, но почти все роутеры загнутся. |
|||
Приемлемого решения не просматривается. |
|||
Сделать записи непересекающимися в листах - задача непростая. Потребуется переписать алгоритм auto-merge из nft, |
|||
но с пониженным расходом памяти. |
|||
Загонять записи по одному отдельными вызовами nft, игнорируя ошибки, займет вечность. |
|||
Загонять блоком отдельных команд, игнорируя ошибки, - nft такого не умеет. Похоже, при любой ошибке происходит откат всего скрипта. |
|||
К тому же при таком подходе будут неточности в итоговом результате. |
|||
Swap позволяет немного сгладить проблему, но лишь незначительно. |
|||
Скажем, если вдруг list загоняется без ошибок с 300 Mb памяти и с падением на 256 Mb, то swap спасает. |
|||
Если памяти становится 200 Mb, то swap уже не спасет. Все равно вызывается OOM killer, заодно убивая и другие процессы, кроме nft, |
|||
а это уже совсем плохо. Может быть убито что-то важное. |
|||
|
|||
Боль N2, не смертельная, но тоже не айс. |
|||
|
|||
Какие-то нерациональные алгоритмы разбора таблиц в nft. |
|||
Например, есть 1 большой set на 100000 элементов и 1 маленький на 2 элемента. |
|||
Чтобы просто пролистать мелкий set или добавить туда еще что-то nft будет мусолить несколько секунд. |
|||
Что он делает за это время ? Тащит из ядра огромный блоб, в котором все в куче, и разбирает его, чтобы выделить искомую мелочь ? |
|||
В какой-то мере удается это сгладить, обьединяя несколько команд в единый скрипт. |
|||
|
|||
Боль N3 |
|||
|
|||
Система nftables построена на виртуальной машине. Правила, которые вы пишите, переводятся в псевдокод VM. |
|||
Чтобы потом их показать , nft декомпилирует код и переводит в читаемый язык. |
|||
Это довольно сложно, и регулярно случаются баги, связанные с неверным отображением. |
|||
|
|||
Кроме этого, часто встречаются и баги парсера. |
|||
Например, все версии nft вплоть до 1.0.1 имеют баг, который не разрешает названия интерфейсов в кавычках в |
|||
определении flowtable. Без кавычек нельзя вставить интерфейсы , имя которых начинается с цифры. |
|||
OpenWRT решает эту проблему отдельным патчем в snapshot версии, но на традиционных системах и в openwrt 21.x- его нет. |
|||
Почему бы не наплевать на интерфейсы, начинающиеся с цифры ? Потому что для openwrt 6to4-6to4, 6in4-he-net - обычное явление. |
|||
На текущий момент этой проблемы в openwrt уже нет, если использовать актуальную версию. |
|||
|
|||
Но тем не менее, хоть nft и давно перешел отметку 1.0, всякая мелочь, особенно на не совсем стандартных правилах, |
|||
регулярно всплывает. Потому чем новее у вас будет версия nft, тем больше там выловлено проблем. |
|||
Здесь обновления важны, чтобы потом не мучаться из-за давно исправленного велосипеда. |
|||
|
|||
Боль N4 |
|||
|
|||
Невозможно , не копаясь в других таблицах и хуках, ничего не зная об их содержании, предотвратить DROP или REJECT. |
|||
Нельзя написать такое правило, которое что-то важное ACCEPTнет, игнорируя остальные хуки во всех таблицах. |
|||
Если у вас есть какой-то фаервол, и он что-то дропает, то как от этого отказаться, если надо временно что-то принять ? |
|||
Это особенность netfilter, он так работает, но в iptables есть лишь стандартные таблицы с их хуками, куда можно |
|||
вставить ACCEPT. Здесь хуков может быть сколько угодно в каких угодно таблицах. |
|||
Эта проблема частично ломает кайф от независимого управления таблицами. |
|||
|
|||
|
|||
Плюс N1, главный |
|||
|
|||
iptables хороши, когда ими пользуется кто-то один. Иначе это проходной двор. |
|||
Когда есть система управления фаерволом, то приходится как-то к ней прикручиваться, чтобы не нарушить ее работу |
|||
и управлять правилами синхронно. Нужно уметь внести и удалить отдельные правила когда это нужно, не трогая все остальное. |
|||
Некоторые системы управления фаерволом вообще не предполагают, чтобы кто-то еще лез в iptables, и это очень сильно портит жизнь. |
|||
У iptables есть предопределенный набор хуков netfilter с фиксированным приоритетом. |
|||
В nftables хуков можно создать неограниченное количество с выбранным приоритетом, управляя ими независимо в отдельных таблицах. |
|||
Система управления фаерволом может работать в одной таблице (fw4 в случае openwrt) и не трогать все остальное. |
|||
zapret может работать в другой таблице и не трогать систему управления фаерволом. Они друг другу не мешают. |
|||
Это снимает множество боли. |
|||
Но есть и исключение. nfset-ы - аналог ipset-ов - нельзя использовать из другой таблицы. Потому если вам нужен ipset, |
|||
создаваемый zapret скриптами, вам понадобится писать правила в той же таблице. Но нет никакой необходимости влезать в цепочки zapret. |
|||
Создаете свои цепочки и хуки и делаете в них что угодно. |
|||
|
|||
Плюс N2 |
|||
|
|||
Возможность выбора приоритета хука позволяет легко решить проблему хаотической и принудительной дефрагментацией L3 ipv6, |
|||
без танцев с загрузкой модулей ядра со специальными параметрами или перекомпиляцией nftables-nft. |
|||
Это же позволяет перехватить трафик после SNAT/MASQUERADE, что на iptables невозможно. |
|||
Атаки на проходящий трафик, ломающие NAT, крайне затруднены на iptables. |
|||
|
|||
Плюс N3 |
|||
|
|||
Наличие множеств (anonymous/named sets) позволяет не писать кучу однообразных правил там, где в iptables их пришлось бы написать. |
|||
|
|||
Плюс N4 |
|||
|
|||
Если у вас есть nftables, то там наверняка есть уже все или почти все. |
|||
Нет кучи разных модулей ядра и .so плагинов для iptables user-mode процесса. |
|||
Отдельные модули ядра есть, но их меньше, чем в iptables, и openwrt их делит на меньшее число пакетов, большинство из которых |
|||
и так ставятся по умолчанию. user-mode процесс nft и вовсе неделим. EXE-шник + lib. |
|||
|
|||
Плюс N5 |
|||
|
|||
Пишут, что nftables работают быстрее. Но это не точно и зависит от много чего. |
|||
В целом - чем меньше правил, тем выше скорость. Но в nftables правил можно писать меньше, значит скрость тоже может быть выше. |
|||
У разработчиков есть идея перевести backend nftables на BPF, а это наверняка будет существенно быстрее. |
|||
|
|||
|
|||
Выводы |
|||
|
|||
Без больших листов все почти прекрасно. Но большие ip листы убивают все. Не для домашних это роутеров. |
|||
А ipset-ы к nftables не прикрутить. |
|||
Зато есть возможность задействовать более продвинутые атаки, конфликтующие с NAT, которые на iptables могут быть невозможны. |
|||
Делать нечего. Openwrt отошел от iptables. С этим придется как-то жить. |
|||
Поэтому пришлось сделать для openwrt поддержку и iptables, и nftables (только с версии openwrt 21.xx, в более старых будут проблемы). |
|||
iptables можно задействовать на любой openwrt версии. |
|||
Если используется fw3, применяется старый механизм интеграции в fw3. |
|||
Если он не используется, то правилами iptables управляем как в традиционных linux системах - то есть с возможностью |
|||
запуска и остановки, а скрипт запуска вносит в том числе и правила iptables. |
|||
|
|||
На новых openwrt возможно снести nftables и firewall4 и установить firewall3 и iptables. |
|||
Если вам никак без больших ip листов на слабой системе, это может быть единственным спасением. |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue