Template
1
0
mirror of https://github.com/bol-van/zapret2.git synced 2026-03-22 01:05:48 +00:00

44 Commits

Author SHA1 Message Date
bol-van
7c320c8d57 update docs 2026-01-12 10:13:26 +03:00
bol-van
b18f0770c8 update docs 2026-01-12 10:12:35 +03:00
bol-van
f7fc845014 update docs 2026-01-12 10:11:10 +03:00
bol-van
2c1a885a07 update docs 2026-01-12 10:10:01 +03:00
bol-van
9eb308d84c update docs 2026-01-12 10:09:02 +03:00
bol-van
3e724c3810 update docs 2026-01-12 10:03:35 +03:00
bol-van
c179d55d88 nfqws2: harden wireguard detector 2026-01-12 09:34:56 +03:00
bol-van
3f1af1441e nfqws2: check quit flag outside of EINTR context 2026-01-12 09:08:19 +03:00
bol-van
4c1b2b65f3 nfqws2: gracefully shutdown on SIGINT and SIGTERM 2026-01-11 21:01:18 +03:00
bol-van
918258413f nfqws2: fix tls reasm logic 2026-01-11 19:41:13 +03:00
bol-van
e6206c5a5f nfqws2: fix tls reasm 2026-01-11 18:20:29 +03:00
bol-van
f93c6de772 nfqws2: --payload-disable 2026-01-11 17:25:53 +03:00
bol-van
5a7e2b1ca2 nfqws2: alternative representation of payload filter in execution_plan item 2026-01-11 16:20:45 +03:00
bol-van
ca8104c72a zapret-lib: remove bitable, use barray 2026-01-11 15:36:10 +03:00
bol-van
3aad1f9ed9 nfqws2: optimize ctx userdata 2026-01-11 14:10:42 +03:00
bol-van
fd288d5e7d nfqws2: move ctx from lightuserdata to userdata. prevents crashes on specific ARM cpus 2026-01-11 13:58:31 +03:00
bol-van
349fe3f7d7 update docs 2026-01-11 12:32:44 +03:00
bol-van
4554b7c15b zapret-lib, zapret-antidpi: use numeric indexes in http dissects 2026-01-11 12:29:53 +03:00
bol-van
0b595ae3a8 AI inspired fixes 2026-01-11 11:39:37 +03:00
bol-van
3e69e1b8c1 zapret-lib: bitable 2026-01-11 11:21:12 +03:00
bol-van
02b895910b dvtws2: openbsd compile fix 2026-01-11 11:04:09 +03:00
bol-van
b2a53e9c64 nfqws2: AI inspired fixes 2026-01-11 10:56:24 +03:00
bol-van
a626cfce8a update docs 2026-01-11 09:36:47 +03:00
bol-van
ebcbfc37ba update docs 2026-01-10 20:14:44 +03:00
bol-van
33d3c94b68 update docs 2026-01-10 20:12:45 +03:00
bol-van
d55dbb7717 update docs 2026-01-10 20:05:21 +03:00
bol-van
cb82be9eab update docs 2026-01-10 20:04:01 +03:00
bol-van
024d36acc4 update docs 2026-01-10 20:02:06 +03:00
bol-van
08c6151a4c update docs 2026-01-10 19:56:22 +03:00
bol-van
520317dc3c update docs 2026-01-10 19:24:02 +03:00
bol-van
6bc0bf1b97 AI inspired fixes 2026-01-10 18:54:26 +03:00
bol-van
d18fec9053 update docs 2026-01-10 16:47:40 +03:00
bol-van
e60e5a0578 update docs 2026-01-10 16:46:44 +03:00
bol-van
84576a7039 update docs 2026-01-10 16:44:07 +03:00
bol-van
7957a0a425 update docs 2026-01-10 16:42:58 +03:00
bol-van
7ba4110416 update docs 2026-01-10 16:35:54 +03:00
bol-van
4babaef6a8 update docs 2026-01-10 16:32:54 +03:00
bol-van
872e37d160 update docs 2026-01-10 16:28:48 +03:00
bol-van
a8219f4897 update docs 2026-01-10 16:25:24 +03:00
bol-van
36267b7e9b update docs 2026-01-10 16:22:35 +03:00
bol-van
99a7f06976 eng manual 2026-01-10 15:42:42 +03:00
bol-van
3617b8934f blockcheck2: 23-seqovl fix 2026-01-10 14:58:38 +03:00
bol-van
8e6387a6df config.default add MDIG comments 2026-01-09 13:14:36 +03:00
bol-van
3bc0e8e350 mdig: EAGAIN->EAI_AGAIN help text 2026-01-09 12:38:06 +03:00
29 changed files with 5610 additions and 335 deletions

View File

@@ -47,14 +47,14 @@ pktws_seqovl_tests_tls()
ok=0 ok=0
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop && ok=1 pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=#$pat:seqovl_pattern=$pat --lua-desync=drop && ok=1 pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=#$pat:seqovl_pattern=$pat --lua-desync=drop && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=tcpseg:pos=0,-1:seqovl=#pat:seqovl_pattern=pat --lua-desync=drop && ok=1 pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=tcpseg:pos=0,-1:seqovl=#pat:seqovl_pattern=$pat --lua-desync=drop && ok=1
ok_any=$ok ok_any=$ok
ok=0 ok=0
for split in 10 10,sniext+1 10,sniext+4 10,midsld; do for split in 10 10,sniext+1 10,sniext+4 10,midsld; do
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=1 && ok=1 pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=1 && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=#$pat:seqovl_pattern=$pat && ok=1 pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=#$pat:seqovl_pattern=$pat && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=multisplit:pos=$split:seqovl=#pat:seqovl_pattern=pat && ok=1 pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=multisplit:pos=$split:seqovl=#pat:seqovl_pattern=$pat && ok=1
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break [ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
done done
for split in '1 2' 'sniext sniext+1' 'sniext+3 sniext+4' 'midsld-1 midsld' '1 2,midsld'; do for split in '1 2' 'sniext sniext+1' 'sniext+3 sniext+4' 'midsld-1 midsld' '1 2,midsld'; do

View File

@@ -366,7 +366,7 @@ random()
local r rs local r rs
setup_random setup_random
if [ -c /dev/urandom ]; then if [ -c /dev/urandom ]; then
read rs </dev/urandom rs=$(dd if=/dev/urandom count=1 bs=16 2>/dev/null | hexdump -e '1 "%02x"')
else else
rs="$RANDOM$RANDOM$(date)" rs="$RANDOM$RANDOM$(date)"
fi fi

View File

@@ -522,11 +522,6 @@ install_openwrt_firewall()
{ {
echo \* installing firewall script $1 echo \* installing firewall script $1
[ -n "MODE" ] || {
echo should specify MODE in $ZAPRET_CONFIG
exitp 7
}
echo "linking : $FW_SCRIPT_SRC => $OPENWRT_FW_INCLUDE" echo "linking : $FW_SCRIPT_SRC => $OPENWRT_FW_INCLUDE"
ln -fs "$FW_SCRIPT_SRC" "$OPENWRT_FW_INCLUDE" ln -fs "$FW_SCRIPT_SRC" "$OPENWRT_FW_INCLUDE"

View File

@@ -41,7 +41,7 @@ ipt6_add_del()
} }
ipt6a_add_del() ipt6a_add_del()
{ {
on_off_function ipt6 ipt6a_del "$@" on_off_function ipt6a ipt6_del "$@"
} }
is_ipt_flow_offload_avail() is_ipt_flow_offload_avail()

View File

@@ -41,7 +41,9 @@ AUTOHOSTLIST_DEBUGLOG=0
# number of parallel threads for domain list resolves # number of parallel threads for domain list resolves
MDIG_THREADS=30 MDIG_THREADS=30
# EAI_AGAIN retries
MDIG_EAGAIN=10 MDIG_EAGAIN=10
# delay between EAI_AGAIN retries (ms)
MDIG_EAGAIN_DELAY=500 MDIG_EAGAIN_DELAY=500
# ipset/*.sh can compress large lists # ipset/*.sh can compress large lists

View File

@@ -169,3 +169,12 @@ v0.8.1
* nfqws2: ignore trailing spaces and tabs in hostlists and ipsets. "host.com " or "1.2.3.4 " are ok now * nfqws2: ignore trailing spaces and tabs in hostlists and ipsets. "host.com " or "1.2.3.4 " are ok now
* init.d: 99-lan-filter custom script * init.d: 99-lan-filter custom script
* mdig: --eagain, --eagain-delay * mdig: --eagain, --eagain-delay
0.8.4
* winws2: fix loopback large packets processing (up to 64K)
* zapret-lib, zapret-antidpi: use numeric indexes in http dissects
* nfqws2: move ctx from lightuserdata to userdata. prevents crashes on specific ARM cpus
* nfqws2: alternative representation of payload filter in execution_plan item
* nfqws2: --payload-disable
* nfqws2: gracefully shutdown on SIGINT and SIGTERM

5098
docs/manual.en.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -14,6 +14,7 @@
- [nfqws2](#nfqws2) - [nfqws2](#nfqws2)
- [Общие принципы задания параметров](#общие-принципы-задания-параметров) - [Общие принципы задания параметров](#общие-принципы-задания-параметров)
- [Полный список опций](#полный-список-опций) - [Полный список опций](#полный-список-опций)
- [Распознавание протоколов](#распознавание-протоколов)
- [Использование множественных профилей](#использование-множественных-профилей) - [Использование множественных профилей](#использование-множественных-профилей)
- [Шаблоны профилей](#шаблоны-профилей) - [Шаблоны профилей](#шаблоны-профилей)
- [Фильтрация по листам](#фильтрация-по-листам) - [Фильтрация по листам](#фильтрация-по-листам)
@@ -668,10 +669,11 @@ nfqws2 использует стандартный парсер getopt_long_only
--pidfile=<filename> ; запись PID в файл --pidfile=<filename> ; запись PID в файл
--ctrack-timeouts=S:E:F[:U] ; таймауты conntrack для стадий tcp SYN, ESTABLISHED, FIN и для udp --ctrack-timeouts=S:E:F[:U] ; таймауты conntrack для стадий tcp SYN, ESTABLISHED, FIN и для udp
--ctrack-disable=[0|1] ; 1 отключает conntrack --ctrack-disable=[0|1] ; 1 отключает conntrack
--payload-disable=[type[,type]] ; отключить распознавание указанных типов пейлоадов. без аргумента - отключить все.
--server=[0|1] ; серверный режим. для обслуживания listener-ов меняются многие аспекты выбора направления и ip/port источника/приемника --server=[0|1] ; серверный режим. для обслуживания listener-ов меняются многие аспекты выбора направления и ip/port источника/приемника
--ipcache-lifetime=<int> ; время жизни записей кэша IP в секундах. 0 - без ограничений. --ipcache-lifetime=<int> ; время жизни записей кэша IP в секундах. 0 - без ограничений.
--ipcache-hostname=[0|1] ; 1 или отсутствие аргумента включают кэширование имен хостов для применения в стратегиях нулевой фазы --ipcache-hostname=[0|1] ; 1 или отсутствие аргумента включают кэширование имен хостов для применения в стратегиях нулевой фазы
--reasm-disable=[proto[,proto]] ; отключить сборку фрагментов для списка пейлоадов : tls_client_hello quic_initial . без аргумента - отключить reasm для всего. --reasm-disable=[type[,type]] ; отключить сборку фрагментов для списка пейлоадов : tls_client_hello quic_initial . без аргумента - отключить reasm для всего.
DESYNC ENGINE INIT: DESYNC ENGINE INIT:
--writeable[=<dir_name>] ; создать директорию для Lua с разрешением записи и поместить путь к ней в переменную env "WRITEABLE" (только одна директория) --writeable[=<dir_name>] ; создать директорию для Lua с разрешением записи и поместить путь к ней в переменную env "WRITEABLE" (только одна директория)
@@ -689,7 +691,7 @@ MULTI-STRATEGY:
--filter-l3=ipv4|ipv6 ; фильтр профиля : версия ip протокола --filter-l3=ipv4|ipv6 ; фильтр профиля : версия ip протокола
--filter-tcp=[~]port1[-port2]|* ; фильтр профиля : порты tcp или диапазоны портов через запятую --filter-tcp=[~]port1[-port2]|* ; фильтр профиля : порты tcp или диапазоны портов через запятую
--filter-udp=[~]port1[-port2]|* ; фильтр профиля : порты udp или диапазоны портов через запятую --filter-udp=[~]port1[-port2]|* ; фильтр профиля : порты udp или диапазоны портов через запятую
--filter-l7=proto[,proto] ; фильтр профиля : список протоколов потока. полный список доступен в help тексте программы. --filter-l7=proto[,proto] ; фильтр профиля : список протоколов потока
--ipset=<filename> ; фильтр профиля : включающий список ip адресов или подсетей из файла. может быть смешанным ipv4+ipv6. --ipset=<filename> ; фильтр профиля : включающий список ip адресов или подсетей из файла. может быть смешанным ipv4+ipv6.
--ipset-ip=<ip_list> ; фильтр профиля : включающий фиксированный список ip адресов или подсетей через запятую --ipset-ip=<ip_list> ; фильтр профиля : включающий фиксированный список ip адресов или подсетей через запятую
--ipset-exclude=<filename> ; фильтр профиля : исключающий список ip адресов или подсетей из файла. может быть смешанным ipv4+ipv6. --ipset-exclude=<filename> ; фильтр профиля : исключающий список ip адресов или подсетей из файла. может быть смешанным ipv4+ipv6.
@@ -710,7 +712,7 @@ MULTI-STRATEGY:
--hostlist-auto-debug=<logfile> ; дебаг лог автолиста --hostlist-auto-debug=<logfile> ; дебаг лог автолиста
LUA PACKET PASS MODE: LUA PACKET PASS MODE:
--payload=type[,type] ; внутрипрофильный фильтр : фильтр пейлоада для последующих инстансов внутри профиля. список пейлоадов доступен в help тексте программы. --payload=type[,type] ; внутрипрофильный фильтр : фильтр пейлоада для последующих инстансов внутри профиля
--out-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; внутрипрофильный фильтр : диапазон счетчиков conntrack для последующих инстансов внутри профиля - исходящее направление --out-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; внутрипрофильный фильтр : диапазон счетчиков conntrack для последующих инстансов внутри профиля - исходящее направление
--in-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; внутрипрофильный фильтр : диапазон счетчиков conntrack для последующих инстансов внутри профиля - входящее направление --in-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; внутрипрофильный фильтр : диапазон счетчиков conntrack для последующих инстансов внутри профиля - входящее направление
@@ -758,6 +760,30 @@ LOGICAL NETWORK FILTER:
--nlm-list[=all] ; вывести список подключенных NLM сетей. all - список всех NLM сетей --nlm-list[=all] ; вывести список подключенных NLM сетей. all - список всех NLM сетей
``` ```
## Распознавание протоколов
nfqws2 сигнатурно распознает типы пейлоадов отдельно взятых пакетов или групп пакетов.
Все пустые пакеты имеют пейлоад empty, неизвестные - unknown.
Протокол потока присваивается после получение первого известного пейлоада и остается с потоком до конца его существования.
При этом последующие пейлоады могут иметь как известный тип, так и неизвестный.
В фильтрах по пейлоаду и протоколу потока доступны специальные значения - all и known. All означает любой, known - не empty и не unknown.
Таблица распознаваемых типов пейлоада и протоколов потока
| Протокол потока | L4 | Пейлоады |
| :-------------- | :-- | :------- |
| http | tcp | http_req<br>http_reply |
| tls | tcp | tls_client_hello<br>tls_server_hello |
| xmpp | tcp | xmpp_stream<br>xmpp_starttls<br>xmpp_proceed<br>xmpp_features |
| mtproto | tcp | mtproto_initial |
| quic | udp | quic_initial |
| wireguard | udp | wireguard_initiation<br>wireguard_response<br>wireguard_cookie<br>wireguard_keepalive |
| dht | udp | dht |
| discord | udp | discord_ip_discovery |
| stun | udp | stun |
| dns | udp | dns_query<br>dns_response |
| dtls | udp | dtls_client_hello<br>dtls_server_hello |
## Использование множественных профилей ## Использование множественных профилей
Профили существуют, чтобы в зависимости от указанных условий фильтра выбрать ту или иную стратегию воздействия на трафик. Профили существуют, чтобы в зависимости от указанных условий фильтра выбрать ту или иную стратегию воздействия на трафик.
@@ -1085,7 +1111,7 @@ Lua код выполняется с ограниченными правами,
Они бывают трех видов - `--payload`, `--in-range`, `--out-range`. Они бывают трех видов - `--payload`, `--in-range`, `--out-range`.
Значения фильтров действуют с момента их указания до следующего переопределения. Значения фильтров действуют с момента их указания до следующего переопределения.
- `--payload=type1[,type2][,type2]...` принимает список известных пейлоадов через зяпятую, "all" или "known". Список известных пейлоадов доступен в help тексте nfqws2. По умолчанию `--payload=all`. - `--payload=type1[,type2][,type2]...` принимает список известных пейлоадов через зяпятую, "all" или "known". [Список известных пейлоадов](#распознавание-протоколов). По умолчанию `--payload=all`.
- `--(in-range|out-range)=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>]` задает диапазоны счетчиков conntrack по входящему и исходящему направлениям. По умолчанию `--in-range=x`, `--out-range=a`. - `--(in-range|out-range)=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>]` задает диапазоны счетчиков conntrack по входящему и исходящему направлениям. По умолчанию `--in-range=x`, `--out-range=a`.
Диапазоны задаются в формах : `mX-mY`, `mX<mY`, `-mY`, `<mY`, `mX-`, где m - режим счетчика, X - нижнее значение, Y - верхнее значение. Диапазоны задаются в формах : `mX-mY`, `mX<mY`, `-mY`, `<mY`, `mX-`, где m - режим счетчика, X - нижнее значение, Y - верхнее значение.
@@ -1417,8 +1443,8 @@ desync
| replay_piece | number | номер проигрываемой части | нумерация с 1 | | replay_piece | number | номер проигрываемой части | нумерация с 1 |
| replay_piece_count | number | количество проигрываемых частей | | | replay_piece_count | number | количество проигрываемых частей | |
| replay_piece_last | bool | последняя проигрываемая часть | | | replay_piece_last | bool | последняя проигрываемая часть | |
| l7payload | string | тип пейлоада текущего пакета или группы пакетов. список возможных в help тексте nfqws2 | если неизвестно - unknown | | l7payload | string | тип [пейлоада](#распознавание-протоколов) текущего пакета или группы пакетов | если неизвестно - unknown |
| l7proto | string | тип протокола потока | если неизвестно - unknown | | l7proto | string | тип [протокола потока](#распознавание-протоколов) | если неизвестно - unknown |
| reasm_data | string | результат сборки многопакетного сообщения, либо сам пейлоад, если сборки не было | пока применяется только для tcp | | reasm_data | string | результат сборки многопакетного сообщения, либо сам пейлоад, если сборки не было | пока применяется только для tcp |
| reasm_offset | string | смещение текущего переигрываемого пакета в сборке | пока применяется только для tcp | | reasm_offset | string | смещение текущего переигрываемого пакета в сборке | пока применяется только для tcp |
| decrypt_data | string | результат сборки и дешифровки пейлоада или пейлоадов нескольких пакетов | применяется для quic | | decrypt_data | string | результат сборки и дешифровки пейлоада или пейлоадов нескольких пакетов | применяется для quic |
@@ -1554,7 +1580,7 @@ ipv6 extension headers и tcp options представляются в форме
| Поле | Тип | Описание | Примечание | | Поле | Тип | Описание | Примечание |
| :------------- | :----- | :-------------------------------------------------------------- | :----------------------------------------------- | | :------------- | :----- | :-------------------------------------------------------------- | :----------------------------------------------- |
| incoming_ttl | number | ttl/hl первого входящего пакета по потоку | может не быть, если не определено | | incoming_ttl | number | ttl/hl первого входящего пакета по потоку | может не быть, если не определено |
| l7proto | string | протокол потока. список возможных доступен в help тексте nfqws2 | есть всегда. если неизвестно - unknown | | l7proto | string | [протокол потока](#распознавание-протоколов) | есть всегда. если неизвестно - unknown |
| hostname | string | имя хоста. определяется на основе анализа L6/L7 протоколов | появляется только после определения | | hostname | string | имя хоста. определяется на основе анализа L6/L7 протоколов | появляется только после определения |
| hostname_is_ip | bool | является ли hostname ip адресом | только если есть hostname | | hostname_is_ip | bool | является ли hostname ip адресом | только если есть hostname |
| lua_state | table | таблица для хранения состояния, привязанного к потоку | есть всегда, передается с каждым пакетом потока | | lua_state | table | таблица для хранения состояния, привязанного к потоку | есть всегда, передается с каждым пакетом потока |
@@ -2212,7 +2238,8 @@ function execution_plan(ctx)
| func_n | number | номер инстанса внутри профиля | | func_n | number | номер инстанса внутри профиля |
| func_instance | string | название инстанса | производная имени функции, номера инстанса и номера профиля | | func_instance | string | название инстанса | производная имени функции, номера инстанса и номера профиля |
| range | table | эффективный диапазон [счетчиков](#внутрипрофильные-фильтры) `--in-range` или `--out-range` в зависимости от текущего направления | | range | table | эффективный диапазон [счетчиков](#внутрипрофильные-фильтры) `--in-range` или `--out-range` в зависимости от текущего направления |
| payload_filter | string | эффективный `--payload-filter` . список названий пейлоадов через запятую | | payload | table | эффективный `--payload-filter` . таблица с индексами - названиями типа пейлоада |
| payload_filter | string | эффективный `--payload-filter` . список названий пейлоадов через запятую (иное представление payload) |
**range** **range**
@@ -2520,7 +2547,9 @@ function http_reconstruct_req(hdis, unixeol)
Разборка HTTP запроса или ответа http. http представляет собой многострочный текст. Разборка HTTP запроса или ответа http. http представляет собой многострочный текст.
Разборка представляет собой таблицу с вложенными подтаблицами. Разборка представляет собой таблицу с вложенными подтаблицами.
В заголовках выдаются позиции начала и конца названия заголовка и самого значения. В заголовках выдаются позиции начала и конца названия заголовка и самого значения.
Названия полей в таблице headers соответствуют названию заголовков в нижнем регисте. Все позиции - внутри строки http. Все позиции - внутри строки http.
Для нахождения хедеров по названию используйте [array_field_search](#array_search) по полю "header_low", которое содержит название хедера в нижнем регистре.
Реконструктор http запроса берет таблицу-разбор и воссоздает raw string. Параметр unixeol заменяет стандартный для http перевод сктроки 0D0A на 0A. Это нестандарт и ломает все сервера, кроме nginx. Реконструктор http запроса берет таблицу-разбор и воссоздает raw string. Параметр unixeol заменяет стандартный для http перевод сктроки 0D0A на 0A. Это нестандарт и ломает все сервера, кроме nginx.
@@ -2530,9 +2559,11 @@ function http_reconstruct_req(hdis, unixeol)
.uri .uri
string /test_uri string /test_uri
.headers .headers
.content-length .1
.header .header
string Content-Length string Content-Length
.header_low
string content-length
.value .value
string 330 string 330
.pos_start .pos_start
@@ -2543,9 +2574,11 @@ function http_reconstruct_req(hdis, unixeol)
number 56 number 56
.pos_value_start .pos_value_start
number 59 number 59
.host .2
.header .header
string Host string Host
.header_low
string host
.value .value
string testhost.com string testhost.com
.pos_start .pos_start
@@ -2566,26 +2599,30 @@ function http_reconstruct_req(hdis, unixeol)
.code .code
number 200 number 200
.headers .headers
.content-type .1
.pos_header_end .pos_header_end
number 28 number 28
.pos_value_start .pos_value_start
number 31 number 31
.header .header
string Content-Type string Content-Type
.header_low
string content-type
.value .value
string text/html string text/html
.pos_start .pos_start
number 17 number 17
.pos_end .pos_end
number 39 number 39
.content-length .2
.pos_header_end .pos_header_end
number 54 number 54
.pos_value_start .pos_value_start
number 57 number 57
.header .header
string Content-Length string Content-Length
.header_low
string content-length
.value .value
string 650 string 650
.pos_start .pos_start
@@ -2928,7 +2965,7 @@ function tls_reconstruct(tdis)
Для некоторых элементов заполняется поле "name". Оно служит для удобства визуального анализа и больше ни для чего не используется. Для некоторых элементов заполняется поле "name". Оно служит для удобства визуального анализа и больше ни для чего не используется.
Первичными являются поля type. Первичными являются поля type.
Для нахождения значений в списках используйте [функции поиска в массивах](#служебные-функции). Для нахождения значений в списках используйте [функции поиска в массивах](#array_search).
Множество констант, связанных с TLS, определено в `zapret-lib.lua`. Прежде чем писать фиксированные значения, посмотрите нет ли нужной константы. Множество констант, связанных с TLS, определено в `zapret-lib.lua`. Прежде чем писать фиксированные значения, посмотрите нет ли нужной константы.
@@ -3319,7 +3356,8 @@ function payload_match_filter(l7payload, l7payload_filter, def)
function payload_check(desync, def) function payload_check(desync, def)
``` ```
Функции работают со строкой - списком пейлоадов через запятую. Список известных типов пейлоада можно получить из help текста nfqws2. Все пустые пакеты имеют пейлоад empty, неизвестные - unknown. Особые значения - all и known. all означает любой пейлоад, known - не unknown и не empty. Префикс `~` в начале означает логическую инверсию - несоответствие списку. Функции работают со строкой - списком пейлоадов через запятую. Особые значения - all и known. all означает любой пейлоад, known - не unknown и не empty. Префикс `~` в начале означает логическую инверсию - несоответствие списку.
См. [распознавание протоколов](#распознавание-протоколов).
- payload_match_filter проверяет соответствие l7payload списку l7payload_filter или def, если l7payload_filter=nil. Если оба nil - список берется как "known". - payload_match_filter проверяет соответствие l7payload списку l7payload_filter или def, если l7payload_filter=nil. Если оба nil - список берется как "known".
- payload_check вызывает `payload_match_filter(desync.l7payload, desync.arg.payload, def)` - payload_check вызывает `payload_match_filter(desync.l7payload, desync.arg.payload, def)`
@@ -3468,7 +3506,7 @@ nfqws2 ничего не знает о том, что нужно `--lua-desync`
### standard payload ### standard payload
Фильтр по пейлоаду берет список типов пейлоада. Список известных типов пейлоада можно получить из help текста nfqws2. Все пустые пакеты имеют пейлоад empty, неизвестные - unknown. Особые значения - all и known. all означает любой пейлоад, known - не unknown и не empty. Фильтр по пейлоаду берет список [типов пейлоада](#распознавание-протоколов).
**standard payload** **standard payload**
@@ -3550,6 +3588,7 @@ function http_methodeol(ctx, desync)
- arg: [standard direction](#standard-direction) - arg: [standard direction](#standard-direction)
Вставляет '\r\n' перед методом, отрезая 2 последних символа из содержимого заголовка `User-Agent:`. Работает только на nginx, остальные сервера ломает. Вставляет '\r\n' перед методом, отрезая 2 последних символа из содержимого заголовка `User-Agent:`. Работает только на nginx, остальные сервера ломает.
Если используется совместно с другими функциями http тамперинга, должен идти последним.
### http_unixeol ### http_unixeol
@@ -3966,7 +4005,7 @@ function udplen(ctx, desync)
- arg: pattern_offset - начальное смещение внутри pattern - arg: pattern_offset - начальное смещение внутри pattern
- payload фильтр по умолчанию - "known" - payload фильтр по умолчанию - "known"
Функция увеличивает или уменьшает длину L4 пейлоада udp. При уменьшении часть информации обрезается и теряется, при увеличении - заполняется pattern. Сегментация udp невозможна - при превышении MTU или PMTU пакет не дойдет до адресата. Ошибка в случае превышения MTU будет только на Linux, остальные системы молча не отправят пакет (windivert и ipdivert не имеют средств обнаружения ошибки). Функция увеличивает или уменьшает длину L4 пейлоада udp. При уменьшении часть информации обрезается и теряется, при увеличении - заполняется pattern. Сегментация udp невозможна - при превышении MTU или PMTU ОС выполнит фрагментацию на уровне IP. Ошибка в случае превышения MTU будет только на Linux, остальные системы молча не отправят пакет (windivert и ipdivert не имеют средств обнаружения ошибки).
### dht_dn ### dht_dn
@@ -4048,7 +4087,7 @@ function standard_hostkey(desync)
### automate_host_record ### automate_host_record
``` ```
function automate_conn_record(desync) function automate_host_record(desync)
``` ```
- arg: key - ключ внутри глобальной таблицы autostate. если не задано, в качестве ключа используется имя текущего инстанса - arg: key - ключ внутри глобальной таблицы autostate. если не задано, в качестве ключа используется имя текущего инстанса
@@ -4326,8 +4365,8 @@ ip2net фильтрует входные данные, выкидывая неп
``` ```
--family=<4|6|46> ; выбор семейства IP адресов : ipv4, ipv6, ipv4+ipv6 --family=<4|6|46> ; выбор семейства IP адресов : ipv4, ipv6, ipv4+ipv6
--threads=<threads_number> ; количество потоков. по умолчанию 1. --threads=<threads_number> ; количество потоков. по умолчанию 1.
--eagain=<eagain_retries> ; количество попыток повтора после EAGAIN. по умолчанию 10 --eagain=<eagain_retries> ; количество попыток повтора после EAI_AGAIN. по умолчанию 10
--eagain-delay=<ms> ; время ожидания в мсек между повторами по EAGAIN. по умолчанию 500. --eagain-delay=<ms> ; время ожидания в мсек между повторами по EAI_AGAIN. по умолчанию 500.
--verbose ; дебаг-лог на консоль --verbose ; дебаг-лог на консоль
--stats=N ; выводить статистику каждые N доменов --stats=N ; выводить статистику каждые N доменов
--log-resolved=<file> ; сохранять успешно отресолвленные домены в файл --log-resolved=<file> ; сохранять успешно отресолвленные домены в файл
@@ -4668,8 +4707,8 @@ nfqws2 может работать и самостоятельно без скр
| IPSET_HOOK | скрипт, который получает имя ipset в $1, выдает в stdout список ip, и они добавляются в ipset | | IPSET_HOOK | скрипт, который получает имя ipset в $1, выдает в stdout список ip, и они добавляются в ipset |
| IP2NET_OPT4<br>IP2NET_OPT6 | настройки ip2net для скриптов получения ip листов | | IP2NET_OPT4<br>IP2NET_OPT6 | настройки ip2net для скриптов получения ip листов |
| MDIG_THREADS | количество потоков mdig. используется при ресолвинге хостлистов | | MDIG_THREADS | количество потоков mdig. используется при ресолвинге хостлистов |
| MDIG_EAGAIN | количество попыток при получении EAGAIN | | MDIG_EAGAIN | количество попыток при получении EAI_AGAIN |
| MDIG_EAGAIN_DELAY | задержка в мсек между попытками при получении EAGAIN | | MDIG_EAGAIN_DELAY | задержка в мсек между попытками при получении EAI_AGAIN |
| AUTOHOSTLIST_INCOMING_MAXSEQ<br>AUTOHOSTLIST_RETRANS_MAXSEQ<br>AUTOHOSTLIST_RETRANS_THRESHOLD<br>AUTOHOSTLIST_RETRANS_RESET<br>AUTOHOSTLIST_FAIL_THRESHOLD<br>AUTOHOSTLIST_FAIL_TIME<br>AUTOHOSTLIST_UDP_IN<br>AUTOHOSTLIST_UDP_OUT | параметры [автохостлистов](#детектор-неудач-автохостлистов) | | AUTOHOSTLIST_INCOMING_MAXSEQ<br>AUTOHOSTLIST_RETRANS_MAXSEQ<br>AUTOHOSTLIST_RETRANS_THRESHOLD<br>AUTOHOSTLIST_RETRANS_RESET<br>AUTOHOSTLIST_FAIL_THRESHOLD<br>AUTOHOSTLIST_FAIL_TIME<br>AUTOHOSTLIST_UDP_IN<br>AUTOHOSTLIST_UDP_OUT | параметры [автохостлистов](#детектор-неудач-автохостлистов) |
| AUTOHOSTLIST_DEBUGLOG | включение autohostlist debug log. лог пишется в `ipset/zapret-hosts-auto-debug.log` | | AUTOHOSTLIST_DEBUGLOG | включение autohostlist debug log. лог пишется в `ipset/zapret-hosts-auto-debug.log` |
| GZIP_LISTS | применять ли сжатие gzip для генерируемых хост и ip листов | | GZIP_LISTS | применять ли сжатие gzip для генерируемых хост и ip листов |

View File

@@ -1,3 +1,7 @@
## English
[Manual](manual.en.md)
## Зачем это нужно ## Зачем это нужно
Автономное средство противодействия DPI, которое не требует подключения каких-либо сторонних серверов. Может помочь Автономное средство противодействия DPI, которое не требует подключения каких-либо сторонних серверов. Может помочь
@@ -11,11 +15,13 @@ VPN. Может использоваться для частичной проз
[Полный мануал](manual.md) [Полный мануал](manual.md)
## Поддержать разработчика ## Поддержать разработчика. Donations
Если вы считаете проект полезным и желаете поддержать разработку, направляйте ваши пожертвования на следующие адреса криптокошельков : Если вы считаете проект полезным и желаете поддержать разработку, направляйте ваши пожертвования на следующие адреса криптокошельков :
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E` (предпочительно сеть ERC-20) If you find this project useful and wish to donate here are crypto wallets :
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E` (предпочительно сеть ERC-20. ERC-20 preferred)
BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve` BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`

View File

@@ -1,30 +1,30 @@
# this custom script demonstrates how to launch extra nfqws instance limited by ipset # this custom script demonstrates how to launch extra nfqws instance limited by ipset
# can override in config : # can override in config :
NFQWS_MY1_OPT="${NFQWS_MY1_OPT:---filter-udp=* --payload known,unknown --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2:payload=all --new --filter-tcp=* --payload=known,unknown --lua-desync=multisplit}" NFQWS2_MY1_OPT="${NFQWS2_MY1_OPT:---filter-udp=* --payload known,unknown --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2:payload=all --new --filter-tcp=* --payload=known,unknown --lua-desync=multisplit}"
NFQWS_MY1_SUBNETS4="${NFQWS_MY1_SUBNETS4:-173.194.0.0/16 108.177.0.0/17 74.125.0.0/16 64.233.160.0/19 172.217.0.0/16}" NFQWS2_MY1_SUBNETS4="${NFQWS2_MY1_SUBNETS4:-173.194.0.0/16 108.177.0.0/17 74.125.0.0/16 64.233.160.0/19 172.217.0.0/16}"
NFQWS_MY1_SUBNETS6="${NFQWS_MY1_SUBNETS6:-2a00:1450::/29}" NFQWS2_MY1_SUBNETS6="${NFQWS2_MY1_SUBNETS6:-2a00:1450::/29}"
NFQWS_MY1_PORTS_TCP=${NFQWS_MY1_PORTS_TCP:-$NFQWS_PORTS_TCP} NFQWS2_MY1_PORTS_TCP=${NFQWS2_MY1_PORTS_TCP:-$NFQWS2_PORTS_TCP}
NFQWS_MY1_PORTS_UDP=${NFQWS_MY1_PORTS_UDP:-$NFQWS_PORTS_UDP} NFQWS2_MY1_PORTS_UDP=${NFQWS2_MY1_PORTS_UDP:-$NFQWS2_PORTS_UDP}
NFQWS_MY1_TCP_PKT_OUT=${NFQWS_MY1_TCP_PKT_OUT:-$NFQWS_TCP_PKT_OUT} NFQWS2_MY1_TCP_PKT_OUT=${NFQWS2_MY1_TCP_PKT_OUT:-$NFQWS2_TCP_PKT_OUT}
NFQWS_MY1_UDP_PKT_OUT=${NFQWS_MY1_UDP_PKT_OUT:-$NFQWS_UDP_PKT_OUT} NFQWS2_MY1_UDP_PKT_OUT=${NFQWS2_MY1_UDP_PKT_OUT:-$NFQWS2_UDP_PKT_OUT}
NFQWS_MY1_TCP_PKT_IN=${NFQWS_MY1_TCP_PKT_IN:-$NFQWS_TCP_PKT_IN} NFQWS2_MY1_TCP_PKT_IN=${NFQWS2_MY1_TCP_PKT_IN:-$NFQWS2_TCP_PKT_IN}
NFQWS_MY1_UDP_PKT_IN=${NFQWS_MY1_UDP_PKT_IN:-$NFQWS_UDP_PKT_IN} NFQWS2_MY1_UDP_PKT_IN=${NFQWS2_MY1_UDP_PKT_IN:-$NFQWS2_UDP_PKT_IN}
NFQWS_MY1_IPSET_SIZE=${NFQWS_MY1_IPSET_SIZE:-4096} NFQWS2_MY1_IPSET_SIZE=${NFQWS2_MY1_IPSET_SIZE:-4096}
NFQWS_MY1_IPSET_OPT="${NFQWS_MY1_IPSET_OPT:-hash:net hashsize 8192 maxelem $NFQWS_MY1_IPSET_SIZE}" NFQWS2_MY1_IPSET_OPT="${NFQWS2_MY1_IPSET_OPT:-hash:net hashsize 8192 maxelem $NFQWS2_MY1_IPSET_SIZE}"
alloc_dnum DNUM_NFQWS_MY1 alloc_dnum DNUM_NFQWS2_MY1
alloc_qnum QNUM_NFQWS_MY1 alloc_qnum QNUM_NFQWS2_MY1
NFQWS_MY1_NAME4=my1nfqws4 NFQWS2_MY1_NAME4=my1nfqws4
NFQWS_MY1_NAME6=my1nfqws6 NFQWS2_MY1_NAME6=my1nfqws6
zapret_custom_daemons() zapret_custom_daemons()
{ {
# $1 - 1 - run, 0 - stop # $1 - 1 - run, 0 - stop
local opt="--qnum=$QNUM_NFQWS_MY1 $NFQWS_MY1_OPT" local opt="--qnum=$QNUM_NFQWS2_MY1 $NFQWS2_MY1_OPT"
do_nfqws $1 $DNUM_NFQWS_MY1 "$opt" do_nfqws $1 $DNUM_NFQWS2_MY1 "$opt"
} }
zapret_custom_firewall() zapret_custom_firewall()
@@ -32,103 +32,103 @@ zapret_custom_firewall()
# $1 - 1 - run, 0 - stop # $1 - 1 - run, 0 - stop
local f4 f6 subnet local f4 f6 subnet
local NFQWS_MY1_PORTS_TCP=$(replace_char - : $NFQWS_MY1_PORTS_TCP) local NFQWS2_MY1_PORTS_TCP=$(replace_char - : $NFQWS2_MY1_PORTS_TCP)
local NFQWS_MY1_PORTS_UDP=$(replace_char - : $NFQWS_MY1_PORTS_UDP) local NFQWS2_MY1_PORTS_UDP=$(replace_char - : $NFQWS2_MY1_PORTS_UDP)
[ "$1" = 1 -a "$DISABLE_IPV4" != 1 ] && { [ "$1" = 1 -a "$DISABLE_IPV4" != 1 ] && {
ipset create $NFQWS_MY1_NAME4 $NFQWS_MY1_IPSET_OPT family inet 2>/dev/null ipset create $NFQWS2_MY1_NAME4 $NFQWS2_MY1_IPSET_OPT family inet 2>/dev/null
ipset flush $NFQWS_MY1_NAME4 ipset flush $NFQWS2_MY1_NAME4
for subnet in $NFQWS_MY1_SUBNETS4; do for subnet in $NFQWS2_MY1_SUBNETS4; do
echo add $NFQWS_MY1_NAME4 $subnet echo add $NFQWS2_MY1_NAME4 $subnet
done | ipset -! restore done | ipset -! restore
} }
[ "$1" = 1 -a "$DISABLE_IPV6" != 1 ] && { [ "$1" = 1 -a "$DISABLE_IPV6" != 1 ] && {
ipset create $NFQWS_MY1_NAME6 $NFQWS_MY1_IPSET_OPT family inet6 2>/dev/null ipset create $NFQWS2_MY1_NAME6 $NFQWS2_MY1_IPSET_OPT family inet6 2>/dev/null
ipset flush $NFQWS_MY1_NAME6 ipset flush $NFQWS2_MY1_NAME6
for subnet in $NFQWS_MY1_SUBNETS6; do for subnet in $NFQWS2_MY1_SUBNETS6; do
echo add $NFQWS_MY1_NAME6 $subnet echo add $NFQWS2_MY1_NAME6 $subnet
done | ipset -! restore done | ipset -! restore
} }
[ -n "$NFQWS_MY1_PORTS_TCP" ] && { [ -n "$NFQWS2_MY1_PORTS_TCP" ] && {
[ -n "$NFQWS_MY1_TCP_PKT_OUT" -a "$NFQWS_MY1_TCP_PKT_OUT" != 0 ] && { [ -n "$NFQWS2_MY1_TCP_PKT_OUT" -a "$NFQWS2_MY1_TCP_PKT_OUT" != 0 ] && {
f4="-p tcp -m multiport --dports $NFQWS_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS_MY1_TCP_PKT_OUT -m set --match-set" f4="-p tcp -m multiport --dports $NFQWS2_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS2_MY1_TCP_PKT_OUT -m set --match-set"
f6="$f4 $NFQWS_MY1_NAME6 dst" f6="$f4 $NFQWS2_MY1_NAME6 dst"
f4="$f4 $NFQWS_MY1_NAME4 dst" f4="$f4 $NFQWS2_MY1_NAME4 dst"
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1 fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
} }
[ -n "$NFQWS_MY1_TCP_PKT_IN" -a "$NFQWS_MY1_TCP_PKT_IN" != 0 ] && { [ -n "$NFQWS2_MY1_TCP_PKT_IN" -a "$NFQWS2_MY1_TCP_PKT_IN" != 0 ] && {
f4="-p tcp -m multiport --sports $NFQWS_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS_MY1_TCP_PKT_IN -m set --match-set" f4="-p tcp -m multiport --sports $NFQWS2_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS2_MY1_TCP_PKT_IN -m set --match-set"
f6="$f4 $NFQWS_MY1_NAME6 src" f6="$f4 $NFQWS2_MY1_NAME6 src"
f4="$f4 $NFQWS_MY1_NAME4 src" f4="$f4 $NFQWS2_MY1_NAME4 src"
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1 fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
} }
} }
[ -n "$NFQWS_MY1_PORTS_UDP" ] && { [ -n "$NFQWS2_MY1_PORTS_UDP" ] && {
[ -n "$NFQWS_MY1_UDP_PKT_OUT" -a "$NFQWS_MY1_UDP_PKT_OUT" != 0 ] && { [ -n "$NFQWS2_MY1_UDP_PKT_OUT" -a "$NFQWS2_MY1_UDP_PKT_OUT" != 0 ] && {
f4="-p udp -m multiport --dports $NFQWS_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS_MY1_UDP_PKT_OUT -m set --match-set" f4="-p udp -m multiport --dports $NFQWS2_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS2_MY1_UDP_PKT_OUT -m set --match-set"
f6="$f4 $NFQWS_MY1_NAME6 dst" f6="$f4 $NFQWS2_MY1_NAME6 dst"
f4="$f4 $NFQWS_MY1_NAME4 dst" f4="$f4 $NFQWS2_MY1_NAME4 dst"
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1 fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
} }
[ -n "$NFQWS_MY1_UDP_PKT_IN" -a "$NFQWS_MY1_UDP_PKT_IN" != 0 ] && { [ -n "$NFQWS2_MY1_UDP_PKT_IN" -a "$NFQWS2_MY1_UDP_PKT_IN" != 0 ] && {
f4="-p udp -m multiport --sports $NFQWS_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS_MY1_UDP_PKT_IN -m set --match-set" f4="-p udp -m multiport --sports $NFQWS2_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS2_MY1_UDP_PKT_IN -m set --match-set"
f6="$f4 $NFQWS_MY1_NAME6 src" f6="$f4 $NFQWS2_MY1_NAME6 src"
f4="$f4 $NFQWS_MY1_NAME4 src" f4="$f4 $NFQWS2_MY1_NAME4 src"
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1 fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
} }
} }
[ "$1" = 1 ] || { [ "$1" = 1 ] || {
ipset destroy $NFQWS_MY1_NAME4 2>/dev/null ipset destroy $NFQWS2_MY1_NAME4 2>/dev/null
ipset destroy $NFQWS_MY1_NAME6 2>/dev/null ipset destroy $NFQWS2_MY1_NAME6 2>/dev/null
} }
} }
zapret_custom_firewall_nft() zapret_custom_firewall_nft()
{ {
local f4 f6 subnets local f4 f6 subnets
local first_packets_only="$nft_connbytes 1-$NFQWS_MY1_PKT_OUT" local first_packets_only="$nft_connbytes 1-$NFQWS2_MY1_PKT_OUT"
[ "$DISABLE_IPV4" != 1 ] && { [ "$DISABLE_IPV4" != 1 ] && {
make_comma_list subnets $NFQWS_MY1_SUBNETS4 make_comma_list subnets $NFQWS2_MY1_SUBNETS4
nft_create_set $NFQWS_MY1_NAME4 "type ipv4_addr; size $NFQWS_MY1_IPSET_SIZE; auto-merge; flags interval;" nft_create_set $NFQWS2_MY1_NAME4 "type ipv4_addr; size $NFQWS2_MY1_IPSET_SIZE; auto-merge; flags interval;"
nft_flush_set $NFQWS_MY1_NAME4 nft_flush_set $NFQWS2_MY1_NAME4
nft_add_set_element $NFQWS_MY1_NAME4 "$subnets" nft_add_set_element $NFQWS2_MY1_NAME4 "$subnets"
} }
[ "$DISABLE_IPV6" != 1 ] && { [ "$DISABLE_IPV6" != 1 ] && {
make_comma_list subnets $NFQWS_MY1_SUBNETS6 make_comma_list subnets $NFQWS2_MY1_SUBNETS6
nft_create_set $NFQWS_MY1_NAME6 "type ipv6_addr; size $NFQWS_MY1_IPSET_SIZE; auto-merge; flags interval;" nft_create_set $NFQWS2_MY1_NAME6 "type ipv6_addr; size $NFQWS2_MY1_IPSET_SIZE; auto-merge; flags interval;"
nft_flush_set $NFQWS_MY1_NAME6 nft_flush_set $NFQWS2_MY1_NAME6
nft_add_set_element $NFQWS_MY1_NAME6 "$subnets" nft_add_set_element $NFQWS2_MY1_NAME6 "$subnets"
} }
[ -n "$NFQWS_MY1_PORTS_TCP" ] && { [ -n "$NFQWS2_MY1_PORTS_TCP" ] && {
[ -n "$NFQWS_MY1_TCP_PKT_OUT" -a "$NFQWS_MY1_TCP_PKT_OUT" != 0 ] && { [ -n "$NFQWS2_MY1_TCP_PKT_OUT" -a "$NFQWS2_MY1_TCP_PKT_OUT" != 0 ] && {
f4="tcp dport {$NFQWS_MY1_PORTS_TCP} $(nft_first_packets $NFQWS_MY1_TCP_PKT_OUT)" f4="tcp dport {$NFQWS2_MY1_PORTS_TCP} $(nft_first_packets $NFQWS2_MY1_TCP_PKT_OUT)"
f6="$f4 ip6 daddr @$NFQWS_MY1_NAME6" f6="$f4 ip6 daddr @$NFQWS2_MY1_NAME6"
f4="$f4 ip daddr @$NFQWS_MY1_NAME4" f4="$f4 ip daddr @$NFQWS2_MY1_NAME4"
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1 nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
} }
[ -n "$NFQWS_MY1_TCP_PKT_IN" -a "$NFQWS_MY1_TCP_PKT_IN" != 0 ] && { [ -n "$NFQWS2_MY1_TCP_PKT_IN" -a "$NFQWS2_MY1_TCP_PKT_IN" != 0 ] && {
f4="tcp sport {$NFQWS_MY1_PORTS_TCP} $(nft_first_packets $NFQWS_MY1_TCP_PKT_IN)" f4="tcp sport {$NFQWS2_MY1_PORTS_TCP} $(nft_first_packets $NFQWS2_MY1_TCP_PKT_IN)"
f6="$f4 ip6 saddr @$NFQWS_MY1_NAME6" f6="$f4 ip6 saddr @$NFQWS2_MY1_NAME6"
f4="$f4 ip saddr @$NFQWS_MY1_NAME4" f4="$f4 ip saddr @$NFQWS2_MY1_NAME4"
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1 nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
} }
} }
[ -n "$NFQWS_MY1_PORTS_UDP" ] && { [ -n "$NFQWS2_MY1_PORTS_UDP" ] && {
[ -n "$NFQWS_MY1_UDP_PKT_OUT" -a "$NFQWS_MY1_UDP_PKT_OUT" != 0 ] && { [ -n "$NFQWS2_MY1_UDP_PKT_OUT" -a "$NFQWS2_MY1_UDP_PKT_OUT" != 0 ] && {
f4="udp dport {$NFQWS_MY1_PORTS_UDP} $(nft_first_packets $NFQWS_MY1_UDP_PKT_OUT)" f4="udp dport {$NFQWS2_MY1_PORTS_UDP} $(nft_first_packets $NFQWS2_MY1_UDP_PKT_OUT)"
f6="$f4 ip6 daddr @$NFQWS_MY1_NAME6" f6="$f4 ip6 daddr @$NFQWS2_MY1_NAME6"
f4="$f4 ip daddr @$NFQWS_MY1_NAME4" f4="$f4 ip daddr @$NFQWS2_MY1_NAME4"
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1 nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
} }
[ -n "$NFQWS_MY1_UDP_PKT_IN" -a "$NFQWS_MY1_UDP_PKT_IN" != 0 ] && { [ -n "$NFQWS2_MY1_UDP_PKT_IN" -a "$NFQWS2_MY1_UDP_PKT_IN" != 0 ] && {
f4="udp sport {$NFQWS_MY1_PORTS_UDP} $(nft_first_packets $NFQWS_MY1_UDP_PKT_IN)" f4="udp sport {$NFQWS2_MY1_PORTS_UDP} $(nft_first_packets $NFQWS2_MY1_UDP_PKT_IN)"
f6="$f4 ip6 saddr @$NFQWS_MY1_NAME6" f6="$f4 ip6 saddr @$NFQWS2_MY1_NAME6"
f4="$f4 ip saddr @$NFQWS_MY1_NAME4" f4="$f4 ip saddr @$NFQWS2_MY1_NAME4"
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1 nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
} }
} }
} }
@@ -139,6 +139,6 @@ zapret_custom_firewall_nft_flush()
# this function is called after all nft fw rules are deleted # this function is called after all nft fw rules are deleted
# however sets are not deleted. it's desired to clear sets here. # however sets are not deleted. it's desired to clear sets here.
nft_del_set $NFQWS_MY1_NAME4 2>/dev/null nft_del_set $NFQWS2_MY1_NAME4 2>/dev/null
nft_del_set $NFQWS_MY1_NAME6 2>/dev/null nft_del_set $NFQWS2_MY1_NAME6 2>/dev/null
} }

View File

@@ -1,3 +1,3 @@
udp.PayloadLength=148 and udp.Payload[0]=0x01 or udp.PayloadLength=148 and udp.Payload32[0]=0x01000000 or
udp.PayloadLength=92 and udp.Payload[0]=0x02 or udp.PayloadLength=92 and udp.Payload32[0]=0x02000000 or
udp.PayloadLength=64 and udp.Payload[0]=0x03 udp.PayloadLength=64 and udp.Payload32[0]=0x03000000

View File

@@ -149,12 +149,17 @@ function http_hostcase(ctx, desync)
error("http_hostcase: invalid host spelling '"..spell.."'") error("http_hostcase: invalid host spelling '"..spell.."'")
else else
local hdis = http_dissect_req(desync.dis.payload) local hdis = http_dissect_req(desync.dis.payload)
if hdis.headers.host then if hdis then
DLOG("http_hostcase: 'Host:' => '"..spell.."'") local idx_host = array_field_search(hdis.headers, "header_low", "host")
desync.dis.payload = string.sub(desync.dis.payload,1,hdis.headers.host.pos_start-1)..spell..string.sub(desync.dis.payload,hdis.headers.host.pos_header_end+1) if idx_host then
return VERDICT_MODIFY DLOG("http_hostcase: 'Host:' => '"..spell.."'")
desync.dis.payload = string.sub(desync.dis.payload,1,hdis.headers[idx_host].pos_start-1)..spell..string.sub(desync.dis.payload,hdis.headers[idx_host].pos_header_end+1)
return VERDICT_MODIFY
else
DLOG("http_hostcase: 'Host:' header not found")
end
else else
DLOG("http_hostcase: 'Host:' header not found") DLOG("http_hostcase: http dissect error")
end end
end end
end end
@@ -162,6 +167,7 @@ end
-- nfqws1 : "--methodeol" -- nfqws1 : "--methodeol"
-- standard args : direction -- standard args : direction
-- NOTE : if using with other http tampering methodeol should be the last !
function http_methodeol(ctx, desync) function http_methodeol(ctx, desync)
if not desync.dis.tcp then if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync) instance_cutoff_shim(ctx, desync)
@@ -170,17 +176,22 @@ function http_methodeol(ctx, desync)
direction_cutoff_opposite(ctx, desync) direction_cutoff_opposite(ctx, desync)
if desync.l7payload=="http_req" and direction_check(desync) then if desync.l7payload=="http_req" and direction_check(desync) then
local hdis = http_dissect_req(desync.dis.payload) local hdis = http_dissect_req(desync.dis.payload)
local ua = hdis.headers["user-agent"] if hdis then
if ua then local idx_ua = array_field_search(hdis.headers, "header_low", "user-agent")
if (ua.pos_end - ua.pos_value_start) < 2 then if idx_ua then
DLOG("http_methodeol: 'User-Agent:' header is too short") local ua = hdis.headers[idx_ua]
if (ua.pos_end - ua.pos_value_start) < 2 then
DLOG("http_methodeol: 'User-Agent:' header is too short")
else
DLOG("http_methodeol: applied")
desync.dis.payload="\r\n"..string.sub(desync.dis.payload,1,ua.pos_end-2)..(string.sub(desync.dis.payload,ua.pos_end+1) or "");
return VERDICT_MODIFY
end
else else
DLOG("http_methodeol: applied") DLOG("http_methodeol: 'User-Agent:' header not found")
desync.dis.payload="\r\n"..string.sub(desync.dis.payload,1,ua.pos_end-2)..(string.sub(desync.dis.payload,ua.pos_end+1) or "");
return VERDICT_MODIFY
end end
else else
DLOG("http_methodeol: 'User-Agent:' header not found") DLOG("http_methodeol: http dissect error")
end end
end end
end end
@@ -197,10 +208,11 @@ function http_unixeol(ctx, desync)
if desync.l7payload=="http_req" and direction_check(desync) then if desync.l7payload=="http_req" and direction_check(desync) then
local hdis = http_dissect_req(desync.dis.payload) local hdis = http_dissect_req(desync.dis.payload)
if hdis then if hdis then
if hdis.headers["user-agent"] then local idx_ua = array_field_search(hdis.headers, "header_low", "user-agent")
if idx_ua then
local http = http_reconstruct_req(hdis, true) local http = http_reconstruct_req(hdis, true)
if #http < #desync.dis.payload then if #http < #desync.dis.payload then
hdis.headers["user-agent"].value = hdis.headers["user-agent"].value .. string.rep(" ", #desync.dis.payload - #http) hdis.headers[idx_ua].value = hdis.headers[idx_ua].value .. string.rep(" ", #desync.dis.payload - #http)
end end
local http = http_reconstruct_req(hdis, true) local http = http_reconstruct_req(hdis, true)
if #http==#desync.dis.payload then if #http==#desync.dis.payload then
@@ -211,7 +223,7 @@ function http_unixeol(ctx, desync)
DLOG("http_unixeol: reconstruct differs in size from original: "..#http.."!="..#desync.dis.payload) DLOG("http_unixeol: reconstruct differs in size from original: "..#http.."!="..#desync.dis.payload)
end end
else else
DLOG("http_unixeol: user-agent header absent") DLOG("http_unixeol: 'User-Agent:' header absent")
end end
else else
DLOG("http_unixeol: could not dissect http") DLOG("http_unixeol: could not dissect http")

View File

@@ -569,7 +569,6 @@ function array_search(a, v)
return k return k
end end
end end
return nil
end end
-- linear search array a for a[index].f==v. return index -- linear search array a for a[index].f==v. return index
function array_field_search(a, f, v) function array_field_search(a, f, v)
@@ -578,7 +577,6 @@ function array_field_search(a, f, v)
return k return k
end end
end end
return nil
end end
-- find pos of the next eol and pos of the next non-eol character after eol -- find pos of the next eol and pos of the next non-eol character after eol
@@ -1558,7 +1556,7 @@ function http_dissect_headers(http, pos)
end end
header,value,pos_endheader,pos_startvalue = http_dissect_header(header) header,value,pos_endheader,pos_startvalue = http_dissect_header(header)
if header then if header then
headers[string.lower(header)] = { header = header, value = value, pos_start = pos, pos_end = eol, pos_header_end = pos+pos_endheader-1, pos_value_start = pos+pos_startvalue-1 } headers[#headers+1] = { header_low = string.lower(header), header = header, value = value, pos_start = pos, pos_end = eol, pos_header_end = pos+pos_endheader-1, pos_value_start = pos+pos_startvalue-1 }
end end
pos=pnext pos=pnext
end end
@@ -1609,11 +1607,16 @@ function http_dissect_reply(http)
code = tonumber(string.sub(http,10,pos-1)) code = tonumber(string.sub(http,10,pos-1))
if not code then return nil end if not code then return nil end
pos = find_next_line(http,pos) pos = find_next_line(http,pos)
return { code = code, headers = http_dissect_headers(http,pos) } local hdis = { code = code }
hdis.headers, hdis.pos_headers_end = http_dissect_headers(http,pos)
if hdis.pos_headers_end then
hdis.body = string.sub(http, hdis.pos_headers_end)
end
return hdis
end end
function http_reconstruct_headers(headers, unixeol) function http_reconstruct_headers(headers, unixeol)
local eol = unixeol and "\n" or "\r\n" local eol = unixeol and "\n" or "\r\n"
return headers and btable(headers, function(a) return a.header..": "..a.value..eol end) or "" return headers and barray(headers, function(a) return a.header..": "..a.value..eol end) or ""
end end
function http_reconstruct_req(hdis, unixeol) function http_reconstruct_req(hdis, unixeol)
local eol = unixeol and "\n" or "\r\n" local eol = unixeol and "\n" or "\r\n"

View File

@@ -455,8 +455,8 @@ static void exithelp(void)
printf( printf(
" --family=<4|6|46>\t\t; ipv4, ipv6, ipv4+ipv6\n" " --family=<4|6|46>\t\t; ipv4, ipv6, ipv4+ipv6\n"
" --threads=<threads_number>\n" " --threads=<threads_number>\n"
" --eagain=<eagain_retries>\t; how many times to retry if EAGAIN received. default %u\n" " --eagain=<eagain_retries>\t; how many times to retry if EAI_AGAIN received. default %u\n"
" --eagain-delay=<ms>\t\t; time in msec to wait between EAGAIN attempts. default %u\n" " --eagain-delay=<ms>\t\t; time in msec to wait between EAI_AGAIN attempts. default %u\n"
" --verbose\t\t\t; print query progress to stderr\n" " --verbose\t\t\t; print query progress to stderr\n"
" --stats=N\t\t\t; print resolve stats to stderr every N domains\n" " --stats=N\t\t\t; print resolve stats to stderr every N domains\n"
" --log-resolved=<file>\t\t; log successfully resolved domains to a file\n" " --log-resolved=<file>\t\t; log successfully resolved domains to a file\n"

View File

@@ -622,7 +622,7 @@ BOOL LowMandatoryLevel(void)
label_low.Label.Sid = (PSID)buf1; label_low.Label.Sid = (PSID)buf1;
InitializeSid(label_low.Label.Sid, &label_authority, 1); InitializeSid(label_low.Label.Sid, &label_authority, 1);
label_low.Label.Attributes = 0; label_low.Label.Attributes = SE_GROUP_INTEGRITY;
*GetSidSubAuthority(label_low.Label.Sid, 0) = SECURITY_MANDATORY_LOW_RID; *GetSidSubAuthority(label_low.Label.Sid, 0) = SECURITY_MANDATORY_LOW_RID;
// S-1-16-12288 : Mandatory Label\High Mandatory Level // S-1-16-12288 : Mandatory Label\High Mandatory Level
@@ -892,7 +892,7 @@ bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_lis
wlan_filter_ssid = ssid_filter; wlan_filter_ssid = ssid_filter;
return true; return true;
} }
bool win_dark_deinit(void) void win_dark_deinit(void)
{ {
if (pNetworkListManager) if (pNetworkListManager)
{ {
@@ -997,11 +997,12 @@ bool nlm_list(bool bAll)
} }
else else
bRet = false; bRet = false;
CoUninitialize();
} }
else else
bRet = false; bRet = false;
CoUninitialize();
return bRet; return bRet;
} }
@@ -1171,8 +1172,11 @@ static HANDLE windivert_init_filter(const char *filter, UINT64 flags)
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, w_win32_error, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPSTR)&errormessage, 0, NULL); NULL, w_win32_error, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPSTR)&errormessage, 0, NULL);
DLOG_ERR("windivert: error opening filter: %s", errormessage); if (errormessage)
LocalFree(errormessage); {
DLOG_ERR("windivert: error opening filter: %s", errormessage);
LocalFree(errormessage);
}
if (w_win32_error == ERROR_INVALID_IMAGE_HASH) if (w_win32_error == ERROR_INVALID_IMAGE_HASH)
DLOG_ERR("windivert: try to disable secure boot and install OS patches\n"); DLOG_ERR("windivert: try to disable secure boot and install OS patches\n");

View File

@@ -94,7 +94,7 @@ bool ensure_dir_access(const char *filename);
bool prepare_low_appdata(); bool prepare_low_appdata();
bool win_sandbox(void); bool win_sandbox(void);
bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_list_head *nlm_filter); bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_list_head *nlm_filter);
bool win_dark_deinit(void); void win_dark_deinit(void);
bool logical_net_filter_present(void); bool logical_net_filter_present(void);
bool logical_net_filter_match(void); bool logical_net_filter_match(void);
bool nlm_list(bool bAll); bool nlm_list(bool bAll);

View File

@@ -30,7 +30,7 @@ static void protocol_probe(t_protocol_probe *probe, int probe_count, const uint8
{ {
for (int i = 0; i < probe_count; i++) for (int i = 0; i < probe_count; i++)
{ {
if ((!probe[i].l7match || *l7proto==probe[i].l7) && probe[i].check(data_payload, len_payload)) if (!l7_payload_match(probe[i].l7p, params.payload_disable) && (!probe[i].l7match || *l7proto==probe[i].l7) && probe[i].check(data_payload, len_payload))
{ {
*l7payload = probe[i].l7p; *l7payload = probe[i].l7p;
if (*l7proto == L7_UNKNOWN) if (*l7proto == L7_UNKNOWN)
@@ -753,7 +753,6 @@ static uint8_t desync(
struct func_list *func; struct func_list *func;
int ref_arg = LUA_NOREF, status; int ref_arg = LUA_NOREF, status;
bool b, b_cutoff_all, b_unwanted_payload; bool b, b_cutoff_all, b_unwanted_payload;
t_lua_desync_context ctx = { .magic = 0, .dp = dp, .ctrack = ctrack, .dis = dis, .cancel = false, .incoming = bIncoming };
const char *sDirection = bIncoming ? "in" : "out"; const char *sDirection = bIncoming ? "in" : "out";
struct packet_range *range; struct packet_range *range;
size_t l; size_t l;
@@ -782,13 +781,24 @@ static uint8_t desync(
if (LIST_FIRST(&dp->lua_desync)) if (LIST_FIRST(&dp->lua_desync))
{ {
lua_rawgeti(params.L, LUA_REGISTRYINDEX, params.ref_desync_ctx);
t_lua_desync_context *ctx = (t_lua_desync_context *)luaL_checkudata(params.L, 1, "desync_ctx");
// this is singleton stored in the registry. safe to pop
lua_pop(params.L,1);
ctx->dp = dp;
ctx->ctrack = ctrack;
ctx->dis = dis;
ctx->cancel = false;
ctx->incoming = bIncoming;
b_cutoff_all = b_unwanted_payload = true; b_cutoff_all = b_unwanted_payload = true;
ctx.func_n = 1; ctx->func_n = 1;
LIST_FOREACH(func, &dp->lua_desync, next) LIST_FOREACH(func, &dp->lua_desync, next)
{ {
ctx.func = func->func; ctx->func = func->func;
desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance)); desync_instance(func->func, dp->n, ctx->func_n, instance, sizeof(instance));
ctx.instance = instance; ctx->instance = instance;
range = bIncoming ? &func->range_in : &func->range_out; range = bIncoming ? &func->range_in : &func->range_out;
if (b_unwanted_payload) if (b_unwanted_payload)
@@ -796,7 +806,7 @@ static uint8_t desync(
if (b_cutoff_all) if (b_cutoff_all)
{ {
if (lua_instance_cutoff_check(params.L, &ctx, bIncoming)) if (lua_instance_cutoff_check(params.L, ctx, bIncoming))
DLOG("* lua '%s' : voluntary cutoff\n", instance); DLOG("* lua '%s' : voluntary cutoff\n", instance);
else if (check_pos_cutoff(pos, range)) else if (check_pos_cutoff(pos, range))
{ {
@@ -814,7 +824,7 @@ static uint8_t desync(
else else
b_cutoff_all = false; b_cutoff_all = false;
} }
ctx.func_n++; ctx->func_n++;
} }
if (b_cutoff_all) if (b_cutoff_all)
{ {
@@ -867,14 +877,14 @@ static uint8_t desync(
} }
ref_arg = luaL_ref(params.L, LUA_REGISTRYINDEX); ref_arg = luaL_ref(params.L, LUA_REGISTRYINDEX);
ctx.func_n = 1; ctx->func_n = 1;
LIST_FOREACH(func, &dp->lua_desync, next) LIST_FOREACH(func, &dp->lua_desync, next)
{ {
ctx.func = func->func; ctx->func = func->func;
desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance)); desync_instance(func->func, dp->n, ctx->func_n, instance, sizeof(instance));
ctx.instance = instance; ctx->instance = instance;
if (!lua_instance_cutoff_check(params.L, &ctx, bIncoming)) if (!lua_instance_cutoff_check(params.L, ctx, bIncoming))
{ {
range = bIncoming ? &func->range_in : &func->range_out; range = bIncoming ? &func->range_in : &func->range_out;
if (check_pos_range(pos, range)) if (check_pos_range(pos, range))
@@ -897,19 +907,17 @@ static uint8_t desync(
DLOG_ERR("desync function '%s' does not exist\n", func->func); DLOG_ERR("desync function '%s' does not exist\n", func->func);
goto err; goto err;
} }
lua_pushlightuserdata(params.L, &ctx); lua_rawgeti(params.L, LUA_REGISTRYINDEX, params.ref_desync_ctx);
lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref_arg); lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref_arg);
lua_pushf_args(params.L, &func->args, -1, true); lua_pushf_args(params.L, &func->args, -1, true);
lua_pushf_str(params.L, "func", func->func); lua_pushf_str(params.L, "func", func->func);
lua_pushf_int(params.L, "func_n", ctx.func_n); lua_pushf_int(params.L, "func_n", ctx->func_n);
lua_pushf_str(params.L, "func_instance", instance); lua_pushf_str(params.L, "func_instance", instance);
// lua should not store and access ctx outside of this call // prevent use of desync ctx object outside of function call
// if this happens make our best to prevent access to bad memory ctx->valid = true;
// this is not crash-proof but better than nothing
ctx.magic = MAGIC_CTX; // mark struct as valid
status = lua_pcall(params.L, 2, LUA_MULTRET, 0); status = lua_pcall(params.L, 2, LUA_MULTRET, 0);
ctx.magic = 0; // mark struct as invalid ctx->valid = false;
if (status) if (status)
{ {
@@ -939,8 +947,8 @@ static uint8_t desync(
range->upper_cutoff ? '<' : '-', range->upper_cutoff ? '<' : '-',
range->to.mode, range->to.pos); range->to.mode, range->to.pos);
} }
if (ctx.cancel) break; if (ctx->cancel) break;
ctx.func_n++; ctx->func_n++;
} }
} }
@@ -1117,7 +1125,7 @@ static uint8_t dpi_desync_tcp_packet_play(
} }
} }
// in absence of conntrack guess direction by presence of interface names. won't work on BSD // in absence of conntrack guess direction by presence of interface names. won't work on BSD
bReverseFixed = ctrack ? (bReverse ^ params.server) : (bReverse = ifin && ifin && (!ifout || !*ifout)); bReverseFixed = ctrack ? (bReverse ^ params.server) : (bReverse = ifin && *ifin && (!ifout || !*ifout));
setup_direction(dis, bReverseFixed, &src, &dst, &sdip4, &sdip6, &sdport); setup_direction(dis, bReverseFixed, &src, &dst, &sdip4, &sdip6, &sdport);
ifname = bReverse ? ifin : ifout; ifname = bReverse ? ifin : ifout;
#ifdef HAS_FILTER_SSID #ifdef HAS_FILTER_SSID
@@ -1272,19 +1280,32 @@ static uint8_t dpi_desync_tcp_packet_play(
process_retrans_fail(ctrack, dis, (struct sockaddr*)&src, ifin); process_retrans_fail(ctrack, dis, (struct sockaddr*)&src, ifin);
if (IsHttp(rdata_payload, rlen_payload)) // do not detect payload if reasm is in progress
if (!ctrack_replay || ReasmIsEmpty(&ctrack_replay->reasm_client))
{ {
DLOG("packet contains HTTP request\n"); t_protocol_probe testers[] = {
l7payload = L7P_HTTP_REQ; {L7P_TLS_CLIENT_HELLO,L7_TLS,IsTLSClientHelloPartial},
if (l7proto == L7_UNKNOWN) {L7P_HTTP_REQ,L7_HTTP,IsHttp,false},
{L7P_XMPP_STREAM,L7_XMPP,IsXMPPStream,false},
{L7P_XMPP_STARTTLS,L7_XMPP,IsXMPPStartTLS,false}
};
protocol_probe(testers, sizeof(testers) / sizeof(*testers), dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
if (l7payload==L7P_UNKNOWN)
{ {
l7proto = L7_HTTP; // this is special type. detection requires AES and can be successful only for the first data packet. no reason to AES every packet
if (ctrack && ctrack->l7proto == L7_UNKNOWN) ctrack->l7proto = l7proto; if (ctrack && (ctrack->pos.client.seq_last - ctrack->pos.client.seq0)==1)
{
t_protocol_probe testers[] = {
{L7P_MTPROTO_INITIAL,L7_MTPROTO,IsMTProto}
};
protocol_probe(testers, sizeof(testers) / sizeof(*testers), dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
}
} }
}
// we do not reassemble http if (l7payload==L7P_HTTP_REQ)
reasm_client_cancel(ctrack); {
bHaveHost = HttpExtractHost(rdata_payload, rlen_payload, host, sizeof(host)); bHaveHost = HttpExtractHost(rdata_payload, rlen_payload, host, sizeof(host));
if (!bHaveHost) if (!bHaveHost)
{ {
@@ -1292,21 +1313,17 @@ static uint8_t dpi_desync_tcp_packet_play(
goto pass; goto pass;
} }
} }
else if (IsTLSClientHello(rdata_payload, rlen_payload, TLS_PARTIALS_ENABLE)) else if (l7payload==L7P_TLS_CLIENT_HELLO || l7proto==L7_TLS && l7payload==L7P_UNKNOWN && ctrack_replay && !ReasmIsEmpty(&ctrack_replay->reasm_client))
{ {
bool bReqFull = IsTLSRecordFull(rdata_payload, rlen_payload);
DLOG(bReqFull ? "packet contains full TLS ClientHello\n" : "packet contains partial TLS ClientHello\n");
l7payload = L7P_TLS_CLIENT_HELLO; l7payload = L7P_TLS_CLIENT_HELLO;
if (l7proto == L7_UNKNOWN)
{ bool bReqFull = IsTLSRecordFull(rdata_payload, rlen_payload);
l7proto = L7_TLS; DLOG(bReqFull ? "TLS client hello is FULL\n" : "TLS client hello is PARTIAL\n");
if (ctrack && ctrack->l7proto == L7_UNKNOWN) ctrack->l7proto = l7proto;
}
if (bReqFull) TLSDebug(rdata_payload, rlen_payload); if (bReqFull) TLSDebug(rdata_payload, rlen_payload);
bHaveHost = TLSHelloExtractHost(rdata_payload, rlen_payload, host, sizeof(host), TLS_PARTIALS_ENABLE); bHaveHost = TLSHelloExtractHost(rdata_payload, rlen_payload, host, sizeof(host), true);
if (ctrack && !(params.reasm_payload_disable && l7_payload_match(l7payload, params.reasm_payload_disable))) if (ctrack && !l7_payload_match(l7payload, params.reasm_payload_disable))
{ {
// do not reasm retransmissions // do not reasm retransmissions
if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_client) && !is_retransmission(&ctrack->pos.client)) if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_client) && !is_retransmission(&ctrack->pos.client))
@@ -1336,26 +1353,6 @@ static uint8_t dpi_desync_tcp_packet_play(
} }
} }
} }
else if (ctrack && (ctrack->pos.client.seq_last - ctrack->pos.client.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[] = {
{L7P_XMPP_STREAM,L7_XMPP,IsXMPPStream,false},
{L7P_XMPP_STARTTLS,L7_XMPP,IsXMPPStartTLS,false}
};
protocol_probe(testers, sizeof(testers) / sizeof(*testers), dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
}
} }
if (bHaveHost) if (bHaveHost)
@@ -1663,7 +1660,7 @@ static uint8_t dpi_desync_udp_packet_play(
} }
} }
// in absence of conntrack guess direction by presence of interface names. won't work on BSD // in absence of conntrack guess direction by presence of interface names. won't work on BSD
bReverseFixed = ctrack ? (bReverse ^ params.server) : (bReverse = ifin && ifin && (!ifout || !*ifout)); bReverseFixed = ctrack ? (bReverse ^ params.server) : (bReverse = ifin && *ifin && (!ifout || !*ifout));
setup_direction(dis, bReverseFixed, &src, &dst, &sdip4, &sdip6, &sdport); setup_direction(dis, bReverseFixed, &src, &dst, &sdip4, &sdip6, &sdport);
ifname = bReverse ? ifin : ifout; ifname = bReverse ? ifin : ifout;
@@ -1756,7 +1753,7 @@ static uint8_t dpi_desync_udp_packet_play(
} }
if (pclean) if (pclean)
{ {
bool reasm_disable = params.reasm_payload_disable && l7_payload_match(l7payload, params.reasm_payload_disable); bool reasm_disable = l7_payload_match(l7payload, params.reasm_payload_disable);
if (ctrack && !reasm_disable && !ReasmIsEmpty(&ctrack->reasm_client)) if (ctrack && !reasm_disable && !ReasmIsEmpty(&ctrack->reasm_client))
{ {
if (ReasmHasSpace(&ctrack->reasm_client, clean_len)) if (ReasmHasSpace(&ctrack->reasm_client, clean_len))
@@ -1818,7 +1815,7 @@ static uint8_t dpi_desync_udp_packet_play(
{ {
data_decrypt = defrag + hello_offset; data_decrypt = defrag + hello_offset;
len_decrypt = hello_len; len_decrypt = hello_len;
bHaveHost = TLSHelloExtractHostFromHandshake(data_decrypt, len_decrypt, host, sizeof(host), TLS_PARTIALS_ENABLE); bHaveHost = TLSHelloExtractHostFromHandshake(data_decrypt, len_decrypt, host, sizeof(host), true);
} }
else else
{ {

View File

@@ -31,7 +31,12 @@ int z_readfile(FILE *F, char **buf, size_t *size, size_t extra_alloc)
r = Z_ERRNO; r = Z_ERRNO;
goto zerr; goto zerr;
} }
if (!zs.avail_in) break; if (!zs.avail_in)
{
// file is not full
r = Z_DATA_ERROR;
goto zerr;
}
zs.next_in = in; zs.next_in = in;
do do
{ {

View File

@@ -396,16 +396,16 @@ void phton64(uint8_t *p, uint64_t v)
p[7] = (uint8_t)v; p[7] = (uint8_t)v;
} }
uint16_t swap16(uint16_t u) uint16_t bswap16(uint16_t u)
{ {
// __builtin_bswap16 is absent in ancient lexra gcc 4.6 // __builtin_bswap16 is absent in ancient lexra gcc 4.6
return (u>>8) | ((u&0xFF)<<8); return (u>>8) | ((u&0xFF)<<8);
} }
uint32_t swap24(uint32_t u) uint32_t bswap24(uint32_t u)
{ {
return (u>>16) & 0xFF | u & 0xFF00 | (u<<16) & 0xFF0000; return (u>>16) & 0xFF | u & 0xFF00 | (u<<16) & 0xFF0000;
} }
uint64_t swap48(uint64_t u) uint64_t bswap48(uint64_t u)
{ {
return ((u & 0xFF0000000000) >> 40) | ((u & 0xFF00000000) >> 24) | ((u & 0xFF000000) >> 8) | ((u & 0xFF0000) << 8) | ((u & 0xFF00) << 24) | ((u & 0xFF) << 40); return ((u & 0xFF0000000000) >> 40) | ((u & 0xFF00000000) >> 24) | ((u & 0xFF000000) >> 8) | ((u & 0xFF0000) << 8) | ((u & 0xFF00) << 24) | ((u & 0xFF) << 40);
} }

View File

@@ -66,9 +66,9 @@ void phton48(uint8_t *p, uint64_t v);
uint64_t pntoh64(const uint8_t *p); uint64_t pntoh64(const uint8_t *p);
void phton64(uint8_t *p, uint64_t v); void phton64(uint8_t *p, uint64_t v);
uint16_t swap16(uint16_t u); uint16_t bswap16(uint16_t u);
uint32_t swap24(uint32_t u); uint32_t bswap24(uint32_t u);
uint64_t swap48(uint64_t u); uint64_t bswap48(uint64_t u);
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size); bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size);
char hex_digit(uint8_t v); char hex_digit(uint8_t v);

View File

@@ -79,7 +79,7 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename)
} }
else else
{ {
DLOG_ERR("zlib decompression failed : result %d\n",r); DLOG_ERR("zlib decompression failed : result %d\n", r);
return false; return false;
} }
} }

View File

@@ -4,7 +4,6 @@
#include "helpers.h" #include "helpers.h"
// inplace tolower() and add to pool
static bool addpool(ipset *ips, char **s, const char *end, int *ct) static bool addpool(ipset *ips, char **s, const char *end, int *ct)
{ {
char *p, cidr[128]; char *p, cidr[128];

View File

@@ -279,7 +279,7 @@ static int luacall_swap16(lua_State *L)
int64_t i = (int64_t)luaL_checklint(L,1); int64_t i = (int64_t)luaL_checklint(L,1);
if (i>0xFFFF || i<-(int64_t)0xFFFF) luaL_error(L, "out of range"); if (i>0xFFFF || i<-(int64_t)0xFFFF) luaL_error(L, "out of range");
uint16_t u = (uint16_t)i; uint16_t u = (uint16_t)i;
lua_pushinteger(L,swap16(u)); lua_pushinteger(L,bswap16(u));
return 1; return 1;
} }
static int luacall_swap24(lua_State *L) static int luacall_swap24(lua_State *L)
@@ -289,7 +289,7 @@ static int luacall_swap24(lua_State *L)
int64_t i =(int64_t)luaL_checklint(L,1); int64_t i =(int64_t)luaL_checklint(L,1);
if (i>0xFFFFFF || i<-(int64_t)0xFFFFFF) luaL_error(L, "out of range"); if (i>0xFFFFFF || i<-(int64_t)0xFFFFFF) luaL_error(L, "out of range");
uint32_t u = (uint32_t)i; uint32_t u = (uint32_t)i;
lua_pushlint(L,swap24(u)); lua_pushlint(L,bswap24(u));
return 1; return 1;
} }
static int luacall_swap32(lua_State *L) static int luacall_swap32(lua_State *L)
@@ -309,7 +309,7 @@ static int luacall_swap48(lua_State *L)
int64_t i =(int64_t)luaL_checklint(L,1); int64_t i =(int64_t)luaL_checklint(L,1);
if (i>0xFFFFFFFFFFFF || i<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range"); if (i>0xFFFFFFFFFFFF || i<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
uint64_t u = (uint64_t)i; uint64_t u = (uint64_t)i;
lua_pushlint(L, swap48(u)); lua_pushlint(L, bswap48(u));
return 1; return 1;
} }
static int lua_uxadd(lua_State *L, int64_t max) static int lua_uxadd(lua_State *L, int64_t max)
@@ -769,20 +769,41 @@ static int luacall_clock_gettime(lua_State *L)
LUA_STACK_GUARD_RETURN(L,2) LUA_STACK_GUARD_RETURN(L,2)
} }
static void lua_mt_init_desync_ctx(lua_State *L)
{
luaL_newmetatable(L, "desync_ctx");
lua_pop(L, 1);
}
static t_lua_desync_context *lua_desync_ctx(lua_State *L) static t_lua_desync_context *lua_desync_ctx(lua_State *L)
{ {
if (lua_isnil(L,1)) if (lua_isnil(L,1)) luaL_error(L, "missing ctx");
luaL_error(L, "missing ctx"); t_lua_desync_context *ctx = (t_lua_desync_context *)luaL_checkudata(L, 1, "desync_ctx");
if (!lua_islightuserdata(L,1)) if (!ctx->valid) luaL_error(L, "ctx is invalid");
luaL_error(L, "bad ctx - invalid data type");
t_lua_desync_context *ctx = lua_touserdata(L,1);
// ensure it's really ctx. LUA could pass us any lightuserdata pointer
if (ctx->magic!=MAGIC_CTX)
luaL_error(L, "bad ctx - magic bytes invalid");
return ctx; return ctx;
} }
static void lua_desync_ctx_create(lua_State *L)
{
if (!params.ref_desync_ctx)
{
LUA_STACK_GUARD_ENTER(L)
t_lua_desync_context *ctx = (t_lua_desync_context *)lua_newuserdata(L, sizeof(t_lua_desync_context));
memset(ctx, 0, sizeof(*ctx));
luaL_getmetatable(L, "desync_ctx");
lua_setmetatable(L, -2);
params.ref_desync_ctx = luaL_ref(params.L, LUA_REGISTRYINDEX);
LUA_STACK_GUARD_LEAVE(L,0)
}
}
static void lua_desync_ctx_destroy(lua_State *L)
{
if (params.ref_desync_ctx)
{
luaL_unref(L, LUA_REGISTRYINDEX, params.ref_desync_ctx);
params.ref_desync_ctx = 0;
}
}
static int luacall_instance_cutoff(lua_State *L) static int luacall_instance_cutoff(lua_State *L)
{ {
@@ -911,24 +932,55 @@ static int luacall_execution_plan(lua_State *L)
lua_newtable(L); lua_newtable(L);
struct func_list *func; struct func_list *func;
char instance[256], pls[2048]; char instance[256], plsl[2048];
struct packet_range *range; struct packet_range *range;
unsigned int n=1; unsigned int n=1;
t_l7payload pl;
const char *pls;
LIST_FOREACH(func, &ctx->dp->lua_desync, next) LIST_FOREACH(func, &ctx->dp->lua_desync, next)
{ {
if (n > ctx->func_n) if (n > ctx->func_n)
{ {
desync_instance(func->func, ctx->dp->n, n, instance, sizeof(instance)); desync_instance(func->func, ctx->dp->n, n, instance, sizeof(instance));
range = ctx->incoming ? &func->range_in : &func->range_out; range = ctx->incoming ? &func->range_in : &func->range_out;
lua_pushinteger(L, n - ctx->func_n); lua_pushinteger(L, n - ctx->func_n);
lua_createtable(L, 0, 6); lua_createtable(L, 0, 7);
lua_pushf_args(L,&func->args, -1, false); lua_pushf_args(L,&func->args, -1, false);
lua_pushf_str(L,"func", func->func); lua_pushf_str(L,"func", func->func);
lua_pushf_int(L,"func_n", ctx->func_n); lua_pushf_int(L,"func_n", ctx->func_n);
lua_pushf_str(L,"func_instance", instance); lua_pushf_str(L,"func_instance", instance);
lua_pushf_range(L,"range", range); lua_pushf_range(L,"range", range);
if (l7_payload_str_list(func->payload_type, pls, sizeof(pls)))
lua_pushf_str(L,"payload_filter", pls); lua_pushstring(L, "payload");
lua_newtable(L);
if (func->payload_type==L7P_ALL)
{
lua_pushliteral(L,"all");
lua_pushboolean(L,true);
lua_rawset(L,-3);
}
else
{
for (pl=0 ; pl<L7P_LAST ; pl++)
{
if (func->payload_type & (1<<pl))
{
if ((pls = l7payload_str(pl)))
{
lua_pushstring(L,pls);
lua_pushboolean(L,true);
lua_rawset(L,-3);
}
}
}
}
lua_rawset(L,-3);
if (l7_payload_str_list(func->payload_type, plsl, sizeof(plsl)))
lua_pushf_str(L,"payload_filter", plsl);
else else
lua_pushf_nil(L,"payload_filter"); lua_pushf_nil(L,"payload_filter");
@@ -2159,8 +2211,9 @@ static int luacall_reconstruct_dissect(lua_State *L)
LUA_STACK_GUARD_ENTER(L) LUA_STACK_GUARD_ENTER(L)
size_t l;
uint8_t buf[RECONSTRUCT_MAX_SIZE]; uint8_t buf[RECONSTRUCT_MAX_SIZE];
size_t l = sizeof(buf); l = sizeof(buf);
bool ip6_preserve_next, badsum; bool ip6_preserve_next, badsum;
lua_reconstruct_extract_options(L, 2, &badsum, &ip6_preserve_next, NULL); lua_reconstruct_extract_options(L, 2, &badsum, &ip6_preserve_next, NULL);
@@ -2412,13 +2465,14 @@ static int luacall_rawsend_dissect(lua_State *L)
LUA_STACK_GUARD_ENTER(L) LUA_STACK_GUARD_ENTER(L)
uint8_t buf[RECONSTRUCT_MAX_SIZE]; size_t len;
size_t len=sizeof(buf);
const char *ifout; const char *ifout;
int repeats; int repeats;
uint32_t fwmark; uint32_t fwmark;
sockaddr_in46 sa; sockaddr_in46 sa;
bool b, badsum, ip6_preserve_next; bool b, badsum, ip6_preserve_next;
uint8_t buf[RECONSTRUCT_MAX_SIZE];
len = sizeof(buf);
luaL_checktype(L,1,LUA_TTABLE); luaL_checktype(L,1,LUA_TTABLE);
lua_rawsend_extract_options(L,2, &repeats, &fwmark, &ifout); lua_rawsend_extract_options(L,2, &repeats, &fwmark, &ifout);
@@ -2844,14 +2898,19 @@ zerr:
// ---------------------------------------- // ----------------------------------------
void lua_cleanup(lua_State *L)
{
lua_desync_ctx_destroy(L);
// conntrack holds lua state. must clear it before lua shoudown
ConntrackPoolDestroy(&params.conntrack);
}
void lua_shutdown() void lua_shutdown()
{ {
if (params.L) if (params.L)
{ {
DLOG("LUA SHUTDOWN\n"); DLOG("LUA SHUTDOWN\n");
// conntrack holds lua state. must clear it before lua shoudown lua_cleanup(params.L);
ConntrackPoolDestroy(&params.conntrack);
lua_close(params.L); lua_close(params.L);
params.L=NULL; params.L=NULL;
} }
@@ -3031,7 +3090,7 @@ static int luaL_doZfile(lua_State *L, const char *filename)
return r; return r;
} }
else else
return luaL_dofile(L, filename); return luaL_dofile(L, fname);
} }
static bool lua_init_scripts(void) static bool lua_init_scripts(void)
@@ -3394,6 +3453,8 @@ static void lua_init_functions(void)
static void lua_init_mt() static void lua_init_mt()
{ {
lua_mt_init_zstream(params.L); lua_mt_init_zstream(params.L);
lua_mt_init_desync_ctx(params.L);
lua_desync_ctx_create(params.L);
} }
bool lua_init(void) bool lua_init(void)
@@ -3401,6 +3462,9 @@ bool lua_init(void)
DLOG("\nLUA INIT\n"); DLOG("\nLUA INIT\n");
if (!lua_basic_init()) return false; if (!lua_basic_init()) return false;
LUA_STACK_GUARD_ENTER(params.L)
lua_sec_harden(); lua_sec_harden();
lua_init_blobs(); lua_init_blobs();
lua_init_const(); lua_init_const();
@@ -3409,10 +3473,11 @@ bool lua_init(void)
if (!lua_init_scripts()) goto err; if (!lua_init_scripts()) goto err;
if (!lua_desync_functions_exist()) goto err; if (!lua_desync_functions_exist()) goto err;
LUA_STACK_GUARD_LEAVE(params.L,0)
DLOG("LUA INIT DONE\n\n"); DLOG("LUA INIT DONE\n\n");
return true; return true;
err: err:
LUA_STACK_GUARD_LEAVE(params.L,0)
lua_shutdown(); lua_shutdown();
return false; return false;
} }

View File

@@ -101,15 +101,14 @@ bool lua_reconstruct_tcphdr(lua_State *L, int idx, struct tcphdr *tcp, size_t *l
bool lua_reconstruct_udphdr(lua_State *L, int idx, struct udphdr *udp); bool lua_reconstruct_udphdr(lua_State *L, int idx, struct udphdr *udp);
bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, bool badsum, bool ip6_preserve_next); bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, bool badsum, bool ip6_preserve_next);
#define MAGIC_CTX 0xE73DC935
typedef struct { typedef struct {
uint32_t magic;
unsigned int func_n; unsigned int func_n;
const char *func, *instance; const char *func, *instance;
const struct desync_profile *dp; const struct desync_profile *dp;
const struct dissect *dis; const struct dissect *dis;
t_ctrack *ctrack; t_ctrack *ctrack;
bool incoming,cancel; bool incoming, cancel;
bool valid;
} t_lua_desync_context; } t_lua_desync_context;
bool lua_instance_cutoff_check(lua_State *L, const t_lua_desync_context *ctx, bool bIn); bool lua_instance_cutoff_check(lua_State *L, const t_lua_desync_context *ctx, bool bIn);

View File

@@ -52,9 +52,7 @@
struct params_s params; struct params_s params;
static volatile sig_atomic_t bReload = false; static volatile sig_atomic_t bReload = false;
#ifdef __CYGWIN__
bool bQuit = false; bool bQuit = false;
#endif
static void onhup(int sig) static void onhup(int sig)
{ {
@@ -102,12 +100,37 @@ static void onusr2(int sig)
ipcachePrint(&params.ipcache); ipcachePrint(&params.ipcache);
printf("\n"); printf("\n");
} }
static void onint(int sig)
{
const char *msg = "INT received !\n";
size_t wr = write(1, msg, strlen(msg));
bQuit = true;
}
static void onterm(int sig)
{
const char *msg = "TERM received !\n";
size_t wr = write(1, msg, strlen(msg));
bQuit = true;
}
static void pre_desync(void) static void pre_desync(void)
{ {
signal(SIGHUP, onhup); struct sigaction sa;
signal(SIGUSR1, onusr1);
signal(SIGUSR2, onusr2); sigemptyset(&sa.sa_mask);
sa.sa_sigaction = NULL;
sa.sa_flags = 0;
sa.sa_handler = onhup;
sigaction(SIGHUP, &sa, NULL);
sa.sa_handler = onusr1;
sigaction(SIGUSR1, &sa, NULL);
sa.sa_handler = onusr2;
sigaction(SIGUSR2, &sa, NULL);
sa.sa_handler = onint;
sigaction(SIGINT, &sa, NULL);
sa.sa_handler = onterm;
sigaction(SIGTERM, &sa, NULL);
} }
@@ -156,13 +179,14 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_da
uint8_t *data; uint8_t *data;
uint32_t ifidx_out, ifidx_in; uint32_t ifidx_out, ifidx_in;
char ifout[IFNAMSIZ], ifin[IFNAMSIZ]; char ifout[IFNAMSIZ], ifin[IFNAMSIZ];
uint8_t mod[RECONSTRUCT_MAX_SIZE];
size_t modlen; size_t modlen;
uint32_t mark;
uint8_t mod[RECONSTRUCT_MAX_SIZE];
ph = nfq_get_msg_packet_hdr(nfa); ph = nfq_get_msg_packet_hdr(nfa);
id = ph ? ntohl(ph->packet_id) : 0; id = ph ? ntohl(ph->packet_id) : 0;
uint32_t mark = nfq_get_nfmark(nfa); mark = nfq_get_nfmark(nfa);
ilen = nfq_get_payload(nfa, &data); ilen = nfq_get_payload(nfa, &data);
ifidx_out = nfq_get_outdev(nfa); ifidx_out = nfq_get_outdev(nfa);
@@ -282,12 +306,12 @@ static void notify_ready(void)
static int nfq_main(void) static int nfq_main(void)
{ {
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned));
struct nfq_handle *h = NULL; struct nfq_handle *h = NULL;
struct nfq_q_handle *qh = NULL; struct nfq_q_handle *qh = NULL;
int res, fd, e; int res, fd, e;
ssize_t rd; ssize_t rd;
FILE *Fpid = NULL; FILE *Fpid = NULL;
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned));
if (*params.pidfile && !(Fpid = fopen(params.pidfile, "w"))) if (*params.pidfile && !(Fpid = fopen(params.pidfile, "w")))
{ {
@@ -348,6 +372,7 @@ static int nfq_main(void)
{ {
while ((rd = recv(fd, buf, sizeof(buf), 0)) >= 0) while ((rd = recv(fd, buf, sizeof(buf), 0)) >= 0)
{ {
if (bQuit) goto quit;
ReloadCheck(); ReloadCheck();
lua_do_gc(); lua_do_gc();
#ifdef HAS_FILTER_SSID #ifdef HAS_FILTER_SSID
@@ -363,6 +388,11 @@ static int nfq_main(void)
else else
DLOG("recv from nfq returned 0 !\n"); DLOG("recv from nfq returned 0 !\n");
} }
if (errno==EINTR)
{
if (bQuit) goto quit;
continue;
}
e = errno; e = errno;
DLOG_ERR("recv: recv=%zd errno %d\n", rd, e); DLOG_ERR("recv: recv=%zd errno %d\n", rd, e);
errno = e; errno = e;
@@ -370,6 +400,7 @@ static int nfq_main(void)
// do not fail on ENOBUFS // do not fail on ENOBUFS
} while (e == ENOBUFS); } while (e == ENOBUFS);
exok:
res=0; res=0;
ex: ex:
nfq_deinit(&h, &qh); nfq_deinit(&h, &qh);
@@ -383,13 +414,15 @@ err:
if (Fpid) fclose(Fpid); if (Fpid) fclose(Fpid);
res=1; res=1;
goto ex; goto ex;
quit:
DLOG_CONDUP("quit requested\n");
goto exok;
} }
#elif defined(BSD) #elif defined(BSD)
static int dvt_main(void) static int dvt_main(void)
{ {
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned));
struct sockaddr_storage sa_from; struct sockaddr_storage sa_from;
int fd[2] = { -1,-1 }; // 4,6 int fd[2] = { -1,-1 }; // 4,6
int i, r, res = 1, fdct = 1, fdmax; int i, r, res = 1, fdct = 1, fdmax;
@@ -398,6 +431,9 @@ static int dvt_main(void)
ssize_t rd, wr; ssize_t rd, wr;
fd_set fdset; fd_set fdset;
FILE *Fpid = NULL; FILE *Fpid = NULL;
struct sockaddr_in bp4;
struct sockaddr_in6 bp6;
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned));
if (*params.pidfile && !(Fpid = fopen(params.pidfile, "w"))) if (*params.pidfile && !(Fpid = fopen(params.pidfile, "w")))
{ {
@@ -405,49 +441,42 @@ static int dvt_main(void)
return 1; return 1;
} }
bp4.sin_family = AF_INET;
bp4.sin_port = htons(params.port);
bp4.sin_addr.s_addr = INADDR_ANY;
DLOG_CONDUP("creating divert4 socket\n");
fd[0] = socket_divert(AF_INET);
if (fd[0] == -1) {
DLOG_PERROR("socket (DIVERT4)");
goto exiterr;
}
DLOG_CONDUP("binding divert4 socket\n");
if (bind(fd[0], (struct sockaddr*)&bp4, sizeof(bp4)) < 0)
{ {
struct sockaddr_in bp4; DLOG_PERROR("bind (DIVERT4)");
bp4.sin_family = AF_INET; goto exiterr;
bp4.sin_port = htons(params.port);
bp4.sin_addr.s_addr = INADDR_ANY;
DLOG_CONDUP("creating divert4 socket\n");
fd[0] = socket_divert(AF_INET);
if (fd[0] == -1) {
DLOG_PERROR("socket (DIVERT4)");
goto exiterr;
}
DLOG_CONDUP("binding divert4 socket\n");
if (bind(fd[0], (struct sockaddr*)&bp4, sizeof(bp4)) < 0)
{
DLOG_PERROR("bind (DIVERT4)");
goto exiterr;
}
} }
#ifdef __OpenBSD__ #ifdef __OpenBSD__
{ // in OpenBSD must use separate divert sockets for ipv4 and ipv6
// in OpenBSD must use separate divert sockets for ipv4 and ipv6 memset(&bp6, 0, sizeof(bp6));
struct sockaddr_in6 bp6; bp6.sin6_family = AF_INET6;
memset(&bp6, 0, sizeof(bp6)); bp6.sin6_port = htons(params.port);
bp6.sin6_family = AF_INET6;
bp6.sin6_port = htons(params.port);
DLOG_CONDUP("creating divert6 socket\n"); DLOG_CONDUP("creating divert6 socket\n");
fd[1] = socket_divert(AF_INET6); fd[1] = socket_divert(AF_INET6);
if (fd[1] == -1) { if (fd[1] == -1) {
DLOG_PERROR("socket (DIVERT6)"); DLOG_PERROR("socket (DIVERT6)");
goto exiterr; goto exiterr;
}
DLOG_CONDUP("binding divert6 socket\n");
if (bind(fd[1], (struct sockaddr*)&bp6, sizeof(bp6)) < 0)
{
DLOG_PERROR("bind (DIVERT6)");
goto exiterr;
}
fdct++;
} }
DLOG_CONDUP("binding divert6 socket\n");
if (bind(fd[1], (struct sockaddr*)&bp6, sizeof(bp6)) < 0)
{
DLOG_PERROR("bind (DIVERT6)");
goto exiterr;
}
fdct++;
#endif #endif
fdmax = (fd[0] > fd[1] ? fd[0] : fd[1]) + 1; fdmax = (fd[0] > fd[1] ? fd[0] : fd[1]) + 1;
@@ -487,13 +516,14 @@ static int dvt_main(void)
FD_ZERO(&fdset); FD_ZERO(&fdset);
for (i = 0; i < fdct; i++) FD_SET(fd[i], &fdset); for (i = 0; i < fdct; i++) FD_SET(fd[i], &fdset);
r = select(fdmax, &fdset, NULL, NULL, NULL); r = select(fdmax, &fdset, NULL, NULL, NULL);
if (bQuit)
{
DLOG_CONDUP("quit requested\n");
goto exitok;
}
if (r == -1) if (r == -1)
{ {
if (errno == EINTR) if (errno == EINTR) continue;
{
// a signal received
continue;
}
DLOG_PERROR("select"); DLOG_PERROR("select");
goto exiterr; goto exiterr;
} }
@@ -571,6 +601,7 @@ static int dvt_main(void)
} }
} }
exitok:
res = 0; res = 0;
exiterr: exiterr:
if (Fpid) fclose(Fpid); if (Fpid) fclose(Fpid);
@@ -590,11 +621,11 @@ static int win_main()
unsigned int id; unsigned int id;
uint8_t verdict; uint8_t verdict;
bool bOutbound; bool bOutbound;
uint8_t packet[RECONSTRUCT_MAX_SIZE];
uint32_t mark; uint32_t mark;
WINDIVERT_ADDRESS wa; WINDIVERT_ADDRESS wa;
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
int res=0; int res=0;
uint8_t packet[RECONSTRUCT_MAX_SIZE];
if (params.daemon) daemonize(); if (params.daemon) daemonize();
@@ -621,7 +652,7 @@ static int win_main()
{ {
if (bQuit) if (bQuit)
{ {
DLOG("QUIT requested\n"); DLOG("quit requested\n");
goto ex; goto ex;
} }
usleep(500000); usleep(500000);
@@ -666,7 +697,7 @@ static int win_main()
} }
else if (errno == EINTR) else if (errno == EINTR)
{ {
DLOG("QUIT requested\n"); DLOG("quit requested\n");
goto ex; goto ex;
} }
DLOG_ERR("windivert: recv failed. errno %d\n", errno); DLOG_ERR("windivert: recv failed. errno %d\n", errno);
@@ -1340,7 +1371,7 @@ static void exithelp(void)
*all_payloads=0; *all_payloads=0;
for (t_l7payload pl=0 ; pl<L7P_LAST; pl++) for (t_l7payload pl=0 ; pl<L7P_LAST; pl++)
{ {
if (pl) strncat(all_payloads, " ", sizeof(all_payloads)-1-1); if (pl) strncat(all_payloads, " ", sizeof(all_payloads)-strlen(all_payloads)-1);
strncat(all_payloads, l7payload_str(pl), sizeof(all_payloads)-strlen(all_payloads)-1); strncat(all_payloads, l7payload_str(pl), sizeof(all_payloads)-strlen(all_payloads)-1);
} }
*all_protos=0; *all_protos=0;
@@ -1382,10 +1413,11 @@ static void exithelp(void)
#endif #endif
" --ctrack-timeouts=S:E:F[:U]\t\t\t\t; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default %u:%u:%u:%u\n" " --ctrack-timeouts=S:E:F[:U]\t\t\t\t; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default %u:%u:%u:%u\n"
" --ctrack-disable=[0|1]\t\t\t\t\t; 1 or no argument disables conntrack\n" " --ctrack-disable=[0|1]\t\t\t\t\t; 1 or no argument disables conntrack\n"
" --payload-disable=[type[,type]]\t\t\t; do not discover these payload types. for available payload types see '--payload'. disable all if no argument.\n"
" --server=[0|1]\t\t\t\t\t\t; change multiple aspects of src/dst ip/port handling for incoming connections\n" " --server=[0|1]\t\t\t\t\t\t; change multiple aspects of src/dst ip/port handling for incoming connections\n"
" --ipcache-lifetime=<int>\t\t\t\t; time in seconds to keep cached hop count and domain name (default %u). 0 = no expiration\n" " --ipcache-lifetime=<int>\t\t\t\t; time in seconds to keep cached hop count and domain name (default %u). 0 = no expiration\n"
" --ipcache-hostname=[0|1]\t\t\t\t; 1 or no argument enables ip->hostname caching\n" " --ipcache-hostname=[0|1]\t\t\t\t; 1 or no argument enables ip->hostname caching\n"
" --reasm-disable=[proto[,proto]]\t\t\t; disable reasm for these L7 payloads : tls_client_hello quic_initial . if no argument - disable all reasm.\n" " --reasm-disable=[type[,type]]\t\t\t\t; disable reasm for these L7 payloads : tls_client_hello quic_initial . if no argument - disable all reasm.\n"
#ifdef __CYGWIN__ #ifdef __CYGWIN__
"\nWINDIVERT FILTER:\n" "\nWINDIVERT FILTER:\n"
" --wf-iface=<int>[.<int>]\t\t\t\t; numeric network interface and subinterface indexes\n" " --wf-iface=<int>[.<int>]\t\t\t\t; numeric network interface and subinterface indexes\n"
@@ -1527,6 +1559,7 @@ enum opt_indices {
#endif #endif
IDX_CTRACK_TIMEOUTS, IDX_CTRACK_TIMEOUTS,
IDX_CTRACK_DISABLE, IDX_CTRACK_DISABLE,
IDX_PAYLOAD_DISABLE,
IDX_SERVER, IDX_SERVER,
IDX_IPCACHE_LIFETIME, IDX_IPCACHE_LIFETIME,
IDX_IPCACHE_HOSTNAME, IDX_IPCACHE_HOSTNAME,
@@ -1620,6 +1653,7 @@ static const struct option long_options[] = {
#endif #endif
[IDX_CTRACK_TIMEOUTS] = {"ctrack-timeouts", required_argument, 0, 0}, [IDX_CTRACK_TIMEOUTS] = {"ctrack-timeouts", required_argument, 0, 0},
[IDX_CTRACK_DISABLE] = {"ctrack-disable", optional_argument, 0, 0}, [IDX_CTRACK_DISABLE] = {"ctrack-disable", optional_argument, 0, 0},
[IDX_PAYLOAD_DISABLE] = {"payload-disable", optional_argument, 0, 0},
[IDX_SERVER] = {"server", optional_argument, 0, 0}, [IDX_SERVER] = {"server", optional_argument, 0, 0},
[IDX_IPCACHE_LIFETIME] = {"ipcache-lifetime", required_argument, 0, 0}, [IDX_IPCACHE_LIFETIME] = {"ipcache-lifetime", required_argument, 0, 0},
[IDX_IPCACHE_HOSTNAME] = {"ipcache-hostname", optional_argument, 0, 0}, [IDX_IPCACHE_HOSTNAME] = {"ipcache-hostname", optional_argument, 0, 0},
@@ -1949,6 +1983,18 @@ int main(int argc, char **argv)
case IDX_IPCACHE_HOSTNAME: case IDX_IPCACHE_HOSTNAME:
params.cache_hostname = !optarg || atoi(optarg); params.cache_hostname = !optarg || atoi(optarg);
break; break;
case IDX_PAYLOAD_DISABLE:
if (optarg)
{
if (!parse_l7p_list(optarg, &params.payload_disable))
{
DLOG_ERR("Invalid payload filter : %s\n", optarg);
exit_clean(1);
}
}
else
params.payload_disable = L7P_ALL;
break;
case IDX_REASM_DISABLE: case IDX_REASM_DISABLE:
if (optarg) if (optarg)
{ {
@@ -1959,7 +2005,7 @@ int main(int argc, char **argv)
} }
} }
else else
params.reasm_payload_disable = 0xFFFFFFFFFFFFFFFF; params.reasm_payload_disable = L7P_ALL;
break; break;
#if defined(__linux__) #if defined(__linux__)
case IDX_FWMARK: case IDX_FWMARK:
@@ -2640,7 +2686,8 @@ int main(int argc, char **argv)
HANDLE hMutexArg; HANDLE hMutexArg;
{ {
char mutex_name[128]; char mutex_name[128];
snprintf(mutex_name, sizeof(mutex_name), "Global\\winws2_arg_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u", hash_wf_tcp_in, hash_wf_udp_in, hash_wf_tcp_out, hash_wf_udp_out, hash_wf_raw, hash_wf_raw_part, hash_ssid_filter, hash_nlm_filter, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6); snprintf(mutex_name, sizeof(mutex_name), "Global\\winws2_arg_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u",
hash_wf_tcp_in, hash_wf_udp_in, hash_wf_tcp_out, hash_wf_udp_out, hash_wf_raw, hash_wf_raw_part, hash_ssid_filter, hash_nlm_filter, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6);
hMutexArg = CreateMutexA(NULL, TRUE, mutex_name); hMutexArg = CreateMutexA(NULL, TRUE, mutex_name);
if (hMutexArg && GetLastError() == ERROR_ALREADY_EXISTS) if (hMutexArg && GetLastError() == ERROR_ALREADY_EXISTS)

View File

@@ -498,6 +498,7 @@ void cleanup_params(struct params_s *params)
ipcacheDestroy(&params->ipcache); ipcacheDestroy(&params->ipcache);
blob_collection_destroy(&params->blobs); blob_collection_destroy(&params->blobs);
strlist_destroy(&params->lua_init_scripts); strlist_destroy(&params->lua_init_scripts);
#ifdef __CYGWIN__ #ifdef __CYGWIN__
strlist_destroy(&params->ssid_filter); strlist_destroy(&params->ssid_filter);
strlist_destroy(&params->nlm_filter); strlist_destroy(&params->nlm_filter);
@@ -531,6 +532,8 @@ void init_params(struct params_s *params)
LIST_INIT(&params->blobs); LIST_INIT(&params->blobs);
LIST_INIT(&params->lua_init_scripts); LIST_INIT(&params->lua_init_scripts);
params->reasm_payload_disable = params->payload_disable = 1<<L7P_NONE;
#ifdef __CYGWIN__ #ifdef __CYGWIN__
LIST_INIT(&params->ssid_filter); LIST_INIT(&params->ssid_filter);
LIST_INIT(&params->nlm_filter); LIST_INIT(&params->nlm_filter);

View File

@@ -21,8 +21,6 @@
#include <wordexp.h> #include <wordexp.h>
#endif #endif
#define TLS_PARTIALS_ENABLE true
#define RAW_SNDBUF (64*1024) // in bytes #define RAW_SNDBUF (64*1024) // in bytes
#define Q_MAXLEN 1024 // in packets #define Q_MAXLEN 1024 // in packets
@@ -45,7 +43,7 @@
// this MSS is used for ipv6 in windows and linux // this MSS is used for ipv6 in windows and linux
#define DEFAULT_MSS 1220 #define DEFAULT_MSS 1220
#define RECONSTRUCT_MAX_SIZE 16384 #define RECONSTRUCT_MAX_SIZE 65536
#define LUA_GC_INTERVAL 60 #define LUA_GC_INTERVAL 60
@@ -176,12 +174,14 @@ struct params_s
unsigned int ipcache_lifetime; unsigned int ipcache_lifetime;
ip_cache ipcache; ip_cache ipcache;
uint64_t reasm_payload_disable; uint64_t reasm_payload_disable;
uint64_t payload_disable;
struct str_list_head lua_init_scripts; struct str_list_head lua_init_scripts;
bool writeable_dir_enable; bool writeable_dir_enable;
char writeable_dir[PATH_MAX]; char writeable_dir[PATH_MAX];
int lua_gc; int lua_gc;
int ref_desync_ctx; // desync ctx userdata registry ref
lua_State *L; lua_State *L;
}; };

View File

@@ -675,7 +675,7 @@ ssize_t TLSPos(t_marker posmarker, int16_t pos, const uint8_t *data, size_t sz)
case PM_HOST_MIDSLD: case PM_HOST_MIDSLD:
case PM_HOST_ENDSLD: case PM_HOST_ENDSLD:
case PM_SNI_EXT: case PM_SNI_EXT:
if (TLSFindExt(data,sz,0,&ext,&elen,TLS_PARTIALS_ENABLE)) if (TLSFindExt(data,sz,0,&ext,&elen,true))
{ {
if (posmarker==PM_SNI_EXT) if (posmarker==PM_SNI_EXT)
{ {
@@ -989,24 +989,18 @@ bool IsQUICCryptoHello(const uint8_t *data, size_t len, size_t *hello_offset, si
uint8_t QUICDraftVersion(uint32_t version) uint8_t QUICDraftVersion(uint32_t version)
{ {
/* IETF Draft versions */ /* IETF Draft versions */
if ((version >> 8) == 0xff0000) { if ((version >> 8) == 0xff0000)
return (uint8_t)version; return (uint8_t)version;
}
/* Facebook mvfst, based on draft -22. */ /* Facebook mvfst, based on draft -22. */
if (version == 0xfaceb001) { if (version == 0xfaceb001)
return 22; return 22;
}
/* Facebook mvfst, based on draft -27. */ /* Facebook mvfst, based on draft -27. */
if (version == 0xfaceb002 || version == 0xfaceb00e) { if (version == 0xfaceb002 || version == 0xfaceb00e)
return 27; return 27;
}
/* GQUIC Q050, T050 and T051: they are not really based on any drafts, /* GQUIC Q050, T050 and T051: they are not really based on any drafts,
* but we must return a sensible value */ * but we must return a sensible value */
if (version == 0x51303530 || if (version == 0x51303530 || version == 0x54303530 || version == 0x54303531)
version == 0x54303530 ||
version == 0x54303531) {
return 27; return 27;
}
/* https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-15 /* https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-15
"Versions that follow the pattern 0x?a?a?a?a are reserved for use in "Versions that follow the pattern 0x?a?a?a?a are reserved for use in
forcing version negotiation to be exercised" forcing version negotiation to be exercised"
@@ -1014,19 +1008,17 @@ uint8_t QUICDraftVersion(uint32_t version)
used to select a proper salt (which depends on the version itself), but used to select a proper salt (which depends on the version itself), but
we don't have a real version here! Let's hope that we need to handle we don't have a real version here! Let's hope that we need to handle
only latest drafts... */ only latest drafts... */
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a) { if ((version & 0x0F0F0F0F) == 0x0a0a0a0a)
return 29; return 29;
}
/* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the /* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the
final draft version */ final draft version */
if (version == 0x00000001) { if (version == 0x00000001)
return 34; return 34;
}
/* QUIC Version 2 */ /* QUIC Version 2 */
/* TODO: for the time being use 100 as a number for V2 and let see how v2 drafts evolve */ /* TODO: for the time being use 100 as a number for V2 and let see how v2 drafts evolve */
if (version == 0x709A50C4) { if ((version == 0x709A50C4) || (version == 0x6b3343cf))
return 100; return 100;
}
return 0; return 0;
} }
@@ -1036,7 +1028,7 @@ static bool is_quic_draft_max(uint32_t draft_version, uint8_t max_version)
} }
static bool is_quic_v2(uint32_t version) static bool is_quic_v2(uint32_t version)
{ {
return version == 0x6b3343cf; return (version == 0x709A50C4) || (version == 0x6b3343cf);
} }
static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, const char *label, uint8_t *out, size_t out_len) static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, const char *label, uint8_t *out, size_t out_len)
@@ -1386,24 +1378,24 @@ bool IsDNSResponse(const uint8_t *data, size_t len)
} }
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len) bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len)
{ {
return len==148 && data[0]==1; return len==148 && pntoh32(data)==0x01000000;
} }
bool IsWireguardHandshakeResponse(const uint8_t *data, size_t len) bool IsWireguardHandshakeResponse(const uint8_t *data, size_t len)
{ {
return len==92 && data[0]==2; return len==92 && pntoh32(data)==0x02000000;
} }
bool IsWireguardHandshakeCookie(const uint8_t *data, size_t len) bool IsWireguardHandshakeCookie(const uint8_t *data, size_t len)
{ {
return len==64 && data[0]==3; return len==64 && pntoh32(data)==0x03000000;
} }
bool IsWireguardData(const uint8_t *data, size_t len) bool IsWireguardData(const uint8_t *data, size_t len)
{ {
// 16 bytes wg header + min 20 bytes for ipv4 encrypted header + 16 byte auth tag // 16 bytes wg header + min 20 bytes for ipv4 encrypted header + 16 byte auth tag
return len>=52 && data[0]==4; return len>=52 && pntoh32(data)==0x04000000;
} }
bool IsWireguardKeepalive(const uint8_t *data, size_t len) bool IsWireguardKeepalive(const uint8_t *data, size_t len)
{ {
return len==32 && data[0]==4; return len==32 && pntoh32(data)==0x04000000;
} }
bool IsDht(const uint8_t *data, size_t len) bool IsDht(const uint8_t *data, size_t len)
{ {

View File

@@ -20,7 +20,7 @@ typedef enum {
L7_XMPP, L7_XMPP,
L7_DNS, L7_DNS,
L7_MTPROTO, L7_MTPROTO,
L7_LAST, L7_INVALID=L7_LAST L7_LAST, L7_INVALID=L7_LAST, L7_NONE=L7_LAST
} t_l7proto; } t_l7proto;
const char *l7proto_str(t_l7proto l7); const char *l7proto_str(t_l7proto l7);
t_l7proto l7proto_from_name(const char *name); t_l7proto l7proto_from_name(const char *name);
@@ -53,7 +53,7 @@ typedef enum {
L7P_DNS_QUERY, L7P_DNS_QUERY,
L7P_DNS_RESPONSE, L7P_DNS_RESPONSE,
L7P_MTPROTO_INITIAL, L7P_MTPROTO_INITIAL,
L7P_LAST, L7P_INVALID=L7P_LAST L7P_LAST, L7P_INVALID=L7P_LAST, L7P_NONE=L7P_LAST
} t_l7payload; } t_l7payload;
t_l7payload l7payload_from_name(const char *name); t_l7payload l7payload_from_name(const char *name);
const char *l7payload_str(t_l7payload l7); const char *l7payload_str(t_l7payload l7);