57 Commits
v70.4 ... v70.6

Author SHA1 Message Date
bol-van
58e73d0331 github actions: do not use broken upx 5.0.0 2025-04-07 17:52:11 +03:00
bol-van
9ebeff621a readme.en : update ver 2025-04-07 10:16:30 +03:00
bol-van
69df271a16 readme: update crypto addresses 2025-04-07 10:15:36 +03:00
bol-van
e285b2401d isakmp fake 2025-04-06 16:42:56 +03:00
bol-van
6e1e7e43bc nfqws: optimize tls mod parse 2025-04-06 11:53:57 +03:00
bol-van
d04419a60c nfqws: safety check 2025-04-06 11:43:25 +03:00
bol-van
fc1bf47e82 update changes.txt 2025-04-06 11:34:43 +03:00
bol-van
929df3f094 nfqws: support different tls mods for every tls fake 2025-04-06 11:29:58 +03:00
bol-van
7272b243cb blockcheck: optimize 2025-04-05 18:13:16 +03:00
bol-van
72d48d957a update changes.txt 2025-04-05 18:10:46 +03:00
bol-van
f4069d484a update changes.txt 2025-04-05 18:10:18 +03:00
bol-van
1c82b0a6af blockcheck: --fix seg only if multiple split pos 2025-04-05 16:35:26 +03:00
bol-van
c08e69aa65 blockcheck: --fix seg only if multiple split pos 2025-04-05 16:31:22 +03:00
bol-van
8097f08020 ipset: some pkill's do not support multiple patterns 2025-04-05 13:56:31 +03:00
bol-van
4cae291e6f blockcheck: remove fix-seg for single split 2025-04-05 12:32:16 +03:00
bol-van
82ad5508dc blockcheck: --fix-seg for tpws multisplits 2025-04-05 12:24:43 +03:00
bol-van
fa8ddcfc79 desync.h fix 2025-04-05 11:53:59 +03:00
bol-van
b560e32e18 nfqws: update default tls fake 2025-04-05 09:45:44 +03:00
bol-van
67e1aee8a8 update compile docs 2025-04-04 17:38:52 +03:00
bol-van
1d8385a9b4 update compile docs 2025-04-04 17:37:49 +03:00
bol-van
340dec62a7 update changes.txt 2025-04-04 15:13:58 +03:00
bol-van
db4585c02f remove discord custom 2025-04-04 15:03:06 +03:00
bol-van
e792ca67ef nfqws: display original SNI value 2025-04-04 14:32:37 +03:00
bol-van
e5e53db6b8 nfqws: fixes 2025-04-04 14:20:36 +03:00
bol-van
e14ee9d1fe nfqws: fix wrong and mask 2025-04-04 14:09:45 +03:00
bol-van
360506ba4e discord and stun fakes 2025-04-04 13:58:46 +03:00
bol-van
aa769e05c6 nfqws: minor optimize 2025-04-04 13:58:33 +03:00
bol-van
6b0bc7a96b nfqws: tls mod set sni 2025-04-04 13:24:02 +03:00
bol-van
93bdfdb6be nfqws: loop for multiple blob cleanup 2025-04-04 09:25:46 +03:00
bol-van
6d95eada2b Merge pull request #1316 from tie/master
nfqws: also add stun l7proto to CLI help output
2025-04-03 21:33:39 +03:00
bol-van
e452ee8688 nfqws: cosmetics 2025-04-03 21:32:28 +03:00
bol-van
6e746f94cd nfqws: help text cosmetics 2025-04-03 21:29:38 +03:00
Ivan Trubach
9fd61e5d38 nfqws: also add stun l7proto to CLI help output 2025-04-03 21:28:46 +03:00
bol-van
0c0fba4461 Merge pull request #1314 from tie/master
nfqws: detect Discord Voice IP Discovery and STUN packets
2025-04-03 21:27:10 +03:00
Ivan Trubach
056e4c588a nfqws: detect STUN message packets 2025-04-03 21:02:42 +03:00
Ivan Trubach
4b288643ac nfqws: detect Discord Voice IP Discovery packets 2025-04-03 17:55:02 +03:00
bol-van
cbdee74e5f Merge pull request #1301 from Lost-gamer/master
update discord subnets
2025-04-01 10:25:22 +03:00
bol-van
743eb5a4a2 tpws makefile support systemd target for old systems 2025-03-31 16:26:00 +03:00
Lost
4e8e3a9ed9 update discord subnets 2025-03-31 10:25:52 +03:00
bol-van
b9b91a0e68 replace tls fake google 2025-03-26 12:09:49 +03:00
bol-van
9de7b66eef update build docs 2025-03-25 13:44:27 +03:00
bol-van
a2ffa3455d nfqws: minor beautify text 2025-03-24 11:20:51 +03:00
bol-van
60b97dbed0 nfqws: remove debug printfs 2025-03-24 11:14:38 +03:00
bol-van
e56e4f5f35 update changes 2025-03-24 10:32:02 +03:00
bol-van
5305ea83c8 fakes: GGC kyber with inter-packet CRYPTO frag 2025-03-24 09:44:50 +03:00
bol-van
14b3dd459b nfqws: define reasm buffer sizes 2025-03-24 09:34:37 +03:00
bol-van
66fda2c33d nfqws: support QUIC multi packet CRYPTO fragmentation 2025-03-23 23:29:16 +03:00
bol-van
77df43b9cb nfqws: minor optimize 2025-03-22 13:03:31 +03:00
bol-van
85f2b37c88 update docs 2025-03-21 21:00:47 +03:00
bol-van
e2d600fcc6 update docs 2025-03-21 20:58:53 +03:00
bol-van
37eda0ad98 nfqws: mod skipped DLOG_ERR -> DLOG 2025-03-21 19:40:25 +03:00
bol-van
770be21e1c nfqws: fix custom tls fake fallback logic 2025-03-21 19:09:37 +03:00
bol-van
1b880d42f9 nfqws,tpws: missing va_end 2025-03-21 17:33:57 +03:00
bol-van
6387315c0b nfqws: multiple fakes 2025-03-21 17:12:36 +03:00
bol-van
3d4b395bfe ignore windivert files in nfq 2025-03-21 14:23:19 +03:00
bol-van
55950ed7d0 remove bad files 2025-03-21 14:22:28 +03:00
bol-van
f2b0341484 blockcheck: add dupsid to tls-mod 2025-03-20 18:14:35 +03:00
31 changed files with 985 additions and 489 deletions

View File

@@ -401,6 +401,7 @@ jobs:
uses: crazy-max/ghaction-upx@v3 uses: crazy-max/ghaction-upx@v3
with: with:
install-only: true install-only: true
version: v4.2.4
- name: Prepare binaries - name: Prepare binaries
shell: bash shell: bash

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@ mdig/mdig
nfq/dvtws nfq/dvtws
nfq/nfqws nfq/nfqws
nfq/winws.exe nfq/winws.exe
nfq/WinDivert*
tpws/tpws tpws/tpws
binaries/my/ binaries/my/
ipset/zapret-ip*.txt ipset/zapret-ip*.txt

View File

@@ -347,6 +347,7 @@ check_system()
UNAME=$(uname) UNAME=$(uname)
SUBSYS= SUBSYS=
FIX_SEG=
local s local s
# can be passed FWTYPE=iptables to override default nftables preference # can be passed FWTYPE=iptables to override default nftables preference
@@ -354,6 +355,7 @@ check_system()
Linux) Linux)
PKTWS="$NFQWS" PKTWS="$NFQWS"
PKTWSD=nfqws PKTWSD=nfqws
FIX_SEG='--fix-seg'
linux_fwtype linux_fwtype
[ "$FWTYPE" = iptables -o "$FWTYPE" = nftables ] || { [ "$FWTYPE" = iptables -o "$FWTYPE" = nftables ] || {
echo firewall type $FWTYPE not supported in $UNAME echo firewall type $FWTYPE not supported in $UNAME
@@ -1168,7 +1170,7 @@ pktws_curl_test_update_vary()
[ "$sec" = 0 ] || proto=tls [ "$sec" = 0 ] || proto=tls
test_has_fake $desync && { test_has_fake $desync && {
zerofake="--dpi-desync-fake-$proto=0x00000000" zerofake="--dpi-desync-fake-$proto=0x00000000"
[ "$sec" = 0 ] || tlsmod="--dpi-desync-fake-tls-mod=rnd,rndsni,padencap" [ "$sec" = 0 ] || tlsmod="--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"
@@ -1430,6 +1432,11 @@ warn_mss()
[ -n "$1" ] && echo 'WARNING ! although mss worked it may not work on all sites and will likely cause significant slowdown. it may only be required for TLS1.2, not TLS1.3' [ -n "$1" ] && echo 'WARNING ! although mss worked it may not work on all sites and will likely cause significant slowdown. it may only be required for TLS1.2, not TLS1.3'
return 0 return 0
} }
fix_seg()
{
# $1 - split-pos
[ -n "$FIX_SEG" ] && contains "$1" , && echo "$FIX_SEG"
}
tpws_check_domain_http_bypass_() tpws_check_domain_http_bypass_()
{ {
@@ -1455,7 +1462,7 @@ tpws_check_domain_http_bypass_()
done done
for s2 in '' '--hostcase' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do for s2 in '' '--hostcase' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do
for s in $splits_http ; do for s in $splits_http ; do
tpws_curl_test_update $1 $3 --split-pos=$s $s2 && [ "$SCANLEVEL" != force ] && { tpws_curl_test_update $1 $3 --split-pos=$s $(fix_seg $s) $s2 && [ "$SCANLEVEL" != force ] && {
[ "$SCANLEVEL" = quick ] && return [ "$SCANLEVEL" = quick ] && return
break break
} }
@@ -1470,7 +1477,7 @@ tpws_check_domain_http_bypass_()
s3=${mss:+--mss=$mss} s3=${mss:+--mss=$mss}
for s2 in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do for s2 in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do
for pos in $splits_tls; do for pos in $splits_tls; do
tpws_curl_test_update $1 $3 --split-pos=$pos $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { tpws_curl_test_update $1 $3 --split-pos=$pos $(fix_seg $pos) $s2 $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && {
[ "$SCANLEVEL" = quick ] && return [ "$SCANLEVEL" = quick ] && return
need_mss=0 need_mss=0
break break
@@ -1478,7 +1485,7 @@ tpws_check_domain_http_bypass_()
done done
done done
for s in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do for s in '' '--oob' '--disorder' ${oobdis:+"$oobdis"}; do
for s2 in '--tlsrec=midsld' '--tlsrec=sniext+1 --split-pos=midsld' '--tlsrec=sniext+4 --split-pos=midsld' '--tlsrec=sniext+1 --split-pos=1,midsld' '--tlsrec=sniext+4 --split-pos=1,midsld' ; do for s2 in '--tlsrec=midsld' '--tlsrec=sniext+1 --split-pos=midsld' '--tlsrec=sniext+4 --split-pos=midsld' "--tlsrec=sniext+1 --split-pos=1,midsld $FIX_SEG" "--tlsrec=sniext+4 --split-pos=1,midsld $FIX_SEG" ; do
tpws_curl_test_update $1 $3 $s2 $s $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && { tpws_curl_test_update $1 $3 $s2 $s $s3 && warn_mss $s3 && [ "$SCANLEVEL" != force ] && {
[ "$SCANLEVEL" = quick ] && return [ "$SCANLEVEL" = quick ] && return
need_mss=0 need_mss=0

View File

@@ -466,3 +466,18 @@ nfqws,tpws: optional systemd notify support. compile using 'make systemd'
nfqws,tpws: systemd instance templates for nfqws and tpws nfqws,tpws: systemd instance templates for nfqws and tpws
nfqws,tpws: separate droproot from dropcaps nfqws,tpws: separate droproot from dropcaps
tpws: detect WSL 1 and warn about non-working options tpws: detect WSL 1 and warn about non-working options
v70.5
nfqws: multiple --dpi-desync-fake-xxx
nfqws: support of inter-packet fragmented QUIC CRYPTO
v70.6
nfqws: detect Discord Voice IP discovery packets
nfqws: detect STUN message packets
nfqws: change SNI to specified value tls mod : --dpi-desync-fake-tls-mod sni=<sni>
nfqws: update default TLS ClientHello fake. firefox 136.0.4 finger, no kyber, SNI=microsoft.com
nfqws: multiple mods for multiple TLS fakes
init.d: remove 50-discord
blockcheck: use tpws --fix-seg on linux for multiple splits

View File

@@ -12,10 +12,10 @@ Other packages may be required on your distribution. Look for the errors.
examples : examples :
curl -o - https://downloads.openwrt.org/releases/23.05.5/targets/x86/64/openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64.tar.xz | tar -Jxvf - curl -o - https://downloads.openwrt.org/releases/23.05.5/targets/x86/64/openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64.tar.xz | tar -Jxv
cd openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64 cd openwrt-sdk-23.05.5-x86-64_gcc-12.3.0_musl.Linux-x86_64
curl -o - https://downloads.openwrt.org/snapshots/targets/x86/64/openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64.tar.zst | tar --zstd -xvf - curl -o - https://downloads.openwrt.org/snapshots/targets/x86/64/openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64.tar.zst | tar --zstd -xv
cd openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64 cd openwrt-sdk-x86-64_gcc-13.3.0_musl.Linux-x86_64
3) Install required libs 3) Install required libs
@@ -48,7 +48,7 @@ static build : make CFLAGS=-static package/{tpws,nfqws,mdig,ip2net}/compile
executables only : build_dir/target/<progname> executables only : build_dir/target/<progname>
ipk or apk packages : bin/packages/*/base ipk or apk packages : bin/packages/*/base
8) Installating to openwrt to use with zapret 8) Installing to openwrt to use with zapret
zapret with or without binaries should be already installed in /opt/zapret. zapret with or without binaries should be already installed in /opt/zapret.
Install ipk's or apk's with all compiled progs using opkg or apk. Install ipk's or apk's with all compiled progs using opkg or apk.

View File

@@ -1,7 +1,7 @@
debian,ubuntu : debian,ubuntu :
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libsystemd-dev
make -C /opt/zapret make -C /opt/zapret systemd
FreeBSD : FreeBSD :

View File

@@ -1,4 +1,4 @@
# zapret v70.4 # zapret v70.6
# SCAMMER WARNING # SCAMMER WARNING
@@ -174,12 +174,14 @@ nfqws takes the following parameters:
--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-http=<filename>|0xHEX ; file containing fake http request
--dpi-desync-fake-tls=<filename>|0xHEX ; file containing fake TLS ClientHello (for https) --dpi-desync-fake-tls=<filename>|0xHEX ; file containing fake TLS ClientHello (for https)
--dpi-desync-fake-tls-mod=mod[,mod] ; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,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=<filename>|0xHEX ; file containing unknown protocol fake payload
--dpi-desync-fake-syndata=<filename>|0xHEX ; file containing SYN data payload --dpi-desync-fake-syndata=<filename>|0xHEX ; file containing SYN data payload
--dpi-desync-fake-quic=<filename>|0xHEX ; file containing fake QUIC Initial --dpi-desync-fake-quic=<filename>|0xHEX ; file containing fake QUIC Initial
--dpi-desync-fake-wireguard=<filename>|0xHEX ; file containing fake wireguard handshake initiation --dpi-desync-fake-wireguard=<filename>|0xHEX ; file containing fake wireguard handshake initiation
--dpi-desync-fake-dht=<filename>|0xHEX ; file containing fake DHT (d1..e) --dpi-desync-fake-dht=<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-stun=<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=<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=<filename>|0xHEX ; udp tail fill pattern
@@ -193,13 +195,13 @@ nfqws takes the following parameters:
--hostlist-auto-fail-threshold=<int> ; how many failed attempts cause hostname to be added to auto hostlist (default : 3) --hostlist-auto-fail-threshold=<int> ; how many failed attempts cause hostname to be added to auto hostlist (default : 3)
--hostlist-auto-fail-time=<int> ; all failed attemps must be within these seconds (default : 60) --hostlist-auto-fail-time=<int> ; all failed attemps must be within these seconds (default : 60)
--hostlist-auto-retrans-threshold=<int> ; how many request retransmissions cause attempt to fail (default : 3) --hostlist-auto-retrans-threshold=<int> ; how many request retransmissions cause attempt to fail (default : 3)
--hostlist-auto-debug=<logfile> ; debug auto hostlist positives --hostlist-auto-debug=<logfile> ; debug auto hostlist positives
--new ; begin new strategy (new profile) --new ; begin new strategy (new profile)
--skip ; do not use this profile --skip ; do not use this profile
--filter-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed. --filter-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
--filter-tcp=[~]port1[-port2]|* ; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list supported. --filter-tcp=[~]port1[-port2]|* ; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list supported.
--filter-udp=[~]port1[-port2]|* ; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list supported. --filter-udp=[~]port1[-port2]|* ; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list supported.
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; L6-L7 protocol filter. multiple comma separated values allowed. --filter-l7=<proto> ; L6-L7 protocol filter. multiple comma separated values allowed. proto: http tls quic wireguard dht discord stun unknown
--ipset=<filename> ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed) --ipset=<filename> ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
--ipset-ip=<ip_list> ; comma separated fixed subnet list --ipset-ip=<ip_list> ; comma separated fixed subnet list
--ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed) --ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
@@ -265,6 +267,12 @@ Fakes are separate generated by nfqws packets carrying false information for DPI
`--dpi-desync-fooling` takes multiple comma separated values. `--dpi-desync-fooling` takes multiple comma separated values.
Multiple parameters `--dpi-desync-fake-???` are supported except for the `--dpi-desync-fake-syndata`.
Fakes are sent in the specified order. `--dpi-desync-repeats` resends each fake.
Resulting order would be : `fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake3 .....`
### FAKE mods ### FAKE mods
**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.
@@ -277,11 +285,20 @@ It's possible to use TLS Client Hello with any fingerprint and any SNI.
* `rnd`. Randomize `random` and `session id` fields. Applied on every request. * `rnd`. Randomize `random` and `session id` fields. Applied on every request.
* `rndsni`. Randomize SNI. If SNI >=7 symbols random SLD is applied with known TLD. Otherwise filled with random symbols. Applied only once at startup. * `rndsni`. Randomize SNI. If SNI >=7 symbols random SLD is applied with known TLD. Otherwise filled with random symbols. Applied only once at startup.
* `dupsid`. Copy `session ID` from original TLS Client Hello. Takes precedence over `rnd`. Applied on every request. * `dupsid`. Copy `session ID` from original TLS Client Hello. Takes precedence over `rnd`. Applied on every request.
* `sni=<sni>`. Set specified SNI value. Changes TLS fake length, fixes lengths in TLS structure. Applied once at startup before `rndsni`.
* `padencap`. Padding extension is extended by original TLS Client Hello size (including multi packet variation with kyber). Padding extension is added to the end if not present, otherwise it must be the last extension. All lengths are increased. Fake size is not changed. Can be useful if DPI does not analyze sequence numbers properly. Applied on every request. * `padencap`. Padding extension is extended by original TLS Client Hello size (including multi packet variation with kyber). Padding extension is added to the end if not present, otherwise it must be the last extension. All lengths are increased. Fake size is not changed. Can be useful if DPI does not analyze sequence numbers properly. Applied on every request.
By default if custom fake is not defined `rnd,rndsni,dupsid` mods are applied. If defined - `none`. By default if custom fake is not defined `rnd,rndsni,dupsid` mods are applied. If defined - `none`.
This behaviour is compatible with previous versions with addition of `dupsid`. This behaviour is compatible with previous versions with addition of `dupsid`.
If multiple TLS fakes are present each one takes the last mod.
If a mod is specified after fake it replaces previous mod.
This way it's possible to use different mods for every TLS fake.
If a mod is set to non-TLS fake it causes error. Use `--dpi-desync-fake-tls-mod=none'.
Example : `--dpi-desync-fake-tls=iana_org.bin --dpi-desync-fake-tls-mod=rndsni --dpi-desync-fake-tls=0xaabbccdd --dpi-desync-fake-tls-mod=none'
### TCP segmentation ### TCP segmentation
* `multisplit`. split request at specified in `--dpi-desync-split-pos` positions * `multisplit`. split request at specified in `--dpi-desync-split-pos` positions
@@ -464,7 +481,7 @@ This option can resist DPIs that track outgoing UDP packet sizes.
Requires that application protocol does not depend on udp payload size. Requires that application protocol does not depend on udp payload size.
QUIC initial packets are recognized. Decryption and hostname extraction is supported so `--hostlist` parameter will work. QUIC initial packets are recognized. Decryption and hostname extraction is supported so `--hostlist` parameter will work.
Wireguard handshake initiation and DHT packets are also recognized. Wireguard handshake initiation, DHT, STUN and [Discord Voice IP Discovery](https://discord.com/developers/docs/topics/voice-connections#ip-discovery) packets are also recognized.
For other protocols desync use `--dpi-desync-any-protocol`. For other protocols desync use `--dpi-desync-any-protocol`.
Conntrack supports udp. `--dpi-desync-cutoff` will work. UDP conntrack timeout can be set in the 4th parameter of `--ctrack-timeouts`. Conntrack supports udp. `--dpi-desync-cutoff` will work. UDP conntrack timeout can be set in the 4th parameter of `--ctrack-timeouts`.
@@ -1434,12 +1451,8 @@ If this is the case then run another script in background and add some delay the
Are welcome here : Are welcome here :
<img src=https://cdn-icons-png.flaticon.com/16/14446/14446252.png alt="USDT" style="vertical-align: middle;"/> USDT USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
```
0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E
```
<img src=https://cdn-icons-png.flaticon.com/16/5968/5968260.png alt="USDT" style="vertical-align: middle;"/> BTC BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`
```
bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve ETH `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
```

View File

@@ -1,4 +1,4 @@
# zapret v70.4 # zapret v70.6
# ВНИМАНИЕ, остерегайтесь мошенников # ВНИМАНИЕ, остерегайтесь мошенников
@@ -196,11 +196,13 @@ dvtws, собираемый из тех же исходников (см. [док
--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-http=<filename>|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному www.iana.org
--dpi-desync-fake-tls=<filename>|0xHEX ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному --dpi-desync-fake-tls=<filename>|0xHEX ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному
--dpi-desync-fake-tls-mod=mod[,mod] ; список через запятую режимов runtime модификации фейков : none,rnd,rndsni,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=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata --dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial --dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
--dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт --dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-discord=<filename>|0xHEX ; файл, содержащий фейковый пейлоад Discord протокола нахождения IP адреса для голосовых чатов для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-stun=<filename>|0xHEX ; файл, содержащий фейковый пейлоад STUN протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт --dpi-desync-fake-unknown-udp=<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=<filename>|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули
@@ -226,7 +228,7 @@ dvtws, собираемый из тех же исходников (см. [док
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии --filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую. --filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую.
--filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую. --filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую.
--filter-l7=[http|tls|quic|wireguard|dht|unknown] ; фильтр протокола L6-L7. поддерживается несколько значений через запятую. --filter-l7=<proto> ; фильтр протокола L6-L7. поддерживается несколько значений через запятую. proto : http tls quic wireguard dht discord stun unknown
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая. --ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей. --ipset-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая. --ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
@@ -320,6 +322,10 @@ dvtws, собираемый из тех же исходников (см. [док
Режимы дурения могут сочетаться в любых комбинациях. `--dpi-desync-fooling` берет множество значений через запятую. Режимы дурения могут сочетаться в любых комбинациях. `--dpi-desync-fooling` берет множество значений через запятую.
Возможно задание множества фейков через повторение парамеров `--dpi-desync-fake-???`, кроме `--dpi-desync-fake-syndata`.
Фейки будут отосланы в указанном порядке. `--dpi-desync-repeats` повторяет каждый отосланный фейк.
Итоговый порядок будет такой : `fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake3 .....`
### МОДИФИКАЦИЯ ФЕЙКОВ ### МОДИФИКАЦИЯ ФЕЙКОВ
В nfqws зашит базовый вариант фейка для TLS. Его можно переопределить опцией `--dpi-desync-fake-tls`. В nfqws зашит базовый вариант фейка для TLS. Его можно переопределить опцией `--dpi-desync-fake-tls`.
@@ -334,11 +340,22 @@ dvtws, собираемый из тех же исходников (см. [док
* `rnd`. Рандомизировать поля `random` и `session id`. Выполняется на каждый запрос. * `rnd`. Рандомизировать поля `random` и `session id`. Выполняется на каждый запрос.
* `dupsid`. Копировать `session ID` из передаваемого TLS Client Hello. Имеет приоритет над `rnd`. Выполняется на каждый запрос. * `dupsid`. Копировать `session ID` из передаваемого TLS Client Hello. Имеет приоритет над `rnd`. Выполняется на каждый запрос.
* `rndsni`. Рандомизировать SNI. Если SNI >=7 символов, применяется случайный домен 2 уровня с известным TLD, иначе заполняется случайными символами без точки. Выполняется один раз при старте. * `rndsni`. Рандомизировать SNI. Если SNI >=7 символов, применяется случайный домен 2 уровня с известным TLD, иначе заполняется случайными символами без точки. Выполняется один раз при старте.
* `sni=<sni>`. Заменить sni на указанное значение. Макс длина SNI - 63 байта. Общая длина TLS фейка и длины в структуре TLS Client Hello меняются. Выполняется один раз при старте. Если сочетается с `rndsni`, выполняется до него.
* `padencap`. Расширяется padding extension на размер передаваемого TLS Client Hello (включая многопакетный вариант с kyber). Если padding отсутствует, он добавляется в конец. Если присутствует - требуется, чтобы padding шел последним extension. Правятся все длины, чтобы создать видимость включения передаваемого TLS Client Hello в padding extension. Размер фейка не изменяется. Расчет идет на DPI, который не анализирует sequence numbers должным образом. Выполняется на каждый запрос. * `padencap`. Расширяется padding extension на размер передаваемого TLS Client Hello (включая многопакетный вариант с kyber). Если padding отсутствует, он добавляется в конец. Если присутствует - требуется, чтобы padding шел последним extension. Правятся все длины, чтобы создать видимость включения передаваемого TLS Client Hello в padding extension. Размер фейка не изменяется. Расчет идет на DPI, который не анализирует sequence numbers должным образом. Выполняется на каждый запрос.
По умолчанию если не задан собственный фейк для TLS используются модификации `rnd,rndsni,dupsid`. Если фейк задан, используется `none`. По умолчанию если не задан собственный фейк для TLS используются модификации `rnd,rndsni,dupsid`. Если фейк задан, используется `none`.
Это соответствует поведению программы более старых версий с добавлением функции `dupsid`. Это соответствует поведению программы более старых версий с добавлением функции `dupsid`.
Если задан режим модификации и имеется множество TLS фейков, к каждому из них применяется последний режим модификации.
Если режим модификации задан после фейка, то он замещает предыдущий режим.
Таким образом можно использовать разные режимы модификации для разных фейков.
При невозможности модифицировать фейк на этапе запуска программа завершается с ошибкой.
Если сначала идет TLS фейк, для него задан режим однократной модификации, затем идет не TLS фейк, то будет ошибка.
Нужно использовать `--dpi-desync-fake-tls-mod=none'.
Пример : `--dpi-desync-fake-tls=iana_org.bin --dpi-desync-fake-tls-mod=rndsni --dpi-desync-fake-tls=0xaabbccdd --dpi-desync-fake-tls-mod=none'
### TCP СЕГМЕНТАЦИЯ ### TCP СЕГМЕНТАЦИЯ
* `multisplit`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях. * `multisplit`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях.
@@ -568,7 +585,8 @@ chrome рандомизирует фингерпринт TLS. SNI может о
На текущий момент работает только с DHT. На текущий момент работает только с DHT.
Поддерживается определение пакетов QUIC Initial с расшифровкой содержимого и имени хоста, то есть параметр Поддерживается определение пакетов QUIC Initial с расшифровкой содержимого и имени хоста, то есть параметр
`--hostlist` будет работать. `--hostlist` будет работать.
Определяются пакеты wireguard handshake initiation и DHT (начинается с 'd1', кончается 'e'). Определяются пакеты wireguard handshake initiation, DHT (начинается с 'd1', кончается 'e'), STUN и
[Discord Voice IP Discovery](https://discord.com/developers/docs/topics/voice-connections#ip-discovery).
Для десинхронизации других протоколов обязательно указывать `--dpi-desync-any-protocol`. Для десинхронизации других протоколов обязательно указывать `--dpi-desync-any-protocol`.
Реализован conntrack для udp. Можно пользоваться --dpi-desync-cutoff. Таймаут conntrack для udp Реализован conntrack для udp. Можно пользоваться --dpi-desync-cutoff. Таймаут conntrack для udp
можно изменить 4-м параметром в `--ctrack-timeouts`. можно изменить 4-м параметром в `--ctrack-timeouts`.
@@ -2350,12 +2368,8 @@ VPS можно приобрести в множестве мест. Сущест
## Поддержать разработчика ## Поддержать разработчика
<img src=https://cdn-icons-png.flaticon.com/16/14446/14446252.png alt="USDT" style="vertical-align: middle;"/> USDT USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
```
0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E
```
<img src=https://cdn-icons-png.flaticon.com/16/5968/5968260.png alt="USDT" style="vertical-align: middle;"/> BTC BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`
```
bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve ETH `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
```

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
files/fake/stun.bin Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,74 @@
# this custom script demonstrates how to launch extra nfqws instance limited by ipset. ipv4 only.
# can override in config :
NFQWS_OPT_DESYNC_NFQWS_MY1="${NFQWS_OPT_DESYNC_NFQWS_MY1:---dpi-desync=fake --dpi-desync-repeats=6 --dpi-desync-any-protocol}"
NFQWS_MY1_PORTS=${NFQWS_MY1_PORTS:-6000-6009}
NFQWS_MY1_SUBNETS="${NFQWS_MY1_SUBNETS:-34.0.48.0/21 34.0.56.0/23 34.0.59.0/24 34.0.60.0/24 34.0.62.0/23}"
alloc_dnum DNUM_NFQWS_MY1
alloc_qnum QNUM_NFQWS_MY1
NFQWS_MY1_SET_NAME=my1nfqws4
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
local opt="--qnum=$QNUM_NFQWS_MY1 $NFQWS_OPT_DESYNC_NFQWS_MY1"
do_nfqws $1 $DNUM_NFQWS_MY1 "$opt"
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local f
local first_packets_only="$ipt_connbytes 1:3"
local NFQWS_MY1_PORTS_IPT=$(replace_char - : $NFQWS_MY1_PORTS)
local dest_set="-m set --match-set $NFQWS_MY1_SET_NAME dst"
local subnet
local DISABLE_IPV6=1
[ "$1" = 1 ] && {
ipset create $NFQWS_MY1_SET_NAME hash:net hashsize 8192 maxelem 4096 2>/dev/null
ipset flush $NFQWS_MY1_SET_NAME
for subnet in $NFQWS_MY1_SUBNETS; do
echo add $NFQWS_MY1_SET_NAME $subnet
done | ipset -! restore
}
f="-p udp -m multiport --dports $NFQWS_MY1_PORTS_IPT"
fw_nfqws_post $1 "$f $first_packets_only $dest_set" "" $QNUM_NFQWS_MY1
[ "$1" = 1 ] || {
ipset destroy $NFQWS_MY1_SET_NAME 2>/dev/null
}
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local f
local first_packets_only="$nft_connbytes 1-3"
local dest_set="ip daddr @$NFQWS_MY1_SET_NAME"
local subnets
local DISABLE_IPV6=1
make_comma_list subnets $NFQWS_MY1_SUBNETS
nft_create_set $NFQWS_MY1_SET_NAME "type ipv4_addr; size 4096; auto-merge; flags interval;"
nft_flush_set $NFQWS_MY1_SET_NAME
nft_add_set_element $NFQWS_MY1_SET_NAME "$subnets"
f="udp dport {$NFQWS_MY1_PORTS}"
nft_fw_nfqws_post "$f $first_packets_only $dest_set" "" $QNUM_NFQWS_MY1
}
zapret_custom_firewall_nft_flush()
{
# this function is called after all nft fw rules are deleted
# however sets are not deleted. it's desired to clear sets here.
nft_del_set $NFQWS_MY1_SET_NAME 2>/dev/null
}

View File

@@ -274,7 +274,9 @@ hup_zapret_daemons()
if exists killall; then if exists killall; then
killall -HUP tpws nfqws dvtws 2>/dev/null killall -HUP tpws nfqws dvtws 2>/dev/null
elif exists pkill; then elif exists pkill; then
pkill -HUP ^tpws$ ^nfqws$ ^dvtws$ pkill -HUP ^tpws$
pkill -HUP ^nfqws$
pkill -HUP ^dvtws$
else else
echo no mass killer available ! cant HUP zapret daemons echo no mass killer available ! cant HUP zapret daemons
fi fi

Binary file not shown.

Binary file not shown.

View File

@@ -16,56 +16,73 @@ const char *fake_http_request_default = "GET / HTTP/1.1\r\nHost: www.iana.org\r\
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n"
"Accept-Encoding: gzip, deflate, br\r\n\r\n"; "Accept-Encoding: gzip, deflate, br\r\n\r\n";
// random : +11 size 32 // SNI - www.microsoft.com
// random : +44 size 32 const uint8_t fake_tls_clienthello_default[680] = {
// sni : gatech.edu +125 size 11 0x16, 0x03, 0x01, 0x02, 0xa3, 0x01, 0x00, 0x02, 0x9f, 0x03, 0x03, 0x41,
const uint8_t fake_tls_clienthello_default[648] = { 0x88, 0x82, 0x2d, 0x4f, 0xfd, 0x81, 0x48, 0x9e, 0xe7, 0x90, 0x65, 0x1f,
0x16,0x03,0x01,0x02,0x83,0x01,0x00,0x02,0x7f,0x03,0x03,0x98,0xfb,0x69,0x1d,0x31, 0xba, 0x05, 0x7b, 0xff, 0xa7, 0x5a, 0xf9, 0x5b, 0x8a, 0x8f, 0x45, 0x8b,
0x66,0xc4,0xd8,0x07,0x25,0x2b,0x74,0x47,0x01,0x44,0x09,0x08,0xcf,0x13,0x67,0xe0, 0x41, 0xf0, 0x3d, 0x1b, 0xdd, 0xe3, 0xf8, 0x20, 0x9b, 0x23, 0xa5, 0xd2,
0x46,0x19,0x1f,0xcb,0xee,0xe6,0x8e,0x33,0xb9,0x91,0xa0,0x20,0xf2,0xed,0x56,0x73, 0x21, 0x1e, 0x9f, 0xe7, 0x85, 0x6c, 0xfc, 0x61, 0x80, 0x3a, 0x3f, 0xba,
0xa4,0x0a,0xce,0xa6,0xad,0xd2,0xfd,0x71,0xb8,0xb9,0xfd,0x06,0x0e,0xdd,0xf0,0x57, 0xb9, 0x60, 0xba, 0xb3, 0x0e, 0x98, 0x27, 0x6c, 0xf7, 0x38, 0x28, 0x65,
0x37,0x7d,0x96,0xb5,0x80,0x6e,0x54,0xe2,0x15,0xce,0x5f,0xff,0x00,0x22,0x13,0x01, 0x80, 0x5d, 0x40, 0x38, 0x00, 0x22, 0x13, 0x01, 0x13, 0x03, 0x13, 0x02,
0x13,0x03,0x13,0x02,0xc0,0x2b,0xc0,0x2f,0xcc,0xa9,0xcc,0xa8,0xc0,0x2c,0xc0,0x30, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2c, 0xc0, 0x30,
0xc0,0x0a,0xc0,0x09,0xc0,0x13,0xc0,0x14,0x00,0x9c,0x00,0x9d,0x00,0x2f,0x00,0x35, 0xc0, 0x0a, 0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x9c, 0x00, 0x9d,
0x01,0x00,0x02,0x14,0x00,0x00,0x00,0x0f,0x00,0x0d,0x00,0x00,0x0a,0x67,0x61,0x74, 0x00, 0x2f, 0x00, 0x35, 0x01, 0x00, 0x02, 0x34, 0x00, 0x00, 0x00, 0x16,
0x65,0x63,0x68,0x2e,0x65,0x64,0x75,0x00,0x17,0x00,0x00,0xff,0x01,0x00,0x01,0x00, 0x00, 0x14, 0x00, 0x00, 0x11, 0x77, 0x77, 0x77, 0x2e, 0x6d, 0x69, 0x63,
0x00,0x0a,0x00,0x0e,0x00,0x0c,0x00,0x1d,0x00,0x17,0x00,0x18,0x00,0x19,0x01,0x00, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x17,
0x01,0x01,0x00,0x0b,0x00,0x02,0x01,0x00,0x00,0x10,0x00,0x0e,0x00,0x0c,0x02,0x68, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x0e, 0x00,
0x32,0x08,0x68,0x74,0x74,0x70,0x2f,0x31,0x2e,0x31,0x00,0x05,0x00,0x05,0x01,0x00, 0x0c, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x01, 0x00, 0x01,
0x00,0x00,0x00,0x00,0x22,0x00,0x0a,0x00,0x08,0x04,0x03,0x05,0x03,0x06,0x03,0x02, 0x01, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
0x03,0x00,0x33,0x00,0x6b,0x00,0x69,0x00,0x1d,0x00,0x20,0x72,0xe5,0xce,0x58,0x31, 0x10, 0x00, 0x0e, 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74,
0x3c,0x08,0xaa,0x2f,0xa8,0x40,0xe7,0x7a,0xdf,0x46,0x5b,0x63,0x62,0xc7,0xfa,0x49, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00,
0x18,0xac,0xa1,0x00,0x7c,0x42,0xc5,0x02,0x94,0x5c,0x44,0x00,0x17,0x00,0x41,0x04, 0x00, 0x00, 0x00, 0x22, 0x00, 0x0a, 0x00, 0x08, 0x04, 0x03, 0x05, 0x03,
0x8f,0x3e,0x5f,0xd4,0x7f,0x37,0x47,0xd3,0x33,0x70,0x38,0x7f,0x11,0x35,0xc1,0x55, 0x06, 0x03, 0x02, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, 0x33, 0x00, 0x6b,
0x8a,0x6c,0xc7,0x5a,0xd4,0xf7,0x31,0xbb,0x9e,0xee,0xd1,0x8f,0x74,0xdd,0x9b,0xbb, 0x00, 0x69, 0x00, 0x1d, 0x00, 0x20, 0x69, 0x15, 0x16, 0x29, 0x6d, 0xad,
0x91,0xa1,0x72,0xda,0xeb,0xf6,0xc6,0x82,0x84,0xfe,0xb7,0xfd,0x7b,0xe1,0x9f,0xd2, 0xd5, 0x68, 0x88, 0x27, 0x2f, 0xde, 0xaf, 0xac, 0x3c, 0x4c, 0xa4, 0xe4,
0xb9,0x3e,0x83,0xa6,0x9c,0xac,0x81,0xe2,0x00,0xd5,0x19,0x55,0x91,0xa7,0x0c,0x29, 0xd8, 0xc8, 0xfb, 0x41, 0x87, 0xf4, 0x76, 0x4e, 0x0e, 0xfa, 0x64, 0xc4,
0x00,0x2b,0x00,0x05,0x04,0x03,0x04,0x03,0x03,0x00,0x0d,0x00,0x18,0x00,0x16,0x04, 0xe9, 0x29, 0x00, 0x17, 0x00, 0x41, 0x04, 0xfe, 0x62, 0xb9, 0x08, 0xc8,
0x03,0x05,0x03,0x06,0x03,0x08,0x04,0x08,0x05,0x08,0x06,0x04,0x01,0x05,0x01,0x06, 0xc3, 0x2a, 0xb9, 0x87, 0x37, 0x84, 0x42, 0x6b, 0x5c, 0xcd, 0xc9, 0xca,
0x01,0x02,0x03,0x02,0x01,0x00,0x1c,0x00,0x02,0x40,0x01,0xfe,0x0d,0x01,0x19,0x00, 0x62, 0x38, 0xd3, 0xd9, 0x99, 0x8a, 0xc4, 0x2d, 0xc6, 0xd0, 0xa3, 0x60,
0x00,0x01,0x00,0x01,0xfe,0x00,0x20,0xae,0x8b,0x30,0x3c,0xf0,0xa9,0x0d,0xa1,0x69, 0xb2, 0x12, 0x54, 0x41, 0x8e, 0x52, 0x5e, 0xe3, 0xab, 0xf9, 0xc2, 0x07,
0x95,0xb8,0xe2,0xed,0x08,0x6d,0x48,0xdf,0xf7,0x5b,0x9d,0x66,0xef,0x15,0x97,0xbc, 0x81, 0xdc, 0xf8, 0xf2, 0x6a, 0x91, 0x40, 0x2f, 0xcb, 0xa4, 0xff, 0x6f,
0x2c,0x99,0x91,0x12,0x7a,0x35,0xd0,0x00,0xef,0xb1,0x8d,0xff,0x61,0x57,0x52,0xef, 0x24, 0xc7, 0x4d, 0x77, 0x77, 0x2d, 0x6f, 0xe0, 0x77, 0xaa, 0x92, 0x00,
0xd6,0xea,0xbf,0xf3,0x6d,0x78,0x14,0x38,0xff,0xeb,0x58,0xe8,0x9d,0x59,0x4b,0xd5, 0x2b, 0x00, 0x05, 0x04, 0x03, 0x04, 0x03, 0x03, 0x00, 0x0d, 0x00, 0x18,
0x9f,0x59,0x12,0xf9,0x03,0x9a,0x20,0x37,0x85,0x77,0xb1,0x4c,0xd8,0xef,0xa6,0xc8, 0x00, 0x16, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05,
0x54,0x8d,0x07,0x27,0x95,0xce,0xd5,0x37,0x4d,0x69,0x18,0xd4,0xfd,0x5e,0xdf,0x64, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01,
0xcc,0x10,0x2f,0x7f,0x0e,0xc9,0xfd,0xd4,0xd0,0x18,0x61,0x1b,0x57,0x8f,0x41,0x7f, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x1c, 0x00, 0x02, 0x40, 0x01,
0x6f,0x4f,0x5c,0xad,0x04,0xc6,0x5e,0x74,0x54,0x87,0xba,0x28,0xe6,0x11,0x0b,0x9d, 0x00, 0x1b, 0x00, 0x07, 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0xfe,
0x3f,0x0b,0x6d,0xf4,0x2d,0xfc,0x31,0x4e,0xfd,0x49,0xe7,0x15,0x96,0xaf,0xee,0x9a, 0x0d, 0x01, 0x19, 0x00, 0x00, 0x01, 0x00, 0x03, 0x21, 0x00, 0x20, 0x62,
0x48,0x1b,0xae,0x5e,0x7c,0x20,0xbe,0xb4,0xec,0x68,0xb6,0x74,0x22,0xa0,0xec,0xff, 0xe8, 0x83, 0xd8, 0x97, 0x05, 0x8a, 0xbe, 0xa1, 0xf2, 0x63, 0x4e, 0xce,
0x19,0x96,0xe4,0x10,0x8f,0x3c,0x91,0x88,0xa1,0xcc,0x78,0xef,0x4e,0x0e,0xe3,0xb6, 0x93, 0x84, 0x8e, 0xcf, 0xe7, 0xdd, 0xb2, 0xe4, 0x87, 0x06, 0xac, 0x11,
0x57,0x8c,0x33,0xef,0xaa,0xb0,0x1d,0x45,0x1c,0x02,0x4c,0xe2,0x80,0x30,0xe8,0x48, 0x19, 0xbe, 0x0e, 0x71, 0x87, 0xf1, 0xa6, 0x00, 0xef, 0xd8, 0x6b, 0x27,
0x7a,0x09,0x71,0x94,0x7c,0xb6,0x75,0x81,0x1c,0xae,0xe3,0x3f,0xde,0xea,0x2b,0x45, 0x5e, 0xc0, 0xa7, 0x5d, 0x42, 0x4e, 0x8c, 0xdc, 0xf3, 0x9f, 0x1c, 0x51,
0xcc,0xe3,0x64,0x09,0xf7,0x60,0x26,0x0c,0x7d,0xad,0x55,0x65,0xb6,0xf5,0x85,0x04, 0x62, 0xef, 0xff, 0x5b, 0xed, 0xc8, 0xfd, 0xee, 0x6f, 0xbb, 0x88, 0x9b,
0x64,0x2f,0x97,0xd0,0x6a,0x06,0x36,0xcd,0x25,0xda,0x51,0xab,0xd6,0xf7,0x5e,0xeb, 0xb1, 0x30, 0x9c, 0x66, 0x42, 0xab, 0x0f, 0x66, 0x89, 0x18, 0x8b, 0x11,
0xd4,0x03,0x39,0xa4,0xc4,0x2a,0x9c,0x17,0xe8,0xb0,0x9f,0xc0,0xd3,0x8c,0x76,0xdd, 0xc1, 0x6d, 0xe7, 0x2a, 0xeb, 0x96, 0x3b, 0x7f, 0x52, 0x78, 0xdb, 0xf8,
0xa1,0x0b,0x76,0x9f,0x23,0xfa,0xed,0xfb,0xd7,0x78,0x0f,0x00,0xf7,0x45,0x03,0x04, 0x6d, 0x04, 0xf7, 0x95, 0x1a, 0xa8, 0xf0, 0x64, 0x52, 0x07, 0x39, 0xf0,
0x84,0x66,0x6b,0xec,0xc7,0xed,0xbc,0xe4 0xa8, 0x1d, 0x0d, 0x16, 0x36, 0xb7, 0x18, 0x0e, 0xc8, 0x44, 0x27, 0xfe,
0xf3, 0x31, 0xf0, 0xde, 0x8c, 0x74, 0xf5, 0xa1, 0xd8, 0x8f, 0x6f, 0x45,
0x97, 0x69, 0x79, 0x5e, 0x2e, 0xd4, 0xb0, 0x2c, 0x0c, 0x1a, 0x6f, 0xcc,
0xce, 0x90, 0xc7, 0xdd, 0xc6, 0x60, 0x95, 0xf3, 0xc2, 0x19, 0xde, 0x50,
0x80, 0xbf, 0xde, 0xf2, 0x25, 0x63, 0x15, 0x26, 0x63, 0x09, 0x1f, 0xc5,
0xdf, 0x32, 0xf5, 0xea, 0x9c, 0xd2, 0xff, 0x99, 0x4e, 0x67, 0xa2, 0xe5,
0x1a, 0x94, 0x85, 0xe3, 0xdf, 0x36, 0xa5, 0x83, 0x4b, 0x0a, 0x1c, 0xaf,
0xd7, 0x48, 0xc9, 0x4b, 0x8a, 0x27, 0xdd, 0x58, 0x7f, 0x95, 0xf2, 0x6b,
0xde, 0x2b, 0x12, 0xd3, 0xec, 0x4d, 0x69, 0x37, 0x9c, 0x13, 0x9b, 0x16,
0xb0, 0x45, 0x52, 0x38, 0x77, 0x69, 0xef, 0xaa, 0x65, 0x19, 0xbc, 0xc2,
0x93, 0x4d, 0xb0, 0x1b, 0x7f, 0x5b, 0x41, 0xff, 0xaf, 0xba, 0x50, 0x51,
0xc3, 0xf1, 0x27, 0x09, 0x25, 0xf5, 0x60, 0x90, 0x09, 0xb1, 0xe5, 0xc0,
0xc7, 0x42, 0x78, 0x54, 0x3b, 0x23, 0x19, 0x7d, 0x8e, 0x72, 0x13, 0xb4,
0xd3, 0xcd, 0x63, 0xb6, 0xc4, 0x4a, 0x28, 0x3d, 0x45, 0x3e, 0x8b, 0xdb,
0x84, 0x4f, 0x78, 0x64, 0x30, 0x69, 0xe2, 0x1b
}; };
#define PKTDATA_MAXDUMP 32 #define PKTDATA_MAXDUMP 32
#define IP_MAXDUMP 80 #define IP_MAXDUMP 80
#define TCP_MAX_REASM 16384
#define UDP_MAX_REASM 16384
bool desync_valid_zero_stage(enum dpi_desync_mode mode) bool desync_valid_zero_stage(enum dpi_desync_mode mode)
{ {
return mode==DESYNC_SYNACK || mode==DESYNC_SYNDATA; return mode==DESYNC_SYNACK || mode==DESYNC_SYNDATA;
@@ -606,45 +623,53 @@ static uint16_t IP4_IP_ID_FIX(const struct ip *ip)
// fake_mod buffer must at least sizeof(desync_profile->fake_tls) // fake_mod buffer must at least sizeof(desync_profile->fake_tls)
// size does not change // size does not change
// return : true - altered, false - not altered // return : true - altered, false - not altered
static bool runtime_tls_mod(const struct desync_profile *dp, uint8_t *fake_mod, const uint8_t *payload, size_t payload_len) static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache, const struct fake_tls_mod *tls_mod, const uint8_t *fake_data, size_t fake_data_size, const uint8_t *payload, size_t payload_len, uint8_t *fake_mod)
{ {
bool b=false; bool b=false;
if (dp->fake_tls_mod & FAKE_TLS_MOD_PADENCAP) if (modcache) // it's filled only if it's TLS
{ {
size_t sz_rec = pntoh16(dp->fake_tls+3) + payload_len; if (tls_mod->mod & FAKE_TLS_MOD_PADENCAP)
size_t sz_handshake = pntoh24(dp->fake_tls+6) + payload_len;
size_t sz_ext = pntoh16(dp->fake_tls+dp->fake_tls_extlen_offset) + payload_len;
size_t sz_pad = pntoh16(dp->fake_tls+dp->fake_tls_padlen_offset) + payload_len;
if ((sz_rec & ~0xFFFF) || (sz_handshake & ~0xFFFFFF) || (sz_ext & ~0xFFFF) || (sz_pad & ~0xFFFF))
DLOG("cannot apply padencap tls mod. length overflow.\n");
else
{ {
memcpy(fake_mod,dp->fake_tls,dp->fake_tls_size); size_t sz_rec = pntoh16(fake_data+3) + payload_len;
phton16(fake_mod+3,(uint16_t)sz_rec); size_t sz_handshake = pntoh24(fake_data+6) + payload_len;
phton24(fake_mod+6,(uint32_t)sz_handshake); size_t sz_ext = pntoh16(fake_data+modcache->extlen_offset) + payload_len;
phton16(fake_mod+dp->fake_tls_extlen_offset,(uint16_t)sz_ext); size_t sz_pad = pntoh16(fake_data+modcache->padlen_offset) + payload_len;
phton16(fake_mod+dp->fake_tls_padlen_offset,(uint16_t)sz_pad); if ((sz_rec & ~0xFFFF) || (sz_handshake & ~0xFFFFFF) || (sz_ext & ~0xFFFF) || (sz_pad & ~0xFFFF))
b=true; DLOG("fake[%d] cannot apply padencap tls mod. length overflow.\n", fake_n);
else
{
memcpy(fake_mod,fake_data,fake_data_size);
phton16(fake_mod+3,(uint16_t)sz_rec);
phton24(fake_mod+6,(uint32_t)sz_handshake);
phton16(fake_mod+modcache->extlen_offset,(uint16_t)sz_ext);
phton16(fake_mod+modcache->padlen_offset,(uint16_t)sz_pad);
b=true;
DLOG("fake[%d] applied padencap tls mod. sizes increased by %zu bytes.\n", fake_n, payload_len);
}
} }
} if (tls_mod->mod & FAKE_TLS_MOD_RND)
if (dp->fake_tls_mod & FAKE_TLS_MOD_RND)
{
if (!b) memcpy(fake_mod,dp->fake_tls,dp->fake_tls_size);
fill_random_bytes(fake_mod+11,32); // random
fill_random_bytes(fake_mod+44,fake_mod[43]); // session id
b=true;
}
if (dp->fake_tls_mod & FAKE_TLS_MOD_DUP_SID)
{
if (dp->fake_tls[43]!=payload[43])
DLOG("cannot apply dupsid tls mod. fake and orig session id length mismatch.\n");
else if (payload_len<(44+payload[43]))
DLOG("cannot apply dupsid tls mod. data payload is not valid.\n");
else
{ {
if (!b) memcpy(fake_mod,dp->fake_tls,dp->fake_tls_size); if (!b) memcpy(fake_mod,fake_data,fake_data_size);
memcpy(fake_mod+44,payload+44,fake_mod[43]); // session id fill_random_bytes(fake_mod+11,32); // random
fill_random_bytes(fake_mod+44,fake_mod[43]); // session id
b=true; b=true;
DLOG("fake[%d] applied rnd tls mod\n", fake_n);
}
if (tls_mod->mod & FAKE_TLS_MOD_DUP_SID)
{
if (payload_len<44)
DLOG("fake[%d] cannot apply dupsid tls mod. data payload is too short.\n",fake_n);
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);
else if (payload_len<(44+payload[43]))
DLOG("fake[%d] cannot apply dupsid tls mod. data payload is not valid.\n",fake_n);
else
{
if (!b) memcpy(fake_mod,fake_data,fake_data_size);
memcpy(fake_mod+44,payload+44,fake_mod[43]); // session id
b=true;
DLOG("fake[%d] applied dupsid tls mod\n", fake_n);
}
} }
} }
return b; return b;
@@ -880,8 +905,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (!(dis->tcp->th_flags & TH_SYN) && dis->len_payload) if (!(dis->tcp->th_flags & TH_SYN) && dis->len_payload)
{ {
const uint8_t *fake; struct blob_collection_head *fake;
size_t fake_size;
char host[256]; char host[256];
bool bHaveHost=false; bool bHaveHost=false;
uint8_t *p, *phost=NULL; uint8_t *p, *phost=NULL;
@@ -893,7 +918,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
int i; int i;
uint16_t ip_id; uint16_t ip_id;
t_l7proto l7proto = UNKNOWN; t_l7proto l7proto = UNKNOWN;
uint8_t fake_mod[sizeof(dp->fake_tls)];
if (replay) if (replay)
{ {
@@ -952,7 +976,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
!(ctrack->req_seq_finalized && seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end))) !(ctrack->req_seq_finalized && seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end)))
{ {
// do not reconstruct unexpected large payload (they are feeding garbage ?) // do not reconstruct unexpected large payload (they are feeding garbage ?)
if (!reasm_orig_start(ctrack,IPPROTO_TCP,TLSRecordLen(dis->data_payload),16384,dis->data_payload,dis->len_payload)) if (!reasm_orig_start(ctrack,IPPROTO_TCP,TLSRecordLen(dis->data_payload),TCP_MAX_REASM,dis->data_payload,dis->len_payload))
{ {
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
return verdict; return verdict;
@@ -1183,16 +1207,13 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
switch(l7proto) switch(l7proto)
{ {
case HTTP: case HTTP:
fake = dp->fake_http; fake = &dp->fake_http;
fake_size = dp->fake_http_size;
break; break;
case TLS: case TLS:
fake = runtime_tls_mod(dp,fake_mod,rdata_payload,rlen_payload) ? fake_mod : dp->fake_tls; fake = &dp->fake_tls;
fake_size = dp->fake_tls_size;
break; break;
default: default:
fake = dp->fake_unknown; fake = &dp->fake_unknown;
fake_size = dp->fake_unknown_size;
break; break;
} }
if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER) if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)
@@ -1273,13 +1294,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
else else
seqovl_pos = 0; seqovl_pos = 0;
// we do not need reasm buffer anymore
reasm_orig_cancel(ctrack);
rdata_payload=NULL;
uint32_t fooling_orig = FOOL_NONE; uint32_t fooling_orig = FOOL_NONE;
bool bFake = false; bool bFake = false;
pkt1_len = sizeof(pkt1);
switch(dp->desync_mode) switch(dp->desync_mode)
{ {
case DESYNC_FAKE_KNOWN: case DESYNC_FAKE_KNOWN:
@@ -1291,28 +1307,69 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
} }
case DESYNC_FAKE: case DESYNC_FAKE:
if (reasm_offset) break; if (reasm_offset) break;
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
fake, fake_size, pkt1, &pkt1_len))
{ {
return verdict; struct blob_item *fake_item;
uint8_t *fake_data;
uint8_t fake_data_buf[FAKE_MAX_TCP];
int n=0;
ip_id = IP4_IP_ID_FIX(dis->ip);
LIST_FOREACH(fake_item, fake, next)
{
n++;
switch(l7proto)
{
case TLS:
if ((fake_item->size <= sizeof(fake_data_buf)) &&
runtime_tls_mod(n,(struct fake_tls_mod_cache *)fake_item->extra,(struct fake_tls_mod *)fake_item->extra2, fake_item->data, fake_item->size, rdata_payload, rlen_payload, fake_data_buf))
{
fake_data = fake_data_buf;
break;
}
default:
fake_data = fake_item->data;
}
pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
ttl_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
fake_data, fake_item->size, pkt1, &pkt1_len))
{
reasm_orig_cancel(ctrack);
return verdict;
}
DLOG("sending fake[%d] : ", n);
hexdump_limited_dlog(fake_data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
{
reasm_orig_cancel(ctrack);
return verdict;
}
ip_id=IP4_IP_ID_NEXT(ip_id);
}
} }
DLOG("sending fake : ");
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
bFake = true; bFake = true;
break; break;
case DESYNC_RST: case DESYNC_RST:
case DESYNC_RSTACK: case DESYNC_RSTACK:
if (reasm_offset) break; if (reasm_offset) break;
pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode==DESYNC_RSTACK ? TH_ACK: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), dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), ttl_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
NULL, 0, pkt1, &pkt1_len)) NULL, 0, pkt1, &pkt1_len))
{ {
reasm_orig_cancel(ctrack);
return verdict; return verdict;
} }
DLOG("sending fake RST/RSTACK\n"); DLOG("sending fake RST/RSTACK\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
{
reasm_orig_cancel(ctrack);
return verdict;
}
bFake = true; bFake = true;
break; break;
case DESYNC_HOPBYHOP: case DESYNC_HOPBYHOP:
@@ -1323,8 +1380,12 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
(!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 && (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);
rdata_payload=NULL;
pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, 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, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), ttl_orig,0,0,IP6_FLOW(dis->ip6),
fooling_orig,0,0, fooling_orig,0,0,
dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
{ {
@@ -1341,11 +1402,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
break; break;
} }
if (bFake) // we do not need reasm buffer anymore
{ reasm_orig_cancel(ctrack);
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) rdata_payload=NULL;
return verdict;
}
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)
@@ -1875,8 +1934,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
if (dis->len_payload) if (dis->len_payload)
{ {
const uint8_t *fake; struct blob_collection_head *fake;
size_t fake_size;
char host[256]; char host[256];
bool bHaveHost=false; bool bHaveHost=false;
uint16_t ip_id; uint16_t ip_id;
@@ -1917,29 +1975,82 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
return verdict; // cannot be first packet return verdict; // cannot be first packet
} }
} }
uint8_t defrag[UDP_MAX_REASM];
uint8_t defrag[16384];
size_t hello_offset, hello_len, defrag_len = sizeof(defrag); size_t hello_offset, hello_len, defrag_len = sizeof(defrag);
if (QUICDefragCrypto(pclean,clean_len,defrag,&defrag_len)) bool bFull;
if (QUICDefragCrypto(pclean,clean_len,defrag,&defrag_len,&bFull))
{ {
bool bIsHello = IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len); if (bFull)
bool bReqFull = bIsHello ? IsTLSHandshakeFull(defrag+hello_offset,hello_len) : false;
DLOG(bIsHello ? bReqFull ? "packet contains full TLS ClientHello\n" : "packet contains partial TLS ClientHello\n" : "packet does not contain TLS ClientHello\n");
if (ctrack)
{ {
if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig)) DLOG("QUIC initial contains CRYPTO with full fragment coverage\n");
bool bIsHello = IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len);
bool bReqFull = bIsHello ? IsTLSHandshakeFull(defrag+hello_offset,hello_len) : false;
DLOG(bIsHello ? bReqFull ? "packet contains full TLS ClientHello\n" : "packet contains partial TLS ClientHello\n" : "packet does not contain TLS ClientHello\n");
if (ctrack)
{ {
// preallocate max buffer to avoid reallocs that cause memory copy if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig))
if (!reasm_orig_start(ctrack,IPPROTO_UDP,16384,16384,clean,clean_len)) {
// preallocate max buffer to avoid reallocs that cause memory copy
if (!reasm_orig_start(ctrack,IPPROTO_UDP,UDP_MAX_REASM,UDP_MAX_REASM,clean,clean_len))
{
reasm_orig_cancel(ctrack);
return verdict;
}
}
if (!ReasmIsEmpty(&ctrack->reasm_orig))
{
verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6);
if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload))
{
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
}
else
{
DLOG_ERR("rawpacket_queue failed !\n");
reasm_orig_cancel(ctrack);
return verdict;
}
if (bReqFull)
{
replay_queue(&ctrack->delayed);
reasm_orig_fin(ctrack);
}
return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt);
}
}
if (bIsHello)
{
bHaveHost = TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, sizeof(host), TLS_PARTIALS_ENABLE);
if (!bHaveHost && dp->desync_skip_nosni)
{ {
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
DLOG("not applying tampering to QUIC ClientHello without hostname in the SNI\n");
return verdict; return verdict;
} }
} }
if (!ReasmIsEmpty(&ctrack->reasm_orig)) else
{ {
if (!quic_reasm_cancel(ctrack,"QUIC initial without ClientHello")) return verdict;
}
}
else
{
DLOG("QUIC initial contains CRYPTO with partial fragment coverage\n");
if (ctrack)
{
if (ReasmIsEmpty(&ctrack->reasm_orig))
{
// preallocate max buffer to avoid reallocs that cause memory copy
if (!reasm_orig_start(ctrack,IPPROTO_UDP,UDP_MAX_REASM,UDP_MAX_REASM,clean,clean_len))
{
reasm_orig_cancel(ctrack);
return verdict;
}
}
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);
if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload)) if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload))
{ {
@@ -1951,28 +2062,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
return verdict; return verdict;
} }
if (bReqFull)
{
replay_queue(&ctrack->delayed);
reasm_orig_fin(ctrack);
}
return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt); return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt);
} }
} if (!quic_reasm_cancel(ctrack,"QUIC initial fragmented CRYPTO")) return verdict;
if (bIsHello)
{
bHaveHost = TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, sizeof(host), TLS_PARTIALS_ENABLE);
if (!bHaveHost && dp->desync_skip_nosni)
{
reasm_orig_cancel(ctrack);
DLOG("not applying tampering to QUIC ClientHello without hostname in the SNI\n");
return verdict;
}
}
else
{
if (!quic_reasm_cancel(ctrack,"QUIC initial without ClientHello")) return verdict;
} }
} }
else else
@@ -2006,6 +2098,18 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
l7proto = DHT; l7proto = DHT;
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto; if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
} }
else if (IsDiscordIpDiscoveryRequest(dis->data_payload,dis->len_payload))
{
DLOG("packet contains discord voice IP discovery\n");
l7proto = DISCORD;
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
}
else if (IsStunMessage(dis->data_payload,dis->len_payload))
{
DLOG("packet contains STUN message\n");
l7proto = STUN;
if (ctrack && ctrack->l7proto==UNKNOWN) ctrack->l7proto = l7proto;
}
else else
{ {
if (!dp->desync_any_proto) if (!dp->desync_any_proto)
@@ -2110,20 +2214,22 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
switch(l7proto) switch(l7proto)
{ {
case QUIC: case QUIC:
fake = dp->fake_quic; fake = &dp->fake_quic;
fake_size = dp->fake_quic_size;
break; break;
case WIREGUARD: case WIREGUARD:
fake = dp->fake_wg; fake = &dp->fake_wg;
fake_size = dp->fake_wg_size;
break; break;
case DHT: case DHT:
fake = dp->fake_dht; fake = &dp->fake_dht;
fake_size = dp->fake_dht_size; break;
case DISCORD:
fake = &dp->fake_discord;
break;
case STUN:
fake = &dp->fake_stun;
break; break;
default: default:
fake = dp->fake_unknown_udp; fake = &dp->fake_unknown_udp;
fake_size = dp->fake_unknown_udp_size;
break; break;
} }
@@ -2140,7 +2246,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
} }
bool bFake = false; bool bFake = false;
pkt1_len = sizeof(pkt1);
switch(dp->desync_mode) switch(dp->desync_mode)
{ {
case DESYNC_FAKE_KNOWN: case DESYNC_FAKE_KNOWN:
@@ -2150,12 +2255,30 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
break; break;
} }
case DESYNC_FAKE: case DESYNC_FAKE:
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len)) {
return verdict; struct blob_item *fake_item;
DLOG("sending fake : "); int n=0;
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) ip_id = IP4_IP_ID_FIX(dis->ip);
return verdict;
LIST_FOREACH(fake_item, fake, next)
{
n++;
pkt1_len = sizeof(pkt1);
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
ttl_fake, IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
dp->desync_fooling_mode, NULL, 0, 0,
fake_item->data, fake_item->size, pkt1, &pkt1_len))
{
return verdict;
}
DLOG("sending fake[%d] : ", n);
hexdump_limited_dlog(fake_item->data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return verdict;
ip_id=IP4_IP_ID_NEXT(ip_id);
}
}
bFake = true; bFake = true;
break; break;
case DESYNC_HOPBYHOP: case DESYNC_HOPBYHOP:
@@ -2164,9 +2287,9 @@ static uint8_t dpi_desync_udp_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_udp(dp->desync_mode2))) if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(dp->desync_mode2)))
{ {
pkt1_len = sizeof(pkt1);
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), ttl_orig,0,0,IP6_FLOW(dis->ip6),fooling_orig,NULL,0,0,
fooling_orig,NULL,0,0,
dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
{ {
return verdict; return verdict;

View File

@@ -41,7 +41,7 @@ enum dpi_desync_mode {
}; };
extern const char *fake_http_request_default; extern const char *fake_http_request_default;
extern const uint8_t fake_tls_clienthello_default[648]; extern const uint8_t fake_tls_clienthello_default[680];
void randomize_default_tls_payload(uint8_t *p); void randomize_default_tls_payload(uint8_t *p);
enum dpi_desync_mode desync_mode_from_string(const char *s); enum dpi_desync_mode desync_mode_from_string(const char *s);

View File

@@ -738,6 +738,10 @@ static bool parse_l7_list(char *opt, uint32_t *l7)
*l7 |= L7_PROTO_WIREGUARD; *l7 |= L7_PROTO_WIREGUARD;
else if (!strcmp(p,"dht")) else if (!strcmp(p,"dht"))
*l7 |= L7_PROTO_DHT; *l7 |= L7_PROTO_DHT;
else if (!strcmp(p,"discord"))
*l7 |= L7_PROTO_DISCORD;
else if (!strcmp(p,"stun"))
*l7 |= L7_PROTO_STUN;
else if (!strcmp(p,"unknown")) else if (!strcmp(p,"unknown"))
*l7 |= L7_PROTO_UNKNOWN; *l7 |= L7_PROTO_UNKNOWN;
else return false; else return false;
@@ -946,35 +950,57 @@ static bool parse_ip_list(char *opt, ipset *pp)
return true; return true;
} }
static bool parse_tlsmod_list(char *opt, uint8_t *mod) static bool parse_tlsmod_list(char *opt, struct fake_tls_mod *tls_mod)
{ {
char *e,*p,c; char *e,*e2,*p,c,c2;
*mod &= FAKE_TLS_MOD_SAVE_MASK; tls_mod->mod &= FAKE_TLS_MOD_SAVE_MASK;
*mod |= FAKE_TLS_MOD_SET; tls_mod->mod |= FAKE_TLS_MOD_SET;
for (p=opt ; p ; ) for (p=opt ; p ; )
{ {
if ((e = strchr(p,','))) for (e2=p ; *e2 && *e2!=',' && *e2!='=' ; e2++);
if ((e = strchr(e2,',')))
{ {
c=*e; c=*e;
*e=0; *e=0;
} }
if (!strcmp(p,"rnd")) if (*e2=='=')
*mod |= FAKE_TLS_MOD_RND; {
else if (!strcmp(p,"rndsni")) c2=*e2;
*mod |= FAKE_TLS_MOD_RND_SNI; *e2=0;
else if (!strcmp(p,"padencap")) }
*mod |= FAKE_TLS_MOD_PADENCAP; else
else if (!strcmp(p,"dupsid")) e2=NULL;
*mod |= FAKE_TLS_MOD_DUP_SID;
else if (strcmp(p,"none"))
return false;
if (!strcmp(p,"rnd"))
tls_mod->mod |= FAKE_TLS_MOD_RND;
else if (!strcmp(p,"rndsni"))
tls_mod->mod |= FAKE_TLS_MOD_RND_SNI;
else if (!strcmp(p,"sni"))
{
tls_mod->mod |= FAKE_TLS_MOD_SNI;
if (!e2 || !e2[1] || e2[1]==',') goto err;
strncpy(tls_mod->sni,e2+1,sizeof(tls_mod->sni)-1);
tls_mod->sni[sizeof(tls_mod->sni)-1-1]=0;
}
else if (!strcmp(p,"padencap"))
tls_mod->mod |= FAKE_TLS_MOD_PADENCAP;
else if (!strcmp(p,"dupsid"))
tls_mod->mod |= FAKE_TLS_MOD_DUP_SID;
else if (strcmp(p,"none"))
goto err;
if (e2) *e2=c2;
if (e) *e++=c; if (e) *e++=c;
p = e; p = e;
} }
return true; return true;
err:
if (e2) *e2=c2;
if (e) *e++=c;
return false;
} }
@@ -1007,104 +1033,194 @@ static void SplitDebug(void)
} }
static const char * tld[]={"com","org","net","edu","gov","biz"}; static const char * tld[]={"com","org","net","edu","gov","biz"};
static void onetime_tls_mod(struct desync_profile *dp)
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;
size_t extlen, slen; size_t extlen;
if (dp->n && !(dp->fake_tls_mod & (FAKE_TLS_MOD_SET|FAKE_TLS_MOD_CUSTOM_FAKE))) modcache->extlen_offset = modcache->padlen_offset = 0;
dp->fake_tls_mod |= FAKE_TLS_MOD_RND|FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_DUP_SID; // old behavior compat + dup_sid if (tls_mod->mod & (FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_SNI|FAKE_TLS_MOD_PADENCAP))
if (!(dp->fake_tls_mod & ~FAKE_TLS_MOD_SAVE_MASK))
return; // nothing to do
if (!IsTLSClientHello(dp->fake_tls,dp->fake_tls_size,false) || (dp->fake_tls_size<(44+dp->fake_tls[43]))) // has session id ?
{ {
DLOG_ERR("profile %d tls mod set but tls fake structure invalid\n", dp->n); if (!TLSFindExtLen(fake_tls,*fake_tls_size,&modcache->extlen_offset))
{
DLOG_ERR("profile %d fake[%d] padencap set but tls fake structure invalid\n", profile_n, fake_n);
return false;
}
DLOG("profile %d fake[%d] tls extensions length offset : %zu\n", profile_n, fake_n, modcache->extlen_offset);
if (tls_mod->mod & (FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_SNI))
{
size_t slen;
if (!TLSFindExt(fake_tls,*fake_tls_size,0,&ext,&extlen,false))
{
DLOG_ERR("profile %d fake[%d] sni mod is set but tls fake does not have SNI\n", profile_n, fake_n);
return false;
}
uint8_t *sniext = fake_tls + (ext - fake_tls);
if (!TLSAdvanceToHostInSNI(&ext,&extlen,&slen))
{
DLOG_ERR("profile %d fake[%d] sni set but tls fake has invalid SNI structure\n", profile_n, fake_n);
return false;
}
uint8_t *sni = fake_tls + (ext - fake_tls);
if (tls_mod->mod & FAKE_TLS_MOD_SNI)
{
size_t slen_new = strlen(tls_mod->sni);
ssize_t slen_delta = slen_new-slen;
char *s1=NULL;
if (params.debug)
{
if ((s1 = malloc(slen+1)))
{
memcpy(s1,sni,slen); s1[slen]=0;
}
}
if (slen_delta)
{
if ((*fake_tls_size+slen_delta)>fake_tls_buf_size)
{
DLOG_ERR("profile %d fake[%d] not enough space for new SNI\n", profile_n, fake_n);
free(s1);
return false;
}
memmove(sni+slen_new,sni+slen,fake_tls+*fake_tls_size-(sni+slen));
phton16(fake_tls+3,(uint16_t)(pntoh16(fake_tls+3)+slen_delta));
phton24(fake_tls+6,(uint32_t)(pntoh24(fake_tls+6)+slen_delta));
phton16(fake_tls+modcache->extlen_offset,(uint16_t)(pntoh16(fake_tls+modcache->extlen_offset)+slen_delta));
phton16(sniext-2,(uint16_t)(pntoh16(sniext-2)+slen_delta));
phton16(sniext,(uint16_t)(pntoh16(sniext)+slen_delta));
phton16(sni-2,(uint16_t)(pntoh16(sni-2)+slen_delta));
*fake_tls_size+=slen_delta;
slen = slen_new;
}
DLOG("profile %d fake[%d] change SNI : %s => %s size_delta=%zd\n", profile_n, fake_n, s1, tls_mod->sni, slen_delta);
free(s1);
memcpy(sni,tls_mod->sni,slen_new);
}
if (tls_mod->mod & FAKE_TLS_MOD_RND_SNI)
{
if (!slen)
{
DLOG_ERR("profile %d fake[%d] rndsni set but tls fake has zero sized SNI\n", profile_n, fake_n);
return false;
}
char *s1=NULL, *s2=NULL;
if (params.debug)
{
if ((s1 = malloc(slen+1)))
{
memcpy(s1,sni,slen); s1[slen]=0;
}
}
fill_random_az(sni,1);
if (slen>=7) // domain name in SNI must be at least 3 chars long to enable xxx.tls randomization
{
fill_random_az09(sni+1,slen-5);
sni[slen-4] = '.';
memcpy(sni+slen-3,tld[random()%(sizeof(tld)/sizeof(*tld))],3);
}
else
fill_random_az09(sni+1,slen-1);
if (params.debug)
{
if (s1 && (s2 = malloc(slen+1)))
{
memcpy(s2,sni,slen); s2[slen]=0;
DLOG("profile %d fake[%d] generated random SNI : %s -> %s\n",profile_n,fake_n,s1,s2);
}
free(s1); free(s2);
}
}
}
if (tls_mod->mod & FAKE_TLS_MOD_PADENCAP)
{
if (TLSFindExt(fake_tls,*fake_tls_size,21,&ext,&extlen,false))
{
if ((ext-fake_tls+extlen)!=*fake_tls_size)
{
DLOG_ERR("profile %d fake[%d] tls padding ext is present but it's not at the end. padding ext offset %zu, padding ext size %zu, fake size %zu\n", profile_n, fake_n, ext-fake_tls, extlen, *fake_tls_size);
return false;
}
modcache->padlen_offset = ext-fake_tls-2;
DLOG("profile %d fake[%d] tls padding ext is present, padding length offset %zu\n", profile_n, fake_n, modcache->padlen_offset);
}
else
{
if ((*fake_tls_size+4)>fake_tls_buf_size)
{
DLOG_ERR("profile %d fake[%d] tls padding is absent and there's no space to add it\n", profile_n, fake_n);
return false;
}
phton16(fake_tls+*fake_tls_size,21);
*fake_tls_size+=2;
modcache->padlen_offset=*fake_tls_size;
phton16(fake_tls+*fake_tls_size,0);
*fake_tls_size+=2;
phton16(fake_tls+modcache->extlen_offset,pntoh16(fake_tls+modcache->extlen_offset)+4);
phton16(fake_tls+3,pntoh16(fake_tls+3)+4); // increase tls record len
phton24(fake_tls+6,pntoh24(fake_tls+6)+4); // increase tls handshake len
DLOG("profile %d fake[%d] tls padding is absent. added. padding length offset %zu\n", profile_n, fake_n, modcache->padlen_offset);
}
}
}
return true;
}
static bool onetime_tls_mod(struct desync_profile *dp)
{
struct blob_item *fake_tls;
struct fake_tls_mod *tls_mod;
int n=0;
LIST_FOREACH(fake_tls, &dp->fake_tls, next)
{
++n;
tls_mod = (struct fake_tls_mod *)fake_tls->extra2;
if (!tls_mod) continue;
if (dp->n && !(tls_mod->mod & (FAKE_TLS_MOD_SET|FAKE_TLS_MOD_CUSTOM_FAKE)))
tls_mod->mod |= FAKE_TLS_MOD_RND|FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_DUP_SID; // old behavior compat + dup_sid
if (!(tls_mod->mod & ~FAKE_TLS_MOD_SAVE_MASK))
continue;
if (!IsTLSClientHello(fake_tls->data,fake_tls->size,false) || (fake_tls->size < (44+fake_tls->data[43]))) // has session id ?
{
DLOG("profile %d fake[%d] tls mod set but tls fake structure invalid.\n", dp->n, n);
return false;
}
if (!fake_tls->extra)
{
fake_tls->extra = malloc(sizeof(struct fake_tls_mod_cache));
if (!fake_tls->extra) return false;
}
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 true;
}
static struct blob_item *load_blob_to_collection(const char *filename, struct blob_collection_head *blobs, size_t max_size, size_t size_reserve)
{
struct blob_item *blob = blob_collection_add(blobs);
uint8_t *p;
if (!blob || (!(blob->data = malloc(max_size+size_reserve))))
{
DLOG_ERR("out of memory\n");
exit_clean(1); exit_clean(1);
} }
if (dp->fake_tls_mod & FAKE_TLS_MOD_PADENCAP) blob->size = max_size;
load_file_or_exit(filename,blob->data,&blob->size);
p = realloc(blob->data,blob->size+size_reserve);
if (!p)
{ {
if (!TLSFindExtLen(dp->fake_tls,dp->fake_tls_size,&dp->fake_tls_extlen_offset)) DLOG_ERR("out of memory\n");
{ exit_clean(1);
DLOG_ERR("profile %d padencap set but tls fake structure invalid\n", dp->n);
exit_clean(1);
}
DLOG("profile %d fake tls extensions length offset : %zu\n", dp->n, dp->fake_tls_extlen_offset);
if (TLSFindExt(dp->fake_tls,dp->fake_tls_size,21,&ext,&extlen,false))
{
if ((ext-dp->fake_tls+extlen)!=dp->fake_tls_size)
{
DLOG_ERR("profile %d fake tls padding ext is present but it's not at the end. padding ext offset %zu, padding ext size %zu, fake size %zu\n", dp->n, ext-dp->fake_tls, extlen, dp->fake_tls_size);
exit_clean(1);
}
dp->fake_tls_padlen_offset = ext-dp->fake_tls-2;
DLOG("profile %d fake tls padding ext is present, padding length offset %zu\n", dp->n, dp->fake_tls_padlen_offset);
}
else
{
if ((dp->fake_tls_size+4)>sizeof(dp->fake_tls))
{
DLOG_ERR("profile %d fake tls padding is absent and there's not space to add it\n", dp->n);
exit_clean(1);
}
phton16(dp->fake_tls+dp->fake_tls_size,21);
dp->fake_tls_size+=2;
dp->fake_tls_padlen_offset=dp->fake_tls_size;
phton16(dp->fake_tls+dp->fake_tls_size,0);
dp->fake_tls_size+=2;
phton16(dp->fake_tls+dp->fake_tls_extlen_offset,pntoh16(dp->fake_tls+dp->fake_tls_extlen_offset)+4);
phton16(dp->fake_tls+3,pntoh16(dp->fake_tls+3)+4); // increase tls record len
phton24(dp->fake_tls+6,pntoh24(dp->fake_tls+6)+4); // increase tls handshake len
DLOG("profile %d fake tls padding is absent. added. padding ledgth offset %zu\n", dp->n, dp->fake_tls_padlen_offset);
}
}
if (dp->fake_tls_mod & FAKE_TLS_MOD_RND_SNI)
{
if (!TLSFindExt(dp->fake_tls,dp->fake_tls_size,0,&ext,&extlen,false))
{
DLOG_ERR("profile %d rndsni set but tls fake does not have SNI\n", dp->n);
exit_clean(1);
}
if (!TLSAdvanceToHostInSNI(&ext,&extlen,&slen))
{
DLOG_ERR("profile %d rndsni set but tls fake has invalid SNI structure\n", dp->n);
exit_clean(1);
}
if (!slen)
{
DLOG_ERR("profile %d rndsni set but tls fake has zero sized SNI\n", dp->n);
exit_clean(1);
}
uint8_t *sni = dp->fake_tls + (ext - dp->fake_tls);
char *s1=NULL, *s2=NULL;
if (params.debug)
{
if ((s1 = malloc(slen+1)))
{
memcpy(s1,sni,slen); s1[slen]=0;
}
}
fill_random_az(sni,1);
if (slen>=7) // domain name in SNI must be at least 3 chars long to enable xxx.tls randomization
{
fill_random_az09(sni+1,slen-5);
sni[slen-4] = '.';
memcpy(sni+slen-3,tld[random()%(sizeof(tld)/sizeof(*tld))],3);
}
else
fill_random_az09(sni+1,slen-1);
if (params.debug)
{
if (s1 && (s2 = malloc(slen+1)))
{
memcpy(s2,sni,slen); s2[slen]=0;
DLOG("profile %d generated random SNI : %s -> %s\n",dp->n,s1,s2);
}
free(s1); free(s2);
}
} }
blob->data = p;
blob->size_buf = blob->size+size_reserve;
return blob;
} }
@@ -1273,7 +1389,7 @@ static void exithelp(void)
" --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; 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; 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; 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|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"
" --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; 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; 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; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)\n"
@@ -1326,12 +1442,14 @@ static void exithelp(void)
" --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-any-protocol=0|1\t\t\t; 0(default)=desync only http and tls 1=desync any nonempty data packet\n"
" --dpi-desync-fake-http=<filename>|0xHEX\t; file containing fake http request\n" " --dpi-desync-fake-http=<filename>|0xHEX\t; file containing fake http request\n"
" --dpi-desync-fake-tls=<filename>|0xHEX\t\t; file containing fake TLS ClientHello (for https)\n" " --dpi-desync-fake-tls=<filename>|0xHEX\t\t; file containing fake TLS ClientHello (for https)\n"
" --dpi-desync-fake-tls-mod=mod[,mod]\t\t; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,dupsid,padencap\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-fake-unknown=<filename>|0xHEX\t; file containing unknown protocol fake payload\n" " --dpi-desync-fake-unknown=<filename>|0xHEX\t; file containing unknown protocol fake payload\n"
" --dpi-desync-fake-syndata=<filename>|0xHEX\t; file containing SYN data payload\n" " --dpi-desync-fake-syndata=<filename>|0xHEX\t; file containing SYN data payload\n"
" --dpi-desync-fake-quic=<filename>|0xHEX\t; file containing fake QUIC Initial\n" " --dpi-desync-fake-quic=<filename>|0xHEX\t; file containing fake QUIC Initial\n"
" --dpi-desync-fake-wireguard=<filename>|0xHEX\t; file containing fake wireguard handshake initiation\n" " --dpi-desync-fake-wireguard=<filename>|0xHEX\t; file containing fake wireguard handshake initiation\n"
" --dpi-desync-fake-dht=<filename>|0xHEX\t\t; file containing DHT protocol fake payload (d1...e)\n" " --dpi-desync-fake-dht=<filename>|0xHEX\t\t; file containing DHT protocol fake payload (d1...e)\n"
" --dpi-desync-fake-discord=<filename>|0xHEX\t; file containing discord protocol fake payload (Voice IP Discovery)\n"
" --dpi-desync-fake-stun=<filename>|0xHEX\t; file containing STUN protocol fake payload\n"
" --dpi-desync-fake-unknown-udp=<filename>|0xHEX\t; file containing unknown udp protocol fake payload\n" " --dpi-desync-fake-unknown-udp=<filename>|0xHEX\t; file containing unknown udp protocol fake payload\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-udplen-increment=<int>\t\t; increase or decrease udp packet length by N bytes (default %u). negative values decrease length.\n"
" --dpi-desync-udplen-pattern=<filename>|0xHEX\t; udp tail fill pattern\n" " --dpi-desync-udplen-pattern=<filename>|0xHEX\t; udp tail fill pattern\n"
@@ -1556,43 +1674,45 @@ int main(int argc, char **argv)
{"dpi-desync-fake-quic",required_argument,0,0},// optidx=43 {"dpi-desync-fake-quic",required_argument,0,0},// optidx=43
{"dpi-desync-fake-wireguard",required_argument,0,0},// optidx=44 {"dpi-desync-fake-wireguard",required_argument,0,0},// optidx=44
{"dpi-desync-fake-dht",required_argument,0,0},// optidx=45 {"dpi-desync-fake-dht",required_argument,0,0},// optidx=45
{"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=46 {"dpi-desync-fake-discord",required_argument,0,0},// optidx=46
{"dpi-desync-udplen-increment",required_argument,0,0},// optidx=47 {"dpi-desync-fake-stun",required_argument,0,0},// optidx=47
{"dpi-desync-udplen-pattern",required_argument,0,0},// optidx=48 {"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=48
{"dpi-desync-cutoff",required_argument,0,0},// optidx=49 {"dpi-desync-udplen-increment",required_argument,0,0},// optidx=49
{"dpi-desync-start",required_argument,0,0},// optidx=50 {"dpi-desync-udplen-pattern",required_argument,0,0},// optidx=50
{"hostlist",required_argument,0,0}, // optidx=51 {"dpi-desync-cutoff",required_argument,0,0},// optidx=51
{"hostlist-domains",required_argument,0,0},// optidx=52 {"dpi-desync-start",required_argument,0,0},// optidx=52
{"hostlist-exclude",required_argument,0,0}, // optidx=53 {"hostlist",required_argument,0,0}, // optidx=53
{"hostlist-exclude-domains",required_argument,0,0},// optidx=54 {"hostlist-domains",required_argument,0,0},// optidx=54
{"hostlist-auto",required_argument,0,0}, // optidx=55 {"hostlist-exclude",required_argument,0,0}, // optidx=55
{"hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=56 {"hostlist-exclude-domains",required_argument,0,0},// optidx=56
{"hostlist-auto-fail-time",required_argument,0,0}, // optidx=57 {"hostlist-auto",required_argument,0,0}, // optidx=57
{"hostlist-auto-retrans-threshold",required_argument,0,0}, // optidx=58 {"hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=58
{"hostlist-auto-debug",required_argument,0,0}, // optidx=59 {"hostlist-auto-fail-time",required_argument,0,0}, // optidx=59
{"new",no_argument,0,0}, // optidx=60 {"hostlist-auto-retrans-threshold",required_argument,0,0}, // optidx=60
{"skip",no_argument,0,0}, // optidx=61 {"hostlist-auto-debug",required_argument,0,0}, // optidx=61
{"filter-l3",required_argument,0,0}, // optidx=62 {"new",no_argument,0,0}, // optidx=62
{"filter-tcp",required_argument,0,0}, // optidx=63 {"skip",no_argument,0,0}, // optidx=63
{"filter-udp",required_argument,0,0}, // optidx=64 {"filter-l3",required_argument,0,0}, // optidx=64
{"filter-l7",required_argument,0,0}, // optidx=65 {"filter-tcp",required_argument,0,0}, // optidx=65
{"ipset",required_argument,0,0}, // optidx=66 {"filter-udp",required_argument,0,0}, // optidx=66
{"ipset-ip",required_argument,0,0}, // optidx=67 {"filter-l7",required_argument,0,0}, // optidx=67
{"ipset-exclude",required_argument,0,0},// optidx=68 {"ipset",required_argument,0,0}, // optidx=68
{"ipset-exclude-ip",required_argument,0,0}, // optidx=69 {"ipset-ip",required_argument,0,0}, // optidx=69
{"ipset-exclude",required_argument,0,0},// optidx=70
{"ipset-exclude-ip",required_argument,0,0}, // optidx=71
#ifdef __linux__ #ifdef __linux__
{"bind-fix4",no_argument,0,0}, // optidx=70 {"bind-fix4",no_argument,0,0}, // optidx=72
{"bind-fix6",no_argument,0,0}, // optidx=71 {"bind-fix6",no_argument,0,0}, // optidx=73
#elif defined(__CYGWIN__) #elif defined(__CYGWIN__)
{"wf-iface",required_argument,0,0}, // optidx=70 {"wf-iface",required_argument,0,0}, // optidx=72
{"wf-l3",required_argument,0,0}, // optidx=71 {"wf-l3",required_argument,0,0}, // optidx=73
{"wf-tcp",required_argument,0,0}, // optidx=72 {"wf-tcp",required_argument,0,0}, // optidx=74
{"wf-udp",required_argument,0,0}, // optidx=73 {"wf-udp",required_argument,0,0}, // optidx=75
{"wf-raw",required_argument,0,0}, // optidx=74 {"wf-raw",required_argument,0,0}, // optidx=76
{"wf-save",required_argument,0,0}, // optidx=75 {"wf-save",required_argument,0,0}, // optidx=77
{"ssid-filter",required_argument,0,0}, // optidx=76 {"ssid-filter",required_argument,0,0}, // optidx=78
{"nlm-filter",required_argument,0,0}, // optidx=77 {"nlm-filter",required_argument,0,0}, // optidx=79
{"nlm-list",optional_argument,0,0}, // optidx=78 {"nlm-list",optional_argument,0,0}, // optidx=80
#endif #endif
{NULL,0,NULL,0} {NULL,0,NULL,0}
}; };
@@ -1992,53 +2112,63 @@ int main(int argc, char **argv)
dp->desync_any_proto = !optarg || atoi(optarg); dp->desync_any_proto = !optarg || atoi(optarg);
break; break;
case 38: /* dpi-desync-fake-http */ case 38: /* dpi-desync-fake-http */
dp->fake_http_size = sizeof(dp->fake_http); load_blob_to_collection(optarg, &dp->fake_http, FAKE_MAX_TCP,0);
load_file_or_exit(optarg,dp->fake_http,&dp->fake_http_size);
break; break;
case 39: /* dpi-desync-fake-tls */ case 39: /* dpi-desync-fake-tls */
dp->fake_tls_size = sizeof(dp->fake_tls); {
load_file_or_exit(optarg,dp->fake_tls,&dp->fake_tls_size); dp->tls_fake_last = load_blob_to_collection(optarg, &dp->fake_tls, FAKE_MAX_TCP,4+sizeof(dp->tls_mod_last.sni));
dp->fake_tls_mod |= FAKE_TLS_MOD_CUSTOM_FAKE; if (!(dp->tls_fake_last->extra2 = malloc(sizeof(struct fake_tls_mod))))
{
DLOG_ERR("out of memory\n");
exit_clean(1);
}
struct fake_tls_mod *tls_mod = (struct fake_tls_mod*)dp->tls_fake_last->extra2;
*tls_mod = dp->tls_mod_last;
tls_mod->mod |= FAKE_TLS_MOD_CUSTOM_FAKE;
}
break; break;
case 40: /* dpi-desync-fake-tls-mod */ case 40: /* dpi-desync-fake-tls-mod */
if (!parse_tlsmod_list(optarg,&dp->fake_tls_mod)) if (!parse_tlsmod_list(optarg,&dp->tls_mod_last))
{ {
DLOG_ERR("Invalid tls mod : %s\n",optarg); DLOG_ERR("Invalid tls mod : %s\n",optarg);
exit_clean(1); exit_clean(1);
} }
if (dp->tls_fake_last)
*(struct fake_tls_mod*)dp->tls_fake_last->extra2 = dp->tls_mod_last;
break; break;
case 41: /* dpi-desync-fake-unknown */ case 41: /* dpi-desync-fake-unknown */
dp->fake_unknown_size = sizeof(dp->fake_unknown); load_blob_to_collection(optarg, &dp->fake_unknown, FAKE_MAX_TCP, 0);
load_file_or_exit(optarg,dp->fake_unknown,&dp->fake_unknown_size);
break; break;
case 42: /* dpi-desync-fake-syndata */ case 42: /* 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);
break; break;
case 43: /* dpi-desync-fake-quic */ case 43: /* dpi-desync-fake-quic */
dp->fake_quic_size = sizeof(dp->fake_quic); load_blob_to_collection(optarg, &dp->fake_quic, FAKE_MAX_UDP, 0);
load_file_or_exit(optarg,dp->fake_quic,&dp->fake_quic_size);
break; break;
case 44: /* dpi-desync-fake-wireguard */ case 44: /* dpi-desync-fake-wireguard */
dp->fake_wg_size = sizeof(dp->fake_wg); load_blob_to_collection(optarg, &dp->fake_wg, FAKE_MAX_UDP, 0);
load_file_or_exit(optarg,dp->fake_wg,&dp->fake_wg_size);
break; break;
case 45: /* dpi-desync-fake-dht */ case 45: /* dpi-desync-fake-dht */
dp->fake_dht_size = sizeof(dp->fake_dht); load_blob_to_collection(optarg, &dp->fake_dht, FAKE_MAX_UDP, 0);
load_file_or_exit(optarg,dp->fake_dht,&dp->fake_dht_size);
break; break;
case 46: /* dpi-desync-fake-unknown-udp */ case 46: /* dpi-desync-fake-discord */
dp->fake_unknown_udp_size = sizeof(dp->fake_unknown_udp); load_blob_to_collection(optarg, &dp->fake_discord, FAKE_MAX_UDP, 0);
load_file_or_exit(optarg,dp->fake_unknown_udp,&dp->fake_unknown_udp_size);
break; break;
case 47: /* dpi-desync-udplen-increment */ case 47: /* dpi-desync-fake-stun */
load_blob_to_collection(optarg, &dp->fake_stun, FAKE_MAX_UDP, 0);
break;
case 48: /* dpi-desync-fake-unknown-udp */
load_blob_to_collection(optarg, &dp->fake_unknown_udp, FAKE_MAX_UDP, 0);
break;
case 49: /* dpi-desync-udplen-increment */
if (sscanf(optarg,"%d",&dp->udplen_increment)<1 || dp->udplen_increment>0x7FFF || dp->udplen_increment<-0x8000) if (sscanf(optarg,"%d",&dp->udplen_increment)<1 || dp->udplen_increment>0x7FFF || dp->udplen_increment<-0x8000)
{ {
DLOG_ERR("dpi-desync-udplen-increment must be integer within -32768..32767 range\n"); DLOG_ERR("dpi-desync-udplen-increment must be integer within -32768..32767 range\n");
exit_clean(1); exit_clean(1);
} }
break; break;
case 48: /* dpi-desync-udplen-pattern */ case 50: /* dpi-desync-udplen-pattern */
{ {
char buf[sizeof(dp->udplen_pattern)]; char buf[sizeof(dp->udplen_pattern)];
size_t sz=sizeof(buf); size_t sz=sizeof(buf);
@@ -2046,21 +2176,21 @@ int main(int argc, char **argv)
fill_pattern(dp->udplen_pattern,sizeof(dp->udplen_pattern),buf,sz); fill_pattern(dp->udplen_pattern,sizeof(dp->udplen_pattern),buf,sz);
} }
break; break;
case 49: /* desync-cutoff */ case 51: /* desync-cutoff */
if (!parse_cutoff(optarg, &dp->desync_cutoff, &dp->desync_cutoff_mode)) if (!parse_cutoff(optarg, &dp->desync_cutoff, &dp->desync_cutoff_mode))
{ {
DLOG_ERR("invalid desync-cutoff value\n"); DLOG_ERR("invalid desync-cutoff value\n");
exit_clean(1); exit_clean(1);
} }
break; break;
case 50: /* desync-start */ case 52: /* desync-start */
if (!parse_cutoff(optarg, &dp->desync_start, &dp->desync_start_mode)) if (!parse_cutoff(optarg, &dp->desync_start, &dp->desync_start_mode))
{ {
DLOG_ERR("invalid desync-start value\n"); DLOG_ERR("invalid desync-start value\n");
exit_clean(1); exit_clean(1);
} }
break; break;
case 51: /* hostlist */ case 53: /* hostlist */
if (bSkip) break; if (bSkip) break;
if (!RegisterHostlist(dp, false, optarg)) if (!RegisterHostlist(dp, false, optarg))
{ {
@@ -2068,7 +2198,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 52: /* hostlist-domains */ case 54: /* hostlist-domains */
if (bSkip) break; if (bSkip) break;
if (!anon_hl && !(anon_hl=RegisterHostlist(dp, false, NULL))) if (!anon_hl && !(anon_hl=RegisterHostlist(dp, false, NULL)))
{ {
@@ -2081,7 +2211,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 53: /* hostlist-exclude */ case 55: /* hostlist-exclude */
if (bSkip) break; if (bSkip) break;
if (!RegisterHostlist(dp, true, optarg)) if (!RegisterHostlist(dp, true, optarg))
{ {
@@ -2089,7 +2219,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 54: /* hostlist-exclude-domains */ case 56: /* hostlist-exclude-domains */
if (bSkip) break; if (bSkip) break;
if (!anon_hl_exclude && !(anon_hl_exclude=RegisterHostlist(dp, true, NULL))) if (!anon_hl_exclude && !(anon_hl_exclude=RegisterHostlist(dp, true, NULL)))
{ {
@@ -2102,7 +2232,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 55: /* hostlist-auto */ case 57: /* hostlist-auto */
if (bSkip) break; if (bSkip) break;
if (dp->hostlist_auto) if (dp->hostlist_auto)
{ {
@@ -2130,7 +2260,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 56: /* hostlist-auto-fail-threshold */ case 58: /* hostlist-auto-fail-threshold */
dp->hostlist_auto_fail_threshold = (uint8_t)atoi(optarg); dp->hostlist_auto_fail_threshold = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_fail_threshold<1 || dp->hostlist_auto_fail_threshold>20) if (dp->hostlist_auto_fail_threshold<1 || dp->hostlist_auto_fail_threshold>20)
{ {
@@ -2138,7 +2268,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 57: /* hostlist-auto-fail-time */ case 59: /* hostlist-auto-fail-time */
dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg); dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_fail_time<1) if (dp->hostlist_auto_fail_time<1)
{ {
@@ -2146,7 +2276,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 58: /* hostlist-auto-retrans-threshold */ case 60: /* hostlist-auto-retrans-threshold */
dp->hostlist_auto_retrans_threshold = (uint8_t)atoi(optarg); dp->hostlist_auto_retrans_threshold = (uint8_t)atoi(optarg);
if (dp->hostlist_auto_retrans_threshold<2 || dp->hostlist_auto_retrans_threshold>10) if (dp->hostlist_auto_retrans_threshold<2 || dp->hostlist_auto_retrans_threshold>10)
{ {
@@ -2154,7 +2284,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 59: /* hostlist-auto-debug */ case 61: /* hostlist-auto-debug */
{ {
FILE *F = fopen(optarg,"a+t"); FILE *F = fopen(optarg,"a+t");
if (!F) if (!F)
@@ -2168,7 +2298,7 @@ int main(int argc, char **argv)
} }
break; break;
case 60: /* new */ case 62: /* new */
if (bSkip) if (bSkip)
{ {
dp_clear(dp); dp_clear(dp);
@@ -2190,18 +2320,18 @@ int main(int argc, char **argv)
anon_hl = anon_hl_exclude = NULL; anon_hl = anon_hl_exclude = NULL;
anon_ips = anon_ips_exclude = NULL; anon_ips = anon_ips_exclude = NULL;
break; break;
case 61: /* skip */ case 63: /* skip */
bSkip = true; bSkip = true;
break; break;
case 62: /* filter-l3 */ case 64: /* filter-l3 */
if (!wf_make_l3(optarg,&dp->filter_ipv4,&dp->filter_ipv6)) if (!wf_make_l3(optarg,&dp->filter_ipv4,&dp->filter_ipv6))
{ {
DLOG_ERR("bad value for --filter-l3\n"); DLOG_ERR("bad value for --filter-l3\n");
exit_clean(1); exit_clean(1);
} }
break; break;
case 63: /* filter-tcp */ case 65: /* filter-tcp */
if (!parse_pf_list(optarg,&dp->pf_tcp)) if (!parse_pf_list(optarg,&dp->pf_tcp))
{ {
DLOG_ERR("Invalid port filter : %s\n",optarg); DLOG_ERR("Invalid port filter : %s\n",optarg);
@@ -2211,7 +2341,7 @@ int main(int argc, char **argv)
if (!port_filters_deny_if_empty(&dp->pf_udp)) if (!port_filters_deny_if_empty(&dp->pf_udp))
exit_clean(1); exit_clean(1);
break; break;
case 64: /* filter-udp */ case 66: /* filter-udp */
if (!parse_pf_list(optarg,&dp->pf_udp)) if (!parse_pf_list(optarg,&dp->pf_udp))
{ {
DLOG_ERR("Invalid port filter : %s\n",optarg); DLOG_ERR("Invalid port filter : %s\n",optarg);
@@ -2221,14 +2351,14 @@ int main(int argc, char **argv)
if (!port_filters_deny_if_empty(&dp->pf_tcp)) if (!port_filters_deny_if_empty(&dp->pf_tcp))
exit_clean(1); exit_clean(1);
break; break;
case 65: /* filter-l7 */ case 67: /* filter-l7 */
if (!parse_l7_list(optarg,&dp->filter_l7)) if (!parse_l7_list(optarg,&dp->filter_l7))
{ {
DLOG_ERR("Invalid l7 filter : %s\n",optarg); DLOG_ERR("Invalid l7 filter : %s\n",optarg);
exit_clean(1); exit_clean(1);
} }
break; break;
case 66: /* ipset */ case 68: /* ipset */
if (bSkip) break; if (bSkip) break;
if (!RegisterIpset(dp, false, optarg)) if (!RegisterIpset(dp, false, optarg))
{ {
@@ -2236,7 +2366,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 67: /* ipset-ip */ case 69: /* ipset-ip */
if (bSkip) break; if (bSkip) break;
if (!anon_ips && !(anon_ips=RegisterIpset(dp, false, NULL))) if (!anon_ips && !(anon_ips=RegisterIpset(dp, false, NULL)))
{ {
@@ -2249,7 +2379,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 68: /* ipset-exclude */ case 70: /* ipset-exclude */
if (bSkip) break; if (bSkip) break;
if (!RegisterIpset(dp, true, optarg)) if (!RegisterIpset(dp, true, optarg))
{ {
@@ -2257,7 +2387,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 69: /* ipset-exclude-ip */ case 71: /* ipset-exclude-ip */
if (bSkip) break; if (bSkip) break;
if (!anon_ips_exclude && !(anon_ips_exclude=RegisterIpset(dp, true, NULL))) if (!anon_ips_exclude && !(anon_ips_exclude=RegisterIpset(dp, true, NULL)))
{ {
@@ -2273,28 +2403,28 @@ int main(int argc, char **argv)
#ifdef __linux__ #ifdef __linux__
case 70: /* bind-fix4 */ case 72: /* bind-fix4 */
params.bind_fix4 = true; params.bind_fix4 = true;
break; break;
case 71: /* bind-fix6 */ case 73: /* bind-fix6 */
params.bind_fix6 = true; params.bind_fix6 = true;
break; break;
#elif defined(__CYGWIN__) #elif defined(__CYGWIN__)
case 70: /* wf-iface */ case 72: /* wf-iface */
if (!sscanf(optarg,"%u.%u",&IfIdx,&SubIfIdx)) if (!sscanf(optarg,"%u.%u",&IfIdx,&SubIfIdx))
{ {
DLOG_ERR("bad value for --wf-iface\n"); DLOG_ERR("bad value for --wf-iface\n");
exit_clean(1); exit_clean(1);
} }
break; break;
case 71: /* wf-l3 */ case 73: /* wf-l3 */
if (!wf_make_l3(optarg,&wf_ipv4,&wf_ipv6)) if (!wf_make_l3(optarg,&wf_ipv4,&wf_ipv6))
{ {
DLOG_ERR("bad value for --wf-l3\n"); DLOG_ERR("bad value for --wf-l3\n");
exit_clean(1); exit_clean(1);
} }
break; break;
case 72: /* wf-tcp */ case 74: /* wf-tcp */
hash_wf_tcp=hash_jen(optarg,strlen(optarg)); hash_wf_tcp=hash_jen(optarg,strlen(optarg));
if (!wf_make_pf(optarg,"tcp","SrcPort",wf_pf_tcp_src,sizeof(wf_pf_tcp_src)) || if (!wf_make_pf(optarg,"tcp","SrcPort",wf_pf_tcp_src,sizeof(wf_pf_tcp_src)) ||
!wf_make_pf(optarg,"tcp","DstPort",wf_pf_tcp_dst,sizeof(wf_pf_tcp_dst))) !wf_make_pf(optarg,"tcp","DstPort",wf_pf_tcp_dst,sizeof(wf_pf_tcp_dst)))
@@ -2303,7 +2433,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 73: /* wf-udp */ case 75: /* wf-udp */
hash_wf_udp=hash_jen(optarg,strlen(optarg)); hash_wf_udp=hash_jen(optarg,strlen(optarg));
if (!wf_make_pf(optarg,"udp","SrcPort",wf_pf_udp_src,sizeof(wf_pf_udp_src)) || if (!wf_make_pf(optarg,"udp","SrcPort",wf_pf_udp_src,sizeof(wf_pf_udp_src)) ||
!wf_make_pf(optarg,"udp","DstPort",wf_pf_udp_dst,sizeof(wf_pf_udp_dst))) !wf_make_pf(optarg,"udp","DstPort",wf_pf_udp_dst,sizeof(wf_pf_udp_dst)))
@@ -2312,7 +2442,7 @@ int main(int argc, char **argv)
exit_clean(1); exit_clean(1);
} }
break; break;
case 74: /* wf-raw */ case 76: /* wf-raw */
hash_wf_raw=hash_jen(optarg,strlen(optarg)); hash_wf_raw=hash_jen(optarg,strlen(optarg));
if (optarg[0]=='@') if (optarg[0]=='@')
{ {
@@ -2326,11 +2456,11 @@ int main(int argc, char **argv)
windivert_filter[sizeof(windivert_filter) - 1] = '\0'; windivert_filter[sizeof(windivert_filter) - 1] = '\0';
} }
break; break;
case 75: /* wf-save */ case 77: /* 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';
break; break;
case 76: /* ssid-filter */ case 78: /* ssid-filter */
hash_ssid_filter=hash_jen(optarg,strlen(optarg)); hash_ssid_filter=hash_jen(optarg,strlen(optarg));
{ {
char *e,*p = optarg; char *e,*p = optarg;
@@ -2348,7 +2478,7 @@ int main(int argc, char **argv)
} }
} }
break; break;
case 77: /* nlm-filter */ case 79: /* nlm-filter */
hash_nlm_filter=hash_jen(optarg,strlen(optarg)); hash_nlm_filter=hash_jen(optarg,strlen(optarg));
{ {
char *e,*p = optarg; char *e,*p = optarg;
@@ -2366,7 +2496,7 @@ int main(int argc, char **argv)
} }
} }
break; break;
case 78: /* nlm-list */ case 80: /* nlm-list */
if (!nlm_list(optarg && !strcmp(optarg,"all"))) if (!nlm_list(optarg && !strcmp(optarg,"all")))
{ {
DLOG_ERR("could not get list of NLM networks\n"); DLOG_ERR("could not get list of NLM networks\n");
@@ -2475,7 +2605,16 @@ int main(int argc, char **argv)
if (AUTOTTL_ENABLED(dp->desync_autottl6)) if (AUTOTTL_ENABLED(dp->desync_autottl6))
DLOG("profile %d autottl ipv6 %u:%u-%u\n",dp->n,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max); DLOG("profile %d autottl ipv6 %u:%u-%u\n",dp->n,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max);
split_compat(dp); split_compat(dp);
onetime_tls_mod(dp); if (!dp_fake_defaults(dp))
{
DLOG_ERR("could not fill fake defaults\n");
exit_clean(1);
}
if (!onetime_tls_mod(dp))
{
DLOG_ERR("could not mod tls\n");
exit_clean(1);
}
#ifndef __CYGWIN__ #ifndef __CYGWIN__
if (params.droproot && dp->hostlist_auto && chown(dp->hostlist_auto->filename, params.uid, -1)) if (params.droproot && dp->hostlist_auto && chown(dp->hostlist_auto->filename, params.uid, -1))
DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", dp->hostlist_auto->filename); DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", dp->hostlist_auto->filename);

View File

@@ -65,6 +65,7 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, va_list
{ {
va_copy(args2,args); va_copy(args2,args);
DLOG_CON(format,syslog_priority,args2); DLOG_CON(format,syslog_priority,args2);
va_end(args2);
} }
if (params.debug) if (params.debug)
{ {
@@ -184,18 +185,7 @@ void dp_init(struct desync_profile *dp)
dp->desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT; dp->desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT;
dp->desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT; dp->desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT;
dp->desync_repeats = 1; dp->desync_repeats = 1;
dp->fake_tls_size = sizeof(fake_tls_clienthello_default);
memcpy(dp->fake_tls,fake_tls_clienthello_default,dp->fake_tls_size);
dp->fake_tls_mod = 0;
dp->fake_http_size = strlen(fake_http_request_default);
memcpy(dp->fake_http,fake_http_request_default,dp->fake_http_size);
dp->fake_quic_size = 620; // must be 601+ for TSPU hack
dp->fake_quic[0] = 0x40; // russian TSPU QUIC short header fake
dp->fake_wg_size = 64;
dp->fake_dht_size = 64;
dp->fake_unknown_size = 256;
dp->fake_syndata_size = 16; dp->fake_syndata_size = 16;
dp->fake_unknown_udp_size = 64;
dp->wscale=-1; // default - dont change scale factor (client) dp->wscale=-1; // default - dont change scale factor (client)
dp->desync_ttl6 = 0xFF; // unused dp->desync_ttl6 = 0xFF; // unused
dp->desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT; dp->desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
@@ -207,6 +197,45 @@ void dp_init(struct desync_profile *dp)
dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT; dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT;
dp->filter_ipv4 = dp->filter_ipv6 = true; dp->filter_ipv4 = dp->filter_ipv6 = true;
} }
bool dp_fake_defaults(struct desync_profile *dp)
{
struct blob_item *item;
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))
return false;
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))))
return false;
if (!(item->extra2 = malloc(sizeof(struct fake_tls_mod))))
return false;
*(struct fake_tls_mod*)item->extra2 = dp->tls_mod_last;
}
if (blob_collection_empty(&dp->fake_unknown))
{
if (!(item=blob_collection_add_blob(&dp->fake_unknown,NULL,256,0)))
return false;
memset(item->data,0,item->size);
}
if (blob_collection_empty(&dp->fake_quic))
{
if (!(item=blob_collection_add_blob(&dp->fake_quic,NULL,620,0)))
return false;
memset(item->data,0,item->size);
item->data[0] = 0x40;
}
struct blob_collection_head **fake,*fakes_z64[] = {&dp->fake_wg, &dp->fake_dht, &dp->fake_discord, &dp->fake_stun, &dp->fake_unknown_udp,NULL};
for(fake=fakes_z64;*fake;fake++)
{
if (blob_collection_empty(*fake))
{
if (!(item=blob_collection_add_blob(*fake,NULL,64,0)))
return false;
memset(item->data,0,item->size);
}
}
return true;
}
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head) struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
{ {
struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list)); struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list));
@@ -235,6 +264,8 @@ static void dp_clear_dynamic(struct desync_profile *dp)
port_filters_destroy(&dp->pf_tcp); port_filters_destroy(&dp->pf_tcp);
port_filters_destroy(&dp->pf_udp); port_filters_destroy(&dp->pf_udp);
HostFailPoolDestroy(&dp->hostlist_auto_fail_counters); HostFailPoolDestroy(&dp->hostlist_auto_fail_counters);
struct blob_collection_head **fake,*fakes[] = {&dp->fake_http, &dp->fake_tls, &dp->fake_unknown, &dp->fake_unknown_udp, &dp->fake_quic, &dp->fake_wg, &dp->fake_dht, &dp->fake_discord, &dp->fake_stun, NULL};
for(fake=fakes;*fake;fake++) blob_collection_destroy(*fake);
} }
void dp_clear(struct desync_profile *dp) void dp_clear(struct desync_profile *dp)
{ {

View File

@@ -44,10 +44,24 @@
#define FAKE_TLS_MOD_RND 0x10 #define FAKE_TLS_MOD_RND 0x10
#define FAKE_TLS_MOD_DUP_SID 0x20 #define FAKE_TLS_MOD_DUP_SID 0x20
#define FAKE_TLS_MOD_RND_SNI 0x40 #define FAKE_TLS_MOD_RND_SNI 0x40
#define FAKE_TLS_MOD_PADENCAP 0x80 #define FAKE_TLS_MOD_SNI 0x80
#define FAKE_TLS_MOD_PADENCAP 0x100
#define FAKE_MAX_TCP 1460
#define FAKE_MAX_UDP 1472
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
struct fake_tls_mod_cache
{
size_t extlen_offset, padlen_offset;
};
struct fake_tls_mod
{
char sni[64];
uint32_t mod;
};
struct desync_profile struct desync_profile
{ {
int n; // number of the profile int n; // number of the profile
@@ -74,12 +88,13 @@ struct desync_profile
autottl desync_autottl, desync_autottl6; autottl desync_autottl, desync_autottl6;
uint32_t desync_fooling_mode; uint32_t desync_fooling_mode;
uint32_t desync_badseq_increment, desync_badseq_ack_increment; uint32_t desync_badseq_increment, desync_badseq_ack_increment;
uint8_t fake_http[1460],fake_unknown[1460],fake_syndata[1460],seqovl_pattern[1460],fsplit_pattern[1460];
uint8_t fake_unknown_udp[1472],udplen_pattern[1472],fake_quic[1472],fake_wg[1472],fake_dht[1472];
size_t fake_http_size,fake_quic_size,fake_wg_size,fake_dht_size,fake_unknown_size,fake_syndata_size,fake_unknown_udp_size;
uint8_t fake_tls[1460],fake_tls_mod; struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht,fake_discord,fake_stun;
size_t fake_tls_size, fake_tls_extlen_offset, fake_tls_padlen_offset; uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],fsplit_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP];
size_t fake_syndata_size;
struct fake_tls_mod tls_mod_last;
struct blob_item *tls_fake_last;
int udplen_increment; int udplen_increment;
@@ -113,6 +128,7 @@ void dp_entry_destroy(struct desync_profile_list *entry);
void dp_list_destroy(struct desync_profile_list_head *head); void dp_list_destroy(struct desync_profile_list_head *head);
bool dp_list_have_autohostlist(struct desync_profile_list_head *head); bool dp_list_have_autohostlist(struct desync_profile_list_head *head);
void dp_init(struct desync_profile *dp); void dp_init(struct desync_profile *dp);
bool dp_fake_defaults(struct desync_profile *dp);
void dp_clear(struct desync_profile *dp); void dp_clear(struct desync_profile *dp);
struct params_s struct params_s

View File

@@ -517,3 +517,65 @@ bool port_filters_deny_if_empty(struct port_filters_head *head)
if (LIST_FIRST(head)) return true; if (LIST_FIRST(head)) return true;
return pf_parse("0",&pf) && port_filter_add(head,&pf); return pf_parse("0",&pf) && port_filter_add(head,&pf);
} }
struct blob_item *blob_collection_add(struct blob_collection_head *head)
{
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
if (entry)
{
// insert to the end
struct blob_item *itemc,*iteml=LIST_FIRST(head);
if (iteml)
{
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
LIST_INSERT_AFTER(iteml, entry, next);
}
else
LIST_INSERT_HEAD(head, entry, next);
}
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 *entry = calloc(1,sizeof(struct blob_item));
if (!entry) return NULL;
if (!(entry->data = malloc(size+size_reserve)))
{
free(entry);
return NULL;
}
if (data) memcpy(entry->data,data,size);
entry->size = size;
entry->size_buf = size+size_reserve;
// insert to the end
struct blob_item *itemc,*iteml=LIST_FIRST(head);
if (iteml)
{
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
LIST_INSERT_AFTER(iteml, entry, next);
}
else
LIST_INSERT_HEAD(head, entry, next);
return entry;
}
void blob_collection_destroy(struct blob_collection_head *head)
{
struct blob_item *entry;
while ((entry = LIST_FIRST(head)))
{
LIST_REMOVE(entry, next);
free(entry->extra);
free(entry->extra2);
free(entry->data);
free(entry);
}
}
bool blob_collection_empty(const struct blob_collection_head *head)
{
return !LIST_FIRST(head);
}

View File

@@ -146,3 +146,18 @@ bool port_filter_add(struct port_filters_head *head, const port_filter *pf);
void port_filters_destroy(struct port_filters_head *head); void port_filters_destroy(struct port_filters_head *head);
bool port_filters_in_range(const struct port_filters_head *head, uint16_t port); bool port_filters_in_range(const struct port_filters_head *head, uint16_t port);
bool port_filters_deny_if_empty(struct port_filters_head *head); bool port_filters_deny_if_empty(struct port_filters_head *head);
struct blob_item {
uint8_t *data; // main data blob
size_t size; // main data blob size
size_t size_buf;// main data blob allocated size
void *extra; // any data without size
void *extra2; // any data without size
LIST_ENTRY(blob_item) next;
};
LIST_HEAD(blob_collection_head, blob_item);
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);
void blob_collection_destroy(struct blob_collection_head *head);
bool blob_collection_empty(const struct blob_collection_head *head);

View File

@@ -35,6 +35,8 @@ const char *l7proto_str(t_l7proto l7)
case QUIC: return "quic"; case QUIC: return "quic";
case WIREGUARD: return "wireguard"; case WIREGUARD: return "wireguard";
case DHT: return "dht"; case DHT: return "dht";
case DISCORD: return "discord";
case STUN: return "stun";
default: return "unknown"; default: return "unknown";
} }
} }
@@ -45,7 +47,9 @@ bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
(l7proto==TLS && (filter_l7 & L7_PROTO_TLS)) || (l7proto==TLS && (filter_l7 & L7_PROTO_TLS)) ||
(l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) || (l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) ||
(l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) || (l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) ||
(l7proto==DHT && (filter_l7 & L7_PROTO_DHT)); (l7proto==DHT && (filter_l7 & L7_PROTO_DHT)) ||
(l7proto==DISCORD && (filter_l7 & L7_PROTO_DISCORD)) ||
(l7proto==STUN && (filter_l7 & L7_PROTO_STUN));
} }
#define PM_ABS 0 #define PM_ABS 0
@@ -844,7 +848,16 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
return !memcmp(data + pn_offset + pkn_len + cryptlen, atag, 16); return !memcmp(data + pn_offset + pkn_len + cryptlen, atag, 16);
} }
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len) struct range64
{
uint64_t offset,len;
};
#define MAX_DEFRAG_PIECES 128
static int cmp_range64(const void * a, const void * b)
{
return (((struct range64*)a)->offset < ((struct range64*)b)->offset) ? -1 : (((struct range64*)a)->offset > ((struct range64*)b)->offset) ? 1 : 0;
}
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len, bool *bFull)
{ {
// Crypto frame can be split into multiple chunks // Crypto frame can be split into multiple chunks
// chromium randomly splits it and pads with zero/one bytes to force support the standard // chromium randomly splits it and pads with zero/one bytes to force support the standard
@@ -853,13 +866,15 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
if (*defrag_len<10) return false; if (*defrag_len<10) return false;
uint8_t *defrag_data = defrag+10; uint8_t *defrag_data = defrag+10;
size_t defrag_data_len = *defrag_len-10; size_t defrag_data_len = *defrag_len-10;
uint8_t ft; uint8_t ft;
uint64_t offset,sz,szmax=0,zeropos=0,pos=0; uint64_t offset,sz,szmax=0,zeropos=0,pos=0;
bool found=false; bool found=false;
struct range64 ranges[MAX_DEFRAG_PIECES];
int i,range=0;
while(pos<clean_len) while(pos<clean_len)
{ {
// frame type
ft = clean[pos]; ft = clean[pos];
pos++; pos++;
if (ft>1) // 00 - padding, 01 - ping if (ft>1) // 00 - padding, 01 - ping
@@ -867,6 +882,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
if (ft!=6) return false; // dont want to know all possible frame type formats if (ft!=6) return false; // dont want to know all possible frame type formats
if (pos>=clean_len) return false; if (pos>=clean_len) return false;
if (range>=MAX_DEFRAG_PIECES) return false;
if ((pos+tvb_get_size(clean[pos])>=clean_len)) return false; if ((pos+tvb_get_size(clean[pos])>=clean_len)) return false;
pos += tvb_get_varint(clean+pos, &offset); pos += tvb_get_varint(clean+pos, &offset);
@@ -875,7 +891,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
pos += tvb_get_varint(clean+pos, &sz); pos += tvb_get_varint(clean+pos, &sz);
if ((pos+sz)>clean_len) return false; if ((pos+sz)>clean_len) return false;
if ((offset+sz)>defrag_data_len) return false; if ((offset+sz)>defrag_data_len) return false; // defrag buf overflow
if (zeropos < offset) if (zeropos < offset)
// make sure no uninitialized gaps exist in case of not full fragment coverage // make sure no uninitialized gaps exist in case of not full fragment coverage
memset(defrag_data+zeropos,0,offset-zeropos); memset(defrag_data+zeropos,0,offset-zeropos);
@@ -886,6 +902,10 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
found=true; found=true;
pos+=sz; pos+=sz;
ranges[range].offset = offset;
ranges[range].len = sz;
range++;
} }
} }
if (found) if (found)
@@ -897,6 +917,23 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
phton64(defrag+2,szmax); phton64(defrag+2,szmax);
defrag[2] |= 0xC0; // 64 bit value defrag[2] |= 0xC0; // 64 bit value
*defrag_len = (size_t)(szmax+10); *defrag_len = (size_t)(szmax+10);
qsort(ranges, range, sizeof(*ranges), cmp_range64);
//for(i=0 ; i<range ; i++)
// printf("RANGE %zu len %zu\n",ranges[i].offset,ranges[i].len);
for(i=0,offset=0,*bFull=true ; i<range ; i++)
{
if (ranges[i].offset!=offset)
{
*bFull = false;
break;
}
offset += ranges[i].len;
}
//printf("bFull=%u\n",*bFull);
} }
return found; return found;
} }
@@ -973,3 +1010,18 @@ bool IsDhtD1(const uint8_t *data, size_t len)
{ {
return len>=7 && data[0]=='d' && data[1]=='1' && data[len-1]=='e'; return len>=7 && data[0]=='d' && data[1]=='1' && data[len-1]=='e';
} }
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len)
{
return len==74 &&
data[0]==0 && data[1]==1 &&
data[2]==0 && data[3]==70 &&
data[8]==0 && memcmp(&data[8],&data[9],63)==0; // address is not set in requests
}
bool IsStunMessage(const uint8_t *data, size_t len)
{
return len>=20 && // header size
(data[0]&0xC0)==0 && // 2 most significant bits must be zeroes
(data[3]&0b11)==0 && // length must be a multiple of 4
ntohl(*(uint32_t*)(&data[4]))==0x2112A442 && // magic cookie
ntohs(*(uint16_t*)(&data[2]))==len-20;
}

View File

@@ -7,12 +7,14 @@
#include "crypto/aes-gcm.h" #include "crypto/aes-gcm.h"
#include "helpers.h" #include "helpers.h"
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto; typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT, DISCORD, STUN} t_l7proto;
#define L7_PROTO_HTTP 0x00000001 #define L7_PROTO_HTTP 0x00000001
#define L7_PROTO_TLS 0x00000002 #define L7_PROTO_TLS 0x00000002
#define L7_PROTO_QUIC 0x00000004 #define L7_PROTO_QUIC 0x00000004
#define L7_PROTO_WIREGUARD 0x00000008 #define L7_PROTO_WIREGUARD 0x00000008
#define L7_PROTO_DHT 0x00000010 #define L7_PROTO_DHT 0x00000010
#define L7_PROTO_DISCORD 0x00000020
#define L7_PROTO_STUN 0x00000040
#define L7_PROTO_UNKNOWN 0x80000000 #define L7_PROTO_UNKNOWN 0x80000000
const char *l7proto_str(t_l7proto l7); const char *l7proto_str(t_l7proto l7);
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7); bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7);
@@ -72,6 +74,8 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len); bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
bool IsDhtD1(const uint8_t *data, size_t len); bool IsDhtD1(const uint8_t *data, size_t len);
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len);
bool IsStunMessage(const uint8_t *data, size_t len);
#define QUIC_MAX_CID_LENGTH 20 #define QUIC_MAX_CID_LENGTH 20
typedef struct quic_cid { typedef struct quic_cid {
@@ -87,5 +91,6 @@ uint8_t QUICDraftVersion(uint32_t version);
bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid); bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid);
bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len); bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len);
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len); // returns true if crypto frames were found . bFull = true if crypto frame fragments have full coverage
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len, bool *bFull);
//bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello); //bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello);

View File

@@ -3,7 +3,7 @@ CFLAGS += -std=gnu99 -Os -flto=auto
CFLAGS_SYSTEMD = -DUSE_SYSTEMD CFLAGS_SYSTEMD = -DUSE_SYSTEMD
CFLAGS_BSD = -Wno-address-of-packed-member CFLAGS_BSD = -Wno-address-of-packed-member
LIBS = -lz -lpthread LIBS = -lz -lpthread
LIBS_SYSTEMD = -lz -lsystemd LIBS_SYSTEMD = -lsystemd
LIBS_ANDROID = -lz LIBS_ANDROID = -lz
SRC_FILES = *.c SRC_FILES = *.c
SRC_FILES_ANDROID = $(SRC_FILES) andr/*.c SRC_FILES_ANDROID = $(SRC_FILES) andr/*.c
@@ -14,7 +14,7 @@ tpws: $(SRC_FILES)
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES) $(LIBS) $(LDFLAGS) $(CC) -s $(CFLAGS) -o tpws $(SRC_FILES) $(LIBS) $(LDFLAGS)
systemd: $(SRC_FILES) systemd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o tpws $(SRC_FILES) $(LIBS_SYSTEMD) $(LDFLAGS) $(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o tpws $(SRC_FILES) $(LIBS) $(LIBS_SYSTEMD) $(LDFLAGS)
android: $(SRC_FILES) android: $(SRC_FILES)
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES_ANDROID) $(LIBS_ANDROID) $(LDFLAGS) $(CC) -s $(CFLAGS) -o tpws $(SRC_FILES_ANDROID) $(LIBS_ANDROID) $(LDFLAGS)

View File

@@ -50,6 +50,7 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, int lev
{ {
va_copy(args2,args); va_copy(args2,args);
DLOG_CON(format,syslog_priority,args2); DLOG_CON(format,syslog_priority,args2);
va_end(args2);
} }
if (params.debug>=level) if (params.debug>=level)
{ {