mirror of
https://github.com/bol-van/zapret2.git
synced 2026-03-15 22:46:09 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1d02aa81d | ||
|
|
38ef16bcdf | ||
|
|
d0fe0f25ba | ||
|
|
0ab1e19ce2 | ||
|
|
9a6353cb14 | ||
|
|
0bc4ce03d2 | ||
|
|
a1f28e4c4a | ||
|
|
a7e6f07ae4 | ||
|
|
fd0a076504 | ||
|
|
5603e1c760 | ||
|
|
873262e49c | ||
|
|
99f64c9b16 | ||
|
|
9ab4ff2acb | ||
|
|
11ab7f7776 | ||
|
|
b972dadc72 | ||
|
|
02a5c28db4 | ||
|
|
792fc02268 | ||
|
|
402943034a | ||
|
|
0f8c3f3fd8 | ||
|
|
89b6a65e16 | ||
|
|
94aded5d21 | ||
|
|
d5c608d5d8 | ||
|
|
be7854eefe | ||
|
|
b577d3cc22 |
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
@@ -131,7 +131,7 @@ jobs:
|
||||
esac
|
||||
(
|
||||
cd luajit2-*
|
||||
make BUILDMODE=static HOST_CC="$HOSTCC" CROSS= CC="$CC" TARGET_AR="$AR rcus" TARGET_STRIP=$STRIP CFLAGS="-Os -s -flto=auto $CFLAGS" -j$(nproc)
|
||||
make BUILDMODE=static XCFLAGS=-DLUAJIT_DISABLE_FFI HOST_CC="$HOSTCC" CROSS= CC="$CC" TARGET_AR="$AR rcus" TARGET_STRIP=$STRIP CFLAGS="-Os -s -flto=auto $CFLAGS" -j$(nproc)
|
||||
make install PREFIX= DESTDIR=$DEPS_DIR
|
||||
)
|
||||
LJIT=1
|
||||
@@ -242,7 +242,7 @@ jobs:
|
||||
esac
|
||||
(
|
||||
cd luajit2-*
|
||||
make BUILDMODE=static HOST_CC="$HOSTCC" CROSS= CC="$CC" TARGET_AR="$AR rcus" TARGET_STRIP=$STRIP CFLAGS="-Os -flto=auto $CFLAGS" -j$(nproc)
|
||||
make BUILDMODE=static XCFLAGS=-DLUAJIT_DISABLE_FFI HOST_CC="$HOSTCC" CROSS= CC="$CC" TARGET_AR="$AR rcus" TARGET_STRIP=$STRIP CFLAGS="-Os -flto=auto $CFLAGS" -j$(nproc)
|
||||
make install PREFIX= DESTDIR=$DEPS_DIR
|
||||
)
|
||||
LJIT=1
|
||||
@@ -319,7 +319,7 @@ jobs:
|
||||
wget -qO- https://github.com/openresty/luajit2/archive/refs/tags/v${LUAJIT_RELEASE}.tar.gz | tar -xz
|
||||
(
|
||||
cd luajit2-*
|
||||
make BUILDMODE=static HOST_CC=gcc CC=$CC CFLAGS="-Os -flto=auto $CFLAGS"
|
||||
make BUILDMODE=static XCFLAGS=-DLUAJIT_DISABLE_FFI HOST_CC=gcc CC=$CC CFLAGS="-Os -flto=auto $CFLAGS"
|
||||
make install PREFIX= DESTDIR=$DEPS_DIR
|
||||
)
|
||||
|
||||
@@ -430,7 +430,7 @@ jobs:
|
||||
wget -q https://github.com/openresty/luajit2/archive/refs/tags/v${LUAJIT_RELEASE}.tar.gz &&
|
||||
tar -xzf v${LUAJIT_RELEASE}.tar.gz &&
|
||||
rm -f v${LUAJIT_RELEASE}.tar.gz &&
|
||||
make -C luajit2-${LUAJIT_RELEASE} BUILDMODE=static CFLAGS="-Os -s" &&
|
||||
make -C luajit2-${LUAJIT_RELEASE} BUILDMODE=static XCFLAGS=-DLUAJIT_DISABLE_FFI CFLAGS="-Os -s" &&
|
||||
make -C luajit2-${LUAJIT_RELEASE} install
|
||||
|
||||
- name: Build winws
|
||||
|
||||
14
docs/changes.txt
Normal file
14
docs/changes.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
v0.1.0
|
||||
|
||||
first public release
|
||||
|
||||
v0.1.1
|
||||
|
||||
* nfqws2: fixed crash on 32-bit platforms if debug is enabled
|
||||
|
||||
v0.1.2
|
||||
|
||||
* nfqws2: 'mtproto' protocol, 'mtproto_initial' payload
|
||||
* nfqws2: 'known' protocol and payload filter
|
||||
* nfqws2: 'aes_ctr' luacall
|
||||
* zapret-antidpi: rst
|
||||
@@ -16,9 +16,9 @@ download latest releast, unpack, cd to it's directory
|
||||
make BUILDMODE=static CFLAGS="-Os"
|
||||
make install
|
||||
|
||||
5) cd to %ZAPRET_BASE%/nfq
|
||||
5) cd to %ZAPRET_BASE%/nfq2
|
||||
|
||||
cd C:/Users/user/Downloads/zapret2/nfq
|
||||
cd C:/Users/user/Downloads/zapret2/nfq2
|
||||
|
||||
6) Compile nfqws2
|
||||
|
||||
|
||||
@@ -278,6 +278,93 @@ nfqws --dpi-desync=ipfrag2 --dpi-desync-ipfrag-pos-udp=8
|
||||
nfqws2 --lua-desync=send:ipfrag:ipfrag_pos_udp=8 --lua-desync=drop
|
||||
```
|
||||
|
||||
Рассмотрим теперь пример из zapret-win-bundle. Как `preset_example.cmd` был переписан в `preset2_example.cmd`.
|
||||
|
||||
Фильтр windivert поменялся только одним - больше нет параметров `--wf-tcp` и `--wf-udp`. Они разделены по направлениям in/out.
|
||||
Для отлова UDP не перехватывается весь udp порт - используются пейлоад фильтры windivert. Тем самым во много раз экономятся ресурсы процессора,
|
||||
вплоть до сотен раз. Когда попадет что-то на мощную выгрузку торрента, и она пойдет через winws, вы вполне можете словить загрузку целого ядра CPU
|
||||
и вой кулеров вашего ноута. А так его не будет.
|
||||
|
||||
Для TCP так тоже можно было бы сделать, но не всегда. Во-первых, надо перехватывать SYN по порту, чтобы работал conntrack.
|
||||
Но это решаемо. А что не решаемо - это перехват вторых частей kyber tls hello. Их невозможно опознать без связи с предыдущими фрагментами. Поэтому перехватывается весь порт.
|
||||
Для HTTP вопрос решаемый, поскольку там нет реассемблирования запросов, но http сейчас стал настолько редким, что и смысла нет заморачиваться.
|
||||
|
||||
Везде расставлены фильтры профиля мультистратегии `--filter-l7`, фильтры по `--out-range` и по `--payload`.
|
||||
Зачем ? В основном для сокращения вызовов LUA кода, который заведомо медленнее C кода.
|
||||
Если пакет не попадет в профили с LUA - ни о каком вызове кода LUA речи быть не может.
|
||||
Если пакет попал в профиль с LUA, то после первых 10 пакетов с данными наступает отсечение по верхней границе range. Все LUA инстансы входят в состояние instance cutoff,
|
||||
соединение входит в состояние "lua cutoff" по направлению "out". Значит вызовов LUA не будет вообще. Не просто вызовов, а даже обращения к движку LUA
|
||||
с какой-либо целью. Будет только C код, который посмотрит на признак "cutoff" и сразу же отпустит пакет.
|
||||
|
||||
Так же везде расставлены фильтры по payload type. Отчасти так же с целью сократить вызовы LUA даже в пределах первых 10 пакетов с данными.
|
||||
С другой стороны, даже при совпадении протокола соединения (`--filter-l7`) может пробежать не интересующий нас пейлоад.
|
||||
По умолчанию многие функции из `zapret-antidpi.lua` реагируют только на известные типы пейлоада, но не на конкретные, а на любые известные.
|
||||
Если допустить малореальный, но гипотетически возможный сценарий, что в рамках протокола http будет отправлен блок данных с tls или фраза, похожая на сообщение из xmpp,
|
||||
то тип пейлоада выскочит tls_client_hello или xmpp_stream, например. Лучше от этого сразу уберечься. Тем более что в других видах протоколов - xmpp, например, -
|
||||
пейлоады могут проскакивать нескольких типов вполне ожидаемо. Но работать надо не по всем.
|
||||
|
||||
В фейке для TLS по умолчанию - fake_default_tls - однократно при старте меняется SNI с "www.microsoft.com" на случайный и рандомизируется поле "random" в TLS handshake.
|
||||
Это делается простой строчкой LUA кода. Больше нет никаких специальных параметров *nfqws2* для модификации пейлоадов.
|
||||
В профиле для youtube на лету меняется SNI на "www.google.com", копируется поле TLS "session id" с обрабатываемого в данный момент TLS handshake.
|
||||
|
||||
```
|
||||
start "zapret: http,https,quic" /min "%~dp0winws.exe" ^
|
||||
--wf-tcp=80,443 ^
|
||||
--wf-raw-part=@"%~dp0windivert.filter\windivert_part.discord_media.txt" ^
|
||||
--wf-raw-part=@"%~dp0windivert.filter\windivert_part.stun.txt" ^
|
||||
--wf-raw-part=@"%~dp0windivert.filter\windivert_part.wireguard.txt" ^
|
||||
--wf-raw-part=@"%~dp0windivert.filter\windivert_part.quic_initial_ietf.txt" ^
|
||||
--filter-tcp=80 --dpi-desync=fake,fakedsplit --dpi-desync-autottl=2 --dpi-desync-fooling=md5sig --new ^
|
||||
--filter-tcp=443 --hostlist="%~dp0files\list-youtube.txt" --dpi-desync=fake,multidisorder --dpi-desync-split-pos=1,midsld --dpi-desync-repeats=11 --dpi-desync-fooling=md5sig --dpi-desync-fake-tls-mod=rnd,dupsid,sni=www.google.com --new ^
|
||||
--filter-tcp=443 --dpi-desync=fake,multidisorder --dpi-desync-split-pos=midsld --dpi-desync-repeats=6 --dpi-desync-fooling=badseq,md5sig --new ^
|
||||
--filter-l7=quic --hostlist="%~dp0files\list-youtube.txt" --dpi-desync=fake --dpi-desync-repeats=11 --dpi-desync-fake-quic="%~dp0files\quic_initial_www_google_com.bin" --new ^
|
||||
--filter-l7=quic --dpi-desync=fake --dpi-desync-repeats=11 ^
|
||||
--filter-l7=wireguard,stun,discord --dpi-desync=fake --dpi-desync-repeats=2
|
||||
|
||||
|
||||
start "zapret: http,https,quic" /min "%~dp0winws2.exe" ^
|
||||
--wf-tcp-out=80,443 ^
|
||||
--lua-init=@"%~dp0lua\zapret-lib.lua" --lua-init=@"%~dp0lua\zapret-antidpi.lua" ^
|
||||
--lua-init="fake_default_tls = tls_mod(fake_default_tls,'rnd,rndsni')" ^
|
||||
--blob=quic_google:@"%~dp0files\quic_initial_www_google_com.bin" ^
|
||||
--wf-raw-part=@"%~dp0windivert.filter\windivert_part.discord_media.txt" ^
|
||||
--wf-raw-part=@"%~dp0windivert.filter\windivert_part.stun.txt" ^
|
||||
--wf-raw-part=@"%~dp0windivert.filter\windivert_part.wireguard.txt" ^
|
||||
--wf-raw-part=@"%~dp0windivert.filter\windivert_part.quic_initial_ietf.txt" ^
|
||||
--filter-tcp=80 --filter-l7=http ^
|
||||
--out-range=-d10 ^
|
||||
--payload=http_req ^
|
||||
--lua-desync=fake:blob=fake_default_http:ip_autottl=-2,3-20:ip6_autottl=-2,3-20:tcp_md5 ^
|
||||
--lua-desync=fakedsplit:ip_autottl=-2,3-20:ip6_autottl=-2,3-20:tcp_md5 ^
|
||||
--new ^
|
||||
--filter-tcp=443 --filter-l7=tls --hostlist="%~dp0files\list-youtube.txt" ^
|
||||
--out-range=-d10 ^
|
||||
--payload=tls_client_hello ^
|
||||
--lua-desync=fake:blob=fake_default_tls:tcp_md5:repeats=11:tls_mod=rnd,dupsid,sni=www.google.com ^
|
||||
--lua-desync=multidisorder:pos=1,midsld ^
|
||||
--new ^
|
||||
--filter-tcp=443 --filter-l7=tls ^
|
||||
--out-range=-d10 ^
|
||||
--payload=tls_client_hello ^
|
||||
--lua-desync=fake:blob=fake_default_tls:tcp_md5:tcp_seq=-10000:repeats=6 ^
|
||||
--lua-desync=multidisorder:pos=midsld ^
|
||||
--new ^
|
||||
--filter-udp=443 --filter-l7=quic --hostlist="%~dp0files\list-youtube.txt" ^
|
||||
--out-range=-d10 ^
|
||||
--payload=quic_initial ^
|
||||
--lua-desync=fake:blob=quic_google:repeats=11 ^
|
||||
--new ^
|
||||
--filter-udp=443 --filter-l7=quic ^
|
||||
--out-range=-d10 ^
|
||||
--payload=quic_initial ^
|
||||
--lua-desync=fake:blob=fake_default_quic:repeats=11 ^
|
||||
--new ^
|
||||
--filter-l7=wireguard,stun,discord ^
|
||||
--out-range=-d10 ^
|
||||
--payload=wireguard_initiation,wireguard_cookie,stun_binding_req,discord_ip_discovery ^
|
||||
--lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2
|
||||
```
|
||||
|
||||
### Какие есть еще параметры
|
||||
|
||||
Как узнать какие есть еще функции и какие у них бывают параметры ? Смотрите `zapret-antidpi.lua`. Перед каждой функцией подробно описано какие параметры она берет.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
REGISTER sip:192.168.102.23 SIP/2.0
|
||||
Via: SIP/2.0/UDP 192.168.102.250:51781;rport;branch=z9hG4bKPj3f42ea713eca49ec93f6cb69f6c38014
|
||||
Max-Forwards: 70
|
||||
From: <sip:233@192.168.102.23>;tag=ca565d7bd4e24a6d80c631d395ee117e
|
||||
To: <sip:233@192.168.102.23>
|
||||
Call-ID: a5e53e302b2d4a4d83c1455527c882c3
|
||||
CSeq: 26538 REGISTER
|
||||
REGISTER sip:192.168.1.1 SIP/2.0
|
||||
Via: SIP/2.0/UDP 192.168.1.2:42931;rport;branch=z9hG4bKPj3fd2e8713ffcd90c43f6ce69f6c98461
|
||||
Max-Forwards: 50
|
||||
From: <sip:703@192.168.1.1>;tag=ca565d7bd4e24a6d80c631d395ee117e
|
||||
To: <sip:703@192.168.1.1>
|
||||
Call-ID: dfec38302b8cea3d83c1452527c895c1
|
||||
CSeq: 26139 REGISTER
|
||||
User-Agent: MicroSIP/3.21.5
|
||||
Contact: <sip:233@192.168.102.250:51781;ob>
|
||||
Contact: <sip:703@192.168.1.2:42931;ob>
|
||||
Expires: 300
|
||||
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
|
||||
Content-Length: 0
|
||||
|
||||
@@ -25,7 +25,7 @@ standard fooling :
|
||||
* ip6_autottl=delta,min-max - set ip.ip_ttl to auto discovered ttl
|
||||
|
||||
* ip6_hopbyhop[=hex] - add hopbyhop ipv6 header with optional data. data size must be 6+N*8. all zero by default.
|
||||
* ip6_hopbyhop2 - add 2 hopbyhop ipv6 headers with optional data. data size must be 6+N*8. all zero by default.
|
||||
* ip6_hopbyhop2[=hex] - add 2 hopbyhop ipv6 headers with optional data. data size must be 6+N*8. all zero by default.
|
||||
* ip6_destopt[=hex] - add destopt ipv6 header with optional data. data size must be 6+N*8. all zero by default.
|
||||
* ip6_routing[=hex] - add routing ipv6 header with optional data. data size must be 6+N*8. all zero by default.
|
||||
* ip6_ah[=hex] - add authentication ipv6 header with optional data. data size must be 6+N*4. 0000 + 4 random bytes by default.
|
||||
@@ -36,8 +36,9 @@ standard fooling :
|
||||
* tcp_md5[=hex] - add MD5 header with optional 16-byte data. all zero by default.
|
||||
* tcp_flags_set=<list> - set tcp flags in comma separated list
|
||||
* tcp_unflags_set=<list> - unset tcp flags in comma separated list
|
||||
* tcp_ts_up - move timestamp tcp option to the top if present (workaround for badack without badseq fooling)
|
||||
|
||||
* fool - custom fooling function : fool_func(dis, fooling_options)
|
||||
* fool=fool_function - custom fooling function : fool_func(dis, fooling_options)
|
||||
|
||||
standard reconstruct :
|
||||
|
||||
@@ -60,11 +61,11 @@ standard ip_id :
|
||||
|
||||
standard ipfrag :
|
||||
|
||||
* ipfrag - ipfrag function name. "ipfrag2" by default if empty
|
||||
* ipfrag[=frag_function] - ipfrag function name. "ipfrag2" by default if empty
|
||||
* ipfrag_disorder - send fragments from last to first
|
||||
* ipfrag2 : ipfrag_pos_udp - udp frag position. ipv4 : starting from L4 header. ipb6: starting from fragmentable part. must be multiple of 8. default 8
|
||||
* ipfrag2 : ipfrag_pos_tcp - tcp frag position. ipv4 : starting from L4 header. ipb6: starting from fragmentable part. must be multiple of 8. default 32
|
||||
* ipfrag2 : ipfrag_next - next protocol field in ipv6 fragment extenstion header of the second fragment. same as first by default.
|
||||
* ipfrag2 : ipfrag_disorder - send fragments from last to first
|
||||
|
||||
]]
|
||||
|
||||
@@ -82,17 +83,17 @@ function pktdebug(ctx, desync)
|
||||
end
|
||||
|
||||
-- drop packet
|
||||
-- standard args : direction
|
||||
-- standard args : direction, payload
|
||||
function drop(ctx, desync)
|
||||
direction_cutoff_opposite(ctx, desync, "any")
|
||||
if direction_check(desync, "any") then
|
||||
if direction_check(desync, "any") and payload_check(desync,"all") then
|
||||
DLOG("drop")
|
||||
return VERDICT_DROP
|
||||
end
|
||||
end
|
||||
|
||||
-- nfqws1 : "--dup"
|
||||
-- standard args : direction, fooling, ip_id, rawsend, reconstruct
|
||||
-- standard args : direction, fooling, ip_id, ipfrag, rawsend, reconstruct
|
||||
function send(ctx, desync)
|
||||
direction_cutoff_opposite(ctx, desync, "any")
|
||||
if direction_check(desync, "any") then
|
||||
@@ -256,7 +257,7 @@ function synack(ctx, desync)
|
||||
end
|
||||
|
||||
|
||||
-- nfqws1 : "--wssize"
|
||||
-- nfqws1 : "--wsize"
|
||||
-- arg : wsize=N . tcp window size
|
||||
-- arg : scale=N . tcp option scale factor
|
||||
function wsize(ctx, desync)
|
||||
@@ -273,7 +274,7 @@ function wsize(ctx, desync)
|
||||
end
|
||||
end
|
||||
|
||||
-- nfqws1 : "--wsize"
|
||||
-- nfqws1 : "--wssize"
|
||||
-- standard args : direction
|
||||
-- arg : wsize=N . tcp window size
|
||||
-- arg : scale=N . tcp option scale factor
|
||||
@@ -322,6 +323,31 @@ function syndata(ctx, desync)
|
||||
end
|
||||
end
|
||||
|
||||
-- nfqws1 : "--dpi-desync=rst"
|
||||
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag
|
||||
-- arg : rstack - send RST,ACK instead of RST
|
||||
function rst(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff(ctx)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
if direction_check(desync, "any") and payload_check(desync) then
|
||||
if replay_first(desync) then
|
||||
local dis = deepcopy(desync.dis)
|
||||
dis.payload = ""
|
||||
dis.tcp.th_flags = TH_RST + (desync.arg.rstack and TH_ACK or 0)
|
||||
apply_fooling(desync, dis)
|
||||
apply_ip_id(desync, dis, nil, "none")
|
||||
DLOG("rst")
|
||||
-- it uses rawsend, reconstruct and ipfrag options
|
||||
rawsend_dissect_ipfrag(dis, desync_opts(desync))
|
||||
else
|
||||
DLOG("rst: not acting on further replay pieces")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- nfqws1 : "--dpi-desync=fake"
|
||||
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag
|
||||
-- arg : blob=<blob> - fake payload
|
||||
|
||||
@@ -762,20 +762,19 @@ function direction_cutoff_opposite(ctx, desync, def)
|
||||
end
|
||||
end
|
||||
-- check if desync payload type comply with payload type list in arg.payload
|
||||
-- if arg.payload is not present - check if desync payload is not "empty" and not "unknown" (nfqws1 behavior without "--desync-any-protocol" option)
|
||||
function payload_check(desync)
|
||||
if desync.arg.payload and desync.arg.payload~="known" then
|
||||
if not in_list(desync.arg.payload, "all") and not in_list(desync.arg.payload, desync.l7payload) then
|
||||
DLOG("payload_check: payload '"..desync.l7payload.."' does not pass '"..desync.arg.payload.."' filter")
|
||||
return false
|
||||
end
|
||||
else
|
||||
if desync.l7payload=="empty" or desync.l7payload=="unknown" then
|
||||
DLOG("payload_check: payload filter accepts only known protocols")
|
||||
return false
|
||||
end
|
||||
-- if arg.payload is not present - check for known payload - not empty and not unknown (nfqws1 behavior without "--desync-any-protocol" option)
|
||||
-- if arg.payload is prefixed with '~' - it means negation
|
||||
function payload_check(desync, def)
|
||||
local b
|
||||
local argpl = desync.arg.payload or def or "known"
|
||||
local neg = string.sub(argpl,1,1)=="~"
|
||||
local pl = neg and string.sub(argpl,2) or argpl
|
||||
|
||||
b = neg ~= (in_list(pl, "all") or in_list(pl, desync.l7payload) or in_list(pl, "known") and desync.l7payload~="unknown" and desync.l7payload~="empty")
|
||||
if not b then
|
||||
DLOG("payload_check: payload '"..desync.l7payload.."' does not pass '"..argpl.."' filter")
|
||||
end
|
||||
return true
|
||||
return b
|
||||
end
|
||||
|
||||
-- return name of replay drop field in track.lua_state for the current desync function instance
|
||||
@@ -978,3 +977,4 @@ function ipfrag2(dis, ipfrag_options)
|
||||
|
||||
return {dis1,dis2}
|
||||
end
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ end
|
||||
|
||||
|
||||
function test_crypto()
|
||||
test_run({test_random, test_aes, test_aes_gcm, test_hkdf, test_hash})
|
||||
test_run({test_random, test_aes, test_aes_gcm, test_aes_ctr, test_hkdf, test_hash})
|
||||
end
|
||||
|
||||
function test_random()
|
||||
@@ -187,6 +187,42 @@ function test_aes_gcm()
|
||||
end
|
||||
end
|
||||
|
||||
function test_aes_ctr()
|
||||
local clear_text="test message "..brandom_az09(math.random(10,50))
|
||||
local iv, key, encrypted, decrypted
|
||||
|
||||
for key_size=16,32,8 do
|
||||
iv = brandom(16)
|
||||
key = brandom(key_size)
|
||||
|
||||
print()
|
||||
print("* aes_ctr test key_size "..tostring(key_size))
|
||||
|
||||
print("clear text: "..clear_text);
|
||||
|
||||
print("* encrypting")
|
||||
encrypted = aes_ctr(key, iv, clear_text)
|
||||
print("encrypted: "..str_or_hex(encrypted))
|
||||
|
||||
print("* decrypting")
|
||||
decrypted = aes_ctr(key, iv, encrypted)
|
||||
print("decrypted: "..str_or_hex(decrypted))
|
||||
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||
test_assert(decrypted==clear_text)
|
||||
|
||||
print("* decrypting with bad key")
|
||||
decrypted = aes_ctr(bu8(u8(string.sub(key,1,1))+1)..string.sub(key,2), iv, encrypted)
|
||||
print("decrypted: "..str_or_hex(decrypted))
|
||||
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||
test_assert(decrypted~=clear_text)
|
||||
|
||||
print("* decrypting with bad iv")
|
||||
decrypted = aes_ctr(key, bu8(u8(string.sub(iv,1,1))+1)..string.sub(iv,2), encrypted)
|
||||
print("decrypted: "..str_or_hex(decrypted))
|
||||
print( decrypted==clear_text and "DECRYPT OK" or "DECRYPT ERROR" )
|
||||
test_assert(decrypted~=clear_text)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function test_ub()
|
||||
|
||||
@@ -53,7 +53,7 @@ function wgobfs(ctx, desync)
|
||||
DLOG("wgobfs: encrypting '"..desync.l7payload.."'. size "..#desync.dis.payload)
|
||||
local key = genkey()
|
||||
-- in aes-gcm every message require it's own crypto secure random iv
|
||||
-- encryption more than one message with the same iv is considered catastrophic failure
|
||||
-- encrypting more than one message with the same iv is considered catastrophic failure
|
||||
-- iv must be sent with encrypted message
|
||||
local iv = bcryptorandom(12)
|
||||
local encrypted, atag = aes_gcm(true, key, iv, bu16(#desync.dis.payload)..desync.dis.payload..brandom(math.random(padmin,padmax)), nil)
|
||||
|
||||
49
nfq2/crypto/aes-ctr.c
Normal file
49
nfq2/crypto/aes-ctr.c
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "aes-ctr.h"
|
||||
#include <string.h>
|
||||
|
||||
#define AES_BLOCKLEN 16
|
||||
|
||||
void aes_ctr_xcrypt_buffer(aes_context *ctx, const uint8_t *iv, const uint8_t *in, size_t length, uint8_t *out)
|
||||
{
|
||||
uint8_t bi, buffer[AES_BLOCKLEN], ivc[AES_BLOCKLEN];
|
||||
size_t i;
|
||||
|
||||
memcpy(ivc,iv,AES_BLOCKLEN);
|
||||
|
||||
for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi)
|
||||
{
|
||||
if (bi == AES_BLOCKLEN) /* we need to regen xor complement in buffer */
|
||||
{
|
||||
memcpy(buffer, ivc, AES_BLOCKLEN);
|
||||
aes_cipher(ctx, buffer, buffer);
|
||||
|
||||
/* Increment ivc and handle overflow */
|
||||
for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi)
|
||||
{
|
||||
/* inc will owerflow */
|
||||
if (ivc[bi] == 255)
|
||||
{
|
||||
ivc[bi] = 0;
|
||||
continue;
|
||||
}
|
||||
ivc[bi] += 1;
|
||||
break;
|
||||
}
|
||||
bi = 0;
|
||||
}
|
||||
out[i] = in[i] ^ buffer[bi];
|
||||
}
|
||||
}
|
||||
|
||||
int aes_ctr_crypt(const uint8_t *key, const size_t key_len, const uint8_t *iv, const uint8_t *in, size_t length, uint8_t *out)
|
||||
{
|
||||
int ret=0;
|
||||
aes_context ctx;
|
||||
|
||||
aes_init_keygen_tables();
|
||||
|
||||
if (!(ret=aes_setkey(&ctx, AES_ENCRYPT, key, key_len)))
|
||||
aes_ctr_xcrypt_buffer(&ctx, iv, in, length, out);
|
||||
|
||||
return ret;
|
||||
}
|
||||
7
nfq2/crypto/aes-ctr.h
Normal file
7
nfq2/crypto/aes-ctr.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "aes.h"
|
||||
|
||||
void aes_ctr_xcrypt_buffer(aes_context *ctx, const uint8_t *iv, const uint8_t *in, size_t length, uint8_t *out);
|
||||
int aes_ctr_crypt(const uint8_t *key, const size_t key_len, const uint8_t *iv, const uint8_t *in, size_t length, uint8_t *out);
|
||||
@@ -607,11 +607,56 @@ uint8_t ttl46(const struct ip *ip, const struct ip6_hdr *ip6)
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
|
||||
uint32_t w_win32_error=0;
|
||||
|
||||
static BOOL RemoveTokenPrivs()
|
||||
{
|
||||
BOOL bRes = FALSE;
|
||||
HANDLE hToken;
|
||||
TOKEN_PRIVILEGES *privs;
|
||||
DWORD k, dwSize;
|
||||
LUID luid_SeChangeNotifyPrivilege;
|
||||
|
||||
if (LookupPrivilegeValue(NULL, SE_CHANGE_NOTIFY_NAME, &luid_SeChangeNotifyPrivilege))
|
||||
{
|
||||
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_PRIVILEGES, &hToken))
|
||||
{
|
||||
if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
if (privs = (PTOKEN_PRIVILEGES)malloc(dwSize))
|
||||
{
|
||||
if (GetTokenInformation(hToken, TokenPrivileges, privs, dwSize, &dwSize))
|
||||
{
|
||||
for (k = 0; k < privs->PrivilegeCount; k++)
|
||||
{
|
||||
if (memcmp(&privs->Privileges[k].Luid, &luid_SeChangeNotifyPrivilege, sizeof(LUID)))
|
||||
privs->Privileges[k].Attributes = SE_PRIVILEGE_REMOVED;
|
||||
}
|
||||
}
|
||||
bRes = AdjustTokenPrivileges(hToken, FALSE, privs, dwSize, NULL, NULL);
|
||||
free(privs);
|
||||
}
|
||||
}
|
||||
CloseHandle(hToken);
|
||||
}
|
||||
}
|
||||
if (!bRes) w_win32_error = GetLastError();
|
||||
return bRes;
|
||||
}
|
||||
static BOOL WinSandbox()
|
||||
{
|
||||
// unfortunately there's no way to remove or disable Administrators group in the current process's token
|
||||
// only possible run child process with restricted token
|
||||
// but at least it's possible to permanently remove privileges
|
||||
// this is not much but better than nothing
|
||||
return RemoveTokenPrivs();
|
||||
}
|
||||
|
||||
|
||||
static HANDLE w_filter = NULL;
|
||||
static OVERLAPPED ovl = { .hEvent = NULL };
|
||||
static const struct str_list_head *wlan_filter_ssid = NULL, *nlm_filter_net = NULL;
|
||||
static DWORD logical_net_filter_tick=0;
|
||||
uint32_t w_win32_error=0;
|
||||
INetworkListManager* pNetworkListManager=NULL;
|
||||
|
||||
static void guid2str(const GUID *guid, char *str)
|
||||
@@ -699,6 +744,9 @@ bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_lis
|
||||
win_dark_deinit();
|
||||
if (LIST_EMPTY(ssid_filter)) ssid_filter=NULL;
|
||||
if (LIST_EMPTY(nlm_filter)) nlm_filter=NULL;
|
||||
|
||||
if (!WinSandbox()) return false;
|
||||
|
||||
if (nlm_filter)
|
||||
{
|
||||
if (SUCCEEDED(w_win32_error = CoInitialize(NULL)))
|
||||
|
||||
@@ -1162,7 +1162,6 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
}
|
||||
|
||||
process_retrans_fail(ctrack, IPPROTO_TCP, (struct sockaddr*)&src);
|
||||
|
||||
if (IsHttp(rdata_payload, rlen_payload))
|
||||
{
|
||||
DLOG("packet contains HTTP request\n");
|
||||
@@ -1202,7 +1201,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
if (l7proto == L7_UNKNOWN)
|
||||
{
|
||||
l7proto = L7_TLS;
|
||||
if (ctrack) ctrack->l7proto = l7proto;
|
||||
if (ctrack->l7proto == L7_UNKNOWN) ctrack->l7proto = l7proto;
|
||||
}
|
||||
|
||||
if (bReqFull) TLSDebug(rdata_payload, rlen_payload);
|
||||
@@ -1253,6 +1252,17 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ctrack && (ctrack->seq_last - ctrack->seq0)==1 && IsMTProto(dis->data_payload, dis->len_payload))
|
||||
{
|
||||
DLOG("packet contains telegram mtproto2 initial\n");
|
||||
// mtproto detection requires aes. react only on the first tcp data packet. do not detect if ctrack unavailable.
|
||||
l7payload = L7P_MTPROTO_INITIAL;
|
||||
if (l7proto == L7_UNKNOWN)
|
||||
{
|
||||
l7proto = L7_MTPROTO;
|
||||
if (ctrack->l7proto == L7_UNKNOWN) ctrack->l7proto = l7proto;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
t_protocol_probe testers[] = {
|
||||
|
||||
79
nfq2/lua.c
79
nfq2/lua.c
@@ -3,6 +3,10 @@
|
||||
#include "lua.h"
|
||||
#include "params.h"
|
||||
#include "helpers.h"
|
||||
#include "crypto/sha.h"
|
||||
#include "crypto/aes-gcm.h"
|
||||
#include "crypto/aes-ctr.h"
|
||||
|
||||
|
||||
static void lua_check_argc(lua_State *L, const char *where, int argc)
|
||||
{
|
||||
@@ -442,7 +446,6 @@ static int luacall_aes_gcm(lua_State *L)
|
||||
uint8_t *output = malloc(input_len);
|
||||
if (!output) luaL_error(L, "out of memory");
|
||||
|
||||
gcm_initialize();
|
||||
if (aes_gcm_crypt(bEncrypt, output, input, input_len, key, key_len, iv, iv_len, add, add_len, atag, sizeof(atag)))
|
||||
{
|
||||
lua_pushnil(L);
|
||||
@@ -458,6 +461,38 @@ static int luacall_aes_gcm(lua_State *L)
|
||||
LUA_STACK_GUARD_RETURN(L,2)
|
||||
}
|
||||
|
||||
static int luacall_aes_ctr(lua_State *L)
|
||||
{
|
||||
// aes_ctr(key, iv, in) returns out
|
||||
lua_check_argc(L,"aes_ctr",3);
|
||||
|
||||
LUA_STACK_GUARD_ENTER(L)
|
||||
|
||||
size_t key_len;
|
||||
const uint8_t *key = (uint8_t*)luaL_checklstring(L,1,&key_len);
|
||||
if (key_len!=16 && key_len!=24 && key_len!=32)
|
||||
luaL_error(L, "aes_ctr: wrong key length %u. should be 16,24,32.", (unsigned)key_len);
|
||||
|
||||
size_t iv_len;
|
||||
const uint8_t *iv = (uint8_t*)luaL_checklstring(L,2,&iv_len);
|
||||
if (iv_len!=16)
|
||||
luaL_error(L, "aes_ctr: wrong iv length %u. should be 16.", (unsigned)iv_len);
|
||||
|
||||
size_t input_len;
|
||||
const uint8_t *input = (uint8_t*)luaL_checklstring(L,3,&input_len);
|
||||
|
||||
uint8_t *output = malloc(input_len);
|
||||
if (!output) luaL_error(L, "out of memory");
|
||||
|
||||
if (aes_ctr_crypt(key, key_len, iv, input, input_len, output))
|
||||
lua_pushnil(L);
|
||||
else
|
||||
lua_pushlstring(L,(const char*)output,input_len);
|
||||
free(output);
|
||||
|
||||
LUA_STACK_GUARD_RETURN(L,1)
|
||||
}
|
||||
|
||||
static int luacall_hkdf(lua_State *L)
|
||||
{
|
||||
// hkdf(hash_type, salt, ikm, info, okm_len) returns okm
|
||||
@@ -2322,27 +2357,36 @@ static bool lua_init_scripts(void)
|
||||
|
||||
static void lua_sec_harden(void)
|
||||
{
|
||||
LUA_STACK_GUARD_ENTER(params.L)
|
||||
|
||||
// remove unwanted functions. lua scripts are not intended to execute files
|
||||
const struct
|
||||
{
|
||||
const char *global, *func;
|
||||
const char *global, *field, *field2;
|
||||
} bad[] = {
|
||||
{"os","execute"},
|
||||
{"io","popen"},
|
||||
{"package","loadlib"},
|
||||
{"debug", NULL}
|
||||
{"os","execute",NULL},
|
||||
{"io","popen",NULL},
|
||||
{"package","loadlib",NULL},
|
||||
{"debug", NULL, NULL},
|
||||
{"package", "loaded", "debug"}
|
||||
};
|
||||
DLOG("LUA REMOVE:");
|
||||
for (int i=0;i<sizeof(bad)/sizeof(*bad);i++)
|
||||
{
|
||||
if (bad[i].func)
|
||||
if (bad[i].field)
|
||||
{
|
||||
lua_getglobal(params.L, bad[i].global);
|
||||
lua_pushstring(params.L, bad[i].func);
|
||||
if (bad[i].field2)
|
||||
{
|
||||
lua_getfield(params.L, -1, bad[i].field);
|
||||
lua_pushstring(params.L, bad[i].field2);
|
||||
}
|
||||
else
|
||||
lua_pushstring(params.L, bad[i].field);
|
||||
lua_pushnil(params.L);
|
||||
lua_rawset(params.L, -3);
|
||||
lua_pop(params.L,1);
|
||||
DLOG(" %s.%s", bad[i].global, bad[i].func);
|
||||
lua_pop(params.L,1 + !!bad[i].field2);
|
||||
DLOG(" %s.%s", bad[i].global, bad[i].field);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2352,10 +2396,14 @@ static void lua_sec_harden(void)
|
||||
}
|
||||
}
|
||||
DLOG("\n");
|
||||
|
||||
LUA_STACK_GUARD_LEAVE(params.L,0)
|
||||
}
|
||||
|
||||
static void lua_init_blobs(void)
|
||||
{
|
||||
LUA_STACK_GUARD_ENTER(params.L)
|
||||
|
||||
struct blob_item *blob;
|
||||
// save some memory - destroy C blobs as they are not needed anymore
|
||||
while ((blob = LIST_FIRST(¶ms.blobs)))
|
||||
@@ -2366,10 +2414,14 @@ static void lua_init_blobs(void)
|
||||
lua_setglobal(params.L, blob->name);
|
||||
blob_destroy(blob);
|
||||
}
|
||||
|
||||
LUA_STACK_GUARD_LEAVE(params.L, 0)
|
||||
}
|
||||
|
||||
static void lua_init_const(void)
|
||||
{
|
||||
LUA_STACK_GUARD_ENTER(params.L)
|
||||
|
||||
const struct
|
||||
{
|
||||
const char *name;
|
||||
@@ -2470,10 +2522,14 @@ static void lua_init_const(void)
|
||||
}
|
||||
|
||||
DLOG("\n");
|
||||
|
||||
LUA_STACK_GUARD_LEAVE(params.L, 0)
|
||||
}
|
||||
|
||||
static void lua_init_functions(void)
|
||||
{
|
||||
LUA_STACK_GUARD_ENTER(params.L)
|
||||
|
||||
const struct
|
||||
{
|
||||
const char *name;
|
||||
@@ -2528,6 +2584,7 @@ static void lua_init_functions(void)
|
||||
{"hash",luacall_hash},
|
||||
{"aes",luacall_aes},
|
||||
{"aes_gcm",luacall_aes_gcm},
|
||||
{"aes_ctr",luacall_aes_ctr},
|
||||
{"hkdf",luacall_hkdf},
|
||||
|
||||
// parsing
|
||||
@@ -2575,6 +2632,8 @@ static void lua_init_functions(void)
|
||||
};
|
||||
for(int i=0;i<(sizeof(lfunc)/sizeof(*lfunc));i++)
|
||||
lua_register(params.L,lfunc[i].name,lfunc[i].f);
|
||||
|
||||
LUA_STACK_GUARD_LEAVE(params.L, 0)
|
||||
}
|
||||
|
||||
bool lua_init(void)
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#include "protocol.h"
|
||||
#include "helpers.h"
|
||||
#include "params.h"
|
||||
#include "crypto/sha.h"
|
||||
#include "crypto/aes-gcm.h"
|
||||
#include "crypto/aes-ctr.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
@@ -26,7 +29,7 @@ static bool FindNLD(const uint8_t *dom, size_t dlen, int level, const uint8_t **
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *l7proto_name[] = {"all","unknown","http","tls","quic","wireguard","dht","discord","stun","xmpp","dns"};
|
||||
static const char *l7proto_name[] = {"all","unknown","known","http","tls","quic","wireguard","dht","discord","stun","xmpp","dns","mtproto"};
|
||||
const char *l7proto_str(t_l7proto l7)
|
||||
{
|
||||
if (l7>=L7_LAST) return NULL;
|
||||
@@ -39,14 +42,16 @@ t_l7proto l7proto_from_name(const char *name)
|
||||
}
|
||||
bool l7_proto_match(t_l7proto l7proto, uint64_t filter_l7)
|
||||
{
|
||||
return !filter_l7 || (filter_l7 & (1<<l7proto));
|
||||
return filter_l7==L7_ALL || (filter_l7 & (1<<l7proto)) || (filter_l7 & (1<<L7_KNOWN)) && l7proto>L7_KNOWN && l7proto<L7_LAST;
|
||||
}
|
||||
|
||||
static const char *l7payload_name[] = {
|
||||
"all","unknown","empty","http_req","http_reply","tls_client_hello","tls_server_hello","quic_initial",
|
||||
"all","unknown","empty","known","http_req","http_reply","tls_client_hello","tls_server_hello","quic_initial",
|
||||
"wireguard_initiation","wireguard_response","wireguard_cookie","wireguard_keepalive","wireguard_data",
|
||||
"dht","discord_ip_discovery","stun_binding_req",
|
||||
"xmpp_stream", "xmpp_starttls", "xmpp_proceed", "xmpp_features", "dns_query", "dns_response"};
|
||||
"xmpp_stream", "xmpp_starttls", "xmpp_proceed", "xmpp_features",
|
||||
"dns_query", "dns_response",
|
||||
"mtproto_initial"};
|
||||
t_l7payload l7payload_from_name(const char *name)
|
||||
{
|
||||
int idx = str_index(l7payload_name,sizeof(l7payload_name)/sizeof(*l7payload_name),name);
|
||||
@@ -59,7 +64,7 @@ const char *l7payload_str(t_l7payload l7)
|
||||
}
|
||||
bool l7_payload_match(t_l7payload l7payload, uint64_t filter_l7p)
|
||||
{
|
||||
return !filter_l7p || (filter_l7p & (1<<l7payload));
|
||||
return filter_l7p==L7P_ALL || (filter_l7p & (1<<l7payload)) || (filter_l7p & (1<<L7P_KNOWN)) && l7payload>L7P_KNOWN && l7payload<L7P_LAST;
|
||||
}
|
||||
|
||||
|
||||
@@ -720,7 +725,7 @@ bool TLSMod(const struct fake_tls_mod *tls_mod, const uint8_t *payload, size_t p
|
||||
DLOG_ERR("cannot apply tls mod.tls structure invalid\n");
|
||||
return false;
|
||||
}
|
||||
DLOG_ERR("tls extensions length offset : %zu\n", extlen_offset);
|
||||
DLOG("tls extensions length offset : %zu\n", extlen_offset);
|
||||
}
|
||||
if (tls_mod->mod & (FAKE_TLS_MOD_RND_SNI | FAKE_TLS_MOD_SNI))
|
||||
{
|
||||
@@ -1146,7 +1151,7 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
|
||||
pn_offset += tvb_get_varint(data + pn_offset, &payload_len);
|
||||
if (payload_len<20 || (pn_offset + payload_len)>data_len) return false;
|
||||
|
||||
gcm_initialize(); // initialize aes keygen tables
|
||||
aes_init_keygen_tables();
|
||||
|
||||
uint8_t sample_enc[16];
|
||||
aes_context ctx;
|
||||
@@ -1385,3 +1390,12 @@ bool IsStunBindingRequest(const uint8_t *data, size_t len)
|
||||
ntohl(*(uint32_t*)(&data[4]))==0x2112A442 && // magic cookie
|
||||
ntohs(*(uint16_t*)(&data[2]))==len-20;
|
||||
}
|
||||
bool IsMTProto(const uint8_t *data, size_t len)
|
||||
{
|
||||
if (len>=64)
|
||||
{
|
||||
uint8_t decrypt[64];
|
||||
aes_ctr_crypt(data+8, 32, data+40, data, 64, decrypt);
|
||||
return !memcmp(decrypt+56,"\xEF\xEF\xEF\xEF",4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "crypto/sha.h"
|
||||
#include "crypto/aes-gcm.h"
|
||||
#include "helpers.h"
|
||||
|
||||
typedef enum {
|
||||
L7_ALL=0,
|
||||
L7_UNKNOWN,
|
||||
L7_KNOWN,
|
||||
L7_HTTP,
|
||||
L7_TLS,
|
||||
L7_QUIC,
|
||||
@@ -19,6 +18,7 @@ typedef enum {
|
||||
L7_STUN,
|
||||
L7_XMPP,
|
||||
L7_DNS,
|
||||
L7_MTPROTO,
|
||||
L7_LAST, L7_INVALID=L7_LAST
|
||||
} t_l7proto;
|
||||
const char *l7proto_str(t_l7proto l7);
|
||||
@@ -29,6 +29,7 @@ typedef enum {
|
||||
L7P_ALL=0,
|
||||
L7P_UNKNOWN,
|
||||
L7P_EMPTY,
|
||||
L7P_KNOWN,
|
||||
L7P_HTTP_REQ,
|
||||
L7P_HTTP_REPLY,
|
||||
L7P_TLS_CLIENT_HELLO,
|
||||
@@ -48,6 +49,7 @@ typedef enum {
|
||||
L7P_XMPP_FEATURES,
|
||||
L7P_DNS_QUERY,
|
||||
L7P_DNS_RESPONSE,
|
||||
L7P_MTPROTO_INITIAL,
|
||||
L7P_LAST, L7P_INVALID=L7P_LAST
|
||||
} t_l7payload;
|
||||
t_l7payload l7payload_from_name(const char *name);
|
||||
@@ -151,6 +153,7 @@ bool IsWireguardData(const uint8_t *data, size_t len);
|
||||
bool IsDht(const uint8_t *data, size_t len);
|
||||
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len);
|
||||
bool IsStunBindingRequest(const uint8_t *data, size_t len);
|
||||
bool IsMTProto(const uint8_t *data, size_t len);
|
||||
|
||||
#define QUIC_MAX_CID_LENGTH 20
|
||||
typedef struct quic_cid {
|
||||
|
||||
Reference in New Issue
Block a user