Compare commits

...

79 Commits

Author SHA1 Message Date
bol-van 3c8e4ed15d update docs 2025-10-12 14:35:27 +03:00
bol-van 8c06a6335d update docs 2025-10-12 14:34:49 +03:00
bol-van f12cae3674 update docs 2025-10-12 14:34:21 +03:00
bol-van 170281bfa6 update docs 2025-10-12 14:33:16 +03:00
bol-van 5d4747458f update docs 2025-10-12 14:30:05 +03:00
bol-van 5774e883d6 update docs 2025-10-12 14:19:04 +03:00
bol-van 80b801c1ca nfqws: fix seqovl>=split_pos message 2025-10-10 17:53:14 +03:00
bol-van 9d8ee398c3 Revert "blockcheck: enable ECN in windows"
This reverts commit 4d35d8d1ec.
2025-10-08 16:32:56 +03:00
bol-van 4d35d8d1ec blockcheck: enable ECN in windows 2025-10-07 10:19:02 +03:00
bol-van 977d117417 nfqws: prevent memleak if multiple fakedsplit pattern options 2025-10-04 20:45:24 +03:00
bol-van cc8313db51 nfqws: optimize default fakedsplit pattern 2025-10-04 20:18:39 +03:00
bol-van 1e51f90130 nfqws: fix fakedsplit-pattern if not specified 2025-10-04 19:59:19 +03:00
bol-van da6b89e739 blockcheck: print some OPENWRT_xxx from /etc/os-release 2025-10-04 18:31:48 +03:00
bol-van 90470440a7 blockcheck: print PRETTY_NAME from /etc/os-release 2025-10-04 18:26:07 +03:00
bol-van a5c9d79417 update docs 2025-10-04 11:58:59 +03:00
bol-van c003ef2a7b update docs 2025-10-04 11:58:35 +03:00
bol-van 42541fcab8 update docs 2025-10-04 11:57:53 +03:00
bol-van 20b5952978 update docs 2025-10-04 11:56:07 +03:00
bol-van 4b6aa1b5f9 nfqws: help text for more altorders 2025-10-04 11:43:06 +03:00
bol-van 9e141dcefd update docs 2025-10-04 11:30:38 +03:00
bol-van b1b992eb3f update docs 2025-10-04 11:28:29 +03:00
bol-van 2d061c911a update docs 2025-10-04 11:27:31 +03:00
bol-van a213084188 update docs 2025-10-04 11:26:42 +03:00
bol-van 1c7ec32b96 update docs 2025-10-04 11:26:00 +03:00
bol-van dcd9cfbb2b nfqws: ip_id fixes, more altorder support 2025-10-04 11:02:23 +03:00
bol-van beb0692d28 quick_start: minor change 2025-10-03 10:48:23 +03:00
bol-van 140af2b741 quick_start: remove easy option 2025-10-03 10:47:40 +03:00
bol-van f8cc109f0b nfqws: remove "file containing" from help text 2025-09-24 16:32:48 +03:00
bol-van b4a2f44d56 remove -2b fakes 2025-09-24 16:26:39 +03:00
bol-van 14d05d8012 update docs 2025-09-24 16:25:08 +03:00
bol-van 71d5afeaf4 update docs 2025-09-24 16:24:36 +03:00
bol-van 45df8bfb09 update docs 2025-09-24 16:21:59 +03:00
bol-van 784058cf66 nfqws: support +offset@filename fake/pattern loading 2025-09-24 16:08:25 +03:00
bol-van ce367b1a91 nfqws: optimize ip_id behavior 2025-09-24 10:31:06 +03:00
bol-van a832c19974 blockcheck: test --dpi-desync-fakedsplit-mod=altorder=1 2025-09-23 14:20:23 +03:00
bol-van 2c14109163 update docs 2025-09-23 14:13:39 +03:00
bol-van c467e696e3 nfqws: --dpi-desync-fakedsplit-mod=altorder 2025-09-23 14:06:23 +03:00
bol-van 528c27a01a update docs 2025-09-23 13:16:18 +03:00
bol-van c2f1e708fc blockcheck: test split fake 2025-09-23 12:21:47 +03:00
bol-van 211a4f4673 update docs 2025-09-23 11:54:59 +03:00
bol-van fd81053d79 nfqws: --dpi-desync-fake-tls=!+offset 2025-09-23 11:52:46 +03:00
bol-van 1bb9f260dd -2b tls fakes 2025-09-23 10:52:38 +03:00
bol-van 26f3cbd06f update docs 2025-09-23 10:52:16 +03:00
bol-van e384f88931 nfqws: --dpi-desync-fake-tcp-mod=seq 2025-09-23 10:51:49 +03:00
bol-van 59bce0036b update docs 2025-09-22 17:39:00 +03:00
bol-van 0a48c923b8 update docs 2025-09-22 17:37:58 +03:00
bol-van ed4782887f update docs 2025-09-22 17:37:21 +03:00
bol-van 80b6b75934 blockcheck: test hostfakesplit altorder 2025-09-22 17:18:23 +03:00
bol-van 245ce41550 nfqws: altorder mod for hostfakesplit 2025-09-22 17:06:30 +03:00
bol-van db5dca28b0 nfqws: fix clang warnings 2025-09-22 15:06:52 +03:00
bol-van 6dad239fe3 blockcheck: fix infinite recursion on mac/bsd 2025-09-22 14:58:51 +03:00
bol-van aa4982a526 blockcheck: working strategies intersection print for multiple domains 2025-09-22 14:49:33 +03:00
bol-van 61808b37d8 base.sh quote parameters in replace_char 2025-09-22 13:05:35 +03:00
bol-van 4b90ee920c update docs 2025-09-22 10:11:06 +03:00
bol-van 170e9d7ffd nfqws: --dpi-desync-hostfakesplit-mod 2025-09-22 09:51:25 +03:00
bol-van d8f9ba29c3 update docs 2025-09-21 19:44:31 +03:00
bol-van 4914b813e7 update docs 2025-09-21 19:42:38 +03:00
bol-van c3fdec9bf0 update docs 2025-09-21 18:54:38 +03:00
bol-van 1cbdf9b891 nfqws: hostfakesplit fix use-after-free 2025-09-21 18:36:49 +03:00
bol-van 706dd7b2d9 nfqws: hostfakesplit send second fake 2025-09-21 18:31:09 +03:00
bol-van b2468a9095 blockcheck: change nft postnat hook from output to postrouting to fix some issues 2025-09-21 17:53:50 +03:00
bol-van acfbbc58ac blockcheck: new strategies 2025-09-21 14:54:31 +03:00
bol-van fd506dfe08 nfqws: print sessionID lengths if dupsid cannot be applied 2025-09-21 13:17:52 +03:00
bol-van 1ee25e01ea nfqws: generate random host with a-z at the first position 2025-09-21 12:51:06 +03:00
bol-van 521c385adb nfqws: --dpi-desync=hostfakesplit 2025-09-21 12:32:53 +03:00
bol-van 17971e87b4 update docs 2025-09-20 15:25:37 +03:00
bol-van 4dc1d035d8 update docs 2025-09-20 15:24:32 +03:00
bol-van 07eee8af25 winws: --wf-raw-part 2025-09-20 13:59:54 +03:00
bol-van 06e7818240 quick_start: traditional linux separate link 2025-09-04 10:12:09 +03:00
bol-van 00b0f3c940 quick_start: typo 2025-09-04 10:09:48 +03:00
bol-van 17df2adbe0 quick_start: curl/wget to stdout info 2025-09-04 10:09:01 +03:00
bol-van 40342745f7 quick_start: curl/wget to stdout info 2025-09-04 10:06:42 +03:00
bol-van 54d4cdb2d5 50-dht4all fix space/tabs 2025-09-03 17:19:35 +03:00
bol-van b251ea839c custom scripts increase repeats 2025-09-03 12:24:00 +03:00
bol-van 595cf863fc put old kernel ver note for @ih to customs 2025-09-01 22:00:55 +03:00
bol-van 91d5b90ded install_easy: install iptables-mod-u32 2025-09-01 21:29:00 +03:00
bol-van 33a7132920 50-dht4all move from @th to @ih 2025-09-01 21:25:30 +03:00
bol-van d9b23f14a2 docs works 2025-08-22 19:13:41 +03:00
bol-van 06613b4fd5 docs: windows server note 2025-08-22 19:10:56 +03:00
32 changed files with 3052 additions and 2174 deletions
+141 -22
View File
@@ -47,6 +47,7 @@ HTTPS_PORT=${HTTPS_PORT:-443}
QUIC_PORT=${QUIC_PORT:-443} QUIC_PORT=${QUIC_PORT:-443}
UNBLOCKED_DOM=${UNBLOCKED_DOM:-iana.org} UNBLOCKED_DOM=${UNBLOCKED_DOM:-iana.org}
PARALLEL_OUT=/tmp/zapret_parallel PARALLEL_OUT=/tmp/zapret_parallel
SIM_SUCCESS_RATE=${SIM_SUCCESS_RATE:-10}
HDRTEMP=/tmp/zapret-hdr HDRTEMP=/tmp/zapret-hdr
@@ -411,6 +412,13 @@ check_system()
else else
uname -a uname -a
fi fi
[ -f /etc/os-release ] && {
. /etc/os-release
[ -n "$PRETTY_NAME" ] && echo "distro: $PRETTY_NAME"
[ -n "$OPENWRT_RELEASE" ] && echo "openwrt release: $OPENWRT_RELEASE"
[ -n "$OPENWRT_BOARD" ] && echo "openwrt board: $OPENWRT_BOARD"
[ -n "$OPENWRT_ARCH" ] && echo "openwrt arch: $OPENWRT_ARCH"
}
echo firewall type is $FWTYPE echo firewall type is $FWTYPE
echo CURL=$CURL echo CURL=$CURL
$CURL --version $CURL --version
@@ -803,7 +811,7 @@ nft_scheme()
make_comma_list iplist $3 make_comma_list iplist $3
nft add table inet $NFT_TABLE nft add table inet $NFT_TABLE
nft "add chain inet $NFT_TABLE postnat { type filter hook output priority 102; }" nft "add chain inet $NFT_TABLE postnat { type filter hook postrouting priority 102; }"
nft "add rule inet $NFT_TABLE postnat meta nfproto ipv${IPV} $1 dport $2 mark and $DESYNC_MARK == 0 ip${ipver} daddr {$iplist} ct mark set ct mark or $DESYNC_MARK queue num $QNUM" nft "add rule inet $NFT_TABLE postnat meta nfproto ipv${IPV} $1 dport $2 mark and $DESYNC_MARK == 0 ip${ipver} daddr {$iplist} ct mark set ct mark or $DESYNC_MARK queue num $QNUM"
# for strategies with incoming packets involved (autottl) # for strategies with incoming packets involved (autottl)
nft "add chain inet $NFT_TABLE prenat { type filter hook prerouting priority -102; }" nft "add chain inet $NFT_TABLE prenat { type filter hook prerouting priority -102; }"
@@ -1063,6 +1071,17 @@ ws_curl_test()
# $3 - domain # $3 - domain
# $4,$5,$6, ... - ws params # $4,$5,$6, ... - ws params
local code ws_start=$1 testf=$2 dom=$3 local code ws_start=$1 testf=$2 dom=$3
[ "$SIMULATE" = 1 ] && {
n=$(random 0 99)
if [ "$n" -lt "$SIM_SUCCESS_RATE" ]; then
echo "SUCCESS"
return 0
else
echo "FAILED"
return 7
fi
}
shift shift
shift shift
shift shift
@@ -1085,7 +1104,7 @@ tpws_curl_test()
shift; shift; shift; shift;
strategy="$@" strategy="$@"
strategy_append_extra_tpws strategy_append_extra_tpws
report_append "ipv${IPV} $dom $testf : tpws ${WF:+$WF }$strategy" report_append "$dom" "$testf ipv${IPV}" "tpws ${WF:+$WF }$strategy"
} }
return $code return $code
} }
@@ -1104,7 +1123,7 @@ pktws_curl_test()
[ "$code" = 0 ] && { [ "$code" = 0 ] && {
strategy="$@" strategy="$@"
strategy_append_extra_pktws strategy_append_extra_pktws
report_append "ipv${IPV} $dom $testf : $PKTWSD ${WF:+$WF }$strategy" report_append "$dom" "$testf ipv${IPV}" "$PKTWSD ${WF:+$WF }$strategy"
} }
return $code return $code
} }
@@ -1144,8 +1163,35 @@ tpws_curl_test_update()
report_append() report_append()
{ {
# $1 - domain
# $2 - test function + ipver
# $3 - value
local hashstr hash hashvar hashcountvar val ct
# save resources if only one domain
[ "$DOMAINS_COUNT" -gt 1 ] && {
hashstr="$2 : $3"
hash="$(echo -n "$hashstr" | md5f)"
hashvar=RESHASH_${hash}
hashcountvar=${hashvar}_COUNTER
NRESHASH=${NRESHASH:-0}
eval val="\$$hashvar"
if [ -n "$val" ]; then
eval ct="\$$hashcountvar"
ct=$(($ct + 1))
eval $hashcountvar="\$ct"
else
eval $hashvar=\"$hashstr\"
eval $hashcountvar=1
eval RES_$NRESHASH="\$hash"
NRESHASH=$(($NRESHASH+1))
fi
}
NREPORT=${NREPORT:-0} NREPORT=${NREPORT:-0}
eval REPORT_${NREPORT}=\"$@\" eval REPORT_${NREPORT}=\"$2 $1 : $3\"
NREPORT=$(($NREPORT+1)) NREPORT=$(($NREPORT+1))
} }
report_print() report_print()
@@ -1158,6 +1204,22 @@ report_print()
n=$(($n+1)) n=$(($n+1))
done done
} }
result_intersection_print()
{
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\"
[ "$ct" = "$DOMAINS_COUNT" ] && {
eval val=\"\$$hashvar\"
echo "$val"
}
n=$(($n + 1))
done
}
report_strategy() report_strategy()
{ {
# $1 - test function # $1 - test function
@@ -1169,23 +1231,26 @@ report_strategy()
strategy="$(echo "$strategy" | xargs)" strategy="$(echo "$strategy" | xargs)"
echo "!!!!! $1: working strategy found for ipv${IPV} $2 : $3 $strategy !!!!!" echo "!!!!! $1: working strategy found for ipv${IPV} $2 : $3 $strategy !!!!!"
echo echo
# report_append "ipv${IPV} $2 $1 : $3 ${WF:+$WF }$strategy"
return 0 return 0
else else
echo "$1: $3 strategy for ipv${IPV} $2 not found" echo "$1: $3 strategy for ipv${IPV} $2 not found"
echo echo
report_append "ipv${IPV} $2 $1 : $3 not working" report_append "$2" "$1 ipv${IPV}" "$3 not working"
return 1 return 1
fi fi
} }
test_has_split()
{
contains "$1" split || contains "$1" disorder
}
test_has_fakedsplit() test_has_fakedsplit()
{ {
contains "$1" fakedsplit || contains "$1" fakeddisorder contains "$1" fakedsplit || contains "$1" fakeddisorder
} }
test_has_split()
{
contains "$1" multisplit || contains "$1" multidisorder || test_has_fakedsplit "$1"
}
test_has_hostfakesplit()
{
contains "$1" hostfakesplit
}
test_has_fake() test_has_fake()
{ {
[ "$1" = fake ] || starts_with "$1" fake, [ "$1" = fake ] || starts_with "$1" fake,
@@ -1210,7 +1275,7 @@ pktws_curl_test_update_vary()
# $5,$6,... - strategy # $5,$6,... - strategy
local testf=$1 sec=$2 domain=$3 desync=$4 proto splits= pos fake ret=1 local testf=$1 sec=$2 domain=$3 desync=$4 proto splits= pos fake ret=1
local fake1=- fake2=- fake3=- local fake1=- fake2=- fake3=- fake4=-
shift; shift; shift; shift shift; shift; shift; shift
@@ -1219,18 +1284,27 @@ pktws_curl_test_update_vary()
test_has_fake $desync && { test_has_fake $desync && {
fake1="--dpi-desync-fake-$proto=0x00000000" fake1="--dpi-desync-fake-$proto=0x00000000"
[ "$sec" = 0 ] || { [ "$sec" = 0 ] || {
fake2="--dpi-desync-fake-tls=0x00000000 --dpi-desync-fake-tls=! --dpi-desync-fake-tls-mod=rnd,rndsni,dupsid" fake2='--dpi-desync-fake-tls=0x00000000 --dpi-desync-fake-tls=! --dpi-desync-fake-tls-mod=rnd,rndsni,dupsid'
fake3="--dpi-desync-fake-tls-mod=rnd,dupsid,rndsni,padencap" # this splits actual fake to '1603' and modified standard fake from offset 2
fake3='--dpi-desync-fake-tls=0x1603 --dpi-desync-fake-tls=!+2 --dpi-desync-fake-tls-mod=rnd,dupsid,rndsni --dpi-desync-fake-tcp-mod=seq'
fake4='--dpi-desync-fake-tls-mod=rnd,dupsid,rndsni,padencap'
} }
} }
if test_has_fakedsplit $desync ; then if test_has_fakedsplit $desync ; then
splits="method+2 midsld" splits="method+2 midsld"
[ "$sec" = 0 ] || splits="1 midsld" [ "$sec" = 0 ] || splits="1 midsld"
# do not send fake first
fake1='--dpi-desync-fakedsplit-mod=altorder=1'
elif test_has_split $desync ; then elif test_has_split $desync ; then
splits="method+2 midsld" splits="method+2 midsld"
[ "$sec" = 0 ] || splits="1 midsld 1,midsld" [ "$sec" = 0 ] || splits="1 midsld 1,midsld"
fi fi
for fake in '' "$fake1" "$fake2" "$fake3" ; do test_has_hostfakesplit $desync && {
fake1="--dpi-desync-hostfakesplit-mod=altorder=1"
fake2="--dpi-desync-hostfakesplit-midhost=midsld"
fake3="--dpi-desync-hostfakesplit-mod=altorder=1 --dpi-desync-hostfakesplit-midhost=midsld"
}
for fake in '' "$fake1" "$fake2" "$fake3" "$fake4" ; do
[ "$fake" = "-" ] && continue [ "$fake" = "-" ] && continue
if [ -n "$splits" ]; then if [ -n "$splits" ]; then
for pos in $splits ; do for pos in $splits ; do
@@ -1257,7 +1331,7 @@ pktws_check_domain_http_bypass_()
# $3 - domain # $3 - domain
local ok ttls s f f2 e desync pos fooling frag sec="$2" delta orig splits local ok ttls s f f2 e desync pos fooling frag sec="$2" delta orig splits
local need_split need_disorder need_fakedsplit need_fakeddisorder need_fake need_wssize local need_split need_disorder need_fakedsplit need_hostfakesplit need_fakeddisorder need_fake need_wssize
local splits_http='method+2 midsld method+2,midsld' local splits_http='method+2 midsld method+2,midsld'
local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1' local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
@@ -1302,25 +1376,33 @@ pktws_check_domain_http_bypass_()
done done
need_fakedsplit=1 need_fakedsplit=1
need_hostfakesplit=1
need_fakeddisorder=1 need_fakeddisorder=1
need_fake=1 need_fake=1
for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit hostfakesplit fake,hostfakesplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do
[ "$need_fake" = 0 ] && test_has_fake "$desync" && continue [ "$need_fake" = 0 ] && test_has_fake "$desync" && continue
[ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue [ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue
[ "$need_hostfakesplit" = 0 ] && contains "$desync" hostfakesplit && continue
[ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue [ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue
ok=0 ok=0
for ttl in $ttls; do for ttl in $ttls; do
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=$ttl $e && { # orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server.
# missing ACK is transmitted in the first data packet of TLS/HTTP proto
for f in '' '--orig-ttl=1 --orig-mod-start=s1 --orig-mod-cutoff=d1'; do
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=$ttl $f $e && {
[ "$SCANLEVEL" = quick ] && return [ "$SCANLEVEL" = quick ] && return
ok=1 ok=1
need_wssize=0 need_wssize=0
break [ "$SCANLEVEL" = force ] || break
} }
done done
[ "$ok" = 1 ] && break
done
# only skip tests if TTL succeeded. do not skip if TTL failed but fooling succeeded # only skip tests if TTL succeeded. do not skip if TTL failed but fooling succeeded
[ $ok = 1 -a "$SCANLEVEL" != force ] && { [ $ok = 1 -a "$SCANLEVEL" != force ] && {
[ "$desync" = fake ] && need_fake=0 [ "$desync" = fake ] && need_fake=0
[ "$desync" = fakedsplit ] && need_fakedsplit=0 [ "$desync" = fakedsplit ] && need_fakedsplit=0
[ "$desync" = hostfakesplit ] && need_hostfakesplit=0
[ "$desync" = fakeddisorder ] && need_fakeddisorder=0 [ "$desync" = fakeddisorder ] && need_fakeddisorder=0
} }
f= f=
@@ -1329,12 +1411,21 @@ pktws_check_domain_http_bypass_()
[ "$IPV" = 6 ] && f="$f hopbyhop hopbyhop2" [ "$IPV" = 6 ] && f="$f hopbyhop hopbyhop2"
for fooling in $f; do for fooling in $f; do
ok=0 ok=0
f2=
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling $e && { pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling $e && {
warn_fool $fooling $desync warn_fool $fooling $desync
[ "$SCANLEVEL" = quick ] && return [ "$SCANLEVEL" = quick ] && return
need_wssize=0 need_wssize=0
ok=1 ok=1
} }
[ "$fooling" = badseq ] && {
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && continue
# --dpi-desync-badseq-increment=0 leaves modified by default ack increment
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling --dpi-desync-badseq-increment=0 $e && {
[ "$SCANLEVEL" = quick ] && return
need_wssize=0
}
}
[ "$fooling" = md5sig ] && { [ "$fooling" = md5sig ] && {
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && continue [ "$ok" = 1 -a "$SCANLEVEL" != force ] && continue
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling --dup=1 --dup-cutoff=n2 --dup-fooling=md5sig $e && { pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling --dup=1 --dup-cutoff=n2 --dup-fooling=md5sig $e && {
@@ -1399,18 +1490,30 @@ pktws_check_domain_http_bypass_()
need_fakedsplit=1 need_fakedsplit=1
need_fakeddisorder=1 need_fakeddisorder=1
need_hostfakesplit=1
need_fake=1 need_fake=1
for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit hostfakesplit fake,hostfakesplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do
[ "$need_fake" = 0 ] && test_has_fake "$desync" && continue [ "$need_fake" = 0 ] && test_has_fake "$desync" && continue
[ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue [ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue
[ "$need_hostfakesplit" = 0 ] && contains "$desync" hostfakesplit && continue
[ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue [ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue
ok=0 ok=0
for orig in '' 1 2 3; do # orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server.
# missing ACK is transmitted in the first data packet of TLS/HTTP proto
for delta in 1 2 3 4 5; do
for f in '' '--orig-ttl=1 --orig-mod-start=s1 --orig-mod-cutoff=d1'; do
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=1 --dpi-desync-autottl=-$delta $f $e && ok=1
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
done
done
[ "$SCANLEVEL" = force ] && {
for orig in 1 2 3; do
for delta in 1 2 3 4 5; do for delta in 1 2 3 4 5; do
pktws_curl_test_update_vary $1 $2 $3 $desync ${orig:+--orig-autottl=+$orig} --dpi-desync-ttl=1 --dpi-desync-autottl=-$delta $e && ok=1 pktws_curl_test_update_vary $1 $2 $3 $desync ${orig:+--orig-autottl=+$orig} --dpi-desync-ttl=1 --dpi-desync-autottl=-$delta $e && ok=1
done done
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break [ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
done done
}
[ "$ok" = 1 ] && [ "$ok" = 1 ] &&
{ {
echo "WARNING ! although autottl worked it requires testing on multiple domains to find out reliable delta" echo "WARNING ! although autottl worked it requires testing on multiple domains to find out reliable delta"
@@ -1420,6 +1523,7 @@ pktws_check_domain_http_bypass_()
[ "$SCANLEVEL" = force ] || { [ "$SCANLEVEL" = force ] || {
[ "$desync" = fake ] && need_fake=0 [ "$desync" = fake ] && need_fake=0
[ "$desync" = fakedsplit ] && need_fakedsplit=0 [ "$desync" = fakedsplit ] && need_fakedsplit=0
[ "$desync" = hostfakesplit ] && need_hostfakesplit=0
[ "$desync" = fakeddisorder ] && need_fakeddisorder=0 [ "$desync" = fakeddisorder ] && need_fakeddisorder=0
} }
} }
@@ -1628,17 +1732,19 @@ check_domain_prolog()
local code local code
[ "$SIMULATE" = 1 ] && return 0
echo echo
echo \* $1 ipv$IPV $3 echo \* $1 ipv$IPV $3
echo "- checking without DPI bypass" echo "- checking without DPI bypass"
curl_test $1 $3 && { curl_test $1 $3 && {
report_append "ipv${IPV} $3 $1 : working without bypass" report_append "$3" "$1 ipv${IPV}" "working without bypass"
[ "$SCANLEVEL" = force ] || return 1 [ "$SCANLEVEL" = force ] || return 1
} }
code=$? code=$?
curl_has_reason_to_continue $code || { curl_has_reason_to_continue $code || {
report_append "ipv${IPV} $3 $1 : test aborted, no reason to continue. curl code $(curl_translate_code $code)" report_append "$3" "$1 ipv${IPV}" "test aborted, no reason to continue. curl code $(curl_translate_code $code)"
return 1 return 1
} }
return 0 return 0
@@ -1822,6 +1928,7 @@ ask_params()
[ -n "$dom" ] && DOMAINS="$dom" [ -n "$dom" ] && DOMAINS="$dom"
} }
} }
DOMAINS_COUNT="$(echo "$DOMAINS" | wc -w | trim)"
local IPVS_def=4 local IPVS_def=4
[ -n "$IPVS" ] || { [ -n "$IPVS" ] || {
@@ -2201,6 +2308,18 @@ cleanup
echo echo
echo \* SUMMARY echo \* SUMMARY
report_print report_print
[ "$DOMAINS_COUNT" -gt 1 ] && {
echo
echo \* COMMON
result_intersection_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 "Current scan level was \"$SCANLEVEL\"".
}
}
echo echo
echo "Please note this SUMMARY does not guarantee a magic pill for you to copy/paste and be happy." echo "Please note this SUMMARY does not guarantee a magic pill for you to copy/paste and be happy."
echo "Understanding how strategies work is very desirable." echo "Understanding how strategies work is very desirable."
+10 -5
View File
@@ -297,10 +297,10 @@ minsleep()
replace_char() replace_char()
{ {
local a=$1 local a="$1"
local b=$2 local b="$2"
shift; shift shift; shift
echo "$@" | tr $a $b echo "$@" | tr "$a" "$b"
} }
replace_str() replace_str()
@@ -318,6 +318,12 @@ setup_md5()
exists $MD5 || MD5=md5 exists $MD5 || MD5=md5
} }
md5f()
{
setup_md5
$MD5 | cut -d ' ' -f1
}
setup_random() setup_random()
{ {
[ -n "$RCUT" ] && return [ -n "$RCUT" ] && return
@@ -330,7 +336,6 @@ random()
{ {
# $1 - min, $2 - max # $1 - min, $2 - max
local r rs local r rs
setup_md5
setup_random setup_random
if [ -c /dev/urandom ]; then if [ -c /dev/urandom ]; then
read rs </dev/urandom read rs </dev/urandom
@@ -338,7 +343,7 @@ random()
rs="$RANDOM$RANDOM$(date)" rs="$RANDOM$RANDOM$(date)"
fi fi
# shells use signed int64 # shells use signed int64
r=1$(echo $rs | $MD5 | sed 's/[^0-9]//g' | $RCUT) r=1$(echo $rs | md5f | sed 's/[^0-9]//g' | $RCUT)
echo $(( ($r % ($2-$1+1)) + $1 )) echo $(( ($r % ($2-$1+1)) + $1 ))
} }
+2 -2
View File
@@ -703,7 +703,7 @@ removable_pkgs_openwrt()
for pkg in $PKGS2; do for pkg in $PKGS2; do
check_package_exists_openwrt $pkg && PKGS="${PKGS:+$PKGS }$pkg" check_package_exists_openwrt $pkg && PKGS="${PKGS:+$PKGS }$pkg"
done done
PKGS="ipset iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra ip6tables-mod-nat ip6tables-extra kmod-nft-queue gzip coreutils-sort coreutils-sleep curl $PKGS" PKGS="ipset iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra iptables-mod-u32 ip6tables-mod-nat ip6tables-extra kmod-nft-queue gzip coreutils-sort coreutils-sleep curl $PKGS"
} }
openwrt_fix_broken_apk_uninstall_scripts() openwrt_fix_broken_apk_uninstall_scripts()
@@ -744,7 +744,7 @@ check_prerequisites_openwrt()
iptables) iptables)
pkg_iptables=iptables pkg_iptables=iptables
check_package_exists_openwrt iptables-zz-legacy && pkg_iptables=iptables-zz-legacy check_package_exists_openwrt iptables-zz-legacy && pkg_iptables=iptables-zz-legacy
PKGS="$PKGS ipset $pkg_iptables iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra" PKGS="$PKGS ipset $pkg_iptables iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra iptables-mod-u32"
check_package_exists_openwrt ip6tables-zz-legacy && pkg_iptables=ip6tables-zz-legacy check_package_exists_openwrt ip6tables-zz-legacy && pkg_iptables=ip6tables-zz-legacy
[ "$DISABLE_IPV6" = 1 ] || PKGS="$PKGS $pkg_iptables ip6tables-mod-nat ip6tables-extra" [ "$DISABLE_IPV6" = 1 ] || PKGS="$PKGS $pkg_iptables ip6tables-mod-nat ip6tables-extra"
;; ;;
+14
View File
@@ -541,3 +541,17 @@ nfqws,tpws: fix possible crashes or high memory usage if hostlist has duplicate
init.d: custom scripts 50-discord-media, 50-stun4all init.d: custom scripts 50-discord-media, 50-stun4all
init.d: windivert filters for discord media, stun, wireguard init.d: windivert filters for discord media, stun, wireguard
readme: hardware problems description readme: hardware problems description
v72
winws: --wf-raw-part
nfqws: --dpi-desync=hostfakesplit
nfqws: --dpi-desync-fake-tcp-mod=seq
nfqws: --dpi-desync-fake-tls=!+offset , --dpi-desync-fake-xxx=[+offset]@filename
nfqws: --dpi-desync-fakedsplit-mod=altorder for fakedsplit/fakeddisorder
nfqws: --dpi-desync-hostfakesplit-mod=altorder
nfqws: fakedsplit/fakeddisorder normalize fake split pattern offset to reasm offset
nfqws: optimize ipv4 ip_id. apply ip_id on all OS the same way.
blockcheck: print PRETTY_NAME and some OPENWRT_xxx from /etc/os-release
blockcheck: new strategies
blockcheck: curl test simulation : SIMULATE=1
+33 -20
View File
@@ -16,7 +16,7 @@
в простыню [readme.md](readme.md). в простыню [readme.md](readme.md).
Обход DPI является хакерской методикой. Под этим словом понимается метод, Обход DPI является хакерской методикой. Под этим словом понимается метод,
которому сопротивляется окружающая среда, которому автоматически не которому оказывается активное противодействие и поэтому автоматически не
гарантирована работоспособность в любых условиях и на любых ресурсах, требуется гарантирована работоспособность в любых условиях и на любых ресурсах, требуется
настройка под специфические условия у вашего провайдера. Условия могут меняться настройка под специфические условия у вашего провайдера. Условия могут меняться
со временем, и методика может начинать или переставать работать, может со временем, и методика может начинать или переставать работать, может
@@ -52,6 +52,18 @@
1. Скачайте последний [tar.gz релиз](https://github.com/bol-van/zapret/releases) в /tmp, распакуйте его, затем удалите архив. 1. Скачайте последний [tar.gz релиз](https://github.com/bol-van/zapret/releases) в /tmp, распакуйте его, затем удалите архив.
Для openwrt и прошивок используйте вариант `openwrt-embedded`. Для openwrt и прошивок используйте вариант `openwrt-embedded`.
Для экономия места в /tmp можно качать через curl в stdout и сразу распаковывать. Для экономия места в /tmp можно качать через curl в stdout и сразу распаковывать.
Пример под openwrt для версии zapret 71.4 (для других URL отличается) :
```
$ curl -Lo - https://github.com/bol-van/zapret/releases/download/v71.4/zapret-v71.4-openwrt-embedded.tar.gz | tar -zx
$ wget -O - https://github.com/bol-van/zapret/releases/download/v71.4/zapret-v71.4-openwrt-embedded.tar.gz | tar -zx
```
Пример под традиционный linux для версии zapret 71.4 (для других URL отличается) :
```
$ curl -Lo - https://github.com/bol-van/zapret/releases/download/v71.4/zapret-v71.4.tar.gz | tar -zx
$ wget -O - https://github.com/bol-van/zapret/releases/download/v71.4/zapret-v71.4.tar.gz | tar -zx
```
curl должен быть предварительно установлен. Но он в любом случае понадобится далее.
Вариант с wget будет работать только если установленный wget поддерживает https.
2. Убедитесь, что у вас отключены все средства обхода блокировок, в том числе и 2. Убедитесь, что у вас отключены все средства обхода блокировок, в том числе и
сам zapret. Гарантированно уберет zapret скрипт `uninstall_easy.sh`. сам zapret. Гарантированно уберет zapret скрипт `uninstall_easy.sh`.
@@ -129,10 +141,14 @@
или `tpws` и запомнить найденные стратегии для дальнейшего применения. или `tpws` и запомнить найденные стратегии для дальнейшего применения.
Следует понимать, что скрипт проверяет доступность только конкретного Следует понимать, что скрипт проверяет доступность только конкретного
домена, который вы вводите в начале. Вероятно, все остальные домены домена, который вы вводите в начале, конкретной программой curl.
блокированы подобным образом, **но не факт**. В большинстве случаев можно У разных клиентов есть свой фингерпринт. У броузеров один, у curl другой.
объединить несколько стратегий в одну универсальную, и это **крайне Может применяться или не применяться многопакетный TLS с постквантовой криптографией (kyber).
желательно**. Необходимо понимать как работают стратегии. zapret **не может От этого может зависеть работоспособность стратегий.
Обычно остальные домены блокированы подобным образом, **но не факт**.
Бывают специальные блокировки. Некоторые параметры требуют тюнинга под "общий знаменатель".
В большинстве случаев можно объединить несколько стратегий в одну универсальную, и это **крайне
желательно**, но это требует понимания как работают стратегии. zapret **не может
пробить блокировку по IP адресу**. Для проверки нескольких доменов вводите пробить блокировку по IP адресу**. Для проверки нескольких доменов вводите
их через пробел. их через пробел.
@@ -143,19 +159,7 @@
> направления (IP сервера). скрипт не всегда может выдать вам в итогах > направления (IP сервера). скрипт не всегда может выдать вам в итогах
> оптимальную стратегию, которую надо просто переписать в настройки. В > оптимальную стратегию, которую надо просто переписать в настройки. В
> некоторых случаях надо реально думать что происходит, анализируя результат > некоторых случаях надо реально думать что происходит, анализируя результат
> на разных стратегиях. Если вы применяете большой TTL, чтобы достать до > на разных стратегиях.
> магистрала, то не лишним будет добавить дополнительный ограничитель
> `--dpi-desync-fooling`, чтобы не сломать сайты на более коротких
> дистанциях. `md5sig` наиболее совместим, но работает **только** на linux
> серверах. `badseq` может работать только на https и не работать на http.
> Чтобы выяснить какие дополнительные ограничители работают, смотрите
> результат теста аналогичных стратегий без TTL с каждым из этих
> ограничителей.
>
> При использовании `autottl` следует протестировать как можно больше разных
> доменов. Эта техника может на одних провайдерах работать стабильно, на
> других потребуется выяснить при каких параметрах она стабильна, на третьих
> полный хаос, и проще отказаться.
> >
> Далее, имея понимание что работает на http, https, quic нужно > Далее, имея понимание что работает на http, https, quic нужно
> сконструировать параметры запуска `tpws` и/или `nfqws` с использованием > сконструировать параметры запуска `tpws` и/или `nfqws` с использованием
@@ -202,8 +206,8 @@
> Но здесь совсем "копи-пастный" вариант. Чем больше вы объедините стратегий и > Но здесь совсем "копи-пастный" вариант. Чем больше вы объедините стратегий и
> сократите их общее количество, тем будет лучше. > сократите их общее количество, тем будет лучше.
> >
> Если вам не нужно дурение отдельных протоколов, лучше всего будет их > Если вам не нужно дурение отдельных протоколов, лучше всего будет убрать
> убрать из системы перехвата трафика через параметры `TPWS_PORTS`, > лишние порты из системы перехвата трафика через параметры `TPWS_PORTS`,
> `NFQWS_PORTS_TCP`, `NFQWS_PORTS_UDP` и убрать соответствующие им профили > `NFQWS_PORTS_TCP`, `NFQWS_PORTS_UDP` и убрать соответствующие им профили
> мультистратегии. > мультистратегии.
> >
@@ -230,6 +234,15 @@
> В этом примере `wssize` будет применяться всегда к порту tcp `443` вне > В этом примере `wssize` будет применяться всегда к порту tcp `443` вне
> зависимости от параметра `MODE_FILTER`. Хостлист будет игнорироваться, > зависимости от параметра `MODE_FILTER`. Хостлист будет игнорироваться,
> если таковой имеется. К http применять `wssize` вредно и бессмысленно. > если таковой имеется. К http применять `wssize` вредно и бессмысленно.
>
> Иногда требуется дописать к стратегиям свои собственные параметры.
> Например, нужно изменить количество повторов фейков или задать свой фейк.
> Это делается через шелл-переменные `PKTWS_EXTRA`, `TPWS_EXTRA`.
>
> ```PKTWS_EXTRA="--dpi-desync-repeats=10 --dpi-desync-fake-tls=/tmp/tls.bin" ./blockcheck.sh```
>
> Перебор всех комбинаций может привести к ожиданию неделями, поэтому выбран разумный
> костяк проверки, на который вы можете навешивать свои кустомизации.
7. Запустите скрипт облегченной установки - `install_easy.sh` Выберите `nfqws` 7. Запустите скрипт облегченной установки - `install_easy.sh` Выберите `nfqws`
и/или `tpws`, затем согласитесь на редактирование параметров. Откроется и/или `tpws`, затем согласитесь на редактирование параметров. Откроется
+44 -55
View File
@@ -11,8 +11,8 @@
## Немного разъяснений ## Немного разъяснений
Обход DPI является хакерской методикой. Под этим словом понимается метод, которому сопротивляется окружающая среда, Обход DPI является хакерской методикой. Под этим словом понимается метод, которому оказывается активное противодействие и поэтому
которому автоматически не гарантирована работоспособность в любых условиях и на любых ресурсах, автоматически не гарантирована работоспособность в любых условиях и на любых ресурсах,
требуется настройка под специфические условия у вашего провайдера. Условия могут меняться со временем, требуется настройка под специфические условия у вашего провайдера. Условия могут меняться со временем,
и методика может начинать или переставать работать, может потребоваться повторный анализ ситуации. и методика может начинать или переставать работать, может потребоваться повторный анализ ситуации.
Могут обнаруживаться отдельные ресурсы, которые заблокированы иначе, и которые не работают или перестали работать. Могут обнаруживаться отдельные ресурсы, которые заблокированы иначе, и которые не работают или перестали работать.
@@ -30,24 +30,7 @@
Будем считать, что у вас есть windows 7 или выше. Задача - обойти блокировки с самой системы. Будем считать, что у вас есть windows 7 или выше. Задача - обойти блокировки с самой системы.
> [!NOTE] ## Я ЧТО-ТО ДЕЛАЛ, НЕ ПОМОГЛО, КАК ТЕПЕРЬ ЭТО УДАЛИТЬ
> Есть решение самое простое, а есть "как положено".
## САМОЕ ПРОСТОЕ РЕШЕНИЕ
_"Совсем ничего не могу, все очень сложно, дайте мне таблетку."_ ©Простой пользователь
1) Скачайте и распакуйте архив https://github.com/bol-van/zapret-win-bundle/archive/refs/heads/master.zip.
2) Запустите `zapret-winws/preset_russia.cmd` от имени администратора. Возможно, заведется сразу.
> То же самое с ограничителем по автоматически создаваемому хост-листу `preset_russia_autohostlist.cmd`.
> Что такое `autohostlist` - читайте [readme.md](./readme.md). Проще говоря, мы обходим только то, что долго и упорно не хочет открываться.
> Сначала не будет, но надо пытаться много раз, и тогда сработает, а дальше будет всегда срабатывать.
> Остальное не будет ломаться. Использовать только, если первый вариант тоже работает.
Не помогла _"таблетка"_ ? Это вовсе не значит, что ничего не получится. Но придется делать по нормальному.
## НЕ ПОМОГЛО, КАК ТЕПЕРЬ ЭТО УДАЛИТЬ
Если вы не устанавливали zapret как службу или запланированную задачу (а это требует редактирования cmd файлов), Если вы не устанавливали zapret как службу или запланированную задачу (а это требует редактирования cmd файлов),
достаточно закрыть окно с winws и запустить windivert_delete.cmd. достаточно закрыть окно с winws и запустить windivert_delete.cmd.
@@ -55,13 +38,16 @@ _"Совсем ничего не могу, все очень сложно, да
После чего можно удалить папку с zapret. На этом деинсталляция закончена. После чего можно удалить папку с zapret. На этом деинсталляция закончена.
Если же вы устанавливали zapret как службу, то вы наверняка знаете как ее удалить. Если же вы устанавливали zapret как службу, то вы наверняка знаете как ее удалить.
## РЕШЕНИЕ "КАК ПОЛОЖЕНО" Если вдруг среди того, на что вы нажимали, есть слова "general", "alt", ".bat", "автозапуск", или же есть файлы, которые отсутствуют
в оригинальных репозиториях, то это сборка. Вы не получите ответа как ее удалить от разработчика zapret.
Спрашивайте самих сборщиков. Разработчик не предоставляет простого решения, этим занимаются сборщики, но они и сами отвечают за свои продукты.
1) Скачайте и распакуйте архив https://github.com/bol-van/zapret-win-bundle/archive/refs/heads/master.zip. ## Настройка
2) Если у вас Windows 7 x64, однократно запустите `win7/install_win7.cmd`. Батник заменит файлы windivert на совместимую с Windows 7 версию. 1. Скачайте и распакуйте архив https://github.com/bol-van/zapret-win-bundle/archive/refs/heads/master.zip.
2. Если у вас Windows 7 x64, однократно запустите `win7/install_win7.cmd`. Батник заменит файлы windivert на совместимую с Windows 7 версию.
> [!WARNING]
> Для 32-битных систем Windows нет готового полного варианта. > Для 32-битных систем Windows нет готового полного варианта.
> На windows 11 arm64 выполните `arm64/install_arm64.cmd` от имени администратора и перезагрузите компьютер. > На windows 11 arm64 выполните `arm64/install_arm64.cmd` от имени администратора и перезагрузите компьютер.
@@ -72,11 +58,11 @@ _"Совсем ничего не могу, все очень сложно, да
> более-менее научились с ним дружить. > более-менее научились с ним дружить.
> Если проблема имеет место , используйте исключения. Если не помогает - отключайте антивирус совсем. > Если проблема имеет место , используйте исключения. Если не помогает - отключайте антивирус совсем.
3) Убедитесь, что у вас отключены все средства обхода блокировок, в том числе и сам zapret. 3. Убедитесь, что у вас отключены все средства обхода блокировок, в том числе и сам zapret.
4) Если вы работаете в виртуальной машине, необходимо использовать соединение с сетью в режиме bridge. nat не подходит 4. Если вы работаете в виртуальной машине, необходимо использовать соединение с сетью в режиме bridge. nat не подходит
5) Запустите `blockcheck\blockcheck.cmd`. blockcheck в начале проверяет **DNS**. 5. Запустите `blockcheck\blockcheck.cmd`. blockcheck в начале проверяет **DNS**.
Если выводятся сообщения о подмене адресов, то нужно будет решить проблему с **DNS**. Если выводятся сообщения о подмене адресов, то нужно будет решить проблему с **DNS**.
blockcheck перейдет в этом случае на **DoH** _(DNS over HTTPS)_ и будет пытаться получить и использовать реальные IP адреса. blockcheck перейдет в этом случае на **DoH** _(DNS over HTTPS)_ и будет пытаться получить и использовать реальные IP адреса.
Но если вы не настроите решение этой проблемы, обход будет работать только для тех программ, Но если вы не настроите решение этой проблемы, обход будет работать только для тех программ,
@@ -92,35 +78,29 @@ blockcheck перейдет в этом случае на **DoH** _(DNS over HTT
> >
> Тут все разжевано как и где это включается : https://hackware.ru/?p=13707 > Тут все разжевано как и где это включается : https://hackware.ru/?p=13707
6) blockcheck позволяет выявить рабочую стратегию обхода блокировок. 6. blockcheck позволяет выявить рабочую стратегию обхода блокировок.
Лог скрипта будет сохранен в `blockcheck\blockcheck.log`. Лог скрипта будет сохранен в `blockcheck\blockcheck.log`.
Запомните/перепишите найденные стратегии. Запомните/перепишите найденные стратегии.
> [!WARNING] Следует понимать, что скрипт проверяет доступность только конкретного
> Следует понимать, что blockcheck проверяет доступность только конкретного домена, который вы вводите в начале. домена, который вы вводите в начале, конкретной программой curl.
> Вероятно, все остальные домены блокированы подобным образом, но не факт. У разных клиентов есть свой фингерпринт. У броузеров один, у curl другой.
Может применяться или не применяться многопакетный TLS с постквантовой криптографией (kyber).
От этого может зависеть работоспособность стратегий.
Обычно остальные домены блокированы подобным образом, **но не факт**.
Бывают специальные блокировки. Некоторые параметры требуют тюнинга под "общий знаменатель".
В большинстве случаев можно объединить несколько стратегий в одну универсальную, и это **крайне
желательно**, но это требует понимания как работают стратегии. zapret **не может
пробить блокировку по IP адресу**. Для проверки нескольких доменов вводите их через пробел.
> [!TIP] > Сейчас блокираторы ставят на магистральных каналах. В сложных случаях у
> В большинстве случаев можно обьединить несколько стратегий в одну универсальную, и это крайне желательно. > вас может быть несколько маршрутов с различной длиной по ХОПам, с DPI на
> разных хопах. Приходится преодолевать целый зоопарк DPI, которые еще и
> Необходимо понимать [как работают стратегии](./readme.md/#nfqws). > включаются в работу хаотичным образом или образом, зависящим от
> zapret не может пробить блокировку по IP адресу. Для проверки нескольких доменов вводите их через пробел. > направления (IP сервера). скрипт не всегда может выдать вам в итогах
> > оптимальную стратегию, которую надо просто переписать в настройки. В
> Сейчас блокираторы ставят на магистральных каналах. В сложных случаях у вас может быть несколько маршрутов > некоторых случаях надо реально думать что происходит, анализируя результат
> с различной длиной по ХОПам, с DPI на разных хопах. Приходится преодолевать целый зоопарк DPI, > на разных стратегиях.
> которые еще и включаются в работу хаотичным образом или образом, зависящим от направления (IP сервера).
> blockcheck не всегда может выдать вам в итогах оптимальную стратегию, которую надо просто переписать в настройки.
> В некоторых случаях надо реально думать что происходит, анализируя результат на разных стратегиях.
> Если вы применяете большой TTL, чтобы достать до магистрала, то не лишним будет добавить дополнительный ограничитель
> `--dpi-desync-fooling`, чтобы не сломать сайты на более коротких дистанциях.
> _md5sig_ наиболее совместим, но работатет только на linux серверах.
> badseq может работать только на https и не работать на http.
> Чтобы выяснить какие дополнительные ограничители работают, смотрите результат теста аналогичных стратегий без TTL
> с каждым из этих ограничителей.
>
> При использовании autottl следует протестировать как можно больше разных доменов. Эта техника
> может на одних провайдерах работать стабильно, на других потребуется выяснить при каких параметрах
> она стабильна, на третьих полный хаос, и проще отказаться.
> >
> Далее, имея понимание что работает на http, https, quic, нужно сконструировать параметры запуска winws > Далее, имея понимание что работает на http, https, quic, нужно сконструировать параметры запуска winws
> с использованием мультистратегии. Как работают мультистратегии описано в [readme.md](./readme.md#множественные-стратегии). > с использованием мультистратегии. Как работают мультистратегии описано в [readme.md](./readme.md#множественные-стратегии).
@@ -183,12 +163,21 @@ blockcheck перейдет в этом случае на **DoH** _(DNS over HTT
> >
> В этих примерах wssize будет применяться всегда к порту tcp 443, а хостлист будет игнорироваться. > В этих примерах wssize будет применяться всегда к порту tcp 443, а хостлист будет игнорироваться.
> К http применять wssize вредно и бессмысленно. > К http применять wssize вредно и бессмысленно.
>
> Иногда требуется дописать к стратегиям свои собственные параметры.
> Например, нужно изменить количество повторов фейков или задать свой фейк.
> Это делается через шелл-переменные `PKTWS_EXTRA`, `TPWS_EXTRA`. Пользуйтесь шеллом `cygwin/cygwin-admin.cmd`.
>
> ```PKTWS_EXTRA="--dpi-desync-repeats=10 --dpi-desync-fake-tls=/tmp/tls.bin" blockcheck```
>
> Перебор всех комбинаций может привести к ожиданию неделями, поэтому выбран разумный
> костяк проверки, на который вы можете навешивать свои кустомизации.
7) Протестируйте найденные стратегии на winws. Winws следует брать из zapret-winws. 7. Протестируйте найденные стратегии на winws. Winws следует брать из zapret-winws.
Для этого откройте командную строку windows от имени администратора в директории zapret-winws. Для этого откройте командную строку windows от имени администратора в директории zapret-winws.
Проще всего это сделать через `_CMD_ADMIN.cmd`. Он сам поднимет права и зайдет в нужную директорию. Проще всего это сделать через `_CMD_ADMIN.cmd`. Он сам поднимет права и зайдет в нужную директорию.
8) Обеспечьте удобную загрузку обхода блокировок. 8. Обеспечьте удобную загрузку обхода блокировок.
> Есть 2 варианта. Ручной запуск через ярлык или автоматический при старте системы, вне контекста текущего пользователя. > Есть 2 варианта. Ручной запуск через ярлык или автоматический при старте системы, вне контекста текущего пользователя.
> Последний вариант разделяется на запуск через планировщик задач и через службы windows. > Последний вариант разделяется на запуск через планировщик задач и через службы windows.
@@ -203,7 +192,7 @@ blockcheck перейдет в этом случае на **DoH** _(DNS over HTT
> >
> Аналогично настраиваются и службы windows. Смотрите `service_*.cmd` > Аналогично настраиваются и службы windows. Смотрите `service_*.cmd`
9) Если ломаются отдельные незаблокированные ресурсы, нужно пользоваться ограничивающим 9. Если ломаются отдельные незаблокированные ресурсы, нужно пользоваться ограничивающим
ipset или хост листом. Читайте основной талмуд [readme.md](./readme.md) ради подробностей. ipset или хост листом. Читайте основной талмуд [readme.md](./readme.md) ради подробностей.
Но еще лучше будет подбирать такие стратегии, которые ломают минимум. Но еще лучше будет подбирать такие стратегии, которые ломают минимум.
Есть стратегии довольно безобидные, а есть сильно ломающие, которые подходят только для точечного пробития отдельных ресурсов, Есть стратегии довольно безобидные, а есть сильно ломающие, которые подходят только для точечного пробития отдельных ресурсов,
+73 -17
View File
@@ -1,4 +1,4 @@
# zapret v71.4 # zapret v72
# SCAMMER WARNING # SCAMMER WARNING
@@ -180,7 +180,7 @@ nfqws takes the following parameters:
--dup-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment for dup. default -66000 --dup-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment for dup. default -66000
--dup-start=[n|d|s]N ; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N --dup-start=[n|d|s]N ; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N
--dup-cutoff=[n|d|s]N ; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N --dup-cutoff=[n|d|s]N ; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--dpi-desync=[<mode0>,]<mode>[,<mode2>] ; try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper --dpi-desync=[<mode0>,]<mode>[,<mode2>] ; try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit hostfakesplit fakeddisorder ipfrag2 udplen tamper
--dpi-desync-fwmark=<int|0xHEX> ; override fwmark for desync packet. default = 0x40000000 (1073741824) --dpi-desync-fwmark=<int|0xHEX> ; override fwmark for desync packet. default = 0x40000000 (1073741824)
--dpi-desync-ttl=<int> ; set ttl for desync packet --dpi-desync-ttl=<int> ; set ttl for desync packet
--dpi-desync-ttl6=<int> ; set ipv6 hop limit for desync packet. by default ttl value is used. --dpi-desync-ttl6=<int> ; set ipv6 hop limit for desync packet. by default ttl value is used.
@@ -194,27 +194,31 @@ nfqws takes the following parameters:
; full list is only used by multisplit and multidisorder ; full list is only used by multisplit and multidisorder
; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise ; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise
--dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; use sequence overlap before first sent original split segment --dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; use sequence overlap before first sent original split segment
--dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; pattern for the fake part of overlap --dpi-desync-split-seqovl-pattern=[+ofs]@<filename>|0xHEX ; pattern for the fake part of overlap
--dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; fake pattern for fakedsplit/fakeddisorder --dpi-desync-fakedsplit-pattern=[+ofs]@<filename>|0xHEX ; fake pattern for fakedsplit/fakeddisorder
--dpi-desync-fakedsplit-mod=mod[,mod] ; mods can be none,altorder=0|1|2|3 + 0|8|16
--dpi-desync-hostfakesplit-midhost=marker+N|marker-N ; additionally split real hostname at specified marker. must be within host..endhost or won't be splitted.
--dpi-desync-hostfakesplit-mod=mod[,mod] ; can be none, host=<hostname>, altorder=0|1
--dpi-desync-ipfrag-pos-tcp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 8. --dpi-desync-ipfrag-pos-tcp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 8.
--dpi-desync-ipfrag-pos-udp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 32. --dpi-desync-ipfrag-pos-udp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 32.
--dpi-desync-ts-increment=<int|0xHEX> ; ts fooling TSval signed increment. default -600000 --dpi-desync-ts-increment=<int|0xHEX> ; ts fooling TSval signed increment. default -600000
--dpi-desync-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment. default -10000 --dpi-desync-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment. default -10000
--dpi-desync-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment. default -66000 --dpi-desync-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment. default -66000
--dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet --dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet
--dpi-desync-fake-http=<filename>|0xHEX ; file containing fake http request --dpi-desync-fake-tcp-mod=mod[,mod] ; comma separated list of tcp fake mods. available mods : none,seq
--dpi-desync-fake-tls=<filename>|0xHEX|! ; file containing fake TLS ClientHello (for https). '!' = standard fake --dpi-desync-fake-http=[+ofs]@<filename>|0xHEX ; file containing fake http request
--dpi-desync-fake-tls=[+ofs]@<filename>|0xHEX|![+offset] ; file containing fake TLS ClientHello (for https). '!' = standard fake
--dpi-desync-fake-tls-mod=mod[,mod] ; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,sni=<sni>,dupsid,padencap --dpi-desync-fake-tls-mod=mod[,mod] ; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,sni=<sni>,dupsid,padencap
--dpi-desync-fake-unknown=<filename>|0xHEX ; file containing unknown protocol fake payload --dpi-desync-fake-unknown=[+ofs]@<filename>|0xHEX ; file containing unknown protocol fake payload
--dpi-desync-fake-syndata=<filename>|0xHEX ; file containing SYN data payload --dpi-desync-fake-syndata=[+ofs]@<filename>|0xHEX ; file containing SYN data payload
--dpi-desync-fake-quic=<filename>|0xHEX ; file containing fake QUIC Initial --dpi-desync-fake-quic=[+ofs]@<filename>|0xHEX ; file containing fake QUIC Initial
--dpi-desync-fake-wireguard=<filename>|0xHEX ; file containing fake wireguard handshake initiation --dpi-desync-fake-wireguard=[+ofs]@<filename>|0xHEX ; file containing fake wireguard handshake initiation
--dpi-desync-fake-dht=<filename>|0xHEX ; file containing fake DHT (d1..e) --dpi-desync-fake-dht=[+ofs]@<filename>|0xHEX ; file containing fake DHT (d1..e)
--dpi-desync-fake-discord=<filename>|0xHEX ; file containing fake Discord voice connection initiation packet (IP Discovery) --dpi-desync-fake-discord=[+ofs]@<filename>|0xHEX ; file containing fake Discord voice connection initiation packet (IP Discovery)
--dpi-desync-fake-stun=<filename>|0xHEX ; file containing fake STUN message --dpi-desync-fake-stun=[+ofs]@<filename>|0xHEX ; file containing fake STUN message
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; file containing unknown udp protocol fake payload --dpi-desync-fake-unknown-udp=[+ofs]@<filename>|0xHEX ; file containing unknown udp protocol fake payload
--dpi-desync-udplen-increment=<int> ; increase or decrease udp packet length by N bytes (default 2). negative values decrease length. --dpi-desync-udplen-increment=<int> ; increase or decrease udp packet length by N bytes (default 2). negative values decrease length.
--dpi-desync-udplen-pattern=<filename>|0xHEX ; udp tail fill pattern --dpi-desync-udplen-pattern=[+ofs]@<filename>|0xHEX ; udp tail fill pattern
--dpi-desync-start=[n|d|s]N ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N --dpi-desync-start=[n|d|s]N ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N
--dpi-desync-cutoff=[n|d|s]N ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N --dpi-desync-cutoff=[n|d|s]N ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--hostlist=<filename> ; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply if not prefixed with `^`, gzip supported, multiple hostlists allowed) --hostlist=<filename> ; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply if not prefixed with `^`, gzip supported, multiple hostlists allowed)
@@ -239,6 +243,10 @@ nfqws takes the following parameters:
--ipset-exclude-ip=<ip_list> ; comma separated fixed subnet list --ipset-exclude-ip=<ip_list> ; comma separated fixed subnet list
``` ```
Many parameters dealing with binary data support loading from hex string prefixed by "0x" or from a file.
Filename can be "as is" or prefixed with "@". If there's "+number" prefix before "@" it means offset of data inside the file.
Offset must be less that data size.
### DPI desync attack ### DPI desync attack
The idea is to take original message, modify it, add additional fake information in such a way that the server OS accepts original data only The idea is to take original message, modify it, add additional fake information in such a way that the server OS accepts original data only
@@ -315,6 +323,9 @@ Resulting order would be : `fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake
### FAKE mods ### FAKE mods
By default all tcp fakes are sent with the same sequence as original packet.
This can be changed by `--dpi-desync-fake-tcp-mod=seq`. In the latter case all fakes are sent as if they would be tcp segments of a single fake.
**nfqws** has built-in TLS fake. It can be customized with `--dpi-desync-fake-tls` option. **nfqws** has built-in TLS fake. It can be customized with `--dpi-desync-fake-tls` option.
Customized fake data can be anything - valid TLS Client Hello or arbitrary data. Customized fake data can be anything - valid TLS Client Hello or arbitrary data.
It's possible to use TLS Client Hello with any fingerprint and any SNI. It's possible to use TLS Client Hello with any fingerprint and any SNI.
@@ -343,8 +354,37 @@ Example : `--dpi-desync-fake-tls=iana_org.bin --dpi-desync-fake-tls-mod=rndsni -
* `multisplit`. split request at specified in `--dpi-desync-split-pos` positions * `multisplit`. split request at specified in `--dpi-desync-split-pos` positions
* `multidisorder`. same as `multisplit` but send in reverse order * `multidisorder`. same as `multisplit` but send in reverse order
* `fakedsplit`. split request into 2 segments adding fakes in the middle of them : fake 1st segment, 1st segment, fake 1st segment, fake 2nd segment, 2nd segment, fake 2nd segment * `fakedsplit`. sequental one position split with fake mix
* `fakeddisorder`. same as `fakedsplit` but with another order : fake 2nd segment, 2nd segment, fake 2nd segment, fake 1st segment, 1st segment, fake 1st segment * `hostfakesplit` (altorder=0). fake host part of the request : before host, random fake host, real host (optionally split this part), random fake host repeat, after host
* `hostfakesplit` (altorder=1). fake host part of the request : before host, random fake host, after host, real host (optionally split this part)
* `fakedsplit`. reverse one position split with fake mix
`--dpi-desync-fakedsplit-mod=altorder=N` specifies number which influence to the presence of individual fakes in `fakedsplit`/`fakeddisorder`.
`fakedsplit` TCP segments of multi-packet messages with split pos :
* `altorder=0`. fake 1st segment, 1st segment, fake 1st segment, fake 2nd segment, 2nd segment, fake 2nd segment
* `altorder=1`. 1st segment, fake 1st segment, fake 2nd segment, 2nd segment, fake 2nd segment
* `altorder=2`. 1st segment, fake 2nd segment, 2nd segment, fake 2nd segment
* `altorder=3`. 1st segment, fake 2nd segment, 2nd segment
`fakeddisorder` TCP segments of multi-packet messages with split pos :
* `altorder=0`. fake 2nd segment, 2nd segment, fake 2nd segment, fake 1st segment, 1st segment, fake 1st segment
* `altorder=1`. 2nd segment, fake 2nd segment, fake 1st segment, 1st segment, fake 1st segment
* `altorder=2`. 2nd segment, fake 1st segment, 1st segment, fake 1st segment
* `altorder=3`. 1st segment, fake 1st segment, 1st segment
`fakedsplit`/`fakeddisorder` TCP segments of multi-packet messages without split pos :
* `altorder=0`. fake, original, fake
* `altorder=8`. original, fake
* `altorder=16`. original
Resulting `altorder=N` is the sum of two `altorder` parts mentioned above.
`--dpi-desync-fakedsplit-pattern` defines data payload of fakes in `fakedsplit`/`fakeddisorder`. By default pattern is simple `0x00`.
Offset of split part + offset of current packet in multi-packet message define offset in the pattern.
Positions are defined by markers. Positions are defined by markers.
@@ -373,6 +413,22 @@ First relative markers are searched. If no suitable found absolute markers are s
For example, `--dpi-desync-split-pos=method+2,midsld,5` means `method+2` for http, `midsld` for TLS and 5 for others. For example, `--dpi-desync-split-pos=method+2,midsld,5` means `method+2` for http, `midsld` for TLS and 5 for others.
`--dpi-desync-fakedsplit-mod=altorder=N` switches `fakedsplit` to alternate segment ordering.
`hostfakesplit` only fakes hostname part of the request making it hard to destinguish between real and fake host names.
It works for tcp protocols with host : TLS and HTTP. Real hostname can be additionally split using `--dpi-desync-hostfakesplit-midhost` marker.
For example, `--dpi-desync-hostfakesplit-midhost=midsld`. Position must be within host range or split won't happen.
Multi-packet queries are supported if hostname part is not already split. If it is fooling is cancelled.
By default fake host names are generated randomly on the fly using `[0-9a-z]` pattern. If host length is >= 7 dot is placed to simulate 3-char TLD and last 3 chars are replaces with a random known 3-char TLD.
It's possible to set fake host template : `--dpi-desync-hostfakesplit-mod=host=<hostname>`.
Template hostname will be expanded to the left to original hostname size with random characters from `[0-9a-z]` pattern : "www.networksolutions.com" -> "h8xmdba4tv7a8.google.com".
If original hostname size is less than template size it will be cut : "habr.com" -> "ogle.com".
If original hostname size is larger than template size by one, dot will be appended to the left : "www.xxx.com" => ".google.com"..
That's why it's a good idea to use short hostnames in template : "ya.ru", "vk.com", "x.com".
`--dpi-desync-hostfakesplit-mod=altorder=1` switches `hostfakesplit` to alternate segment ordering. `altorder=1` sends the whole request with faked host sequentally, then real host segment.
### Sequence numbers overlap ### Sequence numbers overlap
`seqovl` adds to one of the original segment `seqovl` bytes to the beginning and decreases sequence number. For `split` - to the first segment, for `disorder` - to the beginning of the penultimate segment sent (second in the original sequence). `seqovl` adds to one of the original segment `seqovl` bytes to the beginning and decreases sequence number. For `split` - to the first segment, for `disorder` - to the beginning of the penultimate segment sent (second in the original sequence).
+79 -18
View File
@@ -1,4 +1,4 @@
# zapret v71.4 # zapret v72
# ВНИМАНИЕ, остерегайтесь мошенников # ВНИМАНИЕ, остерегайтесь мошенников
@@ -207,7 +207,7 @@ dvtws, собираемый из тех же исходников (см. [док
--methodeol ; добавить перевод строки в unix стиле ('\n') перед методом и убрать пробел из Host: : "GET / ... Host: domain.com" => "\nGET / ... Host:domain.com" --methodeol ; добавить перевод строки в unix стиле ('\n') перед методом и убрать пробел из Host: : "GET / ... Host: domain.com" => "\nGET / ... Host:domain.com"
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase --hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--domcase ; домен после Host: сделать таким : TeSt.cOm --domcase ; домен после Host: сделать таким : TeSt.cOm
--dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper --dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit hostfakesplit fakeddisorder ipfrag2 udplen tamper
--dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000 --dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
--dpi-desync-ttl=<int> ; установить ttl для десинхронизирующих пакетов --dpi-desync-ttl=<int> ; установить ttl для десинхронизирующих пакетов
--dpi-desync-ttl6=<int> ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение --dpi-desync-ttl --dpi-desync-ttl6=<int> ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение --dpi-desync-ttl
@@ -218,25 +218,29 @@ dvtws, собираемый из тех же исходников (см. [док
--dpi-desync-skip-nosni=0|1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI --dpi-desync-skip-nosni=0|1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI
--dpi-desync-split-pos=N|-N|marker+N|marker-N ; список через запятую маркеров для tcp сегментации в режимах split и disorder --dpi-desync-split-pos=N|-N|marker+N|marker-N ; список через запятую маркеров для tcp сегментации в режимах split и disorder
--dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; единичный маркер, определяющий величину перекрытия sequence в режимах split и disorder. для split поддерживается только положительное число. --dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; единичный маркер, определяющий величину перекрытия sequence в режимах split и disorder. для split поддерживается только положительное число.
--dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; чем заполнять фейковую часть overlap --dpi-desync-split-seqovl-pattern=[+ofs]@<filename>|0xHEX ; чем заполнять фейковую часть overlap
--dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; чем заполнять фейки в fakedsplit/fakeddisorder --dpi-desync-fakedsplit-pattern=[+ofs]@<filename>|0xHEX ; чем заполнять фейки в fakedsplit/fakeddisorder
--dpi-desync-fakedsplit-mod=mod[,mod] ; может быть none, altorder=0|1|2|3 + 0|8|16
--dpi-desync-hostfakesplit-midhost=marker+N|marker-N ; маркер дополнительного разреза сегмента с оригинальным хостом. должен попадать в пределы хоста.
--dpi-desync-hostfakesplit-mod=mod[,mod] ; может быть none, host=<hostname>, altorder=0|1
--dpi-desync-ts-increment=<int|0xHEX> ; инкремент TSval для ts. по умолчанию -600000 --dpi-desync-ts-increment=<int|0xHEX> ; инкремент TSval для ts. по умолчанию -600000
--dpi-desync-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000 --dpi-desync-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000
--dpi-desync-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000 --dpi-desync-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
--dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных --dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных
--dpi-desync-fake-http=<filename>|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному www.iana.org --dpi-desync-fake-tcp-mod=mod[,mod] ; список через запятую режимов runtime модификации tcp фейков (любых) : none, seq
--dpi-desync-fake-tls=<filename>|0xHEX|! ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному. '!' = стандартный фейк --dpi-desync-fake-http=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному www.iana.org
--dpi-desync-fake-tls=[+ofs]@<filename>|0xHEX|![+offset] ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному. '!' = стандартный фейк
--dpi-desync-fake-tls-mod=mod[,mod] ; список через запятую режимов runtime модификации фейков : none,rnd,rndsni,sni=<sni>,dupsid,padencap --dpi-desync-fake-tls-mod=mod[,mod] ; список через запятую режимов runtime модификации фейков : none,rnd,rndsni,sni=<sni>,dupsid,padencap
--dpi-desync-fake-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт --dpi-desync-fake-unknown=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata --dpi-desync-fake-syndata=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial --dpi-desync-fake-quic=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
--dpi-desync-fake-wireguard=<filename>|0xHEX ; файл, содержащий фейковый wireguard handshake initiation --dpi-desync-fake-wireguard=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый wireguard handshake initiation
--dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт --dpi-desync-fake-dht=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-discord=<filename>|0xHEX ; файл, содержащий фейковый пейлоад Discord протокола нахождения IP адреса для голосовых чатов для dpi-desync=fake, на замену стандартным нулям 64 байт --dpi-desync-fake-discord=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый пейлоад Discord протокола нахождения IP адреса для голосовых чатов для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-stun=<filename>|0xHEX ; файл, содержащий фейковый пейлоад STUN протокола для dpi-desync=fake, на замену стандартным нулям 64 байт --dpi-desync-fake-stun=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый пейлоад STUN протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт --dpi-desync-fake-unknown-udp=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-udplen-increment=<int> ; на сколько увеличивать длину udp пейлоада в режиме udplen --dpi-desync-udplen-increment=<int> ; на сколько увеличивать длину udp пейлоада в режиме udplen
--dpi-desync-udplen-pattern=<filename>|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули --dpi-desync-udplen-pattern=[+ofs]@<filename>|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули
--dpi-desync-start=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N --dpi-desync-start=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
--dpi-desync-cutoff=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N --dpi-desync-cutoff=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются, если хост не начинается с '^'. --hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются, если хост не начинается с '^'.
@@ -276,6 +280,13 @@ dvtws, собираемый из тех же исходников (см. [док
невозможна. Если вы потом удалите файл, и у процесса не будет прав на создание файла в его директории, лог больше не невозможна. Если вы потом удалите файл, и у процесса не будет прав на создание файла в его директории, лог больше не
будет вестись. Вместо удаления лучше использовать truncate. В шелле это можно сделать через команду ": >filename" будет вестись. Вместо удаления лучше использовать truncate. В шелле это можно сделать через команду ": >filename"
Многие параметры, загружающие двоичные данные из файлов, поддерживают загрузку из hex-строки или из файла.
hex строка начинается с "0x". Имя файла можно писать как есть или использовать префикс "@".
Если перед префиксом "@" указано "+<число>", то это означает смещение полезных данных внутри файла.
Файл может загружаться целиком с нулевой позиции, к нему могут применяться модификации, требующие полного файла (TLS),
но передача пойдет с позиции offset. offset должен быть меньше длины файла. Если к блоку данных применяется мод,
который уменьшает размер данных, и offset окажется не меньше новой длины данных, будет ошибка.
### АТАКА ДЕСИНХРОНИЗАЦИИ DPI ### АТАКА ДЕСИНХРОНИЗАЦИИ DPI
Суть ее в следующем. Берется оригинальный запрос, модифицируется, добавляется поддельная информация (фейки) Суть ее в следующем. Берется оригинальный запрос, модифицируется, добавляется поддельная информация (фейки)
@@ -371,6 +382,10 @@ dvtws, собираемый из тех же исходников (см. [док
### МОДИФИКАЦИЯ ФЕЙКОВ ### МОДИФИКАЦИЯ ФЕЙКОВ
Любые tcp фейки отправляются с исходным sequence по умолчанию, даже если их несколько.
Если задать `--dpi-desync-fake-tcp-mod=seq`, то несколько фейков будут отправлены с увеличением sequence number таким образом,
как будто они являются tcp сегментами одного фейка.
В nfqws зашит базовый вариант фейка для TLS. Его можно переопределить опцией `--dpi-desync-fake-tls`. В nfqws зашит базовый вариант фейка для TLS. Его можно переопределить опцией `--dpi-desync-fake-tls`.
Переопределение фейков дает возможность использовать любые данные в качестве фейка для TLS. Переопределение фейков дает возможность использовать любые данные в качестве фейка для TLS.
Можно использовать фейковый Client Hello с любым фингерпринтом и с любым SNI. Можно использовать фейковый Client Hello с любым фингерпринтом и с любым SNI.
@@ -403,17 +418,61 @@ dvtws, собираемый из тех же исходников (см. [док
* `multisplit`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях. * `multisplit`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях.
* `multidisorder`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях и отправляем в обратном порядке. * `multidisorder`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях и отправляем в обратном порядке.
* `fakedsplit`. нарезаем запрос на 2 части, обрамляя каждую часть фейками : фейк 1-й части, 1 часть, фейк 1-й части, фейк 2-й части, 2 часть, фейк 2-й части * `fakedsplit`. различные варианты замешивания фейков и оригиналов в прямом порядке
* `fakeddisorder`. различные варианты замешивания фейков и оригиналов в обратном порядке
* `hostfakesplit` (altorder=0). фейкование части запроса с хостом : оригинал до хоста, фейк хоста, оригинал хоста (+ опционально нарезка маркером midhost), фейк хоста, оригинал после хоста
* `hostfakesplit` (altorder=1). фейкование части запроса с хостом : оригинал до хоста, фейк хоста, оригинал после хоста, оригинал хоста (+опционально нарезка маркером midhost)
* `fakeddisorder`. аналогично `fakedsplit`, только в обратном порядке : фейк 2-й части, 2 часть, фейк 2-й части, фейк 1-й части, 1 часть, фейк 1 части. * `fakeddisorder`. аналогично `fakedsplit`, только в обратном порядке : фейк 2-й части, 2 часть, фейк 2-й части, фейк 1-й части, 1 часть, фейк 1 части.
Для `fakedsplit` и `fakeddisorder` предусмотрены вариации порядка следования сегментов.
Параметр `--dpi-desync-fakedsplit-mod=altorder=N` задает число, влияющее на наличие отдельных фейков :
Режимы altorder для `fakedsplit` для части многопакетного запроса, где есть сплит-позиция :
* `altorder=0`. фейк 1-й части, 1 часть, фейк 1-й части, фейк 2-й части, 2 часть, фейк 2-й части
* `altorder=1`. 1 часть, фейк 1-й части, фейк 2-й части, 2 часть, фейк 2-й части
* `altorder=2`. 1 часть, фейк 2-й части, 2 часть, фейк 2-й части
* `altorder=3`. 1 часть, фейк 2-й части, 2 часть
Режимы altorder для `fakeddisorder` для части многопакетного запроса, где есть сплит-позиция :
* `altorder=0`. фейк 2-й части, 2 часть, фейк 2-й части, фейк 1-й части, 1 часть, фейк 1-й части
* `altorder=1`. 2 часть, фейк 2-й части, фейк 1-й части, 1 часть, фейк 1-й части
* `altorder=2`. 2 часть, фейк 1-й части, 1 часть, фейк 1-й части
* `altorder=3`. 2 часть, фейк 1-й части, 1 часть
Режимы altorder для `fakedsplit` и `fakeddisorder` для части многопакетного запроса, где нет сплит-позиции :
* `altorder=0`. фейк, оригинал, фейк
* `altorder=8`. оригинал, фейк
* `altorder=16`. оригинал
Итоговое число `altorder=N` вычисляется как сумма чисел из этих двух групп. По умолчанию `altorder=0`.
Содержимое фейков в `fakedsplit`/`fakeddisorder` определяется параметром `--dpi-desync-fakedsplit-pattern` (по умолчанию 0x00). Содержимое фейков в `fakedsplit`/`fakeddisorder` определяется параметром `--dpi-desync-fakedsplit-pattern` (по умолчанию 0x00).
Данные фейков берутся из паттерна со смещением, соответствующим смещению отсылаемых частей. Данные фейков берутся из паттерна со смещением, соответствующим смещению отсылаемых частей, учитывая смещения пакетов в многопакетных запросах.
Размеры фейков соответствуют длинам отсылаемых частей. Размеры фейков соответствуют длинам отсылаемых частей.
Цель этих режимов - максимально усложнить выявление оригинальных данных среди фейков. Цель этих режимов - максимально усложнить выявление оригинальных данных среди фейков.
Использование `fakedsplit` или `fakeddisorder` на TLS kyber с md5sig fooling может привести к ошибкам "message too long", если позиция сплита мала, Использование `fakedsplit` или `fakeddisorder` на TLS kyber с md5sig fooling может привести к ошибкам "message too long", если позиция сплита мала,
поскольку будет превышение MTU из-за md5 tcp option. поскольку будет превышение MTU из-за md5 tcp option.
Режим 'hostfakesplit' имеет задачу минимального вмешательства фейком - как раз по той части запроса, на основании которой DPI принимает решение о блокировке. Конкретно - имени хоста.
По умолчанию фейк хоста генерируется каждый раз случайно из набора `[a-z0-9]`. При длине более 7 символов за 3 символа до конца ставится точка, имитируя TLD, а последние 3 символа заполняются одним из нескольких известных TLD.
Можно переопределить шаблон генерации с помощью `--dpi-desync-hostfakesplit-mod=host=<hostname>`. В последнем случае справа всегда будет указанный hostname.
Слева он будет дополнен до размера оригинального хоста как поддомен со случайными символами. Пример : "www.networksolutions.com" -> "h8xmdba4tv7a8.google.com".
Если размер оригинального хоста меньше шаблона, шаблон будет порезан : "habr.com" -> "ogle.com".
Если размер оригинального хоста больше шаблона на 1, получится инвалидный пустой поддомен : "www.xxx.com" => ".google.com".
Поэтому стоит использовать максимально короткие хосты из разрешенных : "ya.ru", "vk.com".
`--dpi-desync-hostfakesplit-mod=altorder=1` позволяет сменить порядок следования частей на альтернативный вариант.
`altorder=1` шлет фрагменты в таком порядке, чтобы при последовательной сборке сегментов на DPI он получил полностью собранный оригинал запроса с подмененным хостом.
Реальный хост идет отдельным сегментом уже после. То есть в этом варианте применяется разновидность disorder. Сервер принимает фрагменты с нарушенным порядком sequence.
Опционально можно разрезать оригинальный фейк. Например, `--dpi-desync-hostfakesplit-midhost=midsld`. Позиция нарезки должна попадать внутрь хоста.
Многопакетные запросы поддерживаются только, если исходная нарезка пакетов не включает позиции имени хоста. В последнем случае дурение отменяется.
Вариант `fakedsplit` имеет несколько альтернативных порядков нарезки - от 0 до 3. Режим задается в параметре `--dpi-desync-fakedsplit-mod=altorder=N`.
Каждый следующий altorder убирает часть фейков.
Для определения позиций нарезки используются маркеры. Для определения позиций нарезки используются маркеры.
* **Абсолютный положительный маркер** - числовое смещение внутри пакета или группы пакетов от начала. * **Абсолютный положительный маркер** - числовое смещение внутри пакета или группы пакетов от начала.
@@ -783,7 +842,7 @@ L7 протокол становится известен обычно посл
> [!IMPORTANT] > [!IMPORTANT]
> user-mode реализация ipset создавалась не как удобная замена *nix версии, реализованной в ядре. > user-mode реализация ipset создавалась не как удобная замена *nix версии, реализованной в ядре.
> Вариант в ядре работает гораздо эффективнее. Это создавалось для систем без подд3ержки ipset в ядре. > Вариант в ядре работает гораздо эффективнее. Это создавалось для систем без поддержки ipset в ядре.
> Конкретно - Windows и ядра Linux, собранные без nftables и ipset модулей ядра. Например, в android нет ipset. > Конкретно - Windows и ядра Linux, собранные без nftables и ipset модулей ядра. Например, в android нет ipset.
### ФИЛЬТРАЦИЯ ПО WIFI ### ФИЛЬТРАЦИЯ ПО WIFI
@@ -1744,6 +1803,8 @@ SECURE_DNS=0|1 - принудительно выключить или включ
DOH_SERVERS - список URL DoH через пробел для автоматического выбора работающего сервера DOH_SERVERS - список URL DoH через пробел для автоматического выбора работающего сервера
DOH_SERVER - конкретный DoH URL, отказ от поиска DOH_SERVER - конкретный DoH URL, отказ от поиска
UNBLOCKED_DOM - незаблокированный домен, который используется для тестов IP block UNBLOCKED_DOM - незаблокированный домен, который используется для тестов IP block
SIMULATE=1 - включить режим симуляции для отладки логики скрипта. отключаются реальные запросы через curl, заменяются рандомным результатом.
SIM_SUCCESS_RATE=<percent> - вероятность успеха симуляции в процентах
``` ```
Пример запуска с переменными:\ Пример запуска с переменными:\
+15 -1
View File
@@ -47,7 +47,9 @@ Task of `iptables` is done inside `winws` through `windivert` filters. `Windiver
--wf-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed. --wf-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
--wf-tcp=[~]port1[-port2] ; TCP port filter. ~ means negation. multiple comma separated values allowed. --wf-tcp=[~]port1[-port2] ; TCP port filter. ~ means negation. multiple comma separated values allowed.
--wf-udp=[~]port1[-port2] ; UDP port filter. ~ means negation. multiple comma separated values allowed. --wf-udp=[~]port1[-port2] ; UDP port filter. ~ means negation. multiple comma separated values allowed.
--wf-raw=<filter>|@<filename> ; raw windivert filter string or filename --wf-raw-part=<filter>|@<filename> ; partial raw windivert filter string or filename
--wf-filter-lan=0|1 ; add excluding filter for non-global IP (default : 1)
--wf-raw=<filter>|@<filename> ; full raw windivert filter string or filename. replaces --wf-tcp,--wf-udp,--wf-raw-part
--wf-save=<filename> ; save windivert filter string to a file and exit --wf-save=<filename> ; save windivert filter string to a file and exit
--ssid-filter=ssid1[,ssid2,ssid3,...] ; enable winws only if any of specified wifi SSIDs connected --ssid-filter=ssid1[,ssid2,ssid3,...] ; enable winws only if any of specified wifi SSIDs connected
--nlm-filter=net1[,net2,net3,...] ; enable winws only if any of specified NLM network is connected. names and GUIDs are accepted. --nlm-filter=net1[,net2,net3,...] ; enable winws only if any of specified NLM network is connected. names and GUIDs are accepted.
@@ -60,6 +62,12 @@ Interface indexes can be discovered using this command : `netsh int ip show int`
If you can't find index this way use `winws --debug` to see index there. Subinterface index is almost always 0 and you can omit it. If you can't find index this way use `winws --debug` to see index there. Subinterface index is almost always 0 and you can omit it.
`--wf-raw-part` specifies partial windivert filter. Multiple filter parts are supported. They can also be combined with `--wf-tcp`,`--wf-udp`.
`--wf-raw` specifies full windivert filter that replaces `--wf-tcp`,`--wf-udp`,`--wf-raw-part`.
Kernel filtering with windivert language is much more effective than passing massive amount of traffic to winws. Use it if possible to save CPU resources.
Multiple `winws` processes are allowed. However, it's discouraged to intersect their filters. Multiple `winws` processes are allowed. However, it's discouraged to intersect their filters.
`--ssid-filter` allows to enable `winws` only if specified wifi networks are connected. `winws` auto detects SSID appearance and disappearance. `--ssid-filter` allows to enable `winws` only if specified wifi networks are connected. `winws` auto detects SSID appearance and disappearance.
@@ -165,3 +173,9 @@ clone the code in all cmd files to support multiple tasks `winws1,winws2,winws3,
Tasks can also be controlled from GUI `taskschd.msc`. Tasks can also be controlled from GUI `taskschd.msc`.
Also you can use windows services the same way with `service_*.cmd`. Also you can use windows services the same way with `service_*.cmd`.
### Windows Server
winws is linked against wlanapi.dll which is absent by default.
To solve this problem run power shell as administrator and execute command `Install-WindowsFeature -Name Wireless-Networking`.
Then reboot the system.
+22 -6
View File
@@ -44,7 +44,7 @@ tpws в режиме socks можно запускать под более-ме
Это вариант пакетного фильтра nfqws для Windows, построенный на базе windivert. Это вариант пакетного фильтра nfqws для Windows, построенный на базе windivert.
Все функции работоспособны, однако функционал ipset в ядре отсутствует. Он реализован в user mode. Фильтры по большому количеству IP адресов невозможны. Все функции работоспособны, однако функционал ipset в ядре отсутствует. Он реализован в user mode. Фильтры по большому количеству IP адресов невозможны.
Работа с проходящим трафиком, например в случае "расшаривания" соединения, не проверялась и не гарантируется. Работа с проходящим трафиком, например в случае "расшаривания" соединения, невозможна.
Для работы с windivert требуются права администратора. Для работы с windivert требуются права администратора.
Специфические для unix параметры, такие как `--uid`, `--user` и тд, исключены. Все остальные параметры аналогичны nfqws и dvtws. Специфические для unix параметры, такие как `--uid`, `--user` и тд, исключены. Все остальные параметры аналогичны nfqws и dvtws.
@@ -67,7 +67,9 @@ secure boot могут быть проблемы из-за подписи дра
--wf-l3=ipv4|ipv6 ; фильтр L3 протоколов. по умолчанию включены ipv4 и ipv6. --wf-l3=ipv4|ipv6 ; фильтр L3 протоколов. по умолчанию включены ipv4 и ipv6.
--wf-tcp=[~]port1[-port2] ; фильтр портов для tcp. ~ означает отрицание --wf-tcp=[~]port1[-port2] ; фильтр портов для tcp. ~ означает отрицание
--wf-udp=[~]port1[-port2] ; фильтр портов для udp. ~ означает отрицание --wf-udp=[~]port1[-port2] ; фильтр портов для udp. ~ означает отрицание
--wf-raw=<filter>|@<filename> ; задать напрямую фильтр windivert из параметра или из файла. имени файла предшествует символ @. --wf-raw-part=<filter>|@<filename> ; частичный windivert фильтр из параметра или из файла. имени файла предшествует символ @. может быть множество частей. сочетается с --wf-tcp,--wf-udp.
--wf-filter-lan=0|1 ; отфильтровывать адреса назначения, не являющиеся глобальными inet адресами ipv4 или ipv6. по умолчанию - 1.
--wf-raw=<filter>|@<filename> ; полный windivert фильтр из параметра или из файла. имени файла предшествует символ @. замещает --wf-raw-part,--wf-tcp,--wf-udp.
--wf-save=<filename> ; сохранить сконструированный фильтр windivert в файл для последующей правки вручную --wf-save=<filename> ; сохранить сконструированный фильтр windivert в файл для последующей правки вручную
--ssid-filter=ssid1[,ssid2,ssid3,...] ; включать winws только когда подключена любая из указанных wifi сетей --ssid-filter=ssid1[,ssid2,ssid3,...] ; включать winws только когда подключена любая из указанных wifi сетей
--nlm-filter=net1[,net2,net3,...] ; включать winws только когда подключена любая из указанных сетей NLM --nlm-filter=net1[,net2,net3,...] ; включать winws только когда подключена любая из указанных сетей NLM
@@ -80,11 +82,19 @@ secure boot могут быть проблемы из-за подписи дра
Некоторых типы соединений там не увидеть. В этом случае запускайте **winws** с параметром `--debug` и смотрите IfIdx там. Некоторых типы соединений там не увидеть. В этом случае запускайте **winws** с параметром `--debug` и смотрите IfIdx там.
SubInterface используется windivert, но практически всегда **0**, его можно не указывать. Вероятно, он нужен в редких случаях. SubInterface используется windivert, но практически всегда **0**, его можно не указывать. Вероятно, он нужен в редких случаях.
Конструктор фильтров автоматически включает входящие tcp пакеты с tcp synack и tcp rst для корректной работы функций Конструктор стандартных фильтров автоматически включает входящие tcp пакеты с tcp synack и tcp rst для корректной работы функций
autottl и autohostlist. При включении autohostlist так же перенаправляются пакеты данных с http redirect с кодами 302 и 307. autottl и autohostlist. При включении autohostlist так же перенаправляются пакеты данных с http redirect с кодами 302 и 307.
Всегда добавляется фильтр на исключение не-интернет адресов ipv4 и ipv6. Если не указаное иное, добавляется фильтр на исключение не-интернет адресов ipv4 и ipv6.
Для сложных нестандартных сценариев могут потребоваться свои фильтры. Логично будет начать со стандартного шаблона, Для сложных нестандартных сценариев могут потребоваться свои фильтры. Полный фильтр --wf-raw замещает все остальное.
сохраненного через `--wf-save`. Нужно править файл и подсовывать его в параметре `--wf-raw`. Максимальный размер фильтра - **16 Kb**. Частичные фильтры `--wf-raw-part` совместимы друг с другом и `--wf-tcp` и `--wf-udp`. Они позволяют исключить написание
громоздких полных фильтров, сосредоточившись лишь на добавлении какого-то особенного пейлоада.
`--wf-save` позволяет записать итоговый windivert фильтр в файл. Максимальный размер фильтра - **16 Kb**.
Фильтрация windivert производится в ядре. Это несравнимо легче по ресурсам, чем перенаправлять пакеты в пространство user mode,
чтобы winws принимал решение. Поэтому пользуйтесь по максимуму возможностями windivert.
Например, если вам нужно дурить wireguard на все порты, вам придется перенаправить все порты на winws. Или же написать windivert фильтр, который отсечет wireguard по содержимому пакета.
Разница в нагрузке на процессор колоссальна. В первом случае - до 100% одного ядра cpu в зависимости от обьема исходящего udp трафика (привет, торрент и uTP), во втором - близко к 0.
Кроме нагрузки на процессор еще можете порезать себе скорость, тк одно ядро не будет справляться с обработкой вашего гигабитного интернета. А на старых ноутах еще и получите самолетный вой системы охлаждения, приводящий к ее износу.
Можно запускать несколько процессов **winws** с разными стратегиями. Однако, не следует делать пересекающиеся фильтры. Можно запускать несколько процессов **winws** с разными стратегиями. Однако, не следует делать пересекающиеся фильтры.
@@ -257,3 +267,9 @@ _zapret-winws_ - это отдельный комплект для повсед
Все батники требуется запускать от имени администратора. Все батники требуется запускать от имени администратора.
Управлять задачами можно так же из графической программы управления планировщиком `taskschd.msc` Управлять задачами можно так же из графической программы управления планировщиком `taskschd.msc`
## Особенности Windows Server
winws слинкован с wlanapi.dll, который по умолчанию не установлен в windows server.
Для решения этой проблемы запустите power shell под администратором и выполните команду `Install-WindowsFeature -Name Wireless-Networking`.
После чего перезагрузите систему.
+2 -1
View File
@@ -1,4 +1,5 @@
# this custom script runs desync to DHT packets with udp payload length 101..399 , without ipset/hostlist filtering # this custom script runs desync to DHT packets with udp payload length 101..399 , without ipset/hostlist filtering
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
# can override in config : # can override in config :
NFQWS_OPT_DESYNC_DHT="${NFQWS_OPT_DESYNC_DHT:---dpi-desync=tamper}" NFQWS_OPT_DESYNC_DHT="${NFQWS_OPT_DESYNC_DHT:---dpi-desync=tamper}"
@@ -32,6 +33,6 @@ zapret_custom_firewall_nft()
local f local f
local first_packet_only="$nft_connbytes 1" local first_packet_only="$nft_connbytes 1"
f="meta length 109-407 meta l4proto udp @th,64,16 0x6431" f="meta length 109-407 meta l4proto udp @ih,0,16 0x6431"
nft_fw_nfqws_post "$f $first_packet_only" "$f $first_packet_only" $QNUM_DHT4ALL nft_fw_nfqws_post "$f $first_packet_only" "$f $first_packet_only" $QNUM_DHT4ALL
} }
@@ -1,7 +1,8 @@
# this custom script runs desync to all discord media packets # this custom script runs desync to all discord media packets
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
# can override in config : # can override in config :
NFQWS_OPT_DESYNC_DISCORD_MEDIA="${NFQWS_OPT_DESYNC_DISCORD_MEDIA:---dpi-desync=fake}" NFQWS_OPT_DESYNC_DISCORD_MEDIA="${NFQWS_OPT_DESYNC_DISCORD_MEDIA:---dpi-desync=fake --dpi-desync-repeats=2}"
DISCORD_MEDIA_PORT_RANGE="${DISCORD_MEDIA_PORT_RANGE:-50000-50099}" DISCORD_MEDIA_PORT_RANGE="${DISCORD_MEDIA_PORT_RANGE:-50000-50099}"
alloc_dnum DNUM_DISCORD_MEDIA alloc_dnum DNUM_DISCORD_MEDIA
+2 -1
View File
@@ -1,7 +1,8 @@
# this custom script runs desync to all stun packets # this custom script runs desync to all stun packets
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
# can override in config : # can override in config :
NFQWS_OPT_DESYNC_STUN="${NFQWS_OPT_DESYNC_STUN:---dpi-desync=fake}" NFQWS_OPT_DESYNC_STUN="${NFQWS_OPT_DESYNC_STUN:---dpi-desync=fake --dpi-desync-repeats=2}"
alloc_dnum DNUM_STUN4ALL alloc_dnum DNUM_STUN4ALL
alloc_qnum QNUM_STUN4ALL alloc_qnum QNUM_STUN4ALL
+2 -1
View File
@@ -1,8 +1,9 @@
# this custom script runs desync to all wireguard handshake initiation packets # this custom script runs desync to all wireguard handshake initiation packets
# NOTE: this works for original wireguard and may not work for 3rd party implementations such as xray # NOTE: this works for original wireguard and may not work for 3rd party implementations such as xray
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
# can override in config : # can override in config :
NFQWS_OPT_DESYNC_WG="${NFQWS_OPT_DESYNC_WG:---dpi-desync=fake}" NFQWS_OPT_DESYNC_WG="${NFQWS_OPT_DESYNC_WG:---dpi-desync=fake --dpi-desync-repeats=2}"
alloc_dnum DNUM_WG4ALL alloc_dnum DNUM_WG4ALL
alloc_qnum QNUM_WG4ALL alloc_qnum QNUM_WG4ALL
+3 -3
View File
@@ -1,14 +1,14 @@
Цель этих фильтров - отсекать полезную нагрузку в режиме ядра, не насилуя процессор перенаправлением целого потока на winws. Цель этих фильтров - отсекать полезную нагрузку в режиме ядра, не насилуя процессор перенаправлением целого потока на winws.
Задействуются через `winws --wf-raw=@filename`. Задействуются через `winws --wf-raw-part=@filename`. Может быть несколько частичных фильтров. Они могут сочетаться с --wf-tcp и --wf-udp.
Однако, язык фильтров windivert не содержит операций с битовыми полями, сдвигов и побитовой логики. Однако, язык фильтров windivert не содержит операций с битовыми полями, сдвигов и побитовой логики.
Поэтому фильтры получились более слабыми, способными передавать неправильную нагрузку. Поэтому фильтры получились более слабыми, способными передавать неправильную нагрузку.
Дофильтрация производится силами winws. Дофильтрация производится силами winws.
Описание языка фильтров : https://reqrypt.org/windivert-doc.html#filter_language Описание языка фильтров : https://reqrypt.org/windivert-doc.html#filter_language
Пример инстанса для пробития медиапотоков в discord : `winws --wf-raw=@windivert.discord_media+stun.txt --filter-l7=stun,discord --dpi-desync=fake` Пример инстанса для пробития медиапотоков в discord : `winws --wf-raw-part=@windivert_part.discord_media.txt --wf-raw-part=@windivert_part.stun.txt --filter-l7=stun,discord --dpi-desync=fake`
These filters are invoked using `winws --wf-raw=@filename`. These filters are invoked using `winws --wf-raw-part=@filename`. Multiple filter parts are supported. They can be combined with --wf-tcp and --wf-udp.
Filters are kernel mode and save great amount of CPU. Filters are kernel mode and save great amount of CPU.
However windivert cannot filter by bit fields, lacks shift and bitwise logic operations. However windivert cannot filter by bit fields, lacks shift and bitwise logic operations.
Filters are relaxed and can pass wrong payloads. Finer filtering is done by winws. Filters are relaxed and can pass wrong payloads. Finer filtering is done by winws.
@@ -1,29 +0,0 @@
!impostor and !loopback and
(outbound and
((ip and
udp.DstPort>=50000 and udp.DstPort<=50099 and
udp.PayloadLength=74 and
udp.Payload32[0]=0x00010046 and
udp.Payload32[2]=0 and
udp.Payload32[3]=0 and
udp.Payload32[4]=0 and
udp.Payload32[5]=0 and
udp.Payload32[6]=0 and
udp.Payload32[7]=0 and
udp.Payload32[8]=0 and
udp.Payload32[9]=0 and
udp.Payload32[10]=0 and
udp.Payload32[11]=0 and
udp.Payload32[12]=0 and
udp.Payload32[13]=0 and
udp.Payload32[14]=0 and
udp.Payload32[15]=0 and
udp.Payload32[16]=0 and
udp.Payload32[17]=0)
or
(udp.PayloadLength>=20 and
udp.Payload32[1]=0x2112A442 and udp.Payload[0]<0x40)) and
( ((ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and (ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and (ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and (ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and (ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255)) or
((ipv6.DstAddr > ::1) and (ipv6.DstAddr < 2001::0 or ipv6.DstAddr >= 2001:1::0) and (ipv6.DstAddr < fc00::0 or ipv6.DstAddr >= fe00::0) and (ipv6.DstAddr < fe80::0 or ipv6.DstAddr >= fec0::0) and (ipv6.DstAddr < ff00::0 or ipv6.DstAddr >= ffff::0))
)
)
@@ -1,8 +0,0 @@
!impostor and !loopback and
(outbound and
udp.PayloadLength>=20 and
udp.Payload32[1]=0x2112A442 and udp.Payload[0]<0x40 and
( ((ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and (ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and (ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and (ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and (ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255)) or
((ipv6.DstAddr > ::1) and (ipv6.DstAddr < 2001::0 or ipv6.DstAddr >= 2001:1::0) and (ipv6.DstAddr < fc00::0 or ipv6.DstAddr >= fe00::0) and (ipv6.DstAddr < fe80::0 or ipv6.DstAddr >= fec0::0) and (ipv6.DstAddr < ff00::0 or ipv6.DstAddr >= ffff::0))
)
)
@@ -1,8 +0,0 @@
!impostor and !loopback and
(outbound and
udp.PayloadLength=148 and
udp.Payload[0]=0x01 and
( ((ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and (ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and (ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and (ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and (ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255)) or
((ipv6.DstAddr > ::1) and (ipv6.DstAddr < 2001::0 or ipv6.DstAddr >= 2001:1::0) and (ipv6.DstAddr < fc00::0 or ipv6.DstAddr >= fe00::0) and (ipv6.DstAddr < fe80::0 or ipv6.DstAddr >= fec0::0) and (ipv6.DstAddr < ff00::0 or ipv6.DstAddr >= ffff::0))
)
)
@@ -1,5 +1,4 @@
!impostor and !loopback and outbound and ip and
(outbound and
udp.DstPort>=50000 and udp.DstPort<=50099 and udp.DstPort>=50000 and udp.DstPort<=50099 and
udp.PayloadLength=74 and udp.PayloadLength=74 and
udp.Payload32[0]=0x00010046 and udp.Payload32[0]=0x00010046 and
@@ -18,6 +17,4 @@
udp.Payload32[14]=0 and udp.Payload32[14]=0 and
udp.Payload32[15]=0 and udp.Payload32[15]=0 and
udp.Payload32[16]=0 and udp.Payload32[16]=0 and
udp.Payload32[17]=0 and udp.Payload32[17]=0
(ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and (ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and (ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and (ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and (ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255)
)
@@ -0,0 +1,3 @@
outbound and
udp.PayloadLength>=20 and
udp.Payload32[1]=0x2112A442 and udp.Payload[0]<0x40
@@ -0,0 +1,3 @@
outbound and
udp.PayloadLength=148 and
udp.Payload[0]=0x01
+2
View File
@@ -83,6 +83,8 @@ typedef struct
bool b_cutoff; // mark for deletion bool b_cutoff; // mark for deletion
bool b_wssize_cutoff, b_desync_cutoff, b_dup_cutoff, b_orig_mod_cutoff; bool b_wssize_cutoff, b_desync_cutoff, b_dup_cutoff, b_orig_mod_cutoff;
uint16_t ip_id;
t_l7proto l7proto; t_l7proto l7proto;
bool l7proto_discovered; bool l7proto_discovered;
char *hostname; char *hostname;
+2 -2
View File
@@ -420,7 +420,7 @@ bool prepare_udp_segment4(
memcpy(payload,data,len); memcpy(payload,data,len);
if (padding) if (padding)
fill_pattern(payload+len,padlen,padding,padding_size); fill_pattern(payload+len,padlen,padding,padding_size,0);
else else
memset(payload+len,0,padlen); memset(payload+len,0,padlen);
udp4_fix_checksum(udp,ip_payload_len,&ip->ip_src,&ip->ip_dst); udp4_fix_checksum(udp,ip_payload_len,&ip->ip_src,&ip->ip_dst);
@@ -509,7 +509,7 @@ bool prepare_udp_segment6(
memcpy(payload,data,len); memcpy(payload,data,len);
if (padding) if (padding)
fill_pattern(payload+len,padlen,padding,padding_size); fill_pattern(payload+len,padlen,padding,padding_size,0);
else else
memset(payload+len,0,padlen); memset(payload+len,0,padlen);
udp6_fix_checksum(udp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst); udp6_fix_checksum(udp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst);
+368 -74
View File
@@ -170,18 +170,20 @@ bool desync_only_first_stage(enum dpi_desync_mode mode)
{ {
return false; return false;
} }
bool desync_valid_second_stage(enum dpi_desync_mode mode)
{
return mode==DESYNC_NONE || mode==DESYNC_FAKEDDISORDER || mode==DESYNC_FAKEDSPLIT || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2 || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER;
}
bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode) bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode)
{ {
return mode==DESYNC_NONE || mode==DESYNC_FAKEDDISORDER || mode==DESYNC_FAKEDSPLIT || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2; return
mode == DESYNC_NONE || mode == DESYNC_FAKEDDISORDER || mode == DESYNC_FAKEDSPLIT || mode == DESYNC_MULTISPLIT || mode == DESYNC_MULTIDISORDER || mode == DESYNC_HOSTFAKESPLIT ||
mode == DESYNC_IPFRAG2;
} }
bool desync_valid_second_stage_udp(enum dpi_desync_mode mode) bool desync_valid_second_stage_udp(enum dpi_desync_mode mode)
{ {
return mode == DESYNC_NONE || mode == DESYNC_UDPLEN || mode == DESYNC_TAMPER || mode == DESYNC_IPFRAG2; return mode == DESYNC_NONE || mode == DESYNC_UDPLEN || mode == DESYNC_TAMPER || mode == DESYNC_IPFRAG2;
} }
bool desync_valid_second_stage(enum dpi_desync_mode mode)
{
return desync_valid_second_stage_tcp(mode) || desync_valid_second_stage_udp(mode);
}
enum dpi_desync_mode desync_mode_from_string(const char *s) enum dpi_desync_mode desync_mode_from_string(const char *s)
{ {
if (!s) if (!s)
@@ -206,6 +208,8 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
return DESYNC_MULTISPLIT; return DESYNC_MULTISPLIT;
else if (!strcmp(s, "multidisorder") || !strcmp(s, "disorder2")) else if (!strcmp(s, "multidisorder") || !strcmp(s, "disorder2"))
return DESYNC_MULTIDISORDER; return DESYNC_MULTIDISORDER;
else if (!strcmp(s, "hostfakesplit"))
return DESYNC_HOSTFAKESPLIT;
else if (!strcmp(s, "ipfrag2")) else if (!strcmp(s, "ipfrag2"))
return DESYNC_IPFRAG2; return DESYNC_IPFRAG2;
else if (!strcmp(s, "hopbyhop")) else if (!strcmp(s, "hopbyhop"))
@@ -831,20 +835,25 @@ static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr
} }
#ifdef BSD
// BSD pass to divert socket ip_id=0 and does not auto set it if sent via divert socket
static uint16_t IP4_IP_ID_FIX(const struct ip *ip) static uint16_t IP4_IP_ID_FIX(const struct ip *ip)
{ {
return ip ? ip->ip_id ? ip->ip_id : (uint16_t)random() : 0; return ip ? ip->ip_id ? ip->ip_id : (uint16_t)random() : 0;
} }
#define IP4_IP_ID_NEXT(ip_id) net16_add(ip_id,+1) static uint16_t IP4_IP_ID_ADD(uint16_t ip_id, uint16_t inc)
#define IP4_IP_ID_PREV(ip_id) net16_add(ip_id,-1) {
#else if (ip_id)
// in linux kernel sets increasing ip_id if it's zero {
#define IP4_IP_ID_FIX(x) 0 ip_id += net16_add(ip_id, inc);
#define IP4_IP_ID_NEXT(ip_id) ip_id if (!ip_id) ip_id = net16_add(ip_id, ((int16_t)inc) < 0 ? -1 : 1); // do not allow zero
#define IP4_IP_ID_PREV(ip_id) ip_id }
#endif return ip_id;
}
#define IP4_IP_ID_ADD(ip_id,inc) (ip_id ? net16_add(ip_id,inc) : 0)
#define IP4_IP_ID_NEXT(ip_id) IP4_IP_ID_ADD(ip_id,+1)
#define IP4_IP_ID_PREV(ip_id) IP4_IP_ID_ADD(ip_id,-1)
//#define IP4_IP_ID_FIX(x) 0
//#define IP4_IP_ID_NEXT(ip_id) ip_id
//#define IP4_IP_ID_PREV(ip_id) ip_id
// fake_mod buffer must at least sizeof(desync_profile->fake_tls) // fake_mod buffer must at least sizeof(desync_profile->fake_tls)
@@ -887,7 +896,7 @@ static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache
if (payload_len < 44) if (payload_len < 44)
DLOG("fake[%d] cannot apply dupsid tls mod. data payload is too short.\n", fake_n); DLOG("fake[%d] cannot apply dupsid tls mod. data payload is too short.\n", fake_n);
else if (fake_data[43] != payload[43]) else if (fake_data[43] != payload[43])
DLOG("fake[%d] cannot apply dupsid tls mod. fake and orig session id length mismatch.\n",fake_n); DLOG("fake[%d] cannot apply dupsid tls mod. fake and orig session id length mismatch : %u!=%u.\n", fake_n, fake_data[43], payload[43]);
else if (payload_len < (44 + payload[43])) else if (payload_len < (44 + payload[43]))
DLOG("fake[%d] cannot apply dupsid tls mod. data payload is not valid.\n", fake_n); DLOG("fake[%d] cannot apply dupsid tls mod. data payload is not valid.\n", fake_n);
else else
@@ -1107,8 +1116,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
bool bFake = false; bool bFake = false;
struct sockaddr_storage src, dst; struct sockaddr_storage src, dst;
uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN+100], pkt2[DPI_DESYNC_MAX_FAKE_LEN+100]; uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN + 100], pkt2[DPI_DESYNC_MAX_FAKE_LEN + 100], pkt3[DPI_DESYNC_MAX_FAKE_LEN + 100];
size_t pkt1_len, pkt2_len; size_t pkt1_len, pkt2_len, pkt3_len;
uint8_t ttl_orig, ttl_fake, flags_orig, scale_factor; uint8_t ttl_orig, ttl_fake, flags_orig, scale_factor;
uint32_t *timestamps; uint32_t *timestamps;
bool bSack, DF; bool bSack, DF;
@@ -1429,7 +1438,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
size_t multisplit_pos[MAX_SPLITS]; size_t multisplit_pos[MAX_SPLITS];
int multisplit_count; int multisplit_count;
int i; int i;
uint16_t ip_id; uint16_t ip_id = IP4_IP_ID_FIX(dis->ip);
bool bHaveHost = false, bHostIsIp = false; bool bHaveHost = false, bHostIsIp = false;
t_l7proto l7proto = UNKNOWN; t_l7proto l7proto = UNKNOWN;
@@ -1813,6 +1823,51 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
else else
DLOG("regular split pos is outside of this packet\n"); DLOG("regular split pos is outside of this packet\n");
} }
else if (dp->desync_mode == DESYNC_HOSTFAKESPLIT || dp->desync_mode2 == DESYNC_HOSTFAKESPLIT)
{
struct proto_pos splits[2] = {
{.marker = PM_HOST,.pos = 0},
{.marker = PM_HOST_END,.pos = 0}
};
split_pos = 0;
ResolveMultiPos(rdata_payload, rlen_payload, l7proto, splits, 2, multisplit_pos, &multisplit_count);
if (multisplit_count != 2)
{
DLOG("hostfakesplit: host and endhost positions not found\n");
multisplit_count = 0;
}
else
{
int j;
for (i = j = 0; i < multisplit_count; i++)
{
multisplit_pos[j] = pos_normalize(multisplit_pos[i], reasm_offset, dis->len_payload);
if (multisplit_pos[j]) j++;
}
multisplit_count = j;
if (multisplit_count != 2)
{
DLOG("hostfakesplit: host or endhost are outside of this packet\n");
multisplit_count = 0;
}
else
{
DLOG("normalized hostfakesplit pos: ");
for (i = 0; i < multisplit_count; i++) DLOG("%zu ", multisplit_pos[i]);
DLOG("\n");
multisplit_pos[2] = ResolvePos(rdata_payload, rlen_payload, l7proto, &dp->hostfakesplit_midhost);
if (multisplit_pos[2])
{
multisplit_pos[2] = pos_normalize(multisplit_pos[2], reasm_offset, dis->len_payload);
if (multisplit_pos[2] > multisplit_pos[0] && multisplit_pos[2] < multisplit_pos[1])
{
DLOG("normalized hostfakesplit midhost pos: %zu\n", multisplit_pos[2]);
multisplit_count++;
}
}
}
}
}
else else
{ {
multisplit_count = 0; multisplit_count = 0;
@@ -1848,12 +1903,13 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
{ {
struct blob_item *fake_item; struct blob_item *fake_item;
size_t fake_size;
uint8_t *fake_data; uint8_t *fake_data;
uint8_t fake_data_buf[FAKE_MAX_TCP]; uint8_t fake_data_buf[FAKE_MAX_TCP];
int n = 0; int n = 0;
uint32_t sequence, sequence0;
ip_id = IP4_IP_ID_FIX(dis->ip); sequence = sequence0 = ntohl(dis->tcp->th_seq);
LIST_FOREACH(fake_item, fake, next) LIST_FOREACH(fake_item, fake, next)
{ {
n++; n++;
@@ -1869,23 +1925,27 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
default: default:
fake_data = fake_item->data; fake_data = fake_item->data;
} }
fake_data += fake_item->offset;
fake_size = fake_item->size - fake_item->offset;
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, htonl(sequence), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6),
dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment,
fake_data, fake_item->size, pkt1, &pkt1_len)) fake_data, fake_size, pkt1, &pkt1_len))
{ {
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
goto send_orig; goto send_orig;
} }
DLOG("sending fake[%d] : ", n); DLOG("sending fake[%d] seq=+%u : ", n, sequence - sequence0);
hexdump_limited_dlog(fake_data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(fake_data, fake_size, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
{ {
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
goto send_orig; goto send_orig;
} }
ip_id = IP4_IP_ID_NEXT(ip_id); ip_id = IP4_IP_ID_NEXT(ip_id);
if (dp->tcp_mod.seq) sequence += fake_size;
} }
} }
bFake = true; bFake = true;
@@ -1895,7 +1955,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (reasm_offset) break; if (reasm_offset) break;
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode == DESYNC_RSTACK ? TH_ACK : 0), false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode == DESYNC_RSTACK ? TH_ACK : 0), false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF,ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6),
dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment,
NULL, 0, pkt1, &pkt1_len)) NULL, 0, pkt1, &pkt1_len))
{ {
@@ -1908,6 +1968,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
goto send_orig; goto send_orig;
} }
ip_id = IP4_IP_ID_NEXT(ip_id);
bFake = true; bFake = true;
break; break;
case DESYNC_HOPBYHOP: case DESYNC_HOPBYHOP:
@@ -1916,6 +1977,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
fooling_orig = (dp->desync_mode == DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode == DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1; fooling_orig = (dp->desync_mode == DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode == DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
if (dis->ip6 && (dp->desync_mode2 == DESYNC_NONE || !desync_valid_second_stage_tcp(dp->desync_mode2) || if (dis->ip6 && (dp->desync_mode2 == DESYNC_NONE || !desync_valid_second_stage_tcp(dp->desync_mode2) ||
(!split_pos && (dp->desync_mode2 == DESYNC_FAKEDSPLIT || dp->desync_mode2 == DESYNC_FAKEDDISORDER)) || (!split_pos && (dp->desync_mode2 == DESYNC_FAKEDSPLIT || dp->desync_mode2 == DESYNC_FAKEDDISORDER)) ||
(multisplit_count < 2 && dp->desync_mode2 == DESYNC_HOSTFAKESPLIT) ||
(!multisplit_count && (dp->desync_mode2 == DESYNC_MULTISPLIT || dp->desync_mode2 == DESYNC_MULTIDISORDER)))) (!multisplit_count && (dp->desync_mode2 == DESYNC_MULTISPLIT || dp->desync_mode2 == DESYNC_MULTIDISORDER))))
{ {
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
@@ -1947,6 +2009,175 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
enum dpi_desync_mode desync_mode = dp->desync_mode2 == DESYNC_NONE ? dp->desync_mode : dp->desync_mode2; enum dpi_desync_mode desync_mode = dp->desync_mode2 == DESYNC_NONE ? dp->desync_mode : dp->desync_mode2;
switch (desync_mode) switch (desync_mode)
{ {
case DESYNC_HOSTFAKESPLIT:
// can be 2 or 3 split pos
// if 2 split pos : host, endhost
// if 3 split pos : host, endhost, midhost
if (multisplit_count >= 2)
{
uint8_t *seg;
size_t seg_len, host_size, pos_host, pos_endhost, pos_split_host, sz;
uint8_t *fakehost;
uint16_t ip_id_after_host;
seg = dis->data_payload;
seg_len = dis->len_payload;
pos_host = multisplit_pos[0];
pos_endhost = multisplit_pos[1];
pos_split_host = multisplit_count >= 3 ? multisplit_pos[2] : 0;
host_size = pos_endhost - pos_host;
if (replay && ctrack_replay->ip_id) ip_id = ctrack_replay->ip_id;
// before_host segment
pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0,
dis->tcp->th_seq, dis->tcp->th_ack,
dis->tcp->th_win, scale_factor, timestamps,
DF, ttl_orig, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6),
fooling_orig, 0, 0, 0,
seg, pos_host, pkt1, &pkt1_len))
goto send_orig;
ip_id = IP4_IP_ID_NEXT(ip_id);
DLOG("sending hostfakesplit before_host part 0-%zu len=%zu : ", pos_host - 1, pos_host);
hexdump_limited_dlog(seg, pos_host, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
goto send_orig;
if (!(fakehost = malloc(host_size + 1)))
{
DLOG("fakehost out of memory\n");
goto send_orig;
}
if (*dp->hfs_mod.host)
{
if (host_size <= dp->hfs_mod.host_size)
{
// "google.com" => "gle.com"
// "google.com" => "google.com"
memcpy(fakehost, dp->hfs_mod.host + dp->hfs_mod.host_size - host_size, host_size);
}
else
{
// "google.com" => "nb4auv9.google.com"
// "google.com" => ".google.com"
sz = host_size - dp->hfs_mod.host_size;
memcpy(fakehost + sz, dp->hfs_mod.host, dp->hfs_mod.host_size);
fakehost[--sz] = '.';
if (sz)
{
fill_random_az(fakehost, 1);
sz--;
}
fill_random_az09(fakehost + 1, sz);
}
}
else
{
fill_random_az(fakehost, 1);
fill_random_az09(fakehost + 1, host_size - 1);
if (host_size >= 7)
{
fakehost[host_size - 4] = '.';
memcpy(fakehost + host_size - 3, tld[random() % (sizeof(tld) / sizeof(*tld))], 3);
}
}
fakehost[host_size] = 0;
DLOG("generated fake host: %s\n", fakehost);
// pkt2: fake_host segment
pkt2_len = sizeof(pkt2);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0,
net32_add(dis->tcp->th_seq, pos_host), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6),
dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment,
fakehost, host_size, pkt2, &pkt2_len))
goto send_orig_clean;
DLOG("sending hostfakesplit fake host %zu-%zu len=%zu : ", pos_host, pos_endhost - 1, host_size);
hexdump_limited_dlog(fakehost, host_size, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, pkt2, pkt2_len))
goto send_orig_clean;
ip_id_after_host = IP4_IP_ID_NEXT(ip_id);
if (pos_split_host) ip_id_after_host = IP4_IP_ID_NEXT(ip_id_after_host);
// pkt3: after_host segment
pkt3_len = sizeof(pkt3);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0,
net32_add(dis->tcp->th_seq, pos_endhost), dis->tcp->th_ack,
dis->tcp->th_win, scale_factor, timestamps,
DF, ttl_orig, IP4_TOS(dis->ip), ip_id_after_host, IP6_FLOW(dis->ip6),
fooling_orig, 0, 0, 0,
seg + pos_endhost, seg_len - pos_endhost, pkt3, &pkt3_len))
goto send_orig_clean;
if (dp->hfs_mod.ordering == 1)
{
DLOG("sending hostfakesplit after_host part %zu-%zu len=%zu : ", pos_endhost, seg_len - 1, seg_len - pos_endhost);
hexdump_limited_dlog(seg + pos_endhost, seg_len - pos_endhost, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt3, pkt3_len))
goto send_orig_clean;
}
sz = pos_split_host ? pos_split_host - pos_host : host_size;
pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0,
net32_add(dis->tcp->th_seq, pos_host), dis->tcp->th_ack,
dis->tcp->th_win, scale_factor, timestamps,
DF, ttl_orig, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6),
fooling_orig, 0, 0, 0,
seg + pos_host, sz, pkt1, &pkt1_len))
goto send_orig_clean;
DLOG("sending hostfakesplit real host %s%zu-%zu len=%zu : ", pos_split_host ? "part 1 " : "", pos_host, pos_host + sz - 1, sz);
hexdump_limited_dlog(seg + pos_host, sz, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
goto send_orig_clean;
if (pos_split_host)
{
sz = pos_endhost - pos_split_host;
pkt1_len = sizeof(pkt1);
ip_id = IP4_IP_ID_NEXT(ip_id);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0,
net32_add(dis->tcp->th_seq, pos_split_host), dis->tcp->th_ack,
dis->tcp->th_win, scale_factor, timestamps,
DF, ttl_orig, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6),
fooling_orig, 0, 0, 0,
seg + pos_split_host, sz, pkt1, &pkt1_len))
goto send_orig_clean;
DLOG("sending hostfakesplit real host part 2 %zu-%zu len=%zu : ", pos_split_host, pos_endhost - 1, sz);
hexdump_limited_dlog(seg + pos_split_host, sz, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
goto send_orig_clean;
}
if (dp->hfs_mod.ordering == 0)
{
DLOG("sending hostfakesplit fake(2) host %zu-%zu len=%zu : ", pos_host, pos_endhost - 1, host_size);
hexdump_limited_dlog(fakehost, host_size, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, pkt2, pkt2_len))
goto send_orig_clean;
DLOG("sending hostfakesplit after_host part %zu-%zu len=%zu : ", pos_endhost, seg_len - 1, seg_len - pos_endhost);
hexdump_limited_dlog(seg + pos_endhost, seg_len - pos_endhost, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt3, pkt3_len))
goto send_orig_clean;
}
free(fakehost);
if (replay) ctrack_replay->ip_id = IP4_IP_ID_NEXT(ip_id_after_host);
return VERDICT_DROP;
send_orig_clean:
free(fakehost);
goto send_orig;
}
else
goto unsplitted_part;
case DESYNC_MULTISPLIT: case DESYNC_MULTISPLIT:
if (multisplit_count) if (multisplit_count)
{ {
@@ -1954,7 +2185,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
size_t seg_len, from, to; size_t seg_len, from, to;
unsigned int seqovl; unsigned int seqovl;
ip_id = IP4_IP_ID_FIX(dis->ip); if (replay && ctrack_replay->ip_id) ip_id = ctrack_replay->ip_id;
for (i = 0, from = 0; i <= multisplit_count; i++) for (i = 0, from = 0; i <= multisplit_count; i++)
{ {
@@ -1977,7 +2208,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("seqovl is too large"); DLOG("seqovl is too large");
goto send_orig; goto send_orig;
} }
fill_pattern(ovlseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); fill_pattern(ovlseg, seqovl, dp->seqovl_pattern, sizeof(dp->seqovl_pattern), 0);
memcpy(ovlseg + seqovl, dis->data_payload + from, to - from); memcpy(ovlseg + seqovl, dis->data_payload + from, to - from);
seg = ovlseg; seg = ovlseg;
} }
@@ -2017,17 +2248,25 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
from = to; from = to;
} }
if (replay) ctrack_replay->ip_id = ip_id;
return VERDICT_DROP; return VERDICT_DROP;
} }
break; else
goto unsplitted_part;
case DESYNC_MULTIDISORDER: case DESYNC_MULTIDISORDER:
if (multisplit_count) if (multisplit_count)
{ {
uint8_t ovlseg[DPI_DESYNC_MAX_FAKE_LEN + 100], *seg; uint8_t ovlseg[DPI_DESYNC_MAX_FAKE_LEN + 100], *seg;
size_t seg_len, from, to; size_t seg_len, from, to;
unsigned int seqovl; unsigned int seqovl;
uint16_t ip_id_end;
ip_id = IP4_IP_ID_FIX(dis->ip); if (replay && ctrack_replay->ip_id) ip_id = ctrack_replay->ip_id;
ip_id_end = ip_id = IP4_IP_ID_ADD(ip_id, (uint16_t)multisplit_count);
for (i = multisplit_count - 1, to = dis->len_payload; i >= -1; i--) for (i = multisplit_count - 1, to = dis->len_payload; i >= -1; i--)
{ {
@@ -2042,7 +2281,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (i == 0) if (i == 0)
{ {
if (seqovl_pos >= from) if (seqovl_pos >= from)
DLOG("seqovl>=split_pos (%zu>=%zu). cancelling seqovl for part %d.\n",seqovl,from,i+2); DLOG("seqovl>=split_pos (%zu>=%zu). cancelling seqovl for part %d.\n", seqovl_pos, from, i + 2);
else else
{ {
seqovl = seqovl_pos; seqovl = seqovl_pos;
@@ -2052,7 +2291,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("seqovl is too large"); DLOG("seqovl is too large");
goto send_orig; goto send_orig;
} }
fill_pattern(ovlseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); fill_pattern(ovlseg, seqovl, dp->seqovl_pattern, sizeof(dp->seqovl_pattern), 0);
memcpy(ovlseg + seqovl, dis->data_payload + from, to - from); memcpy(ovlseg + seqovl, dis->data_payload + from, to - from);
seg = ovlseg; seg = ovlseg;
} }
@@ -2074,32 +2313,45 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
to = from; to = from;
} }
if (replay) ctrack_replay->ip_id = IP4_IP_ID_NEXT(ip_id_end);
return VERDICT_DROP; return VERDICT_DROP;
} }
break; else
goto unsplitted_part;
case DESYNC_FAKEDDISORDER: case DESYNC_FAKEDDISORDER:
if (split_pos)
{ {
uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN + 100], fakeseg2[DPI_DESYNC_MAX_FAKE_LEN + 100], pat[DPI_DESYNC_MAX_FAKE_LEN], *seg; uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN + 100], fakeseg2[DPI_DESYNC_MAX_FAKE_LEN + 100], pat[DPI_DESYNC_MAX_FAKE_LEN], *seg;
size_t seg_len, fakeseg2_len; size_t seg_len, fakeseg2_len;
unsigned int seqovl; unsigned int seqovl;
int order;
if (dis->len_payload > sizeof(pat)) if (dis->len_payload > sizeof(pat))
{ {
DLOG("packet is too large\n"); DLOG("packet is too large\n");
goto send_orig; goto send_orig;
} }
fill_pattern(pat,dis->len_payload,dp->fsplit_pattern,sizeof(dp->fsplit_pattern));
ip_id = IP4_IP_ID_FIX(dis->ip); if (replay && ctrack_replay->ip_id) ip_id = ctrack_replay->ip_id;
if (seqovl_pos>=split_pos)
{
DLOG("seqovl>=split_pos (%zu>=%zu). cancelling seqovl.\n",seqovl_pos,split_pos);
seqovl = 0; seqovl = 0;
} if (split_pos)
{
order = dp->fs_mod.ordering & 3;
if (seqovl_pos >= split_pos)
DLOG("seqovl>=split_pos (%zu>=%zu). cancelling seqovl.\n", seqovl_pos, split_pos);
else else
seqovl = seqovl_pos; seqovl = seqovl_pos;
ip_id = IP4_IP_ID_NEXT(ip_id);
}
else
{
order = (dp->fs_mod.ordering >> 3) & 3;
}
fill_pattern(pat, dis->len_payload, dp->fsplit_pattern, dp->fsplit_pattern_size, reasm_offset);
if (seqovl) if (seqovl)
{ {
@@ -2109,7 +2361,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("seqovl is too large\n"); DLOG("seqovl is too large\n");
goto send_orig; goto send_orig;
} }
fill_pattern(fakeseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); fill_pattern(fakeseg, seqovl, dp->seqovl_pattern, sizeof(dp->seqovl_pattern), 0);
memcpy(fakeseg + seqovl, dis->data_payload + split_pos, dis->len_payload - split_pos); memcpy(fakeseg + seqovl, dis->data_payload + split_pos, dis->len_payload - split_pos);
seg = fakeseg; seg = fakeseg;
} }
@@ -2125,11 +2377,14 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment,
pat + split_pos, dis->len_payload - split_pos, fakeseg2, &fakeseg2_len)) pat + split_pos, dis->len_payload - split_pos, fakeseg2, &fakeseg2_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_PREV(ip_id);
if (order == 0)
{
DLOG("sending fake(1) 2nd out-of-order tcp segment %zu-%zu len=%zu : ", split_pos, dis->len_payload - 1, dis->len_payload - split_pos); DLOG("sending fake(1) 2nd out-of-order tcp segment %zu-%zu len=%zu : ", split_pos, dis->len_payload - 1, dis->len_payload - split_pos);
hexdump_limited_dlog(pat + split_pos, dis->len_payload - split_pos, PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(pat + split_pos, dis->len_payload - split_pos, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg2, fakeseg2_len)) if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg2, fakeseg2_len))
goto send_orig; goto send_orig;
}
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq, split_pos - seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq, split_pos - seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
@@ -2137,19 +2392,22 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
fooling_orig, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, fooling_orig, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment,
seg, seg_len, pkt1, &pkt1_len)) seg, seg_len, pkt1, &pkt1_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_PREV(ip_id);
DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu seqovl=%u : ", split_pos, dis->len_payload - 1, dis->len_payload - split_pos, seqovl); DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu seqovl=%u : ", split_pos, dis->len_payload - 1, dis->len_payload - split_pos, seqovl);
hexdump_limited_dlog(seg, seg_len, PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(seg, seg_len, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
goto send_orig; goto send_orig;
if (dis->ip) ((struct ip*)fakeseg2)->ip_id = ip_id; if (order <= 1)
ip_id=IP4_IP_ID_PREV(ip_id); {
DLOG("sending fake(2) 2nd out-of-order tcp segment %zu-%zu len=%zu : ", split_pos, dis->len_payload - 1, dis->len_payload - split_pos); DLOG("sending fake(2) 2nd out-of-order tcp segment %zu-%zu len=%zu : ", split_pos, dis->len_payload - 1, dis->len_payload - split_pos);
hexdump_limited_dlog(pat + split_pos, dis->len_payload - split_pos, PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(pat + split_pos, dis->len_payload - split_pos, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg2, fakeseg2_len)) if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg2, fakeseg2_len))
goto send_orig; goto send_orig;
}
if (split_pos)
{
ip_id = IP4_IP_ID_PREV(ip_id);
seg_len = sizeof(fakeseg); seg_len = sizeof(fakeseg);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
@@ -2157,7 +2415,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment,
pat, split_pos, fakeseg, &seg_len)) pat, split_pos, fakeseg, &seg_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_PREV(ip_id);
DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos); DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
hexdump_limited_dlog(pat, split_pos, PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(pat, split_pos, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, seg_len)) if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, seg_len))
@@ -2169,35 +2426,50 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
fooling_orig, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, fooling_orig, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment,
dis->data_payload, split_pos, pkt1, &pkt1_len)) dis->data_payload, split_pos, pkt1, &pkt1_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_PREV(ip_id);
DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos); DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
hexdump_limited_dlog(dis->data_payload, split_pos, PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(dis->data_payload, split_pos, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
goto send_orig; goto send_orig;
if (dis->ip) ((struct ip*)fakeseg)->ip_id = ip_id; if (order <= 2)
{
DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos); DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
hexdump_limited_dlog(pat, split_pos, PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(pat, split_pos, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, seg_len)) if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, seg_len))
goto send_orig; goto send_orig;
}
}
if (replay) ctrack_replay->ip_id = IP4_IP_ID_NEXT(ip_id);
return VERDICT_DROP; return VERDICT_DROP;
} }
break;
case DESYNC_FAKEDSPLIT: case DESYNC_FAKEDSPLIT:
if (split_pos)
{ {
uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN + 100], ovlseg[DPI_DESYNC_MAX_FAKE_LEN + 100], pat[DPI_DESYNC_MAX_FAKE_LEN], *seg; uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN + 100], ovlseg[DPI_DESYNC_MAX_FAKE_LEN + 100], pat[DPI_DESYNC_MAX_FAKE_LEN], *seg;
size_t fakeseg_len, seg_len; size_t fakeseg_len, seg_len;
int order;
if (replay && ctrack_replay->ip_id) ip_id = ctrack_replay->ip_id;
if (dis->len_payload > sizeof(pat)) if (dis->len_payload > sizeof(pat))
{ {
DLOG("packet is too large\n"); DLOG("packet is too large\n");
goto send_orig; goto send_orig;
} }
fill_pattern(pat,dis->len_payload,dp->fsplit_pattern,sizeof(dp->fsplit_pattern));
ip_id = IP4_IP_ID_FIX(dis->ip); fill_pattern(pat, dis->len_payload, dp->fsplit_pattern, dp->fsplit_pattern_size, reasm_offset);
if (split_pos)
{
order = dp->fs_mod.ordering & 3;
}
else
{
order = (dp->fs_mod.ordering >> 3) & 3;
split_pos = dis->len_payload;
}
fakeseg_len = sizeof(fakeseg); fakeseg_len = sizeof(fakeseg);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
@@ -2205,13 +2477,16 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment,
pat, split_pos, fakeseg, &fakeseg_len)) pat, split_pos, fakeseg, &fakeseg_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_NEXT(ip_id);
if (order == 0)
{
DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos); DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
hexdump_limited_dlog(pat, split_pos, PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(pat, split_pos, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len)) if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len))
goto send_orig; goto send_orig;
}
unsigned int seqovl = reasm_offset ? 0 : seqovl_pos; unsigned int seqovl = (reasm_offset || split_pos>=dis->len_payload) ? 0 : seqovl_pos;
#ifdef __linux__ #ifdef __linux__
// only linux return error if MTU is exceeded // only linux return error if MTU is exceeded
for (;; seqovl = 0) for (;; seqovl = 0)
@@ -2222,10 +2497,10 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
seg_len = split_pos + seqovl; seg_len = split_pos + seqovl;
if (seg_len > sizeof(ovlseg)) if (seg_len > sizeof(ovlseg))
{ {
DLOG("seqovl is too large"); DLOG("seqovl is too large\n");
goto send_orig; goto send_orig;
} }
fill_pattern(ovlseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); fill_pattern(ovlseg, seqovl, dp->seqovl_pattern, sizeof(dp->seqovl_pattern), 0);
memcpy(ovlseg + seqovl, dis->data_payload, split_pos); memcpy(ovlseg + seqovl, dis->data_payload, split_pos);
seg = ovlseg; seg = ovlseg;
} }
@@ -2259,20 +2534,22 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
break; break;
} }
#endif #endif
if (dis->ip) ((struct ip*)fakeseg)->ip_id = ip_id; if (order <= 1)
ip_id=IP4_IP_ID_NEXT(ip_id); {
DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos); DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu : ", split_pos - 1, split_pos);
hexdump_limited_dlog(pat, split_pos, PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(pat, split_pos, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len)) if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len))
goto send_orig; goto send_orig;
}
if (split_pos < dis->len_payload)
{
fakeseg_len = sizeof(fakeseg); fakeseg_len = sizeof(fakeseg);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq, split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq, split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6),
dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment,
pat + split_pos, dis->len_payload - split_pos, fakeseg, &fakeseg_len)) pat + split_pos, dis->len_payload - split_pos, fakeseg, &fakeseg_len))
goto send_orig; goto send_orig;
ip_id=IP4_IP_ID_NEXT(ip_id);
DLOG("sending fake(1) 2nd tcp segment %zu-%zu len=%zu : ", split_pos, dis->len_payload - 1, dis->len_payload - split_pos); DLOG("sending fake(1) 2nd tcp segment %zu-%zu len=%zu : ", split_pos, dis->len_payload - 1, dis->len_payload - split_pos);
hexdump_limited_dlog(pat + split_pos, dis->len_payload - split_pos, PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(pat + split_pos, dis->len_payload - split_pos, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len)) if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len))
@@ -2290,25 +2567,27 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
goto send_orig; goto send_orig;
if (dis->ip) ((struct ip*)fakeseg)->ip_id = ip_id; if (order <= 2)
{
DLOG("sending fake(2) 2nd tcp segment %zu-%zu len=%zu : ", split_pos, dis->len_payload - 1, dis->len_payload - split_pos); DLOG("sending fake(2) 2nd tcp segment %zu-%zu len=%zu : ", split_pos, dis->len_payload - 1, dis->len_payload - split_pos);
hexdump_limited_dlog(pat + split_pos, dis->len_payload - split_pos, PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(pat + split_pos, dis->len_payload - split_pos, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len)) if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, fakeseg, fakeseg_len))
goto send_orig; goto send_orig;
}
}
if (replay) ctrack_replay->ip_id = ip_id;
return VERDICT_DROP; return VERDICT_DROP;
} }
break;
case DESYNC_IPFRAG2: case DESYNC_IPFRAG2:
if (!reasm_offset) if (!reasm_offset)
{ {
verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6); verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6);
uint8_t pkt3[DPI_DESYNC_MAX_FAKE_LEN+100], *pkt_orig; uint8_t *pkt_orig;
size_t pkt_orig_len; size_t pkt_orig_len;
ip_id = IP4_IP_ID_FIX(dis->ip);
uint32_t ident = dis->ip ? ip_id ? ip_id : htons(1 + random() % 0xFFFF) : htonl(1 + random() % 0xFFFFFFFF); uint32_t ident = dis->ip ? ip_id ? ip_id : htons(1 + random() % 0xFFFF) : htonl(1 + random() % 0xFFFFFFFF);
size_t ipfrag_pos = (dp->desync_ipfrag_pos_tcp && dp->desync_ipfrag_pos_tcp < dis->transport_len) ? dp->desync_ipfrag_pos_tcp : 24; size_t ipfrag_pos = (dp->desync_ipfrag_pos_tcp && dp->desync_ipfrag_pos_tcp < dis->transport_len) ? dp->desync_ipfrag_pos_tcp : 24;
@@ -2356,6 +2635,17 @@ send_orig:
if (tcp_orig_send(verdict, desync_fwmark, ifout, dp, ctrack_replay, dis, bFake)) if (tcp_orig_send(verdict, desync_fwmark, ifout, dp, ctrack_replay, dis, bFake))
verdict = ct_new_postnat_fix(ctrack, dis->ip, dis->ip6, dis->tcp); verdict = ct_new_postnat_fix(ctrack, dis->ip, dis->ip6, dis->tcp);
return verdict; return verdict;
unsplitted_part:
if (replay && dis->ip && ctrack_replay->ip_id)
{
DLOG("changing ip_id of unsplitted part\n");
dis->ip->ip_id = ctrack_replay->ip_id;
ctrack_replay->ip_id = IP4_IP_ID_NEXT(ctrack_replay->ip_id);
return VERDICT_MODIFY;
}
goto send_orig;
} }
// return : true - should continue, false - should stop with verdict // return : true - should continue, false - should stop with verdict
@@ -2388,7 +2678,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
bool bFake = false; bool bFake = false;
struct sockaddr_storage src, dst; struct sockaddr_storage src, dst;
uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN+100], pkt2[DPI_DESYNC_MAX_FAKE_LEN+100]; uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN + 100], pkt2[DPI_DESYNC_MAX_FAKE_LEN + 100], pkt3[DPI_DESYNC_MAX_FAKE_LEN + 100];
size_t pkt1_len, pkt2_len; size_t pkt1_len, pkt2_len;
uint8_t ttl_orig, ttl_fake; uint8_t ttl_orig, ttl_fake;
bool DF; bool DF;
@@ -2516,7 +2806,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
{ {
struct blob_collection_head *fake; struct blob_collection_head *fake;
bool bHaveHost = false, bHostIsIp = false; bool bHaveHost = false, bHostIsIp = false;
uint16_t ip_id; uint16_t ip_id = IP4_IP_ID_FIX(dis->ip);
if (IsQUICInitial(dis->data_payload, dis->len_payload)) if (IsQUICInitial(dis->data_payload, dis->len_payload))
{ {
@@ -2856,24 +3146,28 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
case DESYNC_FAKE: case DESYNC_FAKE:
if (!reasm_offset) if (!reasm_offset)
{ {
size_t fake_size;
uint8_t *fake_data;
struct blob_item *fake_item; struct blob_item *fake_item;
int n = 0; int n = 0;
ip_id = IP4_IP_ID_FIX(dis->ip);
LIST_FOREACH(fake_item, fake, next) LIST_FOREACH(fake_item, fake, next)
{ {
n++; n++;
fake_data = fake_item->data + fake_item->offset;
fake_size = fake_item->size - fake_item->offset;
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6),
dp->desync_fooling_mode, NULL, 0, 0, dp->desync_fooling_mode, NULL, 0, 0,
fake_item->data, fake_item->size, pkt1, &pkt1_len)) fake_data, fake_size, pkt1, &pkt1_len))
{ {
goto send_orig; goto send_orig;
} }
DLOG("sending fake[%d] : ", n); DLOG("sending fake[%d] : ", n);
hexdump_limited_dlog(fake_item->data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(fake_data, fake_size, PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len)) if (!rawsend_rep(dp->desync_repeats, (struct sockaddr *)&dst, desync_fwmark, ifout, pkt1, pkt1_len))
goto send_orig; goto send_orig;
ip_id = IP4_IP_ID_NEXT(ip_id); ip_id = IP4_IP_ID_NEXT(ip_id);
@@ -2911,7 +3205,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
{ {
case DESYNC_UDPLEN: case DESYNC_UDPLEN:
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, DF, ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), fooling_orig, dp->udplen_pattern, sizeof(dp->udplen_pattern), dp->udplen_increment, dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, DF, ttl_orig, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), fooling_orig, dp->udplen_pattern, sizeof(dp->udplen_pattern), dp->udplen_increment, dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
{ {
DLOG("could not construct packet with modified length. too large ?\n"); DLOG("could not construct packet with modified length. too large ?\n");
break; break;
@@ -2936,7 +3230,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
memcpy(pkt2 + pkt2_len, dis->data_payload + 1, szcopy); memcpy(pkt2 + pkt2_len, dis->data_payload + 1, szcopy);
pkt2_len += szcopy; pkt2_len += szcopy;
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, DF, ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), fooling_orig, NULL, 0 , 0, pkt2, pkt2_len, pkt1, &pkt1_len)) if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, DF, ttl_orig, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), fooling_orig, NULL, 0, 0, pkt2, pkt2_len, pkt1, &pkt1_len))
{ {
DLOG("could not construct packet with modified length. too large ?\n"); DLOG("could not construct packet with modified length. too large ?\n");
break; break;
@@ -2955,7 +3249,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
{ {
verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6); verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6);
uint8_t pkt3[DPI_DESYNC_MAX_FAKE_LEN+100], *pkt_orig; uint8_t *pkt_orig;
size_t pkt_orig_len; size_t pkt_orig_len;
// freebsd do not set ip.id // freebsd do not set ip.id
+1
View File
@@ -32,6 +32,7 @@ enum dpi_desync_mode {
DESYNC_FAKEDDISORDER, DESYNC_FAKEDDISORDER,
DESYNC_MULTISPLIT, DESYNC_MULTISPLIT,
DESYNC_MULTIDISORDER, DESYNC_MULTIDISORDER,
DESYNC_HOSTFAKESPLIT,
DESYNC_IPFRAG2, DESYNC_IPFRAG2,
DESYNC_HOPBYHOP, DESYNC_HOPBYHOP,
DESYNC_DESTOPT, DESYNC_DESTOPT,
+9 -1
View File
@@ -338,10 +338,18 @@ bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size)
return true; return true;
} }
void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize) void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize,size_t offset)
{ {
size_t size; size_t size;
if (offset%=patsize)
{
size = patsize-offset;
size = bufsize>size ? size : bufsize;
memcpy(buf,pattern+offset,size);
buf += size;
bufsize -= size;
}
while (bufsize) while (bufsize)
{ {
size = bufsize>patsize ? patsize : bufsize; size = bufsize>patsize ? patsize : bufsize;
+1 -1
View File
@@ -70,7 +70,7 @@ static inline uint32_t pntoh32(const uint8_t *p) {
} }
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size); bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size);
void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize); void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize,size_t offset);
int fprint_localtime(FILE *F); int fprint_localtime(FILE *F);
+448 -153
View File
@@ -176,7 +176,7 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_da
*ifin = 0; *ifin = 0;
if (ifidx_in) if_indextoname(ifidx_in, ifin); if (ifidx_in) if_indextoname(ifidx_in, ifin);
DLOG("packet: id=%d len=%d mark=%08X ifin=%s(%u) ifout=%s(%u)\n", id, ilen, mark, ifin, ifidx_in, ifout, ifidx_out); DLOG("\npacket: id=%d len=%d mark=%08X ifin=%s(%u) ifout=%s(%u)\n", id, ilen, mark, ifin, ifidx_in, ifout, ifidx_out);
if (ilen >= 0) if (ilen >= 0)
{ {
@@ -502,7 +502,7 @@ static int dvt_main(void)
ReloadCheck(); ReloadCheck();
DLOG("packet: id=%u len=%zu\n", id, len); DLOG("\npacket: id=%u len=%zu\n", id, len);
verdict = processPacketData(&mark, NULL, NULL, buf, &len); verdict = processPacketData(&mark, NULL, NULL, buf, &len);
switch (verdict & VERDICT_MASK) switch (verdict & VERDICT_MASK)
{ {
@@ -583,8 +583,7 @@ static int win_main(const char *windivert_filter)
return 0; return 0;
} }
usleep(500000); usleep(500000);
} } while (!logical_net_filter_match());
while (!logical_net_filter_match());
DLOG_CONDUP("logical network now present\n"); DLOG_CONDUP("logical network now present\n");
} }
@@ -627,7 +626,7 @@ static int win_main(const char *windivert_filter)
*ifname = 0; *ifname = 0;
snprintf(ifname, sizeof(ifname), "%u.%u", wa.Network.IfIdx, wa.Network.SubIfIdx); snprintf(ifname, sizeof(ifname), "%u.%u", wa.Network.IfIdx, wa.Network.SubIfIdx);
DLOG("packet: id=%u len=%zu %s IPv6=%u IPChecksum=%u TCPChecksum=%u UDPChecksum=%u IfIdx=%u.%u\n", id, len, wa.Outbound ? "outbound" : "inbound", wa.IPv6, wa.IPChecksum, wa.TCPChecksum, wa.UDPChecksum, wa.Network.IfIdx, wa.Network.SubIfIdx); DLOG("\npacket: id=%u len=%zu %s IPv6=%u IPChecksum=%u TCPChecksum=%u UDPChecksum=%u IfIdx=%u.%u\n", id, len, wa.Outbound ? "outbound" : "inbound", wa.IPv6, wa.IPChecksum, wa.TCPChecksum, wa.UDPChecksum, wa.Network.IfIdx, wa.Network.SubIfIdx);
if (wa.Impostor) if (wa.Impostor)
{ {
DLOG("windivert: passing impostor packet\n"); DLOG("windivert: passing impostor packet\n");
@@ -747,8 +746,16 @@ static bool parse_net32_signed(const char *opt, uint32_t *value)
return sscanf(opt, "%d", (int32_t*)value) > 0; return sscanf(opt, "%d", (int32_t*)value) > 0;
} }
} }
static void load_file_or_exit(const char *filename, void *buf, size_t *size) static void load_file_or_exit(const char *filename, void *buf, size_t *size, size_t *offset)
{ {
size_t ofs;
// 0xaabbcc
// filename
// @filename
// +123@filename
if (offset) *offset = 0;
if (filename[0] == '0' && filename[1] == 'x') if (filename[0] == '0' && filename[1] == 'x')
{ {
if (!parse_hex_str(filename + 2, buf, size) || !*size) if (!parse_hex_str(filename + 2, buf, size) || !*size)
@@ -760,12 +767,35 @@ static void load_file_or_exit(const char *filename, void *buf, size_t *size)
} }
else else
{ {
ofs = 0;
if (filename[0] == '+')
{
filename++;
if (sscanf(filename, "%zu", &ofs) != 1)
{
DLOG("offset read error: %s\n", filename);
exit_clean(1);
}
while (*filename && *filename != '@') filename++;
if (*filename == '@') filename++;
}
else if (filename[0] == '@')
filename++;
if (!load_file_nonempty(filename, buf, size)) if (!load_file_nonempty(filename, buf, size))
{ {
DLOG_ERR("could not read %s\n", filename); DLOG_ERR("could not read %s\n", filename);
exit_clean(1); exit_clean(1);
} }
DLOG("read %zu bytes from %s\n",*size,filename); DLOG("read %zu bytes from '%s'. offset=%zu\n", *size, filename, ofs);
if (ofs >= *size)
{
DLOG("'%s' : offset %zu is out of data range %zu\n", filename, ofs, *size);
exit_clean(1);
}
if (offset)
*offset = ofs;
else
memmove(buf, (uint8_t*)buf + ofs, *size -= ofs);
} }
} }
@@ -789,7 +819,8 @@ static bool parse_autottl(const char *s, autottl *t, int8_t def_delta, uint8_t d
{ {
neg = false; neg = false;
s++; s++;
} else if (*s=='-') }
else if (*s == '-')
s++; s++;
switch (sscanf(s, "%u:%u-%u", &delta, &min, &max)) switch (sscanf(s, "%u:%u-%u", &delta, &min, &max))
{ {
@@ -1098,6 +1129,138 @@ err:
return false; return false;
} }
static bool parse_hostfakesplit_mod(char *opt, struct hostfakesplit_mod *hfs_mod)
{
char *e, *e2, *p, c, c2;
for (p = opt; p; )
{
for (e2 = p; *e2 && *e2 != ',' && *e2 != '='; e2++);
if ((e = strchr(e2, ',')))
{
c = *e;
*e = 0;
}
if (*e2 == '=')
{
c2 = *e2;
*e2 = 0;
}
else
e2 = NULL;
if (!strcmp(p, "host"))
{
if (!e2 || !e2[1] || e2[1] == ',') goto err;
strncpy(hfs_mod->host, e2 + 1, sizeof(hfs_mod->host) - 1);
hfs_mod->host[sizeof(hfs_mod->host) - 1 - 1] = 0;
hfs_mod->host_size = strlen(hfs_mod->host); // cache value
}
else if (!strcmp(p, "altorder"))
{
if (!e2 || !e2[1] || e2[1] == ',') goto err;
hfs_mod->ordering = atoi(e2 + 1);
if (hfs_mod->ordering < 0 || hfs_mod->ordering>1) goto err;
}
else if (strcmp(p, "none"))
goto err;
if (e2) *e2 = c2;
if (e) *e++ = c;
p = e;
}
return true;
err:
if (e2) *e2 = c2;
if (e) *e++ = c;
return false;
}
static bool parse_fakedsplit_mod(char *opt, struct fakedsplit_mod *fs_mod)
{
char *e, *e2, *p, c, c2;
for (p = opt; p; )
{
for (e2 = p; *e2 && *e2 != ',' && *e2 != '='; e2++);
if ((e = strchr(e2, ',')))
{
c = *e;
*e = 0;
}
if (*e2 == '=')
{
c2 = *e2;
*e2 = 0;
}
else
e2 = NULL;
if (!strcmp(p, "altorder"))
{
if (!e2 || !e2[1] || e2[1] == ',') goto err;
fs_mod->ordering = atoi(e2 + 1);
// unsplitted altorder in 0x03 mask. 0x04 reserved. splitted altorder in 0x18 mask
if ((fs_mod->ordering & 0xFFFFFFE4) || (((fs_mod->ordering>>3) & 3)>2)) goto err;
}
else if (strcmp(p, "none"))
goto err;
if (e2) *e2 = c2;
if (e) *e++ = c;
p = e;
}
return true;
err:
if (e2) *e2 = c2;
if (e) *e++ = c;
return false;
}
static bool parse_tcpmod(char *opt, struct tcp_mod *tcp_mod)
{
char *e, *e2, *p, c, c2;
for (p = opt; p; )
{
for (e2 = p; *e2 && *e2 != ',' && *e2 != '='; e2++);
if ((e = strchr(e2, ',')))
{
c = *e;
*e = 0;
}
if (*e2 == '=')
{
c2 = *e2;
*e2 = 0;
}
else
e2 = NULL;
if (!strcmp(p, "seq"))
{
tcp_mod->seq = true;
}
else if (strcmp(p, "none"))
goto err;
if (e2) *e2 = c2;
if (e) *e++ = c;
p = e;
}
return true;
err:
if (e2) *e2 = c2;
if (e) *e++ = c;
return false;
}
static bool parse_fooling(char *opt, unsigned int *fooling_mode) static bool parse_fooling(char *opt, unsigned int *fooling_mode)
{ {
char *e, *p = opt; char *e, *p = opt;
@@ -1165,11 +1328,10 @@ static void SplitDebug(void)
for (int x = 0; x < dp->split_count; x++) for (int x = 0; x < dp->split_count; x++)
DLOG("profile %d multisplit %s %d\n", dp->n, posmarker_name(dp->splits[x].marker), dp->splits[x].pos); DLOG("profile %d multisplit %s %d\n", dp->n, posmarker_name(dp->splits[x].marker), dp->splits[x].pos);
if (!PROTO_POS_EMPTY(&dp->seqovl)) DLOG("profile %d seqovl %s %d\n", dp->n, posmarker_name(dp->seqovl.marker), dp->seqovl.pos); if (!PROTO_POS_EMPTY(&dp->seqovl)) DLOG("profile %d seqovl %s %d\n", dp->n, posmarker_name(dp->seqovl.marker), dp->seqovl.pos);
if (!PROTO_POS_EMPTY(&dp->hostfakesplit_midhost)) DLOG("profile %d hostfakesplit midhost %s %d\n", dp->n, posmarker_name(dp->hostfakesplit_midhost.marker), dp->hostfakesplit_midhost.pos);
} }
} }
static const char * tld[]={"com","org","net","edu","gov","biz"};
static bool onetime_tls_mod_blob(int profile_n, int fake_n, const struct fake_tls_mod *tls_mod, uint8_t *fake_tls, size_t *fake_tls_size, size_t fake_tls_buf_size, struct fake_tls_mod_cache *modcache) static bool onetime_tls_mod_blob(int profile_n, int fake_n, const struct fake_tls_mod *tls_mod, uint8_t *fake_tls, size_t *fake_tls_size, size_t fake_tls_buf_size, struct fake_tls_mod_cache *modcache)
{ {
const uint8_t *ext; const uint8_t *ext;
@@ -1333,6 +1495,11 @@ static bool onetime_tls_mod(struct desync_profile *dp)
} }
if (!onetime_tls_mod_blob(dp->n, n, tls_mod, fake_tls->data, &fake_tls->size, fake_tls->size_buf, (struct fake_tls_mod_cache*)fake_tls->extra)) if (!onetime_tls_mod_blob(dp->n, n, tls_mod, fake_tls->data, &fake_tls->size, fake_tls->size_buf, (struct fake_tls_mod_cache*)fake_tls->extra))
return false; return false;
if (fake_tls->offset >= fake_tls->size)
{
DLOG("profile %d fake[%d] tls mod shrinked data to %zu and offset %zu is now out of data range\n", dp->n, n, fake_tls->size, fake_tls->offset);
return false;
}
} }
return true; return true;
} }
@@ -1341,13 +1508,14 @@ static struct blob_item *load_blob_to_collection(const char *filename, struct bl
{ {
struct blob_item *blob = blob_collection_add(blobs); struct blob_item *blob = blob_collection_add(blobs);
uint8_t *p; uint8_t *p;
if (!blob || (!(blob->data = malloc(max_size + size_reserve)))) if (!blob || (!(blob->data = malloc(max_size + size_reserve))))
{ {
DLOG_ERR("out of memory\n"); DLOG_ERR("out of memory\n");
exit_clean(1); exit_clean(1);
} }
blob->size = max_size; blob->size = max_size;
load_file_or_exit(filename,blob->data,&blob->size); load_file_or_exit(filename, blob->data, &blob->size, &blob->offset);
p = realloc(blob->data, blob->size + size_reserve); p = realloc(blob->data, blob->size + size_reserve);
if (!p) if (!p)
{ {
@@ -1358,8 +1526,13 @@ static struct blob_item *load_blob_to_collection(const char *filename, struct bl
blob->size_buf = blob->size + size_reserve; blob->size_buf = blob->size + size_reserve;
return blob; return blob;
} }
static struct blob_item *load_const_blob_to_collection(const void *data,size_t sz, struct blob_collection_head *blobs, size_t size_reserve) static struct blob_item *load_const_blob_to_collection(const void *data, size_t sz, struct blob_collection_head *blobs, size_t size_reserve, size_t offset)
{ {
if (offset >= sz)
{
DLOG_ERR("offset %zu is out of data range %zu\n", offset, sz);
exit_clean(1);
}
struct blob_item *blob = blob_collection_add(blobs); struct blob_item *blob = blob_collection_add(blobs);
if (!blob || (!(blob->data = malloc(sz + size_reserve)))) if (!blob || (!(blob->data = malloc(sz + size_reserve))))
{ {
@@ -1368,6 +1541,7 @@ static struct blob_item *load_const_blob_to_collection(const void *data,size_t s
} }
blob->size = sz; blob->size = sz;
blob->size_buf = sz + size_reserve; blob->size_buf = sz + size_reserve;
blob->offset = offset;
memcpy(blob->data, data, sz); memcpy(blob->data, data, sz);
return blob; return blob;
} }
@@ -1447,15 +1621,36 @@ static bool wf_make_filter(
unsigned int IfIdx, unsigned int SubIfIdx, unsigned int IfIdx, unsigned int SubIfIdx,
bool ipv4, bool ipv6, bool ipv4, bool ipv6,
const char *pf_tcp_src, const char *pf_tcp_dst, const char *pf_tcp_src, const char *pf_tcp_dst,
const char *pf_udp_src, const char *pf_udp_dst) const char *pf_udp_src, const char *pf_udp_dst,
const struct str_list_head *wf_raw_part,
bool bFilterOutLAN)
{ {
char pf_dst_buf[8192], iface[64]; char pf_dst_buf[8192], iface[64];
struct str_list *wfpart;
int n;
const char *pf_dst; const char *pf_dst;
const char *f_tcpin = *pf_tcp_src ? dp_list_have_autohostlist(&params.desync_profiles) ? "(" DIVERT_TCP_INBOUNDS " or (" DIVERT_HTTP_REDIRECT "))" : DIVERT_TCP_INBOUNDS : ""; const char *f_tcpin = *pf_tcp_src ? dp_list_have_autohostlist(&params.desync_profiles) ? "(" DIVERT_TCP_INBOUNDS " or (" DIVERT_HTTP_REDIRECT "))" : DIVERT_TCP_INBOUNDS : "";
const char *f_tcp_not_empty = (*pf_tcp_src && !dp_list_need_all_out(&params.desync_profiles)) ? DIVERT_TCP_NOT_EMPTY " and " : ""; const char *f_tcp_not_empty = (*pf_tcp_src && !dp_list_need_all_out(&params.desync_profiles)) ? DIVERT_TCP_NOT_EMPTY " and " : "";
snprintf(iface, sizeof(iface), " ifIdx=%u and subIfIdx=%u and", IfIdx, SubIfIdx); snprintf(iface, sizeof(iface), " ifIdx=%u and subIfIdx=%u and", IfIdx, SubIfIdx);
if (!*pf_tcp_src && !*pf_udp_src) return false; snprintf(wf, len, "%s and%s%s\n(",
DIVERT_PROLOG,
IfIdx ? iface : "",
ipv4 ? ipv6 ? "" : " ip and" : " ipv6 and"
);
n = 0;
if (!LIST_EMPTY(wf_raw_part))
{
LIST_FOREACH(wfpart, wf_raw_part, next)
{
snprintf(wf + strlen(wf), len - strlen(wf), "%s(\n%s\n )", n ? "\n or\n " : "\n ", wfpart->str);
n++;
}
}
if (*pf_tcp_src || *pf_udp_src)
{
if (*pf_tcp_src && *pf_udp_src) if (*pf_tcp_src && *pf_udp_src)
{ {
snprintf(pf_dst_buf, sizeof(pf_dst_buf), "(%s or %s)", pf_tcp_dst, pf_udp_dst); snprintf(pf_dst_buf, sizeof(pf_dst_buf), "(%s or %s)", pf_tcp_dst, pf_udp_dst);
@@ -1463,21 +1658,26 @@ static bool wf_make_filter(
} }
else else
pf_dst = *pf_tcp_dst ? pf_tcp_dst : pf_udp_dst; pf_dst = *pf_tcp_dst ? pf_tcp_dst : pf_udp_dst;
snprintf(wf,len,
DIVERT_PROLOG " and%s%s\n ((outbound and %s%s%s)\n or\n (inbound and tcp%s%s%s%s%s%s%s))", snprintf(wf + strlen(wf), len - strlen(wf), n++ ? "\n or\n " : "\n ");
IfIdx ? iface : "",
ipv4 ? ipv6 ? "" : " ip and" : " ipv6 and", snprintf(wf + strlen(wf), len - strlen(wf),
"(\n (outbound and %s%s)\n or\n (inbound and tcp%s%s%s%s%s)\n )",
f_tcp_not_empty, f_tcp_not_empty,
pf_dst, pf_dst,
ipv4 ? ipv6 ? " and " DIVERT_NO_LOCALNETS_DST : " and " DIVERT_NO_LOCALNETSv4_DST : " and " DIVERT_NO_LOCALNETSv6_DST,
*pf_tcp_src ? "" : " and false", *pf_tcp_src ? "" : " and false",
*f_tcpin ? " and " : "", *f_tcpin ? " and " : "",
*f_tcpin ? f_tcpin : "", *f_tcpin ? f_tcpin : "",
*pf_tcp_src ? " and " : "", *pf_tcp_src ? " and " : "",
*pf_tcp_src ? pf_tcp_src : "", *pf_tcp_src ? pf_tcp_src : "");
*pf_tcp_src ? " and " : "",
*pf_tcp_src ? ipv4 ? ipv6 ? DIVERT_NO_LOCALNETS_SRC : DIVERT_NO_LOCALNETSv4_SRC : DIVERT_NO_LOCALNETSv6_SRC : "" }
); strncat(wf, "\n)", len - strlen(wf) - 1);
if (bFilterOutLAN)
snprintf(wf + strlen(wf), len - strlen(wf), "\nand\n(\n outbound and %s\n or\n inbound and %s\n)\n",
ipv4 ? ipv6 ? DIVERT_NO_LOCALNETS_DST : DIVERT_NO_LOCALNETSv4_DST : DIVERT_NO_LOCALNETSv6_DST,
ipv4 ? ipv6 ? DIVERT_NO_LOCALNETS_SRC : DIVERT_NO_LOCALNETSv4_SRC : DIVERT_NO_LOCALNETSv6_SRC);
return true; return true;
} }
@@ -1496,143 +1696,149 @@ static void exithelp(void)
{ {
printf( printf(
#if !defined( __OpenBSD__) && !defined(__ANDROID__) #if !defined( __OpenBSD__) && !defined(__ANDROID__)
" @<config_file>|$<config_file>\t\t\t; read file for options. must be the only argument. other options are ignored.\n\n" " @<config_file>|$<config_file>\t\t\t\t; read file for options. must be the only argument. other options are ignored.\n\n"
#endif #endif
#ifdef __ANDROID__ #ifdef __ANDROID__
" --debug=0|1|syslog|android|@<filename>\n" " --debug=0|1|syslog|android|@<filename>\n"
#else #else
" --debug=0|1|syslog|@<filename>\n" " --debug=0|1|syslog|@<filename>\n"
#endif #endif
" --version\t\t\t\t\t; print version and exit\n" " --version\t\t\t\t\t\t; print version and exit\n"
" --dry-run\t\t\t\t\t; verify parameters and exit with code 0 if successful\n" " --dry-run\t\t\t\t\t\t; verify parameters and exit with code 0 if successful\n"
" --comment=any_text\n" " --comment=any_text\n"
#ifdef __linux__ #ifdef __linux__
" --qnum=<nfqueue_number>\n" " --qnum=<nfqueue_number>\n"
#elif defined(BSD) #elif defined(BSD)
" --port=<port>\t\t\t\t\t; divert port\n" " --port=<port>\t\t\t\t\t\t; divert port\n"
#endif #endif
" --daemon\t\t\t\t\t; daemonize\n" " --daemon\t\t\t\t\t\t; daemonize\n"
" --pidfile=<filename>\t\t\t\t; write pid to file\n" " --pidfile=<filename>\t\t\t\t\t; write pid to file\n"
#ifndef __CYGWIN__ #ifndef __CYGWIN__
" --user=<username>\t\t\t\t; drop root privs\n" " --user=<username>\t\t\t\t\t; drop root privs\n"
" --uid=uid[:gid1,gid2,...]\t\t\t; drop root privs\n" " --uid=uid[:gid1,gid2,...]\t\t\t\t; drop root privs\n"
#endif #endif
#ifdef __linux__ #ifdef __linux__
" --bind-fix4\t\t\t\t\t; apply outgoing interface selection fix for generated ipv4 packets\n" " --bind-fix4\t\t\t\t\t\t; apply outgoing interface selection fix for generated ipv4 packets\n"
" --bind-fix6\t\t\t\t\t; apply outgoing interface selection fix for generated ipv6 packets\n" " --bind-fix6\t\t\t\t\t\t; apply outgoing interface selection fix for generated ipv6 packets\n"
#endif #endif
" --ctrack-timeouts=S:E:F[:U]\t\t\t; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default %u:%u:%u:%u\n" " --ctrack-timeouts=S:E:F[:U]\t\t\t\t; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default %u:%u:%u:%u\n"
" --ctrack-disable=[0|1]\t\t\t\t; 1 or no argument disables conntrack\n" " --ctrack-disable=[0|1]\t\t\t\t\t; 1 or no argument disables conntrack\n"
" --ipcache-lifetime=<int>\t\t\t; time in seconds to keep cached hop count and domain name (default %u). 0 = no expiration\n" " --ipcache-lifetime=<int>\t\t\t\t; time in seconds to keep cached hop count and domain name (default %u). 0 = no expiration\n"
" --ipcache-hostname=[0|1]\t\t\t; 1 or no argument enables ip->hostname caching\n" " --ipcache-hostname=[0|1]\t\t\t\t; 1 or no argument enables ip->hostname caching\n"
#ifdef __CYGWIN__ #ifdef __CYGWIN__
"\nWINDIVERT FILTER:\n" "\nWINDIVERT FILTER:\n"
" --wf-iface=<int>[.<int>]\t\t\t; numeric network interface and subinterface indexes\n" " --wf-iface=<int>[.<int>]\t\t\t\t; numeric network interface and subinterface indexes\n"
" --wf-l3=ipv4|ipv6\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n" " --wf-l3=ipv4|ipv6\t\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n"
" --wf-tcp=[~]port1[-port2]\t\t\t; TCP port filter. ~ means negation. multiple comma separated values allowed.\n" " --wf-tcp=[~]port1[-port2]\t\t\t\t; TCP port filter. ~ means negation. multiple comma separated values allowed.\n"
" --wf-udp=[~]port1[-port2]\t\t\t; UDP port filter. ~ means negation. multiple comma separated values allowed.\n" " --wf-udp=[~]port1[-port2]\t\t\t\t; UDP port filter. ~ means negation. multiple comma separated values allowed.\n"
" --wf-raw=<filter>|@<filename>\t\t\t; raw windivert filter string or filename\n" " --wf-raw-part=<filter>|@<filename>\t\t\t; partial raw windivert filter string or filename\n"
" --wf-save=<filename>\t\t\t\t; save windivert filter string to a file and exit\n" " --wf-filter-lan=0|1\t\t\t\t\t; add excluding filter for non-global IP (default : 1)\n"
" --wf-raw=<filter>|@<filename>\t\t\t\t; full raw windivert filter string or filename. replaces --wf-tcp,--wf-udp,--wf-raw-part\n"
" --wf-save=<filename>\t\t\t\t\t; save windivert filter string to a file and exit\n"
"\nLOGICAL NETWORK FILTER:\n" "\nLOGICAL NETWORK FILTER:\n"
" --ssid-filter=ssid1[,ssid2,ssid3,...]\t\t; enable winws only if any of specified wifi SSIDs connected\n" " --ssid-filter=ssid1[,ssid2,ssid3,...]\t\t\t; enable winws only if any of specified wifi SSIDs connected\n"
" --nlm-filter=net1[,net2,net3,...]\t\t; enable winws only if any of specified NLM network is connected. names and GUIDs are accepted.\n" " --nlm-filter=net1[,net2,net3,...]\t\t\t; enable winws only if any of specified NLM network is connected. names and GUIDs are accepted.\n"
" --nlm-list[=all]\t\t\t\t; list Network List Manager (NLM) networks. connected only or all.\n" " --nlm-list[=all]\t\t\t\t\t; list Network List Manager (NLM) networks. connected only or all.\n"
#endif #endif
"\nMULTI-STRATEGY:\n" "\nMULTI-STRATEGY:\n"
" --new\t\t\t\t\t\t; begin new strategy\n" " --new\t\t\t\t\t\t\t; begin new strategy\n"
" --skip\t\t\t\t\t\t; do not use this strategy\n" " --skip\t\t\t\t\t\t\t; do not use this strategy\n"
" --filter-l3=ipv4|ipv6\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n" " --filter-l3=ipv4|ipv6\t\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n"
" --filter-tcp=[~]port1[-port2]|*\t\t; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list allowed.\n" " --filter-tcp=[~]port1[-port2]|*\t\t\t; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list allowed.\n"
" --filter-udp=[~]port1[-port2]|*\t\t; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list allowed.\n" " --filter-udp=[~]port1[-port2]|*\t\t\t; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list allowed.\n"
" --filter-l7=[http|tls|quic|wireguard|dht|discord|stun|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.\n" " --filter-l7=[http|tls|quic|wireguard|dht|discord|stun|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed.\n"
#ifdef HAS_FILTER_SSID #ifdef HAS_FILTER_SSID
" --filter-ssid=ssid1[,ssid2,ssid3,...]\t\t; per profile wifi SSID filter\n" " --filter-ssid=ssid1[,ssid2,ssid3,...]\t\t\t; per profile wifi SSID filter\n"
#endif #endif
" --ipset=<filename>\t\t\t\t; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n" " --ipset=<filename>\t\t\t\t\t; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
" --ipset-ip=<ip_list>\t\t\t\t; comma separated fixed subnet list\n" " --ipset-ip=<ip_list>\t\t\t\t\t; comma separated fixed subnet list\n"
" --ipset-exclude=<filename>\t\t\t; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n" " --ipset-exclude=<filename>\t\t\t\t; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
" --ipset-exclude-ip=<ip_list>\t\t\t; comma separated fixed subnet list\n" " --ipset-exclude-ip=<ip_list>\t\t\t\t; comma separated fixed subnet list\n"
"\nHOSTLIST FILTER:\n" "\nHOSTLIST FILTER:\n"
" --hostlist=<filename>\t\t\t\t; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n" " --hostlist=<filename>\t\t\t\t\t; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
" --hostlist-domains=<domain_list>\t\t; comma separated fixed domain list\n" " --hostlist-domains=<domain_list>\t\t\t; comma separated fixed domain list\n"
" --hostlist-exclude=<filename>\t\t\t; do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n" " --hostlist-exclude=<filename>\t\t\t\t; do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply, gzip supported, multiple hostlists allowed)\n"
" --hostlist-exclude-domains=<domain_list>\t; comma separated fixed domain list\n" " --hostlist-exclude-domains=<domain_list>\t\t; comma separated fixed domain list\n"
" --hostlist-auto=<filename>\t\t\t; detect DPI blocks and build hostlist automatically\n" " --hostlist-auto=<filename>\t\t\t\t; detect DPI blocks and build hostlist automatically\n"
" --hostlist-auto-fail-threshold=<int>\t\t; how many failed attempts cause hostname to be added to auto hostlist (default : %d)\n" " --hostlist-auto-fail-threshold=<int>\t\t\t; how many failed attempts cause hostname to be added to auto hostlist (default : %d)\n"
" --hostlist-auto-fail-time=<int>\t\t; all failed attemps must be within these seconds (default : %d)\n" " --hostlist-auto-fail-time=<int>\t\t\t; all failed attemps must be within these seconds (default : %d)\n"
" --hostlist-auto-retrans-threshold=<int>\t; how many request retransmissions cause attempt to fail (default : %d)\n" " --hostlist-auto-retrans-threshold=<int>\t\t; how many request retransmissions cause attempt to fail (default : %d)\n"
" --hostlist-auto-debug=<logfile>\t\t; debug auto hostlist positives\n" " --hostlist-auto-debug=<logfile>\t\t\t; debug auto hostlist positives\n"
"\nTAMPER:\n" "\nTAMPER:\n"
" --wsize=<window_size>[:<scale_factor>]\t\t; set window size. 0 = do not modify. OBSOLETE !\n" " --wsize=<window_size>[:<scale_factor>]\t\t\t; set window size. 0 = do not modify. OBSOLETE !\n"
" --wssize=<window_size>[:<scale_factor>]\t; set window size for server. 0 = do not modify. default scale_factor = 0.\n" " --wssize=<window_size>[:<scale_factor>]\t\t; set window size for server. 0 = do not modify. default scale_factor = 0.\n"
" --wssize-cutoff=[n|d|s]N\t\t\t; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" " --wssize-cutoff=[n|d|s]N\t\t\t\t; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n"
" --synack-split=[syn|synack|acksyn]\t\t; perform TCP split handshake : send SYN only, SYN+ACK or ACK+SYN\n" " --synack-split=[syn|synack|acksyn]\t\t\t; perform TCP split handshake : send SYN only, SYN+ACK or ACK+SYN\n"
" --orig-ttl=<int>\t\t\t\t; set TTL for original packets\n" " --orig-ttl=<int>\t\t\t\t\t; set TTL for original packets\n"
" --orig-ttl6=<int>\t\t\t\t; set ipv6 hop limit for original packets. by default ttl value is used\n" " --orig-ttl6=<int>\t\t\t\t\t; set ipv6 hop limit for original packets. by default ttl value is used\n"
" --orig-autottl=[<delta>[:<min>[-<max>]]|-]\t; auto ttl mode for both ipv4 and ipv6. default: +%d:%u-%u\n" " --orig-autottl=[<delta>[:<min>[-<max>]]|-]\t\t; auto ttl mode for both ipv4 and ipv6. default: +%d:%u-%u\n"
" --orig-autottl6=[<delta>[:<min>[-<max>]]|-]\t; overrides --orig-autottl for ipv6 only\n" " --orig-autottl6=[<delta>[:<min>[-<max>]]|-]\t\t; overrides --orig-autottl for ipv6 only\n"
" --orig-mod-start=[n|d|s]N\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n" " --orig-mod-start=[n|d|s]N\t\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n"
" --orig-mod-cutoff=[n|d|s]N\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" " --orig-mod-cutoff=[n|d|s]N\t\t\t\t; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n"
" --dup=<int>\t\t\t\t\t; duplicate original packets. send N dups before original.\n" " --dup=<int>\t\t\t\t\t\t; duplicate original packets. send N dups before original.\n"
" --dup-replace=[0|1]\t\t\t\t; 1 or no argument means do not send original, only dups\n" " --dup-replace=[0|1]\t\t\t\t\t; 1 or no argument means do not send original, only dups\n"
" --dup-ttl=<int>\t\t\t\t; set TTL for dups\n" " --dup-ttl=<int>\t\t\t\t\t; set TTL for dups\n"
" --dup-ttl6=<int>\t\t\t\t; set ipv6 hop limit for dups. by default ttl value is used\n" " --dup-ttl6=<int>\t\t\t\t\t; set ipv6 hop limit for dups. by default ttl value is used\n"
" --dup-autottl=[<delta>[:<min>[-<max>]]|-]\t; auto ttl mode for both ipv4 and ipv6. default: %d:%u-%u\n" " --dup-autottl=[<delta>[:<min>[-<max>]]|-]\t\t; auto ttl mode for both ipv4 and ipv6. default: %d:%u-%u\n"
" --dup-autottl6=[<delta>[:<min>[-<max>]]|-]\t; overrides --dup-autottl for ipv6 only\n" " --dup-autottl6=[<delta>[:<min>[-<max>]]|-]\t\t; overrides --dup-autottl for ipv6 only\n"
" --dup-fooling=<mode>[,<mode>]\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2\n" " --dup-fooling=<mode>[,<mode>]\t\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2\n"
" --dup-ts-increment=<int|0xHEX>\t\t\t; ts fooling TSval signed increment for dup. default %d\n" " --dup-ts-increment=<int|0xHEX>\t\t\t\t; ts fooling TSval signed increment for dup. default %d\n"
" --dup-badseq-increment=<int|0xHEX>\t\t; badseq fooling seq signed increment for dup. default %d\n" " --dup-badseq-increment=<int|0xHEX>\t\t\t; badseq fooling seq signed increment for dup. default %d\n"
" --dup-badack-increment=<int|0xHEX>\t\t; badseq fooling ackseq signed increment for dup. default %d\n" " --dup-badack-increment=<int|0xHEX>\t\t\t; badseq fooling ackseq signed increment for dup. default %d\n"
" --dup-start=[n|d|s]N\t\t\t\t; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n" " --dup-start=[n|d|s]N\t\t\t\t\t; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n"
" --dup-cutoff=[n|d|s]N\t\t\t\t; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n" " --dup-cutoff=[n|d|s]N\t\t\t\t\t; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n"
" --hostcase\t\t\t\t\t; change Host: => host:\n" " --hostcase\t\t\t\t\t\t; change Host: => host:\n"
" --hostspell\t\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n" " --hostspell\t\t\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n"
" --hostnospace\t\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n" " --hostnospace\t\t\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n"
" --domcase\t\t\t\t\t; mix domain case : Host: TeSt.cOm\n" " --domcase\t\t\t\t\t\t; mix domain case : Host: TeSt.cOm\n"
" --methodeol\t\t\t\t\t; add '\\n' before method and remove space from Host:\n" " --methodeol\t\t\t\t\t\t; add '\\n' before method and remove space from Host:\n"
" --dpi-desync=[<mode0>,]<mode>[,<mode2>]\t; try to desync dpi state. modes :\n" " --dpi-desync=[<mode0>,]<mode>[,<mode2>]\t\t; try to desync dpi state. modes :\n"
"\t\t\t\t\t\t; synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1\n" "\t\t\t\t\t\t\t; synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1\n"
"\t\t\t\t\t\t; multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper\n" "\t\t\t\t\t\t\t; multisplit multidisorder fakedsplit fakeddisorder hostfakesplit ipfrag2 udplen tamper\n"
#ifdef __linux__ #ifdef __linux__
" --dpi-desync-fwmark=<int|0xHEX>\t\t; override fwmark for desync packet. default = 0x%08X (%u)\n" " --dpi-desync-fwmark=<int|0xHEX>\t\t\t; override fwmark for desync packet. default = 0x%08X (%u)\n"
#elif defined(SO_USER_COOKIE) #elif defined(SO_USER_COOKIE)
" --dpi-desync-sockarg=<int|0xHEX>\t\t; override sockarg (SO_USER_COOKIE) for desync packet. default = 0x%08X (%u)\n" " --dpi-desync-sockarg=<int|0xHEX>\t\t\t; override sockarg (SO_USER_COOKIE) for desync packet. default = 0x%08X (%u)\n"
#endif #endif
" --dpi-desync-ttl=<int>\t\t\t\t; set ttl for fakes packets\n" " --dpi-desync-ttl=<int>\t\t\t\t\t; set ttl for fakes packets\n"
" --dpi-desync-ttl6=<int>\t\t\t; set ipv6 hop limit for fake packet. by default --dpi-desync-ttl value is used.\n" " --dpi-desync-ttl6=<int>\t\t\t\t; set ipv6 hop limit for fake packet. by default --dpi-desync-ttl value is used.\n"
" --dpi-desync-autottl=[<delta>[:<min>[-<max>]]|-] ; auto ttl mode for both ipv4 and ipv6. default: %d:%u-%u\n" " --dpi-desync-autottl=[<delta>[:<min>[-<max>]]|-]\t; auto ttl mode for both ipv4 and ipv6. default: %d:%u-%u\n"
" --dpi-desync-autottl6=[<delta>[:<min>[-<max>]]|-] ; overrides --dpi-desync-autottl for ipv6 only\n" " --dpi-desync-autottl6=[<delta>[:<min>[-<max>]]|-]\t; overrides --dpi-desync-autottl for ipv6 only\n"
" --dpi-desync-fooling=<mode>[,<mode>]\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2\n" " --dpi-desync-fooling=<mode>[,<mode>]\t\t\t; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2\n"
" --dpi-desync-repeats=<N>\t\t\t; send every desync packet N times\n" " --dpi-desync-repeats=<N>\t\t\t\t; send every desync packet N times\n"
" --dpi-desync-skip-nosni=0|1\t\t\t; 1(default)=do not act on ClientHello without SNI\n" " --dpi-desync-skip-nosni=0|1\t\t\t\t; 1(default)=do not act on ClientHello without SNI\n"
" --dpi-desync-split-pos=N|-N|marker+N|marker-N\t; comma separated list of split positions\n" " --dpi-desync-split-pos=N|-N|marker+N|marker-N\t\t; comma separated list of split positions\n"
"\t\t\t\t\t\t; markers: method,host,endhost,sld,endsld,midsld,sniext\n" "\t\t\t\t\t\t\t; markers: method,host,endhost,sld,endsld,midsld,sniext\n"
"\t\t\t\t\t\t; full list is only used by multisplit and multidisorder\n" "\t\t\t\t\t\t\t; full list is only used by multisplit and multidisorder\n"
"\t\t\t\t\t\t; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise\n" "\t\t\t\t\t\t\t; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise\n"
" --dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; use sequence overlap before first sent original split segment\n" " --dpi-desync-split-seqovl=N|-N|marker+N|marker-N\t; use sequence overlap before first sent original split segment\n"
" --dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; pattern for the fake part of overlap\n" " --dpi-desync-split-seqovl-pattern=[+ofs]@<filename>|0xHEX ; pattern for the fake part of overlap\n"
" --dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; fake pattern for fakedsplit/fakeddisorder\n" " --dpi-desync-fakedsplit-pattern=[+ofs]@<filename>|0xHEX ; fake pattern for fakedsplit/fakeddisorder\n"
" --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n" " --dpi-desync-fakedsplit-mod=mod[,mod]\t\t\t; mods can be none,altorder=0|1|2|3 + 0|8|16\n"
" --dpi-desync-ipfrag-pos-udp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n" " --dpi-desync-hostfakesplit-midhost=marker+N|marker-N ; additionally split real hostname at specified marker. must be within host..endhost or won't be splitted.\n"
" --dpi-desync-ts-increment=<int|0xHEX>\t\t; ts fooling TSval signed increment. default %d\n" " --dpi-desync-hostfakesplit-mod=mod[,mod]\t\t; mods can be none,host=<hostname>,altorder=0|1\n"
" --dpi-desync-badseq-increment=<int|0xHEX>\t; badseq fooling seq signed increment. default %d\n" " --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
" --dpi-desync-badack-increment=<int|0xHEX>\t; badseq fooling ackseq signed increment. default %d\n" " --dpi-desync-ipfrag-pos-udp=<8..%u>\t\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
" --dpi-desync-any-protocol=0|1\t\t\t; 0(default)=desync only http and tls 1=desync any nonempty data packet\n" " --dpi-desync-ts-increment=<int|0xHEX>\t\t\t; ts fooling TSval signed increment. default %d\n"
" --dpi-desync-fake-http=<filename>|0xHEX\t; file containing fake http request\n" " --dpi-desync-badseq-increment=<int|0xHEX>\t\t; badseq fooling seq signed increment. default %d\n"
" --dpi-desync-fake-tls=<filename>|0xHEX|!\t; file containing fake TLS ClientHello (for https)\n" " --dpi-desync-badack-increment=<int|0xHEX>\t\t; badseq fooling ackseq signed increment. default %d\n"
" --dpi-desync-fake-tls-mod=mod[,mod]\t\t; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,sni=<sni>,dupsid,padencap\n" " --dpi-desync-any-protocol=0|1\t\t\t\t; 0(default)=desync only http and tls 1=desync any nonempty data packet\n"
" --dpi-desync-fake-unknown=<filename>|0xHEX\t; file containing unknown protocol fake payload\n" " --dpi-desync-fake-tcp-mod=mod[,mod]\t\t\t; comma separated list of tcp fake mods. available mods : none,seq\n"
" --dpi-desync-fake-syndata=<filename>|0xHEX\t; file containing SYN data payload\n" " --dpi-desync-fake-http=[+ofs]@<filename>|0xHEX\t\t; fake http request\n"
" --dpi-desync-fake-quic=<filename>|0xHEX\t; file containing fake QUIC Initial\n" " --dpi-desync-fake-tls=[+ofs]@<filename>|0xHEX|![+offset] ; fake TLS ClientHello (for https)\n"
" --dpi-desync-fake-wireguard=<filename>|0xHEX\t; file containing fake wireguard handshake initiation\n" " --dpi-desync-fake-tls-mod=mod[,mod]\t\t\t; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,sni=<sni>,dupsid,padencap\n"
" --dpi-desync-fake-dht=<filename>|0xHEX\t\t; file containing DHT protocol fake payload (d1...e)\n" " --dpi-desync-fake-unknown=[+ofs]@<filename>|0xHEX\t; unknown protocol fake payload\n"
" --dpi-desync-fake-discord=<filename>|0xHEX\t; file containing discord protocol fake payload (Voice IP Discovery)\n" " --dpi-desync-fake-syndata=[+ofs]@<filename>|0xHEX\t; SYN data payload\n"
" --dpi-desync-fake-stun=<filename>|0xHEX\t; file containing STUN protocol fake payload\n" " --dpi-desync-fake-quic=[+ofs]@<filename>|0xHEX\t\t; fake QUIC Initial\n"
" --dpi-desync-fake-unknown-udp=<filename>|0xHEX\t; file containing unknown udp protocol fake payload\n" " --dpi-desync-fake-wireguard=[+ofs]@<filename>|0xHEX\t; fake wireguard handshake initiation\n"
" --dpi-desync-udplen-increment=<int>\t\t; increase or decrease udp packet length by N bytes (default %u). negative values decrease length.\n" " --dpi-desync-fake-dht=[+ofs]@<filename>|0xHEX\t\t; DHT protocol fake payload (d1...e)\n"
" --dpi-desync-udplen-pattern=<filename>|0xHEX\t; udp tail fill pattern\n" " --dpi-desync-fake-discord=[+ofs]@<filename>|0xHEX\t; discord protocol fake payload (Voice IP Discovery)\n"
" --dpi-desync-start=[n|d|s]N\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n" " --dpi-desync-fake-stun=[+ofs]@<filename>|0xHEX\t\t; STUN protocol fake payload\n"
" --dpi-desync-cutoff=[n|d|s]N\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n", " --dpi-desync-fake-unknown-udp=[+ofs]@<filename>|0xHEX\t; unknown udp protocol fake payload\n"
" --dpi-desync-udplen-increment=<int>\t\t\t; increase or decrease udp packet length by N bytes (default %u). negative values decrease length.\n"
" --dpi-desync-udplen-pattern=[+ofs]@<filename>|0xHEX\t; udp tail fill pattern\n"
" --dpi-desync-start=[n|d|s]N\t\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N\n"
" --dpi-desync-cutoff=[n|d|s]N\t\t\t\t; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N\n",
CTRACK_T_SYN, CTRACK_T_EST, CTRACK_T_FIN, CTRACK_T_UDP, CTRACK_T_SYN, CTRACK_T_EST, CTRACK_T_FIN, CTRACK_T_UDP,
IPCACHE_LIFETIME, IPCACHE_LIFETIME,
HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT, HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT, HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT,
@@ -1688,7 +1894,8 @@ void check_dp(const struct desync_profile *dp)
// only linux has connbytes limiter // only linux has connbytes limiter
if ((dp->desync_any_proto && !dp->desync_cutoff && if ((dp->desync_any_proto && !dp->desync_cutoff &&
(dp->desync_mode == DESYNC_FAKE || dp->desync_mode == DESYNC_RST || dp->desync_mode == DESYNC_RSTACK || (dp->desync_mode == DESYNC_FAKE || dp->desync_mode == DESYNC_RST || dp->desync_mode == DESYNC_RSTACK ||
dp->desync_mode==DESYNC_FAKEDSPLIT || dp->desync_mode==DESYNC_FAKEDDISORDER || dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER)) dp->desync_mode == DESYNC_FAKEDSPLIT || dp->desync_mode == DESYNC_FAKEDDISORDER || dp->desync_mode == DESYNC_HOSTFAKESPLIT ||
dp->desync_mode2 == DESYNC_FAKEDSPLIT || dp->desync_mode2 == DESYNC_FAKEDDISORDER || dp->desync_mode2 == DESYNC_HOSTFAKESPLIT))
|| ||
dp->dup_repeats && !dp->dup_cutoff) dp->dup_repeats && !dp->dup_cutoff)
{ {
@@ -1701,7 +1908,7 @@ void check_dp(const struct desync_profile *dp)
DLOG_CONDUP("WARNING !!! fakes or dups will be sent on every processed packet\n"); DLOG_CONDUP("WARNING !!! fakes or dups will be sent on every processed packet\n");
DLOG_CONDUP("WARNING !!! make sure it's really what you want\n"); DLOG_CONDUP("WARNING !!! make sure it's really what you want\n");
#ifdef __CYGWIN__ #ifdef __CYGWIN__
DLOG_CONDUP("WARNING !!! in most cases this is acceptable only with custom payload based windivert filter (--wf-raw)\n"); DLOG_CONDUP("WARNING !!! in most cases this is acceptable only with custom payload based windivert filter (--wf-raw, --wf-raw-part)\n");
#endif #endif
#endif #endif
} }
@@ -1789,12 +1996,16 @@ enum opt_indices {
IDX_DPI_DESYNC_SPLIT_SEQOVL, IDX_DPI_DESYNC_SPLIT_SEQOVL,
IDX_DPI_DESYNC_SPLIT_SEQOVL_PATTERN, IDX_DPI_DESYNC_SPLIT_SEQOVL_PATTERN,
IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN, IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN,
IDX_DPI_DESYNC_FAKEDSPLIT_MOD,
IDX_DPI_DESYNC_HOSTFAKESPLIT_MIDHOST,
IDX_DPI_DESYNC_HOSTFAKESPLIT_MOD,
IDX_DPI_DESYNC_IPFRAG_POS_TCP, IDX_DPI_DESYNC_IPFRAG_POS_TCP,
IDX_DPI_DESYNC_IPFRAG_POS_UDP, IDX_DPI_DESYNC_IPFRAG_POS_UDP,
IDX_DPI_DESYNC_TS_INCREMENT, IDX_DPI_DESYNC_TS_INCREMENT,
IDX_DPI_DESYNC_BADSEQ_INCREMENT, IDX_DPI_DESYNC_BADSEQ_INCREMENT,
IDX_DPI_DESYNC_BADACK_INCREMENT, IDX_DPI_DESYNC_BADACK_INCREMENT,
IDX_DPI_DESYNC_ANY_PROTOCOL, IDX_DPI_DESYNC_ANY_PROTOCOL,
IDX_DPI_DESYNC_FAKE_TCP_MOD,
IDX_DPI_DESYNC_FAKE_HTTP, IDX_DPI_DESYNC_FAKE_HTTP,
IDX_DPI_DESYNC_FAKE_TLS, IDX_DPI_DESYNC_FAKE_TLS,
IDX_DPI_DESYNC_FAKE_TLS_MOD, IDX_DPI_DESYNC_FAKE_TLS_MOD,
@@ -1841,6 +2052,8 @@ enum opt_indices {
IDX_WF_TCP, IDX_WF_TCP,
IDX_WF_UDP, IDX_WF_UDP,
IDX_WF_RAW, IDX_WF_RAW,
IDX_WF_RAW_PART,
IDX_WF_FILTER_LAN,
IDX_WF_SAVE, IDX_WF_SAVE,
IDX_SSID_FILTER, IDX_SSID_FILTER,
IDX_NLM_FILTER, IDX_NLM_FILTER,
@@ -1915,12 +2128,16 @@ static const struct option long_options[] = {
[IDX_DPI_DESYNC_SPLIT_SEQOVL] = {"dpi-desync-split-seqovl", required_argument, 0, 0}, [IDX_DPI_DESYNC_SPLIT_SEQOVL] = {"dpi-desync-split-seqovl", required_argument, 0, 0},
[IDX_DPI_DESYNC_SPLIT_SEQOVL_PATTERN] = {"dpi-desync-split-seqovl-pattern", required_argument, 0, 0}, [IDX_DPI_DESYNC_SPLIT_SEQOVL_PATTERN] = {"dpi-desync-split-seqovl-pattern", required_argument, 0, 0},
[IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN] = {"dpi-desync-fakedsplit-pattern", required_argument, 0, 0}, [IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN] = {"dpi-desync-fakedsplit-pattern", required_argument, 0, 0},
[IDX_DPI_DESYNC_FAKEDSPLIT_MOD] = {"dpi-desync-fakedsplit-mod", required_argument, 0, 0},
[IDX_DPI_DESYNC_HOSTFAKESPLIT_MIDHOST] = {"dpi-desync-hostfakesplit-midhost", required_argument, 0, 0},
[IDX_DPI_DESYNC_HOSTFAKESPLIT_MOD] = {"dpi-desync-hostfakesplit-mod", required_argument, 0, 0},
[IDX_DPI_DESYNC_IPFRAG_POS_TCP] = {"dpi-desync-ipfrag-pos-tcp", required_argument, 0, 0}, [IDX_DPI_DESYNC_IPFRAG_POS_TCP] = {"dpi-desync-ipfrag-pos-tcp", required_argument, 0, 0},
[IDX_DPI_DESYNC_IPFRAG_POS_UDP] = {"dpi-desync-ipfrag-pos-udp", required_argument, 0, 0}, [IDX_DPI_DESYNC_IPFRAG_POS_UDP] = {"dpi-desync-ipfrag-pos-udp", required_argument, 0, 0},
[IDX_DPI_DESYNC_TS_INCREMENT] = {"dpi-desync-ts-increment", required_argument, 0, 0}, [IDX_DPI_DESYNC_TS_INCREMENT] = {"dpi-desync-ts-increment", required_argument, 0, 0},
[IDX_DPI_DESYNC_BADSEQ_INCREMENT] = {"dpi-desync-badseq-increment", required_argument, 0, 0}, [IDX_DPI_DESYNC_BADSEQ_INCREMENT] = {"dpi-desync-badseq-increment", required_argument, 0, 0},
[IDX_DPI_DESYNC_BADACK_INCREMENT] = {"dpi-desync-badack-increment", required_argument, 0, 0}, [IDX_DPI_DESYNC_BADACK_INCREMENT] = {"dpi-desync-badack-increment", required_argument, 0, 0},
[IDX_DPI_DESYNC_ANY_PROTOCOL] = {"dpi-desync-any-protocol", optional_argument, 0, 0}, [IDX_DPI_DESYNC_ANY_PROTOCOL] = {"dpi-desync-any-protocol", optional_argument, 0, 0},
[IDX_DPI_DESYNC_FAKE_TCP_MOD] = {"dpi-desync-fake-tcp-mod", required_argument, 0, 0},
[IDX_DPI_DESYNC_FAKE_HTTP] = {"dpi-desync-fake-http", required_argument, 0, 0}, [IDX_DPI_DESYNC_FAKE_HTTP] = {"dpi-desync-fake-http", required_argument, 0, 0},
[IDX_DPI_DESYNC_FAKE_TLS] = {"dpi-desync-fake-tls", required_argument, 0, 0}, [IDX_DPI_DESYNC_FAKE_TLS] = {"dpi-desync-fake-tls", required_argument, 0, 0},
[IDX_DPI_DESYNC_FAKE_TLS_MOD] = {"dpi-desync-fake-tls-mod", required_argument, 0, 0}, [IDX_DPI_DESYNC_FAKE_TLS_MOD] = {"dpi-desync-fake-tls-mod", required_argument, 0, 0},
@@ -1967,6 +2184,8 @@ static const struct option long_options[] = {
[IDX_WF_TCP] = {"wf-tcp", required_argument, 0, 0}, [IDX_WF_TCP] = {"wf-tcp", required_argument, 0, 0},
[IDX_WF_UDP] = {"wf-udp", required_argument, 0, 0}, [IDX_WF_UDP] = {"wf-udp", required_argument, 0, 0},
[IDX_WF_RAW] = {"wf-raw", required_argument, 0, 0}, [IDX_WF_RAW] = {"wf-raw", required_argument, 0, 0},
[IDX_WF_RAW_PART] = {"wf-raw-part", required_argument, 0, 0},
[IDX_WF_FILTER_LAN] = {"wf-filter-lan", required_argument, 0, 0},
[IDX_WF_SAVE] = {"wf-save", required_argument, 0, 0}, [IDX_WF_SAVE] = {"wf-save", required_argument, 0, 0},
[IDX_SSID_FILTER] = {"ssid-filter", required_argument, 0, 0}, [IDX_SSID_FILTER] = {"ssid-filter", required_argument, 0, 0},
[IDX_NLM_FILTER] = {"nlm-filter", required_argument, 0, 0}, [IDX_NLM_FILTER] = {"nlm-filter", required_argument, 0, 0},
@@ -1994,9 +2213,9 @@ int main(int argc, char **argv)
struct ipset_file *anon_ips = NULL, *anon_ips_exclude = NULL; struct ipset_file *anon_ips = NULL, *anon_ips_exclude = NULL;
#ifdef __CYGWIN__ #ifdef __CYGWIN__
char windivert_filter[16384], wf_pf_tcp_src[4096], wf_pf_tcp_dst[4096], wf_pf_udp_src[4096], wf_pf_udp_dst[4096], wf_save_file[256]; char windivert_filter[16384], wf_pf_tcp_src[4096], wf_pf_tcp_dst[4096], wf_pf_udp_src[4096], wf_pf_udp_dst[4096], wf_save_file[256];
bool wf_ipv4=true, wf_ipv6=true; bool wf_ipv4 = true, wf_ipv6 = true, wf_filter_lan = true;
unsigned int IfIdx = 0, SubIfIdx = 0; unsigned int IfIdx = 0, SubIfIdx = 0;
unsigned int hash_wf_tcp=0,hash_wf_udp=0,hash_wf_raw=0,hash_ssid_filter=0,hash_nlm_filter=0; unsigned int hash_wf_tcp = 0, hash_wf_udp = 0, hash_wf_raw = 0, hash_wf_raw_part = 0, hash_ssid_filter = 0, hash_nlm_filter = 0;
*windivert_filter = *wf_pf_tcp_src = *wf_pf_tcp_dst = *wf_pf_udp_src = *wf_pf_udp_dst = *wf_save_file = 0; *windivert_filter = *wf_pf_tcp_src = *wf_pf_tcp_dst = *wf_pf_udp_src = *wf_pf_udp_dst = *wf_save_file = 0;
#endif #endif
@@ -2037,6 +2256,7 @@ int main(int argc, char **argv)
#ifdef __CYGWIN__ #ifdef __CYGWIN__
LIST_INIT(&params.ssid_filter); LIST_INIT(&params.ssid_filter);
LIST_INIT(&params.nlm_filter); LIST_INIT(&params.nlm_filter);
LIST_INIT(&params.wf_raw_part);
#else #else
if (can_drop_root()) if (can_drop_root())
{ {
@@ -2536,16 +2756,47 @@ int main(int argc, char **argv)
{ {
char buf[sizeof(dp->seqovl_pattern)]; char buf[sizeof(dp->seqovl_pattern)];
size_t sz = sizeof(buf); size_t sz = sizeof(buf);
load_file_or_exit(optarg,buf,&sz); load_file_or_exit(optarg, buf, &sz, NULL);
fill_pattern(dp->seqovl_pattern,sizeof(dp->seqovl_pattern),buf,sz); fill_pattern(dp->seqovl_pattern, sizeof(dp->seqovl_pattern), buf, sz, 0);
} }
break; break;
case IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN: case IDX_DPI_DESYNC_FAKEDSPLIT_PATTERN:
{ {
char buf[sizeof(dp->fsplit_pattern)]; free(dp->fsplit_pattern);
size_t sz=sizeof(buf); if (!(dp->fsplit_pattern = malloc(dp->fsplit_pattern_size=32768)))
load_file_or_exit(optarg,buf,&sz); {
fill_pattern(dp->fsplit_pattern,sizeof(dp->fsplit_pattern),buf,sz); DLOG_ERR("out of memory\n");
exit_clean(1);
}
load_file_or_exit(optarg, dp->fsplit_pattern, &dp->fsplit_pattern_size, NULL);
dp->fsplit_pattern = realloc(dp->fsplit_pattern, dp->fsplit_pattern_size);
}
break;
case IDX_DPI_DESYNC_FAKEDSPLIT_MOD:
if (!parse_fakedsplit_mod(optarg, &dp->fs_mod))
{
DLOG_ERR("Invalid fakedsplit mod : %s\n", optarg);
exit_clean(1);
}
break;
case IDX_DPI_DESYNC_HOSTFAKESPLIT_MIDHOST:
if (!strcmp(optarg, "0"))
{
// allow zero = disable midhost split
dp->hostfakesplit_midhost.marker = PM_ABS;
dp->hostfakesplit_midhost.pos = 0;
}
else if (!parse_split_pos(optarg, &dp->hostfakesplit_midhost))
{
DLOG_ERR("Invalid argument for dpi-desync-hostfakesplit-midhost\n");
exit_clean(1);
}
break;
case IDX_DPI_DESYNC_HOSTFAKESPLIT_MOD:
if (!parse_hostfakesplit_mod(optarg, &dp->hfs_mod))
{
DLOG_ERR("Invalid hostfakesplit mod : %s\n", optarg);
exit_clean(1);
} }
break; break;
case IDX_DPI_DESYNC_IPFRAG_POS_TCP: case IDX_DPI_DESYNC_IPFRAG_POS_TCP:
@@ -2596,14 +2847,22 @@ int main(int argc, char **argv)
case IDX_DPI_DESYNC_ANY_PROTOCOL: case IDX_DPI_DESYNC_ANY_PROTOCOL:
dp->desync_any_proto = !optarg || atoi(optarg); dp->desync_any_proto = !optarg || atoi(optarg);
break; break;
case IDX_DPI_DESYNC_FAKE_TCP_MOD:
if (!parse_tcpmod(optarg, &dp->tcp_mod))
{
DLOG_ERR("Invalid tcp mod : %s\n", optarg);
exit_clean(1);
}
break;
case IDX_DPI_DESYNC_FAKE_HTTP: case IDX_DPI_DESYNC_FAKE_HTTP:
load_blob_to_collection(optarg, &dp->fake_http, FAKE_MAX_TCP, 0); load_blob_to_collection(optarg, &dp->fake_http, FAKE_MAX_TCP, 0);
break; break;
case IDX_DPI_DESYNC_FAKE_TLS: case IDX_DPI_DESYNC_FAKE_TLS:
{ {
dp->tls_fake_last = strcmp(optarg,"!") ? if (optarg[0] == '!' && (optarg[1] == 0 || optarg[1] == '+'))
load_blob_to_collection(optarg, &dp->fake_tls, FAKE_MAX_TCP,4+sizeof(dp->tls_mod_last.sni)) : dp->tls_fake_last = load_const_blob_to_collection(fake_tls_clienthello_default, sizeof(fake_tls_clienthello_default), &dp->fake_tls, 4 + sizeof(dp->tls_mod_last.sni), optarg[1] == '+' ? (size_t)atoi(optarg + 1) : 0);
load_const_blob_to_collection(fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),&dp->fake_tls,4+sizeof(dp->tls_mod_last.sni)); else
dp->tls_fake_last = load_blob_to_collection(optarg, &dp->fake_tls, FAKE_MAX_TCP, 4 + sizeof(dp->tls_mod_last.sni));
if (!(dp->tls_fake_last->extra2 = malloc(sizeof(struct fake_tls_mod)))) if (!(dp->tls_fake_last->extra2 = malloc(sizeof(struct fake_tls_mod))))
{ {
DLOG_ERR("out of memory\n"); DLOG_ERR("out of memory\n");
@@ -2628,7 +2887,7 @@ int main(int argc, char **argv)
break; break;
case IDX_DPI_DESYNC_FAKE_SYNDATA: case IDX_DPI_DESYNC_FAKE_SYNDATA:
dp->fake_syndata_size = sizeof(dp->fake_syndata); dp->fake_syndata_size = sizeof(dp->fake_syndata);
load_file_or_exit(optarg,dp->fake_syndata,&dp->fake_syndata_size); load_file_or_exit(optarg, dp->fake_syndata, &dp->fake_syndata_size, NULL);
break; break;
case IDX_DPI_DESYNC_FAKE_QUIC: case IDX_DPI_DESYNC_FAKE_QUIC:
load_blob_to_collection(optarg, &dp->fake_quic, FAKE_MAX_UDP, 0); load_blob_to_collection(optarg, &dp->fake_quic, FAKE_MAX_UDP, 0);
@@ -2659,8 +2918,8 @@ int main(int argc, char **argv)
{ {
char buf[sizeof(dp->udplen_pattern)]; char buf[sizeof(dp->udplen_pattern)];
size_t sz = sizeof(buf); size_t sz = sizeof(buf);
load_file_or_exit(optarg,buf,&sz); load_file_or_exit(optarg, buf, &sz, NULL);
fill_pattern(dp->udplen_pattern,sizeof(dp->udplen_pattern),buf,sz); fill_pattern(dp->udplen_pattern, sizeof(dp->udplen_pattern), buf, sz, 0);
} }
break; break;
case IDX_DPI_DESYNC_CUTOFF: case IDX_DPI_DESYNC_CUTOFF:
@@ -2944,7 +3203,7 @@ int main(int argc, char **argv)
if (optarg[0] == '@') if (optarg[0] == '@')
{ {
size_t sz = sizeof(windivert_filter) - 1; size_t sz = sizeof(windivert_filter) - 1;
load_file_or_exit(optarg+1,windivert_filter,&sz); load_file_or_exit(optarg, windivert_filter, &sz, NULL);
windivert_filter[sz] = 0; windivert_filter[sz] = 0;
} }
else else
@@ -2953,6 +3212,31 @@ int main(int argc, char **argv)
windivert_filter[sizeof(windivert_filter) - 1] = '\0'; windivert_filter[sizeof(windivert_filter) - 1] = '\0';
} }
break; break;
case IDX_WF_RAW_PART:
hash_wf_raw_part ^= hash_jen(optarg, strlen(optarg));
{
char wfpart[sizeof(windivert_filter)];
if (optarg[0] == '@')
{
size_t sz = sizeof(wfpart) - 1;
load_file_or_exit(optarg, wfpart, &sz, NULL);
wfpart[sz] = 0;
}
else
{
strncpy(wfpart, optarg, sizeof(wfpart));
wfpart[sizeof(wfpart) - 1] = '\0';
}
if (!strlist_add(&params.wf_raw_part, wfpart))
{
DLOG_ERR("out of memory\n");
exit_clean(1);
}
}
break;
case IDX_WF_FILTER_LAN:
wf_filter_lan = !!atoi(optarg);
break;
case IDX_WF_SAVE: case IDX_WF_SAVE:
strncpy(wf_save_file, optarg, sizeof(wf_save_file)); strncpy(wf_save_file, optarg, sizeof(wf_save_file));
wf_save_file[sizeof(wf_save_file) - 1] = '\0'; wf_save_file[sizeof(wf_save_file) - 1] = '\0';
@@ -3032,10 +3316,21 @@ int main(int argc, char **argv)
LIST_FOREACH(dpl, &params.desync_profiles, next) LIST_FOREACH(dpl, &params.desync_profiles, next)
{ {
dp = &dpl->dp; dp = &dpl->dp;
// not specified - use desync_ttl value instead // not specified - use desync_ttl value instead
if (dp->desync_ttl6 == 0xFF) dp->desync_ttl6 = dp->desync_ttl; if (dp->desync_ttl6 == 0xFF) dp->desync_ttl6 = dp->desync_ttl;
if (dp->dup_ttl6 == 0xFF) dp->dup_ttl6 = dp->dup_ttl; if (dp->dup_ttl6 == 0xFF) dp->dup_ttl6 = dp->dup_ttl;
if (dp->orig_mod_ttl6 == 0xFF) dp->orig_mod_ttl6 = dp->orig_mod_ttl; if (dp->orig_mod_ttl6 == 0xFF) dp->orig_mod_ttl6 = dp->orig_mod_ttl;
if (!dp->fsplit_pattern)
{
if (dp->fsplit_pattern=calloc(64,1))
dp->fsplit_pattern_size=64;
else
{
DLOG_ERR("out of memory\n");
exit_clean(1);
}
}
if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl; if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl;
if (!AUTOTTL_ENABLED(dp->orig_autottl6)) dp->orig_autottl6 = dp->orig_autottl; if (!AUTOTTL_ENABLED(dp->orig_autottl6)) dp->orig_autottl6 = dp->orig_autottl;
if (!AUTOTTL_ENABLED(dp->dup_autottl6)) dp->dup_autottl6 = dp->dup_autottl; if (!AUTOTTL_ENABLED(dp->dup_autottl6)) dp->dup_autottl6 = dp->dup_autottl;
@@ -3093,12 +3388,12 @@ int main(int argc, char **argv)
#ifdef __CYGWIN__ #ifdef __CYGWIN__
if (!*windivert_filter) if (!*windivert_filter)
{ {
if (!*wf_pf_tcp_src && !*wf_pf_udp_src) if (!*wf_pf_tcp_src && !*wf_pf_udp_src && LIST_EMPTY(&params.wf_raw_part))
{ {
DLOG_ERR("windivert filter : must specify port filter\n"); DLOG_ERR("windivert filter : must specify port or/and partial raw filter\n");
exit_clean(1); exit_clean(1);
} }
if (!wf_make_filter(windivert_filter, sizeof(windivert_filter), IfIdx, SubIfIdx, wf_ipv4, wf_ipv6, wf_pf_tcp_src, wf_pf_tcp_dst, wf_pf_udp_src, wf_pf_udp_dst)) if (!wf_make_filter(windivert_filter, sizeof(windivert_filter), IfIdx, SubIfIdx, wf_ipv4, wf_ipv6, wf_pf_tcp_src, wf_pf_tcp_dst, wf_pf_udp_src, wf_pf_udp_dst, &params.wf_raw_part, wf_filter_lan))
{ {
DLOG_ERR("windivert filter : could not make filter\n"); DLOG_ERR("windivert filter : could not make filter\n");
exit_clean(1); exit_clean(1);
@@ -3121,7 +3416,7 @@ int main(int argc, char **argv)
HANDLE hMutexArg; HANDLE hMutexArg;
{ {
char mutex_name[128]; char mutex_name[128];
snprintf(mutex_name,sizeof(mutex_name),"Global\\winws_arg_%u_%u_%u_%u_%u_%u_%u_%u_%u",hash_wf_tcp,hash_wf_udp,hash_wf_raw,hash_ssid_filter,hash_nlm_filter,IfIdx,SubIfIdx,wf_ipv4,wf_ipv6); snprintf(mutex_name, sizeof(mutex_name), "Global\\winws_arg_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u", hash_wf_tcp, hash_wf_udp, hash_wf_raw, hash_wf_raw_part, hash_ssid_filter, hash_nlm_filter, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6);
hMutexArg = CreateMutexA(NULL, TRUE, mutex_name); hMutexArg = CreateMutexA(NULL, TRUE, mutex_name);
if (hMutexArg && GetLastError() == ERROR_ALREADY_EXISTS) if (hMutexArg && GetLastError() == ERROR_ALREADY_EXISTS)
+9 -5
View File
@@ -20,6 +20,7 @@ const char *progname = "nfqws";
#error UNKNOWN_SYSTEM_TIME #error UNKNOWN_SYSTEM_TIME
#endif #endif
const char * tld[6] = { "com","org","net","edu","gov","biz" };
int DLOG_FILE(FILE *F, const char *format, va_list args) int DLOG_FILE(FILE *F, const char *format, va_list args)
{ {
@@ -241,11 +242,11 @@ bool dp_fake_defaults(struct desync_profile *dp)
{ {
struct blob_item *item; struct blob_item *item;
if (blob_collection_empty(&dp->fake_http)) if (blob_collection_empty(&dp->fake_http))
if (!blob_collection_add_blob(&dp->fake_http,fake_http_request_default,strlen(fake_http_request_default),0)) if (!blob_collection_add_blob(&dp->fake_http,fake_http_request_default,strlen(fake_http_request_default),0,0))
return false; return false;
if (blob_collection_empty(&dp->fake_tls)) if (blob_collection_empty(&dp->fake_tls))
{ {
if (!(item=blob_collection_add_blob(&dp->fake_tls,fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),4+sizeof(((struct fake_tls_mod*)0)->sni)))) if (!(item=blob_collection_add_blob(&dp->fake_tls,fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),4+sizeof(((struct fake_tls_mod*)0)->sni),0)))
return false; return false;
if (!(item->extra2 = malloc(sizeof(struct fake_tls_mod)))) if (!(item->extra2 = malloc(sizeof(struct fake_tls_mod))))
return false; return false;
@@ -253,13 +254,13 @@ bool dp_fake_defaults(struct desync_profile *dp)
} }
if (blob_collection_empty(&dp->fake_unknown)) if (blob_collection_empty(&dp->fake_unknown))
{ {
if (!(item=blob_collection_add_blob(&dp->fake_unknown,NULL,256,0))) if (!(item=blob_collection_add_blob(&dp->fake_unknown,NULL,256,0,0)))
return false; return false;
memset(item->data,0,item->size); memset(item->data,0,item->size);
} }
if (blob_collection_empty(&dp->fake_quic)) if (blob_collection_empty(&dp->fake_quic))
{ {
if (!(item=blob_collection_add_blob(&dp->fake_quic,NULL,620,0))) if (!(item=blob_collection_add_blob(&dp->fake_quic,NULL,620,0,0)))
return false; return false;
memset(item->data,0,item->size); memset(item->data,0,item->size);
item->data[0] = 0x40; item->data[0] = 0x40;
@@ -269,7 +270,7 @@ bool dp_fake_defaults(struct desync_profile *dp)
{ {
if (blob_collection_empty(*fake)) if (blob_collection_empty(*fake))
{ {
if (!(item=blob_collection_add_blob(*fake,NULL,64,0))) if (!(item=blob_collection_add_blob(*fake,NULL,64,0,0)))
return false; return false;
memset(item->data,0,item->size); memset(item->data,0,item->size);
} }
@@ -297,6 +298,8 @@ struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
} }
static void dp_clear_dynamic(struct desync_profile *dp) static void dp_clear_dynamic(struct desync_profile *dp)
{ {
free(dp->fsplit_pattern);
hostlist_collection_destroy(&dp->hl_collection); hostlist_collection_destroy(&dp->hl_collection);
hostlist_collection_destroy(&dp->hl_collection_exclude); hostlist_collection_destroy(&dp->hl_collection_exclude);
ipset_collection_destroy(&dp->ips_collection); ipset_collection_destroy(&dp->ips_collection);
@@ -371,6 +374,7 @@ void cleanup_params(struct params_s *params)
#ifdef __CYGWIN__ #ifdef __CYGWIN__
strlist_destroy(&params->ssid_filter); strlist_destroy(&params->ssid_filter);
strlist_destroy(&params->nlm_filter); strlist_destroy(&params->nlm_filter);
strlist_destroy(&params->wf_raw_part);
#else #else
free(params->user); params->user=NULL; free(params->user); params->user=NULL;
#endif #endif
+26 -4
View File
@@ -68,6 +68,8 @@
#define MAX_GIDS 64 #define MAX_GIDS 64
extern const char * tld[6];
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG, LOG_TARGET_ANDROID }; enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG, LOG_TARGET_ANDROID };
struct fake_tls_mod_cache struct fake_tls_mod_cache
@@ -76,9 +78,23 @@ struct fake_tls_mod_cache
}; };
struct fake_tls_mod struct fake_tls_mod
{ {
char sni[64]; char sni[128];
uint32_t mod; uint32_t mod;
}; };
struct hostfakesplit_mod
{
char host[128];
size_t host_size;
int ordering;
};
struct fakedsplit_mod
{
int ordering;
};
struct tcp_mod
{
bool seq;
};
typedef enum {SS_NONE=0,SS_SYN,SS_SYNACK,SS_ACKSYN} t_synack_split; typedef enum {SS_NONE=0,SS_SYN,SS_SYNACK,SS_ACKSYN} t_synack_split;
@@ -102,7 +118,7 @@ struct desync_profile
// multisplit // multisplit
struct proto_pos splits[MAX_SPLITS]; struct proto_pos splits[MAX_SPLITS];
int split_count; int split_count;
struct proto_pos seqovl; struct proto_pos seqovl,hostfakesplit_midhost;
char dup_start_mode, dup_cutoff_mode; // n - packets, d - data packets, s - relative sequence char dup_start_mode, dup_cutoff_mode; // n - packets, d - data packets, s - relative sequence
bool dup_replace; bool dup_replace;
@@ -126,12 +142,17 @@ struct desync_profile
uint32_t desync_ts_increment, desync_badseq_increment, desync_badseq_ack_increment; uint32_t desync_ts_increment, desync_badseq_increment, desync_badseq_ack_increment;
struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht,fake_discord,fake_stun; struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht,fake_discord,fake_stun;
uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],fsplit_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP]; uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP];
size_t fake_syndata_size; uint8_t *fsplit_pattern;
size_t fake_syndata_size, fsplit_pattern_size;
struct fake_tls_mod tls_mod_last; struct fake_tls_mod tls_mod_last;
struct blob_item *tls_fake_last; struct blob_item *tls_fake_last;
struct hostfakesplit_mod hfs_mod;
struct fakedsplit_mod fs_mod;
struct tcp_mod tcp_mod;
int udplen_increment; int udplen_increment;
bool filter_ipv4,filter_ipv6; bool filter_ipv4,filter_ipv6;
@@ -200,6 +221,7 @@ struct params_s
#ifdef __CYGWIN__ #ifdef __CYGWIN__
struct str_list_head ssid_filter,nlm_filter; struct str_list_head ssid_filter,nlm_filter;
struct str_list_head wf_raw_part;
#else #else
bool droproot; bool droproot;
char *user; char *user;
+3 -1
View File
@@ -579,8 +579,9 @@ struct blob_item *blob_collection_add(struct blob_collection_head *head)
} }
return entry; return entry;
} }
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve) struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve, size_t offset)
{ {
if (offset>=size) return NULL;
struct blob_item *entry = calloc(1,sizeof(struct blob_item)); struct blob_item *entry = calloc(1,sizeof(struct blob_item));
if (!entry) return NULL; if (!entry) return NULL;
if (!(entry->data = malloc(size+size_reserve))) if (!(entry->data = malloc(size+size_reserve)))
@@ -591,6 +592,7 @@ struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, co
if (data) memcpy(entry->data,data,size); if (data) memcpy(entry->data,data,size);
entry->size = size; entry->size = size;
entry->size_buf = size+size_reserve; entry->size_buf = size+size_reserve;
entry->offset = offset;
// insert to the end // insert to the end
struct blob_item *itemc,*iteml=LIST_FIRST(head); struct blob_item *itemc,*iteml=LIST_FIRST(head);
+2 -1
View File
@@ -157,13 +157,14 @@ struct blob_item {
uint8_t *data; // main data blob uint8_t *data; // main data blob
size_t size; // main data blob size size_t size; // main data blob size
size_t size_buf;// main data blob allocated size size_t size_buf;// main data blob allocated size
size_t offset; // optional offset to useful data
void *extra; // any data without size void *extra; // any data without size
void *extra2; // any data without size void *extra2; // any data without size
LIST_ENTRY(blob_item) next; LIST_ENTRY(blob_item) next;
}; };
LIST_HEAD(blob_collection_head, blob_item); LIST_HEAD(blob_collection_head, blob_item);
struct blob_item *blob_collection_add(struct blob_collection_head *head); struct blob_item *blob_collection_add(struct blob_collection_head *head);
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve); struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve, size_t offset);
void blob_collection_destroy(struct blob_collection_head *head); void blob_collection_destroy(struct blob_collection_head *head);
bool blob_collection_empty(const struct blob_collection_head *head); bool blob_collection_empty(const struct blob_collection_head *head);