mirror of
https://github.com/bol-van/zapret2.git
synced 2026-03-16 14:58:17 +00:00
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c320c8d57 | ||
|
|
b18f0770c8 | ||
|
|
f7fc845014 | ||
|
|
2c1a885a07 | ||
|
|
9eb308d84c | ||
|
|
3e724c3810 | ||
|
|
c179d55d88 | ||
|
|
3f1af1441e | ||
|
|
4c1b2b65f3 | ||
|
|
918258413f | ||
|
|
e6206c5a5f | ||
|
|
f93c6de772 | ||
|
|
5a7e2b1ca2 | ||
|
|
ca8104c72a | ||
|
|
3aad1f9ed9 | ||
|
|
fd288d5e7d | ||
|
|
349fe3f7d7 | ||
|
|
4554b7c15b | ||
|
|
0b595ae3a8 | ||
|
|
3e69e1b8c1 | ||
|
|
02b895910b | ||
|
|
b2a53e9c64 | ||
|
|
a626cfce8a | ||
|
|
ebcbfc37ba | ||
|
|
33d3c94b68 | ||
|
|
d55dbb7717 | ||
|
|
cb82be9eab | ||
|
|
024d36acc4 | ||
|
|
08c6151a4c | ||
|
|
520317dc3c | ||
|
|
6bc0bf1b97 | ||
|
|
d18fec9053 | ||
|
|
e60e5a0578 | ||
|
|
84576a7039 | ||
|
|
7957a0a425 | ||
|
|
7ba4110416 | ||
|
|
4babaef6a8 | ||
|
|
872e37d160 | ||
|
|
a8219f4897 | ||
|
|
36267b7e9b | ||
|
|
99a7f06976 | ||
|
|
3617b8934f | ||
|
|
8e6387a6df | ||
|
|
3bc0e8e350 |
@@ -47,14 +47,14 @@ pktws_seqovl_tests_tls()
|
||||
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 ${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=0
|
||||
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 ${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
|
||||
done
|
||||
for split in '1 2' 'sniext sniext+1' 'sniext+3 sniext+4' 'midsld-1 midsld' '1 2,midsld'; do
|
||||
|
||||
@@ -366,7 +366,7 @@ random()
|
||||
local r rs
|
||||
setup_random
|
||||
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
|
||||
rs="$RANDOM$RANDOM$(date)"
|
||||
fi
|
||||
|
||||
@@ -522,11 +522,6 @@ install_openwrt_firewall()
|
||||
{
|
||||
echo \* installing firewall script $1
|
||||
|
||||
[ -n "MODE" ] || {
|
||||
echo should specify MODE in $ZAPRET_CONFIG
|
||||
exitp 7
|
||||
}
|
||||
|
||||
echo "linking : $FW_SCRIPT_SRC => $OPENWRT_FW_INCLUDE"
|
||||
ln -fs "$FW_SCRIPT_SRC" "$OPENWRT_FW_INCLUDE"
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ ipt6_add_del()
|
||||
}
|
||||
ipt6a_add_del()
|
||||
{
|
||||
on_off_function ipt6 ipt6a_del "$@"
|
||||
on_off_function ipt6a ipt6_del "$@"
|
||||
}
|
||||
|
||||
is_ipt_flow_offload_avail()
|
||||
|
||||
@@ -41,7 +41,9 @@ AUTOHOSTLIST_DEBUGLOG=0
|
||||
|
||||
# number of parallel threads for domain list resolves
|
||||
MDIG_THREADS=30
|
||||
# EAI_AGAIN retries
|
||||
MDIG_EAGAIN=10
|
||||
# delay between EAI_AGAIN retries (ms)
|
||||
MDIG_EAGAIN_DELAY=500
|
||||
|
||||
# ipset/*.sh can compress large lists
|
||||
|
||||
@@ -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
|
||||
* init.d: 99-lan-filter custom script
|
||||
* 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
5098
docs/manual.en.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@
|
||||
- [nfqws2](#nfqws2)
|
||||
- [Общие принципы задания параметров](#общие-принципы-задания-параметров)
|
||||
- [Полный список опций](#полный-список-опций)
|
||||
- [Распознавание протоколов](#распознавание-протоколов)
|
||||
- [Использование множественных профилей](#использование-множественных-профилей)
|
||||
- [Шаблоны профилей](#шаблоны-профилей)
|
||||
- [Фильтрация по листам](#фильтрация-по-листам)
|
||||
@@ -668,10 +669,11 @@ nfqws2 использует стандартный парсер getopt_long_only
|
||||
--pidfile=<filename> ; запись PID в файл
|
||||
--ctrack-timeouts=S:E:F[:U] ; таймауты conntrack для стадий tcp SYN, ESTABLISHED, FIN и для udp
|
||||
--ctrack-disable=[0|1] ; 1 отключает conntrack
|
||||
--payload-disable=[type[,type]] ; отключить распознавание указанных типов пейлоадов. без аргумента - отключить все.
|
||||
--server=[0|1] ; серверный режим. для обслуживания listener-ов меняются многие аспекты выбора направления и ip/port источника/приемника
|
||||
--ipcache-lifetime=<int> ; время жизни записей кэша IP в секундах. 0 - без ограничений.
|
||||
--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:
|
||||
--writeable[=<dir_name>] ; создать директорию для Lua с разрешением записи и поместить путь к ней в переменную env "WRITEABLE" (только одна директория)
|
||||
@@ -689,7 +691,7 @@ MULTI-STRATEGY:
|
||||
--filter-l3=ipv4|ipv6 ; фильтр профиля : версия ip протокола
|
||||
--filter-tcp=[~]port1[-port2]|* ; фильтр профиля : порты tcp или диапазоны портов через запятую
|
||||
--filter-udp=[~]port1[-port2]|* ; фильтр профиля : порты udp или диапазоны портов через запятую
|
||||
--filter-l7=proto[,proto] ; фильтр профиля : список протоколов потока. полный список доступен в help тексте программы.
|
||||
--filter-l7=proto[,proto] ; фильтр профиля : список протоколов потока
|
||||
--ipset=<filename> ; фильтр профиля : включающий список ip адресов или подсетей из файла. может быть смешанным ipv4+ipv6.
|
||||
--ipset-ip=<ip_list> ; фильтр профиля : включающий фиксированный список ip адресов или подсетей через запятую
|
||||
--ipset-exclude=<filename> ; фильтр профиля : исключающий список ip адресов или подсетей из файла. может быть смешанным ipv4+ipv6.
|
||||
@@ -710,7 +712,7 @@ MULTI-STRATEGY:
|
||||
--hostlist-auto-debug=<logfile> ; дебаг лог автолиста
|
||||
|
||||
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 для последующих инстансов внутри профиля - исходящее направление
|
||||
--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 сетей
|
||||
```
|
||||
|
||||
## Распознавание протоколов
|
||||
|
||||
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=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`.
|
||||
|
||||
Диапазоны задаются в формах : `mX-mY`, `mX<mY`, `-mY`, `<mY`, `mX-`, где m - режим счетчика, X - нижнее значение, Y - верхнее значение.
|
||||
@@ -1417,8 +1443,8 @@ desync
|
||||
| replay_piece | number | номер проигрываемой части | нумерация с 1 |
|
||||
| replay_piece_count | number | количество проигрываемых частей | |
|
||||
| replay_piece_last | bool | последняя проигрываемая часть | |
|
||||
| l7payload | string | тип пейлоада текущего пакета или группы пакетов. список возможных в help тексте nfqws2 | если неизвестно - unknown |
|
||||
| l7proto | string | тип протокола потока | если неизвестно - unknown |
|
||||
| l7payload | string | тип [пейлоада](#распознавание-протоколов) текущего пакета или группы пакетов | если неизвестно - unknown |
|
||||
| l7proto | string | тип [протокола потока](#распознавание-протоколов) | если неизвестно - unknown |
|
||||
| reasm_data | string | результат сборки многопакетного сообщения, либо сам пейлоад, если сборки не было | пока применяется только для tcp |
|
||||
| reasm_offset | string | смещение текущего переигрываемого пакета в сборке | пока применяется только для tcp |
|
||||
| decrypt_data | string | результат сборки и дешифровки пейлоада или пейлоадов нескольких пакетов | применяется для quic |
|
||||
@@ -1554,7 +1580,7 @@ ipv6 extension headers и tcp options представляются в форме
|
||||
| Поле | Тип | Описание | Примечание |
|
||||
| :------------- | :----- | :-------------------------------------------------------------- | :----------------------------------------------- |
|
||||
| incoming_ttl | number | ttl/hl первого входящего пакета по потоку | может не быть, если не определено |
|
||||
| l7proto | string | протокол потока. список возможных доступен в help тексте nfqws2 | есть всегда. если неизвестно - unknown |
|
||||
| l7proto | string | [протокол потока](#распознавание-протоколов) | есть всегда. если неизвестно - unknown |
|
||||
| hostname | string | имя хоста. определяется на основе анализа L6/L7 протоколов | появляется только после определения |
|
||||
| hostname_is_ip | bool | является ли hostname ip адресом | только если есть hostname |
|
||||
| lua_state | table | таблица для хранения состояния, привязанного к потоку | есть всегда, передается с каждым пакетом потока |
|
||||
@@ -2212,7 +2238,8 @@ function execution_plan(ctx)
|
||||
| func_n | number | номер инстанса внутри профиля |
|
||||
| func_instance | string | название инстанса | производная имени функции, номера инстанса и номера профиля |
|
||||
| range | table | эффективный диапазон [счетчиков](#внутрипрофильные-фильтры) `--in-range` или `--out-range` в зависимости от текущего направления |
|
||||
| payload_filter | string | эффективный `--payload-filter` . список названий пейлоадов через запятую |
|
||||
| payload | table | эффективный `--payload-filter` . таблица с индексами - названиями типа пейлоада |
|
||||
| payload_filter | string | эффективный `--payload-filter` . список названий пейлоадов через запятую (иное представление payload) |
|
||||
|
||||
**range**
|
||||
|
||||
@@ -2520,7 +2547,9 @@ function http_reconstruct_req(hdis, unixeol)
|
||||
Разборка HTTP запроса или ответа http. http представляет собой многострочный текст.
|
||||
Разборка представляет собой таблицу с вложенными подтаблицами.
|
||||
В заголовках выдаются позиции начала и конца названия заголовка и самого значения.
|
||||
Названия полей в таблице headers соответствуют названию заголовков в нижнем регисте. Все позиции - внутри строки http.
|
||||
Все позиции - внутри строки http.
|
||||
|
||||
Для нахождения хедеров по названию используйте [array_field_search](#array_search) по полю "header_low", которое содержит название хедера в нижнем регистре.
|
||||
|
||||
Реконструктор http запроса берет таблицу-разбор и воссоздает raw string. Параметр unixeol заменяет стандартный для http перевод сктроки 0D0A на 0A. Это нестандарт и ломает все сервера, кроме nginx.
|
||||
|
||||
@@ -2530,9 +2559,11 @@ function http_reconstruct_req(hdis, unixeol)
|
||||
.uri
|
||||
string /test_uri
|
||||
.headers
|
||||
.content-length
|
||||
.1
|
||||
.header
|
||||
string Content-Length
|
||||
.header_low
|
||||
string content-length
|
||||
.value
|
||||
string 330
|
||||
.pos_start
|
||||
@@ -2543,9 +2574,11 @@ function http_reconstruct_req(hdis, unixeol)
|
||||
number 56
|
||||
.pos_value_start
|
||||
number 59
|
||||
.host
|
||||
.2
|
||||
.header
|
||||
string Host
|
||||
.header_low
|
||||
string host
|
||||
.value
|
||||
string testhost.com
|
||||
.pos_start
|
||||
@@ -2566,26 +2599,30 @@ function http_reconstruct_req(hdis, unixeol)
|
||||
.code
|
||||
number 200
|
||||
.headers
|
||||
.content-type
|
||||
.1
|
||||
.pos_header_end
|
||||
number 28
|
||||
.pos_value_start
|
||||
number 31
|
||||
.header
|
||||
string Content-Type
|
||||
.header_low
|
||||
string content-type
|
||||
.value
|
||||
string text/html
|
||||
.pos_start
|
||||
number 17
|
||||
.pos_end
|
||||
number 39
|
||||
.content-length
|
||||
.2
|
||||
.pos_header_end
|
||||
number 54
|
||||
.pos_value_start
|
||||
number 57
|
||||
.header
|
||||
string Content-Length
|
||||
.header_low
|
||||
string content-length
|
||||
.value
|
||||
string 650
|
||||
.pos_start
|
||||
@@ -2928,7 +2965,7 @@ function tls_reconstruct(tdis)
|
||||
Для некоторых элементов заполняется поле "name". Оно служит для удобства визуального анализа и больше ни для чего не используется.
|
||||
Первичными являются поля type.
|
||||
|
||||
Для нахождения значений в списках используйте [функции поиска в массивах](#служебные-функции).
|
||||
Для нахождения значений в списках используйте [функции поиска в массивах](#array_search).
|
||||
|
||||
Множество констант, связанных с TLS, определено в `zapret-lib.lua`. Прежде чем писать фиксированные значения, посмотрите нет ли нужной константы.
|
||||
|
||||
@@ -3319,7 +3356,8 @@ function payload_match_filter(l7payload, l7payload_filter, 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_check вызывает `payload_match_filter(desync.l7payload, desync.arg.payload, def)`
|
||||
@@ -3468,7 +3506,7 @@ nfqws2 ничего не знает о том, что нужно `--lua-desync`
|
||||
|
||||
### standard payload
|
||||
|
||||
Фильтр по пейлоаду берет список типов пейлоада. Список известных типов пейлоада можно получить из help текста nfqws2. Все пустые пакеты имеют пейлоад empty, неизвестные - unknown. Особые значения - all и known. all означает любой пейлоад, known - не unknown и не empty.
|
||||
Фильтр по пейлоаду берет список [типов пейлоада](#распознавание-протоколов).
|
||||
|
||||
**standard payload**
|
||||
|
||||
@@ -3550,6 +3588,7 @@ function http_methodeol(ctx, desync)
|
||||
- arg: [standard direction](#standard-direction)
|
||||
|
||||
Вставляет '\r\n' перед методом, отрезая 2 последних символа из содержимого заголовка `User-Agent:`. Работает только на nginx, остальные сервера ломает.
|
||||
Если используется совместно с другими функциями http тамперинга, должен идти последним.
|
||||
|
||||
### http_unixeol
|
||||
|
||||
@@ -3966,7 +4005,7 @@ function udplen(ctx, desync)
|
||||
- arg: pattern_offset - начальное смещение внутри pattern
|
||||
- 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
|
||||
|
||||
@@ -4048,7 +4087,7 @@ function standard_hostkey(desync)
|
||||
### automate_host_record
|
||||
|
||||
```
|
||||
function automate_conn_record(desync)
|
||||
function automate_host_record(desync)
|
||||
```
|
||||
|
||||
- arg: key - ключ внутри глобальной таблицы autostate. если не задано, в качестве ключа используется имя текущего инстанса
|
||||
@@ -4326,8 +4365,8 @@ ip2net фильтрует входные данные, выкидывая неп
|
||||
```
|
||||
--family=<4|6|46> ; выбор семейства IP адресов : ipv4, ipv6, ipv4+ipv6
|
||||
--threads=<threads_number> ; количество потоков. по умолчанию 1.
|
||||
--eagain=<eagain_retries> ; количество попыток повтора после EAGAIN. по умолчанию 10
|
||||
--eagain-delay=<ms> ; время ожидания в мсек между повторами по EAGAIN. по умолчанию 500.
|
||||
--eagain=<eagain_retries> ; количество попыток повтора после EAI_AGAIN. по умолчанию 10
|
||||
--eagain-delay=<ms> ; время ожидания в мсек между повторами по EAI_AGAIN. по умолчанию 500.
|
||||
--verbose ; дебаг-лог на консоль
|
||||
--stats=N ; выводить статистику каждые N доменов
|
||||
--log-resolved=<file> ; сохранять успешно отресолвленные домены в файл
|
||||
@@ -4668,8 +4707,8 @@ nfqws2 может работать и самостоятельно без скр
|
||||
| IPSET_HOOK | скрипт, который получает имя ipset в $1, выдает в stdout список ip, и они добавляются в ipset |
|
||||
| IP2NET_OPT4<br>IP2NET_OPT6 | настройки ip2net для скриптов получения ip листов |
|
||||
| MDIG_THREADS | количество потоков mdig. используется при ресолвинге хостлистов |
|
||||
| MDIG_EAGAIN | количество попыток при получении EAGAIN |
|
||||
| MDIG_EAGAIN_DELAY | задержка в мсек между попытками при получении EAGAIN |
|
||||
| MDIG_EAGAIN | количество попыток при получении EAI_AGAIN |
|
||||
| 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_DEBUGLOG | включение autohostlist debug log. лог пишется в `ipset/zapret-hosts-auto-debug.log` |
|
||||
| GZIP_LISTS | применять ли сжатие gzip для генерируемых хост и ip листов |
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## English
|
||||
|
||||
[Manual](manual.en.md)
|
||||
|
||||
## Зачем это нужно
|
||||
|
||||
Автономное средство противодействия DPI, которое не требует подключения каких-либо сторонних серверов. Может помочь
|
||||
@@ -11,11 +15,13 @@ VPN. Может использоваться для частичной проз
|
||||
[Полный мануал](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`
|
||||
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
# this custom script demonstrates how to launch extra nfqws instance limited by ipset
|
||||
|
||||
# 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}"
|
||||
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}"
|
||||
NFQWS_MY1_SUBNETS6="${NFQWS_MY1_SUBNETS6:-2a00:1450::/29}"
|
||||
NFQWS_MY1_PORTS_TCP=${NFQWS_MY1_PORTS_TCP:-$NFQWS_PORTS_TCP}
|
||||
NFQWS_MY1_PORTS_UDP=${NFQWS_MY1_PORTS_UDP:-$NFQWS_PORTS_UDP}
|
||||
NFQWS_MY1_TCP_PKT_OUT=${NFQWS_MY1_TCP_PKT_OUT:-$NFQWS_TCP_PKT_OUT}
|
||||
NFQWS_MY1_UDP_PKT_OUT=${NFQWS_MY1_UDP_PKT_OUT:-$NFQWS_UDP_PKT_OUT}
|
||||
NFQWS_MY1_TCP_PKT_IN=${NFQWS_MY1_TCP_PKT_IN:-$NFQWS_TCP_PKT_IN}
|
||||
NFQWS_MY1_UDP_PKT_IN=${NFQWS_MY1_UDP_PKT_IN:-$NFQWS_UDP_PKT_IN}
|
||||
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}"
|
||||
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}"
|
||||
NFQWS2_MY1_SUBNETS6="${NFQWS2_MY1_SUBNETS6:-2a00:1450::/29}"
|
||||
NFQWS2_MY1_PORTS_TCP=${NFQWS2_MY1_PORTS_TCP:-$NFQWS2_PORTS_TCP}
|
||||
NFQWS2_MY1_PORTS_UDP=${NFQWS2_MY1_PORTS_UDP:-$NFQWS2_PORTS_UDP}
|
||||
NFQWS2_MY1_TCP_PKT_OUT=${NFQWS2_MY1_TCP_PKT_OUT:-$NFQWS2_TCP_PKT_OUT}
|
||||
NFQWS2_MY1_UDP_PKT_OUT=${NFQWS2_MY1_UDP_PKT_OUT:-$NFQWS2_UDP_PKT_OUT}
|
||||
NFQWS2_MY1_TCP_PKT_IN=${NFQWS2_MY1_TCP_PKT_IN:-$NFQWS2_TCP_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}
|
||||
NFQWS_MY1_IPSET_OPT="${NFQWS_MY1_IPSET_OPT:-hash:net hashsize 8192 maxelem $NFQWS_MY1_IPSET_SIZE}"
|
||||
NFQWS2_MY1_IPSET_SIZE=${NFQWS2_MY1_IPSET_SIZE:-4096}
|
||||
NFQWS2_MY1_IPSET_OPT="${NFQWS2_MY1_IPSET_OPT:-hash:net hashsize 8192 maxelem $NFQWS2_MY1_IPSET_SIZE}"
|
||||
|
||||
alloc_dnum DNUM_NFQWS_MY1
|
||||
alloc_qnum QNUM_NFQWS_MY1
|
||||
NFQWS_MY1_NAME4=my1nfqws4
|
||||
NFQWS_MY1_NAME6=my1nfqws6
|
||||
alloc_dnum DNUM_NFQWS2_MY1
|
||||
alloc_qnum QNUM_NFQWS2_MY1
|
||||
NFQWS2_MY1_NAME4=my1nfqws4
|
||||
NFQWS2_MY1_NAME6=my1nfqws6
|
||||
|
||||
zapret_custom_daemons()
|
||||
{
|
||||
# $1 - 1 - run, 0 - stop
|
||||
|
||||
local opt="--qnum=$QNUM_NFQWS_MY1 $NFQWS_MY1_OPT"
|
||||
do_nfqws $1 $DNUM_NFQWS_MY1 "$opt"
|
||||
local opt="--qnum=$QNUM_NFQWS2_MY1 $NFQWS2_MY1_OPT"
|
||||
do_nfqws $1 $DNUM_NFQWS2_MY1 "$opt"
|
||||
}
|
||||
|
||||
zapret_custom_firewall()
|
||||
@@ -32,103 +32,103 @@ zapret_custom_firewall()
|
||||
# $1 - 1 - run, 0 - stop
|
||||
|
||||
local f4 f6 subnet
|
||||
local NFQWS_MY1_PORTS_TCP=$(replace_char - : $NFQWS_MY1_PORTS_TCP)
|
||||
local NFQWS_MY1_PORTS_UDP=$(replace_char - : $NFQWS_MY1_PORTS_UDP)
|
||||
local NFQWS2_MY1_PORTS_TCP=$(replace_char - : $NFQWS2_MY1_PORTS_TCP)
|
||||
local NFQWS2_MY1_PORTS_UDP=$(replace_char - : $NFQWS2_MY1_PORTS_UDP)
|
||||
|
||||
[ "$1" = 1 -a "$DISABLE_IPV4" != 1 ] && {
|
||||
ipset create $NFQWS_MY1_NAME4 $NFQWS_MY1_IPSET_OPT family inet 2>/dev/null
|
||||
ipset flush $NFQWS_MY1_NAME4
|
||||
for subnet in $NFQWS_MY1_SUBNETS4; do
|
||||
echo add $NFQWS_MY1_NAME4 $subnet
|
||||
ipset create $NFQWS2_MY1_NAME4 $NFQWS2_MY1_IPSET_OPT family inet 2>/dev/null
|
||||
ipset flush $NFQWS2_MY1_NAME4
|
||||
for subnet in $NFQWS2_MY1_SUBNETS4; do
|
||||
echo add $NFQWS2_MY1_NAME4 $subnet
|
||||
done | ipset -! restore
|
||||
}
|
||||
[ "$1" = 1 -a "$DISABLE_IPV6" != 1 ] && {
|
||||
ipset create $NFQWS_MY1_NAME6 $NFQWS_MY1_IPSET_OPT family inet6 2>/dev/null
|
||||
ipset flush $NFQWS_MY1_NAME6
|
||||
for subnet in $NFQWS_MY1_SUBNETS6; do
|
||||
echo add $NFQWS_MY1_NAME6 $subnet
|
||||
ipset create $NFQWS2_MY1_NAME6 $NFQWS2_MY1_IPSET_OPT family inet6 2>/dev/null
|
||||
ipset flush $NFQWS2_MY1_NAME6
|
||||
for subnet in $NFQWS2_MY1_SUBNETS6; do
|
||||
echo add $NFQWS2_MY1_NAME6 $subnet
|
||||
done | ipset -! restore
|
||||
}
|
||||
|
||||
[ -n "$NFQWS_MY1_PORTS_TCP" ] && {
|
||||
[ -n "$NFQWS_MY1_TCP_PKT_OUT" -a "$NFQWS_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"
|
||||
f6="$f4 $NFQWS_MY1_NAME6 dst"
|
||||
f4="$f4 $NFQWS_MY1_NAME4 dst"
|
||||
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_PORTS_TCP" ] && {
|
||||
[ -n "$NFQWS2_MY1_TCP_PKT_OUT" -a "$NFQWS2_MY1_TCP_PKT_OUT" != 0 ] && {
|
||||
f4="-p tcp -m multiport --dports $NFQWS2_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS2_MY1_TCP_PKT_OUT -m set --match-set"
|
||||
f6="$f4 $NFQWS2_MY1_NAME6 dst"
|
||||
f4="$f4 $NFQWS2_MY1_NAME4 dst"
|
||||
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
[ -n "$NFQWS_MY1_TCP_PKT_IN" -a "$NFQWS_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"
|
||||
f6="$f4 $NFQWS_MY1_NAME6 src"
|
||||
f4="$f4 $NFQWS_MY1_NAME4 src"
|
||||
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_TCP_PKT_IN" -a "$NFQWS2_MY1_TCP_PKT_IN" != 0 ] && {
|
||||
f4="-p tcp -m multiport --sports $NFQWS2_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS2_MY1_TCP_PKT_IN -m set --match-set"
|
||||
f6="$f4 $NFQWS2_MY1_NAME6 src"
|
||||
f4="$f4 $NFQWS2_MY1_NAME4 src"
|
||||
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
}
|
||||
[ -n "$NFQWS_MY1_PORTS_UDP" ] && {
|
||||
[ -n "$NFQWS_MY1_UDP_PKT_OUT" -a "$NFQWS_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"
|
||||
f6="$f4 $NFQWS_MY1_NAME6 dst"
|
||||
f4="$f4 $NFQWS_MY1_NAME4 dst"
|
||||
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_PORTS_UDP" ] && {
|
||||
[ -n "$NFQWS2_MY1_UDP_PKT_OUT" -a "$NFQWS2_MY1_UDP_PKT_OUT" != 0 ] && {
|
||||
f4="-p udp -m multiport --dports $NFQWS2_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS2_MY1_UDP_PKT_OUT -m set --match-set"
|
||||
f6="$f4 $NFQWS2_MY1_NAME6 dst"
|
||||
f4="$f4 $NFQWS2_MY1_NAME4 dst"
|
||||
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
[ -n "$NFQWS_MY1_UDP_PKT_IN" -a "$NFQWS_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"
|
||||
f6="$f4 $NFQWS_MY1_NAME6 src"
|
||||
f4="$f4 $NFQWS_MY1_NAME4 src"
|
||||
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_UDP_PKT_IN" -a "$NFQWS2_MY1_UDP_PKT_IN" != 0 ] && {
|
||||
f4="-p udp -m multiport --sports $NFQWS2_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS2_MY1_UDP_PKT_IN -m set --match-set"
|
||||
f6="$f4 $NFQWS2_MY1_NAME6 src"
|
||||
f4="$f4 $NFQWS2_MY1_NAME4 src"
|
||||
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
}
|
||||
|
||||
[ "$1" = 1 ] || {
|
||||
ipset destroy $NFQWS_MY1_NAME4 2>/dev/null
|
||||
ipset destroy $NFQWS_MY1_NAME6 2>/dev/null
|
||||
ipset destroy $NFQWS2_MY1_NAME4 2>/dev/null
|
||||
ipset destroy $NFQWS2_MY1_NAME6 2>/dev/null
|
||||
}
|
||||
}
|
||||
|
||||
zapret_custom_firewall_nft()
|
||||
{
|
||||
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 ] && {
|
||||
make_comma_list subnets $NFQWS_MY1_SUBNETS4
|
||||
nft_create_set $NFQWS_MY1_NAME4 "type ipv4_addr; size $NFQWS_MY1_IPSET_SIZE; auto-merge; flags interval;"
|
||||
nft_flush_set $NFQWS_MY1_NAME4
|
||||
nft_add_set_element $NFQWS_MY1_NAME4 "$subnets"
|
||||
make_comma_list subnets $NFQWS2_MY1_SUBNETS4
|
||||
nft_create_set $NFQWS2_MY1_NAME4 "type ipv4_addr; size $NFQWS2_MY1_IPSET_SIZE; auto-merge; flags interval;"
|
||||
nft_flush_set $NFQWS2_MY1_NAME4
|
||||
nft_add_set_element $NFQWS2_MY1_NAME4 "$subnets"
|
||||
}
|
||||
[ "$DISABLE_IPV6" != 1 ] && {
|
||||
make_comma_list subnets $NFQWS_MY1_SUBNETS6
|
||||
nft_create_set $NFQWS_MY1_NAME6 "type ipv6_addr; size $NFQWS_MY1_IPSET_SIZE; auto-merge; flags interval;"
|
||||
nft_flush_set $NFQWS_MY1_NAME6
|
||||
nft_add_set_element $NFQWS_MY1_NAME6 "$subnets"
|
||||
make_comma_list subnets $NFQWS2_MY1_SUBNETS6
|
||||
nft_create_set $NFQWS2_MY1_NAME6 "type ipv6_addr; size $NFQWS2_MY1_IPSET_SIZE; auto-merge; flags interval;"
|
||||
nft_flush_set $NFQWS2_MY1_NAME6
|
||||
nft_add_set_element $NFQWS2_MY1_NAME6 "$subnets"
|
||||
}
|
||||
|
||||
[ -n "$NFQWS_MY1_PORTS_TCP" ] && {
|
||||
[ -n "$NFQWS_MY1_TCP_PKT_OUT" -a "$NFQWS_MY1_TCP_PKT_OUT" != 0 ] && {
|
||||
f4="tcp dport {$NFQWS_MY1_PORTS_TCP} $(nft_first_packets $NFQWS_MY1_TCP_PKT_OUT)"
|
||||
f6="$f4 ip6 daddr @$NFQWS_MY1_NAME6"
|
||||
f4="$f4 ip daddr @$NFQWS_MY1_NAME4"
|
||||
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_PORTS_TCP" ] && {
|
||||
[ -n "$NFQWS2_MY1_TCP_PKT_OUT" -a "$NFQWS2_MY1_TCP_PKT_OUT" != 0 ] && {
|
||||
f4="tcp dport {$NFQWS2_MY1_PORTS_TCP} $(nft_first_packets $NFQWS2_MY1_TCP_PKT_OUT)"
|
||||
f6="$f4 ip6 daddr @$NFQWS2_MY1_NAME6"
|
||||
f4="$f4 ip daddr @$NFQWS2_MY1_NAME4"
|
||||
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
[ -n "$NFQWS_MY1_TCP_PKT_IN" -a "$NFQWS_MY1_TCP_PKT_IN" != 0 ] && {
|
||||
f4="tcp sport {$NFQWS_MY1_PORTS_TCP} $(nft_first_packets $NFQWS_MY1_TCP_PKT_IN)"
|
||||
f6="$f4 ip6 saddr @$NFQWS_MY1_NAME6"
|
||||
f4="$f4 ip saddr @$NFQWS_MY1_NAME4"
|
||||
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_TCP_PKT_IN" -a "$NFQWS2_MY1_TCP_PKT_IN" != 0 ] && {
|
||||
f4="tcp sport {$NFQWS2_MY1_PORTS_TCP} $(nft_first_packets $NFQWS2_MY1_TCP_PKT_IN)"
|
||||
f6="$f4 ip6 saddr @$NFQWS2_MY1_NAME6"
|
||||
f4="$f4 ip saddr @$NFQWS2_MY1_NAME4"
|
||||
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
}
|
||||
[ -n "$NFQWS_MY1_PORTS_UDP" ] && {
|
||||
[ -n "$NFQWS_MY1_UDP_PKT_OUT" -a "$NFQWS_MY1_UDP_PKT_OUT" != 0 ] && {
|
||||
f4="udp dport {$NFQWS_MY1_PORTS_UDP} $(nft_first_packets $NFQWS_MY1_UDP_PKT_OUT)"
|
||||
f6="$f4 ip6 daddr @$NFQWS_MY1_NAME6"
|
||||
f4="$f4 ip daddr @$NFQWS_MY1_NAME4"
|
||||
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_PORTS_UDP" ] && {
|
||||
[ -n "$NFQWS2_MY1_UDP_PKT_OUT" -a "$NFQWS2_MY1_UDP_PKT_OUT" != 0 ] && {
|
||||
f4="udp dport {$NFQWS2_MY1_PORTS_UDP} $(nft_first_packets $NFQWS2_MY1_UDP_PKT_OUT)"
|
||||
f6="$f4 ip6 daddr @$NFQWS2_MY1_NAME6"
|
||||
f4="$f4 ip daddr @$NFQWS2_MY1_NAME4"
|
||||
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
|
||||
}
|
||||
[ -n "$NFQWS_MY1_UDP_PKT_IN" -a "$NFQWS_MY1_UDP_PKT_IN" != 0 ] && {
|
||||
f4="udp sport {$NFQWS_MY1_PORTS_UDP} $(nft_first_packets $NFQWS_MY1_UDP_PKT_IN)"
|
||||
f6="$f4 ip6 saddr @$NFQWS_MY1_NAME6"
|
||||
f4="$f4 ip saddr @$NFQWS_MY1_NAME4"
|
||||
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
|
||||
[ -n "$NFQWS2_MY1_UDP_PKT_IN" -a "$NFQWS2_MY1_UDP_PKT_IN" != 0 ] && {
|
||||
f4="udp sport {$NFQWS2_MY1_PORTS_UDP} $(nft_first_packets $NFQWS2_MY1_UDP_PKT_IN)"
|
||||
f6="$f4 ip6 saddr @$NFQWS2_MY1_NAME6"
|
||||
f4="$f4 ip saddr @$NFQWS2_MY1_NAME4"
|
||||
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
|
||||
# however sets are not deleted. it's desired to clear sets here.
|
||||
|
||||
nft_del_set $NFQWS_MY1_NAME4 2>/dev/null
|
||||
nft_del_set $NFQWS_MY1_NAME6 2>/dev/null
|
||||
nft_del_set $NFQWS2_MY1_NAME4 2>/dev/null
|
||||
nft_del_set $NFQWS2_MY1_NAME6 2>/dev/null
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
udp.PayloadLength=148 and udp.Payload[0]=0x01 or
|
||||
udp.PayloadLength=92 and udp.Payload[0]=0x02 or
|
||||
udp.PayloadLength=64 and udp.Payload[0]=0x03
|
||||
udp.PayloadLength=148 and udp.Payload32[0]=0x01000000 or
|
||||
udp.PayloadLength=92 and udp.Payload32[0]=0x02000000 or
|
||||
udp.PayloadLength=64 and udp.Payload32[0]=0x03000000
|
||||
|
||||
@@ -149,12 +149,17 @@ function http_hostcase(ctx, desync)
|
||||
error("http_hostcase: invalid host spelling '"..spell.."'")
|
||||
else
|
||||
local hdis = http_dissect_req(desync.dis.payload)
|
||||
if hdis.headers.host then
|
||||
DLOG("http_hostcase: 'Host:' => '"..spell.."'")
|
||||
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)
|
||||
return VERDICT_MODIFY
|
||||
if hdis then
|
||||
local idx_host = array_field_search(hdis.headers, "header_low", "host")
|
||||
if idx_host then
|
||||
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
|
||||
DLOG("http_hostcase: 'Host:' header not found")
|
||||
DLOG("http_hostcase: http dissect error")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -162,6 +167,7 @@ end
|
||||
|
||||
-- nfqws1 : "--methodeol"
|
||||
-- standard args : direction
|
||||
-- NOTE : if using with other http tampering methodeol should be the last !
|
||||
function http_methodeol(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
@@ -170,17 +176,22 @@ function http_methodeol(ctx, desync)
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
if desync.l7payload=="http_req" and direction_check(desync) then
|
||||
local hdis = http_dissect_req(desync.dis.payload)
|
||||
local ua = hdis.headers["user-agent"]
|
||||
if ua then
|
||||
if (ua.pos_end - ua.pos_value_start) < 2 then
|
||||
DLOG("http_methodeol: 'User-Agent:' header is too short")
|
||||
if hdis then
|
||||
local idx_ua = array_field_search(hdis.headers, "header_low", "user-agent")
|
||||
if idx_ua then
|
||||
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
|
||||
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
|
||||
DLOG("http_methodeol: 'User-Agent:' header not found")
|
||||
end
|
||||
else
|
||||
DLOG("http_methodeol: 'User-Agent:' header not found")
|
||||
DLOG("http_methodeol: http dissect error")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -197,10 +208,11 @@ function http_unixeol(ctx, desync)
|
||||
if desync.l7payload=="http_req" and direction_check(desync) then
|
||||
local hdis = http_dissect_req(desync.dis.payload)
|
||||
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)
|
||||
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
|
||||
local http = http_reconstruct_req(hdis, true)
|
||||
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)
|
||||
end
|
||||
else
|
||||
DLOG("http_unixeol: user-agent header absent")
|
||||
DLOG("http_unixeol: 'User-Agent:' header absent")
|
||||
end
|
||||
else
|
||||
DLOG("http_unixeol: could not dissect http")
|
||||
|
||||
@@ -569,7 +569,6 @@ function array_search(a, v)
|
||||
return k
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
-- linear search array a for a[index].f==v. return index
|
||||
function array_field_search(a, f, v)
|
||||
@@ -578,7 +577,6 @@ function array_field_search(a, f, v)
|
||||
return k
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- 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
|
||||
header,value,pos_endheader,pos_startvalue = http_dissect_header(header)
|
||||
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
|
||||
pos=pnext
|
||||
end
|
||||
@@ -1609,11 +1607,16 @@ function http_dissect_reply(http)
|
||||
code = tonumber(string.sub(http,10,pos-1))
|
||||
if not code then return nil end
|
||||
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
|
||||
function http_reconstruct_headers(headers, unixeol)
|
||||
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
|
||||
function http_reconstruct_req(hdis, unixeol)
|
||||
local eol = unixeol and "\n" or "\r\n"
|
||||
|
||||
@@ -455,8 +455,8 @@ static void exithelp(void)
|
||||
printf(
|
||||
" --family=<4|6|46>\t\t; ipv4, ipv6, ipv4+ipv6\n"
|
||||
" --threads=<threads_number>\n"
|
||||
" --eagain=<eagain_retries>\t; how many times to retry if EAGAIN received. default %u\n"
|
||||
" --eagain-delay=<ms>\t\t; time in msec to wait between EAGAIN attempts. 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 EAI_AGAIN attempts. default %u\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"
|
||||
" --log-resolved=<file>\t\t; log successfully resolved domains to a file\n"
|
||||
|
||||
@@ -622,7 +622,7 @@ BOOL LowMandatoryLevel(void)
|
||||
|
||||
label_low.Label.Sid = (PSID)buf1;
|
||||
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;
|
||||
|
||||
// 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;
|
||||
return true;
|
||||
}
|
||||
bool win_dark_deinit(void)
|
||||
void win_dark_deinit(void)
|
||||
{
|
||||
if (pNetworkListManager)
|
||||
{
|
||||
@@ -997,11 +997,12 @@ bool nlm_list(bool bAll)
|
||||
}
|
||||
else
|
||||
bRet = false;
|
||||
|
||||
CoUninitialize();
|
||||
}
|
||||
else
|
||||
bRet = false;
|
||||
|
||||
CoUninitialize();
|
||||
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,
|
||||
NULL, w_win32_error, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPSTR)&errormessage, 0, NULL);
|
||||
DLOG_ERR("windivert: error opening filter: %s", errormessage);
|
||||
LocalFree(errormessage);
|
||||
if (errormessage)
|
||||
{
|
||||
DLOG_ERR("windivert: error opening filter: %s", errormessage);
|
||||
LocalFree(errormessage);
|
||||
}
|
||||
if (w_win32_error == ERROR_INVALID_IMAGE_HASH)
|
||||
DLOG_ERR("windivert: try to disable secure boot and install OS patches\n");
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ bool ensure_dir_access(const char *filename);
|
||||
bool prepare_low_appdata();
|
||||
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_deinit(void);
|
||||
void win_dark_deinit(void);
|
||||
bool logical_net_filter_present(void);
|
||||
bool logical_net_filter_match(void);
|
||||
bool nlm_list(bool bAll);
|
||||
|
||||
127
nfq2/desync.c
127
nfq2/desync.c
@@ -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++)
|
||||
{
|
||||
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;
|
||||
if (*l7proto == L7_UNKNOWN)
|
||||
@@ -753,7 +753,6 @@ static uint8_t desync(
|
||||
struct func_list *func;
|
||||
int ref_arg = LUA_NOREF, status;
|
||||
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";
|
||||
struct packet_range *range;
|
||||
size_t l;
|
||||
@@ -782,13 +781,24 @@ static uint8_t 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;
|
||||
ctx.func_n = 1;
|
||||
ctx->func_n = 1;
|
||||
LIST_FOREACH(func, &dp->lua_desync, next)
|
||||
{
|
||||
ctx.func = func->func;
|
||||
desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance));
|
||||
ctx.instance = instance;
|
||||
ctx->func = func->func;
|
||||
desync_instance(func->func, dp->n, ctx->func_n, instance, sizeof(instance));
|
||||
ctx->instance = instance;
|
||||
range = bIncoming ? &func->range_in : &func->range_out;
|
||||
|
||||
if (b_unwanted_payload)
|
||||
@@ -796,7 +806,7 @@ static uint8_t desync(
|
||||
|
||||
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);
|
||||
else if (check_pos_cutoff(pos, range))
|
||||
{
|
||||
@@ -814,7 +824,7 @@ static uint8_t desync(
|
||||
else
|
||||
b_cutoff_all = false;
|
||||
}
|
||||
ctx.func_n++;
|
||||
ctx->func_n++;
|
||||
}
|
||||
if (b_cutoff_all)
|
||||
{
|
||||
@@ -867,14 +877,14 @@ static uint8_t desync(
|
||||
}
|
||||
ref_arg = luaL_ref(params.L, LUA_REGISTRYINDEX);
|
||||
|
||||
ctx.func_n = 1;
|
||||
ctx->func_n = 1;
|
||||
LIST_FOREACH(func, &dp->lua_desync, next)
|
||||
{
|
||||
ctx.func = func->func;
|
||||
desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance));
|
||||
ctx.instance = instance;
|
||||
ctx->func = func->func;
|
||||
desync_instance(func->func, dp->n, ctx->func_n, instance, sizeof(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;
|
||||
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);
|
||||
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_pushf_args(params.L, &func->args, -1, true);
|
||||
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 should not store and access ctx outside of this call
|
||||
// if this happens make our best to prevent access to bad memory
|
||||
// this is not crash-proof but better than nothing
|
||||
ctx.magic = MAGIC_CTX; // mark struct as valid
|
||||
// prevent use of desync ctx object outside of function call
|
||||
ctx->valid = true;
|
||||
status = lua_pcall(params.L, 2, LUA_MULTRET, 0);
|
||||
ctx.magic = 0; // mark struct as invalid
|
||||
ctx->valid = false;
|
||||
|
||||
if (status)
|
||||
{
|
||||
@@ -939,8 +947,8 @@ static uint8_t desync(
|
||||
range->upper_cutoff ? '<' : '-',
|
||||
range->to.mode, range->to.pos);
|
||||
}
|
||||
if (ctx.cancel) break;
|
||||
ctx.func_n++;
|
||||
if (ctx->cancel) break;
|
||||
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
|
||||
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);
|
||||
ifname = bReverse ? ifin : ifout;
|
||||
#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);
|
||||
|
||||
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");
|
||||
l7payload = L7P_HTTP_REQ;
|
||||
if (l7proto == L7_UNKNOWN)
|
||||
t_protocol_probe testers[] = {
|
||||
{L7P_TLS_CLIENT_HELLO,L7_TLS,IsTLSClientHelloPartial},
|
||||
{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;
|
||||
if (ctrack && ctrack->l7proto == L7_UNKNOWN) ctrack->l7proto = l7proto;
|
||||
// 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->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
|
||||
reasm_client_cancel(ctrack);
|
||||
|
||||
if (l7payload==L7P_HTTP_REQ)
|
||||
{
|
||||
bHaveHost = HttpExtractHost(rdata_payload, rlen_payload, host, sizeof(host));
|
||||
if (!bHaveHost)
|
||||
{
|
||||
@@ -1292,21 +1313,17 @@ static uint8_t dpi_desync_tcp_packet_play(
|
||||
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;
|
||||
if (l7proto == L7_UNKNOWN)
|
||||
{
|
||||
l7proto = L7_TLS;
|
||||
if (ctrack && ctrack->l7proto == L7_UNKNOWN) ctrack->l7proto = l7proto;
|
||||
}
|
||||
|
||||
bool bReqFull = IsTLSRecordFull(rdata_payload, rlen_payload);
|
||||
DLOG(bReqFull ? "TLS client hello is FULL\n" : "TLS client hello is PARTIAL\n");
|
||||
|
||||
if (bReqFull) TLSDebug(rdata_payload, rlen_payload);
|
||||
|
||||
bHaveHost = TLSHelloExtractHost(rdata_payload, rlen_payload, host, sizeof(host), TLS_PARTIALS_ENABLE);
|
||||
if (ctrack && !(params.reasm_payload_disable && l7_payload_match(l7payload, params.reasm_payload_disable)))
|
||||
bHaveHost = TLSHelloExtractHost(rdata_payload, rlen_payload, host, sizeof(host), true);
|
||||
if (ctrack && !l7_payload_match(l7payload, params.reasm_payload_disable))
|
||||
{
|
||||
// do not reasm retransmissions
|
||||
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)
|
||||
@@ -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
|
||||
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);
|
||||
|
||||
ifname = bReverse ? ifin : ifout;
|
||||
@@ -1756,7 +1753,7 @@ static uint8_t dpi_desync_udp_packet_play(
|
||||
}
|
||||
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 (ReasmHasSpace(&ctrack->reasm_client, clean_len))
|
||||
@@ -1818,7 +1815,7 @@ static uint8_t dpi_desync_udp_packet_play(
|
||||
{
|
||||
data_decrypt = defrag + hello_offset;
|
||||
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
|
||||
{
|
||||
|
||||
@@ -31,7 +31,12 @@ int z_readfile(FILE *F, char **buf, size_t *size, size_t extra_alloc)
|
||||
r = Z_ERRNO;
|
||||
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;
|
||||
do
|
||||
{
|
||||
|
||||
@@ -396,16 +396,16 @@ void phton64(uint8_t *p, uint64_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
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -66,9 +66,9 @@ void phton48(uint8_t *p, uint64_t v);
|
||||
uint64_t pntoh64(const uint8_t *p);
|
||||
void phton64(uint8_t *p, uint64_t v);
|
||||
|
||||
uint16_t swap16(uint16_t u);
|
||||
uint32_t swap24(uint32_t u);
|
||||
uint64_t swap48(uint64_t u);
|
||||
uint16_t bswap16(uint16_t u);
|
||||
uint32_t bswap24(uint32_t u);
|
||||
uint64_t bswap48(uint64_t u);
|
||||
|
||||
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size);
|
||||
char hex_digit(uint8_t v);
|
||||
|
||||
@@ -79,7 +79,7 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename)
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG_ERR("zlib decompression failed : result %d\n",r);
|
||||
DLOG_ERR("zlib decompression failed : result %d\n", r);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "helpers.h"
|
||||
|
||||
|
||||
// inplace tolower() and add to pool
|
||||
static bool addpool(ipset *ips, char **s, const char *end, int *ct)
|
||||
{
|
||||
char *p, cidr[128];
|
||||
|
||||
113
nfq2/lua.c
113
nfq2/lua.c
@@ -279,7 +279,7 @@ static int luacall_swap16(lua_State *L)
|
||||
int64_t i = (int64_t)luaL_checklint(L,1);
|
||||
if (i>0xFFFF || i<-(int64_t)0xFFFF) luaL_error(L, "out of range");
|
||||
uint16_t u = (uint16_t)i;
|
||||
lua_pushinteger(L,swap16(u));
|
||||
lua_pushinteger(L,bswap16(u));
|
||||
return 1;
|
||||
}
|
||||
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);
|
||||
if (i>0xFFFFFF || i<-(int64_t)0xFFFFFF) luaL_error(L, "out of range");
|
||||
uint32_t u = (uint32_t)i;
|
||||
lua_pushlint(L,swap24(u));
|
||||
lua_pushlint(L,bswap24(u));
|
||||
return 1;
|
||||
}
|
||||
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);
|
||||
if (i>0xFFFFFFFFFFFF || i<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
|
||||
uint64_t u = (uint64_t)i;
|
||||
lua_pushlint(L, swap48(u));
|
||||
lua_pushlint(L, bswap48(u));
|
||||
return 1;
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (lua_isnil(L,1))
|
||||
luaL_error(L, "missing ctx");
|
||||
if (!lua_islightuserdata(L,1))
|
||||
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");
|
||||
|
||||
if (lua_isnil(L,1)) luaL_error(L, "missing ctx");
|
||||
t_lua_desync_context *ctx = (t_lua_desync_context *)luaL_checkudata(L, 1, "desync_ctx");
|
||||
if (!ctx->valid) luaL_error(L, "ctx is invalid");
|
||||
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)
|
||||
{
|
||||
@@ -911,24 +932,55 @@ static int luacall_execution_plan(lua_State *L)
|
||||
lua_newtable(L);
|
||||
|
||||
struct func_list *func;
|
||||
char instance[256], pls[2048];
|
||||
char instance[256], plsl[2048];
|
||||
struct packet_range *range;
|
||||
unsigned int n=1;
|
||||
t_l7payload pl;
|
||||
const char *pls;
|
||||
|
||||
LIST_FOREACH(func, &ctx->dp->lua_desync, next)
|
||||
{
|
||||
if (n > ctx->func_n)
|
||||
{
|
||||
desync_instance(func->func, ctx->dp->n, n, instance, sizeof(instance));
|
||||
range = ctx->incoming ? &func->range_in : &func->range_out;
|
||||
|
||||
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_str(L,"func", func->func);
|
||||
lua_pushf_int(L,"func_n", ctx->func_n);
|
||||
lua_pushf_str(L,"func_instance", instance);
|
||||
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
|
||||
lua_pushf_nil(L,"payload_filter");
|
||||
|
||||
@@ -2159,8 +2211,9 @@ static int luacall_reconstruct_dissect(lua_State *L)
|
||||
|
||||
LUA_STACK_GUARD_ENTER(L)
|
||||
|
||||
size_t l;
|
||||
uint8_t buf[RECONSTRUCT_MAX_SIZE];
|
||||
size_t l = sizeof(buf);
|
||||
l = sizeof(buf);
|
||||
|
||||
bool ip6_preserve_next, badsum;
|
||||
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)
|
||||
|
||||
uint8_t buf[RECONSTRUCT_MAX_SIZE];
|
||||
size_t len=sizeof(buf);
|
||||
size_t len;
|
||||
const char *ifout;
|
||||
int repeats;
|
||||
uint32_t fwmark;
|
||||
sockaddr_in46 sa;
|
||||
bool b, badsum, ip6_preserve_next;
|
||||
uint8_t buf[RECONSTRUCT_MAX_SIZE];
|
||||
len = sizeof(buf);
|
||||
|
||||
luaL_checktype(L,1,LUA_TTABLE);
|
||||
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(¶ms.conntrack);
|
||||
}
|
||||
|
||||
void lua_shutdown()
|
||||
{
|
||||
if (params.L)
|
||||
{
|
||||
DLOG("LUA SHUTDOWN\n");
|
||||
// conntrack holds lua state. must clear it before lua shoudown
|
||||
ConntrackPoolDestroy(¶ms.conntrack);
|
||||
lua_cleanup(params.L);
|
||||
lua_close(params.L);
|
||||
params.L=NULL;
|
||||
}
|
||||
@@ -3031,7 +3090,7 @@ static int luaL_doZfile(lua_State *L, const char *filename)
|
||||
return r;
|
||||
}
|
||||
else
|
||||
return luaL_dofile(L, filename);
|
||||
return luaL_dofile(L, fname);
|
||||
}
|
||||
|
||||
static bool lua_init_scripts(void)
|
||||
@@ -3394,6 +3453,8 @@ static void lua_init_functions(void)
|
||||
static void lua_init_mt()
|
||||
{
|
||||
lua_mt_init_zstream(params.L);
|
||||
lua_mt_init_desync_ctx(params.L);
|
||||
lua_desync_ctx_create(params.L);
|
||||
}
|
||||
|
||||
bool lua_init(void)
|
||||
@@ -3401,6 +3462,9 @@ bool lua_init(void)
|
||||
DLOG("\nLUA INIT\n");
|
||||
|
||||
if (!lua_basic_init()) return false;
|
||||
|
||||
LUA_STACK_GUARD_ENTER(params.L)
|
||||
|
||||
lua_sec_harden();
|
||||
lua_init_blobs();
|
||||
lua_init_const();
|
||||
@@ -3409,10 +3473,11 @@ bool lua_init(void)
|
||||
if (!lua_init_scripts()) goto err;
|
||||
if (!lua_desync_functions_exist()) goto err;
|
||||
|
||||
LUA_STACK_GUARD_LEAVE(params.L,0)
|
||||
DLOG("LUA INIT DONE\n\n");
|
||||
|
||||
return true;
|
||||
err:
|
||||
LUA_STACK_GUARD_LEAVE(params.L,0)
|
||||
lua_shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -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_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, bool badsum, bool ip6_preserve_next);
|
||||
|
||||
#define MAGIC_CTX 0xE73DC935
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
unsigned int func_n;
|
||||
const char *func, *instance;
|
||||
const struct desync_profile *dp;
|
||||
const struct dissect *dis;
|
||||
t_ctrack *ctrack;
|
||||
bool incoming,cancel;
|
||||
bool incoming, cancel;
|
||||
bool valid;
|
||||
} t_lua_desync_context;
|
||||
|
||||
bool lua_instance_cutoff_check(lua_State *L, const t_lua_desync_context *ctx, bool bIn);
|
||||
|
||||
161
nfq2/nfqws.c
161
nfq2/nfqws.c
@@ -52,9 +52,7 @@
|
||||
|
||||
struct params_s params;
|
||||
static volatile sig_atomic_t bReload = false;
|
||||
#ifdef __CYGWIN__
|
||||
bool bQuit = false;
|
||||
#endif
|
||||
|
||||
static void onhup(int sig)
|
||||
{
|
||||
@@ -102,12 +100,37 @@ static void onusr2(int sig)
|
||||
ipcachePrint(¶ms.ipcache);
|
||||
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)
|
||||
{
|
||||
signal(SIGHUP, onhup);
|
||||
signal(SIGUSR1, onusr1);
|
||||
signal(SIGUSR2, onusr2);
|
||||
struct sigaction sa;
|
||||
|
||||
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;
|
||||
uint32_t ifidx_out, ifidx_in;
|
||||
char ifout[IFNAMSIZ], ifin[IFNAMSIZ];
|
||||
uint8_t mod[RECONSTRUCT_MAX_SIZE];
|
||||
size_t modlen;
|
||||
uint32_t mark;
|
||||
uint8_t mod[RECONSTRUCT_MAX_SIZE];
|
||||
|
||||
ph = nfq_get_msg_packet_hdr(nfa);
|
||||
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);
|
||||
|
||||
ifidx_out = nfq_get_outdev(nfa);
|
||||
@@ -282,12 +306,12 @@ static void notify_ready(void)
|
||||
|
||||
static int nfq_main(void)
|
||||
{
|
||||
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned));
|
||||
struct nfq_handle *h = NULL;
|
||||
struct nfq_q_handle *qh = NULL;
|
||||
int res, fd, e;
|
||||
ssize_t rd;
|
||||
FILE *Fpid = NULL;
|
||||
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned));
|
||||
|
||||
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)
|
||||
{
|
||||
if (bQuit) goto quit;
|
||||
ReloadCheck();
|
||||
lua_do_gc();
|
||||
#ifdef HAS_FILTER_SSID
|
||||
@@ -363,6 +388,11 @@ static int nfq_main(void)
|
||||
else
|
||||
DLOG("recv from nfq returned 0 !\n");
|
||||
}
|
||||
if (errno==EINTR)
|
||||
{
|
||||
if (bQuit) goto quit;
|
||||
continue;
|
||||
}
|
||||
e = errno;
|
||||
DLOG_ERR("recv: recv=%zd errno %d\n", rd, e);
|
||||
errno = e;
|
||||
@@ -370,6 +400,7 @@ static int nfq_main(void)
|
||||
// do not fail on ENOBUFS
|
||||
} while (e == ENOBUFS);
|
||||
|
||||
exok:
|
||||
res=0;
|
||||
ex:
|
||||
nfq_deinit(&h, &qh);
|
||||
@@ -383,13 +414,15 @@ err:
|
||||
if (Fpid) fclose(Fpid);
|
||||
res=1;
|
||||
goto ex;
|
||||
quit:
|
||||
DLOG_CONDUP("quit requested\n");
|
||||
goto exok;
|
||||
}
|
||||
|
||||
#elif defined(BSD)
|
||||
|
||||
static int dvt_main(void)
|
||||
{
|
||||
uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned));
|
||||
struct sockaddr_storage sa_from;
|
||||
int fd[2] = { -1,-1 }; // 4,6
|
||||
int i, r, res = 1, fdct = 1, fdmax;
|
||||
@@ -398,6 +431,9 @@ static int dvt_main(void)
|
||||
ssize_t rd, wr;
|
||||
fd_set fdset;
|
||||
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")))
|
||||
{
|
||||
@@ -405,49 +441,42 @@ static int dvt_main(void)
|
||||
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;
|
||||
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)
|
||||
{
|
||||
DLOG_PERROR("bind (DIVERT4)");
|
||||
goto exiterr;
|
||||
}
|
||||
DLOG_PERROR("bind (DIVERT4)");
|
||||
goto exiterr;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
{
|
||||
// in OpenBSD must use separate divert sockets for ipv4 and ipv6
|
||||
struct sockaddr_in6 bp6;
|
||||
memset(&bp6, 0, sizeof(bp6));
|
||||
bp6.sin6_family = AF_INET6;
|
||||
bp6.sin6_port = htons(params.port);
|
||||
// in OpenBSD must use separate divert sockets for ipv4 and ipv6
|
||||
memset(&bp6, 0, sizeof(bp6));
|
||||
bp6.sin6_family = AF_INET6;
|
||||
bp6.sin6_port = htons(params.port);
|
||||
|
||||
DLOG_CONDUP("creating divert6 socket\n");
|
||||
fd[1] = socket_divert(AF_INET6);
|
||||
if (fd[1] == -1) {
|
||||
DLOG_PERROR("socket (DIVERT6)");
|
||||
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("creating divert6 socket\n");
|
||||
fd[1] = socket_divert(AF_INET6);
|
||||
if (fd[1] == -1) {
|
||||
DLOG_PERROR("socket (DIVERT6)");
|
||||
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++;
|
||||
#endif
|
||||
fdmax = (fd[0] > fd[1] ? fd[0] : fd[1]) + 1;
|
||||
|
||||
@@ -487,13 +516,14 @@ static int dvt_main(void)
|
||||
FD_ZERO(&fdset);
|
||||
for (i = 0; i < fdct; i++) FD_SET(fd[i], &fdset);
|
||||
r = select(fdmax, &fdset, NULL, NULL, NULL);
|
||||
if (bQuit)
|
||||
{
|
||||
DLOG_CONDUP("quit requested\n");
|
||||
goto exitok;
|
||||
}
|
||||
if (r == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
// a signal received
|
||||
continue;
|
||||
}
|
||||
if (errno == EINTR) continue;
|
||||
DLOG_PERROR("select");
|
||||
goto exiterr;
|
||||
}
|
||||
@@ -571,6 +601,7 @@ static int dvt_main(void)
|
||||
}
|
||||
}
|
||||
|
||||
exitok:
|
||||
res = 0;
|
||||
exiterr:
|
||||
if (Fpid) fclose(Fpid);
|
||||
@@ -590,11 +621,11 @@ static int win_main()
|
||||
unsigned int id;
|
||||
uint8_t verdict;
|
||||
bool bOutbound;
|
||||
uint8_t packet[RECONSTRUCT_MAX_SIZE];
|
||||
uint32_t mark;
|
||||
WINDIVERT_ADDRESS wa;
|
||||
char ifname[IFNAMSIZ];
|
||||
int res=0;
|
||||
uint8_t packet[RECONSTRUCT_MAX_SIZE];
|
||||
|
||||
if (params.daemon) daemonize();
|
||||
|
||||
@@ -621,7 +652,7 @@ static int win_main()
|
||||
{
|
||||
if (bQuit)
|
||||
{
|
||||
DLOG("QUIT requested\n");
|
||||
DLOG("quit requested\n");
|
||||
goto ex;
|
||||
}
|
||||
usleep(500000);
|
||||
@@ -666,7 +697,7 @@ static int win_main()
|
||||
}
|
||||
else if (errno == EINTR)
|
||||
{
|
||||
DLOG("QUIT requested\n");
|
||||
DLOG("quit requested\n");
|
||||
goto ex;
|
||||
}
|
||||
DLOG_ERR("windivert: recv failed. errno %d\n", errno);
|
||||
@@ -1340,7 +1371,7 @@ static void exithelp(void)
|
||||
*all_payloads=0;
|
||||
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);
|
||||
}
|
||||
*all_protos=0;
|
||||
@@ -1382,10 +1413,11 @@ static void exithelp(void)
|
||||
#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-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"
|
||||
" --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"
|
||||
" --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__
|
||||
"\nWINDIVERT FILTER:\n"
|
||||
" --wf-iface=<int>[.<int>]\t\t\t\t; numeric network interface and subinterface indexes\n"
|
||||
@@ -1527,6 +1559,7 @@ enum opt_indices {
|
||||
#endif
|
||||
IDX_CTRACK_TIMEOUTS,
|
||||
IDX_CTRACK_DISABLE,
|
||||
IDX_PAYLOAD_DISABLE,
|
||||
IDX_SERVER,
|
||||
IDX_IPCACHE_LIFETIME,
|
||||
IDX_IPCACHE_HOSTNAME,
|
||||
@@ -1620,6 +1653,7 @@ static const struct option long_options[] = {
|
||||
#endif
|
||||
[IDX_CTRACK_TIMEOUTS] = {"ctrack-timeouts", required_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_IPCACHE_LIFETIME] = {"ipcache-lifetime", required_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:
|
||||
params.cache_hostname = !optarg || atoi(optarg);
|
||||
break;
|
||||
case IDX_PAYLOAD_DISABLE:
|
||||
if (optarg)
|
||||
{
|
||||
if (!parse_l7p_list(optarg, ¶ms.payload_disable))
|
||||
{
|
||||
DLOG_ERR("Invalid payload filter : %s\n", optarg);
|
||||
exit_clean(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
params.payload_disable = L7P_ALL;
|
||||
break;
|
||||
case IDX_REASM_DISABLE:
|
||||
if (optarg)
|
||||
{
|
||||
@@ -1959,7 +2005,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
else
|
||||
params.reasm_payload_disable = 0xFFFFFFFFFFFFFFFF;
|
||||
params.reasm_payload_disable = L7P_ALL;
|
||||
break;
|
||||
#if defined(__linux__)
|
||||
case IDX_FWMARK:
|
||||
@@ -2640,7 +2686,8 @@ int main(int argc, char **argv)
|
||||
HANDLE hMutexArg;
|
||||
{
|
||||
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);
|
||||
if (hMutexArg && GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
|
||||
@@ -498,6 +498,7 @@ void cleanup_params(struct params_s *params)
|
||||
ipcacheDestroy(¶ms->ipcache);
|
||||
blob_collection_destroy(¶ms->blobs);
|
||||
strlist_destroy(¶ms->lua_init_scripts);
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
strlist_destroy(¶ms->ssid_filter);
|
||||
strlist_destroy(¶ms->nlm_filter);
|
||||
@@ -531,6 +532,8 @@ void init_params(struct params_s *params)
|
||||
LIST_INIT(¶ms->blobs);
|
||||
LIST_INIT(¶ms->lua_init_scripts);
|
||||
|
||||
params->reasm_payload_disable = params->payload_disable = 1<<L7P_NONE;
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
LIST_INIT(¶ms->ssid_filter);
|
||||
LIST_INIT(¶ms->nlm_filter);
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include <wordexp.h>
|
||||
#endif
|
||||
|
||||
#define TLS_PARTIALS_ENABLE true
|
||||
|
||||
#define RAW_SNDBUF (64*1024) // in bytes
|
||||
|
||||
#define Q_MAXLEN 1024 // in packets
|
||||
@@ -45,7 +43,7 @@
|
||||
// this MSS is used for ipv6 in windows and linux
|
||||
#define DEFAULT_MSS 1220
|
||||
|
||||
#define RECONSTRUCT_MAX_SIZE 16384
|
||||
#define RECONSTRUCT_MAX_SIZE 65536
|
||||
|
||||
#define LUA_GC_INTERVAL 60
|
||||
|
||||
@@ -176,12 +174,14 @@ struct params_s
|
||||
unsigned int ipcache_lifetime;
|
||||
ip_cache ipcache;
|
||||
uint64_t reasm_payload_disable;
|
||||
uint64_t payload_disable;
|
||||
|
||||
struct str_list_head lua_init_scripts;
|
||||
bool writeable_dir_enable;
|
||||
char writeable_dir[PATH_MAX];
|
||||
|
||||
int lua_gc;
|
||||
int ref_desync_ctx; // desync ctx userdata registry ref
|
||||
lua_State *L;
|
||||
};
|
||||
|
||||
|
||||
@@ -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_ENDSLD:
|
||||
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)
|
||||
{
|
||||
@@ -989,24 +989,18 @@ bool IsQUICCryptoHello(const uint8_t *data, size_t len, size_t *hello_offset, si
|
||||
uint8_t QUICDraftVersion(uint32_t version)
|
||||
{
|
||||
/* IETF Draft versions */
|
||||
if ((version >> 8) == 0xff0000) {
|
||||
if ((version >> 8) == 0xff0000)
|
||||
return (uint8_t)version;
|
||||
}
|
||||
/* Facebook mvfst, based on draft -22. */
|
||||
if (version == 0xfaceb001) {
|
||||
if (version == 0xfaceb001)
|
||||
return 22;
|
||||
}
|
||||
/* Facebook mvfst, based on draft -27. */
|
||||
if (version == 0xfaceb002 || version == 0xfaceb00e) {
|
||||
if (version == 0xfaceb002 || version == 0xfaceb00e)
|
||||
return 27;
|
||||
}
|
||||
/* GQUIC Q050, T050 and T051: they are not really based on any drafts,
|
||||
* but we must return a sensible value */
|
||||
if (version == 0x51303530 ||
|
||||
version == 0x54303530 ||
|
||||
version == 0x54303531) {
|
||||
if (version == 0x51303530 || version == 0x54303530 || version == 0x54303531)
|
||||
return 27;
|
||||
}
|
||||
/* 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
|
||||
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
|
||||
we don't have a real version here! Let's hope that we need to handle
|
||||
only latest drafts... */
|
||||
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a) {
|
||||
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a)
|
||||
return 29;
|
||||
}
|
||||
/* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the
|
||||
final draft version */
|
||||
if (version == 0x00000001) {
|
||||
if (version == 0x00000001)
|
||||
return 34;
|
||||
}
|
||||
/* QUIC Version 2 */
|
||||
/* 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 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)
|
||||
{
|
||||
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)
|
||||
@@ -1386,24 +1378,24 @@ bool IsDNSResponse(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)
|
||||
{
|
||||
return len==92 && data[0]==2;
|
||||
return len==92 && pntoh32(data)==0x02000000;
|
||||
}
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
return len==32 && data[0]==4;
|
||||
return len==32 && pntoh32(data)==0x04000000;
|
||||
}
|
||||
bool IsDht(const uint8_t *data, size_t len)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ typedef enum {
|
||||
L7_XMPP,
|
||||
L7_DNS,
|
||||
L7_MTPROTO,
|
||||
L7_LAST, L7_INVALID=L7_LAST
|
||||
L7_LAST, L7_INVALID=L7_LAST, L7_NONE=L7_LAST
|
||||
} t_l7proto;
|
||||
const char *l7proto_str(t_l7proto l7);
|
||||
t_l7proto l7proto_from_name(const char *name);
|
||||
@@ -53,7 +53,7 @@ typedef enum {
|
||||
L7P_DNS_QUERY,
|
||||
L7P_DNS_RESPONSE,
|
||||
L7P_MTPROTO_INITIAL,
|
||||
L7P_LAST, L7P_INVALID=L7P_LAST
|
||||
L7P_LAST, L7P_INVALID=L7P_LAST, L7P_NONE=L7P_LAST
|
||||
} t_l7payload;
|
||||
t_l7payload l7payload_from_name(const char *name);
|
||||
const char *l7payload_str(t_l7payload l7);
|
||||
|
||||
Reference in New Issue
Block a user