mirror of
https://github.com/bol-van/zapret2.git
synced 2026-10-29 06:02:05 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
019bbe845f | ||
|
|
9679d58499 | ||
|
|
ca7ed6a986 | ||
|
|
c460884213 | ||
|
|
3570f193d5 | ||
|
|
8be19e079d | ||
|
|
4a33055448 | ||
|
|
221d7dff24 | ||
|
|
f94b562482 | ||
|
|
6ec7ee67ce | ||
|
|
98757082b8 | ||
|
|
5786448c93 | ||
|
|
a0028b9895 | ||
|
|
486626d28f | ||
|
|
f8d08b8436 | ||
|
|
a4515beb32 | ||
|
|
299f833f39 | ||
|
|
a0c928be45 | ||
|
|
f256fea2d8 | ||
|
|
3a6f75cd3c | ||
|
|
44fbf1b18e | ||
|
|
a1adf7b868 | ||
|
|
ca950d838a | ||
|
|
873642573e | ||
|
|
e41e4f18c7 | ||
|
|
03ce20156a | ||
|
|
00f5aaa36d | ||
|
|
1e329918dc | ||
|
|
8a398236ac | ||
|
|
074c981a37 | ||
|
|
03c139f34a | ||
|
|
cdcb8d4711 | ||
|
|
970adb5d55 | ||
|
|
6535202a9a | ||
|
|
9bff218b9a | ||
|
|
3e3b902902 | ||
|
|
0f65389571 | ||
|
|
ec25da2277 | ||
|
|
0d2227caf6 | ||
|
|
eb42084b30 | ||
|
|
3b6f0cc345 | ||
|
|
28b6fb853e | ||
|
|
bf3b30af9c | ||
|
|
34a95e8a41 | ||
|
|
bf64220ab8 | ||
|
|
adf7791367 | ||
|
|
1ea7d10f6f | ||
|
|
859c24d32b | ||
|
|
5df635efdb | ||
|
|
7119ffce54 | ||
|
|
2efdb70b1c | ||
|
|
692139aeea | ||
|
|
6b6c63e338 | ||
|
|
5fab86344a | ||
|
|
c1e8e7c0d9 | ||
|
|
d9fde580e6 | ||
|
|
5ebfa6c0dc | ||
|
|
3c93f925be | ||
|
|
3f87539d7c |
No files matched your search
@@ -25,12 +25,21 @@ check_list()
|
||||
esac
|
||||
line=$(echo "$line" | tr -d "\r\n")
|
||||
# dry run eval in subshell. can fail because of unescaped chars or something else
|
||||
if (eval emptyf $line); then
|
||||
if (eval emptyf $line) 2>/dev/null; then
|
||||
# real run in the current shell. can modify vars
|
||||
eval pktws_curl_test_update "$1" "$2" $line && ok=1
|
||||
else
|
||||
echo >&2 BAD STRATEGY: $line
|
||||
echo >&2 "THIS LINE IS PASSED TO eval SHELL FUNCTION. IT'S INTERPRETED AS A SHELL STATEMENT. SPECIAL CHARS MUST BE ESCAPED"
|
||||
# $line contains characters that are meaningful to nfqws2/lua-desync
|
||||
# syntax (e.g. "<" in --out-range=s1<d1, or "(" and "'" in a
|
||||
# --lua-init=...=tls_mod(...,'rnd') expression) but aren't valid
|
||||
# shell syntax on their own, so the dry run above rejected it.
|
||||
# Fall back to a plain (non-eval) split: $line is only word-split
|
||||
# on whitespace here, nothing in it is re-parsed as shell syntax,
|
||||
# so these can be used exactly as blockcheck2 itself prints them,
|
||||
# with no manual escaping needed.
|
||||
pktws_curl_test_update "$1" "$2" $line && ok=1
|
||||
echo >&2 'WARNING: this strategy fails eval (may be unescaped special characters). using fallback space separated method'
|
||||
echo >&2 "WARNING: exact line : $line"
|
||||
fi
|
||||
done < "$3"
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
Скопируйте эту директорию под другим именем в blockcheck2.d, отредактируйте list файлы, впишите туда свои стратегии.
|
||||
В диалоге blockcheck2.sh выберите тест с названием вашей директории.
|
||||
Можно комментировать строки символом '#' в начале строки.
|
||||
Параметры со спец символами типа "<" должны быть эскейпнуты по правилам shell.
|
||||
Параметры со спец символами типа "<" больше не обязательно эскейпить - если строка не разбирается как shell, она пробуется заново буквально. Эскейпинг по правилам shell по-прежнему работает и пробуется первым.
|
||||
Альтернативный путь до файлов стратегий можно задать переменными 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.
|
||||
Parameters with special symbols like "<" must be escaped.
|
||||
Parameters with special symbols like "<" no longer need escaping - a line that doesn't parse as shell is retried literally instead of failing. Escaping by shell rules still works too and is tried first.
|
||||
Strategy list files paths can be overriden in env variables : LIST_HTTP, LIST_HTTPS_TLS12, LIST_HTTPS_TLS13, LIST_QUIC.
|
||||
@@ -41,7 +41,9 @@ pktws_check_http()
|
||||
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
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
for ttl in $attls; do
|
||||
for ff in $fake 0x00000000; do
|
||||
@@ -52,6 +54,7 @@ pktws_check_http()
|
||||
}
|
||||
done
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
|
||||
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_fake=1
|
||||
@@ -64,9 +67,13 @@ 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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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
|
||||
}
|
||||
@@ -115,11 +122,13 @@ pktws_check_https_tls()
|
||||
done
|
||||
for fooling in $FOOLINGS_TCP; do
|
||||
pktws_fake_https_vary $testf $domain "$fooling" "$pre"
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
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
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
|
||||
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_fake=1
|
||||
|
||||
@@ -35,6 +35,7 @@ pktws_check_faked()
|
||||
[ "$SCANLEVEL" = force ] || break
|
||||
}
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$ok" = 1 ] && break
|
||||
done
|
||||
@@ -43,7 +44,9 @@ pktws_check_faked()
|
||||
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
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
for ttl in $attls; do
|
||||
for split in $splits; do
|
||||
@@ -53,10 +56,13 @@ pktws_check_faked()
|
||||
[ "$SCANLEVEL" = force ] || break
|
||||
}
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ $ok = 0 -a "$SCANLEVEL" != force ] && eval need_$splitf=1
|
||||
[ $ok = 1 ] && ok_any=1
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok_any" = 1 ] && break
|
||||
done
|
||||
[ "$ok_any" = 1 ]
|
||||
}
|
||||
|
||||
@@ -7,11 +7,17 @@ pktws_hostfake_vary_()
|
||||
|
||||
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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake1:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake2:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
done
|
||||
[ "$ok_any" = 1 ] && ok=1
|
||||
}
|
||||
@@ -51,11 +57,13 @@ pktws_check_hostfake()
|
||||
done
|
||||
for fooling in $FOOLINGS_TCP; do
|
||||
pktws_hostfake_vary $testf $domain "$fooling" "$pre"
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
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
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_hostfakesplit=1
|
||||
[ $ok = 1 ]
|
||||
|
||||
@@ -70,9 +70,13 @@ 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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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 --lua-desync=$splitf:pos=$split $post && ok_any=1
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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
|
||||
}
|
||||
@@ -122,22 +126,28 @@ pktws_check_https_tls()
|
||||
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
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$ok" = 1 ] && break
|
||||
done
|
||||
for fooling in $FOOLINGS_TCP; do
|
||||
for split in $splits; do
|
||||
pktws_fake_https_vary $testf $domain "$fooling" "$pre"
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
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
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$ok" = 1 ] && ok_any=1
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok_any" = 1 ] && break
|
||||
done
|
||||
[ "$ok_any" = 1 ]
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ pktws_check_http()
|
||||
}
|
||||
done
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$ok" = 1 ] && break
|
||||
done
|
||||
@@ -48,7 +49,9 @@ pktws_check_http()
|
||||
# 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
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
for ttl in $attls; do
|
||||
for split in $splits; do
|
||||
@@ -60,8 +63,11 @@ pktws_check_http()
|
||||
}
|
||||
done
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
}
|
||||
|
||||
@@ -70,9 +76,13 @@ 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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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=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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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
|
||||
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
|
||||
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
|
||||
|
||||
@@ -123,22 +133,28 @@ pktws_check_https_tls()
|
||||
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
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$ok" = 1 ] && break
|
||||
done
|
||||
for fooling in $FOOLINGS_TCP; do
|
||||
for split in $splits; do
|
||||
pktws_fake_https_vary $testf $domain "$fooling" "$pre"
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
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
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$ok" = 1 ] && ok_any=1
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok_any" = 1 ] && break
|
||||
done
|
||||
[ "$ok_any" = 1 ]
|
||||
}
|
||||
|
||||
@@ -7,11 +7,17 @@ pktws_hostfake_vary_()
|
||||
|
||||
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
|
||||
[ "$ok" = 1 -a "$SCANLEVEL" = veryquick ] && return 0
|
||||
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
|
||||
[ "$ok" = 1 -a "$SCANLEVEL" = veryquick ] && return 0
|
||||
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
|
||||
[ "$ok" = 1 -a "$SCANLEVEL" = veryquick ] && return 0
|
||||
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
|
||||
[ "$ok" = 1 -a "$SCANLEVEL" = veryquick ] && return 0
|
||||
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
|
||||
[ "$ok" = 1 -a "$SCANLEVEL" = veryquick ] && return 0
|
||||
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
|
||||
[ "$ok" = 1 -a "$SCANLEVEL" = veryquick ] && return 0
|
||||
done
|
||||
}
|
||||
pktws_hostfake_vary()
|
||||
@@ -48,6 +54,7 @@ pktws_check_hostfake()
|
||||
done
|
||||
for fooling in $FOOLINGS_TCP; do
|
||||
pktws_hostfake_vary $testf $domain "$fooling" "$pre" && ok=1
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
for ttl in $attls; do
|
||||
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
|
||||
@@ -56,6 +63,7 @@ pktws_check_hostfake()
|
||||
[ "$SCANLEVEL" = force ] || break
|
||||
}
|
||||
done
|
||||
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
|
||||
done
|
||||
[ "$ok" = 1 ]
|
||||
}
|
||||
|
||||
+176
-19
@@ -34,9 +34,12 @@ DVTWS2=${DVTWS2:-${ZAPRET_BASE}/nfq2/dvtws2}
|
||||
WINWS2=${WINWS2:-${ZAPRET_BASE}/nfq2/winws2}
|
||||
MDIG=${MDIG:-${ZAPRET_BASE}/mdig/mdig}
|
||||
DESYNC_MARK=0x10000000
|
||||
PACE=${PACE:-0}
|
||||
CURL_MAX_TIME=${CURL_MAX_TIME:-2}
|
||||
CURL_MAX_TIME_QUIC=${CURL_MAX_TIME_QUIC:-$CURL_MAX_TIME}
|
||||
CURL_MAX_TIME_DOH=${CURL_MAX_TIME_DOH:-2}
|
||||
CURL_PAD=${CURL_PAD:-0}
|
||||
PAD_MAX_HEADER=${PAD_MAX_HEADER:-4000}
|
||||
USER_AGENT=${USER_AGENT:-Mozilla}
|
||||
HTTP_PORT=${HTTP_PORT:-80}
|
||||
HTTPS_PORT=${HTTPS_PORT:-443}
|
||||
@@ -49,12 +52,19 @@ IPFW_RULE_NUM=${IPFW_RULE_NUM:-$(($$ % $IPFW_RULE_MAX + 1))}
|
||||
IPFW_DIVERT_PORT=${IPFW_DIVERT_PORT:-$(($$ % 64536 + 1000))}
|
||||
QNUM=${QNUM:-$(($$ % 64536 + 1000))}
|
||||
|
||||
PARALLEL_OUT=/tmp/zapret_parallel_$$
|
||||
HDRTEMP=/tmp/zapret-hdr-$$
|
||||
NFT_TABLE=blockcheck$$
|
||||
IPT_OUT_CHAIN=blockcheck_output_$$
|
||||
IPT_IN_CHAIN=blockcheck_input_$$
|
||||
IPT_COMMENT="-m comment --comment blockcheck_$$"
|
||||
PARALLEL_OUT_TEMPLATE=/tmp/zapret2_parallel_
|
||||
PARALLEL_OUT=$PARALLEL_OUT_TEMPLATE$$
|
||||
HDRTEMP_TEMPLATE=/tmp/zapret2-hdr-
|
||||
HDRTEMP=$HDRTEMP_TEMPLATE$$
|
||||
CURL_PAD_FILE_TEMPLATE=/tmp/zapret2-curlpad-
|
||||
|
||||
NFT_TABLE_TEMPLATE=blockcheck2-
|
||||
NFT_TABLE=$NFT_TABLE_TEMPLATE$$
|
||||
IPT_OUT_CHAIN_TEMPLATE=blockcheck2_output_
|
||||
IPT_OUT_CHAIN=$IPT_OUT_CHAIN_TEMPLATE$$
|
||||
IPT_IN_CHAIN_TEMPLATE=blockcheck2_input_
|
||||
IPT_IN_CHAIN=$IPT_IN_CHAIN_TEMPLATE$$
|
||||
IPT_COMMENT="-m comment --comment blockcheck2_$$"
|
||||
|
||||
DNSCHECK_DNS=${DNSCHECK_DNS:-8.8.8.8 1.1.1.1 77.88.8.1}
|
||||
DNSCHECK_DOM=${DNSCHECK_DOM:-pornhub.com ej.ru rutracker.org www.torproject.org bbc.com}
|
||||
@@ -63,12 +73,59 @@ DNSCHECK_DIG1=/tmp/dig1.txt
|
||||
DNSCHECK_DIG2=/tmp/dig2.txt
|
||||
DNSCHECK_DIGS=/tmp/digs.txt
|
||||
|
||||
GUARD_TIMER="timer_set('exit_guard',function(name,data) io.stderr:write('exit_guard\n'); os.exit(3000); end,20000,true)"
|
||||
|
||||
unset PF_STATUS
|
||||
PF_RULES_SAVE=/tmp/pf-zapret-save.conf
|
||||
PF_RULES_SAVE=/tmp/pf-zapret2-save.conf
|
||||
|
||||
unset ALL_PROXY
|
||||
|
||||
apply_header_padfile()
|
||||
{
|
||||
local n=1 left size f pid
|
||||
|
||||
# A normal exit already removes this run's own pad file (see
|
||||
# cleanup() below), which covers Ctrl+C, a closed terminal, and
|
||||
# a plain kill. kill -9 and crashes bypass that, as they would
|
||||
# for any script's cleanup, so sweep any such leftover from
|
||||
# a previous run before making this run's own - only once its PID
|
||||
# is confirmed no longer running, so a genuinely still-running
|
||||
# concurrent instance (different PID, its own file) is never
|
||||
# touched
|
||||
for f in $CURL_PAD_FILE_TEMPLATE*; do
|
||||
[ -e "$f" ] || continue
|
||||
pid=${f##*-}
|
||||
case "$pid" in ''|*[!0-9]*) continue ;; esac
|
||||
kill -0 "$pid" 2>/dev/null || rm -f "$f"
|
||||
done
|
||||
|
||||
if [ "$CURL_PAD" -gt 0 ] 2>/dev/null; then
|
||||
left=$CURL_PAD
|
||||
CURL_PAD_FILE=$CURL_PAD_FILE_TEMPLATE$$
|
||||
rm -f "$CURL_PAD_FILE"
|
||||
touch "$CURL_PAD_FILE"
|
||||
while [ "$left" -ge 14 ]; do
|
||||
left=$(($left-14))
|
||||
if [ "$left" -gt "$PAD_MAX_HEADER" ]; then
|
||||
size="$PAD_MAX_HEADER"
|
||||
else
|
||||
size=$left
|
||||
fi
|
||||
left=$(($left-$size))
|
||||
# if the next header would be too small add the remainder to the current header
|
||||
[ "$left" -lt 14 ] && size=$(($size+$left))
|
||||
|
||||
printf 'X-Pad-%04d: ' $n >> "$CURL_PAD_FILE"
|
||||
printf "%${size}s" | tr ' ' 'A' >> "$CURL_PAD_FILE"
|
||||
# curl internally adds 0D0A line ending even if it's 0A in the file
|
||||
echo >> "$CURL_PAD_FILE"
|
||||
n=$(($n+1))
|
||||
done
|
||||
CURL_OPT="${CURL_OPT}${CURL_OPT:+ }-H @$CURL_PAD_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
killwait()
|
||||
{
|
||||
# $1 - signal (-9, -2, ...)
|
||||
@@ -163,6 +220,7 @@ cleanup()
|
||||
pf_clean
|
||||
;;
|
||||
esac
|
||||
[ -n "$CURL_PAD_FILE" ] && rm -f "$CURL_PAD_FILE"
|
||||
}
|
||||
|
||||
IPT()
|
||||
@@ -636,8 +694,13 @@ curl_with_subst_ip()
|
||||
local connect_to="--connect-to $1::$ip${2:+:$2}" arg
|
||||
shift ; shift ; shift;
|
||||
[ "$CURL_VERBOSE" = 1 ] && arg="-v"
|
||||
[ "$CURL_CMD" = 1 ] && echo $CURL ${arg:+$arg }$connect_to "$@"
|
||||
ALL_PROXY="$ALL_PROXY" "$CURL" ${arg:+$arg }$connect_to "$@"
|
||||
[ "$CURL_CMD" = 1 ] && echo $CURL -w "%{time_total}" ${arg:+$arg }$connect_to "$@"
|
||||
local tooks
|
||||
tooks=$(ALL_PROXY="$ALL_PROXY" "$CURL" -w "%{time_total}" ${arg:+$arg }$connect_to "$@")
|
||||
local ret=$?
|
||||
local tookms=$(awk "BEGIN {print int($tooks * 1000)}")
|
||||
[ "$PACE" -gt "$tookms" ] && msleep $(($PACE - $tookms))
|
||||
return "$ret"
|
||||
}
|
||||
curl_with_dig()
|
||||
{
|
||||
@@ -943,22 +1006,54 @@ pktws_ipt_unprepare_udp()
|
||||
pktws_ipt_unprepare udp $1
|
||||
}
|
||||
|
||||
pktws_ipt_sweep()
|
||||
{
|
||||
# remove leftovers after hard kill/crash
|
||||
|
||||
local f pid IPTABLES
|
||||
case "$FWTYPE" in
|
||||
nftables)
|
||||
nft list tables | grep '^table inet blockcheck2-' | while IFS= read -r f; do
|
||||
pid=${f##*-}
|
||||
case "$pid" in ''|*[!0-9]*) continue ;; esac
|
||||
kill -0 "$pid" 2>/dev/null || nft delete $f
|
||||
done
|
||||
;;
|
||||
iptables)
|
||||
for IPTABLES in iptables ip6tables; do
|
||||
$IPTABLES -t mangle -S | grep -o -e "INPUT -j $IPT_IN_CHAIN_TEMPLATE[0-9]\+" -e "OUTPUT -j $IPT_OUT_CHAIN_TEMPLATE[0-9]\+" | while IFD= read -r f; do
|
||||
pid=${f##*_}
|
||||
case "$pid" in ''|*[!0-9]*) continue ;; esac
|
||||
kill -0 "$pid" 2>/dev/null || $IPTABLES -t mangle -D $f
|
||||
done
|
||||
$IPTABLES -t mangle -S | grep -o -e "$IPT_IN_CHAIN_TEMPLATE[0-9]\+" -e "$IPT_OUT_CHAIN_TEMPLATE[0-9]\+" | sort -u | while IFD= read -r f; do
|
||||
pid=${f##*_}
|
||||
case "$pid" in ''|*[!0-9]*) continue ;; esac
|
||||
kill -0 "$pid" 2>/dev/null || {
|
||||
$IPTABLES -t mangle -F $f
|
||||
$IPTABLES -t mangle -X $f
|
||||
}
|
||||
done
|
||||
done
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
pktws_start()
|
||||
{
|
||||
case "$UNAME" in
|
||||
Linux)
|
||||
"$NFQWS2" --uid $WS_UID:$WS_GID --fwmark=$DESYNC_MARK --qnum=$QNUM --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
|
||||
"$NFQWS2" --uid $WS_UID:$WS_GID --fwmark=$DESYNC_MARK --qnum=$QNUM --lua-init="$GUARD_TIMER" --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
|
||||
;;
|
||||
FreeBSD|OpenBSD)
|
||||
"$DVTWS2" --port=$IPFW_DIVERT_PORT --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
|
||||
"$DVTWS2" --port=$IPFW_DIVERT_PORT --lua-init="$GUARD_TIMER" --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
|
||||
;;
|
||||
CYGWIN)
|
||||
# some methods require empty acks
|
||||
# use raw filter to filter target ip addresses in-kernel to allow multiple blockchecks running at the same time
|
||||
# use guard timer to kill unmanaged pktws instances
|
||||
"$WINWS2" --wf-tcp-empty=1 $WF --wf-raw-filter="$WFRAWF" \
|
||||
--lua-init="timer_set('exit_guard',function(name,data) io.stderr:write('exit_guard\n'); os.exit(3000); end,20000,true)" \
|
||||
--lua-init="$GUARD_TIMER" \
|
||||
--lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
|
||||
;;
|
||||
esac
|
||||
@@ -1038,7 +1133,7 @@ curl_test()
|
||||
[ $REPEATS -gt 1 ] && echo 'AVAILABLE'
|
||||
else
|
||||
code=$?
|
||||
[ "$SCANLEVEL" = quick ] && break
|
||||
[ "$SCANLEVEL" = quick -o "$SCANLEVEL" = veryquick ] && break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
@@ -1184,6 +1279,29 @@ result_intersection_print()
|
||||
n=$(($n + 1))
|
||||
done
|
||||
}
|
||||
result_coverage_print()
|
||||
{
|
||||
# Lists every distinct successful strategy together with how many of the
|
||||
# DOMAINS_COUNT domains/targets it worked for, most-covered first.
|
||||
# Unlike result_intersection_print, a strategy doesn't need 100% coverage
|
||||
# to be listed here - useful when DOMAINS is a set of largely independent
|
||||
# targets (e.g. one IP per ASN/provider) where no single strategy is
|
||||
# expected to satisfy every one of them, and the question is which
|
||||
# strategy gets closest.
|
||||
local n=0 hash hashvar hashcountvar ct val
|
||||
while : ; do
|
||||
eval hash=\"\$RES_$n\"
|
||||
[ -n "$hash" ] || break
|
||||
hashvar=RESHASH_${hash}
|
||||
hashcountvar=${hashvar}_COUNTER
|
||||
eval ct=\"\$$hashcountvar\"
|
||||
eval val=\"\$$hashvar\"
|
||||
printf '%s %s\n' "$ct" "$val"
|
||||
n=$(($n + 1))
|
||||
done | sort -rn | while IFS=' ' read -r ct rest; do
|
||||
echo "$ct/$DOMAINS_COUNT : $rest"
|
||||
done
|
||||
}
|
||||
report_strategy()
|
||||
{
|
||||
# $1 - test function
|
||||
@@ -1640,10 +1758,11 @@ ask_params()
|
||||
SCANLEVEL=standard
|
||||
[ "$BATCH" = 1 ] || {
|
||||
echo
|
||||
echo quick - in multi-attempt mode skip further attempts after first failure
|
||||
echo standard - do investigation what works on your DPI
|
||||
echo force - scan maximum despite of result
|
||||
ask_list SCANLEVEL "quick standard force" "$SCANLEVEL"
|
||||
echo veryquick - same as quick, and also stop testing more variations of a strategy family once one already succeeds
|
||||
echo quick - in multi-attempt mode skip further attempts after first failure
|
||||
echo standard - do investigation what works on your DPI
|
||||
echo force - scan maximum despite of result
|
||||
ask_list SCANLEVEL "veryquick quick standard force" "$SCANLEVEL"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1842,6 +1961,39 @@ check_dns()
|
||||
return $r
|
||||
}
|
||||
|
||||
|
||||
sweep_stale_pidfiles()
|
||||
{
|
||||
# $1 - fixed filename prefix immediately preceding the pid
|
||||
#
|
||||
# A normal exit already removes this run's own PARALLEL_OUT/HDRTEMP
|
||||
# files (unprepare_all(), further down), which covers Ctrl+C,
|
||||
# a closed terminal, and a plain kill. kill -9 and crashes bypass
|
||||
# that, as they would for any script's cleanup, and can leave
|
||||
# stale files behind indefinitely, since nothing about a later run
|
||||
# gives it any reason to know about a different PID's leftovers.
|
||||
# Removes a matching file only once its PID (the run that created
|
||||
# it) is confirmed no longer running, so a genuinely still-running
|
||||
# concurrent instance - a different PID, its own files - is never
|
||||
# touched.
|
||||
local f pid prefix="$1"
|
||||
for f in "$prefix"*; do
|
||||
[ -e "$f" ] || continue
|
||||
pid=${f#"$prefix"}
|
||||
pid=${pid%%[!0-9]*}
|
||||
[ -n "$pid" ] || continue
|
||||
kill -0 "$pid" 2>/dev/null || rm -f "$f"
|
||||
done
|
||||
}
|
||||
|
||||
sweep_leftovers()
|
||||
{
|
||||
sweep_stale_pidfiles $PARALLEL_OUT_TEMPLATE
|
||||
sweep_stale_pidfiles $HDRTEMP_TEMPLATE
|
||||
pktws_ipt_sweep
|
||||
}
|
||||
|
||||
|
||||
block_signals()
|
||||
{
|
||||
# prevent signal function reenter
|
||||
@@ -1894,11 +2046,13 @@ fix_sbin_path
|
||||
check_system
|
||||
check_already
|
||||
[ "$UNAME" != CYGWIN -a "$SKIP_PKTWS" != 1 ] && require_root
|
||||
sweep_leftovers
|
||||
check_prerequisites
|
||||
trap sigint_cleanup INT
|
||||
check_dns
|
||||
check_virt
|
||||
ask_params
|
||||
apply_header_padfile
|
||||
trap - INT
|
||||
|
||||
PID=
|
||||
@@ -1931,10 +2085,13 @@ report_print
|
||||
echo \* COMMON
|
||||
result_intersection_print
|
||||
echo
|
||||
echo \* COVERAGE
|
||||
result_coverage_print
|
||||
echo
|
||||
[ "$SCANLEVEL" = force ] || {
|
||||
echo "blockcheck optimizes test sequence. To save time some strategies can be skipped if their test is considered useless."
|
||||
echo "That's why COMMON intersection can miss strategies that would work for all domains."
|
||||
echo "Use \"force\" scan level to test all strategies and generate trustable intersection."
|
||||
echo "That's why COMMON intersection can miss strategies that would work for all domains, and COVERAGE counts can undercount."
|
||||
echo "Use \"force\" scan level to test all strategies and generate trustable results."
|
||||
echo "Current scan level was \"$SCANLEVEL\"".
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,3 +337,19 @@ v0.9.4.3
|
||||
1.0.5.1
|
||||
|
||||
* nfqws2: optimize profile search. fast checks first
|
||||
|
||||
1.0.5.2
|
||||
|
||||
* nfqws2: more profile search optimizations
|
||||
|
||||
1.0.6
|
||||
|
||||
* zapret-lib: dissect quic tvb values that can't fit into 52-bit mantissa into raw strings
|
||||
* zapret-lib, nfqws2: treat ? and # characters as domain end in URL
|
||||
* blockcheck2: in 10-list.sh try space separated logic as fallback if eval fails (useful for copy-paste from blockcheck2)
|
||||
* blockcheck2: CURL_PAD - add junk headers to increase request size and trigger 16-kb block without large downloaded data
|
||||
* blockcheck2: in addition to COMMON print COVERAGE section with how many domains worked for each strategy
|
||||
* blockcheck2: sweep old temp files after hard kill or crash. sweep ip/nf tables in linux
|
||||
* blockcheck2: pktws guard timer in all OS
|
||||
* blockcheck2: request PACE-ing
|
||||
* blockcheck2: veryquick scan level
|
||||
+53
-47
@@ -696,8 +696,8 @@ MULTI-STRATEGY:
|
||||
|
||||
LUA PACKET PASS MODE:
|
||||
--payload=type[,type] ; in-profile filter: payload filter for subsequent instances within the profile
|
||||
--out-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; in-profile filter: conntrack counter range for subsequent instances within the profile - outgoing direction
|
||||
--in-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; in-profile filter: conntrack counter range for subsequent instances within the profile - incoming direction
|
||||
--out-range=<mode>[<int>][(-|<)<mode>[<int>]] ; in-profile filter: conntrack counter range for subsequent instances within the profile - outgoing direction
|
||||
--in-range=<mode>[<int>][(-|<)<mode>[<int>]] ; in-profile filter: conntrack counter range for subsequent instances within the profile - incoming direction
|
||||
|
||||
LUA DESYNC ACTION:
|
||||
--lua-desync=<function>[:param1=val1[:param2=val2]] ; call a LUA instance with the specified parameters during profile processing if in-profile filter conditions are met
|
||||
@@ -1065,7 +1065,7 @@ Names are case-sensitive.
|
||||
These come in three types: `--payload`, `--in-range`, and `--out-range`. Filter values remain active from the moment they are specified until the next override.
|
||||
|
||||
- `--payload=type1[,type2][,type3]...` accepts a comma-separated list of known [payloads](#protocol-detection), "all", or "known". The default is `--payload=all`.
|
||||
- `--(in-range|out-range)=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>]` sets conntrack counter ranges for inbound and outbound directions. The default is `--in-range=x`, `--out-range=a`.
|
||||
- `--(in-range|out-range)=<mode>[<int>][(-|<)<mode>[<int>]]` sets conntrack counter ranges for inbound and outbound directions. The default is `--in-range=x`, `--out-range=a`.
|
||||
|
||||
Ranges are specified in the following formats: `mX-mY`, `mX<mY`, `-mY`, `<mY`, `mX-`, where `m` is the counter mode, `X` is the lower bound, and `Y` is the upper bound. Modes `x` and `a` are specified as a single letter without a range or counter value. The `-` sign indicates an inclusive upper bound, while `<` indicates an exclusive one.
|
||||
|
||||
@@ -2250,7 +2250,7 @@ If conntrack is disabled or the packet is not valid tcp or udp, nil is returned.
|
||||
function get_source_ip(target)
|
||||
```
|
||||
|
||||
Get source IP (raw string) that would be used for connection the the target IP.
|
||||
Get source IP (raw string) that would be used for connection to the target IP.
|
||||
Returns nil if destination is unreachable.
|
||||
|
||||
```
|
||||
@@ -2619,10 +2619,10 @@ Performs a linear search in table `a` for value `v`. `array_field_search` assume
|
||||
function in_list(s, v)
|
||||
```
|
||||
|
||||
### find_next_line
|
||||
|
||||
Checks whether string `v` is included in a comma-separated list of strings `s`. For example, `abc` is included in the list `xyz,abc,12345`.
|
||||
|
||||
### find_next_line
|
||||
|
||||
```
|
||||
function find_next_line(s, pos)
|
||||
```
|
||||
@@ -3464,7 +3464,7 @@ The `ipfrag_options` contain only two standard parameters. The rest are handled
|
||||
|
||||
| Field | Description |
|
||||
| :-------------- | :------------------------------------------------------------------------------------------------------------------ |
|
||||
| ipfrag | Name of the fragmenter function. If not specified, `ipfrag2` is used. The fragmenter returns an array of dissects (fragments). |
|
||||
| ipfrag | Name of the fragmenter function. If specified with no value, `ipfrag2` is used. The fragmenter returns an array of dissects (fragments). |
|
||||
| ipfrag_disorder | Send fragments in reverse order. |
|
||||
| ipfrag_pos_udp | (ipfrag2 fragmenter) UDP fragmentation position. Must be a multiple of 8; defaults to 8. |
|
||||
| ipfrag_pos_tcp | (ipfrag2 fragmenter) TCP fragmentation position. Must be a multiple of 8; defaults to 32. |
|
||||
@@ -4206,7 +4206,7 @@ function hostfakesplit(ctx, desync)
|
||||
- arg: host - template for [fake host generation](#genhost) - random.template
|
||||
- arg: midhost - [marker](#markers) for an additional split of the segment containing the real host.
|
||||
- arg: disorder_after - [marker](#markers) for an additional split of the final real part and sending segments in reverse order.
|
||||
- arg: nofake, nofake2 - skip sending specific fake packets.
|
||||
- arg: nofake1, nofake2 - skip sending specific fake packets.
|
||||
- arg: blob - replace the current payload with the specified [blob](#passing-blobs).
|
||||
- arg: optional - abort the operation if the blob is specified but missing.
|
||||
- arg: nodrop - skip issuing a VERDICT_DROP.
|
||||
@@ -4421,7 +4421,7 @@ function automate_failure_counter(hrec, crec, fails, maxtime)
|
||||
- hrec - [host storage](#automate_host_record)
|
||||
- crec - [stream storage](#automate_conn_record)
|
||||
- fails - the target number of failures.
|
||||
- maxtime - the time in seconds after which, since the last failure, the next failure restarts the count from scratch.
|
||||
- time - the time in seconds after which, since the last failure, the next failure restarts the count from scratch.
|
||||
|
||||
Returns `true` if the counter reaches the `fails` value. The counter is reset upon returning `true`.
|
||||
|
||||
@@ -4795,6 +4795,7 @@ Parallel mode is [supported](#shell-variables). In this mode, each attempt is ex
|
||||
|
||||
- **standard** - uses a test algorithm that excludes strategies deemed irrelevant based on previous successes or other criteria. In the case of multiple attempts, testing does not stop upon failure. The success rate and curl errors can also provide useful information for situational analysis.
|
||||
- **quick** - same as standard, but when using multiple attempts, testing stops after the first failure.
|
||||
- **veryquick** - same as quick, and also stops testing further variations of a strategy family (extra TCP foolings, autottl deltas, TTL values, and, where applicable, multisplit/fakedsplit positions and split-mechanisms) as soon as any combination has already succeeded for the current target, instead of continuing through the rest for completeness. Only affects the fake-based strategy families (25-fake.sh, 30-faked.sh, 35-hostfake.sh, 50-fake-multi.sh, 55-fake-faked.sh, 60-fake-hostfake.sh); can make those noticeably faster to test when an early candidate already succeeds, at the cost of not necessarily finding every strategy that would also have succeeded (success here means curl got through - it says nothing about how that strategy will actually do in a real browser).
|
||||
- **force** - tests as extensively as possible, regardless of previous test results.
|
||||
|
||||
### Supported protocols
|
||||
@@ -4928,6 +4929,8 @@ MULTIDISORDER=multidisorder_legacy - replace multidisorder with the version from
|
||||
NOTEST_BASIC_HTTP=1 - disable 10-http-basic.sh tests
|
||||
NOTEST_MISC_HTTP=1 - disable http 15-misc.sh tests
|
||||
NOTEST_MISC_HTTPS=1 - disable https 15-misc.sh tests
|
||||
NOTEST_OOB_HTTP=1 - disable http 17-oob.sh tests
|
||||
NOTEST_OOB_HTTPS=1 - disable https 17-oob.sh tests
|
||||
NOTEST_MULTI_HTTP=1 - disable http 20-multi.sh tests
|
||||
NOTEST_MULTI_HTTPS=1 - disable https 20-multi.sh tests
|
||||
NOTEST_SEQOVL_HTTP=1 - disable http 23-seqovl.sh tests
|
||||
@@ -4940,6 +4943,7 @@ NOTEST_FAKED_HTTP=1 - disable http 25-faked.sh tests
|
||||
NOTEST_FAKED_HTTPS=1 - disable https 25-faked.sh tests
|
||||
NOTEST_HOSTFAKE_HTTP=1 - disable http 35-hostfake.sh tests
|
||||
NOTEST_HOSTFAKE_HTTPS=1 - disable https 35-hostfake.sh tests
|
||||
HOSTFAKE=host - specify hostname for hostfakesplit
|
||||
NOTEST_FAKE_MULTI_HTTP=1 - disable http 50-fake-multi.sh tests
|
||||
NOTEST_FAKE_MULTI_HTTPS=1 - disable https 50-fake-multi.sh tests
|
||||
NOTEST_FAKE_FAKED_HTTP=1 - disable http 55-fake-faked.sh tests
|
||||
@@ -4953,53 +4957,55 @@ NOTEST_QUIC=1 - disable 90-quic.sh tests
|
||||
|
||||
A simple tester that uses strategy lists from files. Strategies must be on separate lines; line breaks within a single strategy are not allowed. Separate lists are used for different protocols: `list_http.txt`, `list_https_tls12.txt`, `list_https_tls13.txt`, and `list_quic.sh`. These files support comments starting with `#`.
|
||||
|
||||
When defining parameters, keep in mind that they will be interpreted as shell arguments. Special characters must be escaped according to shell rules.
|
||||
For example, leaving `<` unquoted across the entire parameter or incorrectly quoting the `--luaexec=code=print("abc")` parameter will result in an error. If your Lua code uses strings, it is best to enclose them in single quotes and wrap the entire parameter in double quotes.
|
||||
When defining parameters, keep in mind that they will first be tried as shell arguments. Special characters (`<`, `(`, `'`, and similar) are shell syntax and would normally need escaping - for example, leaving `<` unquoted across the entire parameter, or incorrectly quoting the `--luaexec=code=print("abc")` parameter, would previously result in an error. If a line fails this way now, it's automatically retried as a plain, unparsed argument list instead (split only on whitespace, nothing re-interpreted), so strategies containing these characters work whether or not you escape them yourself - copy one straight from `blockcheck2`'s own output and it will just work. Escaping by hand (single quotes around Lua strings, the whole parameter wrapped in double quotes) is still supported and still takes priority when it succeeds, for anyone who wants shell-side expansion inside a list line.
|
||||
Note that `blockcheck2` will output strategy parameters without escaping.
|
||||
|
||||
The recommended way to use this is to copy it into its own subdirectory within `blockcheck2.d` and populate the `.txt` files with your tests. Then, select your custom test name from the dialog.
|
||||
|
||||
## Summary
|
||||
|
||||
At the end of the test, all successful strategies are displayed for each domain and each IP protocol version. If more than one domain was tested, the intersection of successful strategies (those that worked for all) is also provided. However, this intersection can only be fully relied upon when using `SCANLEVEL=force`. Otherwise, strategies that might have worked for subsequent domains might not have been tested for the first one.
|
||||
At the end of the test, all successful strategies are displayed for each domain and each IP protocol version. If more than one domain was tested, the intersection of successful strategies (those that worked for all, labeled COMMON) is also provided, together with a COVERAGE listing of every successful strategy and how many of the domains it worked for, most-covered first - useful when testing a set of largely independent targets where no single strategy is expected to satisfy all of them. However, COMMON and the COVERAGE counts can only be fully relied upon when using `SCANLEVEL=force`. Otherwise, strategies that might have worked for subsequent domains might not have been tested for the first one.
|
||||
|
||||
## Shell variables
|
||||
|
||||
```
|
||||
CURL - path to the curl executable
|
||||
CURL_MAX_TIME - curl timeout in seconds
|
||||
CURL_MAX_TIME_QUIC - curl timeout for QUIC. If not set, CURL_MAX_TIME is used
|
||||
CURL_MAX_TIME_DOH - curl timeout for DoH servers
|
||||
CURL_CMD=1 - display curl commands
|
||||
CURL_OPT - additional curl options. `-k` to ignore certificates, `-v` for verbose protocol output
|
||||
CURL_HTTPS_GET=1 - use the GET method instead of HEAD for HTTPS
|
||||
DOMAINS - space-separated list of domains or domains with URIs to test
|
||||
TEST - name of the test
|
||||
IPVS=4|6|46 - IP protocol versions to test
|
||||
ENABLE_HTTP=0|1 - enable plain HTTP test
|
||||
ENABLE_HTTPS_TLS12=0|1 - enable HTTPS TLS 1.2 test
|
||||
ENABLE_HTTPS_TLS13=0|1 - enable HTTPS TLS 1.3 test
|
||||
ENABLE_HTTP3=0|1 - enable QUIC test
|
||||
REPEATS - number of test attempts
|
||||
PARALLEL=0|1 - enable parallel attempts. May overwhelm the site due to aggressive requests and lead to incorrect results
|
||||
SCANLEVEL=quick|standard|force - scanning level
|
||||
BATCH=1 - batch mode (no prompts or waiting for console input)
|
||||
HTTP_PORT, HTTPS_PORT, QUIC_PORT - port numbers for the respective protocols
|
||||
SKIP_DNSCHECK=1 - skip DNS check
|
||||
SKIP_IPBLOCK=1 - skip port or IP blocking tests
|
||||
PKTWS_EXTRA_POST - additional nfqws/dvtws/winws parameters added after the main strategy
|
||||
PKTWS_EXTRA_POST_1 .. PKTWS_EXTRA_POST_9 - separate additional parameters that contain spaces
|
||||
PKTWS_EXTRA_PRE - additional nfqws/dvtws/winws parameters added before the main strategy
|
||||
PKTWS_EXTRA_PRE_1 .. PKTWS_EXTRA_PRE_9 - separate additional parameters that contain spaces
|
||||
DNSCHECK_DNS - space-separated list of third-party DNS servers for DNS spoofing tests
|
||||
DNSCHECK_DOM - space-separated list of domains for DNS spoofing tests
|
||||
SECURE_DNS=0|1 - force enable or disable DoH
|
||||
DOH_SERVERS - space-separated list of DoH URLs for automatic selection of a working server
|
||||
DOH_SERVER - specific DoH URL (disables auto-selection)
|
||||
UNBLOCKED_DOM - an unblocked domain used for IP block tests
|
||||
SIMULATE=1 - enable simulation mode for debugging script logic. Disables real curl requests and replaces them with random results.
|
||||
SIM_SUCCESS_RATE=<percent> - simulation success probability as a percentage
|
||||
```
|
||||
| Variable | Description |
|
||||
| :------- | :---------- |
|
||||
| CURL | path to the curl executable |
|
||||
| CURL_MAX_TIME | curl timeout in seconds |
|
||||
| CURL_MAX_TIME_QUIC | curl timeout for QUIC. If not set, CURL_MAX_TIME is used |
|
||||
| CURL_MAX_TIME_DOH | curl timeout for DoH servers |
|
||||
| CURL_CMD=1 | display curl commands |
|
||||
| CURL_OPT | additional curl options. `-k` to ignore certificates, `-v` for verbose protocol output |
|
||||
| CURL_HTTPS_GET=1 | use the GET method instead of HEAD for HTTPS |
|
||||
| CURL_PAD | pad every curl request with a junk headers of this many bytes. Full length taken into account along with header name, data field and EOL. Useful for testing a "16 KB"-style whitelist block against a target with no large page of its own to download, since that block triggers on total bytes transferred rather than on how much of it was a real response. Independent of CURL_HTTPS_GET; use whichever fits the target |
|
||||
| PAD_MAX_HEADER | maximum length in bytes of the data field of one header for CURL_PAD padding. the length can be exceeded by no more than 14 characters for the last header, if the last header together with the name and EOL could be less than 14 characters |
|
||||
| PACE | minimum time in msec for a single curl query. allows to slow down hammering to avoid server side ban |
|
||||
| DOMAINS | space-separated list of domains or domains with URIs to test |
|
||||
| TEST | name of the test |
|
||||
| IPVS=4\|6\|46 | IP protocol versions to test |
|
||||
| ENABLE_HTTP=0\|1 | enable plain HTTP test |
|
||||
| ENABLE_HTTPS_TLS12=0\|1 | enable HTTPS TLS 1.2 test |
|
||||
| ENABLE_HTTPS_TLS13=0\|1 | enable HTTPS TLS 1.3 test |
|
||||
| ENABLE_HTTP3=0\|1 | enable QUIC test |
|
||||
| REPEATS | number of test attempts |
|
||||
| PARALLEL=0|1 | enable\ parallel\ attempts. May overwhelm the site due to aggressive requests and lead to incorrect results |
|
||||
| SCANLEVEL=quick\|standard\|force | scanning level |
|
||||
| BATCH=1 | batch mode (no prompts or waiting for console input) |
|
||||
| HTTP_PORT, HTTPS_PORT, QUIC_PORT | port numbers for the respective protocols |
|
||||
| SKIP_DNSCHECK=1 | skip DNS check |
|
||||
| SKIP_IPBLOCK=1 | skip port or IP blocking tests |
|
||||
| PKTWS_EXTRA_POST | additional nfqws/dvtws/winws parameters added after the main strategy |
|
||||
| PKTWS_EXTRA_POST_1 .. PKTWS_EXTRA_POST_9 | separate additional parameters that contain spaces |
|
||||
| PKTWS_EXTRA_PRE | additional nfqws/dvtws/winws parameters added before the main strategy |
|
||||
| PKTWS_EXTRA_PRE_1 .. PKTWS_EXTRA_PRE_9 | separate additional parameters that contain spaces |
|
||||
| DNSCHECK_DNS | space-separated list of third-party DNS servers for DNS spoofing tests |
|
||||
| DNSCHECK_DOM | space-separated list of domains for DNS spoofing tests |
|
||||
| SECURE_DNS=0\|1 | force enable or disable DoH |
|
||||
| DOH_SERVERS | space-separated list of DoH URLs for automatic selection of a working server |
|
||||
| DOH_SERVER | specific DoH URL (disables auto-selection) |
|
||||
| UNBLOCKED_DOM | an unblocked domain used for IP block tests |
|
||||
| SIMULATE=1 | enable simulation mode for debugging script logic. Disables real curl requests and replaces them with random results. |
|
||||
| SIM_SUCCESS_RATE=\<percent\> | simulation success probability as a percentage |
|
||||
|
||||
## Why it won't open
|
||||
|
||||
|
||||
+53
-47
@@ -756,8 +756,8 @@ MULTI-STRATEGY:
|
||||
|
||||
LUA PACKET PASS MODE:
|
||||
--payload=type[,type] ; внутрипрофильный фильтр : фильтр пейлоада для последующих инстансов внутри профиля
|
||||
--out-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; внутрипрофильный фильтр : диапазон счетчиков conntrack для последующих инстансов внутри профиля - исходящее направление
|
||||
--in-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; внутрипрофильный фильтр : диапазон счетчиков conntrack для последующих инстансов внутри профиля - входящее направление
|
||||
--out-range=<mode>[<int>][(-|<)<mode>[<int>]] ; внутрипрофильный фильтр : диапазон счетчиков conntrack для последующих инстансов внутри профиля - исходящее направление
|
||||
--in-range=<mode>[<int>][(-|<)<mode>[<int>]] ; внутрипрофильный фильтр : диапазон счетчиков conntrack для последующих инстансов внутри профиля - входящее направление
|
||||
|
||||
LUA DESYNC ACTION:
|
||||
--lua-desync=<function>[:param1=val1[:param2=val2]] ; при обработке профиля вызвать LUA инстанс с указанными параметрами, если соблюдены условия внутрипрофильных фильтров
|
||||
@@ -794,7 +794,7 @@ LUA DESYNC ACTION:
|
||||
--wf-tcp-out=[~]port1[-port2] ; WinDivert конструктор : tcp порты или диапазоны портов для перехвата по исходящему направлению. список через запятую
|
||||
--wf-udp-in=[~]port1[-port2] ; WinDivert конструктор : udp порты или диапазоны портов для перехвата по входящему направлению. список через запятую
|
||||
--wf-udp-out=[~]port1[-port2] ; WinDivert конструктор : udp порты или диапазоны портов для перехвата по исходящему направлению. список через запятую
|
||||
--wf-tcp-empty=[~]port1[-port2] ; WinDivert конструктор : перехватывать пустые tcp пакеты ACK. по умолчанию - нет.
|
||||
--wf-tcp-empty=[0|1] ; WinDivert конструктор : перехватывать пустые tcp пакеты ACK. по умолчанию - нет.
|
||||
--wf-icmp-in=type[:code] ; WinDivert конструктор : icmp type и code по входящему направлению. если code не задан - любой code. список через запятую
|
||||
--wf-icmp-out=type[:code] ; WinDivert конструктор : icmp type и code по исходящему направлению. если code не задан - любой code. список через запятую
|
||||
--wf-ipp-in=type[:code] ; WinDivert конструктор : номера raw ip протоколов по входящему направлению. список через запятую
|
||||
@@ -1194,7 +1194,7 @@ Lua код выполняется с ограниченными правами,
|
||||
Значения фильтров действуют с момента их указания до следующего переопределения.
|
||||
|
||||
- `--payload=type1[,type2][,type3]...` принимает список известных пейлоадов через запятую, "all" или "known". [Список известных пейлоадов](#распознавание-протоколов). По умолчанию `--payload=all`.
|
||||
- `--(in-range|out-range)=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>]` задает диапазоны счетчиков conntrack по входящему и исходящему направлениям. По умолчанию `--in-range=x`, `--out-range=a`.
|
||||
- `--(in-range|out-range)=<mode>[<int>][(-|<)<mode>[<int>]]` задает диапазоны счетчиков conntrack по входящему и исходящему направлениям. По умолчанию `--in-range=x`, `--out-range=a`.
|
||||
|
||||
Диапазоны задаются в формах : `mX-mY`, `mX<mY`, `-mY`, `<mY`, `mX-`, где m - режим счетчика, X - нижнее значение, Y - верхнее значение.
|
||||
Режимы `x` и `a` задаются без диапазона и значения счетчика - единственной буквой. Знак `-` означает включающую верхнюю границу, `<` - исключающую.
|
||||
@@ -2784,10 +2784,10 @@ function array_field_search(a, f, v)
|
||||
function in_list(s, v)
|
||||
```
|
||||
|
||||
### find_next_line
|
||||
|
||||
Включена ли строка v в список строк через запятую s. Например, `abc` включено в список `xyz,abc,12345`.
|
||||
|
||||
### find_next_line
|
||||
|
||||
```
|
||||
function find_next_line(s, pos)
|
||||
```
|
||||
@@ -3641,7 +3641,7 @@ tcp_ts_up дублирует старое поведение - двигает ti
|
||||
|
||||
| Поле | Описание |
|
||||
| :-------------- | :--------------------------------------------------------------------------------------------------------------- |
|
||||
| ipfrag | имя функции фрагментатора. если нет, использовать ipfrag2. фрагментатор возвращает массив диссектов - фрагментов |
|
||||
| ipfrag | имя функции фрагментатора. если имя пустое, использовать ipfrag2. фрагментатор возвращает массив диссектов - фрагментов |
|
||||
| ipfrag_disorder | отправить фрагменты в обратном порядке |
|
||||
| ipfrag_pos_udp | (фрагментатор ipfrag2) позиция фрагментации udp. должна быть кратна 8, по умолчанию 8 |
|
||||
| ipfrag_pos_tcp | (фрагментатор ipfrag2) позиция фрагментации tcp. должна быть кратна 8, по умолчанию 32 |
|
||||
@@ -4397,7 +4397,7 @@ function hostfakesplit(ctx, desync)
|
||||
- arg: host - шаблон для [генерации фейкового хоста](#genhost) - random.template
|
||||
- arg: midhost - [маркер](#маркеры) для дополнительного разреза сегмента с реальным хостом
|
||||
- arg: disorder_after - [маркер](#маркеры) для дополнительного разреза заключительной реальной части и отправки сегментов в обратном порядке
|
||||
- arg: nofake, nofake2 - отказ от отсылки отдельных фейков
|
||||
- arg: nofake1, nofake2 - отказ от отсылки отдельных фейков
|
||||
- arg: blob - заменить текущий пейлоад на указанный [blob](#передача-блобов)
|
||||
- arg: optional - отказ от операции, если blob задан, но отсутствует
|
||||
- arg: nodrop - отказ от вынесения VERDICT_DROP
|
||||
@@ -4640,7 +4640,7 @@ function automate_failure_check(desync, hrec, crec)
|
||||
- arg: success_detector - имя функции детектора удач. если не задано, используется standard_success_detector.
|
||||
- arg: failure_detector - имя функции детектора неудач. если не задано, используется standard_failure_detector.
|
||||
- arg: fails - целевое значение счетчика неудач. По умолчанию - 3.
|
||||
- arg: maxtime - максимальное время в секундах между неудачами, после которого счетчик сбрасывается. По умолчанию - 60 сек.
|
||||
- arg: time - максимальное время в секундах между неудачами, после которого счетчик сбрасывается. По умолчанию - 60 сек.
|
||||
|
||||
Функция выполняет ведение счетчика неудач, вызывая детекторы удачи и неудачи. Возвращает true, если счетчик достиг целевого значения. При этом счетчик сбрасывается автоматически.
|
||||
|
||||
@@ -4983,6 +4983,7 @@ blockcheck2 способен определить подменяется ли DN
|
||||
|
||||
- standard - использовать алгоритм теста, позволяющий исключить тестирование неактуальных по его мнению стратегий в зависимости от успешности предыдущих или по каким-то другим критериям. В случае множественных попыток тестирование не прекращается при неудаче. Процент успеха и ошибки curl тоже могут служить полезной информации при анализе ситуации.
|
||||
- quick - то же самое, что и standard, но при использовании множественных попыток прекращение тестирования после первой неудачи
|
||||
- veryquick - то же самое, что и quick, а также прекращение перебора оставшихся вариантов внутри семейства стратегий (доп. TCP foolings, autottl-дельты, TTL, а где применимо - позиции multisplit/fakedsplit и сами split-механизмы), как только для текущей цели уже нашлась хоть одна успешная комбинация, вместо перебора всех вариантов до конца. Затрагивает только семейства на основе fake (25-fake.sh, 30-faked.sh, 35-hostfake.sh, 50-fake-multi.sh, 55-fake-faked.sh, 60-fake-hostfake.sh); может заметно ускорить тестирование этих семейств, если успешная комбинация находится рано, ценой того, что не все стратегии, которые тоже могли бы оказаться успешными, будут найдены (успех здесь значит, что curl прошел - это ничего не говорит о том, как эта стратегия поведет себя в реальном браузере)
|
||||
- force - тестировать максимально много без учета результата предыдущих тестов
|
||||
|
||||
### Поддерживаемые протоколы
|
||||
@@ -5116,6 +5117,8 @@ MULTIDISORDER=multidisorder_legacy - заменить multidisorder на вар
|
||||
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_OOB_HTTP=1 - отмена тестов http 17-oob.sh
|
||||
NOTEST_OOB_HTTPS=1 - отмена тестов https 17-oob.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
|
||||
@@ -5128,6 +5131,7 @@ NOTEST_FAKED_HTTP=1 - отмена тестов http 25-faked.sh
|
||||
NOTEST_FAKED_HTTPS=1 - отмена тестов https 25-faked.sh
|
||||
NOTEST_HOSTFAKE_HTTP=1 - отмена тестов http 35-hostfake.sh
|
||||
NOTEST_HOSTFAKE_HTTPS=1 - отмена тестов https 35-hostfake.sh
|
||||
HOSTFAKE=host - указание конкретного имени хоста для hostfakesplit
|
||||
NOTEST_FAKE_MULTI_HTTP=1 - отмена тестов http 50-fake-multi.sh
|
||||
NOTEST_FAKE_MULTI_HTTPS=1 - отмена тестов https 50-fake-multi.sh
|
||||
NOTEST_FAKE_FAKED_HTTP=1 - отмена тестов http 55-fake-faked.sh
|
||||
@@ -5141,53 +5145,55 @@ 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 коде используются строки - их стоит заключать в одинарные кавычки, а вокруг параметра - двойные.
|
||||
При записи параметров следует учитывать, что сначала они будут опробованы как параметры shell. Специальные символы (`<`, `(`, `'` и подобные) являются синтаксисом shell и обычно требуют экранирования - например, раньше "<" без кавычек на всем параметре или неверно взятый в кавычки параметр `--luaexec=code=print("abc")` приводили к ошибке. Теперь, если строка не проходит таким образом, она автоматически пробуется заново как обычный, неразбираемый список аргументов (разбивается только по пробелам, ничего не переинтерпретируется) - поэтому стратегии с такими символами работают вне зависимости от того, экранировали вы их сами или нет, и строку можно скопировать прямо из вывода `blockcheck2` без правок. Ручное экранирование (одинарные кавычки вокруг lua-строк, весь параметр в двойных) по-прежнему поддерживается и имеет приоритет, если срабатывает - для тех, кому нужно shell-раскрытие внутри строки списка.
|
||||
blockcheck2 будет выдавать параметры стратегий без экранирования.
|
||||
|
||||
Самый правильный способ применения - скопировать в свою поддиректорию внутри `blockcheck2.d` и заполнить txt файлы с тестами. Выбрать свое имя теста в диалоге.
|
||||
|
||||
## Summary
|
||||
|
||||
В конце теста выдаются все успешные стратегии по каждому домену и каждой версии ip протокола. Если тестировалось более одного домена, дополнительно выдается пересечение успешных стратегий. Однако, ему можно полностью доверять только при использовании SCANLEVEL=force. Иначе возможна ситуация, когда для первого домена не стали тестировать стратегии, которые подошли бы для последующих.
|
||||
В конце теста выдаются все успешные стратегии по каждому домену и каждой версии ip протокола. Если тестировалось более одного домена, дополнительно выдается пересечение успешных стратегий (те, что сработали для всех, блок COMMON), а также список COVERAGE - каждая успешная стратегия и число доменов, для которых она сработала, по убыванию - полезно, когда цели в DOMAINS во многом независимы друг от друга и ни одна стратегия не обязана подходить для всех сразу. Однако, и COMMON, и счетчики в COVERAGE можно полностью доверять только при использовании SCANLEVEL=force. Иначе возможна ситуация, когда для первого домена не стали тестировать стратегии, которые подошли бы для последующих.
|
||||
|
||||
## Shell переменные
|
||||
|
||||
```
|
||||
CURL - замена программы curl
|
||||
CURL_MAX_TIME - время таймаута curl в секундах
|
||||
CURL_MAX_TIME_QUIC - время таймаута curl для quic. если не задано, используется значение CURL_MAX_TIME
|
||||
CURL_MAX_TIME_DOH - время таймаута curl для DoH серверов
|
||||
CURL_CMD=1 - показывать команды curl
|
||||
CURL_OPT - дополнительные параметры curl. `-k` - игнор сертификатов. `-v` - подробный вывод протокола
|
||||
CURL_HTTPS_GET=1 - использовать метод GET вместо HEAD для https
|
||||
DOMAINS - список тестируемых доменов или доменов с URI через пробел
|
||||
TEST - имя теста
|
||||
IPVS=4|6|46 - тестируемые версии ip протокола
|
||||
ENABLE_HTTP=0|1 - включить тест plain http
|
||||
ENABLE_HTTPS_TLS12=0|1 - включить тест https TLS 1.2
|
||||
ENABLE_HTTPS_TLS13=0|1 - включить тест https TLS 1.3
|
||||
ENABLE_HTTP3=0|1 - включить тест QUIC
|
||||
REPEATS - количество попыток тестирования
|
||||
PARALLEL=0|1 - включить параллельные попытки. может обидеть сайт из-за долбежки и привести к неверному результату
|
||||
SCANLEVEL=quick|standard|force - уровень сканирования
|
||||
BATCH=1 - пакетный режим без вопросов и ожидания ввода в консоли
|
||||
HTTP_PORT, HTTPS_PORT, QUIC_PORT - номера портов для соответствующих протоколов
|
||||
SKIP_DNSCHECK=1 - отказ от проверки DNS
|
||||
SKIP_IPBLOCK=1 - отказ от тестов блокировки по порту или IP
|
||||
PKTWS_EXTRA_POST - дополнительные параметры nfqws/dvtws/winws, указываемые после основной стратегии
|
||||
PKTWS_EXTRA_POST_1 .. PKTWS_EXTRA_POST_9 - отдельно дополнительные параметры, содержащие пробелы
|
||||
PKTWS_EXTRA_PRE - дополнительные параметры для nfqws/dvtws/winws, указываемые перед основной стратегией
|
||||
PKTWS_EXTRA_PRE_1 .. PKTWS_EXTRA_PRE_9 - отдельно дополнительные параметры, содержащие пробелы
|
||||
DNSCHECK_DNS - список сторонних DNS через пробел для тестирования подмены DNS
|
||||
DNSCHECK_DOM - список доменов через пробел для тестирования подмены DNS
|
||||
SECURE_DNS=0|1 - принудительно выключить или включить DoH
|
||||
DOH_SERVERS - список URL DoH через пробел для автоматического выбора работающего сервера
|
||||
DOH_SERVER - конкретный DoH URL, отказ от поиска
|
||||
UNBLOCKED_DOM - незаблокированный домен, который используется для тестов IP block
|
||||
SIMULATE=1 - включить режим симуляции для отладки логики скрипта. отключаются реальные запросы через curl, заменяются рандомным результатом.
|
||||
SIM_SUCCESS_RATE=<percent> - вероятность успеха симуляции в процентах
|
||||
```
|
||||
| Переменная | Назначение |
|
||||
| :--------- | :--------- |
|
||||
| CURL| замена программы curl |
|
||||
| CURL_MAX_TIME | время таймаута curl в секундах |
|
||||
| CURL_MAX_TIME_QUIC | время таймаута curl для quic. если не задано, используется значение CURL_MAX_TIME |
|
||||
| CURL_MAX_TIME_DOH | время таймаута curl для DoH серверов |
|
||||
| CURL_CMD=1 | показывать команды curl |
|
||||
| CURL_OPT | дополнительные параметры curl. `-k` - игнор сертификатов. `-v` - подробный вывод протокола |
|
||||
| CURL_HTTPS_GET=1 | использовать метод GET вместо HEAD для https |
|
||||
| CURL_PAD | добавлять к каждому запросу curl мусорные заголовки длиной не более PAD_MAX_HEADER байт (4000 по умолчанию) на указанное число байт. Учитывается полная длина вместе с названием хедера, полем данных и EOL. Полезно для проверки блока в стиле "16 кб" на ресурсе без своей большой страницы для скачивания, поскольку этот блок срабатывает по суммарному числу переданных байт, а не по тому, сколько из них было настоящим ответом. Независимо от CURL_HTTPS_GET, используйте то, что подходит для конкретной цели |
|
||||
| PAD_MAX_HEADER | максимальная длина в байтах поля данных одного хедера для паддинга CURL_PAD. длина может быть превышена на не болеее, чем 14 символов, для последнего хедера, если последний хедер вместе с названием и EOL мог бы получиться менее 14 символов |
|
||||
| PACE | минимальное время выполнения одного curl запроса в мсек. позволяет притормозить долбежку, чтобы не обидеть сайт |
|
||||
| DOMAINS | список тестируемых доменов или доменов с URI через пробел |
|
||||
| TEST | имя теста |
|
||||
| IPVS=4\|6\|46 | тестируемые версии ip протокола |
|
||||
| ENABLE_HTTP=0\|1 | включить тест plain http |
|
||||
| ENABLE_HTTPS_TLS12=0\|1 | включить тест https TLS 1.2 |
|
||||
| ENABLE_HTTPS_TLS13=0\|1 | включить тест https TLS 1.3 |
|
||||
| ENABLE_HTTP3=0\|1 | включить тест QUIC |
|
||||
| REPEATS | количество попыток тестирования |
|
||||
| PARALLEL=0\|1 | включить параллельные попытки. может обидеть сайт из-за долбежки и привести к неверному результату |
|
||||
| SCANLEVEL=quick\|standard\|force | уровень сканирования |
|
||||
| BATCH=1 | пакетный режим без вопросов и ожидания ввода в консоли |
|
||||
| HTTP_PORT, HTTPS_PORT, QUIC_PORT | номера портов для соответствующих протоколов |
|
||||
| SKIP_DNSCHECK=1 | отказ от проверки DNS |
|
||||
| SKIP_IPBLOCK=1 | отказ от тестов блокировки по порту или IP |
|
||||
| PKTWS_EXTRA_POST | дополнительные параметры nfqws/dvtws/winws, указываемые после основной стратегии |
|
||||
| PKTWS_EXTRA_POST_1 .. PKTWS_EXTRA_POST_9 | отдельно дополнительные параметры, содержащие пробелы |
|
||||
| PKTWS_EXTRA_PRE | дополнительные параметры для nfqws/dvtws/winws, указываемые перед основной стратегией |
|
||||
| PKTWS_EXTRA_PRE_1 .. PKTWS_EXTRA_PRE_9 | отдельно дополнительные параметры, содержащие пробелы |
|
||||
| DNSCHECK_DNS | список сторонних DNS через пробел для тестирования подмены DNS |
|
||||
| DNSCHECK_DOM | список доменов через пробел для тестирования подмены DNS |
|
||||
| SECURE_DNS=0\|1 | принудительно выключить или включить DoH |
|
||||
| DOH_SERVERS | список URL DoH через пробел для автоматического выбора работающего сервера |
|
||||
| DOH_SERVER | конкретный DoH URL, отказ от поиска |
|
||||
| UNBLOCKED_DOM | незаблокированный домен, который используется для тестов IP block |
|
||||
| SIMULATE=1 | включить режим симуляции для отладки логики скрипта. отключаются реальные запросы через curl, заменяются рандомным результатом. |
|
||||
| SIM_SUCCESS_RATE=\<percent\> | вероятность успеха симуляции в процентах |
|
||||
|
||||
## Почему не открывается
|
||||
|
||||
|
||||
+9
-2
@@ -52,7 +52,8 @@ Lua код получает от C кода структурированное
|
||||
Имеется библиотека хелперов, написанных на Lua, а так же готовая библиотека программ атаки на DPI (стратегий), реализующая функции *nfqws1* в расширенном варианте
|
||||
и с большей гибкостью.
|
||||
|
||||
Вы всегда сможете взять и дописать что-то свое. В этом и есть смысл, чтобы борьбой с DPI смог заняться любой, кто разбирается в пакетах.
|
||||
Вы всегда сможете взять и дописать что-то свое. От мелкой частной кустомизации, которую бессмысленно зашивать намертво в C код, до полноценной desync функции.
|
||||
В этом и есть смысл, чтобы борьбой с DPI смог заняться любой, кто разбирается в пакетах.
|
||||
Мог "потыкать" его, проверить свои идеи. А потом поделиться с друзьями своим решением "одного клика".
|
||||
zapret2 - инструмент для таких энтузиастов. Но это не готовое решение для чайников. Проект не ставит себе целью сделать все простым для всех.
|
||||
Автор считает, что это невозможно в принципе по обьективным причинам.
|
||||
@@ -429,7 +430,13 @@ nfqws2 \
|
||||
### Не только лишь автономный обман DPI
|
||||
|
||||
Рабочий тестовый пример icmp обфускатора udp от винды к серверу на vps.
|
||||
Для теста используем wireguard. Ничего в конфигах менять не надо - wireguard будет думать, что он работает по udp, но на самом деле он преобразуется в пинги icmp, которые могут проходить NAT. Размер пакетов не изменяется, потому проблемы MTU нет.
|
||||
Для теста используем wireguard. Ничего в конфигах менять не надо - wireguard будет думать, что он работает по udp, но на самом деле он преобразуется в пинги icmp, которые могут проходить NAT.
|
||||
|
||||
Если NAT не меняет поле Identifier в icmp (типично для Linux NAT), можно использовать легкий stateless вариант, когда размер пакета не меняется, и он с гарантией влезает в MTU.
|
||||
Провайдерский CGNAT меняет Identifier. Для его поддержки существует параметр udp2icmp `cgnat`. Клиент увеличит размеры исходящих пакетов на 2 байта, поэтому нужно предварительно
|
||||
уменьшить MTU интерфейса wireguard на 2, если он выбран "под завязку". В режиме cgnat серверный конец будет вести базу измененных идентификаторов и сохранять их при ответе.
|
||||
Обычно на CGNAT время жизни icmp identifier небольшое - 30 секунд, но может быть еще меньше, и освежаться может только исходящими пакетами. Поэтому нужен частый keepalive со стороны клиента.
|
||||
Если этого не сделать, будет обрыв до момента, когда wireguard клиент что-либо пошлет. Некоторые операторы троттлят icmp, поэтому могут быть проблемы со скоростью.
|
||||
|
||||
Будем загонять исходящие с клиента в icmp type 8 (echo request) code 199 , исходящие с сервера в icmp type 0 (echo reply) code 199.
|
||||
Код у обоих концов делаем одинаковый, иначе NAT не соотнесет. Без NAT можно коды делать разными для клиента и сервера.
|
||||
|
||||
@@ -589,7 +589,7 @@ end
|
||||
-- algorithm is not 100% the same as in nfqws1. multi-segment queries can produce different segment ordering.
|
||||
-- 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=<posmarker> . decrease seq number of the second segment in the original order by N and fill N bytes with pattern (default - all zero). N is resolved marker position and 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 : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent
|
||||
@@ -643,7 +643,7 @@ end
|
||||
-- nfqws1 : "--dpi-desync=multidisorder". segment ordering is the same as in nfqws1
|
||||
-- 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=<posmarker> . decrease seq number of the second segment in the original order by N and fill N bytes with pattern (default - all zero). N is resolved marker position and must be less than the first split pos.
|
||||
-- arg : seqovl_pattern=<blob> . override pattern
|
||||
-- arg : optional - use zero pattern if seqovl_pattern blob is absent
|
||||
function multidisorder_legacy(ctx, desync)
|
||||
|
||||
+4
-3
@@ -301,9 +301,10 @@ end
|
||||
-- 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: time=<sec> - if last failure happened earlier than `time` seconds ago - reset failure counter. default is 60.
|
||||
-- arg: success_detector - success detector function name
|
||||
-- arg: failure_detector - failure detector function name
|
||||
-- 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
|
||||
-- args for failure detector - see standard_failure_detector or your own detector
|
||||
-- args for success detector - see standard_success_detector or your own detector
|
||||
@@ -409,7 +410,7 @@ end
|
||||
function cond_tcp_has_ts(desync)
|
||||
return desync.dis.tcp and find_tcp_option(desync.dis.tcp.options, TCP_KIND_TS)
|
||||
end
|
||||
-- exec lua code in "code" arg and return it's result
|
||||
-- exec lua code in "cond_code" arg and return it's result
|
||||
function cond_lua(desync)
|
||||
if not desync.arg.cond_code then
|
||||
error("cond_lua: no 'cond_code' parameter")
|
||||
@@ -463,7 +464,7 @@ function condition(ctx, desync)
|
||||
end
|
||||
-- execute further desync instances.
|
||||
-- each instance must have "cond" arg and may optionally have "cond_neg" arg.
|
||||
-- "cond" - condition function. "neg" - invert condition function result
|
||||
-- "cond" - condition function. "cond_neg" - invert condition function result
|
||||
-- arg: instances - how many instances execute conditionally. all if not defined
|
||||
function per_instance_condition(ctx, desync)
|
||||
orchestrate(ctx, desync)
|
||||
|
||||
+117
-97
@@ -918,7 +918,7 @@ end
|
||||
-- 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_md5[=hex] - add MD5 header with optional 16-byte data. random 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 it's present. this allows linux not to accept badack segments without badseq. this is very strange discovery but it works.
|
||||
@@ -1290,7 +1290,7 @@ function rawsend_payload_segmented(desync, payload, seq, options)
|
||||
end
|
||||
|
||||
|
||||
-- check if desync.outgoing comply with arg.dir or def if it's not present or "out" of they are not present both. dir can be "in","out","any"
|
||||
-- check if desync.outgoing complies with arg.dir or def if it's not present or "out" if they are not present both. dir can be "in","out","any"
|
||||
function direction_check(desync, def)
|
||||
local dir = desync.arg.dir or def or "out"
|
||||
return desync.outgoing and dir~="in" or not desync.outgoing and dir~="out"
|
||||
@@ -1314,7 +1314,7 @@ function payload_match_filter(l7payload, l7payload_filter, def)
|
||||
local pl = neg and string.sub(argpl,2) or argpl
|
||||
return neg ~= (in_list(pl, "all") or in_list(pl, l7payload) or in_list(pl, "known") and l7payload~="unknown" and l7payload~="empty")
|
||||
end
|
||||
-- check if desync payload type comply with payload type list in arg.payload
|
||||
-- check if desync payload type complies with payload type list in arg.payload
|
||||
-- if arg.payload is not present - check for known payload - not empty and not unknown (nfqws1 behavior without "--desync-any-protocol" option)
|
||||
-- if arg.payload is prefixed with '~' - it means negation
|
||||
function payload_check(desync, def)
|
||||
@@ -1476,7 +1476,7 @@ end
|
||||
-- option : ipfrag_pos_udp - udp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 8
|
||||
-- option : ipfrag_pos_tcp - tcp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32
|
||||
-- option : ipfrag_pos_icmp - icmp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 8
|
||||
-- option : ipfrag_pos - icmp frag position for other L4. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32
|
||||
-- option : ipfrag_pos - frag position for other L4. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32
|
||||
-- option : ipfrag_next - next protocol field in ipv6 fragment extenstion header of the second fragment. same as first by default.
|
||||
function ipfrag2(dis, ipfrag_options)
|
||||
local function frag_idx(exthdr)
|
||||
@@ -1602,7 +1602,7 @@ function tls_client_hello_mod(tls, options)
|
||||
DLOG("tls_client_hello_mod: could not dissect tls")
|
||||
return
|
||||
end
|
||||
if not tdis.handshake or not tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT] then
|
||||
if not tdis.handshake or not tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT] or not tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis then
|
||||
DLOG("tls_client_hello_mod: handshake not dissected")
|
||||
return
|
||||
end
|
||||
@@ -1863,7 +1863,7 @@ function dissect_url(url)
|
||||
creds = string.sub(url,p1,pend-1)
|
||||
p1 = pend+1
|
||||
end
|
||||
pstart,pend = string.find(url,"/",p1,true)
|
||||
pstart,pend = string.find(url,"[/?#]",p1)
|
||||
if pend then
|
||||
if pend==pb then
|
||||
uri = string.sub(url,pb)
|
||||
@@ -2281,21 +2281,32 @@ function quic_tvb(data, offset)
|
||||
return bitand(u32(data,offset),0x3FFFFFFF), 4
|
||||
elseif size==3 then
|
||||
if (offset+7)>#data then return end
|
||||
-- only lua 5.3+ can handle this. others can't store 64-bit integers
|
||||
return bitand(u32(data,offset),0x3FFFFFFF) * 0x100000000 + u32(data,offset+4), 8
|
||||
-- only lua 5.3+ has 64-bit integer type. others can't store 64-bit integers. return raw string if the value cannot fit.
|
||||
local msb = bitand(u32(data,offset),0x3FFFFFFF)
|
||||
-- lua 5.3+ has math.type function, older lua and luajit - don't
|
||||
if math.type==nil and msb>0x1FFFFF then
|
||||
return string.sub(data,offset,offset+7), 8
|
||||
else
|
||||
return msb * 0x100000000 + u32(data,offset+4), 8
|
||||
end
|
||||
end
|
||||
end
|
||||
-- quic-style tvb reconstruct
|
||||
function bquic_tvb(v)
|
||||
if v<0x40 then
|
||||
return bu8(v)
|
||||
elseif v<0x4000 then
|
||||
return bu16(v + 0x4000)
|
||||
elseif v<0x40000000 then
|
||||
return bu32(v + 0x80000000)
|
||||
elseif v<0x4000000000000000 then
|
||||
-- only lua 5.3+ can handle 64-bit int !
|
||||
return bu32(divint(v, 0x100000000) + 0xC0000000) .. bu32(v % 0x100000000)
|
||||
if type(v)=="string" then
|
||||
-- raw string. do not do anything, just return it
|
||||
return v
|
||||
else
|
||||
if v<0x40 then
|
||||
return bu8(v)
|
||||
elseif v<0x4000 then
|
||||
return bu16(v + 0x4000)
|
||||
elseif v<0x40000000 then
|
||||
return bu32(v + 0x80000000)
|
||||
elseif v<0x4000000000000000 then
|
||||
-- only lua 5.3+ can handle 64-bit int !
|
||||
return bu32(divint(v, 0x100000000) + 0xC0000000) .. bu32(v % 0x100000000)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2419,7 +2430,7 @@ function tls_dissect_ext(ext)
|
||||
off = off + size
|
||||
left = left - size
|
||||
len, size = quic_tvb(ext.data, off)
|
||||
if not len then return end
|
||||
if type(len)~="number" then return end
|
||||
off = off + size
|
||||
left = left - size
|
||||
if len > left then return end
|
||||
@@ -2436,93 +2447,102 @@ end
|
||||
|
||||
-- dissect client/server hello. leave 'data' as is for others
|
||||
function tls_dissect_handshake(handshake, partialOK)
|
||||
if is_tls_hello(handshake.data, 1, partialOK) then
|
||||
local hlen = tls_handshake_len(handshake.data, 1)
|
||||
if hlen > #handshake.data then
|
||||
if not partialOK then return false end
|
||||
hlen = #handshake.data
|
||||
end
|
||||
local typ = tls_handshake_type(handshake.data, 1)
|
||||
handshake.dis = { type = typ , ver = u16(handshake.data, 5), name = tostring(TLS_HANDSHAKE_TYPE_NAMES[typ]) }
|
||||
|
||||
-- random
|
||||
if hlen<38 then return partialOK end
|
||||
handshake.dis.random = string.sub(handshake.data, 7, 38)
|
||||
|
||||
-- session_id
|
||||
if hlen<39 then return partialOK end
|
||||
local len = u8(handshake.data, 39)
|
||||
local left = hlen-39-len
|
||||
if left<0 then return partialOK end
|
||||
handshake.dis.session_id = string.sub(handshake.data, 40, 40+len-1)
|
||||
local off = 40+len
|
||||
|
||||
-- cipher suite(s)
|
||||
if left<2 then return partialOK end
|
||||
if handshake.dis.type==TLS_HANDSHAKE_TYPE_CLIENT then
|
||||
-- client hello - array
|
||||
len = u16(handshake.data, off)
|
||||
if left<(2+len) then return partialOK end
|
||||
handshake.dis.cipher_suites={}
|
||||
for i=1,(len/2) do
|
||||
handshake.dis.cipher_suites[i] = u16(handshake.data, off + i*2)
|
||||
local function tls_dissect_handshake_(handshake, partialOK)
|
||||
handshake.dis = nil
|
||||
if is_tls_hello(handshake.data, 1, partialOK) then
|
||||
local hlen = tls_handshake_len(handshake.data, 1)
|
||||
if hlen > #handshake.data then
|
||||
if not partialOK then return false end
|
||||
hlen = #handshake.data
|
||||
end
|
||||
off = off + 2 + len
|
||||
left = left - 2 - len
|
||||
else
|
||||
-- server hello - single
|
||||
handshake.dis.cipher_suite = u16(handshake.data, off)
|
||||
local typ = tls_handshake_type(handshake.data, 1)
|
||||
handshake.dis = { type = typ , ver = u16(handshake.data, 5), name = tostring(TLS_HANDSHAKE_TYPE_NAMES[typ]) }
|
||||
|
||||
-- random
|
||||
if hlen<38 then return partialOK end
|
||||
handshake.dis.random = string.sub(handshake.data, 7, 38)
|
||||
|
||||
-- session_id
|
||||
if hlen<39 then return partialOK end
|
||||
local len = u8(handshake.data, 39)
|
||||
local left = hlen-39-len
|
||||
if left<0 then return partialOK end
|
||||
handshake.dis.session_id = string.sub(handshake.data, 40, 40+len-1)
|
||||
local off = 40+len
|
||||
|
||||
-- cipher suite(s)
|
||||
if left<2 then return partialOK end
|
||||
if handshake.dis.type==TLS_HANDSHAKE_TYPE_CLIENT then
|
||||
-- client hello - array
|
||||
len = u16(handshake.data, off)
|
||||
if left<(2+len) then return partialOK end
|
||||
handshake.dis.cipher_suites={}
|
||||
for i=1,(len/2) do
|
||||
handshake.dis.cipher_suites[i] = u16(handshake.data, off + i*2)
|
||||
end
|
||||
off = off + 2 + len
|
||||
left = left - 2 - len
|
||||
else
|
||||
-- server hello - single
|
||||
handshake.dis.cipher_suite = u16(handshake.data, off)
|
||||
off = off + 2
|
||||
left = left - 2
|
||||
end
|
||||
|
||||
-- compression method(s)
|
||||
if left<1 then return partialOK end
|
||||
if handshake.dis.type==1 then
|
||||
-- client hello - array
|
||||
len = u8(handshake.data, off)
|
||||
if left<(1+len) then return partialOK end
|
||||
handshake.dis.compression_methods={}
|
||||
for i=1,len do
|
||||
handshake.dis.compression_methods[i] = u8(handshake.data, off + i)
|
||||
end
|
||||
off = off + 1 + len
|
||||
left = left - 1 - len
|
||||
else
|
||||
-- server hello - single
|
||||
handshake.dis.compression_method = u8(handshake.data, off)
|
||||
off = off + 1
|
||||
left = left - 1
|
||||
end
|
||||
|
||||
-- tls extensions
|
||||
if left<2 then return partialOK end
|
||||
local extlen = u16(handshake.data, off)
|
||||
if left<(2+extlen) and not partialOK then return false end
|
||||
off = off + 2
|
||||
left = left - 2
|
||||
end
|
||||
if left>extlen then left=extlen end
|
||||
|
||||
-- compression method(s)
|
||||
if left<1 then return partialOK end
|
||||
if handshake.dis.type==1 then
|
||||
-- client hello - array
|
||||
len = u8(handshake.data, off)
|
||||
if left<(1+len) then return partialOK end
|
||||
handshake.dis.compression_methods={}
|
||||
for i=1,len do
|
||||
handshake.dis.compression_methods[i] = u8(handshake.data, off + i)
|
||||
end
|
||||
off = off + 1 + len
|
||||
left = left - 1 - len
|
||||
else
|
||||
-- server hello - single
|
||||
handshake.dis.compression_method = u8(handshake.data, off)
|
||||
off = off + 1
|
||||
left = left - 1
|
||||
end
|
||||
|
||||
-- tls extensions
|
||||
if left<2 then return partialOK end
|
||||
local extlen = u16(handshake.data, off)
|
||||
if left<(2+extlen) and not partialOK then return end
|
||||
off = off + 2
|
||||
left = left - 2
|
||||
if left>extlen then left=extlen end
|
||||
|
||||
handshake.dis.ext = {}
|
||||
while left>=4 do
|
||||
len = u16(handshake.data, off + 2)
|
||||
if len>(left-4) then
|
||||
if partialOK then
|
||||
break
|
||||
else
|
||||
return
|
||||
handshake.dis.ext = {}
|
||||
while left>=4 do
|
||||
len = u16(handshake.data, off + 2)
|
||||
if len>(left-4) then
|
||||
if partialOK then
|
||||
break
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
local typ = u16(handshake.data, off)
|
||||
handshake.dis.ext[#handshake.dis.ext+1] = { type = typ, name = tostring(TLS_HELLO_EXT_NAMES[typ]), data = string.sub(handshake.data, off+4, off+4+len-1) }
|
||||
tls_dissect_ext(handshake.dis.ext[#handshake.dis.ext])
|
||||
left = left - 4 - len
|
||||
off = off + 4 + len
|
||||
end
|
||||
local typ = u16(handshake.data, off)
|
||||
handshake.dis.ext[#handshake.dis.ext+1] = { type = typ, name = tostring(TLS_HELLO_EXT_NAMES[typ]), data = string.sub(handshake.data, off+4, off+4+len-1) }
|
||||
tls_dissect_ext(handshake.dis.ext[#handshake.dis.ext])
|
||||
left = left - 4 - len
|
||||
off = off + 4 + len
|
||||
end
|
||||
|
||||
return true
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
return false
|
||||
local b = tls_dissect_handshake_(handshake,partialOK)
|
||||
if not b then
|
||||
-- clear partially filled dissect if failed
|
||||
handshake.dis = nil
|
||||
end
|
||||
return b
|
||||
end
|
||||
|
||||
-- convert tls blob tls dissect
|
||||
|
||||
+70
-5
@@ -173,6 +173,8 @@ end
|
||||
-- arg : scode - server icmp code
|
||||
-- arg : dataxor - blob to xor udp payload
|
||||
-- arg : server=[0|1] - override server mode. by default use "--server" nfqws2 parameter
|
||||
-- arg : cgnat - do not rely on identifier - cgnat in most cases changes it. expand udp packet size by 2 (may exceed MTU !)
|
||||
-- arg : id_lifetime - mapped identifiers lifetime in seconds
|
||||
function udp2icmp(ctx, desync)
|
||||
local dataxor
|
||||
local bserver
|
||||
@@ -221,6 +223,25 @@ function udp2icmp(ctx, desync)
|
||||
desync.dis.payload = bxor(desync.dis.payload, pattern(dataxor,1,#desync.dis.payload))
|
||||
end
|
||||
end
|
||||
local function map_purge()
|
||||
if udp2icmp_map then
|
||||
local last = udp2icmp_map.purge or 0
|
||||
local now = os.time()
|
||||
local timeout = desync.arg.id_lifetime and tonumber(desync.arg.id_lifetime) or 60
|
||||
if last~=now then
|
||||
for k,v in pairs(udp2icmp_map) do
|
||||
if type(v)=='table' and v.t then
|
||||
if now>=(v.t + timeout) then
|
||||
udp2icmp_map[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
udp2icmp_map.purge=now
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
map_purge()
|
||||
|
||||
if desync.arg.dataxor then
|
||||
dataxor = blob(desync,desync.arg.dataxor)
|
||||
@@ -234,19 +255,63 @@ function udp2icmp(ctx, desync)
|
||||
if b_debug then -- save some cpu
|
||||
DLOG("udp2icmp: udp => icmp sport="..desync.dis.udp.uh_sport.." dport="..desync.dis.udp.uh_dport.." size="..#desync.dis.payload)
|
||||
end
|
||||
local id = bitxor(desync.dis.udp.uh_sport,desync.dis.udp.uh_dport)
|
||||
if desync.arg.cgnat then
|
||||
if bserver then
|
||||
-- extract original icmp identifier from the map. it must match original or NAT will not deliver
|
||||
local map_id = (desync.dis.ip6 and desync.dis.ip6.ip6_dst or desync.dis.ip.ip_dst)..
|
||||
(desync.dis.ip6 and desync.dis.ip6.ip6_src or desync.dis.ip.ip_src)..
|
||||
bu16(desync.dis.udp.uh_dport)..bu16(desync.dis.udp.uh_sport)
|
||||
if udp2icmp_map then
|
||||
local id_ = udp2icmp_map[map_id]
|
||||
if id_ then
|
||||
id=id_.id
|
||||
if b_debug then DLOG(string.format("udp2icmp: found mapped icmp identifier %04X",id)) end
|
||||
id_.t=os.time() -- update time
|
||||
else
|
||||
DLOG("udp2icmp: mapped icmp identifier NOT found !")
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
-- cgnat changes identifier. save it in the end of the packet, expand packet size by 2
|
||||
desync.dis.payload = desync.dis.payload .. bu16(id)
|
||||
DLOG("udp2icmp: expanding udp size to "..#desync.dis.payload)
|
||||
end
|
||||
end
|
||||
desync.dis.icmp = {
|
||||
icmp_type = ictype(true),
|
||||
icmp_code = iccode(true),
|
||||
icmp_data = u32(
|
||||
bu16(bitxor(desync.dis.udp.uh_sport,desync.dis.udp.uh_dport))..
|
||||
(bserver and bu16(desync.dis.udp.uh_sport) or bu16(desync.dis.udp.uh_dport)))
|
||||
icmp_data = u32(bu16(id)..(bserver and bu16(desync.dis.udp.uh_sport) or bu16(desync.dis.udp.uh_dport)))
|
||||
}
|
||||
desync.dis.udp = nil
|
||||
fix_ip_proto(desync.dis)
|
||||
return VERDICT_MODIFY
|
||||
elseif desync.dis.icmp and desync.dis.icmp.icmp_type==ictype(false) and desync.dis.icmp.icmp_code==iccode(false) then
|
||||
local pl = bitand(desync.dis.icmp.icmp_data,0xFFFF)
|
||||
local pm = bitxor(bitrshift(desync.dis.icmp.icmp_data,16),pl)
|
||||
local pm
|
||||
local id = bitrshift(desync.dis.icmp.icmp_data,16)
|
||||
if bserver and desync.arg.cgnat then
|
||||
if #desync.dis.payload<2 then
|
||||
DLOG("udp2icmp: udp is less than 2 bytes and cgnat is on ! doing nothing")
|
||||
return VERDICT_PASS
|
||||
end
|
||||
if not udp2icmp_map then udp2icmp_map={} end
|
||||
|
||||
pm = bitxor(u16(desync.dis.payload,#desync.dis.payload-1),pl) -- use right 2 bytes
|
||||
desync.dis.payload = string.sub(desync.dis.payload,1,-3) -- shrink right 2 bytes
|
||||
DLOG("udp2icmp: shrinking udp size to "..#desync.dis.payload)
|
||||
|
||||
-- keep original icmp identifier indexed by ip/port tuple
|
||||
local map_id = (desync.dis.ip6 and desync.dis.ip6.ip6_src or desync.dis.ip.ip_src)..
|
||||
(desync.dis.ip6 and desync.dis.ip6.ip6_dst or desync.dis.ip.ip_dst)..
|
||||
bu16(pm)..bu16(pl)
|
||||
udp2icmp_map[map_id] = { id=id, t=os.time() }
|
||||
if b_debug then DLOG(string.format("udp2icmp: stored mapped icmp identifier %04X",id)) end
|
||||
else
|
||||
pm = bitxor(id,pl)
|
||||
end
|
||||
|
||||
desync.dis.udp = {
|
||||
uh_sport = bserver and pm or pl,
|
||||
uh_dport = bserver and pl or pm,
|
||||
@@ -429,7 +494,7 @@ function synhide(ctx, desync)
|
||||
|
||||
if fl==TH_SYN then
|
||||
-- client sent
|
||||
local ttl = tonumber(desync.dis.ip and desync.arg.ghost or desync.arg.ghost6)
|
||||
local ttl = tonumber(desync.dis.ip and desync.arg.ghost or (desync.dis.ip6 and desync.arg.ghost6))
|
||||
if ttl then
|
||||
DLOG("synhide: punch NAT hole with ttl="..ttl)
|
||||
local dis = deepcopy(desync.dis)
|
||||
|
||||
+4
-4
@@ -72,13 +72,13 @@ static uint16_t do_csum(const uint8_t *buff, size_t len)
|
||||
}
|
||||
if (len & 4)
|
||||
{
|
||||
result += *(uint32_t *)buff;
|
||||
result += *(const uint32_t *)buff;
|
||||
buff += 4;
|
||||
}
|
||||
}
|
||||
if (len & 2)
|
||||
{
|
||||
result += *(uint16_t *)buff;
|
||||
result += *(const uint16_t *)buff;
|
||||
buff += 2;
|
||||
}
|
||||
}
|
||||
@@ -115,8 +115,8 @@ void ip4_fix_checksum(struct ip *ip)
|
||||
uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8_t proto, uint16_t sum)
|
||||
{
|
||||
uint64_t a = (uint64_t)sum + htonl(len + proto) +
|
||||
*(uint32_t *)saddr + *((uint32_t *)saddr + 1) + *((uint32_t *)saddr + 2) + *((uint32_t *)saddr + 3) +
|
||||
*(uint32_t *)daddr + *((uint32_t *)daddr + 1) + *((uint32_t *)daddr + 2) + *((uint32_t *)daddr + 3);
|
||||
*(const uint32_t *)saddr + *((const uint32_t *)saddr + 1) + *((const uint32_t *)saddr + 2) + *((const uint32_t *)saddr + 3) +
|
||||
*(const uint32_t *)daddr + *((const uint32_t *)daddr + 1) + *((const uint32_t *)daddr + 2) + *((const uint32_t *)daddr + 3);
|
||||
return ~from64to16(a);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -146,7 +146,7 @@ static void ConntrackApplyPos(t_ctrack *t, bool bReverse, const struct dissect *
|
||||
{
|
||||
// scale and mss only valid in syn packets
|
||||
scale = tcp_find_scale_factor(dis->tcp);
|
||||
if (scale != SCALE_NONE) direct->scale = scale;
|
||||
if (scale != SCALE_NONE) direct->scale = scale<14 ? scale : 14; // RFC7323 hard limit
|
||||
direct->mss = tcp_find_mss(dis->tcp);
|
||||
}
|
||||
else
|
||||
|
||||
+55
-31
@@ -201,69 +201,80 @@ static void packet_debug(bool replay, const struct dissect *dis)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ipr,ipr6 - reverse ip - ip of the other side of communication
|
||||
struct dp_match_data
|
||||
{
|
||||
const struct in_addr *ip;
|
||||
const struct in6_addr *ip6;
|
||||
const struct in_addr *ipr;
|
||||
const struct in6_addr *ipr6;
|
||||
const char *hostname;
|
||||
const char *ssid;
|
||||
bool *bCheckDone, *bCheckResult, *bExcluded;
|
||||
t_l7proto l7proto;
|
||||
uint32_t fwmark;
|
||||
uint16_t port;
|
||||
uint8_t icmp_type, icmp_code;
|
||||
bool bNoSubdom;
|
||||
uint8_t l3proto;
|
||||
};
|
||||
static bool dp_match(
|
||||
struct desync_profile *dp,
|
||||
uint8_t l3proto,
|
||||
const struct in_addr *ip, const struct in6_addr *ip6,
|
||||
const struct in_addr *ipr, const struct in6_addr *ipr6,
|
||||
uint16_t port, uint8_t icmp_type, uint8_t icmp_code,
|
||||
const char *hostname, bool bNoSubdom, t_l7proto l7proto,
|
||||
const char *ssid, uint32_t fwmark,
|
||||
bool *bCheckDone, bool *bCheckResult, bool *bExcluded)
|
||||
const struct dp_match_data *match)
|
||||
{
|
||||
bool bHostlistsEmpty;
|
||||
|
||||
if (bCheckDone) *bCheckDone = false;
|
||||
if (match->bCheckDone) *match->bCheckDone = false;
|
||||
|
||||
// fast checks first
|
||||
|
||||
#ifdef __linux__
|
||||
if ((fwmark & dp->filter_mark_mask)!=dp->filter_mark)
|
||||
if ((match->fwmark & dp->filter_mark_mask)!=dp->filter_mark)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if ((ip && !dp->filter_ipv4) || (ip6 && !dp->filter_ipv6))
|
||||
if ((match->ip && !dp->filter_ipv4) || (match->ip6 && !dp->filter_ipv6))
|
||||
// L3 filter does not match
|
||||
return false;
|
||||
|
||||
if (!l7_proto_match(l7proto, dp->filter_l7))
|
||||
if (!l7_proto_match(match->l7proto, dp->filter_l7))
|
||||
// L7 filter does not match
|
||||
return false;
|
||||
|
||||
switch(l3proto)
|
||||
switch(match->l3proto)
|
||||
{
|
||||
case IPPROTO_TCP:
|
||||
if (!port_filters_match(&dp->pf_tcp, port)) return false;
|
||||
if (!port_filters_match(&dp->pf_tcp, match->port)) return false;
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
if (!port_filters_match(&dp->pf_udp, port)) return false;
|
||||
if (!port_filters_match(&dp->pf_udp, match->port)) return false;
|
||||
break;
|
||||
case IPPROTO_ICMP:
|
||||
case IPPROTO_ICMPV6:
|
||||
if (!icmp_filters_match(&dp->icf, icmp_type, icmp_code)) return false;
|
||||
if (!icmp_filters_match(&dp->icf, match->icmp_type, match->icmp_code)) return false;
|
||||
break;
|
||||
default:
|
||||
if (!ipp_filters_match(&dp->ipf, l3proto)) return false;
|
||||
if (!ipp_filters_match(&dp->ipf, match->l3proto)) return false;
|
||||
}
|
||||
|
||||
#ifdef HAS_FILTER_SSID
|
||||
if (!LIST_EMPTY(&dp->filter_ssid) && (!strlist_search(&dp->filter_ssid, ssid) ^ dp->filter_ssid_neg))
|
||||
if (!LIST_EMPTY(&dp->filter_ssid) && (!strlist_search(&dp->filter_ssid, match->ssid) ^ dp->filter_ssid_neg))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (!HostlistsReloadCheckForProfile(dp)) return false;
|
||||
|
||||
bHostlistsEmpty = PROFILE_HOSTLISTS_EMPTY(dp);
|
||||
if (!dp->hostlist_auto && !hostname && !bHostlistsEmpty)
|
||||
if (!dp->hostlist_auto && !match->hostname && !bHostlistsEmpty)
|
||||
// avoid cpu consuming ipset check. profile cannot win if regular hostlists are present without auto hostlist and hostname is unknown.
|
||||
return false;
|
||||
if (!IpsetCheck(dp, ip, ip6, ipr, ipr6))
|
||||
if (!IpsetCheck(dp, match->ip, match->ip6, match->ipr, match->ipr6))
|
||||
// target ip does not match
|
||||
return false;
|
||||
|
||||
// autohostlist profile matching l3/l4/l7 filter always win if we have a hostname. no matter it matches or not.
|
||||
if (dp->hostlist_auto && hostname)
|
||||
if (dp->hostlist_auto && match->hostname)
|
||||
{
|
||||
DLOG("autohostlist profile %u (%s) wins because hostname is known\n",dp->n,dp->name);
|
||||
return true;
|
||||
@@ -275,12 +286,12 @@ static bool dp_match(
|
||||
else
|
||||
{
|
||||
// if hostlists are present profile matches only if hostname is known and satisfy profile hostlists
|
||||
if (hostname)
|
||||
if (match->hostname)
|
||||
{
|
||||
if (bCheckDone) *bCheckDone = true;
|
||||
if (match->bCheckDone) *match->bCheckDone = true;
|
||||
bool b;
|
||||
b = HostlistCheck(dp, hostname, bNoSubdom, bExcluded, true);
|
||||
if (bCheckResult) *bCheckResult = b;
|
||||
b = HostlistCheck(dp, match->hostname, match->bNoSubdom, match->bExcluded, true);
|
||||
if (match->bCheckResult) *match->bCheckResult = b;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
@@ -297,6 +308,14 @@ static struct desync_profile *dp_find(
|
||||
bool *bCheckDone, bool *bCheckResult, bool *bExcluded)
|
||||
{
|
||||
struct desync_profile_list *dpl;
|
||||
struct dp_match_data match = {
|
||||
.l3proto=l3proto,
|
||||
.ip=ip, .ip6=ip6, .ipr=ipr, .ipr6=ipr6,
|
||||
.port=port, .icmp_type=icmp_type, .icmp_code=icmp_code,
|
||||
.hostname=hostname, .bNoSubdom=bNoSubdom, .l7proto=l7proto,
|
||||
.ssid=ssid, .fwmark=fwmark,
|
||||
.bCheckDone=bCheckDone, .bCheckResult=bCheckResult, .bExcluded=bExcluded
|
||||
};
|
||||
if (params.debug)
|
||||
{
|
||||
char s[INET6_ADDRSTRLEN];
|
||||
@@ -315,7 +334,7 @@ static struct desync_profile *dp_find(
|
||||
if (bCheckDone) *bCheckDone = false;
|
||||
LIST_FOREACH(dpl, head, next)
|
||||
{
|
||||
if (dp_match(&dpl->dp, l3proto, ip, ip6, ipr, ipr6, port, icmp_type, icmp_code, hostname, bNoSubdom, l7proto, ssid, fwmark, bCheckDone, bCheckResult, bExcluded))
|
||||
if (dp_match(&dpl->dp, &match))
|
||||
{
|
||||
DLOG("desync profile %u (%s) matches\n", dpl->dp.n, PROFILE_NAME(&dpl->dp));
|
||||
return &dpl->dp;
|
||||
@@ -624,8 +643,8 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, const struct dissect *
|
||||
// if used in postnat chain, dropping initial packet will cause conntrack connection teardown
|
||||
// so we need to workaround this.
|
||||
// SYN and SYN,ACK checks are for conntrack-less mode
|
||||
if (ctrack && (params.server ? ctrack->pos.server.pcounter : ctrack->pos.client.pcounter) == 1 ||
|
||||
!ctrack && dis->tcp && (tcp_syn_segment(dis->tcp) || tcp_synack_segment(dis->tcp)))
|
||||
if ((ctrack && (params.server ? ctrack->pos.server.pcounter : ctrack->pos.client.pcounter) == 1) ||
|
||||
(!ctrack && dis->tcp && (tcp_syn_segment(dis->tcp) || tcp_synack_segment(dis->tcp))))
|
||||
{
|
||||
if (dis->len_pkt > *len_mod_pkt)
|
||||
DLOG_ERR("linux postnat conntrack workaround cannot be applied\n");
|
||||
@@ -697,7 +716,7 @@ static bool check_pos_to(const t_ctrack_position *pos, const struct packet_range
|
||||
if (pos)
|
||||
{
|
||||
ps = pos_get(pos, range->to.mode);
|
||||
return (ps < range->to.pos) || !range->upper_cutoff && (ps == range->to.pos);
|
||||
return (ps < range->to.pos) || (!range->upper_cutoff && (ps == range->to.pos));
|
||||
}
|
||||
else
|
||||
return false;
|
||||
@@ -1608,9 +1627,7 @@ static uint8_t dpi_desync_tcp_packet_play(
|
||||
{
|
||||
// likely exceeded packet limit or unlikely out of memory
|
||||
DLOG_ERR("rawpacket_queue failed !\n");
|
||||
reasm_client_cancel(ps.ctrack);
|
||||
ps.l7payload = L7P_UNKNOWN; // middle packet may be not L7P_TLS_CLIENT_HELLO
|
||||
goto rediscover;
|
||||
goto reasm_cancel_rediscover;
|
||||
}
|
||||
if (ReasmIsFull(&ps.ctrack->reasm_client))
|
||||
{
|
||||
@@ -1642,6 +1659,13 @@ pass:
|
||||
pass_reasm_cancel:
|
||||
reasm_client_cancel(ps.ctrack);
|
||||
goto pass;
|
||||
|
||||
reasm_cancel_rediscover:
|
||||
reasm_client_cancel(ps.ctrack);
|
||||
rdata_payload = dis->data_payload;
|
||||
rlen_payload = dis->len_payload;
|
||||
ps.l7payload = L7P_UNKNOWN; // could be middle packet
|
||||
goto rediscover;
|
||||
}
|
||||
|
||||
// return : true - should continue, false - should stop with verdict
|
||||
|
||||
+3
-3
@@ -35,7 +35,7 @@ int unique_ssize_t(ssize_t *pu, int ct) UNIQ_SORT
|
||||
|
||||
static int cmp_size_t(const void * a, const void * b)
|
||||
{
|
||||
return *(size_t*)a < *(size_t*)b ? -1 : *(size_t*)a > *(size_t*)b;
|
||||
return *(const size_t*)a < *(const size_t*)b ? -1 : *(const size_t*)a > *(const size_t*)b;
|
||||
}
|
||||
void qsort_size_t(size_t *array, int ct)
|
||||
{
|
||||
@@ -43,7 +43,7 @@ void qsort_size_t(size_t *array, int ct)
|
||||
}
|
||||
static int cmp_ssize_t(const void * a, const void * b)
|
||||
{
|
||||
return *(ssize_t*)a < *(ssize_t*)b ? -1 : *(ssize_t*)a > *(ssize_t*)b;
|
||||
return *(const ssize_t*)a < *(const ssize_t*)b ? -1 : *(const ssize_t*)a > *(const ssize_t*)b;
|
||||
}
|
||||
void qsort_ssize_t(ssize_t *array, int ct)
|
||||
{
|
||||
@@ -435,7 +435,7 @@ bool file_mod_signature(const char *filename, file_mod_sig *ms)
|
||||
FILE_MOD_RESET(ms);
|
||||
return false;
|
||||
}
|
||||
ms->mod_time = st.st_mtime;
|
||||
ms->mod_time = st.st_mtim;
|
||||
ms->size = st.st_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
+2
-2
@@ -82,10 +82,10 @@ int fprint_localtime(FILE *F);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
time_t mod_time;
|
||||
struct timespec mod_time;
|
||||
off_t size;
|
||||
} file_mod_sig;
|
||||
#define FILE_MOD_COMPARE(ms1,ms2) (((ms1)->mod_time==(ms2)->mod_time) && ((ms1)->size==(ms2)->size))
|
||||
#define FILE_MOD_COMPARE(ms1,ms2) (((ms1)->mod_time.tv_sec==(ms2)->mod_time.tv_sec) && ((ms1)->mod_time.tv_nsec==(ms2)->mod_time.tv_nsec) && ((ms1)->size==(ms2)->size))
|
||||
#define FILE_MOD_RESET(ms) memset(ms,0,sizeof(file_mod_sig))
|
||||
bool file_mod_signature(const char *filename, file_mod_sig *ms);
|
||||
bool file_size(const char *filename, off_t *size);
|
||||
|
||||
+13
-7
@@ -115,7 +115,8 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadHostList(struct hostlist_file *hfile)
|
||||
// bChanged is set to true if the list was changed and not set otherwise
|
||||
static bool LoadHostList(struct hostlist_file *hfile, bool *bChanged)
|
||||
{
|
||||
if (hfile->filename)
|
||||
{
|
||||
@@ -133,6 +134,7 @@ static bool LoadHostList(struct hostlist_file *hfile)
|
||||
DLOG_PERROR("file_open_test");
|
||||
goto unchanged;
|
||||
}
|
||||
if (bChanged) *bChanged=true;
|
||||
// don't want to keep backup copy in memory - it will require *2 RAM. Problem on low-ram devices. It's better to fail hostlist read than have OOM.
|
||||
// if a file can be opened there're few chances it can't be read. fs corruption, disk error, deleted or made inaccessible between 2 syscals ?
|
||||
// it's all hypotetically possible but very unlikely. but OOM is much more real problem on an embedded device if list is large enough
|
||||
@@ -149,14 +151,14 @@ unchanged:
|
||||
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
|
||||
return true;
|
||||
}
|
||||
static bool LoadHostLists(struct hostlist_files_head *list)
|
||||
static bool LoadHostLists(struct hostlist_files_head *list, bool *bChanged)
|
||||
{
|
||||
bool bres=true;
|
||||
struct hostlist_file *hfile;
|
||||
|
||||
LIST_FOREACH(hfile, list, next)
|
||||
{
|
||||
if (!LoadHostList(hfile))
|
||||
if (!LoadHostList(hfile, bChanged))
|
||||
// at least one failed
|
||||
bres=false;
|
||||
}
|
||||
@@ -181,9 +183,10 @@ static void MakeAutolistsNonEmpty()
|
||||
|
||||
bool LoadAllHostLists()
|
||||
{
|
||||
if (!LoadHostLists(¶ms.hostlists))
|
||||
bool bChanged=false;
|
||||
if (!LoadHostLists(¶ms.hostlists, &bChanged))
|
||||
return false;
|
||||
MakeAutolistsNonEmpty();
|
||||
if (bChanged) MakeAutolistsNonEmpty();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -227,12 +230,15 @@ static bool SearchHostList(hostlist_pool *hostlist, const char *host, bool no_ma
|
||||
static bool HostlistsReloadCheck(const struct hostlist_collection_head *hostlists)
|
||||
{
|
||||
struct hostlist_item *item;
|
||||
bool bChanged=false;
|
||||
|
||||
LIST_FOREACH(item, hostlists, next)
|
||||
{
|
||||
if (!LoadHostList(item->hfile))
|
||||
if (!LoadHostList(item->hfile, &bChanged))
|
||||
return false;
|
||||
}
|
||||
MakeAutolistsNonEmpty();
|
||||
// this is relatively heavy function. walks through all the profiles. do not walk if no hostlists were releaded
|
||||
if (bChanged) MakeAutolistsNonEmpty();
|
||||
return true;
|
||||
}
|
||||
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp)
|
||||
|
||||
+2
-2
@@ -1914,8 +1914,8 @@ static void exithelp(void)
|
||||
" --hostlist-auto-debug=<logfile>\t\t\t; debug auto hostlist positives (global parameter)\n"
|
||||
"\nLUA PACKET PASS MODE:\n"
|
||||
" --payload=type[,type]\t\t\t\t\t; set payload types following LUA functions should process : %s\n"
|
||||
" --out-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>]\t; set outgoing packet range for following LUA functions. '-' - include end pos, '<' - not include. prefix meaning : n - packet number, d - data packet number, s - relative sequence, p - data position relative sequence, b - byte count, x - never, a - always\n"
|
||||
" --in-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>]\t; set incoming packet range for following LUA functions. '-' - include end pos, '<' - not include. prefix meaning : n - packet number, d - data packet number, s - relative sequence, p - data position relative sequence, b - byte count, x - never, a - always\n"
|
||||
" --out-range=<mode>[<int>][(-|<)<mode>[<int>]]\t\t; set outgoing packet range for following LUA functions. '-' - include end pos, '<' - not include. mode meaning : n - packet number, d - data packet number, s - relative sequence, p - data position relative sequence, b - byte count, x - never, a - always\n"
|
||||
" --in-range=<mode>[<int>][(-|<)<mode>[<int>]]\t\t; set incoming packet range for following LUA functions. '-' - include end pos, '<' - not include. mode meaning : n - packet number, d - data packet number, s - relative sequence, p - data position relative sequence, b - byte count, x - never, a - always\n"
|
||||
"\nLUA DESYNC ACTION:\n"
|
||||
" --lua-desync=<functon>[:param1=val1[:param2=val2]]\t; call LUA function when packet received\n",
|
||||
#if defined(__linux__) || defined(SO_USER_COOKIE)
|
||||
|
||||
+3
-3
@@ -47,7 +47,7 @@ t_l7proto l7proto_from_name(const char *name)
|
||||
}
|
||||
bool l7_proto_match(t_l7proto l7proto, uint64_t filter_l7)
|
||||
{
|
||||
return filter_l7==L7_ALL || (filter_l7 & (1ULL<<l7proto)) || (filter_l7 & (1ULL<<L7_KNOWN)) && l7proto>L7_KNOWN && l7proto<L7_LAST;
|
||||
return (filter_l7==L7_ALL) || (filter_l7 & (1ULL<<l7proto)) || (filter_l7 & (1ULL<<L7_KNOWN)) && (l7proto>L7_KNOWN) && (l7proto<L7_LAST);
|
||||
}
|
||||
|
||||
static const char *l7payload_name[] = {
|
||||
@@ -76,7 +76,7 @@ const char *l7payload_str(t_l7payload l7)
|
||||
}
|
||||
bool l7_payload_match(t_l7payload l7payload, uint64_t filter_l7p)
|
||||
{
|
||||
return filter_l7p==L7P_ALL || (filter_l7p & (1ULL<<l7payload)) || (filter_l7p & (1ULL<<L7P_KNOWN)) && l7payload>L7P_KNOWN && l7payload<L7P_LAST;
|
||||
return (filter_l7p==L7P_ALL) || (filter_l7p & (1ULL<<l7payload)) || (filter_l7p & (1ULL<<L7P_KNOWN)) && (l7payload>L7P_KNOWN) && (l7payload<L7P_LAST);
|
||||
}
|
||||
bool l7_payload_str_list(uint64_t l7p, char *buf, size_t size)
|
||||
{
|
||||
@@ -385,7 +385,7 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
|
||||
|
||||
// somethinkg like : censor.net/badpage.php?reason=denied&source=RKN
|
||||
|
||||
for(p=redirect_host; *p && *p!='/' ; p++);
|
||||
for(p=redirect_host; *p && *p!='/' && *p!='?' && *p!='#' ; p++);
|
||||
*p=0;
|
||||
if (!*redirect_host) return false;
|
||||
|
||||
|
||||
+10
-2
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/securebits.h>
|
||||
#include <linux/seccomp.h>
|
||||
#include <linux/filter.h>
|
||||
// __X32_SYSCALL_BIT defined in linux/unistd.h
|
||||
@@ -266,8 +267,15 @@ bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count)
|
||||
#ifdef __linux__
|
||||
if (prctl(PR_SET_KEEPCAPS, 1L))
|
||||
{
|
||||
DLOG_PERROR("prctl(PR_SET_KEEPCAPS)");
|
||||
return false;
|
||||
int e=errno;
|
||||
// if SECBIT_NO_SETUID_FIXUP is set PR_SET_KEEPCAPS is not necessary
|
||||
int bits = prctl(PR_GET_SECUREBITS);
|
||||
if (bits<0 || !(bits & SECBIT_NO_SETUID_FIXUP))
|
||||
{
|
||||
errno=e;
|
||||
DLOG_PERROR("prctl(PR_SET_KEEPCAPS)");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (user)
|
||||
|
||||
Reference in new issue
Block a user