mirror of
https://github.com/bol-van/zapret-win-bundle.git
synced 2025-12-16 20:07:04 +03:00
bundle
This commit is contained in:
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
readme.md eol=crlf
|
||||||
|
*.cmd eol=crlf
|
||||||
|
*.bat eol=crlf
|
||||||
2
.github/lockdown.yml
vendored
Normal file
2
.github/lockdown.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Lock issues and pull requests
|
||||||
|
lock: true
|
||||||
BIN
arm64/WinDivert64.sys
Normal file
BIN
arm64/WinDivert64.sys
Normal file
Binary file not shown.
44
arm64/install_arm64.cmd
Normal file
44
arm64/install_arm64.cmd
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
cd /d "%~dp0"
|
||||||
|
setlocal enabledelayedexpansion
|
||||||
|
|
||||||
|
if [%1] == [install] goto :install
|
||||||
|
|
||||||
|
if %PROCESSOR_ARCHITECTURE%==ARM64 (
|
||||||
|
FOR /F "tokens=3 skip=2 USEBACKQ" %%B IN (`reg QUERY "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v CurrentBuild`) do set BUILD=!BUILD!%%B
|
||||||
|
if defined BUILD (
|
||||||
|
goto :build
|
||||||
|
) else (
|
||||||
|
echo could not get OS build number
|
||||||
|
)
|
||||||
|
) else (
|
||||||
|
echo this works only on ARM64
|
||||||
|
)
|
||||||
|
goto :ex
|
||||||
|
|
||||||
|
:build
|
||||||
|
echo OS build number %BUILD%
|
||||||
|
if !BUILD! GEQ 22000 (
|
||||||
|
"%~dp0..\tools\elevator" "%~dpf0" install
|
||||||
|
goto :eof
|
||||||
|
) else (
|
||||||
|
echo only windows 11 or higher is supported
|
||||||
|
)
|
||||||
|
goto :ex
|
||||||
|
|
||||||
|
:install
|
||||||
|
echo stopping windivert driver
|
||||||
|
net stop windivert 2>nul
|
||||||
|
echo setting testsigning on
|
||||||
|
bcdedit /set {current} testsigning on
|
||||||
|
echo replacing WinDivert64.sys with unsigned ARM64 version
|
||||||
|
copy WinDivert64.sys ..\zapret-winws
|
||||||
|
copy WinDivert64.sys ..\blockcheck\zapret\nfq
|
||||||
|
echo copying ip2net and mdig
|
||||||
|
copy ip2net.exe ..\blockcheck\zapret\ip2net
|
||||||
|
copy mdig.exe ..\blockcheck\zapret\mdig
|
||||||
|
echo DONE. now reboot if testsigning was not enabled earlier.
|
||||||
|
|
||||||
|
:ex
|
||||||
|
pause
|
||||||
BIN
arm64/ip2net.exe
Normal file
BIN
arm64/ip2net.exe
Normal file
Binary file not shown.
BIN
arm64/mdig.exe
Normal file
BIN
arm64/mdig.exe
Normal file
Binary file not shown.
8
blockcheck/blockcheck-kyber.cmd
Normal file
8
blockcheck/blockcheck-kyber.cmd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
cd /d "%~dp0"
|
||||||
|
FOR /F "tokens=* USEBACKQ" %%F IN (`..\cygwin\bin\cygpath -C OEM -a -m zapret\blog_kyber.sh`) DO (
|
||||||
|
SET P='%%F'
|
||||||
|
)
|
||||||
|
|
||||||
|
"%~dp0..\tools\elevator" ..\cygwin\bin\bash -i "%P%"
|
||||||
8
blockcheck/blockcheck.cmd
Normal file
8
blockcheck/blockcheck.cmd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
cd /d "%~dp0"
|
||||||
|
FOR /F "tokens=* USEBACKQ" %%F IN (`..\cygwin\bin\cygpath -C OEM -a -m zapret\blog.sh`) DO (
|
||||||
|
SET P='%%F'
|
||||||
|
)
|
||||||
|
|
||||||
|
"%~dp0..\tools\elevator" ..\cygwin\bin\bash -i "%P%"
|
||||||
8
blockcheck/blockcheck2-kyber.cmd
Normal file
8
blockcheck/blockcheck2-kyber.cmd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
cd /d "%~dp0"
|
||||||
|
FOR /F "tokens=* USEBACKQ" %%F IN (`..\cygwin\bin\cygpath -C OEM -a -m zapret2\blog_kyber.sh`) DO (
|
||||||
|
SET P='%%F'
|
||||||
|
)
|
||||||
|
|
||||||
|
"%~dp0..\tools\elevator" ..\cygwin\bin\bash -i "%P%"
|
||||||
8
blockcheck/blockcheck2.cmd
Normal file
8
blockcheck/blockcheck2.cmd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
cd /d "%~dp0"
|
||||||
|
FOR /F "tokens=* USEBACKQ" %%F IN (`..\cygwin\bin\cygpath -C OEM -a -m zapret2\blog.sh`) DO (
|
||||||
|
SET P='%%F'
|
||||||
|
)
|
||||||
|
|
||||||
|
"%~dp0..\tools\elevator" ..\cygwin\bin\bash -i "%P%"
|
||||||
2343
blockcheck/zapret/blockcheck.sh
Normal file
2343
blockcheck/zapret/blockcheck.sh
Normal file
File diff suppressed because it is too large
Load Diff
8
blockcheck/zapret/blog.sh
Normal file
8
blockcheck/zapret/blog.sh
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
EXEDIR="$(dirname "$0")"
|
||||||
|
EXEDIR="$(cd "$EXEDIR"; pwd)"
|
||||||
|
|
||||||
|
"$EXEDIR/blockcheck.sh" 2>&1 | tee "$EXEDIR/../blockcheck.log"
|
||||||
|
# windows 7 notepad does not view unix EOL correctly
|
||||||
|
unix2dos "$EXEDIR/../blockcheck.log"
|
||||||
6
blockcheck/zapret/blog_kyber.sh
Normal file
6
blockcheck/zapret/blog_kyber.sh
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
EXEDIR="$(dirname "$0")"
|
||||||
|
EXEDIR="$(cd "$EXEDIR"; pwd)"
|
||||||
|
|
||||||
|
CURL=curl-kyber exec "$EXEDIR/blog.sh"
|
||||||
456
blockcheck/zapret/common/base.sh
Normal file
456
blockcheck/zapret/common/base.sh
Normal file
@@ -0,0 +1,456 @@
|
|||||||
|
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=:
|
||||||
|
[ "$1" != "${1#/}" ] && [ -x "$1" ] && {
|
||||||
|
echo "$1"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
extract_arg()
|
||||||
|
{
|
||||||
|
# $1 - arg number
|
||||||
|
# $2,$3,... - args
|
||||||
|
local n=$1
|
||||||
|
while [ -n "$1" ]; do
|
||||||
|
shift
|
||||||
|
[ $n -eq 1 ] && { echo "$1"; return 0; }
|
||||||
|
n=$(($n-1))
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
find_str_in_list()
|
||||||
|
{
|
||||||
|
# $1 - string
|
||||||
|
# $2 - space separated values
|
||||||
|
local v
|
||||||
|
[ -n "$1" ] && {
|
||||||
|
for v in $2; do
|
||||||
|
[ "$v" = "$1" ] && return 0
|
||||||
|
done
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
end_with_newline()
|
||||||
|
{
|
||||||
|
local c="$(tail -c 1)"
|
||||||
|
[ "$c" = "" ]
|
||||||
|
}
|
||||||
|
trim()
|
||||||
|
{
|
||||||
|
awk '{gsub(/^ +| +$/,"")}1'
|
||||||
|
}
|
||||||
|
split_by_separator()
|
||||||
|
{
|
||||||
|
# $1 - string
|
||||||
|
# $2 - separator
|
||||||
|
# $3 - var name to get "before" part
|
||||||
|
# $4 - var name to get "after" part
|
||||||
|
local before="${1%%$2*}"
|
||||||
|
local after="${1#*$2}"
|
||||||
|
[ "$after" = "$1" ] && after=
|
||||||
|
[ -n "$3" ] && eval $3="\$before"
|
||||||
|
[ -n "$4" ] && eval $4="\$after"
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_is_not_empty()
|
||||||
|
{
|
||||||
|
# $1 - directory
|
||||||
|
local n
|
||||||
|
[ -d "$1" ] || return 1
|
||||||
|
n=$(ls "$1" | wc -c | xargs)
|
||||||
|
[ "$n" != 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
LC_ALL=C 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"
|
||||||
|
}
|
||||||
|
|
||||||
|
replace_str()
|
||||||
|
{
|
||||||
|
local a=$(echo "$1" | sed 's/\//\\\//g')
|
||||||
|
local b=$(echo "$2" | sed 's/\//\\\//g')
|
||||||
|
shift; shift
|
||||||
|
echo "$@" | sed "s/$a/$b/g"
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_md5()
|
||||||
|
{
|
||||||
|
[ -n "$MD5" ] && return
|
||||||
|
MD5=md5sum
|
||||||
|
exists $MD5 || MD5=md5
|
||||||
|
}
|
||||||
|
|
||||||
|
md5f()
|
||||||
|
{
|
||||||
|
setup_md5
|
||||||
|
$MD5 | cut -d ' ' -f1
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_random()
|
||||||
|
{
|
||||||
|
[ -n "$RCUT" ] && return
|
||||||
|
RCUT="cut -c 1-17"
|
||||||
|
# some shells can operate with 32 bit signed int
|
||||||
|
[ $((0x100000000)) = 0 ] && RCUT="cut -c 1-9"
|
||||||
|
}
|
||||||
|
|
||||||
|
random()
|
||||||
|
{
|
||||||
|
# $1 - min, $2 - max
|
||||||
|
local r rs
|
||||||
|
setup_random
|
||||||
|
if [ -c /dev/urandom ]; then
|
||||||
|
read rs </dev/urandom
|
||||||
|
else
|
||||||
|
rs="$RANDOM$RANDOM$(date)"
|
||||||
|
fi
|
||||||
|
# shells use signed int64
|
||||||
|
r=1$(echo $rs | md5f | sed 's/[^0-9]//g' | $RCUT)
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
alloc_num()
|
||||||
|
{
|
||||||
|
# $1 - source var name
|
||||||
|
# $2 - target var name
|
||||||
|
# $3 - min
|
||||||
|
# $4 - max
|
||||||
|
|
||||||
|
local v
|
||||||
|
eval v="\$$2"
|
||||||
|
# do not replace existing value
|
||||||
|
[ -n "$v" ] && return
|
||||||
|
eval v="\$$1"
|
||||||
|
[ -n "$v" ] || v=$3
|
||||||
|
eval $2="$v"
|
||||||
|
v=$((v + 1))
|
||||||
|
[ $v -gt $4 ] && v=$3
|
||||||
|
eval $1="$v"
|
||||||
|
}
|
||||||
|
|
||||||
|
std_ports()
|
||||||
|
{
|
||||||
|
TPWS_PORTS_IPT=$(replace_char - : $TPWS_PORTS)
|
||||||
|
NFQWS_PORTS_TCP_IPT=$(replace_char - : $NFQWS_PORTS_TCP)
|
||||||
|
NFQWS_PORTS_TCP_KEEPALIVE_IPT=$(replace_char - : $NFQWS_PORTS_TCP_KEEPALIVE)
|
||||||
|
NFQWS_PORTS_UDP_IPT=$(replace_char - : $NFQWS_PORTS_UDP)
|
||||||
|
NFQWS_PORTS_UDP_KEEPALIVE_IPT=$(replace_char - : $NFQWS_PORTS_UDP_KEEPALIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
has_bad_ws_options()
|
||||||
|
{
|
||||||
|
# $1 - nfqws/tpws opts
|
||||||
|
|
||||||
|
contains "$1" "--ipset" && {
|
||||||
|
echo
|
||||||
|
echo "WARNING !!! --ipset parameter is present"
|
||||||
|
echo "It's OK if you only specialize already redirected traffic and also process the rest."
|
||||||
|
echo "If you redirect port X to process several IPs from the list and do nothing with the rest - IT'S VERY INEFFECTIVE !"
|
||||||
|
echo "Kernel ipsets should be used instead. Write custom scripts and filter IPs in kernel."
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
check_bad_ws_options()
|
||||||
|
{
|
||||||
|
# $1 - 0 = stop, 1 = start
|
||||||
|
# $2 - nfqws/tpws options
|
||||||
|
if [ "$1" = 1 ] && has_bad_ws_options "$2"; then
|
||||||
|
echo "!!! REFUSING TO USE BAD OPTIONS : $2"
|
||||||
|
help_bad_ws_options
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
help_bad_ws_options()
|
||||||
|
{
|
||||||
|
echo "WARNING ! BAD options detected"
|
||||||
|
}
|
||||||
58
blockcheck/zapret/common/dialog.sh
Normal file
58
blockcheck/zapret/common/dialog.sh
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
read_yes_no()
|
||||||
|
{
|
||||||
|
# $1 - default (Y/N)
|
||||||
|
local A
|
||||||
|
read A
|
||||||
|
[ -z "$A" ] || ([ "$A" != "Y" ] && [ "$A" != "y" ] && [ "$A" != "N" ] && [ "$A" != "n" ]) && A=$1
|
||||||
|
[ "$A" = "Y" ] || [ "$A" = "y" ] || [ "$A" = "1" ]
|
||||||
|
}
|
||||||
|
ask_yes_no()
|
||||||
|
{
|
||||||
|
# $1 - default (Y/N or 0/1)
|
||||||
|
# $2 - text
|
||||||
|
local DEFAULT=$1
|
||||||
|
[ "$1" = "1" ] && DEFAULT=Y
|
||||||
|
[ "$1" = "0" ] && DEFAULT=N
|
||||||
|
[ -z "$DEFAULT" ] && DEFAULT=N
|
||||||
|
printf "$2 (default : $DEFAULT) (Y/N) ? "
|
||||||
|
read_yes_no $DEFAULT
|
||||||
|
}
|
||||||
|
ask_yes_no_var()
|
||||||
|
{
|
||||||
|
# $1 - variable name for answer : 0/1
|
||||||
|
# $2 - text
|
||||||
|
local DEFAULT
|
||||||
|
eval DEFAULT="\$$1"
|
||||||
|
if ask_yes_no "$DEFAULT" "$2"; then
|
||||||
|
eval $1=1
|
||||||
|
else
|
||||||
|
eval $1=0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
ask_list()
|
||||||
|
{
|
||||||
|
# $1 - mode var
|
||||||
|
# $2 - space separated value list
|
||||||
|
# $3 - (optional) default value
|
||||||
|
local M_DEFAULT
|
||||||
|
eval M_DEFAULT="\$$1"
|
||||||
|
local M_ALL=$M_DEFAULT
|
||||||
|
local M=""
|
||||||
|
local m
|
||||||
|
|
||||||
|
[ -n "$3" ] && { find_str_in_list "$M_DEFAULT" "$2" || M_DEFAULT="$3" ;}
|
||||||
|
|
||||||
|
n=1
|
||||||
|
for m in $2; do
|
||||||
|
echo $n : $m
|
||||||
|
n=$(($n+1))
|
||||||
|
done
|
||||||
|
printf "your choice (default : $M_DEFAULT) : "
|
||||||
|
read m
|
||||||
|
[ -n "$m" ] && M=$(echo $2 | cut -d ' ' -f$m 2>/dev/null)
|
||||||
|
[ -z "$M" ] && M="$M_DEFAULT"
|
||||||
|
echo selected : $M
|
||||||
|
eval $1="\"$M\""
|
||||||
|
|
||||||
|
[ "$M" != "$M_OLD" ]
|
||||||
|
}
|
||||||
28
blockcheck/zapret/common/elevate.sh
Normal file
28
blockcheck/zapret/common/elevate.sh
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
require_root()
|
||||||
|
{
|
||||||
|
local exe preserve_env
|
||||||
|
echo \* checking privileges
|
||||||
|
[ $(id -u) -ne "0" ] && {
|
||||||
|
echo root is required
|
||||||
|
exe="$EXEDIR/$(basename "$0")"
|
||||||
|
exists sudo && {
|
||||||
|
echo elevating with sudo
|
||||||
|
exec sudo -E sh "$exe"
|
||||||
|
}
|
||||||
|
exists su && {
|
||||||
|
echo elevating with su
|
||||||
|
case "$UNAME" in
|
||||||
|
Linux)
|
||||||
|
preserve_env="--preserve-environment"
|
||||||
|
;;
|
||||||
|
FreeBSD|OpenBSD|Darwin)
|
||||||
|
preserve_env="-m"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
exec su $preserve_env root -c "sh \"$exe\""
|
||||||
|
}
|
||||||
|
echo su or sudo not found
|
||||||
|
exitp 2
|
||||||
|
}
|
||||||
|
HAVE_ROOT=1
|
||||||
|
}
|
||||||
64
blockcheck/zapret/common/fwtype.sh
Normal file
64
blockcheck/zapret/common/fwtype.sh
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
linux_ipt_avail()
|
||||||
|
{
|
||||||
|
exists iptables && exists ip6tables
|
||||||
|
}
|
||||||
|
linux_maybe_iptables_fwtype()
|
||||||
|
{
|
||||||
|
linux_ipt_avail && FWTYPE=iptables
|
||||||
|
}
|
||||||
|
linux_nft_avail()
|
||||||
|
{
|
||||||
|
exists nft
|
||||||
|
}
|
||||||
|
linux_fwtype()
|
||||||
|
{
|
||||||
|
[ -n "$FWTYPE" ] && return
|
||||||
|
|
||||||
|
FWTYPE=unsupported
|
||||||
|
|
||||||
|
linux_get_subsys
|
||||||
|
if [ "$SUBSYS" = openwrt ] ; then
|
||||||
|
# linux kernel is new enough if fw4 is there
|
||||||
|
if [ -x /sbin/fw4 ] && linux_nft_avail ; then
|
||||||
|
FWTYPE=nftables
|
||||||
|
else
|
||||||
|
linux_maybe_iptables_fwtype
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
SUBSYS=
|
||||||
|
# generic linux
|
||||||
|
# flowtable is implemented since kernel 4.16
|
||||||
|
if linux_nft_avail && linux_min_version 4 16; then
|
||||||
|
FWTYPE=nftables
|
||||||
|
else
|
||||||
|
linux_maybe_iptables_fwtype
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
export FWTYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
get_fwtype()
|
||||||
|
{
|
||||||
|
[ -n "$FWTYPE" ] && return
|
||||||
|
|
||||||
|
local UNAME="$(uname)"
|
||||||
|
|
||||||
|
case "$UNAME" in
|
||||||
|
Linux)
|
||||||
|
linux_fwtype
|
||||||
|
;;
|
||||||
|
FreeBSD)
|
||||||
|
if exists ipfw ; then
|
||||||
|
FWTYPE=ipfw
|
||||||
|
else
|
||||||
|
FWTYPE=unsupported
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
FWTYPE=unsupported
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
export FWTYPE
|
||||||
|
}
|
||||||
39
blockcheck/zapret/common/virt.sh
Normal file
39
blockcheck/zapret/common/virt.sh
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
get_virt()
|
||||||
|
{
|
||||||
|
local vm s v UNAME
|
||||||
|
UNAME=$(uname)
|
||||||
|
case "$UNAME" in
|
||||||
|
Linux)
|
||||||
|
if exists systemd-detect-virt; then
|
||||||
|
vm=$(systemd-detect-virt --vm)
|
||||||
|
elif [ -f /sys/class/dmi/id/product_name ]; then
|
||||||
|
read s </sys/class/dmi/id/product_name
|
||||||
|
for v in KVM QEMU VMware VMW VirtualBox Xen Bochs Parallels BHYVE Hyper-V; do
|
||||||
|
case "$s" in
|
||||||
|
"$v"*)
|
||||||
|
vm=$v
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "$vm" | awk '{print tolower($0)}'
|
||||||
|
}
|
||||||
|
check_virt()
|
||||||
|
{
|
||||||
|
echo \* checking virtualization
|
||||||
|
local vm="$(get_virt)"
|
||||||
|
if [ -n "$vm" ]; then
|
||||||
|
if [ "$vm" = "none" ]; then
|
||||||
|
echo running on bare metal
|
||||||
|
else
|
||||||
|
echo "!!! WARNING. $vm virtualization detected !!!"
|
||||||
|
echo '!!! WARNING. vmware and virtualbox are known to break most of the DPI bypass techniques when network is NATed using internal hypervisor NAT !!!'
|
||||||
|
echo '!!! WARNING. if this is your case make sure you are bridged not NATed !!!'
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo cannot detect
|
||||||
|
fi
|
||||||
|
}
|
||||||
BIN
blockcheck/zapret/files/fake/dht_find_node.bin
Normal file
BIN
blockcheck/zapret/files/fake/dht_find_node.bin
Normal file
Binary file not shown.
2
blockcheck/zapret/files/fake/dht_get_peers.bin
Normal file
2
blockcheck/zapret/files/fake/dht_get_peers.bin
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
d1:ad2:id20:.+NA-<2D><>ut<14><>E<EFBFBD>wΑiJ<69>9:info_hash20:;
|
||||||
|
<EFBFBD><15><>侧<EFBFBD><E4BEA7><EFBFBD><EFBFBD>O<><4F>2I<32>e1:q9:get_peers1:t2:<3A><>1:v4:LT1:y1:qe
|
||||||
BIN
blockcheck/zapret/files/fake/discord-ip-discovery-with-port.bin
Normal file
BIN
blockcheck/zapret/files/fake/discord-ip-discovery-with-port.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
blockcheck/zapret/files/fake/dtls_clienthello_w3_org.bin
Normal file
BIN
blockcheck/zapret/files/fake/dtls_clienthello_w3_org.bin
Normal file
Binary file not shown.
9
blockcheck/zapret/files/fake/http_iana_org.bin
Normal file
9
blockcheck/zapret/files/fake/http_iana_org.bin
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
GET / HTTP/1.1
|
||||||
|
Host: www.iana.org
|
||||||
|
Connection: keep-alive
|
||||||
|
Upgrade-Insecure-Requests: 1
|
||||||
|
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4300.0 Safari/537.36
|
||||||
|
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
|
||||||
|
Accept-Encoding: gzip, deflate
|
||||||
|
Accept-Language: en-US,en;q=0.9,ru;q=0.8
|
||||||
|
|
||||||
BIN
blockcheck/zapret/files/fake/isakmp_initiator_request.bin
Normal file
BIN
blockcheck/zapret/files/fake/isakmp_initiator_request.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/quic_initial_facebook_com.bin
Normal file
BIN
blockcheck/zapret/files/fake/quic_initial_facebook_com.bin
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
blockcheck/zapret/files/fake/quic_initial_rutracker_org.bin
Normal file
BIN
blockcheck/zapret/files/fake/quic_initial_rutracker_org.bin
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
blockcheck/zapret/files/fake/quic_initial_vk_com.bin
Normal file
BIN
blockcheck/zapret/files/fake/quic_initial_vk_com.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/quic_initial_www_google_com.bin
Normal file
BIN
blockcheck/zapret/files/fake/quic_initial_www_google_com.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/quic_short_header.bin
Normal file
BIN
blockcheck/zapret/files/fake/quic_short_header.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/stun.bin
Normal file
BIN
blockcheck/zapret/files/fake/stun.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/tls_clienthello_gosuslugi_ru.bin
Normal file
BIN
blockcheck/zapret/files/fake/tls_clienthello_gosuslugi_ru.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/tls_clienthello_iana_org.bin
Normal file
BIN
blockcheck/zapret/files/fake/tls_clienthello_iana_org.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
blockcheck/zapret/files/fake/tls_clienthello_sberbank_ru.bin
Normal file
BIN
blockcheck/zapret/files/fake/tls_clienthello_sberbank_ru.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/tls_clienthello_vk_com.bin
Normal file
BIN
blockcheck/zapret/files/fake/tls_clienthello_vk_com.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/tls_clienthello_vk_com_kyber.bin
Normal file
BIN
blockcheck/zapret/files/fake/tls_clienthello_vk_com_kyber.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/tls_clienthello_www_google_com.bin
Normal file
BIN
blockcheck/zapret/files/fake/tls_clienthello_www_google_com.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/wireguard_initiation.bin
Normal file
BIN
blockcheck/zapret/files/fake/wireguard_initiation.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/wireguard_response.bin
Normal file
BIN
blockcheck/zapret/files/fake/wireguard_response.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/zero_1024.bin
Normal file
BIN
blockcheck/zapret/files/fake/zero_1024.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/zero_256.bin
Normal file
BIN
blockcheck/zapret/files/fake/zero_256.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/files/fake/zero_512.bin
Normal file
BIN
blockcheck/zapret/files/fake/zero_512.bin
Normal file
Binary file not shown.
BIN
blockcheck/zapret/ip2net/ip2net.exe
Normal file
BIN
blockcheck/zapret/ip2net/ip2net.exe
Normal file
Binary file not shown.
BIN
blockcheck/zapret/mdig/mdig.exe
Normal file
BIN
blockcheck/zapret/mdig/mdig.exe
Normal file
Binary file not shown.
BIN
blockcheck/zapret/nfq/WinDivert.dll
Normal file
BIN
blockcheck/zapret/nfq/WinDivert.dll
Normal file
Binary file not shown.
BIN
blockcheck/zapret/nfq/WinDivert64.sys
Normal file
BIN
blockcheck/zapret/nfq/WinDivert64.sys
Normal file
Binary file not shown.
BIN
blockcheck/zapret/nfq/winws.exe
Normal file
BIN
blockcheck/zapret/nfq/winws.exe
Normal file
Binary file not shown.
58
blockcheck/zapret2/blockcheck2.d/custom/10-list.sh
Normal file
58
blockcheck/zapret2/blockcheck2.d/custom/10-list.sh
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
LIST_HTTP="${LIST_HTTP:-$TESTDIR/list_http.txt}"
|
||||||
|
LIST_HTTPS_TLS12="${LIST_HTTPS_TLS12:-$TESTDIR/list_https_tls12.txt}"
|
||||||
|
LIST_HTTPS_TLS13="${LIST_HTTPS_TLS13:-$TESTDIR/list_https_tls13.txt}"
|
||||||
|
LIST_QUIC="${LIST_QUIC:-$TESTDIR/list_quic.txt}"
|
||||||
|
|
||||||
|
check_list()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - file
|
||||||
|
|
||||||
|
local line ok=0
|
||||||
|
[ -f "$3" ] || {
|
||||||
|
echo "no strategy file '$3'"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
while IFS= read -r line; do
|
||||||
|
case "$line" in
|
||||||
|
""|\#*) continue ;;
|
||||||
|
esac
|
||||||
|
line=$(echo "$line" | tr -d "\r\n")
|
||||||
|
eval pktws_curl_test_update "$1" "$2" $line && ok=1
|
||||||
|
done < "$3"
|
||||||
|
|
||||||
|
[ "$ok" = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_http()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
|
||||||
|
check_list "$1" "$2" "$LIST_HTTP"
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls12()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
|
||||||
|
check_list "$1" "$2" "$LIST_HTTPS_TLS12"
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls13()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
|
||||||
|
check_list "$1" "$2" "$LIST_HTTPS_TLS13"
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_http3()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
|
||||||
|
check_list "$1" "$2" "$LIST_QUIC"
|
||||||
|
}
|
||||||
10
blockcheck/zapret2/blockcheck2.d/custom/README.txt
Normal file
10
blockcheck/zapret2/blockcheck2.d/custom/README.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Простой тестер стратегий по списку из файла.
|
||||||
|
Скопируйте эту директорию под другим именем в blockcheck2.d, отредактируйте list файлы, впишите туда свои стратегии.
|
||||||
|
В диалоге blockcheck2.sh выберите тест с названием вашей директории.
|
||||||
|
Можно комментировать строки символом '#' в начале строки.
|
||||||
|
Альтернативный путь до файлов стратегий можно задать переменными LIST_HTTP, LIST_HTTPS_TLS12, LIST_HTTPS_TLS13, LIST_QUIC.
|
||||||
|
|
||||||
|
This is simple strategy tester from a file.
|
||||||
|
Copy this folder, write your strategies into list files and select your test in blockcheck2 dialog.
|
||||||
|
Lines can be commented using the '#' symbol at the line start.
|
||||||
|
Strategy list files paths can be overriden in env variables : LIST_HTTP, LIST_HTTPS_TLS12, LIST_HTTPS_TLS13, LIST_QUIC.
|
||||||
4
blockcheck/zapret2/blockcheck2.d/custom/list_http.txt
Normal file
4
blockcheck/zapret2/blockcheck2.d/custom/list_http.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# write nfqws2 parameters here
|
||||||
|
--payload=http_req --lua-desync=http_hostcase
|
||||||
|
--payload=http_req --lua-desync=http_methodeol
|
||||||
|
--payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_ts=-1000
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# write nfqws2 parameters here
|
||||||
|
--payload tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_ts=-1000
|
||||||
|
--payload=tls_client_hello --lua-desync=fake:blob=0x00000000:tcp_md5:repeats=1 --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,dupsid:repeats=1 --lua-desync=multisplit:pos=2
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# write nfqws2 parameters here
|
||||||
|
--payload tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_ts=-1000
|
||||||
|
--payload tls_client_hello --lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop
|
||||||
|
--payload tls_client_hello --lua-desync=luaexec:code="desync.pat=tls_mod(fake_default_tls,'rnd,rndsni,dupsid,padencap',desync.reasm_data)" --lua-desync=tcpseg:pos=0,-1:seqovl=#pat:seqovl_pattern=pat --lua-desync=drop
|
||||||
3
blockcheck/zapret2/blockcheck2.d/custom/list_quic.txt
Normal file
3
blockcheck/zapret2/blockcheck2.d/custom/list_quic.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# write nfqws2 parameters here
|
||||||
|
--payload quic_initial --lua-desync=fake:blob=fake_default_quic:repeats=11
|
||||||
|
--payload quic_initial --lua-desync=send:ipfrag --lua-desync=drop
|
||||||
12
blockcheck/zapret2/blockcheck2.d/standard/10-http-basic.sh
Normal file
12
blockcheck/zapret2/blockcheck2.d/standard/10-http-basic.sh
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
pktws_check_http()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
local s
|
||||||
|
|
||||||
|
[ "$NOTEST_BASIC_HTTP" = 1 ] && { echo "SKIPPED"; return; }
|
||||||
|
|
||||||
|
for s in 'http_hostcase' 'http_hostcase:spell=hoSt' 'http_domcase' 'http_methodeol'; do
|
||||||
|
pktws_curl_test_update $1 $2 --payload http_req --lua-desync=$s
|
||||||
|
done
|
||||||
|
}
|
||||||
38
blockcheck/zapret2/blockcheck2.d/standard/15-misc.sh
Normal file
38
blockcheck/zapret2/blockcheck2.d/standard/15-misc.sh
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
. "$TESTDIR/def.inc"
|
||||||
|
|
||||||
|
pktws_check_http()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
|
||||||
|
local PAYLOAD="--payload http_req" repeats ok
|
||||||
|
|
||||||
|
for repeats in 1 20 100 260; do
|
||||||
|
# send starting bytes of original payload
|
||||||
|
pktws_curl_test_update "$1" "$2" $PAYLOAD --lua-desync=tcpseg:pos=0,method+2:ip_id=rnd:repeats=$repeats && ok=1
|
||||||
|
pktws_curl_test_update "$1" "$2" $PAYLOAD --lua-desync=tcpseg:pos=0,midsld:ip_id=rnd:repeats=$repeats && ok=1
|
||||||
|
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls12()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
|
||||||
|
local PAYLOAD="--payload tls_client_hello" repeats ok
|
||||||
|
|
||||||
|
for repeats in 1 20 100 260; do
|
||||||
|
# send starting bytes of original payload
|
||||||
|
pktws_curl_test_update "$1" "$2" $PAYLOAD --lua-desync=tcpseg:pos=0,1:ip_id=rnd:repeats=$repeats && ok=1
|
||||||
|
pktws_curl_test_update "$1" "$2" $PAYLOAD --lua-desync=tcpseg:pos=0,midsld:ip_id=rnd:repeats=$repeats && ok=1
|
||||||
|
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls13()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls12 "$1" "$2"
|
||||||
|
}
|
||||||
66
blockcheck/zapret2/blockcheck2.d/standard/20-multi.sh
Normal file
66
blockcheck/zapret2/blockcheck2.d/standard/20-multi.sh
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
pktws_simple_split_tests()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain/uri
|
||||||
|
# $3 - splits
|
||||||
|
# $4 - PRE args for nfqws2
|
||||||
|
local pos ok ok_any pre="$4"
|
||||||
|
local splitf splitfs="multisplit multidisorder"
|
||||||
|
|
||||||
|
ok_any=0
|
||||||
|
for splitf in multisplit multidisorder; do
|
||||||
|
eval need_$splitf=0
|
||||||
|
ok=0
|
||||||
|
for pos in $3; do
|
||||||
|
pktws_curl_test_update $1 $2 $pre $PAYLOAD --lua-desync=$splitf:pos=$pos && ok=1
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 -a "$SCANLEVEL" != force ] || eval need_$splitf=1
|
||||||
|
[ "$ok" = 1 ] && ok_any=1
|
||||||
|
done
|
||||||
|
[ "$ok_any" = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pktws_check_http()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
local splits_http='method+2 midsld method+2,midsld'
|
||||||
|
local PAYLOAD="--payload http_req"
|
||||||
|
|
||||||
|
[ "$NOTEST_MULTI_HTTP" = 1 ] && { echo "SKIPPED"; return; }
|
||||||
|
|
||||||
|
pktws_simple_split_tests "$1" "$2" "$splits_http"
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - PRE args for nfqws2
|
||||||
|
local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
|
||||||
|
local PAYLOAD="--payload tls_client_hello"
|
||||||
|
|
||||||
|
[ "$NOTEST_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
|
||||||
|
|
||||||
|
pktws_simple_split_tests "$1" "$2" "$splits_tls" "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls12()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
|
||||||
|
|
||||||
|
# do not use 'need' values obtained with wssize
|
||||||
|
local need_multisplit_save=$need_multisplit need_multidisorder_save=$need_multidisorder
|
||||||
|
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
|
||||||
|
need_multisplit=$need_multisplit_save; need_multidisorder=$need_multidisorder_save
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls13()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2"
|
||||||
|
}
|
||||||
94
blockcheck/zapret2/blockcheck2.d/standard/23-seqovl.sh
Normal file
94
blockcheck/zapret2/blockcheck2.d/standard/23-seqovl.sh
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
pktws_check_http()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
|
||||||
|
[ "$NOTEST_SEQOVL_HTTP" = 1 ] && { echo "SKIPPED"; return; }
|
||||||
|
|
||||||
|
local PAYLOAD="--payload http_req"
|
||||||
|
|
||||||
|
local ok pat= split f f2
|
||||||
|
|
||||||
|
pat=${SEQOVL_PATTERN_HTTP:+seqovl_pat}
|
||||||
|
pat=${pat:-fake_default_http}
|
||||||
|
|
||||||
|
pktws_curl_test_update $1 $2 $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop
|
||||||
|
pktws_curl_test_update $1 $2 ${SEQOVL_PATTERN_HTTP:+--blob=$pat:@"$SEQOVL_PATTERN_HTTP" }$PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=#$pat:seqovl_pattern=$pat --lua-desync=drop
|
||||||
|
|
||||||
|
ok=0
|
||||||
|
for split in method+2 method+2,midsld; do
|
||||||
|
pktws_curl_test_update $1 $2 $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=1 && ok=1
|
||||||
|
pktws_curl_test_update $1 $2 ${SEQOVL_PATTERN_HTTP:+--blob=$pat:@"$SEQOVL_PATTERN_HTTP" }$PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=#$pat:seqovl_pattern=$pat && ok=1
|
||||||
|
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
for split in 'method+1 method+2' 'midsld-1 midsld' 'method+1 method+2,midsld'; do
|
||||||
|
f="$(extract_arg 1 $split)"
|
||||||
|
f2="$(extract_arg 2 $split)"
|
||||||
|
pktws_curl_test_update $1 $2 $PAYLOAD --lua-desync=multidisorder:pos=$f2:seqovl=$f
|
||||||
|
pktws_curl_test_update $1 $2 ${SEQOVL_PATTERN_HTTP:+--blob=$pat:@"$SEQOVL_PATTERN_HTTP" }$PAYLOAD --lua-desync=multidisorder:pos=$f2:seqovl=$f:seqovl_pattern=$pat
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_seqovl_tests_tls()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain/uri
|
||||||
|
# $3 - PRE args for nfqws2
|
||||||
|
local ok ok_any
|
||||||
|
local testf=$1 domain="$2" pre="$3"
|
||||||
|
local pat rnd_mod padencap_mod split f f2
|
||||||
|
local PAYLOAD="--payload tls_client_hello"
|
||||||
|
|
||||||
|
pat=${SEQOVL_PATTERN_HTTPS:+seqovl_pat}
|
||||||
|
pat=${pat:-fake_default_tls}
|
||||||
|
rnd_mod="--lua-init=$pat=tls_mod($pat,'rnd')"
|
||||||
|
padencap_mod="--lua-desync=luaexec:code=desync.pat=tls_mod($pat,'rnd,dupsid,padencap',desync.reasm_data)"
|
||||||
|
|
||||||
|
ok=0
|
||||||
|
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop && ok=1
|
||||||
|
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=#$pat:seqovl_pattern=$pat --lua-desync=drop && ok=1
|
||||||
|
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=tcpseg:pos=0,-1:seqovl=#pat:seqovl_pattern=pat --lua-desync=drop && ok=1
|
||||||
|
ok_any=$ok
|
||||||
|
|
||||||
|
ok=0
|
||||||
|
for split in 10 10,sniext+1 10,sniext+4 10,midsld; do
|
||||||
|
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=1 && ok=1
|
||||||
|
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=#$pat:seqovl_pattern=$pat && ok=1
|
||||||
|
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=multisplit:pos=$split:seqovl=#pat:seqovl_pattern=pat && ok=1
|
||||||
|
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
for split in '1 2' 'sniext sniext+1' 'sniext+3 sniext+4' 'midsld-1 midsld' '1 2,midsld'; do
|
||||||
|
f="$(extract_arg 1 $split)"
|
||||||
|
f2="$(extract_arg 2 $split)"
|
||||||
|
pktws_curl_test_update $1 $2 $PAYLOAD --lua-desync=multidisorder:pos=$f2:seqovl=$f && ok=1
|
||||||
|
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=multidisorder:pos=$f2:seqovl=$f:seqovl_pattern=$pat && ok=1
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ] && ok_any=1
|
||||||
|
[ "$ok_any" = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - PRE args for nfqws2
|
||||||
|
|
||||||
|
[ "$NOTEST_SEQOVL_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
|
||||||
|
|
||||||
|
pktws_seqovl_tests_tls "$1" "$2" "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls12()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_seqovl_tests_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
|
||||||
|
pktws_seqovl_tests_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls13()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_seqovl_tests_tls "$1" "$2"
|
||||||
|
}
|
||||||
49
blockcheck/zapret2/blockcheck2.d/standard/24-syndata.sh
Normal file
49
blockcheck/zapret2/blockcheck2.d/standard/24-syndata.sh
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
. "$TESTDIR/def.inc"
|
||||||
|
|
||||||
|
pktws_check_http()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
|
||||||
|
local PAYLOAD="--payload http_req" split
|
||||||
|
|
||||||
|
for split in '' multisplit multidisorder; do
|
||||||
|
pktws_curl_test_update "$1" "$2" --lua-desync=syndata ${split:+$PAYLOAD --lua-desync=$split}
|
||||||
|
pktws_curl_test_update "$1" "$2" --lua-desync=syndata:blob=fake_default_http $PAYLOAD ${split:+$PAYLOAD --lua-desync=$split}
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - PRE args for nfqws2
|
||||||
|
|
||||||
|
local PAYLOAD="--payload tls_client_hello" ok=0 pre="$3" split
|
||||||
|
|
||||||
|
for split in '' multisplit multidisorder; do
|
||||||
|
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata ${split:+$PAYLOAD --lua-desync=$split} && ok=1
|
||||||
|
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata:blob=0x1603 ${split:+$PAYLOAD --lua-desync=$split} && ok=1
|
||||||
|
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata:blob=fake_default_tls:tls_mod=rnd,dupsid,rndsni ${split:+$PAYLOAD --lua-desync=$split} && ok=1
|
||||||
|
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata:blob=fake_default_tls:tls_mod=rnd,dupsid,sni=google.com ${split:+$PAYLOAD --lua-desync=$split} && ok=1
|
||||||
|
done
|
||||||
|
|
||||||
|
[ "$ok" = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls12()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
|
||||||
|
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
|
||||||
|
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls13()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
|
||||||
|
pktws_check_https_tls "$1" "$2"
|
||||||
|
}
|
||||||
149
blockcheck/zapret2/blockcheck2.d/standard/25-fake.sh
Normal file
149
blockcheck/zapret2/blockcheck2.d/standard/25-fake.sh
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
. "$TESTDIR/def.inc"
|
||||||
|
|
||||||
|
pktws_check_http()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
[ "$NOTEST_FAKE_HTTP" = 1 ] && { echo "SKIPPED"; return; }
|
||||||
|
|
||||||
|
local testf=$1 domain="$2"
|
||||||
|
local ok ok_any ttls attls f ff fake fooling
|
||||||
|
local PAYLOAD="--payload=http_req"
|
||||||
|
|
||||||
|
if [ -n "$FAKE_HTTP" ]; then
|
||||||
|
fake=fake_http
|
||||||
|
else
|
||||||
|
fake=fake_default_http
|
||||||
|
fi
|
||||||
|
|
||||||
|
need_fake=0
|
||||||
|
|
||||||
|
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
|
||||||
|
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
|
||||||
|
|
||||||
|
ok_any=0
|
||||||
|
ok=0
|
||||||
|
for ttl in $ttls; do
|
||||||
|
# orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server.
|
||||||
|
# missing ACK is transmitted in the first data packet of TLS/HTTP proto
|
||||||
|
for ff in $fake 0x00000000; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }$PAYLOAD "--lua-desync=fake:blob=${ff}:ip${IPVV}_ttl=$ttl:repeats=$FAKE_REPEATS" $f && {
|
||||||
|
ok=1
|
||||||
|
[ "$SCANLEVEL" = force ] || break
|
||||||
|
}
|
||||||
|
done
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ] && break
|
||||||
|
done
|
||||||
|
for fooling in $FOOLINGS_TCP; do
|
||||||
|
for ff in $fake 0x00000000; do
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=fake_http:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS && ok=1
|
||||||
|
# duplicate SYN with MD5
|
||||||
|
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --payload empty "--out-range=<s1" --lua-desync=send:tcp_md5 && ok=1
|
||||||
|
done
|
||||||
|
done
|
||||||
|
for ttl in $attls; do
|
||||||
|
for ff in $fake 0x00000000; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:ip${IPVV}_autottl=-$ttl,3-20:repeats=$FAKE_REPEATS $f && {
|
||||||
|
ok=1
|
||||||
|
[ "$SCANLEVEL" = force ] || break
|
||||||
|
}
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_fake=1
|
||||||
|
[ $ok = 1 ] && okany=1
|
||||||
|
[ $okany = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_fake_https_vary_()
|
||||||
|
{
|
||||||
|
local ok_any=0 testf=$1 domain="$2" fooling="$3" pre="$4" post="$5"
|
||||||
|
shift; shift; shift
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=multisplit:blob=$fake:$fooling:pos=2:nodrop:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid,padencap:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||||
|
[ "$ok_any" = 1 ] && ok=1
|
||||||
|
}
|
||||||
|
pktws_fake_https_vary()
|
||||||
|
{
|
||||||
|
local ok_any=0 fooling="$3"
|
||||||
|
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "$5" && ok_any=1
|
||||||
|
# duplicate SYN with MD5
|
||||||
|
contains "$fooling" tcp_md5 && \
|
||||||
|
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5" && ok_any=1
|
||||||
|
[ "$ok_any" = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - PRE args for nfqws2
|
||||||
|
|
||||||
|
[ "$NOTEST_FAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
|
||||||
|
|
||||||
|
local testf=$1 domain="$2" pre="$3"
|
||||||
|
local ok ok_any ttls attls f fake fooling
|
||||||
|
local PAYLOAD="--payload=tls_client_hello"
|
||||||
|
|
||||||
|
shift; shift
|
||||||
|
|
||||||
|
if [ -n "$FAKE_HTTPS" ]; then
|
||||||
|
fake=fake_tls
|
||||||
|
else
|
||||||
|
fake=fake_default_tls
|
||||||
|
fi
|
||||||
|
|
||||||
|
need_fake=0
|
||||||
|
|
||||||
|
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
|
||||||
|
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
|
||||||
|
|
||||||
|
ok_any=0
|
||||||
|
ok=0
|
||||||
|
for ttl in $ttls; do
|
||||||
|
# orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server.
|
||||||
|
# missing ACK is transmitted in the first data packet of TLS/HTTP proto
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_fake_https_vary $testf $domain "ip${IPVV}_ttl=$ttl" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ] && break
|
||||||
|
done
|
||||||
|
for fooling in $FOOLINGS_TCP; do
|
||||||
|
pktws_fake_https_vary $testf $domain "$fooling" "$pre"
|
||||||
|
done
|
||||||
|
for ttl in $attls; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_fake_https_vary $testf $domain "ip${IPVV}_autottl=-$ttl,3-20" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_fake=1
|
||||||
|
[ $ok = 1 ] && okany=1
|
||||||
|
[ $okany = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls12()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
|
||||||
|
|
||||||
|
# do not use 'need' values obtained with wssize
|
||||||
|
local need_fake_save=$need_fake
|
||||||
|
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
|
||||||
|
need_fake=$need_fake_save
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls13()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2"
|
||||||
|
}
|
||||||
103
blockcheck/zapret2/blockcheck2.d/standard/30-faked.sh
Normal file
103
blockcheck/zapret2/blockcheck2.d/standard/30-faked.sh
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
. "$TESTDIR/def.inc"
|
||||||
|
|
||||||
|
pktws_check_faked()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - payload_type
|
||||||
|
# $4 - splits
|
||||||
|
# $5 - pattern
|
||||||
|
# $6 - PRE args for nfqws2
|
||||||
|
local testf=$1 domain="$2" pre="$6"
|
||||||
|
local ok ok_any ttls attls f fooling
|
||||||
|
local splitf splitfs= split splits="$4"
|
||||||
|
local PAYLOAD="--payload=$3"
|
||||||
|
local FAKED_PATTERN="$5"
|
||||||
|
|
||||||
|
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
|
||||||
|
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
|
||||||
|
|
||||||
|
# do not test fakedsplit if multisplit works
|
||||||
|
[ "$need_multisplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=fakedsplit
|
||||||
|
# do not test fakeddisorder if multidisorder works
|
||||||
|
[ "$need_multidisorder" = 0 -a "$SCANLEVEL" != force ] || splitfs="${splitfs:+$splitfs }fakeddisorder"
|
||||||
|
|
||||||
|
ok_any=0
|
||||||
|
for splitf in $splitfs; do
|
||||||
|
ok=0
|
||||||
|
for ttl in $ttls; do
|
||||||
|
# orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server.
|
||||||
|
# missing ACK is transmitted in the first data packet of TLS/HTTP proto
|
||||||
|
for split in $splits; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKED_PATTERN:+--blob=faked_pat:@"$FAKED_PATTERN" }$pre $PAYLOAD --lua-desync=$splitf:${FAKED_PATTERN:+pattern=faked_pat:}pos=$split:ip${IPVV}_ttl=$ttl:repeats=$FAKE_REPEATS $f && {
|
||||||
|
ok=1
|
||||||
|
[ "$SCANLEVEL" = force ] || break
|
||||||
|
}
|
||||||
|
done
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ] && break
|
||||||
|
done
|
||||||
|
for fooling in $FOOLINGS_TCP; do
|
||||||
|
for split in $splits; do
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKED_PATTERN:+--blob=faked_pat:@"$FAKED_PATTERN" }$pre $PAYLOAD --lua-desync=$splitf:${FAKED_PATTERN:+pattern=faked_pat:}pos=$split:$fooling && ok=1
|
||||||
|
# duplicate SYN with MD5
|
||||||
|
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKED_PATTERN:+--blob=faked_pat:@"$FAKED_PATTERN" }$pre $PAYLOAD --lua-desync=$splitf:${FAKED_PATTERN:+pattern=faked_pat:}pos=$split:$fooling:repeats=$FAKE_REPEATS --payload empty --out-range="<s1" --lua-desync=send:tcp_md5 && ok=1
|
||||||
|
done
|
||||||
|
done
|
||||||
|
for ttl in $attls; do
|
||||||
|
for split in $splits; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKED_PATTERN:+--blob=faked_pat:@"$FAKED_PATTERN" }$pre $PAYLOAD --lua-desync=$splitf:${FAKED_PATTERN:+pattern=faked_pat:}pos=$split:ip${IPVV}_autottl=-$ttl,3-20:repeats=$FAKE_REPEATS $f && {
|
||||||
|
ok=1
|
||||||
|
[ "$SCANLEVEL" = force ] || break
|
||||||
|
}
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
[ $ok = 0 -a "$SCANLEVEL" != force ] && eval need_$splitf=1
|
||||||
|
[ $ok = 1 ] && ok_any=1
|
||||||
|
done
|
||||||
|
[ "$ok_any" = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_http()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - PRE args for nfqws2
|
||||||
|
[ "$NOTEST_FAKED_HTTP" = 1 ] && { echo "SKIPPED"; return; }
|
||||||
|
|
||||||
|
local splits='method+2 midsld method+2,midsld'
|
||||||
|
pktws_check_faked $1 "$2" http_req "$splits" "$FAKED_PATTERN_HTTP" "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - PRE args for nfqws2
|
||||||
|
[ "$NOTEST_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
|
||||||
|
|
||||||
|
local splits='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
|
||||||
|
pktws_check_faked $1 "$2" tls_client_hello "$splits" "$FAKED_PATTERN_HTTPS" "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls12()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
|
||||||
|
|
||||||
|
# do not use 'need' values obtained with wssize
|
||||||
|
local need_fakedsplit_save=$need_fakedsplit need_fakeddisorder_save=$need_fakeddisorder
|
||||||
|
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
|
||||||
|
need_fakedsplit=$need_fakedsplit_save need_fakeddisorder=$need_fakeddisorder_save
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls13()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2"
|
||||||
|
}
|
||||||
101
blockcheck/zapret2/blockcheck2.d/standard/35-hostfake.sh
Normal file
101
blockcheck/zapret2/blockcheck2.d/standard/35-hostfake.sh
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
. "$TESTDIR/def.inc"
|
||||||
|
|
||||||
|
|
||||||
|
pktws_hostfake_vary_()
|
||||||
|
{
|
||||||
|
local ok_any=0 testf=$1 domain="$2" fooling="$3" pre="$4" post="$5" disorder
|
||||||
|
shift; shift; shift
|
||||||
|
|
||||||
|
for disorder in '' 'disorder_after:'; do
|
||||||
|
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake1:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake2:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}midhost=midsld:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake1:midhost=midsld:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake2:midhost=midsld:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||||
|
done
|
||||||
|
[ "$ok_any" = 1 ] && ok=1
|
||||||
|
}
|
||||||
|
pktws_hostfake_vary()
|
||||||
|
{
|
||||||
|
local ok_any=0 fooling="$3"
|
||||||
|
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "$5" && ok_any=1
|
||||||
|
# duplicate SYN with MD5
|
||||||
|
contains "$fooling" tcp_md5 && \
|
||||||
|
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5" && ok_any=1
|
||||||
|
[ "$ok_any" = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pktws_check_hostfake()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - payload_type
|
||||||
|
# $4 - PRE args for nfqws2
|
||||||
|
local testf=$1 domain="$2" pre="$4"
|
||||||
|
local ok ttls attls f fooling
|
||||||
|
local PAYLOAD="--payload=$3"
|
||||||
|
|
||||||
|
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
|
||||||
|
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
|
||||||
|
|
||||||
|
need_hostfakesplit=0
|
||||||
|
ok=0
|
||||||
|
for ttl in $ttls; do
|
||||||
|
# orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server.
|
||||||
|
# missing ACK is transmitted in the first data packet of TLS/HTTP proto
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_hostfake_vary $testf $domain "ip${IPVV}_ttl=$ttl" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ] && break
|
||||||
|
done
|
||||||
|
for fooling in $FOOLINGS_TCP; do
|
||||||
|
pktws_hostfake_vary $testf $domain "$fooling" "$pre"
|
||||||
|
done
|
||||||
|
for ttl in $attls; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_hostfake_vary $testf $domain "ip${IPVV}_autottl=-$ttl,3-20" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
done
|
||||||
|
[ $ok = 0 -a "$SCANLEVEL" != force ] && eval need_hostfake=1
|
||||||
|
[ $ok = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_http()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
[ "$NOTEST_HOSTFAKE_HTTP" = 1 ] && { echo "SKIPPED"; return; }
|
||||||
|
|
||||||
|
pktws_check_hostfake $1 "$2" http_req
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - PRE args for nfqws2
|
||||||
|
|
||||||
|
[ "$NOTEST_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
|
||||||
|
|
||||||
|
pktws_check_hostfake $1 "$2" tls_client_hello "$3"
|
||||||
|
}
|
||||||
|
pktws_check_https_tls12()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
|
||||||
|
|
||||||
|
# do not use 'need' values obtained with wssize
|
||||||
|
local need_hostfakesplit_save=$need_hostfakesplit
|
||||||
|
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
|
||||||
|
need_hostfakesplit=$need_hostfakesplit_save
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls13()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2"
|
||||||
|
}
|
||||||
160
blockcheck/zapret2/blockcheck2.d/standard/50-fake-multi.sh
Normal file
160
blockcheck/zapret2/blockcheck2.d/standard/50-fake-multi.sh
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
. "$TESTDIR/def.inc"
|
||||||
|
|
||||||
|
pktws_check_http()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
[ "$NOTEST_FAKE_MULTI_HTTP" = 1 ] && { echo "SKIPPED"; return 0; }
|
||||||
|
|
||||||
|
local testf=$1 domain="$2"
|
||||||
|
local ok ttls attls f ff fake fooling splitf splitfs= split splits='method+2 midsld method+2,midsld'
|
||||||
|
local PAYLOAD="--payload=http_req"
|
||||||
|
|
||||||
|
if [ -n "$FAKE_HTTP" ]; then
|
||||||
|
fake=fake_http
|
||||||
|
else
|
||||||
|
fake=fake_default_http
|
||||||
|
fi
|
||||||
|
|
||||||
|
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
|
||||||
|
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
|
||||||
|
|
||||||
|
# do not test fake + multisplit if multisplit works
|
||||||
|
[ "$need_multisplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=multisplit
|
||||||
|
# do not test fake + multidisorder if multidisorder works
|
||||||
|
[ "$need_multidisorder" = 0 -a "$SCANLEVEL" != force ] || splitfs="${splitfs:+$splitfs }multidisorder"
|
||||||
|
|
||||||
|
for splitf in $splitfs; do
|
||||||
|
ok=0
|
||||||
|
for ttl in $ttls; do
|
||||||
|
for split in $splits; do
|
||||||
|
# orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server.
|
||||||
|
# missing ACK is transmitted in the first data packet of TLS/HTTP proto
|
||||||
|
for ff in $fake 0x00000000; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }$PAYLOAD "--lua-desync=fake:blob=${ff}:ip${IPVV}_ttl=$ttl:repeats=$FAKE_REPEATS" --lua-desync=$splitf:pos=$split $f && {
|
||||||
|
ok=1
|
||||||
|
[ "$SCANLEVEL" = force ] || break
|
||||||
|
}
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ] && break
|
||||||
|
done
|
||||||
|
for fooling in $FOOLINGS_TCP; do
|
||||||
|
for split in $splits; do
|
||||||
|
for ff in $fake 0x00000000; do
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split && ok=1
|
||||||
|
# duplicate SYN with MD5
|
||||||
|
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=fake_http:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split --payload empty "--out-range=<s1" --lua-desync=send:tcp_md5 && ok=1
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
for ttl in $attls; do
|
||||||
|
for split in $splits; do
|
||||||
|
for ff in $fake 0x00000000; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:ip${IPVV}_autottl=-$ttl,3-20:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $f && {
|
||||||
|
ok=1
|
||||||
|
[ "$SCANLEVEL" = force ] || break
|
||||||
|
}
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_fake_https_vary_()
|
||||||
|
{
|
||||||
|
local ok_any=0 testf=$1 domain="$2" fooling="$3" pre="$4" post="$5"
|
||||||
|
shift; shift; shift
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=multisplit:blob=$fake:$fooling:pos=2:nodrop:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid,padencap:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
|
||||||
|
[ "$ok_any" = 1 ] && ok=1
|
||||||
|
}
|
||||||
|
pktws_fake_https_vary()
|
||||||
|
{
|
||||||
|
local ok_any=0 fooling="$3"
|
||||||
|
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "$5" && ok_any=1
|
||||||
|
# duplicate SYN with MD5
|
||||||
|
contains "$fooling" tcp_md5 && \
|
||||||
|
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5" && ok_any=1
|
||||||
|
[ "$ok_any" = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - PRE args for nfqws2
|
||||||
|
|
||||||
|
[ "$NOTEST_FAKE_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
|
||||||
|
|
||||||
|
local testf=$1 domain="$2" pre="$3"
|
||||||
|
local ok ok_any ttls attls f fake fooling splitf splitfs= split splits='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
|
||||||
|
local PAYLOAD="--payload=tls_client_hello"
|
||||||
|
|
||||||
|
shift; shift
|
||||||
|
|
||||||
|
if [ -n "$FAKE_HTTPS" ]; then
|
||||||
|
fake=fake_tls
|
||||||
|
else
|
||||||
|
fake=fake_default_tls
|
||||||
|
fi
|
||||||
|
|
||||||
|
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
|
||||||
|
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
|
||||||
|
|
||||||
|
# do not test fake + multisplit if multisplit works
|
||||||
|
[ "$need_multisplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=multisplit
|
||||||
|
# do not test fake + multidisorder if multidisorder works
|
||||||
|
[ "$need_multidisorder" = 0 -a "$SCANLEVEL" != force ] || splitfs="${splitfs:+$splitfs }multidisorder"
|
||||||
|
|
||||||
|
ok_any=0
|
||||||
|
for splitf in $splitfs; do
|
||||||
|
ok=0
|
||||||
|
for ttl in $ttls; do
|
||||||
|
for split in $splits; do
|
||||||
|
# orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server.
|
||||||
|
# missing ACK is transmitted in the first data packet of TLS/HTTP proto
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_fake_https_vary $testf $domain "ip${IPVV}_ttl=$ttl" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ] && break
|
||||||
|
done
|
||||||
|
for fooling in $FOOLINGS_TCP; do
|
||||||
|
for split in $splits; do
|
||||||
|
pktws_fake_https_vary $testf $domain "$fooling" "$pre"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
for ttl in $attls; do
|
||||||
|
for split in $splits; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_fake_https_vary $testf $domain "ip${IPVV}_autottl=-$ttl,3-20" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ] && ok_any=1
|
||||||
|
done
|
||||||
|
[ "$ok_any" = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls12()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
|
||||||
|
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls13()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2"
|
||||||
|
}
|
||||||
161
blockcheck/zapret2/blockcheck2.d/standard/55-fake-faked.sh
Normal file
161
blockcheck/zapret2/blockcheck2.d/standard/55-fake-faked.sh
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
. "$TESTDIR/def.inc"
|
||||||
|
|
||||||
|
pktws_check_http()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
[ "$NOTEST_FAKE_FAKED_HTTP" = 1 ] && { echo "SKIPPED"; return 0; }
|
||||||
|
|
||||||
|
local testf=$1 domain="$2"
|
||||||
|
local ok ttls attls f ff fake fooling splitf splitfs= split splits='method+2 midsld method+2,midsld'
|
||||||
|
local PAYLOAD="--payload=http_req"
|
||||||
|
|
||||||
|
if [ -n "$FAKE_HTTP" ]; then
|
||||||
|
fake=fake_http
|
||||||
|
else
|
||||||
|
fake=fake_default_http
|
||||||
|
fi
|
||||||
|
|
||||||
|
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
|
||||||
|
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
|
||||||
|
|
||||||
|
# do not test fake + multisplit if multisplit works
|
||||||
|
[ "$need_fakedsplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=fakedsplit
|
||||||
|
# do not test fake + fakeddisorder if fakeddisorder works
|
||||||
|
[ "$need_fakeddisorder" = 0 -a "$SCANLEVEL" != force ] || splitfs="${splitfs:+$splitfs }fakeddisorder"
|
||||||
|
|
||||||
|
for splitf in $splitfs; do
|
||||||
|
ok=0
|
||||||
|
for ttl in $ttls; do
|
||||||
|
for split in $splits; do
|
||||||
|
# orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server.
|
||||||
|
# missing ACK is transmitted in the first data packet of TLS/HTTP proto
|
||||||
|
for ff in $fake 0x00000000; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }${FAKED_PATTERN_HTTP:+--blob=faked_pat:@"$FAKED_PATTERN_HTTP" }$PAYLOAD "--lua-desync=fake:blob=${ff}:ip${IPVV}_ttl=$ttl:repeats=$FAKE_REPEATS" --lua-desync=$splitf:${FAKED_PATTERN_HTTP:+pattern=faked_pat:}pos=$split:ip${IPVV}_ttl=$ttl:repeats=$FAKE_REPEATS $f && {
|
||||||
|
ok=1
|
||||||
|
[ "$SCANLEVEL" = force ] || break
|
||||||
|
}
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ] && break
|
||||||
|
done
|
||||||
|
for fooling in $FOOLINGS_TCP; do
|
||||||
|
for split in $splits; do
|
||||||
|
for ff in $fake 0x00000000; do
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }${FAKED_PATTERN_HTTP:+--blob=faked_pat:@"$FAKED_PATTERN_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTP:+pattern=faked_pat:}pos=$split:$fooling:repeats=$FAKE_REPEATS && ok=1
|
||||||
|
# duplicate SYN with MD5
|
||||||
|
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }${FAKED_PATTERN_HTTP:+--blob=faked_pat:@"$FAKED_PATTERN_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTP:+pattern=faked_pat:}pos=$split:$fooling:repeats=$FAKE_REPEATS --payload empty "--out-range=<s1" --lua-desync=send:tcp_md5 && ok=1
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
for ttl in $attls; do
|
||||||
|
for split in $splits; do
|
||||||
|
for ff in $fake 0x00000000; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }${FAKED_PATTERN_HTTP:+--blob=faked_pat:@"$FAKED_PATTERN_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:ip${IPVV}_autottl=-$ttl,3-20:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTP:+pattern=faked_pat:}pos=$split:ip${IPVV}_autottl=-$ttl,3-20:repeats=$FAKE_REPEATS $f && {
|
||||||
|
ok=1
|
||||||
|
[ "$SCANLEVEL" = force ] || break
|
||||||
|
}
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_fake_https_vary_()
|
||||||
|
{
|
||||||
|
local ok_any=0 testf=$1 domain="$2" fooling="$3" pre="$4" post="$5"
|
||||||
|
shift; shift; shift
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=multisplit:blob=$fake:$fooling:pos=2:nodrop:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
|
||||||
|
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid,padencap:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
|
||||||
|
[ "$ok_any" = 1 ] && ok=1
|
||||||
|
|
||||||
|
}
|
||||||
|
pktws_fake_https_vary()
|
||||||
|
{
|
||||||
|
local ok_any=0 fooling="$3"
|
||||||
|
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "$5" && ok_any=1
|
||||||
|
# duplicate SYN with MD5
|
||||||
|
contains "$fooling" tcp_md5 && \
|
||||||
|
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5" && ok_any=1
|
||||||
|
[ "$ok_any" = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - PRE args for nfqws2
|
||||||
|
|
||||||
|
[ "$NOTEST_FAKE_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
|
||||||
|
|
||||||
|
local testf=$1 domain="$2" pre="$3"
|
||||||
|
local ok ok_any ttls attls f fake fooling splitf splitfs= split splits='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
|
||||||
|
local PAYLOAD="--payload=tls_client_hello"
|
||||||
|
|
||||||
|
shift; shift
|
||||||
|
|
||||||
|
if [ -n "$FAKE_HTTPS" ]; then
|
||||||
|
fake=fake_tls
|
||||||
|
else
|
||||||
|
fake=fake_default_tls
|
||||||
|
fi
|
||||||
|
|
||||||
|
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
|
||||||
|
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
|
||||||
|
|
||||||
|
# do not test fake + fakedsplit if fakedsplit works
|
||||||
|
[ "$need_fakedsplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=fakedsplit
|
||||||
|
# do not test fake + fakeddisorder if fakeddisorder works
|
||||||
|
[ "$need_fakeddisorder" = 0 -a "$SCANLEVEL" != force ] || splitfs="${splitfs:+$splitfs }fakeddisorder"
|
||||||
|
|
||||||
|
ok_any=0
|
||||||
|
for splitf in $splitfs; do
|
||||||
|
ok=0
|
||||||
|
for ttl in $ttls; do
|
||||||
|
for split in $splits; do
|
||||||
|
# orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server.
|
||||||
|
# missing ACK is transmitted in the first data packet of TLS/HTTP proto
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_fake_https_vary $testf $domain "ip${IPVV}_ttl=$ttl" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ] && break
|
||||||
|
done
|
||||||
|
for fooling in $FOOLINGS_TCP; do
|
||||||
|
for split in $splits; do
|
||||||
|
pktws_fake_https_vary $testf $domain "$fooling" "$pre"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
for ttl in $attls; do
|
||||||
|
for split in $splits; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_fake_https_vary $testf $domain "ip${IPVV}_autottl=-$ttl,3-20" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ] && ok_any=1
|
||||||
|
done
|
||||||
|
[ "$ok_any" = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls12()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
|
||||||
|
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls13()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2"
|
||||||
|
}
|
||||||
113
blockcheck/zapret2/blockcheck2.d/standard/60-fake-hostfake.sh
Normal file
113
blockcheck/zapret2/blockcheck2.d/standard/60-fake-hostfake.sh
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
. "$TESTDIR/def.inc"
|
||||||
|
|
||||||
|
pktws_hostfake_vary_()
|
||||||
|
{
|
||||||
|
local testf=$1 domain="$2" fooling="$3" pre="$4" post="$5" disorder
|
||||||
|
shift; shift; shift
|
||||||
|
|
||||||
|
for disorder in '' 'disorder_after:'; do
|
||||||
|
pktws_curl_test_update $testf $domain $pre ${FAKE:+--blob=$fake:@"$FAKE" }$PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}$fooling:repeats=$FAKE_REPEATS $post && ok=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre ${FAKE:+--blob=$fake:@"$FAKE" }$PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake1:$fooling:repeats=$FAKE_REPEATS $post && ok=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre ${FAKE:+--blob=$fake:@"$FAKE" }$PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake2:$fooling:repeats=$FAKE_REPEATS $post && ok=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre ${FAKE:+--blob=$fake:@"$FAKE" }$PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}midhost=midsld:$fooling:repeats=$FAKE_REPEATS $post && ok=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre ${FAKE:+--blob=$fake:@"$FAKE" }$PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake1:midhost=midsld:$fooling:repeats=$FAKE_REPEATS $post && ok=1
|
||||||
|
pktws_curl_test_update $testf $domain $pre ${FAKE:+--blob=$fake:@"$FAKE" }$PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake2:midhost=midsld:$fooling:repeats=$FAKE_REPEATS $post && ok=1
|
||||||
|
done
|
||||||
|
}
|
||||||
|
pktws_hostfake_vary()
|
||||||
|
{
|
||||||
|
local fooling="$3"
|
||||||
|
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "$5"
|
||||||
|
# duplicate SYN with MD5
|
||||||
|
contains "$fooling" tcp_md5 && \
|
||||||
|
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5"
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_hostfake()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - PRE args for nfqws2
|
||||||
|
local testf=$1 domain="$2" pre="$3"
|
||||||
|
local ok ttls attls f fake fooling
|
||||||
|
|
||||||
|
[ "$need_hostfakesplit" = 0 ] && return 0
|
||||||
|
|
||||||
|
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
|
||||||
|
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
|
||||||
|
|
||||||
|
ok=0
|
||||||
|
for ttl in $ttls; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_hostfake_vary $testf $domain "ip${IPVV}_ttl=$ttl" "$pre" "$f" && {
|
||||||
|
ok=1
|
||||||
|
[ "$SCANLEVEL" = force ] || break
|
||||||
|
}
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ] && break
|
||||||
|
done
|
||||||
|
for fooling in $FOOLINGS_TCP; do
|
||||||
|
pktws_hostfake_vary $testf $domain "$fooling" "$pre" && ok=1
|
||||||
|
done
|
||||||
|
for ttl in $attls; do
|
||||||
|
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||||
|
pktws_hostfake_vary $testf $domain "ip${IPVV}_autottl=-$ttl,3-20" "$pre" "$f" && {
|
||||||
|
ok=1
|
||||||
|
[ "$SCANLEVEL" = force ] || break
|
||||||
|
}
|
||||||
|
done
|
||||||
|
done
|
||||||
|
[ "$ok" = 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pktws_check_http()
|
||||||
|
{
|
||||||
|
[ "$NOTEST_FAKE_HOSTFAKE_HTTP" = 1 ] && { echo "SKIPPED"; return 0; }
|
||||||
|
|
||||||
|
local PAYLOAD="--payload=http_req"
|
||||||
|
local FAKE="$FAKE_HTTP"
|
||||||
|
|
||||||
|
if [ -n "$FAKE_HTTP" ]; then
|
||||||
|
fake=bfake
|
||||||
|
else
|
||||||
|
fake=fake_default_http
|
||||||
|
fi
|
||||||
|
|
||||||
|
pktws_check_hostfake "$1" "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
# $3 - PRE args for nfqws2
|
||||||
|
|
||||||
|
[ "$NOTEST_FAKE_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
|
||||||
|
|
||||||
|
local PAYLOAD="--payload=tls_client_hello"
|
||||||
|
local FAKE="$FAKE_HTTPS"
|
||||||
|
|
||||||
|
if [ -n "$FAKE_HTTPS" ]; then
|
||||||
|
fake=bfake
|
||||||
|
else
|
||||||
|
fake=fake_default_tls
|
||||||
|
fi
|
||||||
|
|
||||||
|
pktws_check_hostfake "$1" "$2" "$3"
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls12()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
|
||||||
|
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
|
||||||
|
}
|
||||||
|
|
||||||
|
pktws_check_https_tls13()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
pktws_check_https_tls "$1" "$2"
|
||||||
|
}
|
||||||
28
blockcheck/zapret2/blockcheck2.d/standard/90-quic.sh
Normal file
28
blockcheck/zapret2/blockcheck2.d/standard/90-quic.sh
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
pktws_check_http3()
|
||||||
|
{
|
||||||
|
# $1 - test function
|
||||||
|
# $2 - domain
|
||||||
|
|
||||||
|
[ "$NOTEST_QUIC" = 1 ] && { echo "SKIPPED"; return; }
|
||||||
|
|
||||||
|
local repeats fake pos
|
||||||
|
local PAYLOAD="--payload quic_initial"
|
||||||
|
|
||||||
|
if [ -n "$FAKE_QUIC" ]; then
|
||||||
|
fake=fake_quic
|
||||||
|
else
|
||||||
|
fake=fake_default_quic
|
||||||
|
fi
|
||||||
|
|
||||||
|
for repeats in 1 2 5 10 20; do
|
||||||
|
pktws_curl_test_update $1 $2 ${FAKE_QUIC:+--blob=$fake:@"$FAKE_QUIC" }$PAYLOAD --lua-desync=fake:blob=$fake:repeats=$repeats && [ "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
|
||||||
|
for pos in 8 16 32 64; do
|
||||||
|
pktws_curl_test_update $1 $2 $PAYLOAD --lua-desync=send:ipfrag:ipfrag_pos_udp=$pos --lua-desync=drop && [ "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
|
||||||
|
for pos in 8 16 32 64; do
|
||||||
|
pktws_curl_test_update $1 $2 ${FAKE_QUIC:+--blob=$fake:@"$FAKE_QUIC" }$PAYLOAD --lua-desync=fake:blob=$fake:repeats=$FAKE_REPEATS --lua-desync=send:ipfrag:ipfrag_pos_udp=$pos --lua-desync=drop && [ "$SCANLEVEL" != force ] && break
|
||||||
|
done
|
||||||
|
}
|
||||||
7
blockcheck/zapret2/blockcheck2.d/standard/def.inc
Normal file
7
blockcheck/zapret2/blockcheck2.d/standard/def.inc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
FOOLINGS46_TCP=${FOOLINGS46_TCP:-"tcp_md5 badsum tcp_seq=-3000 tcp_seq=1000000 tcp_ack=-66000:tcp_ts_up tcp_ts=-1000 tcp_flags_unset=ACK tcp_flags_set=SYN"}
|
||||||
|
FOOLINGS6_TCP=${FOOLINGS6_TCP:-"ip6_hopbyhop ip6_hopbyhop:ip6_hopbyhop2 ip6_destopt ip6_routing ip6_ah"}
|
||||||
|
FOOLINGS_TCP="$FOOLINGS46_TCP"
|
||||||
|
[ "$IPV" = 6 ] && FOOLINGS_TCP="$FOOLINGS_TCP $FOOLINGS6_TCP"
|
||||||
|
FOOLINGS_UDP="badsum"
|
||||||
|
|
||||||
|
FAKE_REPEATS=${FAKE_REPEATS:-1}
|
||||||
1913
blockcheck/zapret2/blockcheck2.sh
Normal file
1913
blockcheck/zapret2/blockcheck2.sh
Normal file
File diff suppressed because it is too large
Load Diff
8
blockcheck/zapret2/blog.sh
Normal file
8
blockcheck/zapret2/blog.sh
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
EXEDIR="$(dirname "$0")"
|
||||||
|
EXEDIR="$(cd "$EXEDIR"; pwd)"
|
||||||
|
|
||||||
|
"$EXEDIR/blockcheck2.sh" 2>&1 | tee "$EXEDIR/../blockcheck2.log"
|
||||||
|
# windows 7 notepad does not view unix EOL correctly
|
||||||
|
unix2dos "$EXEDIR/../blockcheck2.log"
|
||||||
6
blockcheck/zapret2/blog_kyber.sh
Normal file
6
blockcheck/zapret2/blog_kyber.sh
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
EXEDIR="$(dirname "$0")"
|
||||||
|
EXEDIR="$(cd "$EXEDIR"; pwd)"
|
||||||
|
|
||||||
|
CURL=curl-kyber exec "$EXEDIR/blog.sh"
|
||||||
459
blockcheck/zapret2/common/base.sh
Normal file
459
blockcheck/zapret2/common/base.sh
Normal file
@@ -0,0 +1,459 @@
|
|||||||
|
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=:
|
||||||
|
[ "$1" != "${1#/}" ] && [ -x "$1" ] && {
|
||||||
|
echo "$1"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
extract_arg()
|
||||||
|
{
|
||||||
|
# $1 - arg number
|
||||||
|
# $2,$3,... - args
|
||||||
|
local n=$1
|
||||||
|
while [ -n "$1" ]; do
|
||||||
|
shift
|
||||||
|
[ $n -eq 1 ] && { echo "$1"; return 0; }
|
||||||
|
n=$(($n-1))
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
find_str_in_list()
|
||||||
|
{
|
||||||
|
# $1 - string
|
||||||
|
# $2 - space separated values
|
||||||
|
local v
|
||||||
|
[ -n "$1" ] && {
|
||||||
|
for v in $2; do
|
||||||
|
[ "$v" = "$1" ] && return 0
|
||||||
|
done
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
end_with_newline()
|
||||||
|
{
|
||||||
|
local c="$(tail -c 1)"
|
||||||
|
[ "$c" = "" ]
|
||||||
|
}
|
||||||
|
trim()
|
||||||
|
{
|
||||||
|
awk '{gsub(/^ +| +$/,"")}1'
|
||||||
|
}
|
||||||
|
split_by_separator()
|
||||||
|
{
|
||||||
|
# $1 - string
|
||||||
|
# $2 - separator
|
||||||
|
# $3 - var name to get "before" part
|
||||||
|
# $4 - var name to get "after" part
|
||||||
|
local before="${1%%$2*}"
|
||||||
|
local after="${1#*$2}"
|
||||||
|
[ "$after" = "$1" ] && after=
|
||||||
|
[ -n "$3" ] && eval $3="\$before"
|
||||||
|
[ -n "$4" ] && eval $4="\$after"
|
||||||
|
}
|
||||||
|
tolower()
|
||||||
|
{
|
||||||
|
echo "$@" | tr 'A-Z' 'a-z'
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_is_not_empty()
|
||||||
|
{
|
||||||
|
# $1 - directory
|
||||||
|
local n
|
||||||
|
[ -d "$1" ] || return 1
|
||||||
|
n=$(ls "$1" | wc -c | xargs)
|
||||||
|
[ "$n" != 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
LC_ALL=C 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"
|
||||||
|
}
|
||||||
|
|
||||||
|
replace_str()
|
||||||
|
{
|
||||||
|
local a=$(echo "$1" | sed 's/\//\\\//g')
|
||||||
|
local b=$(echo "$2" | sed 's/\//\\\//g')
|
||||||
|
shift; shift
|
||||||
|
echo "$@" | sed "s/$a/$b/g"
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_md5()
|
||||||
|
{
|
||||||
|
[ -n "$MD5" ] && return
|
||||||
|
MD5=md5sum
|
||||||
|
exists $MD5 || MD5=md5
|
||||||
|
}
|
||||||
|
|
||||||
|
md5f()
|
||||||
|
{
|
||||||
|
setup_md5
|
||||||
|
$MD5 | cut -d ' ' -f1
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_random()
|
||||||
|
{
|
||||||
|
[ -n "$RCUT" ] && return
|
||||||
|
RCUT="cut -c 1-17"
|
||||||
|
# some shells can operate with 32 bit signed int
|
||||||
|
[ $((0x100000000)) = 0 ] && RCUT="cut -c 1-9"
|
||||||
|
}
|
||||||
|
|
||||||
|
random()
|
||||||
|
{
|
||||||
|
# $1 - min, $2 - max
|
||||||
|
local r rs
|
||||||
|
setup_random
|
||||||
|
if [ -c /dev/urandom ]; then
|
||||||
|
read rs </dev/urandom
|
||||||
|
else
|
||||||
|
rs="$RANDOM$RANDOM$(date)"
|
||||||
|
fi
|
||||||
|
# shells use signed int64
|
||||||
|
r=1$(echo $rs | md5f | sed 's/[^0-9]//g' | $RCUT)
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
alloc_num()
|
||||||
|
{
|
||||||
|
# $1 - source var name
|
||||||
|
# $2 - target var name
|
||||||
|
# $3 - min
|
||||||
|
# $4 - max
|
||||||
|
|
||||||
|
local v
|
||||||
|
eval v="\$$2"
|
||||||
|
# do not replace existing value
|
||||||
|
[ -n "$v" ] && return
|
||||||
|
eval v="\$$1"
|
||||||
|
[ -n "$v" ] || v=$3
|
||||||
|
eval $2="$v"
|
||||||
|
v=$((v + 1))
|
||||||
|
[ $v -gt $4 ] && v=$3
|
||||||
|
eval $1="$v"
|
||||||
|
}
|
||||||
|
|
||||||
|
std_ports()
|
||||||
|
{
|
||||||
|
NFQWS2_PORTS_TCP_IPT=$(replace_char - : $NFQWS2_PORTS_TCP)
|
||||||
|
NFQWS2_PORTS_TCP_KEEPALIVE_IPT=$(replace_char - : $NFQWS2_PORTS_TCP_KEEPALIVE)
|
||||||
|
NFQWS2_PORTS_UDP_IPT=$(replace_char - : $NFQWS2_PORTS_UDP)
|
||||||
|
NFQWS2_PORTS_UDP_KEEPALIVE_IPT=$(replace_char - : $NFQWS2_PORTS_UDP_KEEPALIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
has_bad_ws_options()
|
||||||
|
{
|
||||||
|
# $1 - nfqws2 opts
|
||||||
|
|
||||||
|
contains "$1" "--ipset" && {
|
||||||
|
echo
|
||||||
|
echo "WARNING !!! --ipset parameter is present"
|
||||||
|
echo "It's OK if you only specialize already redirected traffic and also process the rest."
|
||||||
|
echo "If you redirect port X to process several IPs from the list and do nothing with the rest - IT'S VERY INEFFECTIVE !"
|
||||||
|
echo "Kernel ipsets should be used instead. Write custom scripts and filter IPs in kernel."
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
check_bad_ws_options()
|
||||||
|
{
|
||||||
|
# $1 - 0 = stop, 1 = start
|
||||||
|
# $2 - nfqws options
|
||||||
|
if [ "$1" = 1 ] && has_bad_ws_options "$2"; then
|
||||||
|
echo "!!! REFUSING TO USE BAD OPTIONS : $2"
|
||||||
|
help_bad_ws_options
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
help_bad_ws_options()
|
||||||
|
{
|
||||||
|
echo "WARNING ! BAD options detected"
|
||||||
|
}
|
||||||
58
blockcheck/zapret2/common/dialog.sh
Normal file
58
blockcheck/zapret2/common/dialog.sh
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
read_yes_no()
|
||||||
|
{
|
||||||
|
# $1 - default (Y/N)
|
||||||
|
local A
|
||||||
|
read A
|
||||||
|
[ -z "$A" ] || ([ "$A" != "Y" ] && [ "$A" != "y" ] && [ "$A" != "N" ] && [ "$A" != "n" ]) && A=$1
|
||||||
|
[ "$A" = "Y" ] || [ "$A" = "y" ] || [ "$A" = "1" ]
|
||||||
|
}
|
||||||
|
ask_yes_no()
|
||||||
|
{
|
||||||
|
# $1 - default (Y/N or 0/1)
|
||||||
|
# $2 - text
|
||||||
|
local DEFAULT=$1
|
||||||
|
[ "$1" = "1" ] && DEFAULT=Y
|
||||||
|
[ "$1" = "0" ] && DEFAULT=N
|
||||||
|
[ -z "$DEFAULT" ] && DEFAULT=N
|
||||||
|
printf "$2 (default : $DEFAULT) (Y/N) ? "
|
||||||
|
read_yes_no $DEFAULT
|
||||||
|
}
|
||||||
|
ask_yes_no_var()
|
||||||
|
{
|
||||||
|
# $1 - variable name for answer : 0/1
|
||||||
|
# $2 - text
|
||||||
|
local DEFAULT
|
||||||
|
eval DEFAULT="\$$1"
|
||||||
|
if ask_yes_no "$DEFAULT" "$2"; then
|
||||||
|
eval $1=1
|
||||||
|
else
|
||||||
|
eval $1=0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
ask_list()
|
||||||
|
{
|
||||||
|
# $1 - mode var
|
||||||
|
# $2 - space separated value list
|
||||||
|
# $3 - (optional) default value
|
||||||
|
local M_DEFAULT
|
||||||
|
eval M_DEFAULT="\$$1"
|
||||||
|
local M_ALL=$M_DEFAULT
|
||||||
|
local M=""
|
||||||
|
local m
|
||||||
|
|
||||||
|
[ -n "$3" ] && { find_str_in_list "$M_DEFAULT" "$2" || M_DEFAULT="$3" ;}
|
||||||
|
|
||||||
|
n=1
|
||||||
|
for m in $2; do
|
||||||
|
echo $n : $m
|
||||||
|
n=$(($n+1))
|
||||||
|
done
|
||||||
|
printf "your choice (default : $M_DEFAULT) : "
|
||||||
|
read m
|
||||||
|
[ -n "$m" ] && M=$(echo $2 | cut -d ' ' -f$m 2>/dev/null)
|
||||||
|
[ -z "$M" ] && M="$M_DEFAULT"
|
||||||
|
echo selected : $M
|
||||||
|
eval $1="\"$M\""
|
||||||
|
|
||||||
|
[ "$M" != "$M_OLD" ]
|
||||||
|
}
|
||||||
28
blockcheck/zapret2/common/elevate.sh
Normal file
28
blockcheck/zapret2/common/elevate.sh
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
require_root()
|
||||||
|
{
|
||||||
|
local exe preserve_env
|
||||||
|
echo \* checking privileges
|
||||||
|
[ $(id -u) -ne "0" ] && {
|
||||||
|
echo root is required
|
||||||
|
exe="$EXEDIR/$(basename "$0")"
|
||||||
|
exists sudo && {
|
||||||
|
echo elevating with sudo
|
||||||
|
exec sudo -E sh "$exe"
|
||||||
|
}
|
||||||
|
exists su && {
|
||||||
|
echo elevating with su
|
||||||
|
case "$UNAME" in
|
||||||
|
Linux)
|
||||||
|
preserve_env="--preserve-environment"
|
||||||
|
;;
|
||||||
|
FreeBSD|OpenBSD|Darwin)
|
||||||
|
preserve_env="-m"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
exec su $preserve_env root -c "sh \"$exe\""
|
||||||
|
}
|
||||||
|
echo su or sudo not found
|
||||||
|
exitp 2
|
||||||
|
}
|
||||||
|
HAVE_ROOT=1
|
||||||
|
}
|
||||||
64
blockcheck/zapret2/common/fwtype.sh
Normal file
64
blockcheck/zapret2/common/fwtype.sh
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
linux_ipt_avail()
|
||||||
|
{
|
||||||
|
exists iptables && exists ip6tables
|
||||||
|
}
|
||||||
|
linux_maybe_iptables_fwtype()
|
||||||
|
{
|
||||||
|
linux_ipt_avail && FWTYPE=iptables
|
||||||
|
}
|
||||||
|
linux_nft_avail()
|
||||||
|
{
|
||||||
|
exists nft
|
||||||
|
}
|
||||||
|
linux_fwtype()
|
||||||
|
{
|
||||||
|
[ -n "$FWTYPE" ] && return
|
||||||
|
|
||||||
|
FWTYPE=unsupported
|
||||||
|
|
||||||
|
linux_get_subsys
|
||||||
|
if [ "$SUBSYS" = openwrt ] ; then
|
||||||
|
# linux kernel is new enough if fw4 is there
|
||||||
|
if [ -x /sbin/fw4 ] && linux_nft_avail ; then
|
||||||
|
FWTYPE=nftables
|
||||||
|
else
|
||||||
|
linux_maybe_iptables_fwtype
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
SUBSYS=
|
||||||
|
# generic linux
|
||||||
|
# flowtable is implemented since kernel 4.16
|
||||||
|
if linux_nft_avail && linux_min_version 4 16; then
|
||||||
|
FWTYPE=nftables
|
||||||
|
else
|
||||||
|
linux_maybe_iptables_fwtype
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
export FWTYPE
|
||||||
|
}
|
||||||
|
|
||||||
|
get_fwtype()
|
||||||
|
{
|
||||||
|
[ -n "$FWTYPE" ] && return
|
||||||
|
|
||||||
|
local UNAME="$(uname)"
|
||||||
|
|
||||||
|
case "$UNAME" in
|
||||||
|
Linux)
|
||||||
|
linux_fwtype
|
||||||
|
;;
|
||||||
|
FreeBSD)
|
||||||
|
if exists ipfw ; then
|
||||||
|
FWTYPE=ipfw
|
||||||
|
else
|
||||||
|
FWTYPE=unsupported
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
FWTYPE=unsupported
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
export FWTYPE
|
||||||
|
}
|
||||||
39
blockcheck/zapret2/common/virt.sh
Normal file
39
blockcheck/zapret2/common/virt.sh
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
get_virt()
|
||||||
|
{
|
||||||
|
local vm s v UNAME
|
||||||
|
UNAME=$(uname)
|
||||||
|
case "$UNAME" in
|
||||||
|
Linux)
|
||||||
|
if exists systemd-detect-virt; then
|
||||||
|
vm=$(systemd-detect-virt --vm)
|
||||||
|
elif [ -f /sys/class/dmi/id/product_name ]; then
|
||||||
|
read s </sys/class/dmi/id/product_name
|
||||||
|
for v in KVM QEMU VMware VMW VirtualBox Xen Bochs Parallels BHYVE Hyper-V; do
|
||||||
|
case "$s" in
|
||||||
|
"$v"*)
|
||||||
|
vm=$v
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "$vm" | awk '{print tolower($0)}'
|
||||||
|
}
|
||||||
|
check_virt()
|
||||||
|
{
|
||||||
|
echo \* checking virtualization
|
||||||
|
local vm="$(get_virt)"
|
||||||
|
if [ -n "$vm" ]; then
|
||||||
|
if [ "$vm" = "none" ]; then
|
||||||
|
echo running on bare metal
|
||||||
|
else
|
||||||
|
echo "!!! WARNING. $vm virtualization detected !!!"
|
||||||
|
echo '!!! WARNING. vmware and virtualbox are known to break most of the DPI bypass techniques when network is NATed using internal hypervisor NAT !!!'
|
||||||
|
echo '!!! WARNING. if this is your case make sure you are bridged not NATed !!!'
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo cannot detect
|
||||||
|
fi
|
||||||
|
}
|
||||||
BIN
blockcheck/zapret2/ip2net/ip2net.exe
Normal file
BIN
blockcheck/zapret2/ip2net/ip2net.exe
Normal file
Binary file not shown.
892
blockcheck/zapret2/lua/zapret-antidpi.lua
Normal file
892
blockcheck/zapret2/lua/zapret-antidpi.lua
Normal file
@@ -0,0 +1,892 @@
|
|||||||
|
--[[
|
||||||
|
|
||||||
|
NFQWS2 ANTIDPI LIBRARY
|
||||||
|
|
||||||
|
--lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua
|
||||||
|
--lua-desync=func1:arg1[=val1]:arg2[=val2] --lua-desync=func2:arg1[=val1]:arg2[=val2] .... --lua-desync=funcN:arg1[=val1]:arg2[=val2]
|
||||||
|
|
||||||
|
BLOBS
|
||||||
|
|
||||||
|
blobs can be 0xHEX, field name in desync or global var
|
||||||
|
standard way to bring binary data to lua code is using the "--blob" parameter of nfqws2
|
||||||
|
dynamic blobs can be inside desync table. one function can prepare data for next functions.
|
||||||
|
|
||||||
|
STANDARD FUNCTION ARGS
|
||||||
|
|
||||||
|
standard direction :
|
||||||
|
|
||||||
|
* dir = in|out|any
|
||||||
|
|
||||||
|
standard fooling :
|
||||||
|
|
||||||
|
* ip_ttl=N - set ipv.ip_ttl to N
|
||||||
|
* ip6_ttl=N - set ip6.ip6_hlim to N
|
||||||
|
* ip_autottl=delta,min-max - set ip.ip_ttl to auto discovered ttl
|
||||||
|
* ip6_autottl=delta,min-max - set ip.ip_ttl to auto discovered ttl
|
||||||
|
|
||||||
|
* ip6_hopbyhop[=hex] - add hopbyhop ipv6 header with optional data. data size must be 6+N*8. all zero by default.
|
||||||
|
* ip6_hopbyhop2[=hex] - add second hopbyhop ipv6 header with optional data. data size must be 6+N*8. all zero by default.
|
||||||
|
* ip6_destopt[=hex] - add destopt ipv6 header with optional data. data size must be 6+N*8. all zero by default.
|
||||||
|
* ip6_destopt2[=hex] - add second destopt ipv6 header with optional data. data size must be 6+N*8. all zero by default.
|
||||||
|
* ip6_routing[=hex] - add routing ipv6 header with optional data. data size must be 6+N*8. all zero by default.
|
||||||
|
* ip6_ah[=hex] - add authentication ipv6 header with optional data. data size must be 6+N*4. 0000 + 4 random bytes by default.
|
||||||
|
|
||||||
|
* tcp_seq=N - add N to tcp.th_seq
|
||||||
|
* tcp_ack=N - add N to tcp.th_ack
|
||||||
|
* tcp_ts=N - add N to timestamp value
|
||||||
|
* tcp_md5[=hex] - add MD5 header with optional 16-byte data. all zero by default.
|
||||||
|
* tcp_flags_set=<list> - set tcp flags in comma separated list
|
||||||
|
* tcp_flags_unset=<list> - unset tcp flags in comma separated list
|
||||||
|
* tcp_ts_up - move timestamp tcp option to the top if present (workaround for badack without badseq fooling)
|
||||||
|
|
||||||
|
* fool=fool_function - custom fooling function : fool_func(dis, fooling_options)
|
||||||
|
|
||||||
|
standard reconstruct :
|
||||||
|
|
||||||
|
* badsum - make L4 checksum invalid
|
||||||
|
|
||||||
|
standard rawsend :
|
||||||
|
|
||||||
|
* repeats - how many time send the packet
|
||||||
|
* ifout - override outbound interface (if --bind_fix4, --bind-fix6 enabled)
|
||||||
|
* fwmark - override fwmark. desync mark bit(s) will be set unconditionally
|
||||||
|
|
||||||
|
standard payload :
|
||||||
|
|
||||||
|
* payload - comma separarated list of allowed payload types. if not present - allow non-empty known payloads.
|
||||||
|
|
||||||
|
standard ip_id :
|
||||||
|
|
||||||
|
* ip_id - seq|rnd|zero|none
|
||||||
|
* ip_id_conn - in 'seq' mode save current ip_id in track.lua_state to use it between packets
|
||||||
|
|
||||||
|
standard ipfrag :
|
||||||
|
|
||||||
|
* ipfrag[=frag_function] - ipfrag function name. "ipfrag2" by default if empty
|
||||||
|
* ipfrag_disorder - send fragments from last to first
|
||||||
|
* ipfrag2 : ipfrag_pos_udp - udp frag position. ipv4 : starting from L4 header. ipb6: starting from fragmentable part. must be multiple of 8. default 8
|
||||||
|
* ipfrag2 : ipfrag_pos_tcp - tcp frag position. ipv4 : starting from L4 header. ipb6: starting from fragmentable part. must be multiple of 8. default 32
|
||||||
|
* ipfrag2 : ipfrag_next - next protocol field in ipv6 fragment extenstion header of the second fragment. same as first by default.
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
|
-- drop packet
|
||||||
|
-- standard args : direction, payload
|
||||||
|
function drop(ctx, desync)
|
||||||
|
direction_cutoff_opposite(ctx, desync, "any")
|
||||||
|
if direction_check(desync, "any") and payload_check(desync,"all") then
|
||||||
|
DLOG("drop")
|
||||||
|
return VERDICT_DROP
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--dup"
|
||||||
|
-- standard args : direction, fooling, ip_id, ipfrag, rawsend, reconstruct
|
||||||
|
function send(ctx, desync)
|
||||||
|
direction_cutoff_opposite(ctx, desync, "any")
|
||||||
|
if direction_check(desync, "any") then
|
||||||
|
DLOG("send")
|
||||||
|
local dis = deepcopy(desync.dis)
|
||||||
|
apply_fooling(desync, dis)
|
||||||
|
apply_ip_id(desync, dis, nil, "none")
|
||||||
|
-- it uses rawsend, reconstruct and ipfrag options
|
||||||
|
rawsend_dissect_ipfrag(dis, desync_opts(desync))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--orig"
|
||||||
|
-- apply modification to current packet
|
||||||
|
-- standard args : direction, fooling, ip_id
|
||||||
|
function pktmod(ctx, desync)
|
||||||
|
direction_cutoff_opposite(ctx, desync, "any")
|
||||||
|
if direction_check(desync, "any") then
|
||||||
|
-- apply to current packet
|
||||||
|
apply_fooling(desync)
|
||||||
|
apply_ip_id(desync, nil, nil, "none")
|
||||||
|
DLOG("pktmod: applied")
|
||||||
|
return VERDICT_MODIFY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--domcase"
|
||||||
|
-- standard args : direction
|
||||||
|
function http_domcase(ctx, desync)
|
||||||
|
if not desync.dis.tcp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
if desync.l7payload=="http_req" and direction_check(desync) then
|
||||||
|
local host_range = resolve_multi_pos(desync.dis.payload,desync.l7payload,"host,endhost")
|
||||||
|
if #host_range == 2 then
|
||||||
|
local host = string.sub(desync.dis.payload,host_range[1],host_range[2]-1)
|
||||||
|
local newhost="", i
|
||||||
|
for i = 1, #host do
|
||||||
|
newhost=newhost..((i%2)==0 and string.lower(string.sub(host,i,i)) or string.upper(string.sub(host,i,i)))
|
||||||
|
end
|
||||||
|
DLOG("http_domcase: "..host.." => "..newhost)
|
||||||
|
desync.dis.payload = string.sub(desync.dis.payload, 1, host_range[1]-1)..newhost..string.sub(desync.dis.payload, host_range[2])
|
||||||
|
return VERDICT_MODIFY
|
||||||
|
else
|
||||||
|
DLOG("http_domcase: cannot find host range")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--hostcase"
|
||||||
|
-- standard args : direction
|
||||||
|
-- arg : spell=<str> . spelling of the "Host" header. must be exactly 4 chars long
|
||||||
|
function http_hostcase(ctx, desync)
|
||||||
|
if not desync.dis.tcp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
if desync.l7payload=="http_req" and direction_check(desync) then
|
||||||
|
local spell = desync.arg.spell or "host"
|
||||||
|
if #spell ~= 4 then
|
||||||
|
error("http_hostcase: invalid host spelling '"..spell.."'")
|
||||||
|
else
|
||||||
|
local hdis = http_dissect_req(desync.dis.payload)
|
||||||
|
if hdis.headers.host then
|
||||||
|
DLOG("http_hostcase: 'Host:' => '"..spell.."'")
|
||||||
|
desync.dis.payload = string.sub(desync.dis.payload,1,hdis.headers.host.pos_start-1)..spell..string.sub(desync.dis.payload,hdis.headers.host.pos_header_end+1)
|
||||||
|
return VERDICT_MODIFY
|
||||||
|
else
|
||||||
|
DLOG("http_hostcase: 'Host:' header not found")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--methodeol"
|
||||||
|
-- standard args : direction
|
||||||
|
function http_methodeol(ctx, desync)
|
||||||
|
if not desync.dis.tcp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
if desync.l7payload=="http_req" and direction_check(desync) then
|
||||||
|
local hdis = http_dissect_req(desync.dis.payload)
|
||||||
|
local ua = hdis.headers["user-agent"]
|
||||||
|
if ua then
|
||||||
|
if (ua.pos_end - ua.pos_value_start) < 2 then
|
||||||
|
DLOG("http_methodeol: 'User-Agent:' header is too short")
|
||||||
|
else
|
||||||
|
DLOG("http_methodeol: applied")
|
||||||
|
desync.dis.payload="\r\n"..string.sub(desync.dis.payload,1,ua.pos_end-2)..(string.sub(desync.dis.payload,ua.pos_end+1) or "");
|
||||||
|
return VERDICT_MODIFY
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DLOG("http_methodeol: 'User-Agent:' header not found")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--synack-split"
|
||||||
|
-- standard args : rawsend, reconstruct, ipfrag
|
||||||
|
-- arg : mode=syn|synack|acksyn . "synack" by default
|
||||||
|
function synack_split(ctx, desync)
|
||||||
|
if desync.dis.tcp then
|
||||||
|
if bitand(desync.dis.tcp.th_flags, TH_SYN + TH_ACK) == (TH_SYN + TH_ACK) then
|
||||||
|
local mode = desync.arg.mode or "synack"
|
||||||
|
local options = desync_opts(desync)
|
||||||
|
if mode=="syn" then
|
||||||
|
local dis = deepcopy(desync.dis)
|
||||||
|
dis.tcp.th_flags = bitand(desync.dis.tcp.th_flags, bitnot(TH_ACK))
|
||||||
|
DLOG("synack_split: sending SYN")
|
||||||
|
if not rawsend_dissect_ipfrag(dis, options) then return VERDICT_PASS end
|
||||||
|
return VERDICT_DROP
|
||||||
|
elseif mode=="synack" then
|
||||||
|
local dis = deepcopy(desync.dis)
|
||||||
|
dis.tcp.th_flags = bitand(desync.dis.tcp.th_flags, bitnot(TH_ACK))
|
||||||
|
DLOG("synack_split: sending SYN")
|
||||||
|
if not rawsend_dissect_ipfrag(dis, options) then return VERDICT_PASS end
|
||||||
|
dis.tcp.th_flags = bitand(desync.dis.tcp.th_flags, bitnot(TH_SYN))
|
||||||
|
DLOG("synack_split: sending ACK")
|
||||||
|
if not rawsend_dissect_ipfrag(dis, options) then return VERDICT_PASS end
|
||||||
|
return VERDICT_DROP
|
||||||
|
elseif mode=="acksyn" then
|
||||||
|
local dis = deepcopy(desync.dis)
|
||||||
|
dis.tcp.th_flags = bitand(desync.dis.tcp.th_flags, bitnot(TH_SYN))
|
||||||
|
DLOG("synack_split: sending ACK")
|
||||||
|
if not rawsend_dissect_ipfrag(dis, options) then return VERDICT_PASS end
|
||||||
|
dis.tcp.th_flags = bitand(desync.dis.tcp.th_flags, bitnot(TH_ACK))
|
||||||
|
DLOG("synack_split: sending SYN")
|
||||||
|
if not rawsend_dissect_ipfrag(dis, options) then return VERDICT_PASS end
|
||||||
|
return VERDICT_DROP
|
||||||
|
else
|
||||||
|
error("synack_split: bad mode '"..mode.."'")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
instance_cutoff_shim(ctx, desync) -- mission complete
|
||||||
|
end
|
||||||
|
else
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--dpi-desync=synack"
|
||||||
|
-- standard args : rawsend, reconstruct, ipfrag
|
||||||
|
function synack(ctx, desync)
|
||||||
|
if desync.dis.tcp then
|
||||||
|
if bitand(desync.dis.tcp.th_flags, TH_SYN + TH_ACK)==TH_SYN then
|
||||||
|
local dis = deepcopy(desync.dis)
|
||||||
|
dis.tcp.th_flags = bitor(dis.tcp.th_flags, TH_ACK)
|
||||||
|
DLOG("synack: sending")
|
||||||
|
rawsend_dissect_ipfrag(dis, desync_opts(desync))
|
||||||
|
else
|
||||||
|
instance_cutoff_shim(ctx, desync) -- mission complete
|
||||||
|
end
|
||||||
|
else
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- nfqws1 : "--wsize"
|
||||||
|
-- arg : wsize=N . tcp window size
|
||||||
|
-- arg : scale=N . tcp option scale factor
|
||||||
|
function wsize(ctx, desync)
|
||||||
|
if desync.dis.tcp then
|
||||||
|
if bitand(desync.dis.tcp.th_flags, TH_SYN + TH_ACK) == (TH_SYN + TH_ACK) then
|
||||||
|
if wsize_rewrite(desync.dis, desync.arg) then
|
||||||
|
return VERDICT_MODIFY
|
||||||
|
end
|
||||||
|
else
|
||||||
|
instance_cutoff_shim(ctx, desync) -- mission complete
|
||||||
|
end
|
||||||
|
else
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--wssize"
|
||||||
|
-- standard args : direction
|
||||||
|
-- arg : wsize=N . tcp window size
|
||||||
|
-- arg : scale=N . tcp option scale factor
|
||||||
|
-- arg : forced_cutoff=<list> - comma separated list of payloads that trigger forced wssize cutoff. by default - any non-empty payload
|
||||||
|
function wssize(ctx, desync)
|
||||||
|
if not desync.dis.tcp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local verdict = VERDICT_PASS
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
if direction_check(desync) then
|
||||||
|
if wsize_rewrite(desync.dis, desync.arg) then
|
||||||
|
verdict = VERDICT_MODIFY
|
||||||
|
end
|
||||||
|
if #desync.dis.payload>0 and (not desync.arg.forced_cutoff or in_list(desync.arg.forced_cutoff, desync.l7payload)) then
|
||||||
|
DLOG("wssize: forced cutoff")
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return verdict
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--dpi-desync=syndata"
|
||||||
|
-- standard args : fooling, rawsend, reconstruct, ipfrag
|
||||||
|
-- arg : blob=<blob> - fake payload. must fit to single packet. no segmentation possible. default - 16 zero bytes.
|
||||||
|
-- arg : tls_mod=<list> - comma separated list of tls mods : rnd,rndsni,sni=<str>. sni=%var is supported
|
||||||
|
function syndata(ctx, desync)
|
||||||
|
if desync.dis.tcp then
|
||||||
|
if bitand(desync.dis.tcp.th_flags, TH_SYN + TH_ACK)==TH_SYN then
|
||||||
|
local dis = deepcopy(desync.dis)
|
||||||
|
dis.payload = blob(desync, desync.arg.blob, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
|
||||||
|
apply_fooling(desync, dis)
|
||||||
|
if desync.arg.tls_mod then
|
||||||
|
dis.payload = tls_mod_shim(desync, dis.payload, desync.arg.tls_mod, nil)
|
||||||
|
end
|
||||||
|
if b_debug then DLOG("syndata: "..hexdump_dlog(dis.payload)) end
|
||||||
|
if rawsend_dissect_ipfrag(dis, desync_opts(desync)) then
|
||||||
|
return VERDICT_DROP
|
||||||
|
end
|
||||||
|
else
|
||||||
|
instance_cutoff_shim(ctx, desync) -- mission complete
|
||||||
|
end
|
||||||
|
else
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--dpi-desync=rst"
|
||||||
|
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag
|
||||||
|
-- arg : rstack - send RST,ACK instead of RST
|
||||||
|
function rst(ctx, desync)
|
||||||
|
if not desync.dis.tcp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
if direction_check(desync, "any") and payload_check(desync) then
|
||||||
|
if replay_first(desync) then
|
||||||
|
local dis = deepcopy(desync.dis)
|
||||||
|
dis.payload = ""
|
||||||
|
dis.tcp.th_flags = TH_RST + (desync.arg.rstack and TH_ACK or 0)
|
||||||
|
apply_fooling(desync, dis)
|
||||||
|
apply_ip_id(desync, dis, nil, "none")
|
||||||
|
DLOG("rst")
|
||||||
|
-- it uses rawsend, reconstruct and ipfrag options
|
||||||
|
rawsend_dissect_ipfrag(dis, desync_opts(desync))
|
||||||
|
else
|
||||||
|
DLOG("rst: not acting on further replay pieces")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--dpi-desync=fake"
|
||||||
|
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag
|
||||||
|
-- arg : blob=<blob> - fake payload
|
||||||
|
-- arg : tls_mod=<list> - comma separated list of tls mods : rnd,rndsni,sni=<str>,dupsid,padencap . sni=%var is supported
|
||||||
|
function fake(ctx, desync)
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
-- by default process only outgoing known payloads
|
||||||
|
if direction_check(desync) and payload_check(desync) then
|
||||||
|
if replay_first(desync) then
|
||||||
|
if not desync.arg.blob then
|
||||||
|
error("fake: 'blob' arg required")
|
||||||
|
end
|
||||||
|
local fake_payload = blob(desync, desync.arg.blob)
|
||||||
|
if desync.reasm_data and desync.arg.tls_mod then
|
||||||
|
fake_payload = tls_mod_shim(desync, fake_payload, desync.arg.tls_mod, desync.reasm_data)
|
||||||
|
end
|
||||||
|
-- check debug to save CPU
|
||||||
|
if b_debug then DLOG("fake: "..hexdump_dlog(fake_payload)) end
|
||||||
|
rawsend_payload_segmented(desync,fake_payload)
|
||||||
|
else
|
||||||
|
DLOG("fake: not acting on further replay pieces")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--dpi-desync=multisplit"
|
||||||
|
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag
|
||||||
|
-- arg : pos=<posmarker list> . position marker list. for example : "1,host,midsld+1,-10"
|
||||||
|
-- arg : seqovl=N . decrease seq number of the first segment by N and fill N bytes with pattern (default - all zero)
|
||||||
|
-- arg : seqovl_pattern=<blob> . override pattern
|
||||||
|
-- arg : blob=<blob> - use this data instead of desync.dis.payload
|
||||||
|
-- arg : nodrop - do not drop current dissect
|
||||||
|
function multisplit(ctx, desync)
|
||||||
|
if not desync.dis.tcp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
-- by default process only outgoing known payloads
|
||||||
|
local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload
|
||||||
|
if #data>0 and direction_check(desync) and payload_check(desync) then
|
||||||
|
if replay_first(desync) then
|
||||||
|
local spos = desync.arg.pos or "2"
|
||||||
|
-- check debug to save CPU
|
||||||
|
if b_debug then DLOG("multisplit: split pos: "..spos) end
|
||||||
|
local pos = resolve_multi_pos(data, desync.l7payload, spos)
|
||||||
|
if b_debug then DLOG("multisplit: resolved split pos: "..table.concat(zero_based_pos(pos)," ")) end
|
||||||
|
delete_pos_1(pos) -- cannot split at the first byte
|
||||||
|
if #pos>0 then
|
||||||
|
for i=0,#pos do
|
||||||
|
local pos_start = pos[i] or 1
|
||||||
|
local pos_end = i<#pos and pos[i+1]-1 or #data
|
||||||
|
local part = string.sub(data,pos_start,pos_end)
|
||||||
|
local seqovl=0
|
||||||
|
if i==0 and desync.arg.seqovl and tonumber(desync.arg.seqovl)>0 then
|
||||||
|
seqovl = tonumber(desync.arg.seqovl)
|
||||||
|
local pat = desync.arg.seqovl_pattern and blob(desync,desync.arg.seqovl_pattern) or "\x00"
|
||||||
|
part = pattern(pat,1,seqovl)..part
|
||||||
|
end
|
||||||
|
if b_debug then DLOG("multisplit: sending part "..(i+1).." "..(pos_start-1).."-"..(pos_end-1).." len="..#part.." seqovl="..seqovl.." : "..hexdump_dlog(part)) end
|
||||||
|
if not rawsend_payload_segmented(desync,part,pos_start-1-seqovl) then
|
||||||
|
return VERDICT_PASS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
replay_drop_set(desync)
|
||||||
|
return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP
|
||||||
|
else
|
||||||
|
DLOG("multisplit: no valid split positions")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DLOG("multisplit: not acting on further replay pieces")
|
||||||
|
end
|
||||||
|
-- drop replayed packets if reasm was sent successfully in splitted form
|
||||||
|
if replay_drop(desync) then
|
||||||
|
return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--dpi-desync=multidisorder"
|
||||||
|
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag
|
||||||
|
-- arg : pos=<postmarker list> . position marker list. example : "1,host,midsld+1,-10"
|
||||||
|
-- arg : seqovl=N . decrease seq number of the second segment in the original order by N and fill N bytes with pattern (default - all zero). N must be less than the first split pos.
|
||||||
|
-- arg : seqovl_pattern=<blob> . override pattern
|
||||||
|
-- arg : blob=<blob> - use this data instead of reasm_data
|
||||||
|
-- arg : nodrop - do not drop current dissect
|
||||||
|
function multidisorder(ctx, desync)
|
||||||
|
if not desync.dis.tcp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
-- by default process only outgoing known payloads
|
||||||
|
local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload
|
||||||
|
if #data>0 and direction_check(desync) and payload_check(desync) then
|
||||||
|
if replay_first(desync) then
|
||||||
|
local spos = desync.arg.pos or "2"
|
||||||
|
-- check debug to save CPU
|
||||||
|
if b_debug then DLOG("multidisorder: split pos: "..spos) end
|
||||||
|
local pos = resolve_multi_pos(data, desync.l7payload, spos)
|
||||||
|
if b_debug then DLOG("multidisorder: resolved split pos: "..table.concat(zero_based_pos(pos)," ")) end
|
||||||
|
delete_pos_1(pos) -- cannot split at the first byte
|
||||||
|
if #pos>0 then
|
||||||
|
for i=#pos,0,-1 do
|
||||||
|
local pos_start = pos[i] or 1
|
||||||
|
local pos_end = i<#pos and pos[i+1]-1 or #data
|
||||||
|
local part = string.sub(data,pos_start,pos_end)
|
||||||
|
local seqovl=0
|
||||||
|
if i==1 and desync.arg.seqovl then
|
||||||
|
seqovl = resolve_pos(data, desync.l7payload, desync.arg.seqovl)
|
||||||
|
if not seqovl then
|
||||||
|
DLOG("multidisorder: seqovl cancelled because could not resolve marker '"..desync.arg.seqovl.."'")
|
||||||
|
seqovl = 0
|
||||||
|
else
|
||||||
|
seqovl = seqovl - 1
|
||||||
|
if seqovl>=(pos[1]-1) then
|
||||||
|
DLOG("multidisorder: seqovl cancelled because seqovl "..seqovl.." is not less than the first split pos "..(pos[1]-1))
|
||||||
|
seqovl = 0
|
||||||
|
else
|
||||||
|
local pat = desync.arg.seqovl_pattern and blob(desync,desync.arg.seqovl_pattern) or "\x00"
|
||||||
|
part = pattern(pat,1,seqovl)..part
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if b_debug then DLOG("multidisorder: sending part "..(i+1).." "..(pos_start-1).."-"..(pos_end-1).." len="..#part.." seqovl="..seqovl.." : "..hexdump_dlog(part)) end
|
||||||
|
if not rawsend_payload_segmented(desync,part,pos_start-1-seqovl) then
|
||||||
|
return VERDICT_PASS
|
||||||
|
end
|
||||||
|
end
|
||||||
|
replay_drop_set(desync)
|
||||||
|
return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP
|
||||||
|
else
|
||||||
|
DLOG("multidisorder: no valid split positions")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DLOG("multidisorder: not acting on further replay pieces")
|
||||||
|
end
|
||||||
|
-- drop replayed packets if reasm was sent successfully in splitted form
|
||||||
|
if replay_drop(desync) then
|
||||||
|
return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--dpi-desync=hostfakesplit"
|
||||||
|
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct. FOOLING AND REPEATS APPLIED ONLY TO FAKES.
|
||||||
|
-- arg : host=<str> - hostname template. generate hosts like "random.template". example : e8nzn.vk.com
|
||||||
|
-- arg : midhost=<posmarker> - additionally split segment containing host at specified posmarker. must be within host+1 .. endhost-1 or split won't happen. example : "midsld"
|
||||||
|
-- arg : nofake1, nofake2 - do not send individual fakes
|
||||||
|
-- arg : disorder_after=<posmarker> - send after_host part in 2 disordered segments. if posmarker is empty string use marker "-1"
|
||||||
|
-- arg : blob=<blob> - use this data instead of desync.dis.payload
|
||||||
|
-- arg : nodrop - do not drop current dissect
|
||||||
|
function hostfakesplit(ctx, desync)
|
||||||
|
if not desync.dis.tcp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
-- by default process only outgoing known payloads
|
||||||
|
local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload
|
||||||
|
if #data>0 and direction_check(desync) and payload_check(desync) then
|
||||||
|
if replay_first(desync) then
|
||||||
|
local pos = resolve_range(data, desync.l7payload, "host,endhost-1", true)
|
||||||
|
if pos then
|
||||||
|
if b_debug then DLOG("hostfakesplit: resolved host range: "..table.concat(zero_based_pos(pos)," ")) end
|
||||||
|
|
||||||
|
-- do not apply fooling to original parts except tcp_ts_up but apply ip_id
|
||||||
|
local part, fakehost
|
||||||
|
local opts_orig = {rawsend = rawsend_opts_base(desync), reconstruct = {}, ipfrag = {}, ipid = desync.arg, fooling = {tcp_ts_up = desync.arg.tcp_ts_up}}
|
||||||
|
local opts_fake = {rawsend = rawsend_opts(desync), reconstruct = reconstruct_opts(desync), ipfrag = {}, ipid = desync.arg, fooling = desync.arg}
|
||||||
|
|
||||||
|
part = string.sub(data,1,pos[1]-1)
|
||||||
|
if b_debug then DLOG("hostfakesplit: sending before_host part 0-"..(pos[1]-2).." len="..#part.." : "..hexdump_dlog(part)) end
|
||||||
|
if not rawsend_payload_segmented(desync,part,0, opts_orig) then return VERDICT_PASS end
|
||||||
|
|
||||||
|
fakehost = genhost(pos[2]-pos[1]+1, desync.arg.host)
|
||||||
|
|
||||||
|
if not desync.arg.nofake1 then
|
||||||
|
if b_debug then DLOG("hostfakesplit: sending fake host part (1) "..(pos[1]-1).."-"..(pos[2]-1).." len="..#fakehost.." : "..hexdump_dlog(fakehost)) end
|
||||||
|
if not rawsend_payload_segmented(desync,fakehost,pos[1]-1, opts_fake) then return VERDICT_PASS end
|
||||||
|
end
|
||||||
|
|
||||||
|
local midhost
|
||||||
|
if desync.arg.midhost then
|
||||||
|
midhost = resolve_pos(data,desync.l7payload,desync.arg.midhost)
|
||||||
|
if not midhost then
|
||||||
|
DLOG("hostfakesplit: cannot resolve midhost marker '"..desync.arg.midhost.."'")
|
||||||
|
end
|
||||||
|
DLOG("hosfakesplit: midhost marker resolved to "..midhost)
|
||||||
|
if midhost<=pos[1] or midhost>pos[2] then
|
||||||
|
DLOG("hostfakesplit: midhost is not inside the host range")
|
||||||
|
midhost = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- if present apply ipfrag only to real host parts. fakes and parts outside of the host must be visible to DPI.
|
||||||
|
if midhost then
|
||||||
|
part = string.sub(data,pos[1],midhost-1)
|
||||||
|
if b_debug then DLOG("hostfakesplit: sending real host part 1 "..(pos[1]-1).."-"..(midhost-2).." len="..#part.." : "..hexdump_dlog(part)) end
|
||||||
|
if not rawsend_payload_segmented(desync,part,pos[1]-1, opts_orig) then return VERDICT_PASS end
|
||||||
|
|
||||||
|
part = string.sub(data,midhost,pos[2])
|
||||||
|
if b_debug then DLOG("hostfakesplit: sending real host part 2 "..(midhost-1).."-"..(pos[2]-1).." len="..#part.." : "..hexdump_dlog(part)) end
|
||||||
|
if not rawsend_payload_segmented(desync,part,midhost-1, opts_orig) then return VERDICT_PASS end
|
||||||
|
else
|
||||||
|
part = string.sub(data,pos[1],pos[2])
|
||||||
|
if b_debug then DLOG("hostfakesplit: sending real host part "..(pos[1]-1).."-"..(pos[2]-1).." len="..#part.." : "..hexdump_dlog(part)) end
|
||||||
|
if not rawsend_payload_segmented(desync,part,pos[1]-1, opts_orig) then return VERDICT_PASS end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not desync.arg.nofake2 then
|
||||||
|
if b_debug then DLOG("hostfakesplit: sending fake host part (2) "..(pos[1]-1).."-"..(pos[2]-1).." len="..#fakehost.." : "..hexdump_dlog(fakehost)) end
|
||||||
|
if not rawsend_payload_segmented(desync,fakehost,pos[1]-1, opts_fake) then return VERDICT_PASS end
|
||||||
|
end
|
||||||
|
|
||||||
|
local disorder_after_pos
|
||||||
|
if desync.arg.disorder_after then
|
||||||
|
disorder_after_pos = resolve_pos(data, desync.l7payload, desync.arg.disorder_after=="" and "-1" or desync.arg.disorder_after)
|
||||||
|
if disorder_after_pos then
|
||||||
|
-- pos[2] points to the last letter of the host starting from 1
|
||||||
|
if disorder_after_pos<=(pos[2]+1) then
|
||||||
|
DLOG("hostfakesplit: disorder_after marker '"..(disorder_after_pos-1).."' resolved to pos not after after_host pos "..pos[2])
|
||||||
|
disorder_after_pos = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
DLOG("hostfakesplit: could not resolve disorder_after marker '"..desync.arg.disorder_after.."'")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if disorder_after_pos then
|
||||||
|
part = string.sub(data,disorder_after_pos)
|
||||||
|
if b_debug then DLOG("hostfakesplit: sending after_host part (2) "..(disorder_after_pos-1).."-"..(#data-1).." len="..#part.." : "..hexdump_dlog(part)) end
|
||||||
|
if not rawsend_payload_segmented(desync,part,disorder_after_pos-1, opts_orig) then return VERDICT_PASS end
|
||||||
|
|
||||||
|
part = string.sub(data,pos[2]+1,disorder_after_pos-1)
|
||||||
|
if b_debug then DLOG("hostfakesplit: sending after_host part (1) "..pos[2].."-"..(disorder_after_pos-2).." len="..#part.." : "..hexdump_dlog(part)) end
|
||||||
|
else
|
||||||
|
part = string.sub(data,pos[2]+1)
|
||||||
|
if b_debug then DLOG("hostfakesplit: sending after_host part "..pos[2].."-"..(#data-1).." len="..#part.." : "..hexdump_dlog(part)) end
|
||||||
|
end
|
||||||
|
if not rawsend_payload_segmented(desync,part,pos[2], opts_orig) then return VERDICT_PASS end
|
||||||
|
|
||||||
|
replay_drop_set(desync)
|
||||||
|
return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP
|
||||||
|
else
|
||||||
|
DLOG("hostfakesplit: host range cannot be resolved")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DLOG("hostfakesplit: not acting on further replay pieces")
|
||||||
|
end
|
||||||
|
-- drop replayed packets if reasm was sent successfully in splitted form
|
||||||
|
if replay_drop(desync) then
|
||||||
|
return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--dpi-desync=fakedsplit"
|
||||||
|
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct. FOOLING AND REPEATS APPLIED ONLY TO FAKES.
|
||||||
|
-- arg : pos=<posmarker> - split position marker
|
||||||
|
-- arg : nofake1, nofake2, nofake3, nofake4 - do not send individual fakes
|
||||||
|
-- arg : pattern=<blob> . fill fake parts with this pattern
|
||||||
|
-- arg : seqovl=N . decrease seq number of the first segment by N and fill N bytes with pattern (default - all zero)
|
||||||
|
-- arg : seqovl_pattern=<blob> . override seqovl pattern
|
||||||
|
-- arg : blob=<blob> - use this data instead of reasm_data
|
||||||
|
-- arg : nodrop - do not drop current dissect
|
||||||
|
function fakedsplit(ctx, desync)
|
||||||
|
if not desync.dis.tcp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
-- by default process only outgoing known payloads
|
||||||
|
local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload
|
||||||
|
if #data>0 and direction_check(desync) and payload_check(desync) then
|
||||||
|
if replay_first(desync) then
|
||||||
|
local spos = desync.arg.pos or "2"
|
||||||
|
local pos = resolve_pos(data, desync.l7payload, spos)
|
||||||
|
if pos then
|
||||||
|
if pos == 1 then
|
||||||
|
DLOG("multidisorder: split pos resolved to 0. cannot split.")
|
||||||
|
else
|
||||||
|
if b_debug then DLOG("fakedsplit: resolved split pos: "..tostring(pos-1)) end
|
||||||
|
|
||||||
|
-- do not apply fooling to original parts except tcp_ts_up but apply ip_id
|
||||||
|
local fake, fakepat, part, pat
|
||||||
|
local opts_orig = {rawsend = rawsend_opts_base(desync), reconstruct = {}, ipfrag = {}, ipid = desync.arg, fooling = {tcp_ts_up = desync.arg.tcp_ts_up}}
|
||||||
|
local opts_fake = {rawsend = rawsend_opts(desync), reconstruct = reconstruct_opts(desync), ipfrag = {}, ipid = desync.arg, fooling = desync.arg}
|
||||||
|
|
||||||
|
fakepat = desync.arg.pattern and blob(desync,desync.arg.pattern) or "\x00"
|
||||||
|
|
||||||
|
-- first fake
|
||||||
|
fake = pattern(fakepat,1,pos-1)
|
||||||
|
|
||||||
|
if not desync.arg.nofake1 then
|
||||||
|
if b_debug then DLOG("fakedsplit: sending fake part 1 (1) : 0-"..(pos-2).." len="..#fake.." : "..hexdump_dlog(fake)) end
|
||||||
|
if not rawsend_payload_segmented(desync,fake,0, opts_fake) then return VERDICT_PASS end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- first real
|
||||||
|
part = string.sub(data,1,pos-1)
|
||||||
|
local seqovl=0
|
||||||
|
if desync.arg.seqovl and tonumber(desync.arg.seqovl)>0 then
|
||||||
|
seqovl = tonumber(desync.arg.seqovl)
|
||||||
|
pat = desync.arg.seqovl_pattern and blob(desync,desync.arg.seqovl_pattern) or "\x00"
|
||||||
|
part = pattern(pat,1,seqovl)..part
|
||||||
|
end
|
||||||
|
if b_debug then DLOG("fakedsplit: sending real part 1 : 0-"..(pos-2).." len="..#part.." seqovl="..seqovl.." : "..hexdump_dlog(part)) end
|
||||||
|
if not rawsend_payload_segmented(desync,part,-seqovl, opts_orig) then return VERDICT_PASS end
|
||||||
|
|
||||||
|
-- first fake again
|
||||||
|
if not desync.arg.nofake2 then
|
||||||
|
if b_debug then DLOG("fakedsplit: sending fake part 1 (2) : 0-"..(pos-2).." len="..#fake.." : "..hexdump_dlog(fake)) end
|
||||||
|
if not rawsend_payload_segmented(desync,fake,0, opts_fake) then return VERDICT_PASS end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- second fake
|
||||||
|
fake = pattern(fakepat,pos,#data-pos+1)
|
||||||
|
if not desync.arg.nofake3 then
|
||||||
|
if b_debug then DLOG("fakedsplit: sending fake part 2 (1) : "..(pos-1).."-"..(#data-1).." len="..#fake.." : "..hexdump_dlog(fake)) end
|
||||||
|
if not rawsend_payload_segmented(desync,fake,pos-1, opts_fake) then return VERDICT_PASS end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- second real
|
||||||
|
part = string.sub(data,pos)
|
||||||
|
if b_debug then DLOG("fakedsplit: sending real part 2 : "..(pos-1).."-"..(#data-1).." len="..#part.." : "..hexdump_dlog(part)) end
|
||||||
|
if not rawsend_payload_segmented(desync,part,pos-1, opts_orig) then return VERDICT_PASS end
|
||||||
|
|
||||||
|
-- second fake again
|
||||||
|
if not desync.arg.nofake4 then
|
||||||
|
if b_debug then DLOG("fakedsplit: sending fake part 2 (2) : "..(pos-1).."-"..(#data-1).." len="..#fake.." : "..hexdump_dlog(fake)) end
|
||||||
|
if not rawsend_payload_segmented(desync,fake,pos-1, opts_fake) then return VERDICT_PASS end
|
||||||
|
end
|
||||||
|
|
||||||
|
replay_drop_set(desync)
|
||||||
|
return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DLOG("fakedsplit: cannot resolve pos '"..desync.arg.pos.."'")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DLOG("fakedsplit: not acting on further replay pieces")
|
||||||
|
end
|
||||||
|
-- drop replayed packets if reasm was sent successfully in splitted form
|
||||||
|
if replay_drop(desync) then
|
||||||
|
return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--dpi-desync=fakeddisorder"
|
||||||
|
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct. FOOLING AND REPEATS APPLIED ONLY TO FAKES.
|
||||||
|
-- arg : pos=<posmarker> - split position marker
|
||||||
|
-- arg : nofake1, nofake2, nofake3, nofake4 - do not send individual fakes
|
||||||
|
-- arg : pattern=<blob> . fill fake parts with this pattern
|
||||||
|
-- arg : seqovl=N . decrease seq number of the second segment by N and fill N bytes with pattern (default - all zero). N must be less than the split pos.
|
||||||
|
-- arg : seqovl_pattern=<blob> . override seqovl pattern
|
||||||
|
-- arg : blob=<blob> - use this data instead of desync.dis.payload
|
||||||
|
-- arg : nodrop - do not drop current dissect
|
||||||
|
function fakeddisorder(ctx, desync)
|
||||||
|
if not desync.dis.tcp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
-- by default process only outgoing known payloads
|
||||||
|
local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload
|
||||||
|
if #data>0 and direction_check(desync) and payload_check(desync) then
|
||||||
|
if replay_first(desync) then
|
||||||
|
local spos = desync.arg.pos or "2"
|
||||||
|
local pos = resolve_pos(data, desync.l7payload, spos)
|
||||||
|
if pos then
|
||||||
|
if pos == 1 then
|
||||||
|
DLOG("multidisorder: split pos resolved to 0. cannot split.")
|
||||||
|
else
|
||||||
|
if b_debug then DLOG("fakeddisorder: resolved split pos: "..tostring(pos-1)) end
|
||||||
|
|
||||||
|
-- do not apply fooling to original parts except tcp_ts_up but apply ip_id
|
||||||
|
local fake, part, pat
|
||||||
|
local opts_orig = {rawsend = rawsend_opts_base(desync), reconstruct = {}, ipfrag = {}, ipid = desync.arg, fooling = {tcp_ts_up = desync.arg.tcp_ts_up}}
|
||||||
|
local opts_fake = {rawsend = rawsend_opts(desync), reconstruct = reconstruct_opts(desync), ipfrag = {}, ipid = desync.arg, fooling = desync.arg}
|
||||||
|
|
||||||
|
fakepat = desync.arg.pattern and blob(desync,desync.arg.pattern) or "\x00"
|
||||||
|
|
||||||
|
-- second fake
|
||||||
|
fake = pattern(fakepat,pos,#data-pos+1)
|
||||||
|
if not desync.arg.nofake1 then
|
||||||
|
if b_debug then DLOG("fakeddisorder: sending fake part 2 (1) : "..(pos-1).."-"..(#data-1).." len="..#fake.." : "..hexdump_dlog(fake)) end
|
||||||
|
if not rawsend_payload_segmented(desync,fake,pos-1, opts_fake) then return VERDICT_PASS end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- second real
|
||||||
|
part = string.sub(data,pos)
|
||||||
|
local seqovl = 0
|
||||||
|
if desync.arg.seqovl then
|
||||||
|
seqovl = resolve_pos(data, desync.l7payload, desync.arg.seqovl)
|
||||||
|
if seqovl then
|
||||||
|
seqovl = seqovl - 1
|
||||||
|
if seqovl>=(pos-1) then
|
||||||
|
DLOG("fakeddisorder: seqovl cancelled because seqovl "..seqovl.." is not less than the split pos "..(pos-1))
|
||||||
|
seqovl = 0
|
||||||
|
else
|
||||||
|
local pat = desync.arg.seqovl_pattern and blob(desync,desync.arg.seqovl_pattern) or "\x00"
|
||||||
|
part = pattern(pat,1,seqovl)..part
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DLOG("fakeddisorder: seqovl cancelled because could not resolve marker '"..desync.arg.seqovl.."'")
|
||||||
|
seqovl = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if b_debug then DLOG("fakeddisorder: sending real part 2 : "..(pos-1).."-"..(#data-1).." len="..#part.." seqovl="..seqovl.." : "..hexdump_dlog(part)) end
|
||||||
|
if not rawsend_payload_segmented(desync,part,pos-1-seqovl, opts_orig) then return VERDICT_PASS end
|
||||||
|
|
||||||
|
-- second fake again
|
||||||
|
if not desync.arg.nofake2 then
|
||||||
|
if b_debug then DLOG("fakeddisorder: sending fake part 2 (2) : "..(pos-1).."-"..(#data-1).." len="..#fake.." : "..hexdump_dlog(fake)) end
|
||||||
|
if not rawsend_payload_segmented(desync,fake,pos-1, opts_fake) then return VERDICT_PASS end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- first fake
|
||||||
|
fake = pattern(fakepat,1,pos-1)
|
||||||
|
if not desync.arg.nofake3 then
|
||||||
|
if b_debug then DLOG("fakeddisorder: sending fake part 1 (1) : 0-"..(pos-2).." len="..#fake.." : "..hexdump_dlog(fake)) end
|
||||||
|
if not rawsend_payload_segmented(desync,fake,0, opts_fake) then return VERDICT_PASS end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- first real
|
||||||
|
part = string.sub(data,1,pos-1)
|
||||||
|
if b_debug then DLOG("fakeddisorder: sending real part 1 : 0-"..(pos-2).." len="..#part.." : "..hexdump_dlog(part)) end
|
||||||
|
if not rawsend_payload_segmented(desync,part,0, opts_orig) then return VERDICT_PASS end
|
||||||
|
|
||||||
|
-- first fake again
|
||||||
|
if not desync.arg.nofake4 then
|
||||||
|
if b_debug then DLOG("fakeddisorder: sending fake part 1 (2) : 0-"..(pos-2).." len="..#fake.." : "..hexdump_dlog(fake)) end
|
||||||
|
if not rawsend_payload_segmented(desync,fake,0, opts_fake) then return VERDICT_PASS end
|
||||||
|
end
|
||||||
|
|
||||||
|
replay_drop_set(desync)
|
||||||
|
return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DLOG("fakeddisorder: cannot resolve pos '"..desync.arg.pos.."'")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DLOG("fakeddisorder: not acting on further replay pieces")
|
||||||
|
end
|
||||||
|
-- drop replayed packets if reasm was sent successfully in splitted form
|
||||||
|
if replay_drop(desync) then
|
||||||
|
return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : not available
|
||||||
|
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag
|
||||||
|
-- arg : pos=<postmarker list> . position marker list. 2 pos required, only 2 first pos used. example : "host,endhost"
|
||||||
|
-- arg : seqovl=N . decrease seq number of the first segment by N and fill N bytes with pattern (default - all zero)
|
||||||
|
-- arg : seqovl_pattern=<blob> . override pattern
|
||||||
|
-- arg : blob=<blob> - use this data instead of desync.dis.payload
|
||||||
|
function tcpseg(ctx, desync)
|
||||||
|
if not desync.dis.tcp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
if not desync.arg.pos then
|
||||||
|
error("tcpseg: no pos specified")
|
||||||
|
end
|
||||||
|
-- by default process only outgoing known payloads
|
||||||
|
local data = blob_or_def(desync, desync.arg.blob) or desync.reasm_data or desync.dis.payload
|
||||||
|
if #data>0 and direction_check(desync) and payload_check(desync) then
|
||||||
|
if replay_first(desync) then
|
||||||
|
if b_debug then DLOG("tcpseg: pos: "..desync.arg.pos) end
|
||||||
|
-- always returns 2 positions or nil or causes error
|
||||||
|
local pos = resolve_range(data, desync.l7payload, desync.arg.pos)
|
||||||
|
if pos then
|
||||||
|
-- check debug to save CPU
|
||||||
|
if b_debug then DLOG("tcpseg: resolved range: "..table.concat(zero_based_pos(pos)," ")) end
|
||||||
|
local part = string.sub(data,pos[1],pos[2])
|
||||||
|
local seqovl=0
|
||||||
|
if desync.arg.seqovl and tonumber(desync.arg.seqovl)>0 then
|
||||||
|
seqovl = tonumber(desync.arg.seqovl)
|
||||||
|
local pat = desync.arg.seqovl_pattern and blob(desync,desync.arg.seqovl_pattern) or "\x00"
|
||||||
|
part = pattern(pat,1,seqovl)..part
|
||||||
|
end
|
||||||
|
if b_debug then DLOG("tcpseg: sending "..(pos[1]-1).."-"..(pos[2]-1).." len="..#part.." seqovl="..seqovl.." : "..hexdump_dlog(part)) end
|
||||||
|
rawsend_payload_segmented(desync,part,pos[1]-1-seqovl)
|
||||||
|
else
|
||||||
|
DLOG("tcpseg: range cannot be resolved")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DLOG("tcpseg: not acting on further replay pieces")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--dpi-desync=udplen"
|
||||||
|
-- standard args : direction, payload
|
||||||
|
-- arg : min=N . do not act on payloads smaller than N bytes
|
||||||
|
-- arg : max=N . do not act on payloads larger than N bytes
|
||||||
|
-- arg : increment=N . 2 by default. negative increment shrinks the packet, positive grows it.
|
||||||
|
-- arg : pattern=<blob> . used to fill extra bytes when length increases
|
||||||
|
-- arg : pattern_offset=N . offset in the pattern. 0 by default
|
||||||
|
function udplen(ctx, desync)
|
||||||
|
if not desync.dis.udp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
if direction_check(desync) and payload_check(desync) then
|
||||||
|
local len = #desync.dis.payload
|
||||||
|
if (desync.arg.min and #desync.dis.payload < tonumber(desync.arg.min)) then
|
||||||
|
DLOG("udplen: payload size "..len.." is less than the minimum size "..desync.arg.min)
|
||||||
|
elseif (desync.arg.max and #desync.dis.payload > tonumber(desync.arg.max)) then
|
||||||
|
DLOG("udplen: payload size "..len.." is more than the maximum size "..desync.arg.max)
|
||||||
|
else
|
||||||
|
local inc = desync.arg.increment and tonumber(desync.arg.increment) or 2
|
||||||
|
if inc>0 then
|
||||||
|
local pat = desync.arg.pattern and blob(desync,desync.arg.pattern) or "\x00"
|
||||||
|
local pat_offset = desync.arg.pattern_offset and (tonumber(desync.arg.pattern_offset)+1) or 1
|
||||||
|
desync.dis.payload = desync.dis.payload .. pattern(pat, pat_offset, inc)
|
||||||
|
DLOG("udplen: "..len.." => "..#desync.dis.payload)
|
||||||
|
return VERDICT_MODIFY
|
||||||
|
elseif inc<0 then
|
||||||
|
if (len+inc)<1 then
|
||||||
|
DLOG("udplen: will not shrink to zero length")
|
||||||
|
else
|
||||||
|
desync.dis.payload = string.sub(desync.dis.payload,1,len+inc)
|
||||||
|
DLOG("udplen: "..len.." => "..#desync.dis.payload)
|
||||||
|
end
|
||||||
|
return VERDICT_MODIFY
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- nfqws1 : "--dpi-desync=tamper" for dht proto
|
||||||
|
-- standard args : direction
|
||||||
|
-- arg : dn=N - message starts from "dN". 2 by default
|
||||||
|
function dht_dn(ctx, desync)
|
||||||
|
if not desync.dis.udp then
|
||||||
|
instance_cutoff_shim(ctx, desync)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
direction_cutoff_opposite(ctx, desync)
|
||||||
|
if desync.l7payload=="dht" and direction_check(desync) then
|
||||||
|
local N = tonumber(desync.arg.dn) or 2
|
||||||
|
-- remove "d1" from the start not breaking bencode
|
||||||
|
local prefix = "d"..tostring(N)..":"..string.rep("0",N).."1:x"
|
||||||
|
desync.dis.payload = prefix..string.sub(desync.dis.payload,2)
|
||||||
|
DLOG("dht_dn: tampered dht to start with '"..prefix.."' instead of 'd1:'")
|
||||||
|
return VERDICT_MODIFY
|
||||||
|
end
|
||||||
|
end
|
||||||
429
blockcheck/zapret2/lua/zapret-auto.lua
Normal file
429
blockcheck/zapret2/lua/zapret-auto.lua
Normal file
@@ -0,0 +1,429 @@
|
|||||||
|
-- standard automation/orchestration code
|
||||||
|
-- this is related to making dynamic strategy decisions without rewriting or altering strategy function code
|
||||||
|
-- orchestrators can decide which instances to call or not to call or pass them dynamic arguments
|
||||||
|
-- failure and success detectors test potential block conditions for orchestrators
|
||||||
|
|
||||||
|
-- standard host key generator for per-host storage
|
||||||
|
-- arg: reqhost - require hostname, do not work with ip
|
||||||
|
-- arg: nld=N - cut hostname to N level domain. NLD=2 static.intranet.microsoft.com => microsoft.com
|
||||||
|
function standard_hostkey(desync)
|
||||||
|
local hostkey = desync.track and desync.track.hostname
|
||||||
|
if hostkey then
|
||||||
|
if desync.arg.nld and tonumber(desync.arg.nld)>0 then
|
||||||
|
-- dissect_nld returns nil if domain is invalid or does not have this NLD
|
||||||
|
-- fall back to original hostkey if it fails
|
||||||
|
local hktemp = dissect_nld(hostkey, tonumber(desync.arg.nld))
|
||||||
|
if hktemp then
|
||||||
|
hostkey = hktemp
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif not desync.arg.reqhost then
|
||||||
|
hostkey = host_ip(desync)
|
||||||
|
end
|
||||||
|
return hostkey
|
||||||
|
end
|
||||||
|
|
||||||
|
-- per-host storage
|
||||||
|
-- arg: key - a string - table name inside autostate table. to allow multiple orchestrator instances to use single host storage
|
||||||
|
-- arg: hostkey - hostkey generator function name
|
||||||
|
function automate_host_record(desync)
|
||||||
|
local hostkey, hkf, askey
|
||||||
|
|
||||||
|
if desync.arg.hostkey then
|
||||||
|
if type(_G[desync.arg.hostkey])~="function" then
|
||||||
|
error("automate: invalid hostkey function '"..desync.arg.hostkey.."'")
|
||||||
|
end
|
||||||
|
hkf = _G[desync.arg.hostkey]
|
||||||
|
else
|
||||||
|
hkf = standard_hostkey
|
||||||
|
end
|
||||||
|
hostkey = hkf(desync)
|
||||||
|
if not hostkey then
|
||||||
|
DLOG("automate: host record key unavailable")
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
askey = (desync.arg.key and #desync.arg.key>0) and desync.arg.key or desync.func_instance
|
||||||
|
DLOG("automate: host record key 'autostate."..askey.."."..hostkey.."'")
|
||||||
|
if not autostate then
|
||||||
|
autostate = {}
|
||||||
|
end
|
||||||
|
if not autostate[askey] then
|
||||||
|
autostate[askey] = {}
|
||||||
|
end
|
||||||
|
if not autostate[askey][hostkey] then
|
||||||
|
autostate[askey][hostkey] = {}
|
||||||
|
end
|
||||||
|
return autostate[askey][hostkey]
|
||||||
|
end
|
||||||
|
-- per-connection storage
|
||||||
|
function automate_conn_record(desync)
|
||||||
|
if not desync.track.lua_state.automate then
|
||||||
|
desync.track.lua_state.automate = {}
|
||||||
|
end
|
||||||
|
return desync.track.lua_state.automate
|
||||||
|
end
|
||||||
|
|
||||||
|
-- counts failure, optionally (if crec is given) prevents dup failure counts in a single connection
|
||||||
|
-- if 'maxtime' between failures is exceeded then failure count is reset
|
||||||
|
-- return true if threshold ('fails') is reached
|
||||||
|
-- hres is host record. host or ip bound table
|
||||||
|
-- cres is connection record. connection bound table
|
||||||
|
function automate_failure_counter(hrec, crec, fails, maxtime)
|
||||||
|
if crec and crec.failure then
|
||||||
|
DLOG("automate: duplicate failure in the same connection. not counted")
|
||||||
|
else
|
||||||
|
if crec then crec.failure = true end
|
||||||
|
local tnow=os.time()
|
||||||
|
if not hrec.failure_time_last then
|
||||||
|
hrec.failure_time_last = tnow
|
||||||
|
end
|
||||||
|
if not hrec.failure_counter then
|
||||||
|
hrec.failure_counter = 0
|
||||||
|
elseif tnow>(hrec.failure_time_last + maxtime) then
|
||||||
|
DLOG("automate: failure counter reset because last failure was "..(tnow - hrec.failure_time_last).." seconds ago")
|
||||||
|
hrec.failure_counter = 0
|
||||||
|
end
|
||||||
|
hrec.failure_counter = hrec.failure_counter + 1
|
||||||
|
hrec.failure_time_last = tnow
|
||||||
|
if b_debug then DLOG("automate: failure counter "..hrec.failure_counter..(fails and ('/'..fails) or '')) end
|
||||||
|
if fails and hrec.failure_counter>=fails then
|
||||||
|
hrec.failure_counter = nil -- reset counter
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
-- resets failure counter if it has started counting
|
||||||
|
function automate_failure_counter_reset(hrec)
|
||||||
|
if hrec.failure_counter then
|
||||||
|
DLOG("automate: failure counter reset")
|
||||||
|
hrec.failure_counter = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- location is url compatible with Location: header
|
||||||
|
-- hostname is original hostname
|
||||||
|
function is_dpi_redirect(hostname, location)
|
||||||
|
local ds = dissect_url(location)
|
||||||
|
if ds.domain then
|
||||||
|
local sld1 = dissect_nld(hostname,2)
|
||||||
|
local sld2 = dissect_nld(ds.domain,2)
|
||||||
|
return sld2 and sld1~=sld2
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function standard_detector_defaults(arg)
|
||||||
|
return {
|
||||||
|
inseq = tonumber(arg.inseq) or 4096,
|
||||||
|
retrans = tonumber(arg.retrans) or 3,
|
||||||
|
maxseq = tonumber(arg.maxseq) or 32768,
|
||||||
|
udp_in = tonumber(arg.udp_in) or 1,
|
||||||
|
udp_out = tonumber(arg.udp_out) or 4,
|
||||||
|
no_http_redirect = arg.no_http_redirect,
|
||||||
|
no_rst = arg.no_rst
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- standard failure detector
|
||||||
|
-- works with tcp and udp
|
||||||
|
-- detected failures:
|
||||||
|
-- incoming RST
|
||||||
|
-- incoming http redirection
|
||||||
|
-- outgoing retransmissions
|
||||||
|
-- udp too much out with too few in
|
||||||
|
-- arg: maxseq=<rseq> - tcp: test retransmissions only within this relative sequence. default is 32K
|
||||||
|
-- arg: retrans=N - tcp: retrans count threshold. default is 3
|
||||||
|
-- arg: inseq=<rseq> - tcp: maximum relative sequence number to treat incoming RST as DPI reset. default is 4K
|
||||||
|
-- arg: no_http_redirect - tcp: disable http_reply dpi redirect trigger
|
||||||
|
-- arg: no_rst - tcp: disable incoming RST trigger
|
||||||
|
-- arg: udp_out - udp: >= outgoing udp packets. default is 4
|
||||||
|
-- arg: udp_in - udp: with <= incoming udp packets. default is 1
|
||||||
|
function standard_failure_detector(desync, crec)
|
||||||
|
local arg = standard_detector_defaults(desync.arg)
|
||||||
|
local trigger = false
|
||||||
|
if desync.dis.tcp then
|
||||||
|
local seq = pos_get(desync,'s')
|
||||||
|
if desync.outgoing then
|
||||||
|
if #desync.dis.payload>0 and arg.retrans and arg.maxseq>0 and seq<=arg.maxseq and (crec.retrans or 0)<arg.retrans then
|
||||||
|
if is_retransmission(desync) then
|
||||||
|
crec.retrans = crec.retrans and (crec.retrans+1) or 1
|
||||||
|
DLOG("standard_failure_detector: retransmission "..crec.retrans.."/"..arg.retrans)
|
||||||
|
trigger = crec.retrans>=arg.retrans
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if not arg.no_rst and arg.inseq>0 and bitand(desync.dis.tcp.th_flags, TH_RST)~=0 and seq>=1 then
|
||||||
|
trigger = seq<=arg.inseq
|
||||||
|
if b_debug then
|
||||||
|
if trigger then
|
||||||
|
DLOG("standard_failure_detector: incoming RST s"..seq.." in range s"..arg.inseq)
|
||||||
|
else
|
||||||
|
DLOG("standard_failure_detector: not counting incoming RST s"..seq.." beyond s"..arg.inseq)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif not arg.no_http_redirect and desync.l7payload=="http_reply" and desync.track.hostname then
|
||||||
|
local hdis = http_dissect_reply(desync.dis.payload)
|
||||||
|
if hdis and (hdis.code==302 or hdis.code==307) and hdis.headers.location and hdis.headers.location then
|
||||||
|
trigger = is_dpi_redirect(desync.track.hostname, hdis.headers.location.value)
|
||||||
|
if b_debug then
|
||||||
|
if trigger then
|
||||||
|
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers.location.value.."'. looks like DPI redirect.")
|
||||||
|
else
|
||||||
|
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers.location.value.."'. NOT a DPI redirect.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif desync.dis.udp then
|
||||||
|
if desync.outgoing then
|
||||||
|
if arg.udp_out>0 then
|
||||||
|
local pos_out = pos_get(desync,'n',false)
|
||||||
|
local pos_in = pos_get(desync,'n',true)
|
||||||
|
trigger = pos_out>=arg.udp_out and pos_in<=arg.udp_in
|
||||||
|
if trigger then
|
||||||
|
if b_debug then
|
||||||
|
DLOG("standard_failure_detector: arg.udp_out "..pos_out..">="..arg.udp_out.." arg.udp_in "..pos_in.."<="..arg.udp_in)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return trigger
|
||||||
|
end
|
||||||
|
|
||||||
|
-- standard success detector
|
||||||
|
-- success means previous failures were temporary and counter should be reset
|
||||||
|
-- detected successes:
|
||||||
|
-- tcp: outgoing seq is beyond 'maxseq' and maxseq>0
|
||||||
|
-- tcp: incoming seq is beyond 'inseq' and inseq>0
|
||||||
|
-- udp: incoming packets count > `udp_in` and `udp_out`>0
|
||||||
|
-- arg: maxseq=<rseq> - tcp: success if outgoing relative sequence is beyond this value. default is 32K
|
||||||
|
-- arg: inseq=<rseq> - tcp: success if incoming relative sequence is beyond this value. default is 4K
|
||||||
|
-- arg: udp_out - udp : must be nil or >0 to test udp_in
|
||||||
|
-- arg: udp_in - udp: if number if incoming packets > udp_in it means success
|
||||||
|
function standard_success_detector(desync, crec)
|
||||||
|
local arg = standard_detector_defaults(desync.arg)
|
||||||
|
if desync.dis.tcp then
|
||||||
|
local seq = pos_get(desync,'s')
|
||||||
|
if desync.outgoing then
|
||||||
|
if arg.maxseq>0 and seq>arg.maxseq then
|
||||||
|
DLOG("standard_success_detector: outgoing s"..seq.." is beyond s"..arg.maxseq..". treating connection as successful")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if arg.inseq>0 and seq>arg.inseq then
|
||||||
|
DLOG("standard_success_detector: incoming s"..seq.." is beyond s"..arg.inseq..". treating connection as successful")
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif desync.dis.udp then
|
||||||
|
if not desync.outgoing then
|
||||||
|
local pos = pos_get(desync,'n')
|
||||||
|
if arg.udp_out>0 and pos>arg.udp_in then
|
||||||
|
if b_debug then
|
||||||
|
DLOG("standard_success_detector: arg.udp_in "..pos..">"..arg.udp_in)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- calls success and failure detectors
|
||||||
|
-- resets counter if success is detected
|
||||||
|
-- increases counter if failure is detected
|
||||||
|
-- returns true if failure counter exceeds threshold
|
||||||
|
function automate_failure_check(desync, hrec, crec)
|
||||||
|
if crec.nocheck then return false end
|
||||||
|
|
||||||
|
local failure_detector, success_detector
|
||||||
|
if desync.arg.failure_detector then
|
||||||
|
if type(_G[desync.arg.failure_detector])~="function" then
|
||||||
|
error("automate: invalid failure detector function '"..desync.arg.failure_detector.."'")
|
||||||
|
end
|
||||||
|
failure_detector = _G[desync.arg.failure_detector]
|
||||||
|
else
|
||||||
|
failure_detector = standard_failure_detector
|
||||||
|
end
|
||||||
|
if desync.arg.success_detector then
|
||||||
|
if type(_G[desync.arg.success_detector])~="function" then
|
||||||
|
error("automate: invalid success detector function '"..desync.arg.success_detector.."'")
|
||||||
|
end
|
||||||
|
success_detector = _G[desync.arg.success_detector]
|
||||||
|
else
|
||||||
|
success_detector = standard_success_detector
|
||||||
|
end
|
||||||
|
|
||||||
|
if success_detector(desync, crec) then
|
||||||
|
crec.nocheck = true
|
||||||
|
DLOG("automate: success detected")
|
||||||
|
automate_failure_counter_reset(hrec)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if failure_detector(desync, crec) then
|
||||||
|
crec.nocheck = true
|
||||||
|
DLOG("automate: failure detected")
|
||||||
|
local fails = tonumber(desync.arg.fails) or 3
|
||||||
|
local maxtime = tonumber(desync.arg.time) or 60
|
||||||
|
return automate_failure_counter(hrec, crec, fails, maxtime)
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- circularily change strategy numbers when failure count reaches threshold ('fails')
|
||||||
|
-- this orchestrator requires redirection of incoming traffic to cache RST and http replies !
|
||||||
|
-- each orchestrated instance must have strategy=N arg, where N starts from 1 and increment without gaps
|
||||||
|
-- if 'final' arg is present in an orchestrated instance it stops rotation
|
||||||
|
-- arg: fails=N - failture count threshold. default is 3
|
||||||
|
-- arg: time=<sec> - if last failure happened earlier than `maxtime` seconds ago - reset failure counter. default is 60.
|
||||||
|
-- arg: success_detector - success detector function name
|
||||||
|
-- arg: failure_detector - failure detector function name
|
||||||
|
-- arg: hostkey - hostkey generator function name
|
||||||
|
-- args for failure detector - see standard_failure_detector or your own detector
|
||||||
|
-- args for success detector - see standard_success_detector or your own detector
|
||||||
|
-- args for hostkey generator - see standard_hostkey or your own generator
|
||||||
|
-- test case: nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua --in-range=-s34228 --lua-desync=circular --lua-desync=argdebug:strategy=1 --lua-desync=argdebug:strategy=2
|
||||||
|
function circular(ctx, desync)
|
||||||
|
local function count_strategies(hrec)
|
||||||
|
if not hrec.ctstrategy then
|
||||||
|
local uniq={}
|
||||||
|
local n=0
|
||||||
|
for i,instance in pairs(desync.plan) do
|
||||||
|
if instance.arg.strategy then
|
||||||
|
n = tonumber(instance.arg.strategy)
|
||||||
|
if not n or n<1 then
|
||||||
|
error("circular: strategy number '"..tostring(instance.arg.strategy).."' is invalid")
|
||||||
|
end
|
||||||
|
uniq[tonumber(instance.arg.strategy)] = true
|
||||||
|
if instance.arg.final then
|
||||||
|
hrec.final = n
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
n=0
|
||||||
|
for i,v in pairs(uniq) do
|
||||||
|
n=n+1
|
||||||
|
end
|
||||||
|
if n~=#uniq then
|
||||||
|
error("circular: strategies numbers must start from 1 and increment. gaps are not allowed.")
|
||||||
|
end
|
||||||
|
hrec.ctstrategy = n
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- take over execution. prevent further instance execution in case of error
|
||||||
|
orchestrate(ctx, desync)
|
||||||
|
|
||||||
|
if not desync.track then
|
||||||
|
DLOG_ERR("circular: conntrack is missing but required")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local hrec = automate_host_record(desync)
|
||||||
|
if not hrec then
|
||||||
|
DLOG("circular: passing with no tampering")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
count_strategies(hrec)
|
||||||
|
if hrec.ctstrategy==0 then
|
||||||
|
error("circular: add strategy=N tag argument to each following instance ! N must start from 1 and increment")
|
||||||
|
end
|
||||||
|
if not hrec.nstrategy then
|
||||||
|
DLOG("circular: start from strategy 1")
|
||||||
|
hrec.nstrategy = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local verdict = VERDICT_PASS
|
||||||
|
if hrec.final~=hrec.nstrategy then
|
||||||
|
local crec = automate_conn_record(desync)
|
||||||
|
if automate_failure_check(desync, hrec, crec) then
|
||||||
|
hrec.nstrategy = (hrec.nstrategy % hrec.ctstrategy) + 1
|
||||||
|
DLOG("circular: rotate strategy to "..hrec.nstrategy)
|
||||||
|
if hrec.nstrategy == hrec.final then
|
||||||
|
DLOG("circular: final strategy "..hrec.final.." reached. will rotate no more.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
DLOG("circular: current strategy "..hrec.nstrategy)
|
||||||
|
while true do
|
||||||
|
local instance = plan_instance_pop(desync)
|
||||||
|
if not instance then break end
|
||||||
|
if instance.arg.strategy and tonumber(instance.arg.strategy)==hrec.nstrategy then
|
||||||
|
verdict = plan_instance_execute(desync, verdict, instance)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return verdict
|
||||||
|
end
|
||||||
|
|
||||||
|
-- test iff functions
|
||||||
|
function cond_true(desync)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
function cond_false(desync)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
-- arg: percent - of true . 50 by default
|
||||||
|
function cond_random(desync)
|
||||||
|
return math.random(0,99)<(tonumber(desync.arg.percent) or 50)
|
||||||
|
end
|
||||||
|
-- this iif function detects packets having 'arg.pattern' string in their payload
|
||||||
|
-- test case : nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua --lua-desync=condition:iff=cond_payload_str:pattern=1234 --lua-desync=argdebug:testarg=1 --lua-desync=argdebug:testarg=2:morearg=xyz
|
||||||
|
-- test case (true) : echo aaz1234zzz | ncat -4u 1.1.1.1 443
|
||||||
|
-- test case (false) : echo aaze124zzz | ncat -4u 1.1.1.1 443
|
||||||
|
function cond_payload_str(desync)
|
||||||
|
if not desync.arg.pattern then
|
||||||
|
error("cond_payload_str: missing 'pattern'")
|
||||||
|
end
|
||||||
|
return string.find(desync.dis.payload,desync.arg.pattern,1,true)
|
||||||
|
end
|
||||||
|
-- check iff function available. error if not
|
||||||
|
function require_iff(desync, name)
|
||||||
|
if not desync.arg.iff then
|
||||||
|
error(name..": missing 'iff' function")
|
||||||
|
end
|
||||||
|
if type(_G[desync.arg.iff])~="function" then
|
||||||
|
error(name..": invalid 'iff' function '"..desync.arg.iff.."'")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- execute further desync instances only if user-provided 'iff' function returns true
|
||||||
|
-- for example, this can be used by custom protocol detectors
|
||||||
|
-- arg: iff - condition function. takes desync as arg and returns bool. (cant use 'if' because of reserved word)
|
||||||
|
-- arg: neg - invert condition function result
|
||||||
|
-- test case : nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua --lua-desync=condition:iff=cond_random --lua-desync=argdebug:testarg=1 --lua-desync=argdebug:testarg=2:morearg=xyz
|
||||||
|
function condition(ctx, desync)
|
||||||
|
require_iff(desync, "condition")
|
||||||
|
orchestrate(ctx, desync)
|
||||||
|
if logical_xor(_G[desync.arg.iff](desync), desync.arg.neg) then
|
||||||
|
DLOG("condition: true")
|
||||||
|
return replay_execution_plan(desync)
|
||||||
|
else
|
||||||
|
DLOG("condition: false")
|
||||||
|
plan_clear(desync)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- clear execution plan if user provided 'iff' functions returns true
|
||||||
|
-- can be used with other orchestrators to stop execution conditionally
|
||||||
|
-- arg: iff - condition function. takes desync as arg and returns bool. (cant use 'if' because of reserved word)
|
||||||
|
-- arg: neg - invert condition function result
|
||||||
|
-- test case : nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua --in-range=-s1 --lua-desync=circular --lua-desync=stopif:iff=cond_random:strategy=1 --lua-desync=argdebug:strategy=1 --lua-desync=argdebug:strategy=2
|
||||||
|
function stopif(ctx, desync)
|
||||||
|
require_iff(desync, "stopif")
|
||||||
|
orchestrate(ctx, desync)
|
||||||
|
if logical_xor(_G[desync.arg.iff](desync), desync.arg.neg) then
|
||||||
|
DLOG("stopif: true")
|
||||||
|
plan_clear(desync)
|
||||||
|
else
|
||||||
|
-- do not do anything. allow other orchestrator to finish the plan
|
||||||
|
DLOG("stopif: false")
|
||||||
|
end
|
||||||
|
end
|
||||||
1398
blockcheck/zapret2/lua/zapret-lib.lua
Normal file
1398
blockcheck/zapret2/lua/zapret-lib.lua
Normal file
File diff suppressed because it is too large
Load Diff
39
blockcheck/zapret2/lua/zapret-pcap.lua
Normal file
39
blockcheck/zapret2/lua/zapret-pcap.lua
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
function pcap_write_header(file)
|
||||||
|
-- big endian, nanoseconds in timestamps, ver 2.4, max packet size - 0x4000 (16384), 0x65 - l3 packets without l2
|
||||||
|
file:write("\xA1\xB2\x3C\x4D\x00\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x65")
|
||||||
|
end
|
||||||
|
function pcap_write_packet(file, raw)
|
||||||
|
local sec, nsec = clock_gettime();
|
||||||
|
file:write(bu32(sec)..bu32(nsec)..bu32(#raw)..bu32(#raw))
|
||||||
|
file:write(raw)
|
||||||
|
file:close()
|
||||||
|
end
|
||||||
|
function pcap_write(file, raw)
|
||||||
|
local pos = file:seek()
|
||||||
|
if (pos==0) then
|
||||||
|
pcap_write_header(file)
|
||||||
|
end
|
||||||
|
pcap_write_packet(file, raw)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- test case : nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-pcap.lua --writeable=zdir --in-range=a --lua-desync=pcap:file=test.pcap
|
||||||
|
-- arg : file=<filename> - file for storing pcap data. if --writeable is specified and filename is relative - append filename to writeable path
|
||||||
|
-- arg : keep - do not overwrite file, append packets to existing
|
||||||
|
function pcap(ctx, desync)
|
||||||
|
if not desync.arg.file or #desync.arg.file==0 then
|
||||||
|
error("pcap requires 'file' parameter")
|
||||||
|
end
|
||||||
|
local fn_cache_name = desync.func_instance.."_fn"
|
||||||
|
if not _G[fn_cache_name] then
|
||||||
|
_G[fn_cache_name] = writeable_file_name(desync.arg.file)
|
||||||
|
if not desync.arg.keep then
|
||||||
|
-- overwrite file
|
||||||
|
os.remove(_G[fn_cache_name])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local f = io.open(_G[fn_cache_name], "a")
|
||||||
|
if not f then
|
||||||
|
error("pcap: could not write to '".._G[fn_cache_name].."'")
|
||||||
|
end
|
||||||
|
pcap_write(f, raw_packet(ctx))
|
||||||
|
end
|
||||||
704
blockcheck/zapret2/lua/zapret-tests.lua
Normal file
704
blockcheck/zapret2/lua/zapret-tests.lua
Normal file
@@ -0,0 +1,704 @@
|
|||||||
|
-- nfqws2 C functions tests
|
||||||
|
-- to run : --lua-init=@zapret-lib.lua --lua-init=@zapret-tests.lua --lua-init="test_all()"
|
||||||
|
|
||||||
|
function test_assert(b)
|
||||||
|
assert(b, "test failed")
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_run(tests,...)
|
||||||
|
for k,f in pairs(tests) do
|
||||||
|
f(...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function test_all(...)
|
||||||
|
test_run({test_crypto, test_bin, test_ipstr, test_dissect, test_csum, test_resolve, test_rawsend},...)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function test_crypto(...)
|
||||||
|
test_run({test_random, test_aes, test_aes_gcm, test_aes_ctr, test_hkdf, test_hash},...)
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_random()
|
||||||
|
local rnds={}
|
||||||
|
for i=1,20 do
|
||||||
|
local rnd = bcryptorandom(math.random(10,20))
|
||||||
|
print("random: "..string2hex(rnd))
|
||||||
|
test_assert(not rnds[rnd]) -- should not be repeats
|
||||||
|
rnds[rnd] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_hash()
|
||||||
|
local hashes={}
|
||||||
|
for i=1,5 do
|
||||||
|
local rnd = brandom(math.random(5,64))
|
||||||
|
print("data: "..string2hex(rnd))
|
||||||
|
for k,sha in pairs({"sha256","sha224"}) do
|
||||||
|
local hsh = hash(sha, rnd)
|
||||||
|
print(sha..": "..string2hex(hsh))
|
||||||
|
local hsh2 = hash(sha, rnd)
|
||||||
|
test_assert(hsh==hsh2)
|
||||||
|
test_assert(not hashes[hsh])
|
||||||
|
hashes[hsh] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_hkdf()
|
||||||
|
local nblob = 2
|
||||||
|
local okms = {}
|
||||||
|
for nsalt=1,nblob do
|
||||||
|
local salt = brandom(math.random(10,20))
|
||||||
|
for nikm=1,nblob do
|
||||||
|
local ikm = brandom(math.random(5,10))
|
||||||
|
for ninfo=1,nblob do
|
||||||
|
local info = brandom(math.random(5,10))
|
||||||
|
local okm_prev
|
||||||
|
for k,sha in pairs({"sha256","sha224"}) do
|
||||||
|
for k,okml in pairs({8, 16, 50}) do
|
||||||
|
local okm_prev
|
||||||
|
local okm
|
||||||
|
print("* hkdf "..sha)
|
||||||
|
print("salt: "..string2hex(salt))
|
||||||
|
print("ikm : "..string2hex(ikm))
|
||||||
|
print("info: "..string2hex(info))
|
||||||
|
print("okml: "..tostring(okml))
|
||||||
|
okm = hkdf(sha, salt, ikm, info, okml)
|
||||||
|
test_assert(okm)
|
||||||
|
print("okm: "..string2hex(okm))
|
||||||
|
if okms[okm] then
|
||||||
|
print("duplicate okm !")
|
||||||
|
end
|
||||||
|
okms[okm] = true
|
||||||
|
|
||||||
|
test_assert(not okm_prev or okm_prev==string.sub(okm, 1, #okm_prev))
|
||||||
|
okm_prev = okm
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_aes()
|
||||||
|
local clear_text="test "..brandom_az09(11)
|
||||||
|
local iv, key, encrypted, decrypted
|
||||||
|
|
||||||
|
for key_size=16,32,8 do
|
||||||
|
local key = brandom(key_size)
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("* aes test key_size "..tostring(key_size))
|
||||||
|
|
||||||
|
print("clear text: "..clear_text);
|
||||||
|
|
||||||
|
print("* encrypting")
|
||||||
|
encrypted = aes(true, key, clear_text)
|
||||||
|
print("encrypted: "..str_or_hex(encrypted))
|
||||||
|
|
||||||
|
print("* decrypting everything good")
|
||||||
|
decrypted = aes(false, key, encrypted)
|
||||||
|
print("decrypted: "..str_or_hex(decrypted))
|
||||||
|
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||||
|
test_assert(decrypted==clear_text)
|
||||||
|
|
||||||
|
print("* decrypting bad payload with good key")
|
||||||
|
decrypted = aes(false, key, brandom(16))
|
||||||
|
print("decrypted: "..str_or_hex(decrypted))
|
||||||
|
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||||
|
test_assert(decrypted~=clear_text)
|
||||||
|
|
||||||
|
print("* decrypting good payload with bad key")
|
||||||
|
decrypted = aes(false, brandom(key_size), encrypted)
|
||||||
|
print("decrypted: "..str_or_hex(decrypted))
|
||||||
|
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||||
|
test_assert(decrypted~=clear_text)
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_aes_gcm()
|
||||||
|
local authenticated_data = "authenticated message "..brandom_az09(math.random(10,50))
|
||||||
|
local clear_text="test message "..brandom_az09(math.random(10,50))
|
||||||
|
local iv, key, encrypted, atag, decrypted, atag2
|
||||||
|
|
||||||
|
for key_size=16,32,8 do
|
||||||
|
iv = brandom(12)
|
||||||
|
key = brandom(key_size)
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("* aes_gcm test key_size "..tostring(key_size))
|
||||||
|
|
||||||
|
print("clear text: "..clear_text);
|
||||||
|
print("authenticated data: "..authenticated_data);
|
||||||
|
|
||||||
|
print("* encrypting")
|
||||||
|
encrypted, atag = aes_gcm(true, key, iv, clear_text, authenticated_data)
|
||||||
|
print("encrypted: "..str_or_hex(encrypted))
|
||||||
|
print("auth tag: "..string2hex(atag))
|
||||||
|
|
||||||
|
print("* decrypting everything good")
|
||||||
|
decrypted, atag2 = aes_gcm(false, key, iv, encrypted, authenticated_data)
|
||||||
|
print("decrypted: "..str_or_hex(decrypted))
|
||||||
|
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||||
|
test_assert(decrypted==clear_text)
|
||||||
|
print("auth tag: "..string2hex(atag2))
|
||||||
|
print( atag==atag2 and "TAG OK" or "TAG ERROR" )
|
||||||
|
test_assert(atag==atag2)
|
||||||
|
|
||||||
|
print("* decrypting bad payload with good key/iv and correct authentication data")
|
||||||
|
decrypted, atag2 = aes_gcm(false, key, iv, brandom(#encrypted), authenticated_data)
|
||||||
|
print("decrypted: "..str_or_hex(decrypted))
|
||||||
|
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||||
|
test_assert(decrypted~=clear_text)
|
||||||
|
print("auth tag: "..string2hex(atag2))
|
||||||
|
print( atag==atag2 and "TAG OK" or "TAG ERROR" )
|
||||||
|
test_assert(atag~=atag2)
|
||||||
|
|
||||||
|
print("* decrypting good payload with good key/iv and incorrect authentication data")
|
||||||
|
decrypted, atag2 = aes_gcm(false, key, iv, encrypted, authenticated_data.."x")
|
||||||
|
print("decrypted: "..str_or_hex(decrypted))
|
||||||
|
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||||
|
test_assert(decrypted==clear_text)
|
||||||
|
print("auth tag: "..string2hex(atag2))
|
||||||
|
print( atag==atag2 and "TAG OK" or "TAG ERROR" )
|
||||||
|
test_assert(atag~=atag2)
|
||||||
|
|
||||||
|
print("* decrypting good payload with bad key, good iv and correct authentication data")
|
||||||
|
decrypted, atag2 = aes_gcm(false, brandom(key_size), iv, encrypted, authenticated_data)
|
||||||
|
print("decrypted: "..str_or_hex(decrypted))
|
||||||
|
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||||
|
test_assert(decrypted~=clear_text)
|
||||||
|
print("auth tag: "..string2hex(atag2))
|
||||||
|
print( atag==atag2 and "TAG OK" or "TAG ERROR" )
|
||||||
|
test_assert(atag~=atag2)
|
||||||
|
|
||||||
|
print("* decrypting good payload with good key, bad iv and correct authentication data")
|
||||||
|
decrypted, atag2 = aes_gcm(false, key, brandom(12), encrypted, authenticated_data)
|
||||||
|
print("decrypted: "..str_or_hex(decrypted))
|
||||||
|
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||||
|
test_assert(decrypted~=clear_text)
|
||||||
|
print("auth tag: "..string2hex(atag2))
|
||||||
|
print( atag==atag2 and "TAG OK" or "TAG ERROR" )
|
||||||
|
test_assert(atag~=atag2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_aes_ctr()
|
||||||
|
local clear_text="test message "..brandom_az09(math.random(10,50))
|
||||||
|
local iv, key, encrypted, decrypted
|
||||||
|
|
||||||
|
for key_size=16,32,8 do
|
||||||
|
iv = brandom(16)
|
||||||
|
key = brandom(key_size)
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("* aes_ctr test key_size "..tostring(key_size))
|
||||||
|
|
||||||
|
print("clear text: "..clear_text);
|
||||||
|
|
||||||
|
print("* encrypting")
|
||||||
|
encrypted = aes_ctr(key, iv, clear_text)
|
||||||
|
print("encrypted: "..str_or_hex(encrypted))
|
||||||
|
|
||||||
|
print("* decrypting")
|
||||||
|
decrypted = aes_ctr(key, iv, encrypted)
|
||||||
|
print("decrypted: "..str_or_hex(decrypted))
|
||||||
|
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||||
|
test_assert(decrypted==clear_text)
|
||||||
|
|
||||||
|
print("* decrypting with bad key")
|
||||||
|
decrypted = aes_ctr(bu8(bitand(u8(string.sub(key,1,1))+1,0xFF))..string.sub(key,2), iv, encrypted)
|
||||||
|
print("decrypted: "..str_or_hex(decrypted))
|
||||||
|
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||||
|
test_assert(decrypted~=clear_text)
|
||||||
|
|
||||||
|
print("* decrypting with bad iv")
|
||||||
|
decrypted = aes_ctr(key, bu8(bitand(u8(string.sub(iv,1,1))+1,0xFF))..string.sub(iv,2), encrypted)
|
||||||
|
print("decrypted: "..str_or_hex(decrypted))
|
||||||
|
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||||
|
test_assert(decrypted~=clear_text)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- openssl enc -aes-256-ctr -d -in rnd.bin -out rnd_decrypted.bin -K c39383634d87eb3b6e56edf2c8c0ba99cc8cadf000fb2cd737e37947eecde5fd -iv d745164b233f10b93945526ffe94b87f
|
||||||
|
print("* aes_ctr const tests")
|
||||||
|
|
||||||
|
local data="\x9d\x9c\xa0\x78\x2e\x17\x84\xfc\x87\xc7\xf5\xdf\x5b\xb5\x71\xfd\xb9\xcb\xd2\x4d\xae\x2f\xf0\x19\xf3\xad\x79\xa8\x9a\xb4\xed\x28\x88\x3c\xe1\x78\x91\x23\x27\xd4\x8d\x94\xb3\xd0\x81\x88\xd2\x55\x95\x8a\x88\x70\x67\x99\x75\xb2\xee\x30\x0f\xe7\xc6\x32\x10"
|
||||||
|
local iv="\xd7\x45\x16\x4b\x23\x3f\x10\xb9\x39\x45\x52\x6f\xfe\x94\xb8\x7f"
|
||||||
|
local tests = {
|
||||||
|
{
|
||||||
|
key="\xc3\x93\x83\x63\x4d\x87\xeb\x3b\x6e\x56\xed\xf2\xc8\xc0\xba\x99\xcc\x8c\xad\xf0\x00\xfb\x2c\xd7\x37\xe3\x79\x47\xee\xcd\xe5\xfd",
|
||||||
|
result="\x8C\x2C\x15\x99\x83\x37\x33\xEE\xA1\x70\xA7\x4A\x44\x2E\x6F\x56\x22\x41\xE1\xFC\xC5\x84\x21\x1C\x16\xC6\xE9\x75\x22\x57\x55\x4A\x02\x04\xCE\xAD\xE9\x0A\x45\xAB\x4E\x38\xB8\xB2\x6F\x95\xDA\x46\x4F\x9E\xB1\xFF\xF4\x40\x8A\x57\x25\xD2\xF6\xB6\x93\x65\x75"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key="\xc3\x93\x83\x63\x4d\x87\xeb\x3b\x6e\x56\xed\xf2\xc8\xc0\xba\x99\xcc\x8c\xad\xf0\x00\xfb\x2c\xd7",
|
||||||
|
result="\xB0\x4C\xC9\xDB\x0C\xE5\x67\x51\x1D\x24\x3C\x15\x87\x1B\xF9\x62\x84\x8C\xD0\x57\x33\x93\xE0\x71\x91\x3A\x11\x26\xCA\x77\xA7\x54\xBD\xC6\x5E\x96\x60\x2C\x94\x0F\xBA\x3E\x79\xDC\x48\xA0\x22\x97\xA7\x77\x55\xC8\x14\xEA\xC2\xF5\xA0\x88\x6F\xE2\x44\x32\x68"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key="\xc3\x93\x83\x63\x4d\x87\xeb\x3b\x6e\x56\xed\xf2\xc8\xc0\xba\x99",
|
||||||
|
result="\xD9\xAC\xC7\x7D\xC8\xC9\xF1\x59\x9A\xDF\x15\xF3\x58\x61\xFD\x2B\x1D\x01\x9A\x5F\x04\x53\xA2\xA8\xFD\x52\xDC\x8A\xE9\x3B\x2E\x5E\x0D\x13\xCB\xBD\x16\xED\xC1\xF2\x0D\x68\x62\xB7\xD5\x0F\x8D\xD4\xEB\xA1\xC5\x75\xF2\x0B\x26\x75\x1D\x7E\x5A\x37\xA6\x8A\xCD"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k,t in pairs(tests) do
|
||||||
|
local decrypted = aes_ctr(t.key, iv, data)
|
||||||
|
io.write("KEY SIZE "..(#t.key*8).." ")
|
||||||
|
print( decrypted==t.result and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||||
|
test_assert(decrypted==t.result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_ub()
|
||||||
|
for k,f in pairs({{u8,bu8,0xFF,8}, {u16,bu16,0xFFFF,16}, {u24,bu24,0xFFFFFF,24}, {u32,bu32,0xFFFFFFFF,32}}) do
|
||||||
|
local v = math.random(0,f[3])
|
||||||
|
local pos = math.random(1,20)
|
||||||
|
local s = brandom(pos-1)..f[2](v)..brandom(20)
|
||||||
|
local v2 = f[1](s,pos)
|
||||||
|
print("u"..tostring(f[4]).." pos="..tostring(pos).." "..tostring(v).." "..tostring(v2))
|
||||||
|
test_assert(v==v2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_bit()
|
||||||
|
local v, v2, v3, v4, b1, b2, pow
|
||||||
|
|
||||||
|
v = math.random(0,0xFFFFFFFF)
|
||||||
|
b1 = math.random(1,16)
|
||||||
|
|
||||||
|
v2 = bitrshift(v, b1)
|
||||||
|
pow = 2^b1
|
||||||
|
v3 = divint(v, pow)
|
||||||
|
print(string.format("rshift(0x%X,%u) = 0x%X 0x%X/%u = 0x%X", v,b1,v2, v,pow,v3))
|
||||||
|
test_assert(v2==v3)
|
||||||
|
|
||||||
|
v2 = bitlshift(v, b1)
|
||||||
|
pow = 2^b1
|
||||||
|
v3 = (v * pow) % 0x100000000
|
||||||
|
print(string.format("lshift(0x%X,%u) = 0x%X 0x%X*%u %% 0x10000000 = 0x%X", v,b1,v2, v,pow,v3))
|
||||||
|
test_assert(v2==v3)
|
||||||
|
|
||||||
|
v2 = math.random(0,0xFFFFFFFF)
|
||||||
|
v3 = bitxor(v, v2)
|
||||||
|
v4 = bitor(v, v2) - bitand(v, v2)
|
||||||
|
print(string.format("xor(0x%X,0x%X) = %X or/and/minus = %X", v, v2, v3, v4))
|
||||||
|
test_assert(v3==v4)
|
||||||
|
|
||||||
|
b2 = b1 + math.random(1,15)
|
||||||
|
v2 = bitget(v, b1, b2)
|
||||||
|
pow = 2^(b2-b1+1) - 1
|
||||||
|
v3 = bitand(bitrshift(v,b1), pow)
|
||||||
|
print(string.format("bitget(0x%X,%u,%u) = 0x%X bitand/bitrshift/pow = 0x%X", v, b1, b2, v2, v3))
|
||||||
|
test_assert(v2==v3)
|
||||||
|
|
||||||
|
v4 = math.random(0,pow)
|
||||||
|
v2 = bitset(v, b1, b2, v4)
|
||||||
|
v3 = bitor(bitlshift(v4, b1), bitand(v, bitnot(bitlshift(pow, b1))))
|
||||||
|
print(string.format("bitset(0x%X,%u,%u,0x%X) = 0x%X bitand/bitnot/bitlshift/pow = 0x%X", v, b1, b2, v4, v2, v3))
|
||||||
|
test_assert(v2==v3)
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_ux()
|
||||||
|
local v1, v2, v3, usum, sum
|
||||||
|
for k,test in pairs({
|
||||||
|
{ add=u8add, fname="u8add", max = 0xFF },
|
||||||
|
{ add=u16add, fname="u16add", max = 0xFFFF },
|
||||||
|
{ add=u24add, fname="u24add", max = 0xFFFFFF },
|
||||||
|
{ add=u32add, fname="u32add", max = 0xFFFFFFFF }
|
||||||
|
}) do
|
||||||
|
io.write(test.fname.." : ")
|
||||||
|
for i=1,1000 do
|
||||||
|
v1=math.random(-test.max,test.max)
|
||||||
|
v2=math.random(-test.max,test.max)
|
||||||
|
v3=math.random(-test.max,test.max)
|
||||||
|
usum = test.add(v1,v2,v3)
|
||||||
|
sum = bitand((v1+v2+v3)%(test.max+1),test.max)
|
||||||
|
if sum~=usum then
|
||||||
|
print("FAIL")
|
||||||
|
end
|
||||||
|
test_assert(sum==usum)
|
||||||
|
end
|
||||||
|
print("OK")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_bin(...)
|
||||||
|
test_run({test_ub, test_bit, test_ux},...)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function test_ipstr()
|
||||||
|
local s_ip, ip, s_ip2
|
||||||
|
|
||||||
|
s_ip = string.format("%u.%u.%u.%u", math.random(0,255), math.random(0,255), math.random(0,255), math.random(0,255));
|
||||||
|
ip = pton(s_ip)
|
||||||
|
s_ip2 = ntop(ip)
|
||||||
|
print("IP: "..s_ip)
|
||||||
|
print("IPBIN: "..string2hex(ip))
|
||||||
|
print("IP2: "..s_ip2)
|
||||||
|
test_assert(s_ip==s_ip2)
|
||||||
|
|
||||||
|
s_ip = string.format("%x:%x:%x:%x:%x:%x:%x:%x", math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF));
|
||||||
|
ip = pton(s_ip)
|
||||||
|
s_ip2 = ntop(ip)
|
||||||
|
print("IP: "..s_ip)
|
||||||
|
print("IPBIN: "..string2hex(ip))
|
||||||
|
print("IP2: "..s_ip2)
|
||||||
|
test_assert(s_ip==s_ip2)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function test_dissect()
|
||||||
|
local dis, raw1, raw2
|
||||||
|
|
||||||
|
for i=1,20 do
|
||||||
|
print("* dissect test "..tostring(i))
|
||||||
|
|
||||||
|
local ip_tcp = {
|
||||||
|
ip = {
|
||||||
|
ip_tos = math.random(0,255),
|
||||||
|
ip_id = math.random(0,0xFFFF),
|
||||||
|
ip_off = 0,
|
||||||
|
ip_ttl = math.random(0,255),
|
||||||
|
ip_p = IPPROTO_TCP,
|
||||||
|
ip_src = brandom(4),
|
||||||
|
ip_dst = brandom(4),
|
||||||
|
options = brandom(math.random(0,40))
|
||||||
|
},
|
||||||
|
tcp = {
|
||||||
|
th_sport = math.random(0,0xFFFF),
|
||||||
|
th_dport = math.random(0,0xFFFF),
|
||||||
|
th_seq = math.random(0,0xFFFFFFFF),
|
||||||
|
th_ack = math.random(0,0xFFFFFFFF),
|
||||||
|
th_x2 = math.random(0,0xF),
|
||||||
|
th_flags = math.random(0,0xFF),
|
||||||
|
th_win = math.random(0,0xFFFF),
|
||||||
|
th_urp = math.random(0,0xFFFF),
|
||||||
|
options = {
|
||||||
|
{ kind = 1 },
|
||||||
|
{ kind = 0xE0, data = brandom(math.random(1,10)) },
|
||||||
|
{ kind = 1 },
|
||||||
|
{ kind = 0xE1, data = brandom(math.random(1,10)) },
|
||||||
|
{ kind = 0 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
payload = brandom(math.random(0, 20))
|
||||||
|
}
|
||||||
|
raw1 = reconstruct_dissect(ip_tcp)
|
||||||
|
print("IP+TCP : "..string2hex(raw1))
|
||||||
|
dis1 = dissect(raw1);
|
||||||
|
raw2 = reconstruct_dissect(dis1)
|
||||||
|
dis2 = dissect(raw2);
|
||||||
|
print("IP+TCP2: "..string2hex(raw2))
|
||||||
|
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
|
||||||
|
test_assert(raw1==raw2)
|
||||||
|
|
||||||
|
local ip6_udp = {
|
||||||
|
ip6 = {
|
||||||
|
ip6_flow = 0x60000000 + math.random(0,0xFFFFFFF),
|
||||||
|
ip6_hlim = math.random(1,0xFF),
|
||||||
|
ip6_src = brandom(16),
|
||||||
|
ip6_dst = brandom(16),
|
||||||
|
exthdr = {
|
||||||
|
{ type = IPPROTO_HOPOPTS, data = brandom(6+8*math.random(0,2)) },
|
||||||
|
{ type = IPPROTO_AH, data = brandom(6+4*math.random(0,4)) }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
udp = {
|
||||||
|
uh_sport = math.random(0,0xFFFF),
|
||||||
|
uh_dport = math.random(0,0xFFFF)
|
||||||
|
},
|
||||||
|
payload = brandom(math.random(0, 20))
|
||||||
|
}
|
||||||
|
|
||||||
|
raw1 = reconstruct_dissect(ip6_udp)
|
||||||
|
print("IP6+UDP : "..string2hex(raw1))
|
||||||
|
dis1 = dissect(raw1);
|
||||||
|
raw2 = reconstruct_dissect(dis1)
|
||||||
|
dis2 = dissect(raw2);
|
||||||
|
print("IP6+UDP2: "..string2hex(raw2))
|
||||||
|
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
|
||||||
|
test_assert(raw1==raw2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_csum()
|
||||||
|
local payload = brandom(math.random(10,20))
|
||||||
|
local ip4b, ip6b, raw, tcpb, udpb, dis1, dis2
|
||||||
|
local ip = {
|
||||||
|
ip_tos = math.random(0,255),
|
||||||
|
ip_id = math.random(0,0xFFFF),
|
||||||
|
ip_len = math.random(0,0xFFFF),
|
||||||
|
ip_off = 0,
|
||||||
|
ip_ttl = math.random(0,255),
|
||||||
|
ip_p = IPPROTO_TCP,
|
||||||
|
ip_src = brandom(4),
|
||||||
|
ip_dst = brandom(4),
|
||||||
|
options = brandom(4*math.random(0,10))
|
||||||
|
}
|
||||||
|
ip4b = reconstruct_iphdr(ip)
|
||||||
|
raw = bu8(0x40 + 5 + #ip.options/4) ..
|
||||||
|
bu8(ip.ip_tos) ..
|
||||||
|
bu16(ip.ip_len) ..
|
||||||
|
bu16(ip.ip_id) ..
|
||||||
|
bu16(ip.ip_off) ..
|
||||||
|
bu8(ip.ip_ttl) ..
|
||||||
|
bu8(ip.ip_p) ..
|
||||||
|
bu16(0) ..
|
||||||
|
ip.ip_src .. ip.ip_dst ..
|
||||||
|
ip.options
|
||||||
|
raw = csum_ip4_fix(raw)
|
||||||
|
print( raw==ip4b and "IP4 RECONSTRUCT+CSUM OK" or "IP4 RECONSTRUCT+CSUM FAILED" )
|
||||||
|
test_assert(raw==ip4b)
|
||||||
|
|
||||||
|
|
||||||
|
local tcp = {
|
||||||
|
th_sport = math.random(0,0xFFFF),
|
||||||
|
th_dport = math.random(0,0xFFFF),
|
||||||
|
th_seq = math.random(0,0xFFFFFFFF),
|
||||||
|
th_ack = math.random(0,0xFFFFFFFF),
|
||||||
|
th_x2 = math.random(0,0xF),
|
||||||
|
th_flags = math.random(0,0xFF),
|
||||||
|
th_win = math.random(0,0xFFFF),
|
||||||
|
th_urp = math.random(0,0xFFFF),
|
||||||
|
options = {
|
||||||
|
{ kind = 1 },
|
||||||
|
{ kind = 0xE0, data = brandom(math.random(1,10)) },
|
||||||
|
{ kind = 1 },
|
||||||
|
{ kind = 0xE1, data = brandom(math.random(1,10)) },
|
||||||
|
{ kind = 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tcpb = reconstruct_tcphdr(tcp)
|
||||||
|
raw = bu16(tcp.th_sport) ..
|
||||||
|
bu16(tcp.th_dport) ..
|
||||||
|
bu32(tcp.th_seq) ..
|
||||||
|
bu32(tcp.th_ack) ..
|
||||||
|
bu8(l4_len({tcp = tcp}) * 4 + tcp.th_x2) ..
|
||||||
|
bu8(tcp.th_flags) ..
|
||||||
|
bu16(tcp.th_win) ..
|
||||||
|
bu16(0) ..
|
||||||
|
bu16(tcp.th_urp) ..
|
||||||
|
bu8(tcp.options[1].kind)..
|
||||||
|
bu8(tcp.options[2].kind)..bu8(2 + #tcp.options[2].data)..tcp.options[2].data ..
|
||||||
|
bu8(tcp.options[3].kind)..
|
||||||
|
bu8(tcp.options[4].kind)..bu8(2 + #tcp.options[4].data)..tcp.options[4].data ..
|
||||||
|
bu8(tcp.options[5].kind)
|
||||||
|
raw = raw .. string.rep(bu8(TCP_KIND_NOOP), bitand(4-bitand(#raw,3),3))
|
||||||
|
print( raw==tcpb and "TCP RECONSTRUCT OK" or "TCP RECONSTRUCT FAILED" )
|
||||||
|
test_assert(raw==tcpb)
|
||||||
|
|
||||||
|
raw = reconstruct_dissect({ip=ip, tcp=tcp, payload=payload})
|
||||||
|
dis1 = dissect(raw)
|
||||||
|
tcpb = csum_tcp_fix(ip4b,tcpb,payload)
|
||||||
|
dis2 = dissect(ip4b..tcpb..payload)
|
||||||
|
print( dis1.tcp.th_sum==dis2.tcp.th_sum and "TCP+IP4 CSUM OK" or "TCP+IP4 CSUM FAILED" )
|
||||||
|
test_assert(dis1.tcp.th_sum==dis2.tcp.th_sum)
|
||||||
|
|
||||||
|
|
||||||
|
local ip6 = {
|
||||||
|
ip6_flow = 0x60000000 + math.random(0,0xFFFFFFF),
|
||||||
|
ip6_hlim = math.random(1,0xFF),
|
||||||
|
ip6_src = brandom(16),
|
||||||
|
ip6_dst = brandom(16),
|
||||||
|
exthdr = {
|
||||||
|
{ type = IPPROTO_HOPOPTS, data = brandom(6+8*math.random(0,2)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ip6.ip6_plen = packet_len({ip6=ip6,tcp=tcp,payload=payload}) - IP6_BASE_LEN
|
||||||
|
ip6b = reconstruct_ip6hdr(ip6, {ip6_last_proto=IPPROTO_TCP})
|
||||||
|
raw = bu32(ip6.ip6_flow) ..
|
||||||
|
bu16(ip6.ip6_plen) ..
|
||||||
|
bu8(ip6.exthdr[1].type) ..
|
||||||
|
bu8(ip6.ip6_hlim) ..
|
||||||
|
ip6.ip6_src .. ip6.ip6_dst ..
|
||||||
|
bu8(IPPROTO_TCP) ..
|
||||||
|
bu8((#ip6.exthdr[1].data+2)/8 - 1) ..
|
||||||
|
ip6.exthdr[1].data
|
||||||
|
print( raw==ip6b and "IP6 RECONSTRUCT OK" or "IP6 RECONSTRUCT FAILED" )
|
||||||
|
test_assert(raw==ip6b)
|
||||||
|
|
||||||
|
raw = reconstruct_dissect({ip6=ip6, tcp=tcp, payload=payload})
|
||||||
|
dis1 = dissect(raw)
|
||||||
|
tcpb = csum_tcp_fix(ip6b,tcpb,payload)
|
||||||
|
dis2 = dissect(ip6b..tcpb..payload)
|
||||||
|
print( dis1.tcp.th_sum==dis2.tcp.th_sum and "TCP+IP6 CSUM OK" or "TCP+IP6 CSUM FAILED" )
|
||||||
|
test_assert(dis1.tcp.th_sum==dis2.tcp.th_sum)
|
||||||
|
|
||||||
|
|
||||||
|
ip.ip_p = IPPROTO_UDP
|
||||||
|
ip4b = reconstruct_iphdr(ip)
|
||||||
|
ip6.ip6_plen = packet_len({ip6=ip6,udp=udp,payload=payload}) - IP6_BASE_LEN
|
||||||
|
ip6b = reconstruct_ip6hdr(ip6, {ip6_last_proto=IPPROTO_UDP})
|
||||||
|
|
||||||
|
local udp = {
|
||||||
|
uh_sport = math.random(0,0xFFFF),
|
||||||
|
uh_dport = math.random(0,0xFFFF),
|
||||||
|
uh_ulen = UDP_BASE_LEN + #payload
|
||||||
|
}
|
||||||
|
|
||||||
|
udpb = reconstruct_udphdr(udp)
|
||||||
|
raw = bu16(udp.uh_sport) ..
|
||||||
|
bu16(udp.uh_dport) ..
|
||||||
|
bu16(udp.uh_ulen) ..
|
||||||
|
bu16(0)
|
||||||
|
print( raw==udpb and "UDP RECONSTRUCT OK" or "UDP RECONSTRUCT FAILED" )
|
||||||
|
test_assert(raw==udpb)
|
||||||
|
|
||||||
|
raw = reconstruct_dissect({ip=ip, udp=udp, payload=payload})
|
||||||
|
dis1 = dissect(raw)
|
||||||
|
udpb = csum_udp_fix(ip4b,udpb,payload)
|
||||||
|
dis2 = dissect(ip4b..udpb..payload)
|
||||||
|
print( dis1.udp.uh_sum==dis2.udp.uh_sum and "UDP+IP4 CSUM OK" or "UDP+IP4 CSUM FAILED" )
|
||||||
|
test_assert(dis1.udp.uh_sum==dis2.udp.uh_sum)
|
||||||
|
|
||||||
|
raw = reconstruct_dissect({ip6=ip6, udp=udp, payload=payload})
|
||||||
|
dis1 = dissect(raw)
|
||||||
|
udpb = csum_udp_fix(ip6b,udpb,payload)
|
||||||
|
dis2 = dissect(ip6b..udpb..payload)
|
||||||
|
print( dis1.udp.uh_sum==dis2.udp.uh_sum and "UDP+IP6 CSUM OK" or "UDP+IP6 CSUM FAILED" )
|
||||||
|
test_assert(dis1.udp.uh_sum==dis2.udp.uh_sum)
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_resolve()
|
||||||
|
local pos
|
||||||
|
|
||||||
|
pos = zero_based_pos(resolve_multi_pos(fake_default_tls,"tls_client_hello","1,extlen,sniext,host,sld,midsld,endsld,endhost,-5"))
|
||||||
|
test_assert(pos)
|
||||||
|
print("resolve_multi_pos tls : "..table.concat(pos," "))
|
||||||
|
pos = zero_based_pos(resolve_range(fake_default_tls,"tls_client_hello","host,endhost"))
|
||||||
|
test_assert(pos)
|
||||||
|
print("resolve_range tls : "..table.concat(pos," "))
|
||||||
|
pos = resolve_pos(fake_default_tls,"tls_client_hello","midsld")
|
||||||
|
test_assert(pos)
|
||||||
|
print("resolve_pos tls : "..pos - 1)
|
||||||
|
pos = resolve_pos(fake_default_tls,"tls_client_hello","method")
|
||||||
|
test_assert(not pos)
|
||||||
|
print("resolve_pos tls non-existent : "..tostring(pos))
|
||||||
|
|
||||||
|
pos = zero_based_pos(resolve_multi_pos(fake_default_http,"http_req","method,host,sld,midsld,endsld,endhost,-5"))
|
||||||
|
test_assert(pos)
|
||||||
|
print("resolve_multi_pos http : "..table.concat(pos," "))
|
||||||
|
pos = resolve_pos(fake_default_http,"http_req","sniext")
|
||||||
|
test_assert(not pos)
|
||||||
|
print("resolve_pos http non-existent : "..tostring(pos))
|
||||||
|
end
|
||||||
|
|
||||||
|
function test_rawsend(opts)
|
||||||
|
local ifout = (opts and opts.ifout) and opts.ifout
|
||||||
|
local function rawsend_fail_warning()
|
||||||
|
if not opts or not opts.ifout or #opts.ifout==0 then
|
||||||
|
local un = uname()
|
||||||
|
if string.sub(un.sysname,1,6)=="CYGWIN" then
|
||||||
|
print("windivert requires interface name in the form '<int>.<int>'. take it from winws2 output with '--debug' option and call test_rawsend({ifout=interface_name})")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function rawsend_dissect_print(dis, options)
|
||||||
|
if options then
|
||||||
|
options.ifout = ifout
|
||||||
|
else
|
||||||
|
options = { ifout = ifout }
|
||||||
|
end
|
||||||
|
local b = rawsend_dissect(dis, options)
|
||||||
|
if not b then
|
||||||
|
print("rawsend_dissect failed")
|
||||||
|
rawsend_fail_warning()
|
||||||
|
end
|
||||||
|
return b
|
||||||
|
end
|
||||||
|
local function rawsend_print(raw, options)
|
||||||
|
if options then
|
||||||
|
options.ifout = ifout
|
||||||
|
else
|
||||||
|
options = { ifout = ifout }
|
||||||
|
end
|
||||||
|
print("rawsend: "..string2hex(raw))
|
||||||
|
local b = rawsend(raw, options)
|
||||||
|
if not b then
|
||||||
|
print("rawsend failed")
|
||||||
|
rawsend_fail_warning()
|
||||||
|
end
|
||||||
|
return b
|
||||||
|
end
|
||||||
|
local ip, ip6, udp, dis, ddis, raw_ip, raw_udp, raw
|
||||||
|
local payload = brandom(math.random(100,1200))
|
||||||
|
local b
|
||||||
|
|
||||||
|
ip = {
|
||||||
|
ip_tos = 0,
|
||||||
|
ip_id = math.random(0,0xFFFF),
|
||||||
|
ip_off = 0,
|
||||||
|
ip_ttl = 1,
|
||||||
|
ip_p = IPPROTO_UDP,
|
||||||
|
ip_src = pton("192.168.1.1"),
|
||||||
|
ip_dst = pton("192.168.1.2")
|
||||||
|
}
|
||||||
|
udp = {
|
||||||
|
uh_sport = math.random(0,0xFFFF),
|
||||||
|
uh_dport = math.random(0,0xFFFF)
|
||||||
|
}
|
||||||
|
dis = {ip = ip, udp = udp, payload = payload}
|
||||||
|
print("send ipv4 udp")
|
||||||
|
test_assert(rawsend_dissect_print(dis, {repeats=3}))
|
||||||
|
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80})
|
||||||
|
for k,d in pairs(ddis) do
|
||||||
|
print("send ipv4 udp frag "..k)
|
||||||
|
test_assert(rawsend_dissect_print(d))
|
||||||
|
end
|
||||||
|
|
||||||
|
local ip2=ip
|
||||||
|
ip2.ip_len = IP_BASE_LEN + UDP_BASE_LEN + #payload
|
||||||
|
raw_ip = reconstruct_iphdr(ip2)
|
||||||
|
raw_udp = reconstruct_udphdr({uh_sport = udp.uh_sport, uh_dport = udp.uh_dport, uh_ulen = UDP_BASE_LEN + #payload})
|
||||||
|
raw_udp = csum_udp_fix(raw_ip,raw_udp,payload)
|
||||||
|
raw = raw_ip .. raw_udp .. payload
|
||||||
|
print("send ipv4 udp using pure rawsend without dissect")
|
||||||
|
test_assert(rawsend_print(raw, {repeats=5}))
|
||||||
|
|
||||||
|
ip6 = {
|
||||||
|
ip6_flow = 0x60000000,
|
||||||
|
ip6_hlim = 1,
|
||||||
|
ip6_src = pton("fdce:3124:164a:5318::1"),
|
||||||
|
ip6_dst = pton("fdce:3124:164a:5318::2")
|
||||||
|
}
|
||||||
|
dis = {ip6 = ip6, udp = udp, payload = payload}
|
||||||
|
print("send ipv6 udp")
|
||||||
|
test_assert(rawsend_dissect_print(dis, {repeats=3}))
|
||||||
|
|
||||||
|
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80})
|
||||||
|
for k,d in pairs(ddis) do
|
||||||
|
print("send ipv6 udp frag "..k)
|
||||||
|
test_assert(rawsend_dissect_print(d))
|
||||||
|
end
|
||||||
|
|
||||||
|
ip6.exthdr={{ type = IPPROTO_HOPOPTS, data = "\x00\x00\x00\x00\x00\x00" }}
|
||||||
|
print("send ipv6 udp with hopbyhop ext header")
|
||||||
|
test_assert(rawsend_dissect_print(dis, {repeats=3}))
|
||||||
|
|
||||||
|
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80})
|
||||||
|
for k,d in pairs(ddis) do
|
||||||
|
print("send ipv6 udp frag "..k.." with hopbyhop ext header")
|
||||||
|
test_assert(rawsend_dissect_print(d))
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(ip6.exthdr, { type = IPPROTO_DSTOPTS, data = "\x00\x00\x00\x00\x00\x00" })
|
||||||
|
table.insert(ip6.exthdr, { type = IPPROTO_DSTOPTS, data = "\x00\x00\x00\x00\x00\x00" })
|
||||||
|
ip6.ip6_flow = 0x60001234;
|
||||||
|
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80})
|
||||||
|
for k,d in pairs(ddis) do
|
||||||
|
print("send ipv6 udp frag "..k.." with hopbyhop, destopt ext headers in unfragmentable part and another destopt ext header in fragmentable part")
|
||||||
|
test_assert(rawsend_dissect_print(d, {fwmark = 0x50EA}))
|
||||||
|
end
|
||||||
|
|
||||||
|
fix_ip6_next(ip6) -- required to forge next proto in the second fragment
|
||||||
|
ip6.ip6_flow = 0x6000AE38;
|
||||||
|
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80, ipfrag_next = IPPROTO_TCP})
|
||||||
|
for k,d in pairs(ddis) do
|
||||||
|
print("send ipv6 udp frag "..k.." with hopbyhop, destopt ext headers in unfragmentable part and another destopt ext header in fragmentable part. forge next proto in fragment header of the second fragment to TCP")
|
||||||
|
-- reconstruct dissect using next proto fields in the dissect. do not auto fix next proto chain.
|
||||||
|
-- by default reconstruct fixes next proto chain
|
||||||
|
test_assert(rawsend_dissect_print(d, {fwmark = 0x409A, repeats=2}, {ip6_preserve_next = true}))
|
||||||
|
end
|
||||||
|
end
|
||||||
79
blockcheck/zapret2/lua/zapret-wgobfs.lua
Normal file
79
blockcheck/zapret2/lua/zapret-wgobfs.lua
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
-- test case : nfqws2 --qnum 200 --debug --lua-init=@zapret-wgobfs.lua --in-range=a --out-range=a --lua-desync=wgobfs:secret=mycoolpassword
|
||||||
|
-- encrypt standard wireguard messages - initiation, response, cookie - and change udp packet size
|
||||||
|
-- do not encrypt data messages and keepalives
|
||||||
|
-- wgobfs adds maximum of 30+padmax bytes to udp size
|
||||||
|
-- reduce MTU of wireguard interface to avoid ip fragmentation !
|
||||||
|
-- without knowing the secret encrypted packets should be crypto strong white noise with no signature
|
||||||
|
-- arg : secret - shared secret. any string. must be the same on both peers
|
||||||
|
-- arg : padmin - min random garbage bytes. 0 by default
|
||||||
|
-- arg : padmax - max random garbage bytes. 16 by default
|
||||||
|
function wgobfs(ctx, desync)
|
||||||
|
local padmin = desync.arg.padmin and tonumber(desync.arg.padmin) or 0
|
||||||
|
local padmax = desync.arg.padmax and tonumber(desync.arg.padmax) or 16
|
||||||
|
local function genkey()
|
||||||
|
-- cache key in a global var bound to instance name
|
||||||
|
local key_cache_name = desync.func_instance.."_key"
|
||||||
|
key = _G[key_cache_name]
|
||||||
|
if not key then
|
||||||
|
key = hkdf("sha256", "wgobfs_salt", desync.arg.secret, nil, 16)
|
||||||
|
_G[key_cache_name] = key
|
||||||
|
end
|
||||||
|
return key
|
||||||
|
end
|
||||||
|
local function maybe_encrypted_payload(payload)
|
||||||
|
for k,plsize in pairs({2+12+16+148, 2+12+16+92, 2+12+16+64}) do
|
||||||
|
if #payload>=(plsize+padmin) and #payload<=(plsize+padmax) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local function wg_payload_from_size(payload)
|
||||||
|
if #payload==148 then return "wireguard_initiation"
|
||||||
|
elseif #payload==92 then return "wireguard_response"
|
||||||
|
elseif #payload==64 then return "wireguard_cookie"
|
||||||
|
else return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not desync.dis.udp then
|
||||||
|
instance_cutoff(ctx)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not desync.arg.secret or #desync.arg.secret==0 then
|
||||||
|
error("wgobfs requires secret")
|
||||||
|
end
|
||||||
|
if padmin>padmax then
|
||||||
|
error("wgobfs: padmin>padmax")
|
||||||
|
end
|
||||||
|
if desync.l7payload=="wireguard_initiation" or desync.l7payload=="wireguard_response" or desync.l7payload=="wireguard_cookie" and #desync.dis.payload<65506 then
|
||||||
|
DLOG("wgobfs: encrypting '"..desync.l7payload.."'. size "..#desync.dis.payload)
|
||||||
|
local key = genkey()
|
||||||
|
-- in aes-gcm every message require it's own crypto secure random iv
|
||||||
|
-- encrypting more than one message with the same iv is considered catastrophic failure
|
||||||
|
-- iv must be sent with encrypted message
|
||||||
|
local iv = bcryptorandom(12)
|
||||||
|
local encrypted, atag = aes_gcm(true, key, iv, bu16(#desync.dis.payload)..desync.dis.payload..brandom(math.random(padmin,padmax)), nil)
|
||||||
|
desync.dis.payload = iv..atag..encrypted
|
||||||
|
return VERDICT_MODIFY
|
||||||
|
end
|
||||||
|
|
||||||
|
if desync.l7payload=="unknown" and maybe_encrypted_payload(desync.dis.payload) then
|
||||||
|
local key = genkey()
|
||||||
|
local iv = string.sub(desync.dis.payload,1,12)
|
||||||
|
local atag = string.sub(desync.dis.payload,13,28)
|
||||||
|
local decrypted, atag2 = aes_gcm(false, key, iv, string.sub(desync.dis.payload,29))
|
||||||
|
if atag==atag2 then
|
||||||
|
local plen = u16(decrypted)
|
||||||
|
if plen>(#decrypted-2) then
|
||||||
|
DLOG("wgobfs: bad decrypted payload data")
|
||||||
|
else
|
||||||
|
desync.dis.payload = string.sub(decrypted, 3, 3+plen-1)
|
||||||
|
if b_debug then DLOG("wgobfs: decrypted '"..(wg_payload_from_size(desync.dis.payload) or "unknown").."' message. size "..plen) end
|
||||||
|
return VERDICT_MODIFY
|
||||||
|
end
|
||||||
|
else
|
||||||
|
DLOG("wgobfs: decrypt auth tag mismatch")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
BIN
blockcheck/zapret2/mdig/mdig.exe
Normal file
BIN
blockcheck/zapret2/mdig/mdig.exe
Normal file
Binary file not shown.
BIN
blockcheck/zapret2/nfq2/WinDivert.dll
Normal file
BIN
blockcheck/zapret2/nfq2/WinDivert.dll
Normal file
Binary file not shown.
BIN
blockcheck/zapret2/nfq2/WinDivert64.sys
Normal file
BIN
blockcheck/zapret2/nfq2/WinDivert64.sys
Normal file
Binary file not shown.
BIN
blockcheck/zapret2/nfq2/winws2.exe
Normal file
BIN
blockcheck/zapret2/nfq2/winws2.exe
Normal file
Binary file not shown.
BIN
cygwin/bin/[.exe
Normal file
BIN
cygwin/bin/[.exe
Normal file
Binary file not shown.
BIN
cygwin/bin/arch.exe
Normal file
BIN
cygwin/bin/arch.exe
Normal file
Binary file not shown.
3
cygwin/bin/awk
Normal file
3
cygwin/bin/awk
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
exec gawk "$@"
|
||||||
BIN
cygwin/bin/basename.exe
Normal file
BIN
cygwin/bin/basename.exe
Normal file
Binary file not shown.
BIN
cygwin/bin/bash.exe
Normal file
BIN
cygwin/bin/bash.exe
Normal file
Binary file not shown.
BIN
cygwin/bin/bunzip2.exe
Normal file
BIN
cygwin/bin/bunzip2.exe
Normal file
Binary file not shown.
BIN
cygwin/bin/bzcat.exe
Normal file
BIN
cygwin/bin/bzcat.exe
Normal file
Binary file not shown.
85
cygwin/bin/bzgrep
Normal file
85
cygwin/bin/bzgrep
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Bzgrep wrapped for bzip2,
|
||||||
|
# adapted from zgrep by Philippe Troin <phil@fifi.org> for Debian GNU/Linux.
|
||||||
|
## zgrep notice:
|
||||||
|
## zgrep -- a wrapper around a grep program that decompresses files as needed
|
||||||
|
## Adapted from a version sent by Charles Levert <charles@comm.polymtl.ca>
|
||||||
|
|
||||||
|
PATH="/usr/bin:$PATH"; export PATH
|
||||||
|
|
||||||
|
prog=`echo $0 | sed 's|.*/||'`
|
||||||
|
case "$prog" in
|
||||||
|
*egrep) grep=${EGREP-egrep} ;;
|
||||||
|
*fgrep) grep=${FGREP-fgrep} ;;
|
||||||
|
*) grep=${GREP-grep} ;;
|
||||||
|
esac
|
||||||
|
pat=""
|
||||||
|
while test $# -ne 0; do
|
||||||
|
case "$1" in
|
||||||
|
-e | -f) opt="$opt $1"; shift; pat="$1"
|
||||||
|
if test "$grep" = grep; then # grep is buggy with -e on SVR4
|
||||||
|
grep=egrep
|
||||||
|
fi;;
|
||||||
|
-A | -B) opt="$opt $1 $2"; shift;;
|
||||||
|
-*) opt="$opt $1";;
|
||||||
|
*) if test -z "$pat"; then
|
||||||
|
pat="$1"
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
fi;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if test -z "$pat"; then
|
||||||
|
echo "grep through bzip2 files"
|
||||||
|
echo "usage: $prog [grep_options] pattern [files]"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
list=0
|
||||||
|
silent=0
|
||||||
|
op=`echo "$opt" | sed -e 's/ //g' -e 's/-//g'`
|
||||||
|
case "$op" in
|
||||||
|
*l*) list=1
|
||||||
|
esac
|
||||||
|
case "$op" in
|
||||||
|
*h*) silent=1
|
||||||
|
esac
|
||||||
|
|
||||||
|
if test $# -eq 0; then
|
||||||
|
bzip2 -cdfq | $grep $opt "$pat"
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
res=0
|
||||||
|
for i do
|
||||||
|
if test -f "$i"; then :; else if test -f "$i.bz2"; then i="$i.bz2"; fi; fi
|
||||||
|
if test $list -eq 1; then
|
||||||
|
bzip2 -cdfq "$i" | $grep $opt "$pat" 2>&1 > /dev/null && echo $i
|
||||||
|
r=$?
|
||||||
|
elif test $# -eq 1 -o $silent -eq 1; then
|
||||||
|
bzip2 -cdfq "$i" | $grep $opt "$pat"
|
||||||
|
r=$?
|
||||||
|
else
|
||||||
|
j=$(echo "$i" | sed 's/\\/&&/g;s/|/\\&/g;s/&/\\&/g')
|
||||||
|
j=`printf "%s" "$j" | tr '\n' ' '`
|
||||||
|
# A trick adapted from
|
||||||
|
# https://groups.google.com/forum/#!original/comp.unix.shell/x1345iu10eg/Nn1n-1r1uU0J
|
||||||
|
# that has the same effect as the following bash code:
|
||||||
|
# bzip2 -cdfq "$i" | $grep $opt "$pat" | sed "s|^|${j}:|"
|
||||||
|
# r=${PIPESTATUS[1]}
|
||||||
|
exec 3>&1
|
||||||
|
eval `
|
||||||
|
exec 4>&1 >&3 3>&-
|
||||||
|
{
|
||||||
|
bzip2 -cdfq "$i" 4>&-
|
||||||
|
} | {
|
||||||
|
$grep $opt "$pat" 4>&-; echo "r=$?;" >&4
|
||||||
|
} | sed "s|^|${j}:|"
|
||||||
|
`
|
||||||
|
fi
|
||||||
|
test "$r" -ne 0 && res="$r"
|
||||||
|
done
|
||||||
|
exit $res
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user