Template
1
0
mirror of https://github.com/bol-van/zapret2.git synced 2026-03-15 14:36:09 +00:00

69 Commits
v0.8 ... v0.8.2

Author SHA1 Message Date
bol-van
2983c681d7 update docs 2026-01-04 14:28:02 +03:00
bol-van
68eefd9dd7 update docs 2026-01-04 14:21:14 +03:00
bol-van
73f6f7c522 update docs 2026-01-04 14:18:54 +03:00
bol-van
df83a29b98 update docs 2026-01-04 14:17:07 +03:00
bol-van
9881cc4da2 update docs 2026-01-04 13:00:37 +03:00
bol-van
44f8ad6747 update docs 2026-01-04 12:38:33 +03:00
bol-van
c651367d6a update docs 2026-01-04 12:35:08 +03:00
bol-van
90f88271c5 update docs 2026-01-04 12:34:07 +03:00
bol-van
9ba8d6cbdf update docs 2026-01-04 12:18:17 +03:00
bol-van
27efbb37d7 update docs 2026-01-04 12:16:57 +03:00
bol-van
d725bd8fd7 update docs 2026-01-04 12:13:58 +03:00
bol-van
0ef50d04dc update docs 2026-01-04 12:13:33 +03:00
bol-van
fdae4b1812 update docs 2026-01-04 12:08:36 +03:00
bol-van
d0644f6160 update docs 2026-01-04 12:06:01 +03:00
bol-van
b4f1765574 update docs 2026-01-04 12:04:58 +03:00
bol-van
8454d48fcd update docs 2026-01-04 12:01:30 +03:00
bol-van
70d7a77d06 update docs 2026-01-04 11:56:51 +03:00
bol-van
2a48f82feb update docs 2026-01-04 11:54:34 +03:00
bol-van
c5d997ce48 update docs 2026-01-04 11:52:55 +03:00
bol-van
c950edb380 update docs 2026-01-04 11:39:23 +03:00
bol-van
0d96b03f49 blockcheck2: additional NOTEST 2026-01-04 11:38:47 +03:00
bol-van
9772641813 init.d: 80-dns-intercept use mangle iptable 2026-01-03 20:19:28 +03:00
bol-van
7307a03ff7 init.d: 80-dns-intercept print_op 2026-01-03 20:16:49 +03:00
bol-van
b529198f24 80-dns-intercept: remove DISABLE_IPVx filters 2026-01-03 19:59:51 +03:00
bol-van
5f5cfb434c update docs 2026-01-03 19:48:42 +03:00
bol-van
2f1aa5734e winws2: --wf-filter-loopback 2026-01-03 19:44:29 +03:00
bol-van
062360f3f3 update docs 2026-01-03 19:24:12 +03:00
bol-van
7122808425 init.d: dns intercept scheme 2026-01-03 19:14:35 +03:00
bol-van
515921522e init.d: ressurect lanif 2026-01-03 17:50:11 +03:00
bol-van
c0ce825a95 update lame issue warning 2026-01-03 15:04:39 +03:00
bol-van
c4b23d21ce init.d: sysv functions fix wrong interface order 2026-01-03 14:55:39 +03:00
bol-van
0847d9f140 nfqws2: replace printf with write in sighup 2026-01-03 13:24:18 +03:00
bol-van
b239690e33 AI inspired fixes 2026-01-03 13:15:01 +03:00
bol-van
4f6510daf1 base.sh: detect hard links to busybox 2026-01-03 00:39:29 +03:00
bol-van
0cad2329a1 install_bin: fix and 2026-01-03 00:39:03 +03:00
bol-van
24d9eb1fe2 nfqws2: use query name in dns response extraction 2026-01-03 00:12:43 +03:00
bol-van
f98445d36b update docs 2026-01-02 22:45:02 +03:00
bol-van
7278bb1b87 nfqws2: fix non-working dns ipcache if --debug=0 2026-01-02 20:01:23 +03:00
bol-van
5b58997e3e update docs 2026-01-02 19:53:22 +03:00
bol-van
93a6487eb5 update docs 2026-01-02 19:39:31 +03:00
bol-van
fdca797671 nfqws2: cache dns response IP addresses if --ipcache-hostname enabled 2026-01-02 19:29:33 +03:00
bol-van
bb9e78e8fb nfqws2: optimize udp protocol detect code 2026-01-02 17:44:52 +03:00
bol-van
2a15a1a778 Merge pull request #61 from Pavel4e5/typos
Typos
2026-01-02 17:26:44 +03:00
Pavel4e5
bf89b415bb Merge branch 'bol-van:master' into typos 2026-01-02 18:42:40 +05:00
bol-van
735936efc5 zapret-tests: test_swap 2026-01-01 14:26:23 +03:00
bol-van
9d09d8adcc nfqws2: fix comment 2025-12-31 18:07:30 +03:00
bol-van
3874e16075 nfqws2: print luajit status at startup 2025-12-31 16:10:22 +03:00
bol-van
cbb05967ba update docs 2025-12-31 10:49:19 +03:00
bol-van
665bd5f318 zapret-lib: check NFQWS2_COMPAT_VER 2025-12-31 10:48:42 +03:00
bol-van
fa1d7c30c3 blockcheck2: --payload= 2025-12-31 10:42:54 +03:00
Pavel4e5
940f94162d update docs 2025-12-31 02:47:05 +05:00
Pavel4e5
60108bf378 zapret-antidpi: correct error message 2025-12-31 02:40:33 +05:00
bol-van
5a68245e32 update docs 2025-12-30 15:33:28 +03:00
bol-van
b2dbdd4dd7 update docs 2025-12-30 15:32:55 +03:00
bol-van
5bc65c3b91 update docs 2025-12-30 15:20:49 +03:00
bol-van
6bf7f2c7c0 nfqws2: use luaL_loadbuffer 2025-12-30 15:11:15 +03:00
bol-van
44a80abb3f nfqws2: use luaL_loadbuffer 2025-12-30 15:05:42 +03:00
bol-van
89f0f39b83 update docs 2025-12-30 13:27:07 +03:00
bol-van
ad6f1db149 blockcheck2: http_unixeol test 2025-12-30 13:26:51 +03:00
bol-van
9154fe1677 zapret-lib, zapret-antidpi: http_reconstruct_req, http_unixeol 2025-12-30 13:26:15 +03:00
bol-van
5e63a0f5c5 update docs 2025-12-30 11:24:08 +03:00
bol-van
0521053991 github actions: use pigz -11 instead of gzip 2025-12-30 11:10:10 +03:00
bol-van
7b7ed1ad60 update docs 2025-12-30 10:51:07 +03:00
bol-van
2915647c63 update docs 2025-12-30 10:50:19 +03:00
bol-van
958a4e918b update docs 2025-12-30 10:48:11 +03:00
bol-van
cb332dad74 update docs 2025-12-30 10:44:05 +03:00
bol-van
17e9e0a8e6 update docs 2025-12-29 20:40:50 +03:00
bol-van
78b348a193 nfqws2: bu48 crash fix 2025-12-29 19:25:28 +03:00
bol-van
8103a02689 nfqws2: fix wrong bitset on 32-bit platforms 2025-12-29 19:14:25 +03:00
26 changed files with 576 additions and 113 deletions

View File

@@ -11,7 +11,11 @@ Issues - это место для обращений к разработчику
Discussions - место для обсуждения вопросов между пользователями.
Все, что выходит за рамки багов и технически грамотных предложений, идей,
вопросы типа "как мне это запустить", "что нажать", "что вписать" - будет безжалостно удаляться.
вопросы типа "как мне это запустить", "что нажать", "что вписать", "перестало открываться" - будет безжалостно удаляться.
Если вы не знаете как пользоваться, для вас что-то сложно, здесь - не место обучению программе или linux и не место для вопросов подобного рода.
Поймите, пожалуйста, что zapret - это инструмент, а не готовое решение для пользователя. В его функциях нет кнопки "открыть сайты", поэтому
если они перестали открываться - это не issue. Функцию "открыть сайты" дают только сборки - ищите их и все вопросы адресуйте туда.
Если вы игнорируете данное требование, вы не достигните своих целей , а только добавите желания удалить ваш issue или при настойчивости забанить.
Идите в дискуссии, не захламляйте issues.
Here is the place for bugs only. All questions, especially user-like questions (non-technical) go to Discussions.

View File

@@ -75,11 +75,11 @@ jobs:
sudo dpkg --add-architecture i386
sudo apt update -qq
if [[ "$ARCH" == lexra ]]; then
sudo apt install -y libcap-dev libc6:i386 zlib1g:i386
sudo apt install -y pigz libcap-dev libc6:i386 zlib1g:i386
URL=https://github.com/$REPO/raw/refs/heads/master/$DIR.txz
else
# luajit buildvm requires 32 bit executable on host platform for 32 bit cross targets
sudo apt install -y libcap-dev libc6-dev gcc-multilib
sudo apt install -y pigz libcap-dev libc6-dev gcc-multilib
URL=https://github.com/$REPO/releases/download/latest/$TOOL.tar.xz
fi
mkdir -p $HOME/tools
@@ -553,7 +553,7 @@ jobs:
rm -rf binaries/{android*,freebsd*,win*} \
init.d/{openrc,pfsense,runit,s6,systemd,windivert.filter.examples} \
nfq2 ip2net mdig docs Makefile
gzip lua/*.lua
pigz -11 lua/*.lua
)
tar --owner=0 --group=0 -czf ${{ env.repo_dir }}-openwrt-embedded.tar.gz ${{ env.repo_dir }}

View File

@@ -6,7 +6,7 @@ pktws_check_http()
[ "$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
for s in 'http_hostcase' 'http_hostcase:spell=hoSt' 'http_domcase' 'http_methodeol' 'http_unixeol'; do
pktws_curl_test_update $1 $2 --payload=http_req --lua-desync=$s
done
}

View File

@@ -5,7 +5,9 @@ pktws_check_http()
# $1 - test function
# $2 - domain
local PAYLOAD="--payload http_req" repeats ok
local PAYLOAD="--payload=http_req" repeats ok
[ "$NOTEST_MISC_HTTP" = 1 ] && { echo "SKIPPED"; return; }
for repeats in 1 20 100 260; do
# send starting bytes of original payload
@@ -20,7 +22,9 @@ pktws_check_https_tls12()
# $1 - test function
# $2 - domain
local PAYLOAD="--payload tls_client_hello" repeats ok
local PAYLOAD="--payload=tls_client_hello" repeats ok
[ "$NOTEST_MISC_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
for repeats in 1 20 100 260; do
# send starting bytes of original payload

View File

@@ -26,7 +26,7 @@ pktws_check_http()
# $1 - test function
# $2 - domain
local splits_http='method+2 midsld method+2,midsld'
local PAYLOAD="--payload http_req"
local PAYLOAD="--payload=http_req"
[ "$NOTEST_MULTI_HTTP" = 1 ] && { echo "SKIPPED"; return; }
@@ -39,7 +39,7 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,midsld,1220 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
local PAYLOAD="--payload tls_client_hello"
local PAYLOAD="--payload=tls_client_hello"
[ "$NOTEST_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return; }

View File

@@ -5,7 +5,7 @@ pktws_check_http()
[ "$NOTEST_SEQOVL_HTTP" = 1 ] && { echo "SKIPPED"; return; }
local PAYLOAD="--payload http_req"
local PAYLOAD="--payload=http_req"
local ok pat= split f f2
@@ -37,7 +37,7 @@ pktws_seqovl_tests_tls()
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"
local PAYLOAD="--payload=tls_client_hello"
pat=${SEQOVL_PATTERN_HTTPS:+seqovl_pat}
pat=${pat:-fake_default_tls}

View File

@@ -5,7 +5,9 @@ pktws_check_http()
# $1 - test function
# $2 - domain
local PAYLOAD="--payload http_req" split
local PAYLOAD="--payload=http_req" split
[ "$NOTEST_SYNDATA_HTTP" = 1 ] && { echo "SKIPPED"; return; }
for split in '' multisplit $MULTIDISORDER; do
pktws_curl_test_update "$1" "$2" --lua-desync=syndata ${split:+$PAYLOAD --lua-desync=$split}
@@ -19,7 +21,9 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
local PAYLOAD="--payload tls_client_hello" ok=0 pre="$3" split
local PAYLOAD="--payload=tls_client_hello" ok=0 pre="$3" split
[ "$NOTEST_SYNDATA_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
for split in '' multisplit $MULTIDISORDER; do
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata ${split:+$PAYLOAD --lua-desync=$split} && ok=1

View File

@@ -40,7 +40,7 @@ pktws_check_http()
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
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

View File

@@ -42,7 +42,7 @@ pktws_check_faked()
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
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

View File

@@ -46,7 +46,7 @@ pktws_check_http()
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
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

View File

@@ -46,7 +46,7 @@ pktws_check_http()
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
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

View File

@@ -8,7 +8,7 @@ pktws_check_http3()
[ "$NOTEST_QUIC" = 1 ] && { echo "SKIPPED"; return; }
local repeats fake pos fool
local PAYLOAD="--payload quic_initial"
local PAYLOAD="--payload=quic_initial"
if [ -n "$FAKE_QUIC" ]; then
fake=fake_quic

View File

@@ -172,15 +172,23 @@ unique()
is_linked_to_busybox()
{
local IFS F P
local IFS F P BB
BB="$(which busybox)"
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
F="$path/$1"
if [ -L "$F" ]; then
P="$(readlink $F)"
if [ -z "$P" ] && [ -x $F ] && [ ! -L $F ]; then return 1; fi
[ "${P%busybox*}" != "$P" ] && return
elif [ -f "$F" -a -n "$BB" ]; then
# possible hardlink
[ $(get_dir_inode "$F") = $(get_dir_inode "$BB") ] && return
fi
done
return 1
}
get_dir_inode()
{

View File

@@ -18,6 +18,18 @@ nft_list_table()
nft -t list table inet $ZAPRET_NFT_TABLE
}
nft_add_chain()
{
# $1 - chain
# $2 - params
nft add chain inet $ZAPRET_NFT_TABLE $1 "{ $2 }"
}
nft_delete_chain()
{
# $1 - chain
nft delete chain inet $ZAPRET_NFT_TABLE $1
}
nft_create_set()
{
# $1 - set name
@@ -52,7 +64,7 @@ nft_flush_chain()
nft_chain_empty()
{
# $1 - chain name
local count=$(nft list chain inet $ZAPRET_NFT_TABLE prerouting | wc -l)
local count=$(nft list chain inet $ZAPRET_NFT_TABLE $1 | wc -l)
[ "$count" -le 4 ]
}
nft_rule_exists()
@@ -163,10 +175,10 @@ cat << EOF | nft -f -
add chain inet $ZAPRET_NFT_TABLE postnat_hook { type filter hook postrouting priority 101; }
flush chain inet $ZAPRET_NFT_TABLE postnat_hook
add chain inet $ZAPRET_NFT_TABLE prerouting_hook { type filter hook prerouting priority -99; }
flush chain inet $ZAPRET_NFT_TABLE prerouting_hook
add chain inet $ZAPRET_NFT_TABLE prerouting
flush chain inet $ZAPRET_NFT_TABLE prerouting
add chain inet $ZAPRET_NFT_TABLE prerouting_hook { type filter hook prerouting priority -99; }
flush chain inet $ZAPRET_NFT_TABLE prerouting_hook
add chain inet $ZAPRET_NFT_TABLE prenat_hook { type filter hook prerouting priority -101; }
flush chain inet $ZAPRET_NFT_TABLE prenat_hook
@@ -185,6 +197,7 @@ cat << EOF | nft -f -
add set inet $ZAPRET_NFT_TABLE wanif { type ifname; }
add set inet $ZAPRET_NFT_TABLE wanif6 { type ifname; }
add set inet $ZAPRET_NFT_TABLE lanif { type ifname; }
add chain inet $ZAPRET_NFT_TABLE ruletest
flush chain inet $ZAPRET_NFT_TABLE ruletest
@@ -230,8 +243,6 @@ cat << EOF | nft -f - 2>/dev/null
delete chain inet $ZAPRET_NFT_TABLE flow_offload_always
delete chain inet $ZAPRET_NFT_TABLE ruletest
EOF
# unfortunately this approach breaks udp desync of the connection initiating packet (new, first one)
# delete chain inet $ZAPRET_NFT_TABLE predefrag
}
nft_del_flowtable()
{
@@ -257,14 +268,17 @@ nft_create_or_update_flowtable()
nft_flush_ifsets()
{
cat << EOF | nft -f - 2>/dev/null
flush set inet $ZAPRET_NFT_TABLE wanif
flush set inet $ZAPRET_NFT_TABLE wanif6
for set in wanif wanif6 lanif; do
flush set inet $ZAPRET_NFT_TABLE $set
done
EOF
}
nft_list_ifsets()
{
nft list set inet $ZAPRET_NFT_TABLE wanif
nft list set inet $ZAPRET_NFT_TABLE wanif6
for set in wanif wanif6 lanif; do
nft list set inet $ZAPRET_NFT_TABLE $set
done
nft list flowtable inet $ZAPRET_NFT_TABLE ft 2>/dev/null
}
@@ -402,7 +416,9 @@ nft_fill_ifsets()
# calling all in one shot helps not to waste cpu time many times
script="flush set inet $ZAPRET_NFT_TABLE wanif
flush set inet $ZAPRET_NFT_TABLE wanif6"
flush set inet $ZAPRET_NFT_TABLE wanif6
flush set inet $ZAPRET_NFT_TABLE lanif"
nft_script_add_ifset_element lanif "$1"
[ "$DISABLE_IPV4" = "1" ] || nft_script_add_ifset_element wanif "$2"
[ "$DISABLE_IPV6" = "1" ] || nft_script_add_ifset_element wanif6 "$3"

View File

@@ -144,3 +144,21 @@ v0.8.0
* zapret-antidpi: tls_client_hello_clone
* zapret-antidpi: "optional" arg to blob taking functions
* nfqws2: support gzipped lua file. auto use script.lua.gz
v0.8.1
* nfqws2: fix bu48 crash and wrong results in bitset
* zapret-lib: http_reconstruct_req
* zapret-antidpi: http_unixeol
* blockcheck2: http_unixeol test
0.8.2
* nfqws2: do not start if NFQWS2_COMPAT_VER unexpected
* nfqws2: cache dns response IP addresses if --ipcache-hostname enabled
* winws2: remove hardcoded filter for loopback
* init.d: ressurect @lanif in nft scheme
* init.d: fix broken @wanif/@wanif6 fill in sysv nft scheme
* init.d: 80-dns-intercept
* winws2: --wf-filter-loopback
* blockcheck2: NOTEST_MISC_HTTP[S], NOTEST_SYNDATA_HTTP[S]

View File

@@ -158,12 +158,13 @@
- [http\_hostcase](#http_hostcase)
- [http\_domcase](#http_domcase)
- [http\_methodeol](#http_methodeol)
- [http\_unixeol](#http_unixeol)
- [Замена window size](#замена-window-size)
- [wsize](#wsize)
- [wssize](#wssize)
- [Фейки](#фейки)
- [syndata](#syndata)
- [tls_client_hello_clone](#tls_client_hello_clone)
- [tls\_client\_hello\_clone](#tls_client_hello_clone)
- [fake](#fake)
- [rst](#rst)
- [TCP сегментация](#tcp-сегментация)
@@ -254,6 +255,7 @@
- [Принципы интеграции с openrc](#принципы-интеграции-с-openrc)
- [Шпаргалка openrc](#шпаргалка-openrc)
- [Альтернативная установка на systemd](#альтернативная-установка-на-systemd)
- [Другие прошивки](#другие-прошивки)
# Введение
@@ -972,6 +974,16 @@ ipcache представляет собой структуру в памяти
Домен может скакать по разным IP на CDN. Сейчас один адрес, через час - другой. Эта проблема решается через время жизни записей кэша : `--ipcache-lifetime`. По умолчанию 2 часа.
Однако, может случиться и так, что в вашем случае применение техники несет больше пользы, чем проблем. Будьте готовы к непонятному на первый взгляд поведению, которое может быть исследовано только через `--debug` лог.
Имена хостов для кэширования берутся из анализа L7 протоколов и из DNS ответов (не DoH).
Извлечение DNS работает только по udp протоколу и требует перенаправления пакетов с порта 53. Нужны только ответы DNS, имеющие source port 53.
На Windows это будет `--wf-udp-in=53`. Скорее всего будет обращение к DNS внутри локальной сети, поэтому нужен параметр `--wf-filter-lan=0`.
Если на Windows крутится какой-то dns proxy, а DNS настроен на localhost, потребуется еще и `--wf-filter-loopback=0`.
На роутере, если используется шифрованный DNS, надо ловить запросы от клиента еще до шифрования - на LAN интерфейсе.
Если шифрование не используется, можно ловить и на WAN.
Для LAN интерфейса они будут исходящими, для интерфейса WAN - входящими, по направлению conntrack - reply.
При использовании [скриптов запуска](#скрипты-запуска) в Linux для перехвата DNS ответов существует [custom script](#custom-скрипты) `80-dns-intercept`. Его достаточно скопировать в "custom.d".
## Сигналы
- **SIGHUP** принудительно перечитывает все файлы хостлистов и ipset
@@ -1834,7 +1846,9 @@ nfqws2 не использует никакие криптобиблиотеки
function bcryptorandom(size)
```
Генерирует raw строку - криптографически стойкий блок случайных данных указанного размера. Источник - `/dev/random`
Генерирует raw строку - криптографически стойкий блок случайных данных указанного размера. Источник - `/dev/random`.
Если пул энтропии исчерпывается, может вызывать зависания. Чтобы этого не было - установите haveged или rngd.
Не стоит использовать для получения случайных данных, не требующих крипто-стойкости.
#### hash
@@ -2234,10 +2248,10 @@ function pktdebug(ctx, desync)
function argdebug(ctx, desync)
```
### posdebug
Вывести таблицу аргументов в debug log.
### posdebug
```
function posdebug(ctx, desync)
```
@@ -2373,8 +2387,12 @@ function blob_or_def(desync, name, def)
```
function barray(a, packer)
function btable(a, packer)
```
- barray использует только числовые индексы, начиная с 1. порядок соблюдается
- btable использует все индексы, но не гарантирует порядок
Упаковка элементов массива a в порядке возрастания индекса от 1 до последнего.
`packer` - функция, берущая элемент a и возвращающая raw string.
Для числовых массивов в качестве packer можно использовать [функции паковки чисел](#bux).
@@ -2463,6 +2481,7 @@ function dissect_nld(domain, level)
```
function http_dissect_req(http)
function http_dissect_reply(http)
function http_reconstruct_req(hdis, unixeol)
```
Разборка HTTP запроса или ответа http. http представляет собой многострочный текст.
@@ -2470,6 +2489,8 @@ function http_dissect_reply(http)
В заголовках выдаются позиции начала и конца названия заголовка и самого значения.
Названия полей в таблице headers соответствуют названию заголовков в нижнем регисте. Все позиции - внутри строки http.
Реконструктор http запроса берет таблицу-разбор и воссоздает raw string. Параметр unixeol заменяет стандартный для http перевод сктроки 0D0A на 0A. Это нестандарт и ломает все сервера, кроме nginx.
<details>
<summary><b>Пример разборки http запроса `http://testhost.com/testuri`</b></summary>
<pre>
@@ -2558,7 +2579,9 @@ function tls_reconstruct(tdis)
7. Если есть record layer, реконструкция выполняется согласно длинам отдельных records. Если последняя часть не влезает, tls record расширяется под оставшиеся данные.
8. При отсутствии изменений dissect+reconstruct дают бинарно идентичные блобы.
Функции не работают с DTLS. В случае ошибки возвращается nil.
Функции не работают с DTLS.
`tls_dissect` возвращает таблицу - разбор raw строки tls со смещения offset (начиная с 1), `reconstruct_dissect` возвращает raw строку собранного разбора tdis. В случае ошибки возвращается nil.
Простейший способ получить образец диссекта : `--payload=tls_client_hello --lua-desync=luaexec:code="var_debug(tls_dissect(desync.reasm_data))"`.
И вызвать TLS запрос.
@@ -2876,9 +2899,11 @@ function tls_reconstruct(tdis)
Множество констант, связанных с TLS, определено в `zapret-lib.lua`. Прежде чем писать фиксированные значения, посмотрите нет ли нужной константы.
Таблица handshake индексируется по типу hadnshake. Самыми типичными являются `TLS_HANDSHAKE_TYPE_CLIENT` и `TLS_HANDSHAKE_TYPE_SERVER`.
Таблица handshake индексируется по типу handshake. Самыми типичными являются `TLS_HANDSHAKE_TYPE_CLIENT` и `TLS_HANDSHAKE_TYPE_SERVER`.
Они имеют значения 1 и 2 соответственно, поэтому может показаться, что элементы handshake идут от 1 и по возрастающей. Это не так.
extensions и другие списки индексируются по номеру с 1, а не по типу, потому что важен порядок их следования, и может быть несколько элементов одного типа.
Если вы что-то добавляете свое, вам нужно воспроизвести минимальный вариант исходной структуры.
Можно заполнить только raw data field. Если нет подтаблицы dis - при реконструкции будет взято оно.
Если есть dis, то он должен быть заполнен корректно согласно рассматриваемому элементу данных.
@@ -3448,6 +3473,16 @@ function http_methodeol(ctx, desync)
Вставляет '\r\n' перед методом, отрезая 2 последних символа из содержимого заголовка `User-Agent:`. Работает только на nginx, остальные сервера ломает.
### http_unixeol
```
function http_unixeol(ctx, desync)
```
- arg: [standard direction](#standard-direction)
Заменяет перевод строки 0D0A на 0A. Разницу в длине добавляет пробелами в конец хедера "User-Agent". Работает только на nginx, остальные сервера ломает.
## Замена window size
### wsize
@@ -4428,10 +4463,14 @@ SEQOVL_PATTERN_HTTPS - путь к файлу с seqovl pattern для https
MULTIDISORDER=multidisorder_legacy - заменить multidisorder на вариант из nfqws1
NOTEST_BASIC_HTTP=1 - отмена тестов 10-http-basic.sh
NOTEST_MISC_HTTP=1 - отмена тестов http 15-misc.sh
NOTEST_MISC_HTTPS=1 - отмена тестов https 15-misc.sh
NOTEST_MULTI_HTTP=1 - отмена тестов http 20-multi.sh
NOTEST_MULTI_HTTPS=1 - отмена тестов https 20-multi.sh
NOTEST_SEQOVL_HTTP=1 - отмена тестов http 23-seqovl.sh
NOTEST_SEQOVL_HTTPS=1 - отмена тестов https 23-seqovl.sh
NOTEST_SYNDATA_HTTP=1 - отмена тестов http 24-syndata.sh
NOTEST_SYNDATA_HTTPS=1 - отмена тестов https 24-syndata.sh
NOTEST_FAKE_HTTP=1 - отмена тестов http 25-fake.sh
NOTEST_FAKE_HTTPS=1 - отмена тестов https 25-fake.sh
NOTEST_FAKED_HTTP=1 - отмена тестов http 25-faked.sh
@@ -4451,6 +4490,10 @@ NOTEST_QUIC=1 - отмена тестов 90-quic.sh
Простой тестировщик по списку стратегий из файлов. Стратегии должны быть на отдельных строчках, переносы строки не допускаются. Используются отдельные списки для протоколов - `list_http.txt`, `list_https_tls12.txt`, `list_https_tls13.txt`, `list_quic.sh`. В файлах поддерживаются комментарии, начинающиеся на `#`.
При записи параметров следует учитывать, что они будут интерпретироваься как параметры shell. Специальные символы нужно экранировать по правилам shell.
Если вы оставите "<" без кавычек на всем параметре или возьмете в кавычки параметр `--luaexec=code=print("abc")`, будет ошибка. Если в lua коде используются строки - их стоит заключать в одинарные кавычки, а вокруг параметра - двойные.
blockcheck2 будет выдавать параметры стратегий без экранирования.
Самый правильный способ применения - скопировать в свою поддиректорию внутри `blockcheck2.d` и заполнить txt файлы с тестами. Выбрать свое имя теста в диалоге.
## Summary
@@ -4501,13 +4544,17 @@ SIM_SUCCESS_RATE=<percent> - вероятность успеха симуляц
blockcheck проверяет доступность одного отдельно взятого "domain[/uri]" с отдельно взятым протоколом, не более.
Броузер делает куда больше. В чем же разница ?
1. Может все начинаться с DNS. blockcheck использует системный или doh, а броузер - наоборот. Такие сайты, как instagram, частично заблокированы по IP. Успех зависит от того, какой именно IP выдается конкретным DNS.
1. Может все начинаться с DNS. blockcheck использует системный или doh, а броузер - наоборот. Такие сайты, как instagram, частично заблокированы по IP. Успех зависит от того, какой именно IP выдается конкретным DNS. Если же у вас DNS отравлен провайдером, а ваш клиент не поддерживает шифрованный DNS, то это сразу конец всем обходам. Вы пойдете на IP адрес заглушки, и , естественно, никакой zapret не поможет. Бывает, провайдер вообще не выдает DNS ответ на заблокированный домен или выдает 127.0.0.1.
2. Сайт - это не один домен и не один URI. Жмете F12 в броузере и во вкладке "сеть" смотрите куда лезет сайт. Он может споткнуться на другом домене.
3. Цель броузера - открыть сайт как можно быстрее, не нагружая пользователя техническими терминами, которые для него неотличимы от китайского языка. Поэтому он лезет на сайт по разным протоколам так, чтобы страница открылась быстрее. Может скакать между ipv4 и ipv6, между tls и quic. Уже 4 комбинации. А ведь для каждого из них отдельный тест блокчека. Все ли они пробились одной стратегией ? Корректно ли вы перенесли эти стратегии в рабочий конфиг ? Правильно ли их обьединили ?
4. Отдельный важный параметр - kyber. Постквантовая криптография, которая однопакетный запрос TLS/QUIC превращает в 2 или 3 пакетный. Само по себе фактор при обходе DPI. Современные броузеры обычно используют kyber. curl - зависит от его старости и от старости криптобиблиотеки, с которой он слинкован. OpenSSL 3.5.0 выдает kyber, старее - нет. LibreSSL или mbedTLS не выдают kyber. Сейчас. А завтра выдадут, потому что тренд идет в ту сторону.
5. Блокираторы ничем не брезгуют. Бывает они даже привязываются к фингерприту клиента. Что это такое ? Наличие/порядок tls extensions прежде всего, характерный для броузера или curl.
6. Знаменитый "16 кб" блок. Как проверить 16 кб блок ? Дернуть curl какой-то URI, на котором сайт выдаст достаточно длинную страницу. Если загрузка виснет посередине - это оно. Поставлена задача загнать всех под российскую юрисдикцию, а для этого гнобят крупные хостинги - cloudfare, hetzner, akamai, aws и другие. Им надо оставить несколько важных сайтов. hp.com - откуда еще драйвера для LaserJet качать ? А hp на одном из таких хостингов. Получается белый список. Следовательно, вам нужен пейлоад, который ему удовлетворяет. Но беда в том, что блокчек , как и сам zapret, - всего лишь инструмент. Он не включает в себя готовых рецептов. Вам самим нужно искать чем пробивать конкретные хостинги. Сейчас это так, а завтра будет еще что-то другое. Автор не будет гнаться за ситуацией, не будет оперативно менять блокчек, чтобы он вам выдавал готовые copy+paste рецепты. Вам нужно самим смотреть на ситуацию и искать решение. Сегодня белые списки в стиле "16 кб" пробиваются или белым SNI, или каким-то другим белым типом протокола, не TLS. Завтра будет что-то другое. [Стандартный чекер](#тест-standard) берет целый список переменных для кустомизации сканирования. Есть возможность подсунуть [что-то до и что-то после](#shell-переменные) стратегии. Наконец, свет клином не сошелся на блокчеке. Иногда удобнее вручную проверять.
7. Ходит информации о поведении DPI в стиле "наказать шалуна". DPI видит попытки его задурить и на некоторое время блокирует доступ по IP. Раз-два прошло, потом никакие конекты не проходят. Если IP динамический, помогает переподключение к линии провайдера, но лишь до новой попытки. Автор не сталкивался с подобными блокировками, но сами динамические блокировки - это тот путь, которым прошел Китай. В России тоже можно ожидать.
5. Блокираторы ничем не брезгуют. Бывает они даже привязываются к фингерприту клиента. Что это такое ? Наличие/порядок tls extensions прежде всего, характерный для броузера или curl. Никак нельзя забанить IP адреса, но нужно устранить очередной новый VPN клиент ? Смотрят его handshake, находят уникальные особенности и рубят по ним. Заодно отрубается что-то еще. Но им на это уже плевать.
6. ECH - технология зашифрованной передачи SNI, чтобы блокираторы не видели к какому ресурсу обращаются. Технология отличная, но, к сожалению, запоздавшая. Точка, когда технология уже окончательно вьелась в стандарты де-факто, не была пройдена. Поэтому могут банить как по самому наличию ECH, так и по внешнему SNI-заглушке. На cloudflare это "cloudflare-ech.com". curl дергает сайт без ECH, а броузер может с ним - вот и разница.
7. Версия TLS протокола. По умолчанию blockcheck2 тестирует TLS 1.2 как самый тяжелый для обхода вариант. Броузер скорее всего полезет по TLS 1.3. Были случаи, когда блокираторы намеренно банили протокол TLS 1.3, потому что его использует и требует популярный метод обхода через VLESS-REALITY. Уровень пофигизма на сопутствующий ущерб уже настолько высок, что поломка множества легальных ресурсов их не останавливает.
8. Знаменитый "16 кб" блок. Как проверить 16 кб блок ? Дернуть curl какой-то URI, на котором сайт выдаст достаточно длинную страницу. Если загрузка виснет посередине - это оно. По умолчанию blockcheck2 на https использует HEAD, чтобы не мучать сервер и экономить трафик - все равно под https ничего не видно. Это можно поменять через [CURL_HTTPS_GET=1](#shell-переменные). Но так вы скорее всего начнете получать сплошные "UNAVAILABLE". Стандартный вариант дает стратегии, которые будут работать при обходе 16кб блока, поэтому более информативен. Почему же они это делают ? Поставлена задача загнать всех под российскую юрисдикцию, а для этого гнобят крупные хостинги - cloudfare, hetzner, akamai, aws и другие. CDN часто используются для скрытого проброса прокси или VPN. Им надо оставить несколько важных сайтов. hp.com - откуда еще драйвера для LaserJet качать ? А hp на одном из таких хостингов. Получается белый список. Следовательно, вам нужен пейлоад, который ему удовлетворяет. Но беда в том, что блокчек , как и сам zapret, - всего лишь инструмент. Он не включает в себя готовых рецептов. Вам самим нужно искать чем пробивать конкретные хостинги. Сейчас это так, а завтра будет еще что-то другое. Автор не будет гнаться за ситуацией, не будет оперативно менять блокчек, чтобы он вам выдавал готовые copy+paste рецепты. Вам нужно самим смотреть на ситуацию и искать решение. Сегодня белые списки в стиле "16 кб" пробиваются или белым SNI, или каким-то другим белым типом протокола, не TLS. Завтра будет что-то другое. [Стандартный чекер](#тест-standard) берет целый список переменных для кустомизации сканирования. Есть возможность подсунуть [что-то до и что-то после](#shell-переменные) стратегии. Наконец, свет клином не сошелся на блокчеке. Иногда удобнее вручную проверять.
9. В продолжение предыдущего пункта - широко развилась практика вводить особые правила на диапазонах IP адресов. Поэтому вы можете найти стратегию, работающую для большинства ресурсов, но на некоторых она работать не будет.
10. Ходит информация о поведении DPI в стиле "наказать шалуна". DPI видит попытки его задурить и на некоторое время блокирует доступ по IP. Раз-два прошло, потом никакие конекты не проходят. Если IP динамический, помогает переподключение к линии провайдера, но лишь до новой попытки. Другой вариант - отправка udp пакета на триггерный IP (например, через торрент клиент) и последующий блок некоторых IP диапазонов. Автор не сталкивался с подобными блокировками, но сами динамические блокировки - это тот путь, которым прошел Китай. В России тоже можно ожидать.
11. Нестабильность стратегии. Балансировка на провайдерах - явление частое. Трафик может идти то через один DPI, то через другой, и стратегия может работать через раз. blockcheck2 по умолчанию тестирует только одну попытку. Если есть сомнения в стабильности - следует увеличить количество попыток минимум до 5. Можно использовать [PARALLEL=1](#shell-переменные), но это может привести к срабатыванию защиты самого ресурса от долбежки.
Гланая цель блокираторов - устранить массовое нарушение их блокировок.
Если 99% нажимает на кнопку, и она не срабатывает, для них решение не работает.
@@ -4588,6 +4635,9 @@ ip листы разделяются на ipv4 и ipv6. ipv6 листы имею
В зависимости от режима хостлисты могут ресолвиться в ip листы через [mdig](#mdig) или применяться как есть. Если хостлисты применяются как есть в nfqws2, учитываются только имена доменов, а IP адреса и подсети - нет.
Включающие ip листы загоняются в сеты ядра и применяются в правилах таблиц только, если указан [MODE_FILTER=ipset](#файл-config).
Исключающий ip лист загоняется в сеты ядра и применяется всегда в правилах таблиц.
| Хостлист | Тип | Назначение | ip листы |
| :---------------------------- | :--------------- | :-------------- | :---------------------------------------------------- |
| zapret-hosts-user.txt | пользовательский | включающий | zapret-ip-user.txt<br>zapret-ip-user6.txt |
@@ -4696,8 +4746,8 @@ create_ipset no-update
| start<br>stop<br>restart | запуск/останов/перезапуск демонов и firewall. firewall не запускается, если [INIT_APPLY_FW](#файл-config) не равно 1. На openwrt с fw3 (iptables) firewall запускается отдельно, команды работают только с демонами и не трогают firewall |
| start_daemons<br>stop_daemons<br>restart_daemons | запуск/останов/перезапуск демонов |
| start_fw<br>stop_fw<br>restart_fw | запуск/останов/перезапуск firewall. На openwrt с fw3 (iptables) команды работают, но firewall запускается отдельно через firewall include в `/etc/config/firewall`. Отдельные операции не рекомендованы. |
| reload_ifsets | (только для nftables) перезагрузка сетов wanif и wanif6 |
| list_ifsets | (только для nftables) показ wanif, wanif6 и flowtable |
| reload_ifsets | (только для nftables) перезагрузка сетов wanif, wanif6, lanif |
| list_ifsets | (только для nftables) показ wanif, wanif6, lanif и flowtable |
| list_table | (только для nftables) показ таблицы zapret2 |
sysv вариант предназначен для любых Linux, не являющихся OpenWRT. На системах с различными системами запуска все равно работает sysv скрипт, а прикрутка к системам запуска представляет собой лишь адаптер, его запускающий. На системах с неподдерживаемыми системами запуска и на прошивках вы сами должны знать куда прикрутить "zapret2 start" и "zapret2 stop", чтобы работал автостарт и останов в рамках вашей системы запуска.
@@ -4712,7 +4762,7 @@ sysv вариант предназначен для любых Linux, не яв
#### Интеграция с OpenWRT firewall
Готовая интеграция с firewall имеется для OpenWRT. Скрипты запуска автоматически определяют fw3 и отключат управление firewall через start/stop/restart. Вместо этого в `/etc/config/firewall` прописывается firewall include `firewall.zapret2`, который и запускает правила zapret синхронно после поднятия fw3. Дополнительно вешается хук `90-zapret2` в `/etc/hotplug.d/iface` на поднятие/опускание интерфейсов. В варианте fw3 происходит рестарт fw3, чтобы правила применились к новым интерфейсам или наоборот - были удалены для более несуществующих интерфейсов. В варианте nftables происходит лишь перезагрузка сетов wanif, wanif6 и flowtable.
Готовая интеграция с firewall имеется для OpenWRT. Скрипты запуска автоматически определяют fw3 и отключат управление firewall через start/stop/restart. Вместо этого в `/etc/config/firewall` прописывается firewall include `firewall.zapret2`, который и запускает правила zapret синхронно после поднятия fw3. Дополнительно вешается хук `90-zapret2` в `/etc/hotplug.d/iface` на поднятие/опускание интерфейсов. В варианте fw3 происходит рестарт fw3, чтобы правила применились к новым интерфейсам или наоборот - были удалены для более несуществующих интерфейсов. В варианте nftables происходит лишь перезагрузка сетов wanif, wanif6, lanif и flowtable.
### custom скрипты
@@ -4723,7 +4773,7 @@ sysv вариант предназначен для любых Linux, не яв
custom скрипт может иметь следующие shell функции, которые вызываются системой запуска :
- **zapret_custom_daemons** - поднятие и останов демонов. $1 = 1 - поднятие, 0 - останов.
- **zapret_custom_firewall** - поднятие и снятие правил iptables. $1 - поднятие, 0 - снятие.
- **zapret_custom_firewall** - поднятие и снятие правил iptables. $1 = 1 - поднятие, 0 - снятие.
- **zapret_custom_firewall_nft** - поднятие правил nftables. останов не требуется, поскольку основной код при останове очищает цепочки nft вместе с custom правилами.
- **zapret_custom_firewall_nft_flush** - вызывается при останове nftables, чтобы можно было удалить обьекты, выходящие за рамки стандартных цепочек - такие, как собственные set-ы или собственные цепочки.
@@ -4904,6 +4954,11 @@ nft_reverse_nfqws_rule()
Замена элементов nftables фильтра с прямого на обратное направление - меняется dst на src. Результат выводится в stdout.
```
nft_add_chain()
# $1 - имя цепочки
# $2 - параметры внутри { }
nft_delete_chain()
# $1 - имя цепочки
nft_create_set()
# $1 - имя сета
# $2 - параметры внутри { }
@@ -4972,13 +5027,13 @@ ln -s /opt/zapret2/init.d/openwrt/zapret2 /etc/init.d
/etc/init.d/zapret2 enable
```
1. Обновление правил firewall по событию поднятия/опускания интерфейсов.
2. Обновление правил firewall по событию поднятия/опускания интерфейсов.
```
ln -s /opt/zapret2/init.d/openwrt/90-zapret2 /etc/hotplug.d/iface
```
1. (только для fw3) Интеграция с firewall.
3. (только для fw3) Интеграция с firewall.
```
ln -s /opt/zapret2/init.d/openwrt/firewall.zapret2 /etc
@@ -4988,7 +5043,7 @@ uci set firewall.@include[-1].reload=1
uci commit
```
1. Обновление листов - cron job на вызов `/opt/zapret2/ipset/get_config.sh` ночью в случайное время каждые 2 дня - для обновления листов. Рассчет идет на роутер, работающий круглосуточно.
4. Обновление листов - cron job на вызов `/opt/zapret2/ipset/get_config.sh` ночью в случайное время каждые 2 дня - для обновления листов. Рассчет идет на роутер, работающий круглосуточно.
### Шпаргалка OpenWRT
@@ -5009,7 +5064,7 @@ systemctl daemon-reload
systemctl enable zapret2
```
1. Таймер для обновления листов - в случайное время суток каждые 2 дня. Рассчет идет на любую систему, в том числе десктопную, которую могут включать только днем.
2. Таймер для обновления листов - в случайное время суток каждые 2 дня. Рассчет идет на любую систему, в том числе десктопную, которую могут включать только днем.
```
cp /opt/zapret2/init.d/systemd/zapret2-list-update.* /lib/systemd/system
@@ -5036,7 +5091,7 @@ ln -s /opt/zapret2/init.d/openrc/zapret2 /etc/init.d
rc-update add zapret2
```
1. Обновление листов - cron job на вызов `/opt/zapret2/ipset/get_config.sh` днем в случайное время каждые 2 дня. Рассчет идет на любую систему, в том числе десктопную, которую могут включать только днем.
2. Обновление листов - cron job на вызов `/opt/zapret2/ipset/get_config.sh` днем в случайное время каждые 2 дня. Рассчет идет на любую систему, в том числе десктопную, которую могут включать только днем.
### Шпаргалка openrc
@@ -5061,3 +5116,66 @@ rc-update add zapret2
8. Перезапуск : `systemctl restart nfqws2@INSTANCE`
Этот способ не поднимает правила ip/nf tables - вам это придется сделать отдельно, как и написать сами правила. Правила нужно прописать куда-то, чтобы они поднимались после старта системы. Например, можно сделать отдельный systemd unit с запуском шелл скрипта или `nft -f /path/to/file.nft`.
## Другие прошивки
Для статических бинарников не имеет значения на чем они запущены: PC, android, приставка, роутер, любой другой девайс.
Подойдет любая прошивка, дистрибутив Linux. Статические бинарники запустятся на всем.
Им нужно только ядро с необходимыми опциями сборки или модулями.
Но кроме бинарников в проекте используются еще и скрипты, в которых задействуются некоторые
стандартные программы.
Основные причины почему нельзя просто так взять и установить эту систему на что угодно:
* отсутствие доступа к девайсу через shell
* отсутствие рута
* отсутствие раздела r/w для записи и энергонезависимого хранения файлов
* отсутствие возможности поставить что-то в автозапуск
* отсутствие cron
* неотключаемый flow offload или другая проприетарщина в netfilter
* недостаток модулей ядра или опций его сборки
* недостаток модулей iptables (/usr/lib/iptables/lib*.so)
* недостаток стандартных программ (типа ipset, curl) или их кастрированность (облегченная замена)
* кастрированный или нестандартный шелл sh
Если в вашей прошивке есть все необходимое, то вы можете адаптировать zapret под ваш девайс в той или иной степени.
Пересобрать ядро или модули для него будет скорее всего достаточно трудно.
Для этого вам необходимо будет по крайней мере получить исходники вашей прошивки.
User mode компоненты могут быть привнесены относительно безболезненно, если есть место куда их записать.
Специально для девайсов, имеющих область r/w, существует проект entware.
Некоторые прошивки даже имеют возможность его облегченной установки через веб интерфейс.
entware содержит репозиторий user-mode компонент, которые устанавливаются в /opt.
С их помощью можно компенсировать недостаток ПО основной прошивки, за исключением ядра.
Можно попытаться использовать [sysv init script](#стартовые-скрипты).
В случае ругани на отсутствие каких-то базовых программ, их следует восполнить посредством entware.
Перед запуском скрипта путь к дополнительным программам должен быть помещен в PATH.
Обратите внимание, что entware патчен на предмет замены стандартных путей файлов типа /etc/passwd на /opt/etc/passwd.
Статические бинарники zapret собраны без учета этой особенности, поэтому оцпия --user может не работать - юзер ищется в /etc/passwd,
который находится на r/o разделе, в том время как adduser добавляет юзеров в /opt/etc/passwd.
Поэтому может понадобиться раскомментировать в [config](#файл-config) WS_USER и указать юзера, который есть в /etc/passwd.
Для keenetic существуют дополнительные важные особенности, без учета которых zapret будет "слетать" каждые несколько минут или не работать с udp.
Существуют готовые сторонние решения по интеграции с keenetic.
Подробное описание настроек для других прошивок выходит за рамки данного проекта.
OpenWrt является одной из немногих относительно полноценных linux систем для embedded devices.
Она характеризуется следующими вещами, которые и послужили основой выбора именно этой прошивки:
* полный root доступ к девайсу через shell. на заводских прошивках чаще всего отсутствует, на многих альтернативных есть
* корень r/w. это практически уникальная особенность OpenWrt. заводские и большинство альтернативных прошивок
построены на базе squashfs root (r/o), а конфигурация хранится в специально отформатированной области
встроенной памяти, называемой nvram. не имеющие r/w корня системы сильно кастрированы. они не имеют
возможности доустановки ПО из репозитория без специальных вывертов и заточены в основном
на чуть более продвинутого, чем обычно, пользователя и управление имеющимся функционалом через веб интерфейс,
но функционал фиксированно ограничен. альтернативные прошивки, как правило, могут монтировать r/w раздел
в какую-то область файловой системы, заводские обычно могут монтировать лишь флэшки, подключенные к USB,
и не факт, что есть поддержка unix файловых системы. может быть поддержка только fat и ntfs.
* возможность выноса корневой файловой системы на внешний носитель (extroot) или создания на нем оверлея (overlay)
* наличие менеджера пакетов opkg и репозитория софта
* flow offload предсказуемо, стандартно и выборочно управляем, а так же отключаем
* в репозитории есть все модули ядра, их можно доустановить через opkg. ядро пересобирать не нужно.
* в репозитории есть все модули iptables, их можно доустановить через opkg
* в репозитории есть огромное количество стандартных программ и дополнительного софта
* наличие SDK, позволяющего собрать недостающее

View File

@@ -0,0 +1,59 @@
# this custom script feeds dns response data to main nfqws2 instance
# DISABLE_IPV{4,6} filters are not used intentionally. despite of not having wan ipv6 it's possible to query LAN DNS server over local ipv6
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local filt="-p udp --sport 53"
local jump="-j NFQUEUE --queue-num $QNUM --queue-bypass"
local rule chain lan lanifs
get_lanif lanifs
# router
for lan in $lanifs; do
rule="-o $lan $filt $jump"
ipt_print_op $1 "$rule" "nfqws FORWARD (qnum $QNUM)"
ipt_add_del $1 FORWARD -t mangle $rule
ipt_print_op $1 "$rule" "nfqws FORWARD (qnum $QNUM)" 6
ipt6_add_del $1 FORWARD -t mangle $rule
done
# dns client server
for chain in INPUT OUTPUT ; do
rule="$filt $jump"
ipt_print_op $1 "$rule" "nfqws $chain (qnum $QNUM)"
ipt_add_del $1 $chain -t mangle $rule
ipt_print_op $1 "$rule" "nfqws $chain (qnum $QNUM)" 6
ipt6_add_del $1 $chain -t mangle $rule
done
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local rule="udp sport 53 queue num $QNUM bypass"
# dns client
nft_print_op "oifname @lanif $rule" "nfqws forward (qnum $QNUM)" "4+6"
nft_add_chain forward_dns_feed "type filter hook forward priority mangle;"
nft_add_rule forward_dns_feed oifname @lanif $rule
# router
nft_print_op "$rule" "nfqws input (qnum $QNUM)" "4+6"
nft_add_chain input_dns_feed "type filter hook input priority mangle;"
nft_add_rule input_dns_feed $rule
# dns server
nft_print_op "$rule" "nfqws output (qnum $QNUM)" "4+6"
nft_add_chain output_dns_feed "type filter hook output priority mangle;"
nft_add_rule output_dns_feed $rule
}
zapret_custom_firewall_nft_flush()
{
local chain
for chain in forward_dns_feed input_dns_feed output_dns_feed; do
nft_delete_chain $chain 2>/dev/null
done
}

View File

@@ -62,6 +62,20 @@ network_find_wanX_devices()
call_for_multiple_items network_get_device $2 "$ifaces"
}
get_wanif46()
{
# $1 - 4/6
# $2 - var to receive interface list
local ifaces
network_find_wan${1}_all ifaces
call_for_multiple_items network_get_device $2 "$ifaces"
}
get_lanif()
{
# $1 - var to receive interface list
call_for_multiple_items network_get_device $1 "$OPENWRT_LAN"
}
fw_nfqws_prepost_x()
{
@@ -71,10 +85,8 @@ fw_nfqws_prepost_x()
# $4 - 4/6
# $5 - post/pre
local ifaces DWAN
network_find_wan${4}_all ifaces
call_for_multiple_items network_get_device DWAN "$ifaces"
local DWAN
get_wanif46 $4 DWAN
[ -n "$DWAN" ] && _fw_nfqws_${5}${4} $1 "$2" $3 "$(unique $DWAN)"
}
fw_nfqws_post4()

View File

@@ -75,6 +75,26 @@ NFQWS2="${NFQWS2:-$ZAPRET_BASE/nfq2/nfqws2}"
LUAOPT="--lua-init=@$ZAPRET_BASE/lua/zapret-lib.lua --lua-init=@$ZAPRET_BASE/lua/zapret-antidpi.lua --lua-init=@$ZAPRET_BASE/lua/zapret-auto.lua"
NFQWS2_OPT_BASE="$USEROPT --fwmark=$DESYNC_MARK $LUAOPT"
get_wanif46()
{
# $1 - 4/6
# $2 - var to receive interface list
case $1 in
6)
eval $2="\${IFACE_WAN6:-$IFACE_WAN}"
;;
4)
eval $2="\$IFACE_WAN"
;;
*)
eval $2=
esac
}
get_lanif()
{
# $1 - var to receive interface list
eval $1="\$IFACE_LAN"
}
fw_nfqws_post4()
{
@@ -119,7 +139,7 @@ nft_wanif6_filter_present()
}
nft_fill_ifsets_overload()
{
nft_fill_ifsets "$IFACE_WAN" "${IFACE_WAN6:-$IFACE_WAN}" "$IFACE_LAN"
nft_fill_ifsets "$IFACE_LAN" "$IFACE_WAN" "${IFACE_WAN6:-$IFACE_WAN}"
}

View File

@@ -31,7 +31,7 @@ select_test_method()
elif exists zsh && [ "$UNAME" != CYGWIN ] ; then
TEST=zsh
elif [ "$UNAME" != CYGWIN ]; then
if exists hexdump and exists dd; then
if exists hexdump && exists dd; then
# macos does not use ELF
TEST=elf
ELF=

View File

@@ -185,6 +185,40 @@ function http_methodeol(ctx, desync)
end
end
-- nfqws1 : not available
-- tpws : --unixeol
-- standard args : direction
function http_unixeol(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)
if hdis then
if hdis.headers["user-agent"] then
local http = http_reconstruct_req(hdis, true)
if #http < #desync.dis.payload then
hdis.headers["user-agent"].value = hdis.headers["user-agent"].value .. string.rep(" ", #desync.dis.payload - #http)
end
local http = http_reconstruct_req(hdis, true)
if #http==#desync.dis.payload then
desync.dis.payload = http
DLOG("http_unixeol: applied")
return VERDICT_MODIFY
else
DLOG("http_unixeol: reconstruct differs in size from original: "..#http.."!="..#desync.dis.payload)
end
else
DLOG("http_unixeol: user-agent header absent")
end
else
DLOG("http_unixeol: could not dissect http")
end
end
end
-- nfqws1 : "--synack-split"
-- standard args : rawsend, reconstruct, ipfrag
-- arg : mode=syn|synack|acksyn . "synack" by default
@@ -305,7 +339,7 @@ function tls_client_hello_clone(ctx, desync)
direction_cutoff_opposite(ctx, desync)
if direction_check(desync) then
if not desync.arg.blob then
error("fake: 'blob' arg required")
error("tls_client_hello_clone: 'blob' arg required")
end
if desync.l7payload=="tls_client_hello" then
desync[desync.arg.blob] = tls_client_hello_mod(desync.reasm_data or desync.dis.payload, desync.arg)

View File

@@ -1,3 +1,9 @@
NFQWS2_COMPAT_VER_REQUIRED=4
if NFQWS2_COMPAT_VER~=NFQWS2_COMPAT_VER_REQUIRED then
error("Incompatible NFQWS2_COMPAT_VER. Use pktws and lua scripts from the same release !")
end
HEXDUMP_DLOG_MAX = HEXDUMP_DLOG_MAX or 32
NOT3=bitnot(3)
NOT7=bitnot(7)
@@ -304,7 +310,7 @@ function pos_str(desync, pos)
return pos.mode..pos_get(desync, pos.mode)
end
-- convert array a to packed string using 'packer' function
-- convert array a to packed string using 'packer' function. only numeric indexes starting from 1, order preserved
function barray(a, packer)
if a then
local s=""
@@ -314,6 +320,16 @@ function barray(a, packer)
return s
end
end
-- convert table a to packed string using 'packer' function. any indexes, any order
function btable(a, packer)
if a then
local s=""
for k,v in pairs(a) do
s = s .. packer(v)
end
return s
end
end
-- sequence comparision functions. they work only within 2G interval
-- seq1>=seq2
@@ -1423,19 +1439,22 @@ function http_dissect_header(header)
end
-- make table with structured http header representation
function http_dissect_headers(http, pos)
local eol,pnext,header,value,idx,headers,pos_endheader,pos_startvalue
local eol,pnext,header,value,idx,headers,pos_endheader,pos_startvalue,pos_headers_next
headers={}
while pos do
eol,pnext = find_next_line(http,pos)
header = string.sub(http,pos,eol)
if #header == 0 then break end
if #header == 0 then
pos_headers_end = pnext
break
end
header,value,pos_endheader,pos_startvalue = http_dissect_header(header)
if header then
headers[string.lower(header)] = { header = header, value = value, pos_start = pos, pos_end = eol, pos_header_end = pos+pos_endheader-1, pos_value_start = pos+pos_startvalue-1 }
end
pos=pnext
end
return headers
return headers, pos_headers_end
end
-- make table with structured http request representation
function http_dissect_req(http)
@@ -1457,9 +1476,21 @@ function http_dissect_req(http)
pos = string.find(req,"[^ \t]",pos+1)
if not pos then return nil end
pnext = string.find(req,"[ \t]",pos+1)
if not pnext then pnext = #http + 1 end
if not pnext then pnext = #req + 1 end
local uri = string.sub(req,pos,pnext-1)
return { method = method, uri = uri, headers = http_dissect_headers(http,hdrpos) }
pos = string.find(req,"[^ \t]",pnext)
local http_ver
if pos then
pnext = string.find(req,"[\r\n]",pos)
if not pnext then pnext = #req + 1 end
http_ver = string.sub(req,pos,pnext-1)
end
local hdis = { method = method, uri = uri, http_ver = http_ver }
hdis.headers, hdis.pos_headers_end = http_dissect_headers(http,hdrpos)
if hdis.pos_headers_end then
hdis.body = string.sub(http, hdis.pos_headers_end)
end
return hdis
end
function http_dissect_reply(http)
if not http then return nil; end
@@ -1472,6 +1503,14 @@ function http_dissect_reply(http)
pos = find_next_line(http,pos)
return { code = code, headers = http_dissect_headers(http,pos) }
end
function http_reconstruct_headers(headers, unixeol)
local eol = unixeol and "\n" or "\r\n"
return headers and btable(headers, function(a) return a.header..": "..a.value..eol end) or ""
end
function http_reconstruct_req(hdis, unixeol)
local eol = unixeol and "\n" or "\r\n"
return hdis.method.." "..hdis.uri..(hdis.http_ver and (" "..hdis.http_ver) or "")..eol..http_reconstruct_headers(hdis.headers, unixeol)..eol..(hdis.body or "")
end
function dissect_url(url)
local p1,pb,pstart,pend

View File

@@ -304,6 +304,39 @@ function test_bit()
end
end
function test_swap()
local v1, v2, v3
v1 = math.random(0,0xFFFF)
v2 = swap16(v1)
v3 = divint(v1,0x100) + v1%0x100*0x100
print("swap16: "..(v2==v3 and "OK" or "FAIL"))
test_assert(v2==v3)
v1 = math.random(0,0xFFFFFF)
v2 = swap24(v1)
v3 = divint(v1,0x10000) + divint(v1,0x100)%0x100*0x100 + v1%0x100*0x10000
print("swap24: "..(v2==v3 and "OK" or "FAIL"))
test_assert(v2==v3)
v1 = math.random(0,0xFFFFFFFF)
v2 = swap32(v1)
v3 = divint(v1,0x1000000) + divint(v1,0x10000)%0x100*0x100 + divint(v1,0x100)%0x100*0x10000 + v1%0x100*0x1000000
print("swap32: "..(v2==v3 and "OK" or "FAIL"))
test_assert(v2==v3)
v1 = math.random(0,0xFFFFFFFFFFFF)
v2 = swap48(v1)
v3 = divint(v1,0x10000000000) +
divint(v1,0x100000000)%0x100*0x100 +
divint(v1,0x1000000)%0x100*0x10000 +
divint(v1,0x10000)%0x100*0x1000000 +
divint(v1,0x100)%0x100*0x100000000 +
v1%0x100*0x10000000000
print("swap48: "..(v2==v3 and "OK" or "FAIL"))
test_assert(v2==v3)
end
function test_ux()
local v1, v2, v3, usum, sum
for k,test in pairs({
@@ -330,7 +363,7 @@ function test_ux()
end
function test_bin(...)
test_run({test_ub, test_bit, test_ux},...)
test_run({test_ub, test_bit, test_swap, test_ux},...)
end

View File

@@ -1492,6 +1492,88 @@ static void udp_standard_protocol_probe(const uint8_t *data_payload, size_t len_
protocol_probe(testers, sizeof(testers) / sizeof(*testers), data_payload, len_payload, ctrack, l7proto, l7payload);
}
static const uint8_t *dns_extract_name(const uint8_t *a, const uint8_t *b, const uint8_t *e, char *name, size_t name_size)
{
size_t nl, off;
const uint8_t *p;
bool bptr = (*a & 0xC0)==0xC0;
if (bptr)
{
// name pointer
off = (*a & 0x3F)<<8 | a[1];
p = b + off;
}
else
// real name
p = a;
if (p>=e) return NULL;
for (nl=0; *p ;)
{
if ((p+*p+1)>=e || (*p+1)>=(name_size-nl)) return NULL;
if (nl) name[nl++] = '.';
memcpy(name + nl, p + 1, *p);
nl += *p;
p += *p + 1;
}
name[nl] = 0;
return bptr ? a+2 : p+1;
}
static bool feed_dns_response(const uint8_t *a, size_t len)
{
if (!params.cache_hostname) return true;
// check of minimum header length and response flag
uint16_t k, off, dlen, qcount = a[4]<<8 | a[5], acount = a[6]<<8 | a[7];
char s_ip[40];
const uint8_t *b = a, *p;
const uint8_t *e = b + len;
size_t nl;
char name[256] = "";
if (len<12 || !(a[2]&0x80)) return false;
a+=12; len-=12;
for(k=0;k<qcount;k++)
{
// remember original query name
if (!(p = dns_extract_name(a, b, e, name, sizeof(name)))) return false;
len -= p-a;
// must be A or AAAA query. others are not interesting
if ((len<4) || p[0] || p[1]!=1 && p[1]!=28 || p[2] || p[3]!=1) return false;
// skip type, class
a=p+4; len-=4;
}
if (!*name) return false;
for(k=0;k<acount;k++)
{
// 11 higher bits indicate pointer
if (len<12 || (*a & 0xC0)!=0xC0) return false;
dlen = a[10]<<8 | a[11];
if (len<(dlen+12)) return false;
if (a[4]==0 && a[5]==1 && a[2]==0) // IN class and higher byte of type = 0
{
switch(a[3])
{
case 1: // A
if (dlen!=4) break;
if (params.debug && inet_ntop(AF_INET, a+12, s_ip, sizeof(s_ip)))
DLOG("DNS response : %s\n", s_ip);
ipcache_put_hostname((struct in_addr *)(a+12), NULL, name, false);
break;
case 28: // AAAA
if (dlen!=16) break;
if (params.debug && inet_ntop(AF_INET6, a+12, s_ip, sizeof(s_ip)))
DLOG("DNS response : %s\n", s_ip);
ipcache_put_hostname(NULL, (struct in6_addr *)(a+12), name, false);
break;
}
}
len -= 12+dlen; a += 12+dlen;
}
return true;
}
static uint8_t dpi_desync_udp_packet_play(
unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset,
@@ -1652,22 +1734,13 @@ static uint8_t dpi_desync_udp_packet_play(
if (dis->len_payload)
{
bool bHaveHost = false, bHostIsIp = false;
if (bReverse)
udp_standard_protocol_probe(dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
if (!bReverse)
{
udp_standard_protocol_probe(dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
}
else
{
struct blob_collection_head *fake;
if (IsQUICInitial(dis->data_payload, dis->len_payload))
if (l7payload==L7P_QUIC_INITIAL)
{
DLOG("packet contains QUIC initial\n");
l7payload = L7P_QUIC_INITIAL;
l7proto = L7_QUIC;
// update ctrack l7proto here because reasm can happen
if (ctrack && ctrack->l7proto == L7_UNKNOWN) ctrack->l7proto = l7proto;
uint8_t clean[UDP_MAX_REASM], *pclean;
size_t clean_len;
@@ -1789,15 +1862,14 @@ static uint8_t dpi_desync_udp_packet_play(
quic_reasm_cancel(ctrack, "QUIC initial decryption failed");
}
}
else // not QUIC initial
{
// not quic initial - stop reasm
reasm_client_cancel(ctrack);
udp_standard_protocol_probe(dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
}
}
reasm_client_cancel(ctrack);
if (l7payload==L7P_DNS_RESPONSE)
feed_dns_response(dis->data_payload, dis->len_payload);
if (bHaveHost)
{
bHostIsIp = strip_host_to_ip(host);

View File

@@ -193,7 +193,7 @@ static int luacall_bitset(lua_State *L)
if (from>to || from>47 || to>47)
luaL_error(L, "bit range invalid");
lua_Integer mask = ~((lua_Integer)-1 << (to-from+1));
uint64_t mask = ~((uint64_t)-1 << (to-from+1));
set = (set & mask) << from;
mask <<= from;
what = what & ~mask | set;
@@ -401,7 +401,7 @@ static int luacall_bu48(lua_State *L)
int64_t i = (int64_t)luaL_checklint(L,1);
if (i>0xFFFFFFFFFFFF || i<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
uint8_t v[4];
uint8_t v[6];
phton48(v,(uint64_t)i);
lua_pushlstring(L,(char*)v,6);
return 1;
@@ -2870,11 +2870,35 @@ static bool lua_basic_init()
#else
DLOG_CONDUP("LUA v%u.%u\n",ver/100,ver%100);
#endif
#if LUA_VERSION_NUM >= 504
lua_setwarnf(params.L,lua_warn,NULL);
#endif
lua_atpanic(params.L,lua_panic);
luaL_openlibs(params.L); /* Load Lua libraries */
lua_getfield(params.L, LUA_REGISTRYINDEX, "_LOADED");
if (lua_type(params.L, -1)==LUA_TTABLE)
{
lua_getfield(params.L, -1, "jit");
if (lua_type(params.L, -1)==LUA_TTABLE)
{
lua_getfield(params.L, -1, "status");
if (lua_type(params.L, -1)==LUA_TFUNCTION)
{
const char *s;
int n = lua_gettop(params.L);
lua_call(params.L, 0, LUA_MULTRET);
DLOG_CONDUP(lua_toboolean(params.L, n) ? "JIT: ON" : "JIT: OFF");
for (n++; (s = lua_tostring(params.L, n)); n++)
DLOG_CONDUP(" %s", s);
DLOG_CONDUP("\n");
}
}
}
lua_settop(params.L, 0);
return true;
}
@@ -2961,13 +2985,13 @@ static int luaL_doZfile(lua_State *L, const char *filename)
FILE *F = fopen(fname, "rb");
if (!F)
luaL_error(L, "could not open lua file '%s'", fname);
r = z_readfile(F, &buf, &size, 1);
r = z_readfile(F, &buf, &size, 0);
fclose(F);
if (r != Z_OK)
luaL_error(L, "could not unzip lua file '%s'", fname);
buf[size] = 0;
r = luaL_dostring(L, buf);
r = luaL_loadbuffer(L, buf, size, fname);
free(buf);
if (!r) r=lua_pcall(L, 0, LUA_MULTRET, 0);
return r;
}
else

View File

@@ -51,14 +51,15 @@
#define MAX_CONFIG_FILE_SIZE 16384
struct params_s params;
static bool bReload = false;
static volatile sig_atomic_t bReload = false;
#ifdef __CYGWIN__
bool bQuit = false;
#endif
static void onhup(int sig)
{
printf("HUP received ! Lists will be reloaded.\n");
const char *msg = "HUP received ! Lists will be reloaded.\n";
size_t wr = write(1, msg, strlen(msg));
bReload = true;
}
static void ReloadCheck()
@@ -683,11 +684,6 @@ static int win_main()
DLOG("windivert: passing impostor packet\n");
verdict = VERDICT_PASS;
}
else if (wa.Loopback)
{
DLOG("windivert: passing loopback packet\n");
verdict = VERDICT_PASS;
}
else
{
mark = 0;
@@ -1257,7 +1253,7 @@ static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *bu
// HTTP/1.? 30(2|7)
#define DIVERT_HTTP_REDIRECT "tcp.PayloadLength>=12 and tcp.Payload32[0]==0x48545450 and tcp.Payload16[2]==0x2F31 and tcp.Payload[6]==0x2E and tcp.Payload16[4]==0x2033 and tcp.Payload[10]==0x30 and (tcp.Payload[11]==0x32 or tcp.Payload[11]==0x37)"
#define DIVERT_PROLOG "!impostor and !loopback"
#define DIVERT_PROLOG "!impostor"
static bool wf_make_filter(
char *wf, size_t len,
@@ -1268,12 +1264,14 @@ static bool wf_make_filter(
const char *pf_tcp_src_in, const char *pf_tcp_dst_in,
const char *pf_udp_src_in, const char *pf_udp_dst_out,
const struct str_list_head *wf_raw_part,
bool bFilterOutLAN)
bool bFilterOutLAN, bool bFilterOutLoopback)
{
struct str_list *wfpart;
bool bHaveTCP = *pf_tcp_src_in || *pf_tcp_dst_out;
snprintf(wf, len, "%s", DIVERT_PROLOG);
if (bFilterOutLoopback)
snprintf(wf + strlen(wf), len - strlen(wf), " and !loopback");
if (IfIdx)
snprintf(wf + strlen(wf), len - strlen(wf), " and ifIdx=%u and subIfIdx=%u", IfIdx, SubIfIdx);
if (ipv4 ^ ipv6)
@@ -1397,6 +1395,7 @@ static void exithelp(void)
" --wf-tcp-empty=[0|1]\t\t\t\t\t; enable processing of empty tcp packets without flags SYN,RST,FIN (default : 0)\n"
" --wf-raw-part=<filter>|@<filename>\t\t\t; partial raw windivert filter string or filename\n"
" --wf-filter-lan=0|1\t\t\t\t\t; add excluding filter for non-global IP (default : 1)\n"
" --wf-filter-loopback=0|1\t\t\t\t; add excluding filter for loopback (default : 1)\n"
" --wf-raw=<filter>|@<filename>\t\t\t\t; full raw windivert filter string or filename. replaces --wf-tcp,--wf-udp,--wf-raw-part\n"
" --wf-save=<filename>\t\t\t\t\t; save windivert filter string to a file and exit\n"
"\nLOGICAL NETWORK FILTER:\n"
@@ -1495,10 +1494,6 @@ void config_from_file(const char *filename)
}
#endif
static void check_dp(const struct desync_profile *dp)
{
}
static void ApplyDefaultBlobs(struct blob_collection_head *blobs)
{
load_const_blob_to_collection("fake_default_tls",fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),blobs,BLOB_EXTRA_BYTES);
@@ -1594,6 +1589,7 @@ enum opt_indices {
IDX_WF_RAW,
IDX_WF_RAW_PART,
IDX_WF_FILTER_LAN,
IDX_WF_FILTER_LOOPBACK,
IDX_WF_SAVE,
IDX_SSID_FILTER,
IDX_NLM_FILTER,
@@ -1683,6 +1679,7 @@ static const struct option long_options[] = {
[IDX_WF_RAW] = {"wf-raw", required_argument, 0, 0},
[IDX_WF_RAW_PART] = {"wf-raw-part", required_argument, 0, 0},
[IDX_WF_FILTER_LAN] = {"wf-filter-lan", required_argument, 0, 0},
[IDX_WF_FILTER_LOOPBACK] = {"wf-filter-loopback", required_argument, 0, 0},
[IDX_WF_SAVE] = {"wf-save", required_argument, 0, 0},
[IDX_SSID_FILTER] = {"ssid-filter", required_argument, 0, 0},
[IDX_NLM_FILTER] = {"nlm-filter", required_argument, 0, 0},
@@ -1726,7 +1723,7 @@ int main(int argc, char **argv)
struct packet_range range_in = PACKET_RANGE_NEVER, range_out = PACKET_RANGE_ALWAYS;
#ifdef __CYGWIN__
char wf_save_file[256]="";
bool wf_ipv4 = true, wf_ipv6 = true, wf_filter_lan = true, wf_tcp_empty = false;
bool wf_ipv4 = true, wf_ipv6 = true, wf_filter_lan = true, wf_filter_loopback = true, wf_tcp_empty = false;
unsigned int IfIdx = 0, SubIfIdx = 0;
unsigned int hash_wf_tcp_in = 0, hash_wf_udp_in = 0, hash_wf_tcp_out = 0, hash_wf_udp_out = 0, hash_wf_raw = 0, hash_wf_raw_part = 0, hash_ssid_filter = 0, hash_nlm_filter = 0;
#endif
@@ -2136,7 +2133,6 @@ int main(int argc, char **argv)
}
else
{
check_dp(dp);
if (bTemplate)
{
if (dp->name && dp_list_search_name(&params.desync_templates, dp->name))
@@ -2228,7 +2224,7 @@ int main(int argc, char **argv)
DLOG_ERR("Invalid port filter : %s\n", optarg);
exit_clean(1);
}
// deny tcp if not set
// deny udp if not set
if (!port_filters_deny_if_empty(&dp->pf_udp))
exit_clean(1);
break;
@@ -2438,6 +2434,9 @@ int main(int argc, char **argv)
case IDX_WF_FILTER_LAN:
wf_filter_lan = !!atoi(optarg);
break;
case IDX_WF_FILTER_LOOPBACK:
wf_filter_loopback = !!atoi(optarg);
break;
case IDX_WF_SAVE:
strncpy(wf_save_file, optarg, sizeof(wf_save_file));
wf_save_file[sizeof(wf_save_file) - 1] = '\0';
@@ -2477,7 +2476,6 @@ int main(int argc, char **argv)
}
else
{
check_dp(dp);
if (bTemplate)
{
if (dp->name && dp_list_search_name(&params.desync_templates, dp->name))
@@ -2607,13 +2605,13 @@ int main(int argc, char **argv)
params.wf_pf_tcp_dst_out, params.wf_pf_tcp_src_out,
params.wf_pf_tcp_dst_in, params.wf_pf_tcp_src_in,
params.wf_pf_udp_dst_in, params.wf_pf_udp_src_out,
&params.wf_raw_part, wf_filter_lan) :
&params.wf_raw_part, wf_filter_lan, wf_filter_loopback) :
wf_make_filter(params.windivert_filter, WINDIVERT_MAX, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6,
wf_tcp_empty,
params.wf_pf_tcp_src_out, params.wf_pf_tcp_dst_out,
params.wf_pf_tcp_src_in, params.wf_pf_tcp_dst_in,
params.wf_pf_udp_src_in, params.wf_pf_udp_dst_out,
&params.wf_raw_part, wf_filter_lan);
&params.wf_raw_part, wf_filter_lan, wf_filter_loopback);
cleanup_windivert_portfilters(&params);
if (!b)
{